238 Commits

Author SHA1 Message Date
Mark Thom
eb9d865635 Merge pull request #1635 from mthom/rebis-dev
Some checks failed
Test / windows (push) Has been cancelled
Docker Publish / build (push) Has been cancelled
Test / build (macos-10.15, beta) (push) Has been cancelled
Test / build (macos-10.15, stable) (push) Has been cancelled
Test / build (ubuntu-20.04, beta) (push) Has been cancelled
Test / build (ubuntu-20.04, stable) (push) Has been cancelled
Test / msrv (macos-10.15) (push) Has been cancelled
Test / msrv (ubuntu-20.04) (push) Has been cancelled
Merge rebis-dev into master
2022-11-10 07:18:10 +01:00
Mark Thom
694c87cb61 bump version to 0.9.1 2022-11-10 06:59:03 +01:00
Mark Thom
c41aba6b90 remove num-rug-adapter 2022-11-10 06:56:57 +01:00
Mark Thom
28ea672e36 move asserta/2, assertz/2 to iso_ext 2022-11-10 06:47:32 +01:00
Mark Thom
9366a48d6d introduce InlineTermStream to avoid arena allocations during call_inline (#1576) 2022-11-09 00:01:01 +01:00
Mark Thom
c7e1f5d568 Merge pull request #1630 from epilys/fix-1625
fix type_error with instantiated EOF -1 byte literal in get_byte/2
2022-10-26 23:37:36 -06:00
Markus Triska
d91ee5b77c FIXED: CLP(ℤ): Correctly remove all attributes during propagation of all_distinct/1 and other global constraints.
The constraints from library(clpz) were already correctly removed, but
others such as pending freeze/2 goals were not, potentially leading to
an accumulation of redundant constraints during propagation.

Test case:

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

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

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

    ?- chars_si("hello").
       true.

    ?- chars_si(5).
       false.

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

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

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

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

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

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

    get_byte(+stream_or_alias, ?in_byte)

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

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

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

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

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

Fixes #1626

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

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

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

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

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

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

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

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

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

    ?- Ls = [_|Ls].

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

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

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

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

We therefore introduce:

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

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

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

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

(cherry picked from commit fcfa3beaa3)
2022-03-12 19:23:33 +01:00
Mark Thom
64c9ac4071 Merge pull request #1348 from mthom/revert-1347-min-rust-version
Revert "Set minimum rust version in Cargo.toml"
2022-03-12 11:10:25 -07:00
Mark Thom
75fc922898 Revert "Set minimum rust version in Cargo.toml" 2022-03-12 11:10:17 -07:00
Mark Thom
59e2c3fd5e Merge pull request #1347 from Skgland/min-rust-version
Set minimum rust version in Cargo.toml
2022-03-12 11:07:03 -07:00
Skgland
5bd73741cf add a CI job to verify msrv is still correct 2022-03-12 19:02:34 +01:00
Skgland
fcfa3beaa3 add min rust version
was proposed in https://github.com/mthom/scryer-prolog/issues/1335#issuecomment-1062039516 and got positive feedback
2022-03-12 18:57:33 +01:00
Mark Thom
dfbdaa9dab Merge pull request #1342 from wkral/no-add-history
Add --no-add-history flag
2022-03-11 18:25:47 -07:00
William Kral
5f1f07e5a1 Add --no-add-history flag
Flag prevents the input stream from saving terms to ~/.scryer_history
when set. Use the flag when running tests to increase test isolation.
2022-03-10 21:48:41 -08:00
Mark Thom
eace0d9b37 print rationals that are integers as integers (#663) 2022-03-09 21:24:16 -07:00
Mark Thom
d83b32a200 print variables instead of offsets in setup_call_cleanup tests 2022-03-08 22:05:54 -07:00
Mark Thom
9cefb33388 correct loading of variable name strings in write_term/3 2022-03-08 22:00:12 -07:00
Mark Thom
bd5d6d0686 fix parser bounds check bug (#1333, #1301) 2022-03-08 21:25:19 -07:00
Mark Thom
ecebaf8216 unify empty list to '' in atom_chars/2 (#1334, #1336) 2022-03-08 18:25:40 -07:00
Mark Thom
8762647b55 wrap meta-predicate specifications in functors (#1330) 2022-03-07 22:36:52 -07:00
Mark Thom
664c0ee77c fix float formatting (#1331) 2022-03-07 19:44:39 -07:00
Mark Thom
7a9c3d351d Merge pull request #1332 from triska/call_nth_0
ENHANCED: call_nth(Goal, 0) now fails, correct error for N < 0.
2022-03-07 15:16:47 -07:00
Markus Triska
69e52d1ed8 ENHANCED: call_nth(Goal, 0) now fails, correct error for N < 0.
This addresses #1307.
2022-03-07 23:38:30 +01:00
Mark Thom
bd594e0c05 fix number/1 (#1329) 2022-03-06 19:17:52 -07:00
Mark Thom
3bf42860e2 Merge pull request #1328 from pmoura/fix_bounded_and_max_arity_flags
Fix querying the values of the bounded and max_arity flags
2022-03-06 18:51:14 -07:00
Paulo Moura
0532f51cc2 Fix querying the values of the bounded and max_arity flags 2022-03-07 00:30:35 +00:00
Mark Thom
1808597258 compare functor arity first (#1327) 2022-03-06 16:37:21 -07:00
Mark Thom
2744989cf1 fix compare/3 (#1327) 2022-03-06 15:49:01 -07:00
Mark Thom
0d04abb5c7 Merge pull request #1326 from pmoura/fix_halt_1_predicate_compliance
Fix halt/1 built-in predicate for ISO Prolog Core standard compliance
2022-03-06 14:46:46 -07:00
Paulo Moura
495168e7bb Fix halt/1 built-in predicate for ISO Prolog Core standard compliance 2022-03-06 21:33:49 +00:00
Mark Thom
475fbf9561 Merge pull request #1323 from triska/simplex
ADDED: library(simplex), for solving linear programming problems.
2022-03-06 13:46:32 -07:00
Markus Triska
c6264cf098 ADDED: library(simplex), for solving linear programming problems. 2022-03-06 21:49:52 +01:00
Mark Thom
bc9123affb only recommend git cloning to get the latest scryer version in README.md 2022-03-06 10:27:25 -07:00
Mark Thom
7fd12972ad Merge pull request #1322 from triska/explain_strings_better
DOC: Better explanation of strings and partial strings.
2022-03-06 10:07:37 -07:00
Markus Triska
8ad4f188f2 DOC: Better explanation of strings and partial strings. 2022-03-06 11:05:31 +01:00
96 changed files with 10620 additions and 5748 deletions

4
.gitattributes vendored Normal file
View File

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

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

@@ -0,0 +1,52 @@
name: Docker Publish
on:
push:
tags: [ 'v*.*.*' ]
env:
IMAGE_NAME: mjt128/scryer-prolog
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v3
# Workaround: https://github.com/docker/build-push-action/issues/461
- name: Setup Docker buildx
uses: docker/setup-buildx-action@79abd3f86f79a9d68a23c75a09a9a85889262adf
# Login against Docker registry
# https://github.com/docker/login-action
- name: Log into registry
uses: docker/login-action@28218f9b04b4f3f62068d7b6ce6ca5b26e35336c
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
# Extract Docker image tag from git tag. E.g. if git tag is "v0.19.1" then use
# Docker image tag "0.19.1". Tag "latest" is automatically synced with newest
# version.
# https://github.com/docker/metadata-action
- name: Extract Docker metadata
id: meta
uses: docker/metadata-action@98669ae865ea3cffbcbaa878cf57c20bbf1c6c38
with:
images: docker.io/${{ env.IMAGE_NAME }}
tags: |
type=semver,pattern={{version}}
# Build and push Docker image with Buildx
# https://github.com/docker/build-push-action
- name: Build and push Docker image
id: build-and-push
uses: docker/build-push-action@ad44023a93711e3deb337508980b4b5e9bcdc5dc
with:
context: .
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}

View File

@@ -38,3 +38,34 @@ jobs:
with: with:
command: test command: test
args: --verbose --all --no-default-features --features num args: --verbose --all --no-default-features --features num
msrv:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-20.04, macos-10.15]
steps:
- name: Checkout sources
uses: actions/checkout@v2
- name: Install cargo-msrv
uses: baptiste0928/cargo-install@v1.1.0
with:
crate: cargo-msrv
- name: Verify MSRV
run: cargo msrv --verify
windows:
runs-on: windows-latest
defaults:
run:
shell: msys2 {0}
steps:
- name: Setup MSYS2
uses: msys2/setup-msys2@v2
with:
update: true
install: >-
base-devel
mingw-w64-x86_64-rust
- name: Checkout sources
uses: actions/checkout@v3
- name: Test on Windows
run: cargo test --verbose --all

1607
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.0" version = "0.9.1"
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."
@@ -9,31 +9,26 @@ repository = "https://github.com/mthom/scryer-prolog"
license = "BSD-3-Clause" 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.rs" build = "build/main.rs"
rust-version = "1.61"
[workspace]
members = ["crates/num-rug-adapter",
"crates/static-string-indexing",
"crates/instructions-template",
"crates/to-syn-value",
"crates/to-syn-value_derive"]
[features] [features]
num = ["num-rug-adapter"]
# no default features to make num tests work
# workaround for --no-default-features and --features not working intuitively for workspaces with a root package
# see rust-lang/cargo#7160
default = ["rug"] default = ["rug"]
[build-dependencies] [build-dependencies]
indexmap = "1.0.2" indexmap = "1.0.2"
static-string-indexing = { path = "./crates/static-string-indexing" } proc-macro2 = "1.0.36"
instructions-template = { path = "./crates/instructions-template" } quote = "1.0.15"
proc-macro2 = "*" strum = "0.23"
strum_macros = "0.23"
syn = { version = "1.0.88", features = ['full', 'visit', 'extra-traits'] }
to-syn-value = "0.1.0"
to-syn-value_derive = "0.1.0"
walkdir = "2"
[dependencies] [dependencies]
cpu-time = "1.0.0" cpu-time = "1.0.0"
crossterm = "0.16.0" crossterm = "0.20.0"
dirs-next = "2.0.0" dirs-next = "2.0.0"
divrem = "0.1.0" divrem = "0.1.0"
fxhash = "0.2.1" fxhash = "0.2.1"
@@ -43,33 +38,39 @@ indexmap = "1.0.2"
lazy_static = "1.4.0" lazy_static = "1.4.0"
lexical = "5.2.2" lexical = "5.2.2"
libc = "0.2.62" libc = "0.2.62"
modular-bitfield = { git = "https://github.com/mthom/modular-bitfield" } # modular-bitfield = "0.11.2" modular-bitfield = "0.11.2"
nix = "0.15.0" ctrlc = "3.2.2"
num-rug-adapter = { optional = true, path = "./crates/num-rug-adapter" } ordered-float = "2.6.0"
ordered-float = "2.1.1"
phf = { version = "0.9", features = ["macros"] } phf = { version = "0.9", features = ["macros"] }
ref_thread_local = "0.0.0" ref_thread_local = "0.0.0"
rug = { version = "1.12.0", optional = true } rug = { version = "1.15.0", optional = true }
rustyline = "9.0.0" rustyline = "9.0.0"
ring = "0.16.13" ring = "0.16.13"
ripemd160 = "0.8.0" ripemd160 = "0.8.0"
sha3 = "0.8.2" sha3 = "0.8.2"
blake2 = "0.8.1" blake2 = "0.8.1"
openssl = { version = "0.10.29", features = ["vendored"] } crrl ="0.2.0"
native-tls = "0.2.4" native-tls = "0.2.4"
chrono = "0.4.11" chrono = "0.4.11"
select = "0.4.3" select = "0.4.3"
roxmltree = "0.11.0" roxmltree = "0.11.0"
base64 = "0.12.3" base64 = "0.12.3"
smallvec = "*" smallvec = "1.8.0"
sodiumoxide = "0.2.6" sodiumoxide = "0.2.6"
static_assertions = "1.1.0" static_assertions = "1.1.0"
slice-deque = "0.3.0" ryu = "1.0.9"
hyper = { version = "0.14", features = ["full"] }
hyper-tls = "0.5.0"
tokio = { version = "1", features = ["full"] }
futures = "0.3"
[dev-dependencies] [dev-dependencies]
assert_cmd = "1.0.3" assert_cmd = "1.0.3"
predicates-core = "1.0.2" predicates-core = "1.0.2"
serial_test = "0.5.1" serial_test = "0.5.1"
[patch.crates-io]
modular-bitfield = { git = "https://github.com/mthom/modular-bitfield" }
[profile.release] [profile.release]
debug = true debug = true

View File

@@ -1,5 +1,5 @@
# See https://github.com/LukeMathWalker/cargo-chef # See https://github.com/LukeMathWalker/cargo-chef
ARG RUST_VERSION=1.52.1-buster ARG RUST_VERSION=1.60-buster
FROM rust:${RUST_VERSION} as planner FROM rust:${RUST_VERSION} as planner
WORKDIR /scryer-prolog WORKDIR /scryer-prolog
RUN cargo install cargo-chef RUN cargo install cargo-chef

View File

@@ -1,3 +1,4 @@
# Scryer Prolog # Scryer Prolog
Scryer Prolog aims to become to ISO Prolog what GHC is to Haskell: an open Scryer Prolog aims to become to ISO Prolog what GHC is to Haskell: an open
@@ -101,7 +102,7 @@ strings.
## Installing Scryer Prolog ## Installing Scryer Prolog
### Native Install (Unix Only) ### Native Install
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
@@ -112,20 +113,8 @@ Rust updated to the latest stable release; any existing Rust
distribution should be uninstalled from your system before rustup is distribution should be uninstalled from your system before rustup is
used. used.
Scryer Prolog can be installed with cargo, like so: Currently the only way to install the latest version of Scryer is to
clone directly from this git repository, which can be done as follows:
```
$> cargo install scryer-prolog
```
cargo will download and install the libraries Scryer Prolog uses
automatically from crates.io. You can find the `scryer-prolog`
executable in `~/.cargo/bin`.
Publishing Rust crates to crates.io and pushing to git are entirely
distinct, independent processes, so to be sure you have the latest
commit, it is recommended to clone directly from this git repository,
which can be done as follows:
``` ```
$> git clone https://github.com/mthom/scryer-prolog $> git clone https://github.com/mthom/scryer-prolog
@@ -136,9 +125,20 @@ $> cargo run [--release]
The optional `--release` flag will perform various optimizations, The optional `--release` flag will perform various optimizations,
producing a faster executable. producing a faster executable.
On Windows, Scryer Prolog is easier to build inside a [MSYS2](https://www.msys2.org/)
environment as some crates may require native C compilation. However,
the resulting binary does not need MSYS2 to run. When executing Scryer in a shell, it is recommended to use a more advanced shell than mintty (the default MSYS2 shell). The [Windows Terminal](https://github.com/microsoft/terminal) works correctly.
To build a Windows Installer, you'll need first Scryer Prolog compiled in release mode, then, with WiX Toolset installed, execute:
```
candle.exe scryer-prolog.wxs
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.
Scryer Prolog must be built with **Rust 1.57 and up**. Scryer Prolog must be built with **Rust 1.57 and up**.
### Docker Install (All Platforms) ### Docker Install
First, install [Docker](https://docs.docker.com/get-docker/) on Linux, First, install [Docker](https://docs.docker.com/get-docker/) on Linux,
Windows, or Mac. Windows, or Mac.
@@ -213,8 +213,14 @@ predicates it defines. For example, with the program shown above:
Press `SPACE` to show further answers, if any exist. Press `RETURN` Press `SPACE` to show further answers, if any exist. Press `RETURN`
or&nbsp;`.` to abort the search and return to the or&nbsp;`.` to abort the search and return to the
toplevel&nbsp;prompt. Press&nbsp;`f` to see the next 5 answers, and toplevel&nbsp;prompt. Press&nbsp;`f` to see up to the next multiple of
`a` to see all answers. Press&nbsp;`h` to show a help message. 5 answers, and `a` to see all answers. Press&nbsp;`h` to show a help
message.
Use `TAB` to complete atoms and predicate names in queries. For
instance, after consulting the program above, typing `decl` followed
by&nbsp;`TAB` yields `declarative_world`. Press&nbsp;`TAB` repeatedly
to cycle through alternative completions.
To quit Scryer Prolog, use the standard predicate `halt/0`: To quit Scryer Prolog, use the standard predicate `halt/0`:
@@ -267,9 +273,30 @@ in any clause of a predicate's definition.
### Strings and partial strings ### Strings and partial strings
A very compact internal representation of *strings* is one of the key
innovations of Scryer Prolog. This means that terms which appear as
lists of characters to Prolog programs are stored in packed
UTF-8&nbsp;encoding by the engine.
Without this innovation, storing a list of characters in memory
would use one memory&nbsp;cell per character, one memory&nbsp;cell per
list constructor, and one memory&nbsp;cell for each tail that occurs
in the list. Since one memory&nbsp;cell takes 8&nbsp;bytes on 64-bit
machines, the packed representation used by Scryer&nbsp;Prolog yields
an up&nbsp;to **24-fold&nbsp;reduction** of memory usage, and
corresponding reduction of memory&nbsp;accesses when creating and
processing strings.
Scryer Prolog's compact internal string representation makes it
ideally suited for the use case Prolog was originally developed for:
efficient and convenient text processing, especially with definite
clause grammars (DCGs) as provided by
[`library(dcgs)`](src/lib/dcgs.pl) and
[`library(pio)`](src/lib/pio.pl) to transparently apply DCGs to files.
In Scryer Prolog, the default value of the Prolog flag `double_quotes` In Scryer Prolog, the default value of the Prolog flag `double_quotes`
is `chars`, which is also the recommended setting. This means that is `chars`, which is also the recommended setting. This means that
double-quoted strings are interpreted as lists of *characters*, in the lists of characters can be written as double-quoted strings, in the
tradition of Marseille&nbsp;Prolog. tradition of Marseille&nbsp;Prolog.
For example, the following query succeeds: For example, the following query succeeds:
@@ -279,15 +306,9 @@ For example, the following query succeeds:
true. true.
``` ```
Internally, strings are represented very compactly in packed This shows that the string `"abc"`, which is represented as a sequence
UTF-8&nbsp;encoding. A naive representation of strings as lists of of 3&nbsp;bytes internally, appears to Prolog programs as a list of
characters would use one memory&nbsp;cell per character, one characters.
memory&nbsp;cell per list constructor, and one memory&nbsp;cell for
each tail that occurs in the list. Since one memory&nbsp;cell takes
8&nbsp;bytes on 64-bit machines, the packed representation used by
Scryer&nbsp;Prolog yields an up&nbsp;to **24-fold&nbsp;reduction** of
memory usage, and corresponding reduction of memory&nbsp;accesses when
creating and processing strings.
Scryer Prolog uses the same efficient encoding for *partial* strings, Scryer Prolog uses the same efficient encoding for *partial* strings,
which appear to Prolog code as partial lists of characters. The which appear to Prolog code as partial lists of characters. The
@@ -310,13 +331,11 @@ the above example, posting <tt>Ls0&nbsp;=&nbsp;[a,b,c|Ls]</tt> yields
the exact same internal representation, and has the advantage that the exact same internal representation, and has the advantage that
only the standard predicate&nbsp;`(=)/2` is used. only the standard predicate&nbsp;`(=)/2` is used.
Definite clause grammars as provided by The efficient internal representation of strings and partial strings
[`library(dcgs)`](src/lib/dcgs.pl), and the predicates from was first proposed and explained by Ulrich Neumerkel in
[`library(lists)`](src/lib/lists.pl), are ideally suited for reasoning issues&nbsp;[#24](https://github.com/mthom/scryer-prolog/issues/24)
about strings. and&nbsp;[#95](https://github.com/mthom/scryer-prolog/issues/95), and
Scryer&nbsp;Prolog is the first Prolog&nbsp;system that implements it.
Partial strings were first proposed by Ulrich Neumerkel in issue
[#95](https://github.com/mthom/scryer-prolog/issues/95).
### Occurs check and cyclic terms ### Occurs check and cyclic terms
@@ -520,7 +539,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.0 web server. * [`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.
* [`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
@@ -562,6 +581,9 @@ The modules that ship with Scryer&nbsp;Prolog are also called
* [`tls`](src/lib/tls.pl) * [`tls`](src/lib/tls.pl)
Predicates for negotiating TLS connections explicitly. Predicates for negotiating TLS connections explicitly.
* [`ugraphs`](src/lib/ugraphs.pl) Graph manipulation library * [`ugraphs`](src/lib/ugraphs.pl) Graph manipulation library
* [`simplex`](src/lib/simplex.pl) Providing `assignment/2`,
`transportation/4` and other predicates for solving linear
programming problems.
To use predicates provided by the `lists` library, write: To use predicates provided by the `lists` library, write:

View File

@@ -190,9 +190,9 @@ enum REPLCodePtr {
DynamicProperty, DynamicProperty,
#[strum_discriminants(strum(props(Arity = "3", Name = "$abolish_clause")))] #[strum_discriminants(strum(props(Arity = "3", Name = "$abolish_clause")))]
AbolishClause, AbolishClause,
#[strum_discriminants(strum(props(Arity = "5", Name = "$asserta")))] #[strum_discriminants(strum(props(Arity = "3", Name = "$asserta")))]
Asserta, Asserta,
#[strum_discriminants(strum(props(Arity = "5", Name = "$assertz")))] #[strum_discriminants(strum(props(Arity = "3", Name = "$assertz")))]
Assertz, Assertz,
#[strum_discriminants(strum(props(Arity = "4", Name = "$retract_clause")))] #[strum_discriminants(strum(props(Arity = "4", Name = "$retract_clause")))]
Retract, Retract,
@@ -276,6 +276,8 @@ enum SystemClauseType {
DeleteHeadAttribute, DeleteHeadAttribute,
#[strum_discriminants(strum(props(Arity = "arity", Name = "$module_call")))] #[strum_discriminants(strum(props(Arity = "arity", Name = "$module_call")))]
DynamicModuleResolution(usize), DynamicModuleResolution(usize),
#[strum_discriminants(strum(props(Arity = "arity", Name = "$prepare_call_clause")))]
PrepareCallClause(usize),
#[strum_discriminants(strum(props(Arity = "1", Name = "$enqueue_attr_var")))] #[strum_discriminants(strum(props(Arity = "1", Name = "$enqueue_attr_var")))]
EnqueueAttributedVar, EnqueueAttributedVar,
#[strum_discriminants(strum(props(Arity = "2", Name = "$fetch_global_var")))] #[strum_discriminants(strum(props(Arity = "2", Name = "$fetch_global_var")))]
@@ -402,8 +404,6 @@ enum SystemClauseType {
InferenceLevel, InferenceLevel,
#[strum_discriminants(strum(props(Arity = "1", Name = "$clean_up_block")))] #[strum_discriminants(strum(props(Arity = "1", Name = "$clean_up_block")))]
CleanUpBlock, CleanUpBlock,
#[strum_discriminants(strum(props(Arity = "0", Name = "$erase_ball")))]
EraseBall,
#[strum_discriminants(strum(props(Arity = "0", Name = "$fail")))] #[strum_discriminants(strum(props(Arity = "0", Name = "$fail")))]
Fail, Fail,
#[strum_discriminants(strum(props(Arity = "1", Name = "$get_ball")))] #[strum_discriminants(strum(props(Arity = "1", Name = "$get_ball")))]
@@ -432,6 +432,12 @@ enum SystemClauseType {
ReturnFromVerifyAttr, ReturnFromVerifyAttr,
#[strum_discriminants(strum(props(Arity = "1", Name = "$set_ball")))] #[strum_discriminants(strum(props(Arity = "1", Name = "$set_ball")))]
SetBall, SetBall,
#[strum_discriminants(strum(props(Arity = "0", Name = "$push_ball_stack")))]
PushBallStack,
#[strum_discriminants(strum(props(Arity = "0", Name = "$pop_ball_stack")))]
PopBallStack,
#[strum_discriminants(strum(props(Arity = "0", Name = "$pop_from_ball_stack")))]
PopFromBallStack,
#[strum_discriminants(strum(props(Arity = "1", Name = "$set_cp_by_default")))] #[strum_discriminants(strum(props(Arity = "1", Name = "$set_cp_by_default")))]
SetCutPointByDefault(RegType), SetCutPointByDefault(RegType),
#[strum_discriminants(strum(props(Arity = "1", Name = "$set_double_quotes")))] #[strum_discriminants(strum(props(Arity = "1", Name = "$set_double_quotes")))]
@@ -490,7 +496,7 @@ enum SystemClauseType {
CryptoDataEncrypt, CryptoDataEncrypt,
#[strum_discriminants(strum(props(Arity = "6", Name = "$crypto_data_decrypt")))] #[strum_discriminants(strum(props(Arity = "6", Name = "$crypto_data_decrypt")))]
CryptoDataDecrypt, CryptoDataDecrypt,
#[strum_discriminants(strum(props(Arity = "5", 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")))] #[strum_discriminants(strum(props(Arity = "4", Name = "$ed25519_sign")))]
Ed25519Sign, Ed25519Sign,
@@ -538,6 +544,26 @@ enum SystemClauseType {
PopCount, PopCount,
#[strum_discriminants(strum(props(Arity = "1", Name = "$cpu_now")))] #[strum_discriminants(strum(props(Arity = "1", Name = "$cpu_now")))]
CpuNow, CpuNow,
#[strum_discriminants(strum(props(Arity = "2", Name = "$det_length_rundown")))]
DeterministicLengthRundown,
#[strum_discriminants(strum(props(Arity = "7", Name = "$http_open")))]
HttpOpen,
#[strum_discriminants(strum(props(Arity = "2", Name = "$http_listen")))]
HttpListen,
#[strum_discriminants(strum(props(Arity = "7", Name = "$http_accept")))]
HttpAccept,
#[strum_discriminants(strum(props(Arity = "4", Name = "$http_answer")))]
HttpAnswer,
#[strum_discriminants(strum(props(Arity = "3", Name = "$predicate_defined")))]
PredicateDefined,
#[strum_discriminants(strum(props(Arity = "3", Name = "$strip_module")))]
StripModule,
#[strum_discriminants(strum(props(Arity = "4", Name = "$compile_inline_or_expanded_goal")))]
CompileInlineOrExpandedGoal,
#[strum_discriminants(strum(props(Arity = "arity", Name = "$call_inline")))]
InlineCallN(usize),
#[strum_discriminants(strum(props(Arity = "1", Name = "$is_expanded_or_inlined")))]
IsExpandedOrInlined,
REPL(REPLCodePtr), REPL(REPLCodePtr),
} }
@@ -802,8 +828,8 @@ fn generate_instruction_preface() -> TokenStream {
use crate::parser::ast::*; use crate::parser::ast::*;
use crate::types::*; use crate::types::*;
use fxhash::FxBuildHasher;
use indexmap::IndexMap; use indexmap::IndexMap;
use slice_deque::SliceDeque;
use std::collections::VecDeque; use std::collections::VecDeque;
@@ -915,8 +941,8 @@ fn generate_instruction_preface() -> TokenStream {
IndexingCodePtr, IndexingCodePtr,
IndexingCodePtr, IndexingCodePtr,
), ),
SwitchOnConstant(IndexMap<Literal, IndexingCodePtr>), SwitchOnConstant(IndexMap<Literal, IndexingCodePtr, FxBuildHasher>),
SwitchOnStructure(IndexMap<(Atom, usize), IndexingCodePtr>), SwitchOnStructure(IndexMap<(Atom, usize), IndexingCodePtr, FxBuildHasher>),
} }
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
@@ -1026,8 +1052,8 @@ fn generate_instruction_preface() -> TokenStream {
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub enum IndexingLine { pub enum IndexingLine {
Indexing(IndexingInstruction), Indexing(IndexingInstruction),
IndexedChoice(SliceDeque<IndexedChoiceInstruction>), IndexedChoice(VecDeque<IndexedChoiceInstruction>),
DynamicIndexedChoice(SliceDeque<usize>), DynamicIndexedChoice(VecDeque<usize>),
} }
impl From<IndexingInstruction> for IndexingLine { impl From<IndexingInstruction> for IndexingLine {
@@ -1095,6 +1121,7 @@ fn generate_instruction_preface() -> TokenStream {
#[inline] #[inline]
pub fn is_head_instr(&self) -> bool { pub fn is_head_instr(&self) -> bool {
match self { match self {
Instruction::Deallocate |
Instruction::GetConstant(..) | Instruction::GetConstant(..) |
Instruction::GetList(..) | Instruction::GetList(..) |
Instruction::GetPartialString(..) | Instruction::GetPartialString(..) |
@@ -1424,6 +1451,12 @@ fn generate_instruction_preface() -> TokenStream {
&Instruction::DefaultExecuteN(arity, _) => { &Instruction::DefaultExecuteN(arity, _) => {
functor!(atom!("execute_default_n"), [fixnum(arity)]) functor!(atom!("execute_default_n"), [fixnum(arity)])
} }
&Instruction::CallInlineCallN(arity, _) => {
functor!(atom!("call_n_inline"), [fixnum(arity)])
}
&Instruction::ExecuteInlineCallN(arity, _) => {
functor!(atom!("call_n_inline"), [fixnum(arity)])
}
&Instruction::CallTermGreaterThan(_) | &Instruction::CallTermGreaterThan(_) |
&Instruction::CallTermLessThan(_) | &Instruction::CallTermLessThan(_) |
&Instruction::CallTermGreaterThanOrEqual(_) | &Instruction::CallTermGreaterThanOrEqual(_) |
@@ -1585,6 +1618,9 @@ fn generate_instruction_preface() -> TokenStream {
&Instruction::CallDeleteAttribute(_) | &Instruction::CallDeleteAttribute(_) |
&Instruction::CallDeleteHeadAttribute(_) | &Instruction::CallDeleteHeadAttribute(_) |
&Instruction::CallDynamicModuleResolution(..) | &Instruction::CallDynamicModuleResolution(..) |
&Instruction::CallPrepareCallClause(..) |
&Instruction::CallCompileInlineOrExpandedGoal(..) |
&Instruction::CallIsExpandedOrInlined(_) |
&Instruction::CallEnqueueAttributedVar(_) | &Instruction::CallEnqueueAttributedVar(_) |
&Instruction::CallFetchGlobalVar(_) | &Instruction::CallFetchGlobalVar(_) |
&Instruction::CallFirstStream(_) | &Instruction::CallFirstStream(_) |
@@ -1648,7 +1684,6 @@ fn generate_instruction_preface() -> TokenStream {
&Instruction::CallSetStreamPosition(_) | &Instruction::CallSetStreamPosition(_) |
&Instruction::CallInferenceLevel(_) | &Instruction::CallInferenceLevel(_) |
&Instruction::CallCleanUpBlock(_) | &Instruction::CallCleanUpBlock(_) |
&Instruction::CallEraseBall(_) |
&Instruction::CallFail(_) | &Instruction::CallFail(_) |
&Instruction::CallGetBall(_) | &Instruction::CallGetBall(_) |
&Instruction::CallGetCurrentBlock(_) | &Instruction::CallGetCurrentBlock(_) |
@@ -1658,12 +1693,22 @@ fn generate_instruction_preface() -> TokenStream {
&Instruction::CallInstallNewBlock(_) | &Instruction::CallInstallNewBlock(_) |
&Instruction::CallMaybe(_) | &Instruction::CallMaybe(_) |
&Instruction::CallCpuNow(_) | &Instruction::CallCpuNow(_) |
&Instruction::CallDeterministicLengthRundown(_) |
&Instruction::CallHttpOpen(_) |
&Instruction::CallHttpListen(_) |
&Instruction::CallHttpAccept(_) |
&Instruction::CallHttpAnswer(_) |
&Instruction::CallPredicateDefined(_) |
&Instruction::CallStripModule(_) |
&Instruction::CallCurrentTime(_) | &Instruction::CallCurrentTime(_) |
&Instruction::CallQuotedToken(_) | &Instruction::CallQuotedToken(_) |
&Instruction::CallReadTermFromChars(_) | &Instruction::CallReadTermFromChars(_) |
&Instruction::CallResetBlock(_) | &Instruction::CallResetBlock(_) |
&Instruction::CallReturnFromVerifyAttr(_) | &Instruction::CallReturnFromVerifyAttr(_) |
&Instruction::CallSetBall(_) | &Instruction::CallSetBall(_) |
&Instruction::CallPushBallStack(_) |
&Instruction::CallPopBallStack(_) |
&Instruction::CallPopFromBallStack(_) |
&Instruction::CallSetCutPointByDefault(..) | &Instruction::CallSetCutPointByDefault(..) |
&Instruction::CallSetDoubleQuotes(_) | &Instruction::CallSetDoubleQuotes(_) |
&Instruction::CallSetSeed(_) | &Instruction::CallSetSeed(_) |
@@ -1786,7 +1831,10 @@ fn generate_instruction_preface() -> TokenStream {
&Instruction::ExecuteFileTime(_) | &Instruction::ExecuteFileTime(_) |
&Instruction::ExecuteDeleteAttribute(_) | &Instruction::ExecuteDeleteAttribute(_) |
&Instruction::ExecuteDeleteHeadAttribute(_) | &Instruction::ExecuteDeleteHeadAttribute(_) |
&Instruction::ExecuteDynamicModuleResolution(_, _) | &Instruction::ExecuteDynamicModuleResolution(..) |
&Instruction::ExecutePrepareCallClause(..) |
&Instruction::ExecuteCompileInlineOrExpandedGoal(..) |
&Instruction::ExecuteIsExpandedOrInlined(_) |
&Instruction::ExecuteEnqueueAttributedVar(_) | &Instruction::ExecuteEnqueueAttributedVar(_) |
&Instruction::ExecuteFetchGlobalVar(_) | &Instruction::ExecuteFetchGlobalVar(_) |
&Instruction::ExecuteFirstStream(_) | &Instruction::ExecuteFirstStream(_) |
@@ -1850,7 +1898,6 @@ fn generate_instruction_preface() -> TokenStream {
&Instruction::ExecuteSetStreamPosition(_) | &Instruction::ExecuteSetStreamPosition(_) |
&Instruction::ExecuteInferenceLevel(_) | &Instruction::ExecuteInferenceLevel(_) |
&Instruction::ExecuteCleanUpBlock(_) | &Instruction::ExecuteCleanUpBlock(_) |
&Instruction::ExecuteEraseBall(_) |
&Instruction::ExecuteFail(_) | &Instruction::ExecuteFail(_) |
&Instruction::ExecuteGetBall(_) | &Instruction::ExecuteGetBall(_) |
&Instruction::ExecuteGetCurrentBlock(_) | &Instruction::ExecuteGetCurrentBlock(_) |
@@ -1860,12 +1907,22 @@ fn generate_instruction_preface() -> TokenStream {
&Instruction::ExecuteInstallNewBlock(_) | &Instruction::ExecuteInstallNewBlock(_) |
&Instruction::ExecuteMaybe(_) | &Instruction::ExecuteMaybe(_) |
&Instruction::ExecuteCpuNow(_) | &Instruction::ExecuteCpuNow(_) |
&Instruction::ExecuteDeterministicLengthRundown(_) |
&Instruction::ExecuteHttpOpen(_) |
&Instruction::ExecuteHttpListen(_) |
&Instruction::ExecuteHttpAccept(_) |
&Instruction::ExecuteHttpAnswer(_) |
&Instruction::ExecutePredicateDefined(_) |
&Instruction::ExecuteStripModule(_) |
&Instruction::ExecuteCurrentTime(_) | &Instruction::ExecuteCurrentTime(_) |
&Instruction::ExecuteQuotedToken(_) | &Instruction::ExecuteQuotedToken(_) |
&Instruction::ExecuteReadTermFromChars(_) | &Instruction::ExecuteReadTermFromChars(_) |
&Instruction::ExecuteResetBlock(_) | &Instruction::ExecuteResetBlock(_) |
&Instruction::ExecuteReturnFromVerifyAttr(_) | &Instruction::ExecuteReturnFromVerifyAttr(_) |
&Instruction::ExecuteSetBall(_) | &Instruction::ExecuteSetBall(_) |
&Instruction::ExecutePushBallStack(_) |
&Instruction::ExecutePopBallStack(_) |
&Instruction::ExecutePopFromBallStack(_) |
&Instruction::ExecuteSetCutPointByDefault(_, _) | &Instruction::ExecuteSetCutPointByDefault(_, _) |
&Instruction::ExecuteSetDoubleQuotes(_) | &Instruction::ExecuteSetDoubleQuotes(_) |
&Instruction::ExecuteSetSeed(_) | &Instruction::ExecuteSetSeed(_) |
@@ -2158,6 +2215,7 @@ pub fn generate_instructions_rs() -> TokenStream {
let mut clause_type_from_name_and_arity_arms = vec![]; let mut clause_type_from_name_and_arity_arms = vec![];
let mut clause_type_to_instr_arms = vec![]; let mut clause_type_to_instr_arms = vec![];
let mut clause_type_name_arms = vec![]; let mut clause_type_name_arms = vec![];
let mut is_inbuilt_arms = vec![];
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();
@@ -2212,6 +2270,12 @@ pub fn generate_instructions_rs() -> TokenStream {
) => Instruction::#instr_ident(#(#placeholder_ids),*, 0) ) => Instruction::#instr_ident(#(#placeholder_ids),*, 0)
} }
); );
is_inbuilt_arms.push(
quote! {
(atom!(#name), #arity) => true
}
);
} }
for (name, arity, variant) in instr_data.compare_term_variants { for (name, arity, variant) in instr_data.compare_term_variants {
@@ -2241,6 +2305,12 @@ pub fn generate_instructions_rs() -> TokenStream {
) => Instruction::#instr_ident(0) ) => Instruction::#instr_ident(0)
} }
); );
is_inbuilt_arms.push(
quote! {
(atom!(#name), #arity) => true
}
);
} }
for (name, arity, variant) in instr_data.builtin_type_variants { for (name, arity, variant) in instr_data.builtin_type_variants {
@@ -2302,6 +2372,12 @@ pub fn generate_instructions_rs() -> TokenStream {
) => Instruction::#instr_ident(0) ) => Instruction::#instr_ident(0)
} }
}); });
is_inbuilt_arms.push(
quote! {
(atom!(#name), #arity) => true
}
);
} }
for (name, arity, variant) in instr_data.inlined_type_variants { for (name, arity, variant) in instr_data.inlined_type_variants {
@@ -2361,6 +2437,12 @@ pub fn generate_instructions_rs() -> TokenStream {
) => Instruction::#instr_ident(#(#placeholder_ids),*,0) ) => Instruction::#instr_ident(#(#placeholder_ids),*,0)
} }
); );
is_inbuilt_arms.push(
quote! {
(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 {
@@ -2391,6 +2473,12 @@ pub fn generate_instructions_rs() -> TokenStream {
SystemClauseType::#ident(temp_v!(1)) SystemClauseType::#ident(temp_v!(1))
) )
} }
} else if ident.to_string() == "InlineCallN" {
quote! {
(atom!(#name), arity) => ClauseType::System(
SystemClauseType::#ident(arity)
)
}
} else { } else {
quote! { quote! {
(atom!(#name), #arity) => ClauseType::System( (atom!(#name), #arity) => ClauseType::System(
@@ -2421,6 +2509,7 @@ pub fn generate_instructions_rs() -> TokenStream {
}); });
let ident = variant.ident; let ident = variant.ident;
let instr_ident = if ident != "CallContinuation" { let instr_ident = if ident != "CallContinuation" {
format_ident!("Call{}", ident) format_ident!("Call{}", ident)
} else { } else {
@@ -2444,6 +2533,18 @@ pub fn generate_instructions_rs() -> TokenStream {
) => Instruction::#instr_ident(0) ) => Instruction::#instr_ident(0)
} }
}); });
is_inbuilt_arms.push(
if let Arity::Ident("arity") = &arity {
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 {
@@ -2509,6 +2610,12 @@ pub fn generate_instructions_rs() -> TokenStream {
)) => Instruction::#instr_ident(0) )) => Instruction::#instr_ident(0)
} }
}); });
is_inbuilt_arms.push(
quote! {
(atom!(#name), #arity) => true
}
);
} }
for (name, arity, variant) in instr_data.clause_type_variants { for (name, arity, variant) in instr_data.clause_type_variants {
@@ -2516,7 +2623,7 @@ pub fn generate_instructions_rs() -> TokenStream {
if ident == "Named" { if ident == "Named" {
clause_type_from_name_and_arity_arms.push(quote! { clause_type_from_name_and_arity_arms.push(quote! {
(name, arity) => ClauseType::Named(arity, name, CodeIndex::default()) (name, arity) => ClauseType::Named(arity, name, CodeIndex::default(arena))
}); });
clause_type_to_instr_arms.push(quote! { clause_type_to_instr_arms.push(quote! {
@@ -2578,6 +2685,12 @@ pub fn generate_instructions_rs() -> TokenStream {
ClauseType::#ident => Instruction::#ident(0) ClauseType::#ident => Instruction::#ident(0)
} }
}); });
is_inbuilt_arms.push(
quote! {
(atom!(#name), _arity) => true
}
);
} }
let to_execute_arms: Vec<_> = instr_data.instr_variants let to_execute_arms: Vec<_> = instr_data.instr_variants
@@ -2912,7 +3025,7 @@ pub fn generate_instructions_rs() -> TokenStream {
} }
impl ClauseType { impl ClauseType {
pub fn from(name: Atom, arity: usize) -> ClauseType { pub fn from(name: Atom, arity: usize, arena: &mut Arena) -> ClauseType {
match (name, arity) { match (name, arity) {
#( #(
#clause_type_from_name_and_arity_arms, #clause_type_from_name_and_arity_arms,
@@ -2928,19 +3041,12 @@ pub fn generate_instructions_rs() -> TokenStream {
} }
} }
pub fn is_builtin(&self) -> bool { pub fn is_inbuilt(name: Atom, arity: usize) -> bool {
if let ClauseType::BuiltIn(_) = self { match (name, arity) {
true #(
} else { #is_inbuilt_arms,
false )*
} _ => false,
}
pub fn is_inlined(&self) -> bool {
if let ClauseType::Inlined(_) = self {
true
} else {
false
} }
} }
@@ -3135,7 +3241,7 @@ enum Arity {
impl From<&'static str> for Arity { impl From<&'static str> for Arity {
fn from(arity: &'static str) -> Self { fn from(arity: &'static str) -> Self {
usize::from_str_radix(&arity, 10) usize::from_str_radix(&arity, 10)
.map(|n| Arity::Static(n)) .map(Arity::Static)
.unwrap_or_else(|_| Arity::Ident(arity)) .unwrap_or_else(|_| Arity::Ident(arity))
} }
} }

View File

@@ -1,12 +1,15 @@
use static_string_indexing::index_static_strings; mod instructions_template;
mod static_string_indexing;
use instructions_template::generate_instructions_rs; use instructions_template::generate_instructions_rs;
use static_string_indexing::index_static_strings;
use std::env; use std::env;
use std::fs; use std::fs;
use std::fs::File; use std::fs::File;
use std::io::Write; use std::io::Write;
use std::path::Path; use std::path::Path;
use std::process::Command; use std::process::{Command, Stdio};
fn find_prolog_files(libraries: &mut File, prefix: &str, current_dir: &Path) { fn find_prolog_files(libraries: &mut File, prefix: &str, current_dir: &Path) {
let entries = match current_dir.read_dir() { let entries = match current_dir.read_dir() {
@@ -39,6 +42,16 @@ fn find_prolog_files(libraries: &mut File, prefix: &str, current_dir: &Path) {
} }
fn main() { fn main() {
let has_rustfmt = Command::new("rustfmt")
.arg("--version")
.stdin(Stdio::inherit())
.status()
.is_ok();
if !has_rustfmt {
println!("Failed to run rustfmt, will skip formatting generated files.")
}
let out_dir = env::var("OUT_DIR").unwrap(); let out_dir = env::var("OUT_DIR").unwrap();
let dest_path = Path::new(&out_dir).join("libraries.rs"); let dest_path = Path::new(&out_dir).join("libraries.rs");
@@ -65,10 +78,9 @@ fn main() {
.write_all(quoted_output.to_string().as_bytes()) .write_all(quoted_output.to_string().as_bytes())
.unwrap(); .unwrap();
Command::new("rustfmt") if has_rustfmt {
.arg(instructions_path.as_os_str()) format_generated_file(instructions_path.as_path());
.spawn().unwrap() }
.wait().unwrap();
let static_atoms_path = Path::new(&out_dir).join("static_atoms.rs"); let static_atoms_path = Path::new(&out_dir).join("static_atoms.rs");
let mut static_atoms_file = File::create(&static_atoms_path).unwrap(); let mut static_atoms_file = File::create(&static_atoms_path).unwrap();
@@ -79,10 +91,24 @@ fn main() {
.write_all(quoted_output.to_string().as_bytes()) .write_all(quoted_output.to_string().as_bytes())
.unwrap(); .unwrap();
Command::new("rustfmt") if has_rustfmt {
.arg(static_atoms_path.as_os_str()) format_generated_file(static_atoms_path.as_path());
.spawn().unwrap() }
.wait().unwrap();
println!("cargo:rerun-if-changed=src/"); println!("cargo:rerun-if-changed=src/");
} }
fn format_generated_file(path: &Path) {
Command::new("rustfmt")
.arg(path.as_os_str())
.spawn()
.unwrap_or_else(|err| {
panic!(
"{}: rustfmt was detected as available, but failed to format generated file '{}'",
err,
path.display()
);
})
.wait()
.unwrap();
}

View File

@@ -66,7 +66,7 @@ impl<'ast> Visit<'ast> for StaticStrVisitor {
if let Some(Lit::Str(string)) = m.parse_body::<Lit>().ok() { if let Some(Lit::Str(string)) = m.parse_body::<Lit>().ok() {
self.static_strs.insert(string.value()); self.static_strs.insert(string.value());
} }
} else if path.is_ident("read_heap_cell") { } else if path.is_ident("read_heap_cell") || path.is_ident("match_untyped_arena_ptr") {
if let Some(m) = m.parse_body::<ReadHeapCellExprAndArms>().ok() { if let Some(m) = m.parse_body::<ReadHeapCellExprAndArms>().ok() {
self.visit_expr(&m.expr); self.visit_expr(&m.expr);
@@ -170,7 +170,7 @@ pub fn index_static_strings(instruction_rs_path: &std::path::Path) -> TokenStrea
#((#static_strs) => { Atom { index: #indices_iter } };)* #((#static_strs) => { Atom { index: #indices_iter } };)*
} }
static STATIC_ATOMS_MAP: phf::Map<&'static str, Atom> = phf::phf_map! { pub static STATIC_ATOMS_MAP: phf::Map<&'static str, Atom> = phf::phf_map! {
#(#static_strs => { Atom { index: #indices } },)* #(#static_strs => { Atom { index: #indices } },)*
}; };
} }

View File

@@ -1,129 +0,0 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "autocfg"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
[[package]]
name = "hashbrown"
version = "0.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e"
[[package]]
name = "heck"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c"
dependencies = [
"unicode-segmentation",
]
[[package]]
name = "indexmap"
version = "1.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bc633605454125dec4b66843673f01c7df2b89479b32e0ed634e43a91cff62a5"
dependencies = [
"autocfg",
"hashbrown",
]
[[package]]
name = "instructions-template"
version = "0.1.0"
dependencies = [
"indexmap",
"proc-macro2",
"quote",
"strum",
"strum_macros",
"syn",
]
[[package]]
name = "proc-macro2"
version = "1.0.35"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "392a54546fda6b7cc663379d0e6ce8b324cf88aecc5a499838e1be9781bdce2e"
dependencies = [
"unicode-xid",
]
[[package]]
name = "quote"
version = "1.0.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "38bc8cc6a5f2e3655e0899c1b848643b2562f853f114bfec7be120678e3ace05"
dependencies = [
"proc-macro2",
]
[[package]]
name = "rustversion"
version = "1.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f2cc38e8fa666e2de3c4aba7edeb5ffc5246c1c2ed0e3d17e560aeeba736b23f"
[[package]]
name = "strum"
version = "0.23.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cae14b91c7d11c9a851d3fbc80a963198998c2a64eec840477fa92d8ce9b70bb"
[[package]]
name = "strum_macros"
version = "0.23.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5bb0dc7ee9c15cea6199cde9a127fa16a4c5819af85395457ad72d68edc85a38"
dependencies = [
"heck",
"proc-macro2",
"quote",
"rustversion",
"syn",
]
[[package]]
name = "syn"
version = "1.0.84"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ecb2e6da8ee5eb9a61068762a32fa9619cc591ceb055b3687f4cd4051ec2e06b"
dependencies = [
"proc-macro2",
"quote",
"unicode-xid",
]
[[package]]
name = "to-syn-value"
version = "0.1.0"
dependencies = [
"syn",
"to-syn-value_derive",
]
[[package]]
name = "to-syn-value_derive"
version = "0.1.0"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "unicode-segmentation"
version = "1.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8895849a949e7845e06bd6dc1aa51731a103c42707010a5b591c0038fb73385b"
[[package]]
name = "unicode-xid"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"

View File

@@ -1,14 +0,0 @@
[package]
name = "instructions-template"
version = "0.1.0"
edition = "2021"
[dependencies]
indexmap = "*"
proc-macro2 = "*"
quote = "*"
strum = "0.23"
strum_macros = "0.23"
syn = { version = "*", features = ['full', 'visit', 'extra-traits'] }
to-syn-value = { path = "../to-syn-value" }
to-syn-value_derive = { path = "../to-syn-value_derive" }

View File

@@ -1,18 +0,0 @@
[package]
name = "num-rug-adapter"
version = "0.1.5"
authors = ["Marco A L Barbosa <malbarbo@gmail.com>"]
edition = "2021"
description = "An adapter to use num crate where rug is needed."
license = "MIT/Apache-2.0"
repository = "https://github.com/malbarbo/num-rug-adapter"
keywords = ["mathematics", "numerics", "bignum"]
categories = ["api-bindings", "science"]
readme = "README.md"
[dependencies]
libc = "0.2"
num-bigint = "0.2"
num-integer = "0.1.41"
num-rational = "0.2"
num-traits = "0.2"

View File

@@ -1,888 +0,0 @@
use num_bigint::{BigInt, ParseBigIntError};
use num_integer::Integer as _;
use num_rational::BigRational;
use num_traits::{FromPrimitive, Num, Signed, ToPrimitive};
use num_traits::identities::One;
use std::cmp::Ordering;
use std::fmt::{self, Display, Formatter};
use std::ops::*;
use std::str::FromStr;
#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct Integer(BigInt);
impl Integer {
#[inline]
pub fn new() -> Self {
Integer(BigInt::default())
}
#[inline]
pub fn from_str_radix(s: &str, radix: u32) -> Result<Self, ParseBigIntError> {
BigInt::from_str_radix(s, radix).map(Integer)
}
#[inline]
pub fn to_u8(&self) -> Option<u8> {
self.0.to_u8()
}
#[inline]
pub fn to_u32(&self) -> Option<u32> {
self.0.to_u32()
}
#[inline]
pub fn to_u64(&self) -> Option<u64> {
self.0.to_u64()
}
#[inline]
pub fn to_usize(&self) -> Option<usize> {
self.0.to_usize()
}
#[inline]
pub fn to_i32(&self) -> Option<i32> {
self.0.to_i32()
}
#[inline]
pub fn to_isize(&self) -> Option<isize> {
self.0.to_isize()
}
#[inline]
pub fn to_f64(&self) -> f64 {
self.0.to_f64().unwrap()
}
#[inline]
pub fn abs(&self) -> Self {
Integer(self.0.abs())
}
#[inline]
pub fn abs_ref(&self) -> Self {
Integer(self.0.abs())
}
#[inline]
pub fn div_rem(&self, other: Self) -> (Self, Self) {
let (a, b) = num_integer::Integer::div_rem(&self.0, &other.0);
(Integer(a), Integer(b))
}
#[inline]
pub fn div_rem_ref(&self, other: &Self) -> (Self, Self) {
let (a, b) = num_integer::Integer::div_rem(&self.0, &other.0);
(Integer(a), Integer(b))
}
#[inline]
pub fn div_rem_floor(&self, other: Self) -> (Self, Self) {
let (a, b) = num_integer::Integer::div_mod_floor(&self.0, &other.0);
(Integer(a), Integer(b))
}
#[inline]
pub fn div_rem_floor_ref(&self, other: &Self) -> (Self, Self) {
let (a, b) = num_integer::Integer::div_mod_floor(&self.0, &other.0);
(Integer(a), Integer(b))
}
#[inline]
pub fn mod_u(&self, modulo: u32) -> u32 {
(self.0.abs() % modulo).to_u32().unwrap()
}
#[inline]
pub fn is_odd(&self) -> bool {
num_integer::Integer::is_odd(&self.0)
}
#[inline]
pub fn from_f64(v: f64) -> Option<Self> {
BigInt::from_f64(v).map(Integer)
}
#[inline]
pub fn gcd_ref(&self, other: &Self) -> Self {
Integer(num_integer::Integer::gcd(&self.0, &other.0))
}
#[inline]
pub fn gcd(&self, other: &Self) -> Self {
Integer(num_integer::Integer::gcd(&self.0, &other.0))
}
#[inline]
pub fn count_ones(&self) -> Option<u32> {
Some(self.0.to_u32_digits().1.iter().map(|&d| d.count_ones()).sum())
}
}
impl From<&Integer> for Integer {
#[inline]
fn from(s: &Integer) -> Self {
s.clone()
}
}
impl From<i32> for Integer {
#[inline]
fn from(s: i32) -> Self {
Integer(BigInt::from(s))
}
}
impl From<isize> for Integer {
#[inline]
fn from(s: isize) -> Self {
Integer(BigInt::from(s))
}
}
impl From<u8> for Integer {
#[inline]
fn from(s: u8) -> Self {
Integer(BigInt::from(s))
}
}
impl From<u32> for Integer {
#[inline]
fn from(s: u32) -> Self {
Integer(BigInt::from(s))
}
}
impl From<u64> for Integer {
#[inline]
fn from(s: u64) -> Self {
Integer(BigInt::from(s))
}
}
impl From<usize> for Integer {
#[inline]
fn from(s: usize) -> Self {
Integer(BigInt::from(s))
}
}
impl Mul for Integer {
type Output = Integer;
#[inline]
fn mul(self, other: Integer) -> Self::Output {
Integer(self.0 * other.0)
}
}
impl Mul<u32> for Integer {
type Output = Integer;
#[inline]
fn mul(self, other: u32) -> Self::Output {
Integer(self.0 * other)
}
}
impl Mul<&Integer> for Integer {
type Output = Integer;
fn mul(self, other: &Integer) -> Self::Output {
Integer(self.0 * &other.0)
}
}
impl MulAssign<&Integer> for Integer {
#[inline]
fn mul_assign(&mut self, other: &Integer) {
self.0 *= &other.0;
}
}
impl Add for Integer {
type Output = Integer;
#[inline]
fn add(self, other: Integer) -> Self::Output {
Integer(self.0 + other.0)
}
}
impl Add<Integer> for &Integer {
type Output = Integer;
#[inline]
fn add(self, other: Integer) -> Self::Output {
Integer(&self.0 + other.0)
}
}
impl Add<&Integer> for Integer {
type Output = Integer;
#[inline]
fn add(self, other: &Integer) -> Self::Output {
Integer(self.0 + &other.0)
}
}
impl Add<&Integer> for &Integer {
type Output = Integer;
#[inline]
fn add(self, other: &Integer) -> Self::Output {
Integer(&self.0 + &other.0)
}
}
impl AddAssign<i64> for Integer {
#[inline]
fn add_assign(&mut self, other: i64) {
self.0 += other;
}
}
impl AddAssign<&Integer> for Integer {
#[inline]
fn add_assign(&mut self, other: &Integer) {
self.0 += &other.0;
}
}
impl Div for Integer {
type Output = Integer;
#[inline]
fn div(self, other: Integer) -> Integer {
Integer(self.0 / other.0)
}
}
impl Div<&Integer> for Integer {
type Output = Integer;
#[inline]
fn div(self, other: &Integer) -> Integer {
Integer(self.0 / &other.0)
}
}
impl Div<Integer> for &Integer {
type Output = Integer;
#[inline]
fn div(self, other: Integer) -> Integer {
Integer(&self.0 / &other.0)
}
}
impl Shr<u32> for Integer {
type Output = Integer;
#[inline]
fn shr(self, rhs: u32) -> Self::Output {
Integer(self.0 >> rhs as usize)
}
}
impl Shr<u32> for &Integer {
type Output = Integer;
#[inline]
fn shr(self, rhs: u32) -> Self::Output {
Integer(&self.0 >> rhs as usize)
}
}
impl ShrAssign<u32> for Integer {
#[inline]
fn shr_assign(&mut self, rhs: u32) {
self.0 >>= rhs as usize;
}
}
impl Shl<u32> for Integer {
type Output = Integer;
#[inline]
fn shl(self, rhs: u32) -> Self::Output {
Integer(self.0 << rhs as usize)
}
}
impl Shl<u32> for &Integer {
type Output = Integer;
#[inline]
fn shl(self, rhs: u32) -> Self::Output {
Integer(&self.0 << rhs as usize)
}
}
impl Not for Integer {
type Output = Integer;
#[inline]
fn not(self) -> Self::Output {
Integer(!self.0)
}
}
impl Not for &Integer {
type Output = Integer;
#[inline]
fn not(self) -> Self::Output {
Integer(!&self.0)
}
}
impl Rem for Integer {
type Output = Integer;
#[inline]
fn rem(self, other: Integer) -> Self::Output {
Integer(self.0.mod_floor(&other.0))
}
}
impl Rem<&Integer> for Integer {
type Output = Integer;
#[inline]
fn rem(self, other: &Integer) -> Self::Output {
Integer(self.0.mod_floor(&other.0))
}
}
impl Rem<&Integer> for &Integer {
type Output = Integer;
#[inline]
fn rem(self, other: &Integer) -> Self::Output {
Integer(self.0.mod_floor(&other.0))
}
}
impl Rem<Integer> for &Integer {
type Output = Integer;
#[inline]
fn rem(self, other: Integer) -> Self::Output {
Integer(self.0.mod_floor(&other.0))
}
}
impl BitAnd for Integer {
type Output = Integer;
#[inline]
fn bitand(self, other: Integer) -> Self::Output {
Integer(self.0 & &other.0)
}
}
impl BitAnd<&Integer> for Integer {
type Output = Integer;
#[inline]
fn bitand(self, other: &Integer) -> Self::Output {
Integer(self.0 & &other.0)
}
}
impl BitAnd<Integer> for &Integer {
type Output = Integer;
#[inline]
fn bitand(self, other: Integer) -> Self::Output {
Integer(&self.0 & other.0)
}
}
impl BitAnd for &Integer {
type Output = Integer;
#[inline]
fn bitand(self, other: &Integer) -> Self::Output {
Integer(&self.0 & &other.0)
}
}
impl BitOr for Integer {
type Output = Integer;
#[inline]
fn bitor(self, other: Integer) -> Self::Output {
Integer(self.0 | other.0)
}
}
impl BitOr<&Integer> for Integer {
type Output = Integer;
#[inline]
fn bitor(self, other: &Integer) -> Self::Output {
Integer(self.0 | &other.0)
}
}
impl BitOr<Integer> for &Integer {
type Output = Integer;
#[inline]
fn bitor(self, other: Integer) -> Self::Output {
Integer(&self.0 | other.0)
}
}
impl BitOr for &Integer {
type Output = Integer;
#[inline]
fn bitor(self, other: &Integer) -> Self::Output {
Integer(&self.0 | &other.0)
}
}
impl BitXor for Integer {
type Output = Integer;
#[inline]
fn bitxor(self, other: Integer) -> Self::Output {
Integer(self.0 ^ other.0)
}
}
impl BitXor<&Integer> for Integer {
type Output = Integer;
#[inline]
fn bitxor(self, other: &Integer) -> Self::Output {
Integer(self.0 ^ &other.0)
}
}
impl BitXor<Integer> for &Integer {
type Output = Integer;
#[inline]
fn bitxor(self, other: Integer) -> Self::Output {
Integer(&self.0 ^ other.0)
}
}
impl BitXor<&Integer> for &Integer {
type Output = Integer;
#[inline]
fn bitxor(self, other: &Integer) -> Self::Output {
Integer(&self.0 ^ &other.0)
}
}
impl PartialEq<i32> for Integer {
#[inline]
fn eq(&self, other: &i32) -> bool {
self.0 == BigInt::from(*other)
}
}
impl PartialEq<i64> for Integer {
#[inline]
fn eq(&self, other: &i64) -> bool {
self.0 == BigInt::from(*other)
}
}
impl PartialEq<isize> for Integer {
#[inline]
fn eq(&self, other: &isize) -> bool {
self.0 == BigInt::from(*other)
}
}
impl PartialEq<usize> for Integer {
#[inline]
fn eq(&self, other: &usize) -> bool {
self.0 == BigInt::from(*other)
}
}
impl PartialEq<Integer> for isize {
#[inline]
fn eq(&self, other: &Integer) -> bool {
other.0 == BigInt::from(*self)
}
}
impl PartialOrd<i32> for Integer {
#[inline]
fn partial_cmp(&self, other: &i32) -> Option<Ordering> {
self.0.partial_cmp(&BigInt::from(*other))
}
}
impl PartialOrd<i64> for Integer {
#[inline]
fn partial_cmp(&self, other: &i64) -> Option<Ordering> {
self.0.partial_cmp(&BigInt::from(*other))
}
}
impl PartialOrd<isize> for Integer {
#[inline]
fn partial_cmp(&self, other: &isize) -> Option<Ordering> {
self.0.partial_cmp(&BigInt::from(*other))
}
}
impl PartialOrd<usize> for Integer {
#[inline]
fn partial_cmp(&self, other: &usize) -> Option<Ordering> {
self.0.partial_cmp(&BigInt::from(*other))
}
}
impl FromStr for Integer {
type Err = <BigInt as FromStr>::Err;
#[inline]
fn from_str(s: &str) -> Result<Self, Self::Err> {
Ok(Integer(s.parse()?))
}
}
impl Neg for Integer {
type Output = Integer;
#[inline]
fn neg(self) -> Self {
Integer(-self.0)
}
}
impl Display for Integer {
#[inline]
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
write!(f, "{}", self.0)
}
}
// Rational
#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct Rational(BigRational);
impl Rational {
#[inline]
pub fn new() -> Self {
Rational(BigRational::from(BigInt::default()))
}
#[inline]
pub fn from_f64(v: f64) -> Option<Self> {
BigRational::from_f64(v).map(Rational)
}
#[inline]
pub fn to_f64(&self) -> f64 {
self.0.numer().to_f64().unwrap() / self.0.denom().to_f64().unwrap()
}
#[inline]
pub fn numer(&self) -> &Integer {
unsafe { ::std::mem::transmute(self.0.numer()) }
}
#[inline]
pub fn denom(&self) -> &Integer {
unsafe { ::std::mem::transmute(self.0.denom()) }
}
#[inline]
pub fn abs(self) -> Self {
Rational(self.0.abs())
}
#[inline]
pub fn abs_ref(&self) -> Self {
Rational(self.0.abs())
}
#[inline]
pub fn fract_floor_ref(&self) -> &Self {
panic!()
}
}
impl From<isize> for Rational {
#[inline]
fn from(s: isize) -> Self {
Rational(BigRational::new_raw(BigInt::from(s), One::one()))
}
}
impl From<&Integer> for Rational {
#[inline]
fn from(s: &Integer) -> Self {
Rational::from(s.clone())
}
}
impl From<&Rational> for Rational {
#[inline]
fn from(s: &Rational) -> Self {
s.clone()
}
}
impl From<Integer> for Rational {
#[inline]
fn from(i: Integer) -> Self {
Rational(BigRational::from(i.0))
}
}
impl Add for Rational {
type Output = Rational;
#[inline]
fn add(self, other: Rational) -> Self::Output {
Rational(self.0 + other.0)
}
}
impl Add<&Rational> for Rational {
type Output = Rational;
#[inline]
fn add(self, other: &Rational) -> Self::Output {
Rational(self.0 + &other.0)
}
}
impl PartialEq<i32> for Rational {
#[inline]
fn eq(&self, other: &i32) -> bool {
self.0 == BigRational::from(BigInt::from(*other))
}
}
impl PartialEq<i64> for Rational {
#[inline]
fn eq(&self, other: &i64) -> bool {
self.0 == BigRational::from(BigInt::from(*other))
}
}
impl PartialEq<isize> for Rational {
#[inline]
fn eq(&self, other: &isize) -> bool {
self == &Rational::from(*other)
}
}
impl PartialEq<Rational> for isize {
#[inline]
fn eq(&self, other: &Rational) -> bool {
other == &Rational::from(*self)
}
}
impl PartialOrd<isize> for Rational {
#[inline]
fn partial_cmp(&self, other: &isize) -> Option<Ordering> {
self.0.partial_cmp(&BigRational::from(BigInt::from(*other)))
}
}
impl PartialOrd<i64> for Rational {
#[inline]
fn partial_cmp(&self, other: &i64) -> Option<Ordering> {
self.0.partial_cmp(&BigRational::from(BigInt::from(*other)))
}
}
impl PartialOrd<i32> for Rational {
#[inline]
fn partial_cmp(&self, other: &i32) -> Option<Ordering> {
self.0.partial_cmp(&BigRational::from(BigInt::from(*other)))
}
}
impl Neg for Rational {
type Output = Rational;
#[inline]
fn neg(self) -> Self {
Rational(-self.0)
}
}
impl Mul for Rational {
type Output = Rational;
#[inline]
fn mul(self, other: Rational) -> Self::Output {
Rational(self.0 * other.0)
}
}
impl Mul<&Rational> for Rational {
type Output = Rational;
fn mul(self, other: &Rational) -> Self::Output {
Rational(self.0 * &other.0)
}
}
impl Div for Rational {
type Output = Rational;
#[inline]
fn div(self, other: Rational) -> Self::Output {
Rational(self.0 / other.0)
}
}
impl Div<&Rational> for &Rational {
type Output = Rational;
#[inline]
fn div(self, other: &Rational) -> Self::Output {
Rational(&self.0 / &other.0)
}
}
impl Display for Rational {
#[inline]
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
write!(f, "{}", self.0)
}
}
pub trait Assign<Src = Self> {
fn assign(&mut self, src: Src);
}
impl Assign<&Rational> for (&mut Rational, &mut Integer) {
fn assign(&mut self, _src: &Rational) {
panic!()
}
}
pub mod ops {
use super::{Integer, Rational};
pub trait Pow<Rhs> {
type Output;
fn pow(self, rhs: Rhs) -> Self::Output;
}
impl Pow<u32> for Integer {
type Output = Integer;
fn pow(self, rhs: u32) -> Self::Output {
Integer(num_traits::Pow::pow(&self.0, rhs))
}
}
pub trait PowAssign<Rhs> {
fn pow_assign(&mut self, rhs: Rhs);
}
impl PowAssign<u32> for Integer {
fn pow_assign(&mut self, rhs: u32) {
// FIXME: make it efficient
self.0 = num_traits::Pow::pow(&self.0, rhs);
}
}
pub trait NegAssign {
fn neg_assign(&mut self);
}
impl NegAssign for Integer {
fn neg_assign(&mut self) {
self.0 = -std::mem::replace(self, Integer::new()).0;
}
}
impl NegAssign for Rational {
#[inline]
fn neg_assign(&mut self) {
self.0 = -std::mem::replace(self, Rational::new()).0;
}
}
}
pub mod rand {
use super::Integer;
use std::marker::PhantomData;
pub struct RandState<'a>{
_marker: PhantomData<&'a ()>,
}
impl<'a> RandState<'a> {
pub fn new() -> Self {
unsafe { libc::srand(libc::time(std::ptr::null_mut()) as _) };
RandState { _marker: PhantomData }
}
pub fn borrow_mut(&self) -> &Self {
self
}
pub fn bits(&mut self, bits: u32) -> u32 {
assert!(bits <= 32);
(unsafe { libc::rand() } as u32) & (u32::max_value() >> (32 - bits))
}
pub fn seed(&mut self, seed: &Integer) {
unsafe { libc::srand(seed.to_f64() as _)}
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use super::ops::NegAssign;
#[test]
fn bits() {
let mut rand = rand::RandState::new();
for bits in 1..32 {
for _ in 0..100 {
let r = rand.bits(bits);
let max = 1 << bits;
assert!(max > r, "{} > {}", max, r);
}
}
}
#[test]
fn neg_rational() {
let mut x = Rational::from_f64(5.0).unwrap();
let x_neg = Rational::from_f64(-5.0).unwrap();
x.neg_assign();
assert_eq!(x, x_neg);
}
#[test]
fn neg_integer() {
let mut x = Integer::from(5);
let x_neg = Integer::from(-5);
x.neg_assign();
assert_eq!(x, x_neg);
}
}

View File

@@ -1,11 +0,0 @@
[package]
name = "static-string-indexing"
version = "0.1.0"
edition = "2021"
[dependencies]
proc-macro2 = "*"
syn = { version = "*", features = ['full', 'visit', 'extra-traits'] }
indexmap = "*"
walkdir = "2"
quote = "*"

View File

@@ -1,10 +0,0 @@
[package]
name = "to-syn-value"
version = "0.1.0"
authors = ["Mark Thom <markjordanthom@gmail.com>"]
edition = "2021"
publish = false
[dependencies]
syn = { version = "*", features = ['full', 'visit', 'extra-traits'] }
to-syn-value_derive = { path = "../to-syn-value_derive" }

View File

@@ -1,3 +0,0 @@
pub trait ToDeriveInput {
fn to_derive_input() -> syn::DeriveInput;
}

View File

@@ -1,14 +0,0 @@
[package]
name = "to-syn-value_derive"
version = "0.1.0"
authors = ["Mark Thom <markjordanthom@gmail.com>"]
edition = "2021"
publish = false
[lib]
proc-macro = true
[dependencies]
proc-macro2 = "*"
syn = { version = "*", features = ['full', 'visit', 'extra-traits'] }
quote = "*"

View File

@@ -1,20 +0,0 @@
use syn::*;
use quote::*;
#[proc_macro_derive(ToDeriveInput)]
pub fn derive_to_derive_input(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
let derive_input = parse_macro_input!(input as DeriveInput);
let ty_name = derive_input.ident.clone();
quote! {
use to_syn_value::*;
impl ToDeriveInput for #ty_name {
fn to_derive_input() -> syn::DeriveInput {
syn::parse_quote! {
#derive_input
}
}
}
}.into()
}

31
scryer-prolog.wxs Normal file
View File

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

View File

@@ -59,6 +59,7 @@ pub(crate) trait Allocator {
fn bindings_mut(&mut self) -> &mut AllocVarDict; fn bindings_mut(&mut self) -> &mut AllocVarDict;
fn take_bindings(self) -> AllocVarDict; fn take_bindings(self) -> AllocVarDict;
fn max_reg_allocated(&self) -> usize;
fn drain_var_data<'a>( fn drain_var_data<'a>(
&mut self, &mut self,

View File

@@ -1,11 +1,12 @@
use crate::http::{HttpListener, HttpResponse};
use crate::machine::loader::LiveLoadState; 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::read::*; use crate::read::*;
use modular_bitfield::prelude::*;
use ordered_float::OrderedFloat; use ordered_float::OrderedFloat;
use rug::{Integer, Rational}; use crate::parser::rug::{Integer, Rational};
use std::alloc; use std::alloc;
use std::fmt; use std::fmt;
@@ -20,14 +21,116 @@ 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 { $arena.alloc(result) } unsafe { ArenaAllocated::alloc($arena, result) }
}}; }};
} }
#[macro_export]
macro_rules! float_alloc {
($e:expr, $arena:expr) => {{
let result = $e;
#[allow(unused_unsafe)]
unsafe { $arena.f64_tbl.build_with(result) }
}};
}
#[cfg(test)]
use std::cell::RefCell;
const F64_TABLE_INIT_SIZE: usize = 1 << 16;
const F64_TABLE_ALIGN: usize = 8;
#[cfg(test)]
thread_local! {
static F64_TABLE_BUF_BASE: RefCell<*const u8> = RefCell::new(ptr::null_mut());
}
#[cfg(not(test))]
static mut F64_TABLE_BUF_BASE: *const u8 = ptr::null_mut();
impl RawBlockTraits for F64Table {
#[inline]
fn init_size() -> usize {
F64_TABLE_INIT_SIZE
}
#[inline]
fn align() -> usize {
F64_TABLE_ALIGN
}
}
#[derive(Debug)]
pub struct F64Table {
block: RawBlock<F64Table>,
}
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)]
pub fn lookup_float(offset: usize) -> *mut OrderedFloat<f64> {
let base = get_f64_tbl_buf_base() as usize;
(base + offset) as *mut _
}
impl F64Table {
#[inline]
pub fn new() -> Self {
let table = Self { block: RawBlock::new() };
set_f64_tbl_buf_base(table.block.base);
table
}
pub unsafe fn build_with(&mut self, value: f64) -> F64Ptr {
let mut ptr;
loop {
ptr = self.block.alloc(mem::size_of::<f64>());
if ptr.is_null() {
self.block.grow();
set_f64_tbl_buf_base(self.block.base);
} else {
break;
}
}
ptr::write(ptr as *mut OrderedFloat<f64>, OrderedFloat(value));
F64Ptr(ptr::NonNull::new_unchecked(ptr as *mut _))
}
}
#[derive(BitfieldSpecifier, Copy, Clone, Debug, PartialEq)] #[derive(BitfieldSpecifier, Copy, Clone, Debug, PartialEq)]
#[bits = 7] #[bits = 7]
pub enum ArenaHeaderTag { pub enum ArenaHeaderTag {
F64 = 0b01,
Integer = 0b10, Integer = 0b10,
Rational = 0b11, Rational = 0b11,
OssifiedOpDir = 0b0000100, OssifiedOpDir = 0b0000100,
@@ -37,6 +140,8 @@ pub enum ArenaHeaderTag {
OutputFileStream = 0b10100, OutputFileStream = 0b10100,
NamedTcpStream = 0b011100, NamedTcpStream = 0b011100,
NamedTlsStream = 0b100000, NamedTlsStream = 0b100000,
HttpReadStream = 0b100001,
HttpWriteStream = 0b100010,
ReadlineStream = 0b110000, ReadlineStream = 0b110000,
StaticStringStream = 0b110100, StaticStringStream = 0b110100,
ByteStream = 0b111000, ByteStream = 0b111000,
@@ -44,7 +149,13 @@ pub enum ArenaHeaderTag {
StandardErrorStream = 0b11000, StandardErrorStream = 0b11000,
NullStream = 0b111100, NullStream = 0b111100,
TcpListener = 0b1000000, TcpListener = 0b1000000,
HttpListener = 0b1000001,
HttpResponse = 0b1000010,
Dropped = 0b1000100, Dropped = 0b1000100,
IndexPtrDynamicUndefined = 0b1000101,
IndexPtrDynamicIndex = 0b1000110,
IndexPtrIndex = 0b1000111,
IndexPtrUndefined = 0b1001000,
} }
#[bitfield] #[bitfield]
@@ -72,9 +183,15 @@ impl ArenaHeader {
} }
} }
#[derive(Debug, PartialOrd, Ord)] #[derive(Debug)]
pub struct TypedArenaPtr<T: ?Sized>(ptr::NonNull<T>); pub struct TypedArenaPtr<T: ?Sized>(ptr::NonNull<T>);
impl<T: ?Sized + PartialOrd> PartialOrd for TypedArenaPtr<T> {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
(**self).partial_cmp(&**other)
}
}
impl<T: ?Sized + PartialEq> PartialEq for TypedArenaPtr<T> { impl<T: ?Sized + PartialEq> PartialEq for TypedArenaPtr<T> {
fn eq(&self, other: &TypedArenaPtr<T>) -> bool { fn eq(&self, other: &TypedArenaPtr<T>) -> bool {
self.0 == other.0 || &**self == &**other self.0 == other.0 || &**self == &**other
@@ -83,6 +200,12 @@ impl<T: ?Sized + PartialEq> PartialEq for TypedArenaPtr<T> {
impl<T: ?Sized + PartialEq> Eq for TypedArenaPtr<T> {} impl<T: ?Sized + PartialEq> Eq for TypedArenaPtr<T> {}
impl<T: ?Sized + Ord> Ord for TypedArenaPtr<T> {
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
(**self).cmp(&**other)
}
}
impl<T: ?Sized + Hash> Hash for TypedArenaPtr<T> { impl<T: ?Sized + Hash> Hash for TypedArenaPtr<T> {
#[inline(always)] #[inline(always)]
fn hash<H: Hasher>(&self, hasher: &mut H) { fn hash<H: Hasher>(&self, hasher: &mut H) {
@@ -118,7 +241,7 @@ impl<T: fmt::Display> fmt::Display for TypedArenaPtr<T> {
} }
} }
impl<T: ?Sized> TypedArenaPtr<T> { impl<T: ?Sized + ArenaAllocated> TypedArenaPtr<T> {
#[inline] #[inline]
pub const fn new(data: *mut T) -> Self { pub const fn new(data: *mut T) -> Self {
unsafe { TypedArenaPtr(ptr::NonNull::new_unchecked(data)) } unsafe { TypedArenaPtr(ptr::NonNull::new_unchecked(data)) }
@@ -132,14 +255,14 @@ impl<T: ?Sized> TypedArenaPtr<T> {
#[inline] #[inline]
pub fn header_ptr(&self) -> *const ArenaHeader { pub fn header_ptr(&self) -> *const ArenaHeader {
let mut ptr = self.as_ptr() as *const u8 as usize; let mut ptr = self.as_ptr() as *const u8 as usize;
ptr -= mem::size_of::<*const ArenaHeader>(); ptr -= T::header_offset_from_payload(); // mem::size_of::<*const ArenaHeader>();
ptr as *const ArenaHeader ptr as *const ArenaHeader
} }
#[inline] #[inline]
fn header_ptr_mut(&mut self) -> *mut ArenaHeader { fn header_ptr_mut(&mut self) -> *mut ArenaHeader {
let mut ptr = self.as_ptr() as *const u8 as usize; let mut ptr = self.as_ptr() as *const u8 as usize;
ptr -= mem::size_of::<*const ArenaHeader>(); ptr -= T::header_offset_from_payload(); // mem::size_of::<*const ArenaHeader>();
ptr as *mut ArenaHeader ptr as *mut ArenaHeader
} }
@@ -173,18 +296,66 @@ impl<T: ?Sized> TypedArenaPtr<T> {
} }
} }
pub trait ArenaAllocated { pub trait ArenaAllocated: Sized {
type PtrToAllocated; type PtrToAllocated;
fn tag() -> ArenaHeaderTag; fn tag() -> ArenaHeaderTag;
fn size(&self) -> usize; fn size(&self) -> usize;
fn copy_to_arena(self, dst: *mut Self) -> Self::PtrToAllocated fn copy_to_arena(self, dst: *mut Self) -> Self::PtrToAllocated;
where
Self: Sized; fn header_offset_from_payload() -> usize {
mem::size_of::<*const ArenaHeader>()
}
unsafe fn alloc(arena: &mut Arena, value: Self) -> Self::PtrToAllocated {
let size = value.size() + mem::size_of::<AllocSlab>();
let align = mem::align_of::<AllocSlab>();
let layout = alloc::Layout::from_size_align_unchecked(size, align);
let slab = alloc::alloc(layout) as *mut AllocSlab;
(*slab).next = arena.base;
(*slab).header = ArenaHeader::build_with(value.size() as u64, Self::tag());
let offset = (*slab).payload_offset();
let result = value.copy_to_arena(offset as *mut Self);
arena.base = slab;
result
}
} }
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)] #[derive(Copy, Clone, Debug)]
pub struct F64Ptr(pub TypedArenaPtr<OrderedFloat<f64>>); pub struct F64Ptr(pub ptr::NonNull<OrderedFloat<f64>>);
impl PartialEq for F64Ptr {
fn eq(&self, other: &F64Ptr) -> bool {
self.0 == other.0 || &**self == &**other
}
}
impl Eq for F64Ptr {}
impl PartialOrd for F64Ptr {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
(**self).partial_cmp(&**other)
}
}
impl Ord for F64Ptr {
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
(**self).cmp(&**other)
}
}
impl Hash for F64Ptr {
#[inline(always)]
fn hash<H: Hasher>(&self, hasher: &mut H) {
(&*self as &OrderedFloat<f64>).hash(hasher)
}
}
impl fmt::Display for F64Ptr { impl fmt::Display for F64Ptr {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
@@ -193,41 +364,94 @@ impl fmt::Display for F64Ptr {
} }
impl Deref for F64Ptr { impl Deref for F64Ptr {
type Target = TypedArenaPtr<OrderedFloat<f64>>; type Target = OrderedFloat<f64>;
#[inline] #[inline]
fn deref(&self) -> &Self::Target { fn deref(&self) -> &Self::Target {
&self.0 unsafe { &*self.0.as_ptr() }
} }
} }
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 {
&mut self.0 unsafe { &mut *self.0.as_ptr() }
} }
} }
impl ArenaAllocated for OrderedFloat<f64> { impl F64Ptr {
type PtrToAllocated = F64Ptr; #[inline(always)]
pub fn from_offset(offset: usize) -> Self {
#[inline]
fn tag() -> ArenaHeaderTag {
ArenaHeaderTag::F64
}
#[inline]
fn size(&self) -> usize {
mem::size_of::<Self>()
}
#[inline]
fn copy_to_arena(self, dst: *mut Self) -> Self::PtrToAllocated {
unsafe { unsafe {
ptr::write(dst, self); F64Ptr(ptr::NonNull::new_unchecked(lookup_float(offset)))
F64Ptr(TypedArenaPtr::new(dst as *mut Self))
} }
} }
#[inline(always)]
pub fn as_offset(&self) -> F64Offset {
F64Offset(self.0.as_ptr() as usize - get_f64_tbl_buf_base() as usize)
}
}
#[derive(Clone, Copy, Debug)]
pub struct F64Offset(usize);
impl F64Offset {
#[inline(always)]
pub fn new(offset: usize) -> Self {
Self(offset)
}
#[inline(always)]
pub fn from_ptr(ptr: F64Ptr) -> Self {
ptr.as_offset()
}
#[inline(always)]
pub fn as_ptr(self) -> F64Ptr {
F64Ptr::from_offset(self.0)
}
#[inline(always)]
pub fn to_u64(self) -> u64 {
self.0 as u64
}
}
impl PartialEq for F64Offset {
#[inline(always)]
fn eq(&self, other: &F64Offset) -> bool {
self.as_ptr() == other.as_ptr()
}
}
impl Eq for F64Offset {}
impl PartialOrd for F64Offset {
#[inline(always)]
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
self.as_ptr().partial_cmp(&other.as_ptr())
}
}
impl Ord for F64Offset {
#[inline(always)]
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
self.as_ptr().cmp(&other.as_ptr())
}
}
impl Hash for F64Offset {
#[inline(always)]
fn hash<H: Hasher>(&self, hasher: &mut H) {
self.as_ptr().hash(hasher)
}
}
impl fmt::Display for F64Offset {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "F64Offset({})", self.0)
}
} }
impl ArenaAllocated for Integer { impl ArenaAllocated for Integer {
@@ -340,6 +564,93 @@ impl ArenaAllocated for TcpListener {
} }
} }
impl ArenaAllocated for HttpListener {
type PtrToAllocated = TypedArenaPtr<HttpListener>;
#[inline]
fn tag() -> ArenaHeaderTag {
ArenaHeaderTag::HttpListener
}
#[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 HttpResponse {
type PtrToAllocated = TypedArenaPtr<HttpResponse>;
#[inline]
fn tag() -> ArenaHeaderTag {
ArenaHeaderTag::HttpResponse
}
#[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 IndexPtr {
type PtrToAllocated = TypedArenaPtr<IndexPtr>;
#[inline]
fn tag() -> ArenaHeaderTag {
ArenaHeaderTag::IndexPtrUndefined
}
#[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)
}
}
#[inline]
fn header_offset_from_payload() -> usize {
0
}
unsafe fn alloc(arena: &mut Arena, value: Self) -> Self::PtrToAllocated {
let size = mem::size_of::<AllocSlab>();
let align = mem::align_of::<AllocSlab>();
let layout = alloc::Layout::from_size_align_unchecked(size, align);
let slab = alloc::alloc(layout) as *mut AllocSlab;
(*slab).next = arena.base;
let result = value.copy_to_arena(mem::transmute::<_, *mut IndexPtr>(&(*slab).header));
arena.base = slab;
result
}
}
#[derive(Clone, Copy, Debug)] #[derive(Clone, Copy, Debug)]
struct AllocSlab { struct AllocSlab {
next: *mut AllocSlab, next: *mut AllocSlab,
@@ -347,7 +658,10 @@ struct AllocSlab {
} }
#[derive(Debug)] #[derive(Debug)]
pub struct Arena(*mut AllocSlab); pub struct Arena {
base: *mut AllocSlab,
pub f64_tbl: F64Table,
}
unsafe impl Send for Arena {} unsafe impl Send for Arena {}
unsafe impl Sync for Arena {} unsafe impl Sync for Arena {}
@@ -355,26 +669,7 @@ unsafe impl Sync for Arena {}
impl Arena { impl Arena {
#[inline] #[inline]
pub fn new() -> Self { pub fn new() -> Self {
Arena(ptr::null_mut()) Arena { base: ptr::null_mut(), f64_tbl: F64Table::new() }
}
pub unsafe fn alloc<T: ArenaAllocated>(&mut self, value: T) -> T::PtrToAllocated {
let size = value.size() + mem::size_of::<AllocSlab>();
let align = mem::align_of::<AllocSlab>();
let layout = alloc::Layout::from_size_align_unchecked(size, align);
let slab = alloc::alloc(layout) as *mut AllocSlab;
(*slab).next = self.0;
(*slab).header = ArenaHeader::build_with(value.size() as u64, T::tag());
let offset = (*slab).payload_offset();
let result = value.copy_to_arena(offset as *mut T);
self.0 = slab;
result
} }
} }
@@ -400,6 +695,12 @@ unsafe fn drop_slab_in_place(value: &mut AllocSlab) {
ArenaHeaderTag::NamedTlsStream => { ArenaHeaderTag::NamedTlsStream => {
ptr::drop_in_place(value.payload_offset::<StreamLayout<CharReader<NamedTlsStream>>>()); ptr::drop_in_place(value.payload_offset::<StreamLayout<CharReader<NamedTlsStream>>>());
} }
ArenaHeaderTag::HttpReadStream => {
ptr::drop_in_place(value.payload_offset::<StreamLayout<CharReader<HttpReadStream>>>());
}
ArenaHeaderTag::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>>());
} }
@@ -420,20 +721,28 @@ unsafe fn drop_slab_in_place(value: &mut AllocSlab) {
ArenaHeaderTag::TcpListener => { ArenaHeaderTag::TcpListener => {
ptr::drop_in_place(value.payload_offset::<TcpListener>()); ptr::drop_in_place(value.payload_offset::<TcpListener>());
} }
ArenaHeaderTag::HttpListener => {
ptr::drop_in_place(value.payload_offset::<HttpListener>());
}
ArenaHeaderTag::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::F64 | ArenaHeaderTag::NullStream => { ArenaHeaderTag::NullStream | ArenaHeaderTag::IndexPtrUndefined |
ArenaHeaderTag::IndexPtrDynamicUndefined | ArenaHeaderTag::IndexPtrDynamicIndex |
ArenaHeaderTag::IndexPtrIndex => {
} }
} }
} }
impl Drop for Arena { impl Drop for Arena {
fn drop(&mut self) { fn drop(&mut self) {
let mut ptr = self.0; let mut ptr = self.base;
while !ptr.is_null() { while !ptr.is_null() {
unsafe { unsafe {
@@ -452,7 +761,7 @@ impl Drop for Arena {
} }
} }
self.0 = ptr::null_mut(); self.base = ptr::null_mut();
} }
} }
@@ -479,27 +788,27 @@ mod tests {
use crate::machine::partial_string::*; use crate::machine::partial_string::*;
use ordered_float::OrderedFloat; use ordered_float::OrderedFloat;
use rug::{Integer, Rational}; use crate::parser::rug::{Integer, Rational};
#[test] #[test]
fn float_ptr_cast() { fn float_ptr_cast() {
let mut wam = MockWAM::new(); let mut wam = MockWAM::new();
let f = OrderedFloat(0f64); let f = 0f64;
let mut fp = arena_alloc!(f, &mut wam.machine_st.arena); let fp = float_alloc!(f, wam.machine_st.arena);
let cell = HeapCellValue::from(fp); let mut cell = HeapCellValue::from(fp);
assert_eq!(cell.get_tag(), HeapCellValueTag::F64); assert_eq!(cell.get_tag(), HeapCellValueTag::F64);
assert_eq!(fp.get_mark_bit(), false); assert_eq!(cell.get_mark_bit(), false);
assert_eq!(**fp, f); assert_eq!(*fp, OrderedFloat(f));
fp.mark(); cell.set_mark_bit(true);
assert_eq!(fp.get_mark_bit(), true); assert_eq!(cell.get_mark_bit(), true);
read_heap_cell!(cell, read_heap_cell!(cell,
(HeapCellValueTag::F64, ptr) => { (HeapCellValueTag::F64, ptr) => {
assert_eq!(**ptr, f) assert_eq!(OrderedFloat(*ptr), OrderedFloat(f))
} }
_ => { unreachable!() } _ => { unreachable!() }
); );
@@ -542,8 +851,9 @@ mod tests {
// integer // integer
let big_int = 2 * Integer::from(1u64 << 63); let big_int: Integer = 2 * Integer::from(1u64 << 63);
let big_int_ptr: TypedArenaPtr<Integer> = arena_alloc!(big_int, &mut wam.machine_st.arena); let big_int_ptr: TypedArenaPtr<Integer> =
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());
@@ -696,16 +1006,16 @@ mod tests {
_ => { unreachable!() } _ => { unreachable!() }
); );
let fixnum_b_cell = fixnum_as_cell!(Fixnum::build_with(1 << 55)); let fixnum_b_cell = fixnum_as_cell!(Fixnum::build_with(1 << 54));
assert_eq!(fixnum_b_cell.get_tag(), HeapCellValueTag::Fixnum); assert_eq!(fixnum_b_cell.get_tag(), HeapCellValueTag::Fixnum);
match fixnum_b_cell.to_fixnum() { match fixnum_b_cell.to_fixnum() {
Some(n) => assert_eq!(n.get_num(), 1 << 55), Some(n) => assert_eq!(n.get_num(), 1 << 54),
None => assert!(false), None => assert!(false),
} }
match Fixnum::build_with_checked(1 << 57) { match Fixnum::build_with_checked(1 << 56) {
Ok(_) => assert!(false), Ok(_) => assert!(false),
_ => assert!(true), _ => assert!(true),
} }
@@ -725,17 +1035,17 @@ mod tests {
_ => assert!(false), _ => assert!(false),
} }
match Fixnum::build_with_checked((1 << 56) - 1) { match Fixnum::build_with_checked((1 << 55) - 1) {
Ok(n) => assert_eq!(n.get_num(), (1 << 56) - 1), Ok(n) => assert_eq!(n.get_num(), (1 << 55) - 1),
_ => assert!(false), _ => assert!(false),
} }
match Fixnum::build_with_checked(-(1 << 56)) { match Fixnum::build_with_checked(-(1 << 55)) {
Ok(n) => assert_eq!(n.get_num(), -(1 << 56)), Ok(n) => assert_eq!(n.get_num(), -(1 << 55)),
_ => assert!(false), _ => assert!(false),
} }
match Fixnum::build_with_checked(-(1 << 56) - 1) { match Fixnum::build_with_checked(-(1 << 55) - 1) {
Ok(_n) => assert!(false), Ok(_n) => assert!(false),
_ => assert!(true), _ => assert!(true),
} }
@@ -747,22 +1057,11 @@ mod tests {
// float // float
let float = OrderedFloat(3.1415926f64); let float = 3.1415926f64;
let float_ptr = arena_alloc!(float, &mut wam.machine_st.arena); let float_ptr = float_alloc!(float, wam.machine_st.arena);
let cell = HeapCellValue::from(float_ptr);
assert!(!float_ptr.as_ptr().is_null()); assert_eq!(cell.get_tag(), HeapCellValueTag::F64);
let float_cell = typed_arena_ptr_as_cell!(float_ptr);
assert_eq!(cell.get_tag(), HeapCellValueTag::Cons);
match float_cell.to_untyped_arena_ptr() {
Some(untyped_arena_ptr) => {
assert_eq!(Some(float_ptr.header_ptr()), Some(untyped_arena_ptr.into()),);
}
None => {
assert!(false); // we fail.
}
}
// char // char

View File

@@ -1,10 +1,11 @@
use crate::allocator::*; use crate::allocator::*;
use crate::arena::*; use crate::arena::*;
use crate::atom_table::*; use crate::atom_table::*;
use crate::fixtures::*; use crate::debray_allocator::*;
use crate::forms::*; use crate::forms::*;
use crate::instructions::*; use crate::instructions::*;
use crate::iterators::*; use crate::iterators::*;
use crate::targets::QueryInstruction;
use crate::types::*; use crate::types::*;
use crate::parser::ast::*; use crate::parser::ast::*;
@@ -12,7 +13,6 @@ use crate::parser::rug::ops::PowAssign;
use crate::parser::rug::{Assign, Integer, Rational}; use crate::parser::rug::{Assign, Integer, Rational};
use crate::machine::machine_errors::*; use crate::machine::machine_errors::*;
use crate::machine::machine_indices::*;
use ordered_float::*; use ordered_float::*;
@@ -64,21 +64,24 @@ impl<'a> ArithInstructionIterator<'a> {
fn from(term: &'a Term) -> Result<Self, ArithmeticError> { fn from(term: &'a Term) -> Result<Self, ArithmeticError> {
let state = match term { let state = match term {
Term::AnonVar => return Err(ArithmeticError::UninstantiatedVar), Term::AnonVar => return Err(ArithmeticError::UninstantiatedVar),
Term::Clause(cell, name, terms) => match ClauseType::from(*name, terms.len()) { Term::Clause(cell, name, terms) => {
TermIterState::Clause(Level::Shallow, 0, cell, *name, terms)
}
/* match ClauseType::from(*name, terms.len()) {
ct @ ClauseType::Named(..) => { ct @ ClauseType::Named(..) => {
Ok(TermIterState::Clause(Level::Shallow, 0, cell, ct, terms)) Ok(TermIterState::Clause(Level::Shallow, 0, cell, ct, terms))
} }
ClauseType::Inlined(InlinedClauseType::IsFloat(_)) => { ct @ ClauseType::Inlined(InlinedClauseType::IsFloat(_)) => {
let ct = ClauseType::Named(1, atom!("float"), CodeIndex::default()); // let ct = ClauseType::Named(1, atom!("float"), CodeIndex::default());
Ok(TermIterState::Clause(Level::Shallow, 0, cell, ct, terms)) Ok(TermIterState::Clause(Level::Shallow, 0, cell, ct, terms))
} }
_ => Err(ArithmeticError::NonEvaluableFunctor( _ => Err(ArithmeticError::NonEvaluableFunctor(
Literal::Atom(*name), Literal::Atom(*name),
terms.len(), terms.len(),
)), )),
}?, }?,*/
Term::Literal(cell, cons) => TermIterState::Literal(Level::Shallow, cell, cons), Term::Literal(cell, cons) => TermIterState::Literal(Level::Shallow, cell, cons),
Term::Cons(..) | Term::PartialString(..) => { Term::Cons(..) | Term::PartialString(..) | Term::CompleteString(..) => {
return Err(ArithmeticError::NonEvaluableFunctor( return Err(ArithmeticError::NonEvaluableFunctor(
Literal::Atom(atom!(".")), Literal::Atom(atom!(".")),
2, 2,
@@ -107,29 +110,26 @@ impl<'a> Iterator for ArithInstructionIterator<'a> {
while let Some(iter_state) = self.state_stack.pop() { while let Some(iter_state) = self.state_stack.pop() {
match iter_state { match iter_state {
TermIterState::AnonVar(_) => return Some(Err(ArithmeticError::UninstantiatedVar)), TermIterState::AnonVar(_) => return Some(Err(ArithmeticError::UninstantiatedVar)),
TermIterState::Clause(lvl, child_num, cell, ct, subterms) => { TermIterState::Clause(lvl, child_num, cell, name, subterms) => {
let arity = subterms.len(); let arity = subterms.len();
if child_num == arity { if child_num == arity {
return Some(Ok(ArithTermRef::Op(ct.name(), arity))); return Some(Ok(ArithTermRef::Op(name, arity)));
} else { } else {
self.state_stack.push(TermIterState::Clause( self.state_stack.push(TermIterState::Clause(
lvl, lvl,
child_num + 1, child_num + 1,
cell, cell,
ct, name,
subterms, subterms,
)); ));
self.push_subterm(lvl, &subterms[child_num]); self.push_subterm(lvl.child_level(), &subterms[child_num]);
} }
} }
TermIterState::Literal(_, _, c) => return Some(Ok(ArithTermRef::Literal(c))), TermIterState::Literal(_, _, c) => return Some(Ok(ArithTermRef::Literal(c))),
TermIterState::Var(lvl, cell, var) => { TermIterState::Var(lvl, cell, var) => {
// the expression is the second argument of an return Some(Ok(ArithTermRef::Var(lvl, cell, var.clone())));
// is/2 but the iterator can't see that, so the
// level needs to be demoted manually.
return Some(Ok(ArithTermRef::Var(lvl.child_level(), cell, var.clone())));
} }
_ => { _ => {
return Some(Err(ArithmeticError::NonEvaluableFunctor( return Some(Err(ArithmeticError::NonEvaluableFunctor(
@@ -145,8 +145,8 @@ impl<'a> Iterator for ArithInstructionIterator<'a> {
} }
#[derive(Debug)] #[derive(Debug)]
pub(crate) struct ArithmeticEvaluator<'a, TermMarker> { pub(crate) struct ArithmeticEvaluator<'a> {
marker: &'a mut TermMarker, marker: &'a mut DebrayAllocator,
interm: Vec<ArithmeticTerm>, interm: Vec<ArithmeticTerm>,
interm_c: usize, interm_c: usize,
} }
@@ -169,16 +169,16 @@ fn push_literal(interm: &mut Vec<ArithmeticTerm>, c: &Literal) -> Result<(), Ari
match c { match c {
Literal::Fixnum(n) => interm.push(ArithmeticTerm::Number(Number::Fixnum(*n))), Literal::Fixnum(n) => interm.push(ArithmeticTerm::Number(Number::Fixnum(*n))),
Literal::Integer(n) => interm.push(ArithmeticTerm::Number(Number::Integer(*n))), Literal::Integer(n) => interm.push(ArithmeticTerm::Number(Number::Integer(*n))),
Literal::Float(n) => interm.push(ArithmeticTerm::Number(Number::Float(***n))), 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(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(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(f64::EPSILON)), Number::Float(OrderedFloat(std::f64::EPSILON))
)), )),
_ => return Err(ArithmeticError::NonEvaluableFunctor(*c, 0)), _ => return Err(ArithmeticError::NonEvaluableFunctor(*c, 0)),
} }
@@ -186,8 +186,8 @@ fn push_literal(interm: &mut Vec<ArithmeticTerm>, c: &Literal) -> Result<(), Ari
Ok(()) Ok(())
} }
impl<'a, TermMarker: Allocator> ArithmeticEvaluator<'a, TermMarker> { impl<'a> ArithmeticEvaluator<'a> {
pub(crate) fn new(marker: &'a mut TermMarker, target_int: usize) -> Self { pub(crate) fn new(marker: &'a mut DebrayAllocator, target_int: usize) -> Self {
ArithmeticEvaluator { ArithmeticEvaluator {
marker, marker,
interm: Vec::new(), interm: Vec::new(),
@@ -315,10 +315,11 @@ impl<'a, TermMarker: Allocator> ArithmeticEvaluator<'a, TermMarker> {
} }
} }
pub(crate) fn eval( pub(crate) fn compile_is(
&mut self, &mut self,
src: &'a Term, src: &'a Term,
term_loc: GenContext, term_loc: GenContext,
arg: usize,
) -> Result<ArithCont, ArithmeticError> ) -> Result<ArithCont, ArithmeticError>
{ {
let mut code = vec![]; let mut code = vec![];
@@ -328,17 +329,15 @@ impl<'a, TermMarker: Allocator> ArithmeticEvaluator<'a, TermMarker> {
match term_ref? { match term_ref? {
ArithTermRef::Literal(c) => push_literal(&mut self.interm, c)?, ArithTermRef::Literal(c) => push_literal(&mut self.interm, c)?,
ArithTermRef::Var(lvl, cell, name) => { ArithTermRef::Var(lvl, cell, name) => {
let r = if cell.get().norm().reg_num() == 0 { let r = if lvl == Level::Shallow {
let mut getter = || { self.marker.mark_non_callable(
use crate::targets::QueryInstruction; name.clone(),
arg,
loop { term_loc,
match self.marker.bindings().get(&name) { cell,
Some(&VarData::Temp(_, t, _)) if t != 0 => &mut code,
return RegType::Temp(t), )
Some(&VarData::Perm(p)) if p != 0 => } else if term_loc.is_last() || cell.get().norm().reg_num() == 0 {
return RegType::Perm(p),
_ => {
self.marker.mark_var::<QueryInstruction>( self.marker.mark_var::<QueryInstruction>(
name.clone(), name.clone(),
lvl, lvl,
@@ -346,15 +345,8 @@ impl<'a, TermMarker: Allocator> ArithmeticEvaluator<'a, TermMarker> {
term_loc, term_loc,
&mut code, &mut code,
); );
}
}
}
};
getter() self.marker.get_binding(&name).unwrap()
/*
_ => return Err(ArithmeticError::UninstantiatedVar),
*/
} else { } else {
cell.get().norm() cell.get().norm()
}; };
@@ -374,16 +366,38 @@ impl<'a, TermMarker: Allocator> ArithmeticEvaluator<'a, TermMarker> {
// integer division rounding function -- 9.1.3.1. // integer division rounding function -- 9.1.3.1.
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(_) | &Number::Fixnum(_) => *n, &Number::Integer(i) => {
&Number::Float(OrderedFloat(f)) => fixnum!(Number, f.floor() as i64, arena), if let Some(n) = i.to_i64() {
fixnum!(Number, n, arena)
} else {
*n
}
}
&Number::Fixnum(_) => *n,
&Number::Float(f) => {
let f = f.floor();
const I64_MIN_TO_F: OrderedFloat<f64> = OrderedFloat(i64::MIN as f64);
const I64_MAX_TO_F: OrderedFloat<f64> = OrderedFloat(i64::MAX as f64);
if I64_MIN_TO_F <= f && f <= I64_MAX_TO_F {
fixnum!(Number, f.into_inner() as i64, arena)
} else {
Number::Integer(arena_alloc!(Integer::from_f64(f.into_inner()).unwrap(), arena))
}
}
&Number::Rational(ref r) => { &Number::Rational(ref r) => {
let r_ref = r.fract_floor_ref(); let r_ref = r.fract_floor_ref();
let (mut fract, mut floor) = (Rational::new(), Integer::new()); let (mut fract, mut floor) = (Rational::new(), Integer::new());
(&mut fract, &mut floor).assign(r_ref); (&mut fract, &mut floor).assign(r_ref);
if let Some(floor) = floor.to_i64() {
fixnum!(Number, floor, arena)
} else {
Number::Integer(arena_alloc!(floor, arena)) Number::Integer(arena_alloc!(floor, arena))
} }
} }
}
} }
impl From<Fixnum> for Integer { impl From<Fixnum> for Integer {
@@ -404,23 +418,14 @@ pub(crate) fn rnd_f(n: &Number) -> f64 {
} }
// floating point result function -- 9.1.4.2. // floating point result function -- 9.1.4.2.
pub(crate) fn result_f<Round>(n: &Number, round: Round) -> Result<f64, EvalError> pub(crate) fn result_f(n: &Number) -> Result<f64, EvalError> {
where classify_float(rnd_f(n))
Round: Fn(&Number) -> f64,
{
let f = rnd_f(n);
classify_float(f, round)
} }
fn classify_float<Round>(f: f64, round: Round) -> Result<f64, EvalError> fn classify_float(f: f64) -> Result<f64, EvalError> {
where
Round: Fn(&Number) -> f64,
{
match f.classify() { match f.classify() {
FpCategory::Normal | FpCategory::Zero => Ok(round(&Number::Float(OrderedFloat(f)))), FpCategory::Normal | FpCategory::Zero => Ok(f),
FpCategory::Infinite => { FpCategory::Infinite => {
let f = round(&Number::Float(OrderedFloat(f)));
if OrderedFloat(f) == OrderedFloat(f64::MAX) { if OrderedFloat(f) == OrderedFloat(f64::MAX) {
Ok(f) Ok(f)
} else { } else {
@@ -428,33 +433,33 @@ where
} }
} }
FpCategory::Nan => Err(EvalError::Undefined), FpCategory::Nan => Err(EvalError::Undefined),
_ => Ok(round(&Number::Float(OrderedFloat(f)))), _ => Ok(f)
} }
} }
#[inline] #[inline]
pub(crate) fn float_fn_to_f(n: i64) -> Result<f64, EvalError> { pub(crate) fn float_fn_to_f(n: i64) -> Result<f64, EvalError> {
classify_float(n as f64, rnd_f) classify_float(n as f64)
} }
#[inline] #[inline]
pub(crate) fn float_i_to_f(n: &Integer) -> Result<f64, EvalError> { pub(crate) fn float_i_to_f(n: &Integer) -> Result<f64, EvalError> {
classify_float(n.to_f64(), rnd_f) classify_float(n.to_f64())
} }
#[inline] #[inline]
pub(crate) fn float_r_to_f(r: &Rational) -> Result<f64, EvalError> { pub(crate) fn float_r_to_f(r: &Rational) -> Result<f64, EvalError> {
classify_float(r.to_f64(), rnd_f) classify_float(r.to_f64())
} }
#[inline] #[inline]
pub(crate) fn add_f(f1: f64, f2: f64) -> Result<OrderedFloat<f64>, EvalError> { pub(crate) fn add_f(f1: f64, f2: f64) -> Result<OrderedFloat<f64>, EvalError> {
Ok(OrderedFloat(classify_float(f1 + f2, rnd_f)?)) Ok(OrderedFloat(classify_float(f1 + f2)?))
} }
#[inline] #[inline]
pub(crate) fn mul_f(f1: f64, f2: f64) -> Result<OrderedFloat<f64>, EvalError> { pub(crate) fn mul_f(f1: f64, f2: f64) -> Result<OrderedFloat<f64>, EvalError> {
Ok(OrderedFloat(classify_float(f1 * f2, rnd_f)?)) Ok(OrderedFloat(classify_float(f1 * f2)?))
} }
#[inline] #[inline]
@@ -462,7 +467,7 @@ fn div_f(f1: f64, f2: f64) -> Result<OrderedFloat<f64>, EvalError> {
if FpCategory::Zero == f2.classify() { if FpCategory::Zero == f2.classify() {
Err(EvalError::ZeroDivisor) Err(EvalError::ZeroDivisor)
} else { } else {
Ok(OrderedFloat(classify_float(f1 / f2, rnd_f)?)) Ok(OrderedFloat(classify_float(f1 / f2)?))
} }
} }
@@ -672,9 +677,6 @@ impl TryFrom<HeapCellValue> for Number {
read_heap_cell!(value, read_heap_cell!(value,
(HeapCellValueTag::Cons, c) => { (HeapCellValueTag::Cons, c) => {
match_untyped_arena_ptr!(c, match_untyped_arena_ptr!(c,
(ArenaHeaderTag::F64, n) => {
Ok(Number::Float(*n))
}
(ArenaHeaderTag::Integer, n) => { (ArenaHeaderTag::Integer, n) => {
Ok(Number::Integer(n)) Ok(Number::Integer(n))
} }
@@ -687,7 +689,7 @@ impl TryFrom<HeapCellValue> for Number {
) )
} }
(HeapCellValueTag::F64, n) => { (HeapCellValueTag::F64, n) => {
Ok(Number::Float(**n)) Ok(Number::Float(*n))
} }
(HeapCellValueTag::Fixnum, n) => { (HeapCellValueTag::Fixnum, n) => {
Ok(Number::Fixnum(n)) Ok(Number::Fixnum(n))

View File

@@ -1,20 +1,11 @@
fn main() { fn main() {
use nix::sys::signal; use std::sync::atomic::Ordering;
use scryer_prolog::*; use scryer_prolog::*;
let handler = signal::SigHandler::Handler(handle_sigint); ctrlc::set_handler(move || {
unsafe { signal::signal(signal::Signal::SIGINT, handler) }.unwrap(); scryer_prolog::machine::INTERRUPT.store(true, Ordering::Relaxed);
}).unwrap();
let mut wam = machine::Machine::new(); let mut wam = machine::Machine::new();
wam.run_top_level(); wam.run_top_level();
} }
pub extern "C" fn handle_sigint(signal: libc::c_int) {
use nix::sys::signal;
use std::sync::atomic::Ordering;
let signal = signal::Signal::from_c_int(signal).unwrap();
if signal == signal::Signal::SIGINT {
scryer_prolog::machine::INTERRUPT.store(true, Ordering::Relaxed);
}
}

View File

@@ -4,6 +4,7 @@ use crate::{perm_v, temp_v};
use crate::allocator::*; use crate::allocator::*;
use crate::arithmetic::*; use crate::arithmetic::*;
use crate::debray_allocator::*;
use crate::fixtures::*; use crate::fixtures::*;
use crate::forms::*; use crate::forms::*;
use crate::indexing::*; use crate::indexing::*;
@@ -195,12 +196,22 @@ impl CodeGenSettings {
Instruction::TrustMe(0) Instruction::TrustMe(0)
} }
} }
pub(crate) fn default_call_policy(&self) -> CallPolicy {
// calls are inference counted by default if and only if
// backtracking is counted too.
if self.non_counted_bt {
CallPolicy::Default
} else {
CallPolicy::Counted
}
}
} }
#[derive(Debug)] #[derive(Debug)]
pub(crate) struct CodeGenerator<'a, TermMarker> { pub(crate) struct CodeGenerator<'a> {
pub(crate) atom_tbl: &'a mut AtomTable, pub(crate) atom_tbl: &'a mut AtomTable,
marker: TermMarker, marker: DebrayAllocator,
pub(crate) var_count: IndexMap<Rc<String>, usize>, pub(crate) var_count: IndexMap<Rc<String>, usize>,
settings: CodeGenSettings, settings: CodeGenSettings,
pub(crate) skeleton: PredicateSkeleton, pub(crate) skeleton: PredicateSkeleton,
@@ -208,11 +219,76 @@ pub(crate) struct CodeGenerator<'a, TermMarker> {
global_jmp_by_locs_offset: usize, global_jmp_by_locs_offset: usize,
} }
impl<'b, TermMarker: Allocator> CodeGenerator<'b, TermMarker> { impl DebrayAllocator {
fn mark_var_in_non_callable(
&mut self,
name: Rc<String>,
term_loc: GenContext,
vr: &Cell<VarReg>,
code: &mut Code,
) -> RegType {
self.mark_var::<QueryInstruction>(name, Level::Shallow, vr, term_loc, code);
vr.get().norm()
}
#[inline(always)]
pub(crate) fn get_binding(&self, name: &String) -> Option<RegType> {
match self.bindings().get(name) {
Some(&VarData::Temp(_, t, _)) if t != 0 => Some(RegType::Temp(t)),
Some(&VarData::Perm(p)) if p != 0 => Some(RegType::Perm(p)),
_ => None,
}
}
pub(crate) fn mark_non_callable(
&mut self,
name: Rc<String>,
arg: usize,
term_loc: GenContext,
vr: &Cell<VarReg>,
code: &mut Code,
) -> RegType {
match self.get_binding(&name) {
Some(RegType::Temp(t)) => RegType::Temp(t),
Some(RegType::Perm(p)) => {
if let GenContext::Last(_) = term_loc {
self.mark_var_in_non_callable(name.clone(), term_loc, vr, code);
temp_v!(arg)
} else {
RegType::Perm(p)
}
}
None => self.mark_var_in_non_callable(name, term_loc, vr, code),
}
}
}
// if the final argument of the structure is a Literal::Index,
// decrement the arity of the PutStructure instruction by 1.
fn trim_structure_by_last_arg(instr: &mut Instruction, last_arg: &Term) {
match instr {
Instruction::PutStructure(_, ref mut arity, _) |
Instruction::GetStructure(_, ref mut arity, _) => {
if let Term::Literal(_, Literal::CodeIndex(_)) = last_arg {
// it is acceptable if arity == 0 is the result of
// this decrement. call/N will have to read the index
// constant for '$call_inline' to succeed. to find it,
// it must know the heap location of the index.
// self.store must stop before reading the atom into a
// register.
*arity -= 1;
}
}
_ => {}
}
}
impl<'b> CodeGenerator<'b> {
pub(crate) fn new(atom_tbl: &'b mut AtomTable, settings: CodeGenSettings) -> Self { pub(crate) fn new(atom_tbl: &'b mut AtomTable, settings: CodeGenSettings) -> Self {
CodeGenerator { CodeGenerator {
atom_tbl, atom_tbl,
marker: Allocator::new(), marker: DebrayAllocator::new(),
var_count: IndexMap::new(), var_count: IndexMap::new(),
settings, settings,
skeleton: PredicateSkeleton::new(), skeleton: PredicateSkeleton::new(),
@@ -234,45 +310,6 @@ impl<'b, TermMarker: Allocator> CodeGenerator<'b, TermMarker> {
*self.var_count.get(var).unwrap() *self.var_count.get(var).unwrap()
} }
fn mark_var_in_non_callable(
&mut self,
name: Rc<String>,
term_loc: GenContext,
vr: &Cell<VarReg>,
code: &mut Code,
) -> RegType {
let mut target = Code::new();
self.marker.mark_var::<QueryInstruction>(name, Level::Shallow, vr, term_loc, &mut target);
if !target.is_empty() {
code.extend(target.into_iter());
}
vr.get().norm()
}
fn mark_non_callable(
&mut self,
name: Rc<String>,
arg: usize,
term_loc: GenContext,
vr: &Cell<VarReg>,
code: &mut Code,
) -> RegType {
match self.marker.bindings().get(&name) {
Some(&VarData::Temp(_, t, _)) if t != 0 => RegType::Temp(t),
Some(&VarData::Perm(p)) if p != 0 => {
if let GenContext::Last(_) = term_loc {
self.mark_var_in_non_callable(name.clone(), term_loc, vr, code);
temp_v!(arg)
} else {
RegType::Perm(p)
}
}
_ => self.mark_var_in_non_callable(name, term_loc, vr, code),
}
}
fn add_or_increment_void_instr<'a, Target>(target: &mut Code) fn add_or_increment_void_instr<'a, Target>(target: &mut Code)
where where
Target: crate::targets::CompilationTarget<'a>, Target: crate::targets::CompilationTarget<'a>,
@@ -316,9 +353,10 @@ impl<'b, TermMarker: Allocator> CodeGenerator<'b, TermMarker> {
&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, ..) => {
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(Target::clause_arg_to_instr(cell.get())); target.push(Target::clause_arg_to_instr(cell.get()));
} }
@@ -352,9 +390,15 @@ impl<'b, TermMarker: Allocator> CodeGenerator<'b, TermMarker> {
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, ct, 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(Target::to_structure(ct.name(), terms.len(), cell.get())); target.push(Target::to_structure(name, terms.len(), cell.get()));
if let Some(instr) = target.last_mut() {
if let Some(term) = terms.last() {
trim_structure_by_last_arg(instr, term);
}
}
for subterm in terms { for subterm in terms {
self.subterm_to_instr::<Target>(subterm, term_loc, is_exposed, &mut target); self.subterm_to_instr::<Target>(subterm, term_loc, is_exposed, &mut target);
@@ -377,13 +421,14 @@ impl<'b, TermMarker: Allocator> CodeGenerator<'b, TermMarker> {
} }
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.mark_non_var::<Target>(lvl, term_loc, cell, &mut target);
let atom = self.atom_tbl.build_with(&string);
if let Some(tail) = tail { target.push(Target::to_pstr(lvl, atom, cell.get(), true));
target.push(Target::to_pstr(lvl, string, cell.get(), true));
self.subterm_to_instr::<Target>(tail, term_loc, is_exposed, &mut target); self.subterm_to_instr::<Target>(tail, term_loc, is_exposed, &mut target);
} else {
target.push(Target::to_pstr(lvl, string, cell.get(), false));
} }
TermRef::CompleteString(lvl, cell, atom) => {
self.marker.mark_non_var::<Target>(lvl, term_loc, cell, &mut target);
target.push(Target::to_pstr(lvl, atom, cell.get(), false));
} }
TermRef::Var(lvl @ Level::Shallow, cell, ref var) if var.as_str() == "!" => { TermRef::Var(lvl @ Level::Shallow, cell, ref var) if var.as_str() == "!" => {
if self.marker.is_unbound(var.clone()) { if self.marker.is_unbound(var.clone()) {
@@ -397,6 +442,7 @@ impl<'b, TermMarker: Allocator> CodeGenerator<'b, TermMarker> {
perm_v!(1), perm_v!(1),
false, false,
); );
continue; continue;
} }
} }
@@ -430,7 +476,6 @@ impl<'b, TermMarker: Allocator> CodeGenerator<'b, TermMarker> {
}; };
self.update_var_count(chunked_term.post_order_iter()); self.update_var_count(chunked_term.post_order_iter());
vs.mark_vars_in_chunk(chunked_term.post_order_iter(), lt_arity, term_loc); vs.mark_vars_in_chunk(chunked_term.post_order_iter(), lt_arity, term_loc);
} }
} }
@@ -451,10 +496,10 @@ impl<'b, TermMarker: Allocator> CodeGenerator<'b, TermMarker> {
self.jmp_by_locs.push(code.len()); self.jmp_by_locs.push(code.len());
code.push(instr!("jmp_by_call", vars.len(), 0, pvs)); code.push(instr!("jmp_by_call", vars.len(), 0, pvs));
} }
&QueryTerm::Clause(_, ref ct, _, true) => { &QueryTerm::Clause(_, ref ct, _, CallPolicy::Default) => {
code.push(call_clause_by_default!(ct.clone(), pvs)); code.push(call_clause_by_default!(ct.clone(), pvs));
} }
&QueryTerm::Clause(_, ref ct, _, false) => { &QueryTerm::Clause(_, ref ct, _, CallPolicy::Counted) => {
code.push(call_clause!(ct.clone(), pvs)); code.push(call_clause!(ct.clone(), pvs));
} }
_ => {} _ => {}
@@ -501,35 +546,39 @@ impl<'b, TermMarker: Allocator> CodeGenerator<'b, TermMarker> {
&InlinedClauseType::CompareNumber(mut cmp) => { &InlinedClauseType::CompareNumber(mut cmp) => {
self.marker.reset_arg(2); self.marker.reset_arg(2);
let (mut lcode, at_1) = self.compile_arith_expr(&terms[0], 1, term_loc)?; let (mut lcode, at_1) = self.compile_arith_expr(&terms[0], 1, term_loc, 1)?;
let (mut rcode, at_2) = self.compile_arith_expr(&terms[1], 2, term_loc)?;
let at_1 = if let &Term::Var(ref vr, ref name) = &terms[0] { if !matches!(terms[0], Term::Var(..)) {
ArithmeticTerm::Reg(self.mark_non_callable(name.clone(), 1, term_loc, vr, code)) self.marker.advance_arg();
} else { }
at_1.unwrap_or(interm!(1))
};
let at_2 = if let &Term::Var(ref vr, ref name) = &terms[1] { let (mut rcode, at_2) = self.compile_arith_expr(&terms[1], 2, term_loc, 2)?;
ArithmeticTerm::Reg(self.mark_non_callable(name.clone(), 2, term_loc, vr, code))
} else {
at_2.unwrap_or(interm!(2))
};
code.append(&mut lcode); code.append(&mut lcode);
code.append(&mut rcode); code.append(&mut rcode);
let at_1 = at_1.unwrap_or(interm!(1));
let at_2 = at_2.unwrap_or(interm!(2));
code.push(compare_number_instr!(cmp, at_1, at_2)); code.push(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(..)) => {
code.push(instr!("$succeed", 0)); code.push(instr!("$succeed", 0));
} }
&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.mark_non_callable(name.clone(), 1, term_loc, vr, code);
let r = self.marker.mark_non_callable(
name.clone(),
1,
term_loc,
vr,
code,
);
code.push(instr!("atom", r, 0)); code.push(instr!("atom", r, 0));
} }
_ => { _ => {
@@ -537,7 +586,11 @@ impl<'b, TermMarker: Allocator> CodeGenerator<'b, TermMarker> {
} }
}, },
&InlinedClauseType::IsAtomic(..) => match &terms[0] { &InlinedClauseType::IsAtomic(..) => match &terms[0] {
&Term::AnonVar | &Term::Clause(..) | &Term::Cons(..) | &Term::PartialString(..) => { &Term::AnonVar |
&Term::Clause(..) |
&Term::Cons(..) |
&Term::PartialString(..) |
&Term::CompleteString(..) => {
code.push(instr!("$fail", 0)); code.push(instr!("$fail", 0));
} }
&Term::Literal(_, Literal::String(_)) => { &Term::Literal(_, Literal::String(_)) => {
@@ -548,18 +601,37 @@ impl<'b, TermMarker: Allocator> CodeGenerator<'b, TermMarker> {
} }
&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.mark_non_callable(name.clone(), 1, term_loc, vr, code);
let r = self.marker.mark_non_callable(
name.clone(),
1,
term_loc,
vr,
code,
);
code.push(instr!("atomic", r, 0)); code.push(instr!("atomic", r, 0));
} }
}, },
&InlinedClauseType::IsCompound(..) => match &terms[0] { &InlinedClauseType::IsCompound(..) => match &terms[0] {
&Term::Clause(..) | &Term::Cons(..) | &Term::PartialString(..) | &Term::Clause(..) |
&Term::Cons(..) |
&Term::PartialString(..) |
&Term::CompleteString(..) |
&Term::Literal(_, Literal::String(..)) => { &Term::Literal(_, Literal::String(..)) => {
code.push(instr!("$succeed", 0)); code.push(instr!("$succeed", 0));
} }
&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.mark_non_callable(name.clone(), 1, term_loc, vr, code);
let r = self.marker.mark_non_callable(
name.clone(),
1,
term_loc,
vr,
code,
);
code.push(instr!("compound", r, 0)); code.push(instr!("compound", r, 0));
} }
_ => { _ => {
@@ -572,7 +644,7 @@ impl<'b, TermMarker: Allocator> CodeGenerator<'b, TermMarker> {
} }
&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.mark_non_callable(name.clone(), 1, term_loc, vr, code); let r = self.marker.mark_non_callable(name.clone(), 1, term_loc, vr, code);
code.push(instr!("rational", r, 0)); code.push(instr!("rational", r, 0));
} }
_ => { _ => {
@@ -585,7 +657,15 @@ impl<'b, TermMarker: Allocator> CodeGenerator<'b, TermMarker> {
} }
&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.mark_non_callable(name.clone(), 1, term_loc, vr, code);
let r = self.marker.mark_non_callable(
name.clone(),
1,
term_loc,
vr,
code,
);
code.push(instr!("float", r, 0)); code.push(instr!("float", r, 0));
} }
_ => { _ => {
@@ -593,15 +673,23 @@ impl<'b, TermMarker: Allocator> CodeGenerator<'b, TermMarker> {
} }
}, },
&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(_)) => {
code.push(instr!("$succeed", 0)); code.push(instr!("$succeed", 0));
} }
&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.mark_non_callable(name.clone(), 1, term_loc, vr, code);
let r = self.marker.mark_non_callable(
name.clone(),
1,
term_loc,
vr,
code,
);
code.push(instr!("number", r, 0)); code.push(instr!("number", r, 0));
} }
_ => { _ => {
@@ -614,7 +702,15 @@ impl<'b, TermMarker: Allocator> CodeGenerator<'b, TermMarker> {
} }
&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.mark_non_callable(name.clone(), 1, term_loc, vr, code);
let r = self.marker.mark_non_callable(
name.clone(),
1,
term_loc,
vr,
code,
);
code.push(instr!("nonvar", r, 0)); code.push(instr!("nonvar", r, 0));
} }
_ => { _ => {
@@ -622,12 +718,21 @@ impl<'b, TermMarker: Allocator> CodeGenerator<'b, TermMarker> {
} }
}, },
&InlinedClauseType::IsInteger(..) => match &terms[0] { &InlinedClauseType::IsInteger(..) => match &terms[0] {
&Term::Literal(_, Literal::Integer(_)) | &Term::Literal(_, Literal::Fixnum(_)) => { &Term::Literal(_, Literal::Integer(_)) |
&Term::Literal(_, Literal::Fixnum(_)) => {
code.push(instr!("$succeed", 0)); code.push(instr!("$succeed", 0));
} }
&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.mark_non_callable(name.clone(), 1, term_loc, vr, code);
let r = self.marker.mark_non_callable(
name.clone(),
1,
term_loc,
vr,
code,
);
code.push(instr!("integer", r, 0)); code.push(instr!("integer", r, 0));
} }
_ => { _ => {
@@ -635,10 +740,11 @@ impl<'b, TermMarker: Allocator> CodeGenerator<'b, TermMarker> {
} }
}, },
&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(..) => {
code.push(instr!("$fail", 0)); code.push(instr!("$fail", 0));
} }
&Term::AnonVar => { &Term::AnonVar => {
@@ -646,7 +752,15 @@ impl<'b, TermMarker: Allocator> CodeGenerator<'b, TermMarker> {
} }
&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.mark_non_callable(name.clone(), 1, term_loc, vr, code);
let r = self.marker.mark_non_callable(
name.clone(),
1,
term_loc,
vr,
code,
);
code.push(instr!("var", r, 0)); code.push(instr!("var", r, 0));
} }
}, },
@@ -660,9 +774,10 @@ impl<'b, TermMarker: Allocator> CodeGenerator<'b, TermMarker> {
term: &Term, term: &Term,
target_int: usize, target_int: usize,
term_loc: GenContext, term_loc: GenContext,
arg: usize,
) -> Result<ArithCont, ArithmeticError> { ) -> Result<ArithCont, ArithmeticError> {
let mut evaluator = ArithmeticEvaluator::new(&mut self.marker, target_int); let mut evaluator = ArithmeticEvaluator::new(&mut self.marker, target_int);
evaluator.eval(term, term_loc) evaluator.compile_is(term, term_loc, arg)
} }
fn compile_is_call( fn compile_is_call(
@@ -670,11 +785,11 @@ impl<'b, TermMarker: Allocator> CodeGenerator<'b, TermMarker> {
terms: &Vec<Term>, terms: &Vec<Term>,
code: &mut Code, code: &mut Code,
term_loc: GenContext, term_loc: GenContext,
use_default_call_policy: bool, 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], 1, $term_loc)?; let (acode, at) = $self.compile_arith_expr(&$terms[1], 1, $term_loc, 2)?;
$code.extend(acode.into_iter()); $code.extend(acode.into_iter());
at at
}); });
@@ -712,7 +827,7 @@ impl<'b, TermMarker: Allocator> CodeGenerator<'b, TermMarker> {
let at = at.unwrap_or(interm!(1)); let at = at.unwrap_or(interm!(1));
Ok(if use_default_call_policy { Ok(if let CallPolicy::Default = call_policy {
code.push(instr!("is", default, temp_v!(1), at, 0)); code.push(instr!("is", default, temp_v!(1), at, 0));
} else { } else {
code.push(instr!("is", temp_v!(1), at, 0)); code.push(instr!("is", temp_v!(1), at, 0));
@@ -774,8 +889,8 @@ impl<'b, TermMarker: Allocator> CodeGenerator<'b, TermMarker> {
_, _,
ClauseType::BuiltIn(BuiltInClauseType::Is(..)), ClauseType::BuiltIn(BuiltInClauseType::Is(..)),
ref terms, ref terms,
use_default_call_policy, call_policy,
) => self.compile_is_call(terms, code, term_loc, use_default_call_policy)?, ) => self.compile_is_call(terms, 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, code)? self.compile_inlined(ct, terms, term_loc, code)?
} }
@@ -787,6 +902,10 @@ impl<'b, TermMarker: Allocator> CodeGenerator<'b, TermMarker> {
}; };
self.compile_query_line(term, term_loc, code, num_perm_vars, is_exposed); self.compile_query_line(term, term_loc, code, num_perm_vars, is_exposed);
if self.marker.max_reg_allocated() > MAX_ARITY {
return Err(CompilationError::ExceededMaxArity);
}
} }
} }
} }
@@ -856,6 +975,10 @@ impl<'b, TermMarker: Allocator> CodeGenerator<'b, TermMarker> {
let iter = FactIterator::from_rule_head_clause(args); let iter = FactIterator::from_rule_head_clause(args);
let mut fact = self.compile_target::<FactInstruction, _>(iter, GenContext::Head, false); let mut fact = self.compile_target::<FactInstruction, _>(iter, GenContext::Head, false);
if self.marker.max_reg_allocated() > MAX_ARITY {
return Err(CompilationError::ExceededMaxArity);
}
let mut unsafe_var_marker = UnsafeVarMarker::new(); let mut unsafe_var_marker = UnsafeVarMarker::new();
if !fact.is_empty() { if !fact.is_empty() {
@@ -893,7 +1016,7 @@ impl<'b, TermMarker: Allocator> CodeGenerator<'b, TermMarker> {
UnsafeVarMarker::from_safe_vars(safe_vars) UnsafeVarMarker::from_safe_vars(safe_vars)
} }
pub(crate) fn compile_fact(&mut self, term: &Term) -> Code { pub(crate) fn compile_fact(&mut self, term: &Term) -> Result<Code, CompilationError> {
self.update_var_count(post_order_iter(term)); self.update_var_count(post_order_iter(term));
let mut vs = VariableFixtures::new(); let mut vs = VariableFixtures::new();
@@ -915,6 +1038,10 @@ impl<'b, TermMarker: Allocator> CodeGenerator<'b, TermMarker> {
false, false,
); );
if self.marker.max_reg_allocated() > MAX_ARITY {
return Err(CompilationError::ExceededMaxArity);
}
self.mark_unsafe_fact_vars(&mut compiled_fact); self.mark_unsafe_fact_vars(&mut compiled_fact);
if !compiled_fact.is_empty() { if !compiled_fact.is_empty() {
@@ -923,7 +1050,7 @@ impl<'b, TermMarker: Allocator> CodeGenerator<'b, TermMarker> {
} }
code.push(instr!("proceed")); code.push(instr!("proceed"));
code Ok(code)
} }
fn compile_query_line( fn compile_query_line(
@@ -939,10 +1066,7 @@ impl<'b, TermMarker: Allocator> CodeGenerator<'b, TermMarker> {
let iter = query_term_post_order_iter(term); let iter = query_term_post_order_iter(term);
let query = self.compile_target::<QueryInstruction, _>(iter, term_loc, is_exposed); let query = self.compile_target::<QueryInstruction, _>(iter, term_loc, is_exposed);
if !query.is_empty() {
code.extend(query.into_iter()); code.extend(query.into_iter());
}
self.add_conditional_call(code, term, num_perm_vars_left); self.add_conditional_call(code, term, num_perm_vars_left);
} }
@@ -1033,14 +1157,13 @@ impl<'b, TermMarker: Allocator> CodeGenerator<'b, TermMarker> {
self.global_jmp_by_locs_offset = self.jmp_by_locs.len(); self.global_jmp_by_locs_offset = self.jmp_by_locs.len();
let clause_code = match clause { let clause_code = match clause {
&PredicateClause::Fact(ref fact, ..) => self.compile_fact(fact), &PredicateClause::Fact(ref fact, ..) => self.compile_fact(fact)?,
&PredicateClause::Rule(ref rule, ..) => self.compile_rule(rule)?, &PredicateClause::Rule(ref rule, ..) => self.compile_rule(rule)?,
}; };
if clauses.len() > 1 { if clauses.len() > 1 {
let choice = match i { let choice = match i {
0 => self.settings.internal_try_me_else(clause_code.len() + 1), 0 => self.settings.internal_try_me_else(clause_code.len() + 1),
//Instruction::TryMeElse(clause_code.len() + 1),
_ if i == clauses.len() - 1 => self.settings.internal_trust_me(), _ if i == clauses.len() - 1 => self.settings.internal_trust_me(),
_ => self.settings.internal_retry_me_else(clause_code.len() + 1), _ => self.settings.internal_retry_me_else(clause_code.len() + 1),
}; };
@@ -1062,28 +1185,39 @@ impl<'b, TermMarker: Allocator> CodeGenerator<'b, TermMarker> {
skip_stub_try_me_else = !self.settings.is_dynamic(); skip_stub_try_me_else = !self.settings.is_dynamic();
} }
let arg = match clause.args() { let arg = clause.args().and_then(|args| args.iter().nth(optimal_index));
Some(args) => match args.iter().nth(optimal_index) {
Some(term) => Some(term),
None => None,
},
None => None,
};
if let Some(arg) = arg { if let Some(arg) = arg {
let index = code.len(); let index = code.len();
if clauses.len() > 1 || self.settings.is_dynamic() {
code_offsets.index_term(arg, index, &mut clause_index_info, self.atom_tbl); code_offsets.index_term(arg, index, &mut clause_index_info, self.atom_tbl);
} }
}
if !(clauses.len() == 1 && self.settings.is_extensible) { if !(code_offsets.no_indices() && clauses.len() == 1 && self.settings.is_extensible) {
// the peculiar condition of this block, when false,
// anticipates code.pop_front() being called about a
// dozen lines below.
if !skip_stub_try_me_else {
// if the condition is false, code_offsets.no_indices() is false,
// so don't repeat the work of the condition on skip_stub_try_me_else
// below.
self.increment_jmp_by_locs_by(code.len()); self.increment_jmp_by_locs_by(code.len());
} }
}
self.skeleton.clauses.push_back(clause_index_info); self.skeleton.clauses.push_back(clause_index_info);
code.extend(clause_code.into_iter()); code.extend(clause_code.into_iter());
} }
let index_code = code_offsets.compute_indices(skip_stub_try_me_else); let index_code = if clauses.len() > 1 || self.settings.is_dynamic() {
code_offsets.compute_indices(skip_stub_try_me_else)
} else {
vec![]
};
self.global_jmp_by_locs_offset = jmp_by_locs_len; self.global_jmp_by_locs_offset = jmp_by_locs_len;
if !index_code.is_empty() { if !index_code.is_empty() {
@@ -1147,7 +1281,10 @@ impl<'b, TermMarker: Allocator> CodeGenerator<'b, TermMarker> {
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[skel_lower_bound..].iter_mut() { for clause_index_info in self.skeleton.clauses
.make_contiguous()[skel_lower_bound..]
.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);
clause_index_info.opt_arg_index_key += clause_start_offset + 1; clause_index_info.opt_arg_index_key += clause_start_offset + 1;

View File

@@ -151,16 +151,13 @@ impl DebrayAllocator {
}; };
} }
fn alloc_reg_to_var<'a, Target>( fn alloc_reg_to_var<'a, Target: CompilationTarget<'a>>(
&mut self, &mut self,
var: &String, var: &String,
lvl: Level, lvl: Level,
term_loc: GenContext, term_loc: GenContext,
target: &mut Vec<Instruction>, target: &mut Vec<Instruction>,
) -> usize ) -> usize {
where
Target: CompilationTarget<'a>,
{
match term_loc { match term_loc {
GenContext::Head => { GenContext::Head => {
if let Level::Shallow = lvl { if let Level::Shallow = lvl {
@@ -404,4 +401,9 @@ impl Allocator for DebrayAllocator {
self.arg_c = 1; self.arg_c = 1;
self.temp_lb = arity + 1; self.temp_lb = arity + 1;
} }
#[inline(always)]
fn max_reg_allocated(&self) -> usize {
std::cmp::max(self.temp_lb, self.arg_c)
}
} }

View File

@@ -15,9 +15,8 @@ use fxhash::FxBuildHasher;
use indexmap::{IndexMap, IndexSet}; use indexmap::{IndexMap, IndexSet};
use ordered_float::OrderedFloat; use ordered_float::OrderedFloat;
use slice_deque::*;
use std::cell::Cell; use std::cell::Cell;
use std::collections::VecDeque;
use std::convert::TryFrom; use std::convert::TryFrom;
use std::fmt; use std::fmt;
use std::ops::AddAssign; use std::ops::AddAssign;
@@ -58,7 +57,7 @@ impl AppendOrPrepend {
} }
} }
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Level { pub enum Level {
Deep, Deep,
Root, Root,
@@ -74,10 +73,16 @@ impl Level {
} }
} }
#[derive(Debug, Clone, Copy)]
pub enum CallPolicy {
Default,
Counted,
}
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum QueryTerm { pub enum QueryTerm {
// register, clause type, subterms, use default call policy. // register, clause type, subterms, clause call policy.
Clause(Cell<RegType>, ClauseType, Vec<Term>, bool), Clause(Cell<RegType>, ClauseType, Vec<Term>, CallPolicy),
BlockedCut, // a cut which is 'blocked by letters', like the P term in P -> Q. BlockedCut, // a cut which is 'blocked by letters', like the P term in P -> Q.
UnblockedCut(Cell<VarReg>), UnblockedCut(Cell<VarReg>),
GetLevelAndUnify(Cell<VarReg>, Rc<String>), GetLevelAndUnify(Cell<VarReg>, Rc<String>),
@@ -85,9 +90,9 @@ pub enum QueryTerm {
} }
impl QueryTerm { impl QueryTerm {
pub(crate) fn set_default_caller(&mut self) { pub(crate) fn set_call_policy(&mut self, cp: CallPolicy) {
match self { match self {
&mut QueryTerm::Clause(_, _, _, ref mut use_default_cp) => *use_default_cp = true, &mut QueryTerm::Clause(_, _, _, ref mut clause_cp) => *clause_cp = cp,
_ => {} _ => {}
} }
} }
@@ -149,24 +154,21 @@ impl ClauseInfo for PredicateKey {
impl ClauseInfo for Term { impl ClauseInfo for Term {
fn name(&self) -> Option<Atom> { fn name(&self) -> Option<Atom> {
//, atom_tbl: &AtomTable) -> Option<StringBuffer> {
match self { match self {
Term::Clause(_, name, terms) => { Term::Clause(_, name, terms) => {
// let str_buf = StringBuffer::from(*name, atom_tbl);
match name.as_str() { match name {
// str_buf.as_str() { atom!(":-") => {
":-" => {
match terms.len() { match terms.len() {
1 => None, // a declaration. 1 => None, // a declaration.
2 => terms[0].name(), //.map(|name| StringBuffer::from(name, atom_tbl)), 2 => terms[0].name(),
_ => Some(*name), _ => Some(*name),
} }
} }
_ => Some(*name), //str_buf), _ => Some(*name), //str_buf),
} }
} }
Term::Literal(_, Literal::Atom(name)) => Some(*name), //Some(StringBuffer::from(*name, atom_tbl)), Term::Literal(_, Literal::Atom(name)) => Some(*name),
_ => None, _ => None,
} }
} }
@@ -267,6 +269,7 @@ pub enum MetaSpec {
Minus, Minus,
Plus, Plus,
Either, Either,
Colon,
RequiresExpansionWithArgument(usize), RequiresExpansionWithArgument(usize),
} }
@@ -363,6 +366,18 @@ pub enum AtomOrString {
} }
impl AtomOrString { impl AtomOrString {
#[inline]
pub fn as_atom(&self, atom_tbl: &mut AtomTable) -> Atom {
match self {
&AtomOrString::Atom(atom) => {
atom
}
AtomOrString::String(string) => {
atom_tbl.build_with(&string)
}
}
}
#[inline] #[inline]
pub fn as_str(&self) -> &str { pub fn as_str(&self) -> &str {
match self { match self {
@@ -607,7 +622,7 @@ impl ArenaFrom<Number> for Literal {
match value { match value {
Number::Fixnum(n) => Literal::Fixnum(n), Number::Fixnum(n) => Literal::Fixnum(n),
Number::Integer(n) => Literal::Integer(n), Number::Integer(n) => Literal::Integer(n),
Number::Float(f) => Literal::Float(arena_alloc!(f, arena)), Number::Float(OrderedFloat(f)) => Literal::from(float_alloc!(f, arena)),
Number::Rational(r) => Literal::Rational(r), Number::Rational(r) => Literal::Rational(r),
} }
} }
@@ -619,13 +634,29 @@ impl ArenaFrom<Number> for HeapCellValue {
match value { match value {
Number::Fixnum(n) => fixnum_as_cell!(n), Number::Fixnum(n) => fixnum_as_cell!(n),
Number::Integer(n) => typed_arena_ptr_as_cell!(n), Number::Integer(n) => typed_arena_ptr_as_cell!(n),
Number::Float(n) => typed_arena_ptr_as_cell!(arena_alloc!(n, arena)), Number::Float(OrderedFloat(n)) => HeapCellValue::from(float_alloc!(n, arena)),
Number::Rational(n) => typed_arena_ptr_as_cell!(n), Number::Rational(n) => typed_arena_ptr_as_cell!(n),
} }
} }
} }
impl Number { impl Number {
pub(crate) fn sign(&self) -> Number {
match self {
&Number::Float(f) if f == 0.0 => Number::Float(OrderedFloat(0f64)),
&Number::Float(f) => Number::Float(OrderedFloat(f.signum())),
_ => {
if self.is_positive() {
Number::Fixnum(Fixnum::build_with(1))
} else if self.is_negative() {
Number::Fixnum(Fixnum::build_with(-1))
} else {
Number::Fixnum(Fixnum::build_with(0))
}
}
}
}
#[inline] #[inline]
pub(crate) fn is_positive(&self) -> bool { pub(crate) fn is_positive(&self) -> bool {
match self { match self {
@@ -791,7 +822,7 @@ pub(crate) struct LocalPredicateSkeleton {
pub(crate) is_discontiguous: bool, pub(crate) is_discontiguous: bool,
pub(crate) is_dynamic: bool, pub(crate) is_dynamic: bool,
pub(crate) is_multifile: bool, pub(crate) is_multifile: bool,
pub(crate) clause_clause_locs: SliceDeque<usize>, pub(crate) clause_clause_locs: VecDeque<usize>,
pub(crate) clause_assert_margin: usize, pub(crate) clause_assert_margin: usize,
pub(crate) retracted_dynamic_clauses: Option<Vec<ClauseIndexInfo>>, // always None if non-dynamic. pub(crate) retracted_dynamic_clauses: Option<Vec<ClauseIndexInfo>>, // always None if non-dynamic.
} }
@@ -803,7 +834,7 @@ impl LocalPredicateSkeleton {
is_discontiguous: false, is_discontiguous: false,
is_dynamic: false, is_dynamic: false,
is_multifile: false, is_multifile: false,
clause_clause_locs: sdeq![], clause_clause_locs: VecDeque::new(),
clause_assert_margin: 0, clause_assert_margin: 0,
retracted_dynamic_clauses: Some(vec![]), retracted_dynamic_clauses: Some(vec![]),
} }
@@ -844,7 +875,7 @@ impl LocalPredicateSkeleton {
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub(crate) struct PredicateSkeleton { pub(crate) struct PredicateSkeleton {
pub(crate) core: LocalPredicateSkeleton, pub(crate) core: LocalPredicateSkeleton,
pub(crate) clauses: SliceDeque<ClauseIndexInfo>, pub(crate) clauses: VecDeque<ClauseIndexInfo>,
} }
impl PredicateSkeleton { impl PredicateSkeleton {
@@ -852,7 +883,7 @@ impl PredicateSkeleton {
pub(crate) fn new() -> Self { pub(crate) fn new() -> Self {
PredicateSkeleton { PredicateSkeleton {
core: LocalPredicateSkeleton::new(), core: LocalPredicateSkeleton::new(),
clauses: sdeq![], clauses: VecDeque::new(),
} }
} }
@@ -868,18 +899,22 @@ impl PredicateSkeleton {
} }
pub(crate) fn target_pos_of_clause_clause_loc( pub(crate) fn target_pos_of_clause_clause_loc(
&self, &mut self,
clause_clause_loc: usize, clause_clause_loc: usize,
) -> Option<usize> { ) -> Option<usize> {
let search_result = self.core.clause_clause_locs[0..self.core.clause_assert_margin] let search_result = self.core.clause_clause_locs
.make_contiguous()[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(_) => self.core.clause_clause_locs[self.core.clause_assert_margin..] Err(_) => {
self.core.clause_clause_locs
.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()
}
} }
} }
} }

View File

@@ -1,3 +1,4 @@
#[cfg(test)]
pub(crate) use crate::machine::gc::{IteratorUMP, StacklessPreOrderHeapIter}; pub(crate) use crate::machine::gc::{IteratorUMP, StacklessPreOrderHeapIter};
use crate::machine::heap::*; use crate::machine::heap::*;
@@ -9,6 +10,49 @@ use modular_bitfield::prelude::*;
use std::ops::Deref; use std::ops::Deref;
use std::vec::Vec; use std::vec::Vec;
#[derive(BitfieldSpecifier, Clone, Copy, Debug, PartialEq, Eq)]
#[bits = 2]
enum IterStackLocTag {
Iterable,
Marked,
PendingMark,
}
#[bitfield]
#[repr(u64)]
#[derive(Clone, Copy, Debug)]
pub struct IterStackLoc {
value: B62,
tag: IterStackLocTag,
}
impl IterStackLoc {
#[inline]
pub fn iterable_heap_loc(h: usize) -> Self {
IterStackLoc::new().with_tag(IterStackLocTag::Iterable).with_value(h as u64)
}
#[inline]
pub fn mark_heap_loc(h: usize) -> Self {
IterStackLoc::new().with_tag(IterStackLocTag::Marked).with_value(h as u64)
}
#[inline]
pub fn pending_mark_heap_loc(h: usize) -> Self {
IterStackLoc::new().with_tag(IterStackLocTag::PendingMark).with_value(h as u64)
}
#[inline]
pub fn is_marked(self) -> bool {
self.tag() == IterStackLocTag::Marked
}
#[inline]
pub fn is_pending_mark(self) -> bool {
self.tag() == IterStackLocTag::PendingMark
}
}
#[inline] #[inline]
fn forward_if_referent_marked(heap: &mut [HeapCellValue], h: usize) { fn forward_if_referent_marked(heap: &mut [HeapCellValue], h: usize) {
read_heap_cell!(heap[h], read_heap_cell!(heap[h],
@@ -25,26 +69,6 @@ fn forward_if_referent_marked(heap: &mut [HeapCellValue], h: usize) {
) )
} }
#[bitfield]
#[repr(u64)]
#[derive(Clone, Copy, Debug)]
pub struct IterStackLoc {
value: B63,
m: bool,
}
impl IterStackLoc {
#[inline]
pub fn iterable_heap_loc(h: usize) -> Self {
IterStackLoc::new().with_m(false).with_value(h as u64)
}
#[inline]
pub fn mark_heap_loc(h: usize) -> Self {
IterStackLoc::new().with_m(true).with_value(h as u64)
}
}
#[derive(Debug)] #[derive(Debug)]
pub struct StackfulPreOrderHeapIter<'a> { pub struct StackfulPreOrderHeapIter<'a> {
pub heap: &'a mut Vec<HeapCellValue>, pub heap: &'a mut Vec<HeapCellValue>,
@@ -65,6 +89,17 @@ impl<'a> Drop for StackfulPreOrderHeapIter<'a> {
} }
} }
pub trait FocusedHeapIter: Iterator<Item = HeapCellValue> {
fn focus(&self) -> usize;
}
impl<'a> FocusedHeapIter for StackfulPreOrderHeapIter<'a> {
#[inline]
fn focus(&self) -> usize {
self.h
}
}
impl<'a> StackfulPreOrderHeapIter<'a> { impl<'a> StackfulPreOrderHeapIter<'a> {
#[inline] #[inline]
fn new(heap: &'a mut Vec<HeapCellValue>, cell: HeapCellValue) -> Self { fn new(heap: &'a mut Vec<HeapCellValue>, cell: HeapCellValue) -> Self {
@@ -86,11 +121,11 @@ impl<'a> StackfulPreOrderHeapIter<'a> {
#[inline] #[inline]
pub fn stack_last(&self) -> Option<usize> { pub fn stack_last(&self) -> Option<usize> {
for h in self.stack.iter().rev() { for h in self.stack.iter().rev() {
let is_readable_marked = h.m(); let is_readable_marked = h.is_marked();
let h = h.value() as usize; let h = h.value() as usize;
let cell = self.heap[h]; let cell = self.heap[h];
if cell.get_forwarding_bit() == Some(true) { if cell.get_forwarding_bit() {
return Some(h); return Some(h);
} else if cell.get_mark_bit() && !is_readable_marked { } else if cell.get_mark_bit() && !is_readable_marked {
continue; continue;
@@ -102,26 +137,16 @@ impl<'a> StackfulPreOrderHeapIter<'a> {
None None
} }
#[inline]
pub fn stack_is_empty(&self) -> bool {
self.stack.is_empty()
}
#[inline]
pub fn focus(&self) -> usize {
self.h
}
#[inline] #[inline]
pub fn pop_stack(&mut self) -> Option<HeapCellValue> { pub fn pop_stack(&mut self) -> Option<HeapCellValue> {
while let Some(h) = self.stack.pop() { while let Some(h) = self.stack.pop() {
let is_readable_marked = h.m(); let is_readable_marked = h.is_marked();
let h = h.value() as usize; let h = h.value() as usize;
self.h = h; self.h = h;
let cell = &mut self.heap[h]; let cell = &mut self.heap[h];
if cell.get_forwarding_bit() == Some(true) { if cell.get_forwarding_bit() {
cell.set_forwarding_bit(false); cell.set_forwarding_bit(false);
} else if cell.get_mark_bit() && !is_readable_marked { } else if cell.get_mark_bit() && !is_readable_marked {
cell.set_mark_bit(false); cell.set_mark_bit(false);
@@ -143,13 +168,23 @@ impl<'a> StackfulPreOrderHeapIter<'a> {
fn follow(&mut self) -> Option<HeapCellValue> { fn follow(&mut self) -> Option<HeapCellValue> {
while let Some(h) = self.stack.pop() { while let Some(h) = self.stack.pop() {
let is_readable_marked = h.m(); if h.is_pending_mark() {
let h = h.value() as usize;
self.push_if_unmarked(h);
self.stack.push(IterStackLoc::mark_heap_loc(h));
forward_if_referent_marked(&mut self.heap, h);
continue;
}
let is_readable_marked = h.is_marked();
let h = h.value() as usize; let h = h.value() as usize;
self.h = h; self.h = h;
let cell = &mut self.heap[h]; let cell = &mut self.heap[h];
if cell.get_forwarding_bit() == Some(true) { if cell.get_forwarding_bit() {
let copy = *cell; let copy = *cell;
cell.set_forwarding_bit(false); cell.set_forwarding_bit(false);
return Some(copy); return Some(copy);
@@ -159,23 +194,23 @@ impl<'a> StackfulPreOrderHeapIter<'a> {
} }
read_heap_cell!(*cell, read_heap_cell!(*cell,
(HeapCellValueTag::Str, vh) => { (HeapCellValueTag::Str | HeapCellValueTag::PStrLoc, vh) => {
self.stack.push(IterStackLoc::iterable_heap_loc(vh)); self.push_if_unmarked(vh);
self.stack.push(IterStackLoc::mark_heap_loc(vh));
} }
(HeapCellValueTag::Lis, vh) => { (HeapCellValueTag::Lis, vh) => {
self.push_if_unmarked(vh); self.push_if_unmarked(vh);
self.stack.push(IterStackLoc::iterable_heap_loc(vh + 1)); self.stack.push(IterStackLoc::pending_mark_heap_loc(vh + 1));
forward_if_referent_marked(&mut self.heap, vh + 1);
self.stack.push(IterStackLoc::mark_heap_loc(vh)); self.stack.push(IterStackLoc::mark_heap_loc(vh));
forward_if_referent_marked(&mut self.heap, vh); forward_if_referent_marked(&mut self.heap, vh);
return Some(self.heap[h]); return Some(self.heap[h]);
} }
(HeapCellValueTag::AttrVar | HeapCellValueTag::PStrLoc | HeapCellValueTag::Var, vh) => { (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, vh) => {
self.push_if_unmarked(h); self.push_if_unmarked(vh);
self.stack.push(IterStackLoc::iterable_heap_loc(vh)); self.stack.push(IterStackLoc::mark_heap_loc(vh));
forward_if_referent_marked(&mut self.heap, vh); forward_if_referent_marked(&mut self.heap, vh);
} }
(HeapCellValueTag::PStrOffset, offset) => { (HeapCellValueTag::PStrOffset, offset) => {
@@ -187,19 +222,20 @@ impl<'a> StackfulPreOrderHeapIter<'a> {
(HeapCellValueTag::PStr) => { (HeapCellValueTag::PStr) => {
self.push_if_unmarked(h); self.push_if_unmarked(h);
forward_if_referent_marked(&mut self.heap, h+1);
self.stack.push(IterStackLoc::iterable_heap_loc(h+1)); self.stack.push(IterStackLoc::iterable_heap_loc(h+1));
forward_if_referent_marked(&mut self.heap, h+1);
return Some(self.heap[h]); return Some(self.heap[h]);
} }
(HeapCellValueTag::Atom, (_name, arity)) => { (HeapCellValueTag::Atom, (_name, arity)) => {
if arity > 0 { for h in (h + 2 .. h + arity + 1).rev() {
self.push_if_unmarked(h); self.stack.push(IterStackLoc::pending_mark_heap_loc(h));
} }
for h in (h + 1 .. h + arity + 1).rev() { if arity > 0 {
forward_if_referent_marked(&mut self.heap, h); self.push_if_unmarked(h+1);
self.stack.push(IterStackLoc::iterable_heap_loc(h)); self.stack.push(IterStackLoc::mark_heap_loc(h+1));
forward_if_referent_marked(&mut self.heap, h+1);
} }
return Some(self.heap[h]); return Some(self.heap[h]);
@@ -223,12 +259,13 @@ impl<'a> Iterator for StackfulPreOrderHeapIter<'a> {
} }
} }
#[cfg(test)]
#[inline(always)] #[inline(always)]
pub(crate) fn stackless_preorder_iter( pub(crate) fn stackless_preorder_iter(
heap: &mut Vec<HeapCellValue>, heap: &mut Vec<HeapCellValue>,
cell: HeapCellValue, cell: HeapCellValue,
) -> StacklessPreOrderHeapIter<IteratorUMP> { ) -> StacklessPreOrderHeapIter<IteratorUMP> {
StacklessPreOrderHeapIter::new(heap, cell) StacklessPreOrderHeapIter::<IteratorUMP>::new(heap, cell)
} }
#[inline(always)] #[inline(always)]
@@ -240,13 +277,14 @@ pub(crate) fn stackful_preorder_iter(
} }
#[derive(Debug)] #[derive(Debug)]
pub(crate) struct PostOrderIterator<Iter: Iterator<Item = HeapCellValue>> { pub(crate) struct PostOrderIterator<Iter: FocusedHeapIter> {
focus: usize,
base_iter: Iter, base_iter: Iter,
base_iter_valid: bool, base_iter_valid: bool,
parent_stack: Vec<(usize, HeapCellValue)>, // number of children, parent node. parent_stack: Vec<(usize, HeapCellValue, usize)>, // number of children, parent node, focus.
} }
impl<Iter: Iterator<Item = HeapCellValue>> Deref for PostOrderIterator<Iter> { impl<Iter: FocusedHeapIter> Deref for PostOrderIterator<Iter> {
type Target = Iter; type Target = Iter;
fn deref(&self) -> &Self::Target { fn deref(&self) -> &Self::Target {
@@ -254,9 +292,10 @@ impl<Iter: Iterator<Item = HeapCellValue>> Deref for PostOrderIterator<Iter> {
} }
} }
impl<Iter: Iterator<Item = HeapCellValue>> PostOrderIterator<Iter> { impl<Iter: FocusedHeapIter> PostOrderIterator<Iter> {
pub(crate) fn new(base_iter: Iter) -> Self { pub(crate) fn new(base_iter: Iter) -> Self {
PostOrderIterator { PostOrderIterator {
focus: 0,
base_iter, base_iter,
base_iter_valid: true, base_iter_valid: true,
parent_stack: vec![], parent_stack: vec![],
@@ -264,32 +303,36 @@ impl<Iter: Iterator<Item = HeapCellValue>> PostOrderIterator<Iter> {
} }
} }
impl<Iter: Iterator<Item = HeapCellValue>> Iterator for PostOrderIterator<Iter> { impl<Iter: FocusedHeapIter> Iterator for PostOrderIterator<Iter> {
type Item = HeapCellValue; type Item = HeapCellValue;
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {
loop { loop {
if let Some((child_count, node)) = self.parent_stack.pop() { if let Some((child_count, node, focus)) = self.parent_stack.pop() {
if child_count == 0 { if child_count == 0 {
self.focus = focus;
return Some(node); return Some(node);
} }
self.parent_stack.push((child_count - 1, node)); self.parent_stack.push((child_count - 1, node, focus));
} }
if self.base_iter_valid { if self.base_iter_valid {
if let Some(item) = self.base_iter.next() { if let Some(item) = self.base_iter.next() {
let focus = self.base_iter.focus();
read_heap_cell!(item, read_heap_cell!(item,
(HeapCellValueTag::Atom, (_name, arity)) => { (HeapCellValueTag::Atom, (_name, arity)) => {
self.parent_stack.push((arity, item)); self.parent_stack.push((arity, item, focus));
} }
(HeapCellValueTag::Lis) => { (HeapCellValueTag::Lis) => {
self.parent_stack.push((2, item)); self.parent_stack.push((2, item, focus));
} }
(HeapCellValueTag::PStr | HeapCellValueTag::PStrOffset) => { (HeapCellValueTag::PStr | HeapCellValueTag::PStrOffset) => {
self.parent_stack.push((1, item)); self.parent_stack.push((1, item, focus));
} }
_ => { _ => {
self.focus = focus;
return Some(item); return Some(item);
} }
); );
@@ -307,12 +350,40 @@ impl<Iter: Iterator<Item = HeapCellValue>> Iterator for PostOrderIterator<Iter>
} }
} }
impl<Iter: FocusedHeapIter> FocusedHeapIter for PostOrderIterator<Iter> {
#[inline(always)]
fn focus(&self) -> usize {
self.focus
}
}
impl<Iter: FocusedHeapIter> PostOrderIterator<Iter> {
/* return true if the term at heap offset idx_loc is a
* direct/inlined subterm of a structure at the focus of
* self.stack.last(). this function is used to determine, e.g.,
* ownership of inlined code indices.
*/
#[inline]
pub(crate) fn direct_subterm_of_str(&self, idx_loc: usize) -> bool {
if let Some((_child_count, item, focus)) = self.parent_stack.last() {
read_heap_cell!(item,
(HeapCellValueTag::Atom, (_name, arity)) => {
return focus + arity >= idx_loc && *focus < idx_loc;
}
_ => {}
);
}
false
}
}
pub(crate) type LeftistPostOrderHeapIter<'a> = PostOrderIterator<StackfulPreOrderHeapIter<'a>>; pub(crate) type LeftistPostOrderHeapIter<'a> = PostOrderIterator<StackfulPreOrderHeapIter<'a>>;
impl<'a> LeftistPostOrderHeapIter<'a> { impl<'a> LeftistPostOrderHeapIter<'a> {
#[inline] #[inline]
pub fn pop_stack(&mut self) { pub fn pop_stack(&mut self) {
if let Some((child_count, _)) = self.parent_stack.last() { if let Some((child_count, ..)) = self.parent_stack.last() {
for _ in 0 .. *child_count { for _ in 0 .. *child_count {
self.base_iter.pop_stack(); self.base_iter.pop_stack();
} }
@@ -335,9 +406,11 @@ pub(crate) fn stackful_post_order_iter<'a>(
PostOrderIterator::new(StackfulPreOrderHeapIter::new(heap, cell)) PostOrderIterator::new(StackfulPreOrderHeapIter::new(heap, cell))
} }
#[cfg(test)]
pub(crate) type RightistPostOrderHeapIter<'a> = pub(crate) type RightistPostOrderHeapIter<'a> =
PostOrderIterator<StacklessPreOrderHeapIter<'a, IteratorUMP>>; PostOrderIterator<StacklessPreOrderHeapIter<'a, IteratorUMP>>;
#[cfg(test)]
#[inline] #[inline]
pub(crate) fn stackless_post_order_iter<'a>( pub(crate) fn stackless_post_order_iter<'a>(
heap: &'a mut Heap, heap: &'a mut Heap,
@@ -351,6 +424,7 @@ mod tests {
use super::*; use super::*;
use crate::machine::mock_wam::*; use crate::machine::mock_wam::*;
#[test] #[test]
fn heap_stackless_iter_tests() { fn heap_stackless_iter_tests() {
let mut wam = MockWAM::new(); let mut wam = MockWAM::new();
@@ -513,6 +587,7 @@ mod tests {
unmark_cell_bits!(iter.next().unwrap()), unmark_cell_bits!(iter.next().unwrap()),
atom_as_cell!(b_atom) atom_as_cell!(b_atom)
); );
assert_eq!( assert_eq!(
unmark_cell_bits!(iter.next().unwrap()), unmark_cell_bits!(iter.next().unwrap()),
atom_as_cell!(a_atom) atom_as_cell!(a_atom)
@@ -574,7 +649,7 @@ mod tests {
heap_loc_as_cell!(1), heap_loc_as_cell!(1),
); );
assert_eq!(iter.next(), None); assert!(iter.next().is_none());
} }
assert_eq!(wam.machine_st.heap[0], pstr_cell); assert_eq!(wam.machine_st.heap[0], pstr_cell);
@@ -601,7 +676,7 @@ mod tests {
heap_loc_as_cell!(3), heap_loc_as_cell!(3),
); );
assert_eq!(iter.next(), None); assert!(iter.next().is_none());
} }
assert_eq!(wam.machine_st.heap[0], pstr_cell); assert_eq!(wam.machine_st.heap[0], pstr_cell);
@@ -623,8 +698,8 @@ mod tests {
let pstr_offset_cell = pstr_offset_as_cell!(0); let pstr_offset_cell = pstr_offset_as_cell!(0);
assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_offset_cell); assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_offset_cell);
assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_second_cell);
assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_cell); assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_cell);
assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_second_cell);
assert_eq!(iter.next(), None); assert_eq!(iter.next(), None);
} }
@@ -1257,6 +1332,42 @@ mod tests {
assert_eq!(wam.machine_st.heap[0], atom_as_cell!(atom!("f"), 2)); assert_eq!(wam.machine_st.heap[0], atom_as_cell!(atom!("f"), 2));
assert_eq!(wam.machine_st.heap[1], heap_loc_as_cell!(1)); assert_eq!(wam.machine_st.heap[1], heap_loc_as_cell!(1));
assert_eq!(wam.machine_st.heap[2], heap_loc_as_cell!(1)); assert_eq!(wam.machine_st.heap[2], heap_loc_as_cell!(1));
wam.machine_st.heap.clear();
// representation of one of the heap terms as in issue #1384.
/*
wam.machine_st.heap.push(list_loc_as_cell!(7));
wam.machine_st.heap.push(heap_loc_as_cell!(0));
wam.machine_st.heap.push(list_loc_as_cell!(3));
wam.machine_st.heap.push(list_loc_as_cell!(5));
wam.machine_st.heap.push(empty_list_as_cell!());
wam.machine_st.heap.push(heap_loc_as_cell!(2));
wam.machine_st.heap.push(heap_loc_as_cell!(2));
wam.machine_st.heap.push(empty_list_as_cell!());
wam.machine_st.heap.push(heap_loc_as_cell!(3));
{
let mut iter = stackless_preorder_iter(
&mut wam.machine_st.heap,
heap_loc_as_cell!(0),
);
while let Some(_) = iter.next() {
print_heap_terms(iter.heap.iter(), 0);
println!("");
}
/*
assert_eq!(
unmark_cell_bits!(iter.next().unwrap()),
atom_as_cell!(atom!("f"), 2)
);
assert!(iter.next().is_none());
*/
}
*/
} }
#[test] #[test]
@@ -1271,7 +1382,7 @@ mod tests {
.extend(functor!(f_atom, [atom(a_atom), atom(b_atom)])); .extend(functor!(f_atom, [atom(a_atom), atom(b_atom)]));
{ {
let mut iter = StackfulPreOrderHeapIter::new(&mut wam.machine_st.heap, heap_loc_as_cell!(0)); let mut iter = StackfulPreOrderHeapIter::new(&mut wam.machine_st.heap, str_loc_as_cell!(0));
assert_eq!( assert_eq!(
unmark_cell_bits!(iter.next().unwrap()), unmark_cell_bits!(iter.next().unwrap()),
@@ -1302,7 +1413,7 @@ mod tests {
)); ));
for _ in 0..20 { for _ in 0..20 {
let mut iter = StackfulPreOrderHeapIter::new(&mut wam.machine_st.heap, heap_loc_as_cell!(0)); let mut iter = StackfulPreOrderHeapIter::new(&mut wam.machine_st.heap, str_loc_as_cell!(0));
assert_eq!( assert_eq!(
unmark_cell_bits!(iter.next().unwrap()), unmark_cell_bits!(iter.next().unwrap()),
@@ -1425,7 +1536,7 @@ mod tests {
); );
assert_eq!( assert_eq!(
unmark_cell_bits!(iter.next().unwrap()), unmark_cell_bits!(iter.next().unwrap()),
list_loc_as_cell!(1) heap_loc_as_cell!(0)
); );
assert_eq!(iter.next(), None); assert_eq!(iter.next(), None);
@@ -1669,7 +1780,9 @@ mod tests {
); );
let mut link_back = list_loc_as_cell!(1); let mut link_back = list_loc_as_cell!(1);
link_back.set_forwarding_bit(true); link_back.set_forwarding_bit(true);
link_back.set_mark_bit(true);
assert_eq!(iter.next().unwrap(), link_back); assert_eq!(iter.next().unwrap(), link_back);
@@ -1691,9 +1804,14 @@ mod tests {
); );
let mut cyclic_link = list_loc_as_cell!(1); let mut cyclic_link = list_loc_as_cell!(1);
cyclic_link.set_forwarding_bit(true);
assert_eq!(iter.next().unwrap(), list_loc_as_cell!(1)); cyclic_link.set_forwarding_bit(true);
cyclic_link.set_mark_bit(true);
assert_eq!(
unmark_cell_bits!(iter.next().unwrap()),
list_loc_as_cell!(1)
);
assert_eq!( assert_eq!(
unmark_cell_bits!(iter.next().unwrap()), unmark_cell_bits!(iter.next().unwrap()),
list_loc_as_cell!(1) list_loc_as_cell!(1)
@@ -1757,11 +1875,11 @@ mod tests {
assert_eq!( assert_eq!(
unmark_cell_bits!(iter.next().unwrap()), unmark_cell_bits!(iter.next().unwrap()),
str_loc_as_cell!(1) heap_loc_as_cell!(0)
); );
assert_eq!( assert_eq!(
iter.next().unwrap(), unmark_cell_bits!(iter.next().unwrap()),
atom_as_cell!(atom!("y")) atom_as_cell!(atom!("y"))
); );
@@ -1781,7 +1899,7 @@ mod tests {
.extend(functor!(f_atom, [atom(a_atom), atom(b_atom)])); .extend(functor!(f_atom, [atom(a_atom), atom(b_atom)]));
{ {
let mut iter = stackful_post_order_iter(&mut wam.machine_st.heap, heap_loc_as_cell!(0)); let mut iter = stackful_post_order_iter(&mut wam.machine_st.heap, str_loc_as_cell!(0));
assert_eq!( assert_eq!(
unmark_cell_bits!(iter.next().unwrap()), unmark_cell_bits!(iter.next().unwrap()),
@@ -1812,7 +1930,7 @@ mod tests {
)); ));
for _ in 0..20 { // 0000 { for _ in 0..20 { // 0000 {
let mut iter = stackful_post_order_iter(&mut wam.machine_st.heap, heap_loc_as_cell!(0)); let mut iter = stackful_post_order_iter(&mut wam.machine_st.heap, str_loc_as_cell!(0));
assert_eq!( assert_eq!(
unmark_cell_bits!(iter.next().unwrap()), unmark_cell_bits!(iter.next().unwrap()),
@@ -1929,7 +2047,7 @@ mod tests {
); );
assert_eq!( assert_eq!(
unmark_cell_bits!(iter.next().unwrap()), unmark_cell_bits!(iter.next().unwrap()),
list_loc_as_cell!(1) heap_loc_as_cell!(0)
); );
assert_eq!( assert_eq!(
unmark_cell_bits!(iter.next().unwrap()), unmark_cell_bits!(iter.next().unwrap()),
@@ -2157,7 +2275,9 @@ mod tests {
); );
let mut link_back = list_loc_as_cell!(1); let mut link_back = list_loc_as_cell!(1);
link_back.set_forwarding_bit(true); link_back.set_forwarding_bit(true);
link_back.set_mark_bit(true);
assert_eq!(iter.next().unwrap(), link_back); assert_eq!(iter.next().unwrap(), link_back);
@@ -2271,6 +2391,11 @@ mod tests {
let mut iter = stackless_post_order_iter(&mut wam.machine_st.heap, heap_loc_as_cell!(0)); let mut iter = stackless_post_order_iter(&mut wam.machine_st.heap, heap_loc_as_cell!(0));
assert_eq!(
unmark_cell_bits!(iter.next().unwrap()),
heap_loc_as_cell!(1)
);
assert_eq!( assert_eq!(
unmark_cell_bits!(iter.next().unwrap()), unmark_cell_bits!(iter.next().unwrap()),
heap_loc_as_cell!(0) heap_loc_as_cell!(0)

View File

@@ -1,6 +1,5 @@
use crate::arena::*; use crate::arena::*;
use crate::atom_table::*; use crate::atom_table::*;
use crate::instructions::*;
use crate::parser::ast::*; use crate::parser::ast::*;
use crate::parser::rug::{Integer, Rational}; use crate::parser::rug::{Integer, Rational};
use crate::{ use crate::{
@@ -116,7 +115,6 @@ impl<'a> StackfulPreOrderHeapIter<'a> {
let mut parent_spec = DirectedOp::Left(atom!("-"), OpDesc::build_with(200, FY as u8)); let mut parent_spec = DirectedOp::Left(atom!("-"), OpDesc::build_with(200, FY as u8));
loop { loop {
// match self.machine_st.store(self.machine_st.deref(addr)) {
read_heap_cell!(self.heap[h], read_heap_cell!(self.heap[h],
(HeapCellValueTag::Str, s) => { (HeapCellValueTag::Str, s) => {
read_heap_cell!(self.heap[s], read_heap_cell!(self.heap[s],
@@ -156,7 +154,6 @@ impl<'a> StackfulPreOrderHeapIter<'a> {
None => return false, None => return false,
}; };
// let addr = self.machine_st.store(self.machine_st.deref(addr));
property_check(addr) property_check(addr)
} }
} }
@@ -171,16 +168,12 @@ fn char_to_string(is_quoted: bool, c: char) -> String {
'\u{0c}' if is_quoted => "\\f".to_string(), // UTF-8 form feed '\u{0c}' if is_quoted => "\\f".to_string(), // UTF-8 form feed
'\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(), '\\' 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()
} }
'\u{a0}'..='\u{d6}' => c.to_string(), '\u{0}'..='\u{1f}' => format!("\\x{:x}\\", c as u32), // print all other control characters in hex.
'\u{d8}'..='\u{f6}' => c.to_string(), _ => c.to_string(),
'\u{f8}'..='\u{74f}' => c.to_string(),
'\x20'..='\x7e' => c.to_string(),
_ => format!("\\x{:x}\\", c as u32),
} }
} }
@@ -208,9 +201,10 @@ enum TokenOrRedirect {
Op(Atom, OpDesc), Op(Atom, OpDesc),
NumberedVar(String), NumberedVar(String),
CompositeRedirect(usize, DirectedOp), CompositeRedirect(usize, DirectedOp),
CurlyBracketRedirect(usize),
FunctorRedirect(usize), FunctorRedirect(usize),
#[allow(unused)] IpAddr(IpAddr), #[allow(unused)] IpAddr(IpAddr),
NumberFocus(NumberFocus, Option<DirectedOp>), NumberFocus(usize, NumberFocus, Option<DirectedOp>),
Open, Open,
Close, Close,
Comma, Comma,
@@ -382,9 +376,9 @@ impl HCValueOutputter for PrinterOutputter {
} }
} }
#[inline] #[inline(always)]
fn is_numbered_var(ct: &ClauseType, arity: usize) -> bool { fn is_numbered_var(name: Atom, arity: usize) -> bool {
arity == 1 && ct.name().as_str() == "$VAR" arity == 1 && name == atom!("$VAR")
} }
#[inline] #[inline]
@@ -407,43 +401,6 @@ fn negated_op_needs_bracketing(
} }
} }
pub(crate) fn numbervar(offset: &Integer, addr: HeapCellValue) -> Option<String> {
fn numbervar(n: Integer) -> String {
static CHAR_CODES: [char; 26] = [
'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',
];
let i = n.mod_u(26) as usize;
let j = n.div_rem_floor(Integer::from(26));
let j = <(Integer, Integer)>::from(j).0;
if j == 0 {
CHAR_CODES[i].to_string()
} else {
format!("{}{}", CHAR_CODES[i], j)
}
}
match Number::try_from(addr) {
Ok(Number::Fixnum(n)) => {
if n.get_num() >= 0 {
Some(numbervar(offset + Integer::from(n.get_num())))
} else {
None
}
}
Ok(Number::Integer(n)) => {
if &*n >= &0 {
Some(numbervar(Integer::from(offset + &*n)))
} else {
None
}
}
_ => None,
}
}
macro_rules! push_char { macro_rules! push_char {
($self:ident, $c:expr) => {{ ($self:ident, $c:expr) => {{
$self.outputter.push_char($c); $self.outputter.push_char($c);
@@ -484,11 +441,33 @@ macro_rules! print_char {
}; };
} }
pub fn fmt_float(mut fl: f64) -> String {
if OrderedFloat(fl) == -0f64 {
fl = 0f64;
}
let mut buffer = ryu::Buffer::new();
let fl_str = buffer.format(fl);
/* When printing floats with zero fractional parts in scientific notation, ryu
* prints "{integer part}e{exponent}" without a ".0" preceding "e",
* which is not valid ISO Prolog syntax. Add ".0" manually in this
* case.
*/
if let Some(e_index) = fl_str.find('e') {
if !fl_str[0 .. e_index].contains('.') {
return fl_str[0 .. e_index].to_string() + ".0" + &fl_str[e_index ..];
}
}
fl_str.to_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>,
arena: &'a mut Arena,
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,10 +492,46 @@ macro_rules! push_space_if_amb {
}; };
} }
pub(crate) fn numbervar(offset: &Integer, addr: HeapCellValue) -> Option<String> {
fn numbervar(n: Integer) -> String {
static CHAR_CODES: [char; 26] = [
'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',
];
let i = n.mod_u(26) as usize;
let j = n.div_rem_floor(Integer::from(26));
let j = <(Integer, Integer)>::from(j).0;
if j == 0 {
CHAR_CODES[i].to_string()
} else {
format!("{}{}", CHAR_CODES[i], j)
}
}
match Number::try_from(addr) {
Ok(Number::Fixnum(n)) => {
if n.get_num() >= 0 {
Some(numbervar(offset + Integer::from(n.get_num())))
} else {
None
}
}
Ok(Number::Integer(n)) => {
if &*n >= &0 {
Some(numbervar(Integer::from(offset + &*n)))
} else {
None
}
}
_ => None,
}
}
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,
arena: &'a mut Arena,
op_dir: &'a OpDir, op_dir: &'a OpDir,
output: Outputter, output: Outputter,
cell: HeapCellValue, cell: HeapCellValue,
@@ -524,7 +539,6 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
HCPrinter { HCPrinter {
outputter: output, outputter: output,
iter: stackful_preorder_iter(heap, cell), iter: stackful_preorder_iter(heap, cell),
arena,
op_dir, op_dir,
state_stack: vec![], state_stack: vec![],
toplevel_spec: None, toplevel_spec: None,
@@ -545,9 +559,7 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
requires_space(tail, atom) requires_space(tail, atom)
} }
fn enqueue_op(&mut self, mut max_depth: usize, ct: ClauseType, spec: OpDesc) { fn enqueue_op(&mut self, mut max_depth: usize, name: Atom, spec: OpDesc) {
let name = ct.name();
if is_postfix!(spec.get_spec()) { if is_postfix!(spec.get_spec()) {
if self.check_max_depth(&mut max_depth) { if self.check_max_depth(&mut max_depth) {
self.iter.pop_stack(); self.iter.pop_stack();
@@ -634,26 +646,30 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
self.iter.pop_stack(); self.iter.pop_stack();
} }
if arity > 0 {
self.state_stack.push(TokenOrRedirect::Close); self.state_stack.push(TokenOrRedirect::Close);
self.state_stack.push(TokenOrRedirect::Atom(atom!("..."))); self.state_stack.push(TokenOrRedirect::Atom(atom!("...")));
self.state_stack.push(TokenOrRedirect::Open); self.state_stack.push(TokenOrRedirect::Open);
}
self.state_stack.push(TokenOrRedirect::Atom(name)); self.state_stack.push(TokenOrRedirect::Atom(name));
return false; return false;
} }
if arity > 0 {
self.state_stack.push(TokenOrRedirect::Close); self.state_stack.push(TokenOrRedirect::Close);
for _ in 0..arity { for _ in 0..arity {
self.state_stack self.state_stack.push(TokenOrRedirect::FunctorRedirect(max_depth));
.push(TokenOrRedirect::FunctorRedirect(max_depth));
self.state_stack.push(TokenOrRedirect::Comma); self.state_stack.push(TokenOrRedirect::Comma);
} }
self.state_stack.pop(); self.state_stack.pop();
self.state_stack.push(TokenOrRedirect::Open); self.state_stack.push(TokenOrRedirect::Open);
}
self.state_stack.push(TokenOrRedirect::Atom(name)); self.state_stack.push(TokenOrRedirect::Atom(name));
true true
@@ -672,8 +688,7 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
let op = DirectedOp::Left(name, spec); let op = DirectedOp::Left(name, spec);
self.state_stack self.state_stack.push(TokenOrRedirect::CompositeRedirect(max_depth, op));
.push(TokenOrRedirect::CompositeRedirect(max_depth, op));
self.state_stack.push(TokenOrRedirect::Space); self.state_stack.push(TokenOrRedirect::Space);
self.state_stack.push(TokenOrRedirect::Atom(name)); self.state_stack.push(TokenOrRedirect::Atom(name));
} }
@@ -720,9 +735,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 self.state_stack.push(TokenOrRedirect::CurlyBracketRedirect(max_depth));
.push(TokenOrRedirect::FunctorRedirect(max_depth));
self.state_stack.push(TokenOrRedirect::LeftCurly); self.state_stack.push(TokenOrRedirect::LeftCurly);
true true
@@ -731,8 +746,14 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
fn format_numbered_vars(&mut self) -> bool { fn format_numbered_vars(&mut self) -> bool {
let h = self.iter.stack_last().unwrap(); let h = self.iter.stack_last().unwrap();
let addr = self.iter.heap[h];
let addr = heap_bound_store(
&self.iter.heap,
heap_bound_deref(&self.iter.heap, addr),
);
// 7.10.4 // 7.10.4
if let Some(var) = numbervar(&self.numbervars_offset, self.iter.heap[h]) { if let Some(var) = numbervar(&self.numbervars_offset, addr) {
self.iter.pop_stack(); self.iter.pop_stack();
self.state_stack.push(TokenOrRedirect::NumberedVar(var)); self.state_stack.push(TokenOrRedirect::NumberedVar(var));
return true; return true;
@@ -745,17 +766,16 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
&mut self, &mut self,
max_depth: usize, max_depth: usize,
arity: usize, arity: usize,
ct: ClauseType, name: Atom,
op_desc: Option<OpDesc>, op_desc: Option<OpDesc>,
) -> bool { ) -> bool {
if self.numbervars && is_numbered_var(&ct, arity) { if self.numbervars && is_numbered_var(name, arity) {
if self.format_numbered_vars() { if self.format_numbered_vars() {
return true; return true;
} }
} }
let dot_atom = atom!("."); let dot_atom = atom!(".");
let name = ct.name();
if let Some(spec) = op_desc { if let Some(spec) = op_desc {
if dot_atom == name && is_infix!(spec.get_spec()) { if dot_atom == name && is_infix!(spec.get_spec()) {
@@ -766,13 +786,13 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
} }
if !self.ignore_ops && spec.get_prec() > 0 { if !self.ignore_ops && spec.get_prec() > 0 {
self.enqueue_op(max_depth, ct, spec); self.enqueue_op(max_depth, name, spec);
return true; return true;
} }
} }
return match (name.as_str(), arity) { return match (name, arity) {
("{}", 1) if !self.ignore_ops => self.format_curly_braces(max_depth), (atom!("{}"), 1) if !self.ignore_ops => self.format_curly_braces(max_depth),
_ => self.format_struct(max_depth, arity, name), _ => self.format_struct(max_depth, arity, name),
}; };
} }
@@ -810,7 +830,7 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
fn check_for_seen(&mut self) -> Option<HeapCellValue> { fn check_for_seen(&mut self) -> Option<HeapCellValue> {
if let Some(addr) = self.iter.next() { if let Some(addr) = self.iter.next() {
let is_cyclic = addr.is_forwarded(); let is_cyclic = addr.get_forwarding_bit();
let addr = heap_bound_store( let addr = heap_bound_store(
self.iter.heap, self.iter.heap,
@@ -836,7 +856,7 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
None None
} }
var_opt => { var_opt => {
if is_cyclic && addr.is_compound() { if is_cyclic && addr.is_compound(self.iter.heap) {
// self-referential variables are marked "cyclic". // self-referential variables are marked "cyclic".
match var_opt { match var_opt {
Some(var) => { Some(var) => {
@@ -922,7 +942,7 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
append_str!(self, &format!("0x{:x}", ptr as *const u8 as usize)); append_str!(self, &format!("0x{:x}", ptr as *const u8 as usize));
} }
fn print_number(&mut self, n: NumberFocus, op: &Option<DirectedOp>) { fn print_number(&mut self, max_depth: usize, n: NumberFocus, op: &Option<DirectedOp>) {
let add_brackets = if let Some(op) = op { let add_brackets = if let Some(op) = op {
op.is_negative_sign() && !n.is_negative() op.is_negative_sign() && !n.is_negative()
} else { } else {
@@ -935,30 +955,15 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
match n { match n {
NumberFocus::Unfocused(n) => match n { NumberFocus::Unfocused(n) => match n {
Number::Float(OrderedFloat(mut fl)) => { Number::Float(OrderedFloat(fl)) => {
if OrderedFloat(fl) == -0f64 { let output_str = fmt_float(fl);
fl = 0f64;
}
let output_str = if fl.fract() == 0f64 {
if fl.abs() >= 1.0e16 {
format!("{:.1e}", fl.trunc())
} else {
format!("{:.1}", fl.trunc())
}
} else if 0f64 < fl.fract().abs() && fl.fract().abs() <= 1.0e-16 {
format!("{:>1e}", fl)
} else {
format!("{}", fl)
};
push_space_if_amb!(self, &output_str, { push_space_if_amb!(self, &output_str, {
append_str!(self, &output_str); append_str!(self, &output_str);
}); });
} }
Number::Rational(r) => { Number::Rational(r) => {
self.print_rational(r, add_brackets); self.print_rational(max_depth, r);
return;
} }
n => { n => {
let output_str = format!("{}", n); let output_str = format!("{}", n);
@@ -989,11 +994,27 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
} }
} }
fn print_rational(&mut self, r: TypedArenaPtr<Rational>, add_brackets: bool) { fn print_rational(&mut self, mut max_depth: usize, r: TypedArenaPtr<Rational>) {
if self.check_max_depth(&mut max_depth) {
self.state_stack.push(TokenOrRedirect::Close);
self.state_stack.push(TokenOrRedirect::Atom(atom!("...")));
self.state_stack.push(TokenOrRedirect::Open);
self.state_stack.push(TokenOrRedirect::Atom(atom!("rdiv")));
return;
}
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 add_brackets { if r.is_integer() {
self.state_stack.push(TokenOrRedirect::Close); let output_str = format!("{}", r);
push_space_if_amb!(self, &output_str, {
append_str!(self, &output_str);
});
return;
} }
let rdiv_ct = atom!("rdiv"); let rdiv_ct = atom!("rdiv");
@@ -1010,8 +1031,9 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
None None
}; };
if op_desc.get_prec() > 0 { if !self.ignore_ops && op_desc.get_prec() > 0 {
self.state_stack.push(TokenOrRedirect::NumberFocus( self.state_stack.push(TokenOrRedirect::NumberFocus(
max_depth,
NumberFocus::Denominator(r), NumberFocus::Denominator(r),
left_directed_op, left_directed_op,
)); ));
@@ -1020,6 +1042,7 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
.push(TokenOrRedirect::Op(rdiv_ct, *op_desc)); .push(TokenOrRedirect::Op(rdiv_ct, *op_desc));
self.state_stack.push(TokenOrRedirect::NumberFocus( self.state_stack.push(TokenOrRedirect::NumberFocus(
max_depth,
NumberFocus::Numerator(r), NumberFocus::Numerator(r),
right_directed_op, right_directed_op,
)); ));
@@ -1027,6 +1050,7 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
self.state_stack.push(TokenOrRedirect::Close); self.state_stack.push(TokenOrRedirect::Close);
self.state_stack.push(TokenOrRedirect::NumberFocus( self.state_stack.push(TokenOrRedirect::NumberFocus(
max_depth,
NumberFocus::Denominator(r), NumberFocus::Denominator(r),
None, None,
)); ));
@@ -1034,6 +1058,7 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
self.state_stack.push(TokenOrRedirect::Comma); self.state_stack.push(TokenOrRedirect::Comma);
self.state_stack.push(TokenOrRedirect::NumberFocus( self.state_stack.push(TokenOrRedirect::NumberFocus(
max_depth,
NumberFocus::Numerator(r), NumberFocus::Numerator(r),
None, None,
)); ));
@@ -1076,10 +1101,19 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
push_char!(self, '"'); push_char!(self, '"');
let iter = HeapPStrIter::new(self.iter.heap, focus); let iter = HeapPStrIter::new(self.iter.heap, focus);
let char_to_string = |c: char| {
// refrain from quoting characters other than '"' and '\'
// unless self.quoted is true.
match c {
'\\' => "\\\\".to_string(),
'"' => "\\\"".to_string(),
_ => char_to_string(self.quoted, c),
}
};
if max_depth == 0 { if max_depth == 0 {
for c in iter.chars() { for c in iter.chars() {
for c in char_to_string(self.quoted, c).chars() { for c in char_to_string(c).chars() {
push_char!(self, c); push_char!(self, c);
} }
} }
@@ -1089,7 +1123,7 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
for c in iter.chars().take(max_depth) { for c in iter.chars().take(max_depth) {
char_count += 1; char_count += 1;
for c in char_to_string(self.quoted, c).chars() { for c in char_to_string(c).chars() {
push_char!(self, c); push_char!(self, c);
} }
} }
@@ -1175,18 +1209,25 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
let pstr = cell_as_string!(self.iter.heap[h]); let pstr = cell_as_string!(self.iter.heap[h]);
let pstr = pstr.as_str_from(offset.get_num() as usize); let pstr = pstr.as_str_from(offset.get_num() as usize);
let tag = value.get_tag();
if tag == HeapCellValueTag::PStrOffset {
// remove the fixnum offset from the iterator stack so we don't
// print an extraneous number. pstr offset value cells are never
// used by the iterator to mark cyclic terms so the removal is safe.
self.iter.pop_stack();
}
if max_depth > 0 && pstr.chars().count() + 1 >= max_depth { if max_depth > 0 && pstr.chars().count() + 1 >= max_depth {
if value.get_tag() != HeapCellValueTag::CStr { if tag != HeapCellValueTag::PStrOffset && tag != HeapCellValueTag::CStr {
self.iter.pop_stack(); self.iter.pop_stack();
} }
self.state_stack.push(TokenOrRedirect::Atom(atom!("..."))); self.state_stack.push(TokenOrRedirect::Atom(atom!("...")));
self.state_stack.push(TokenOrRedirect::HeadTailSeparator); self.state_stack.push(TokenOrRedirect::HeadTailSeparator);
} else if end_cell != empty_list_as_cell!() { } else if end_cell != empty_list_as_cell!() {
if value.get_tag() != HeapCellValueTag::CStr { if tag == HeapCellValueTag::PStrOffset {
self.iter.pop_stack(); self.iter.push_stack(end_h);
self.iter.push_stack(h+1);
} }
self.state_stack.push(TokenOrRedirect::FunctorRedirect(max_depth)); self.state_stack.push(TokenOrRedirect::FunctorRedirect(max_depth));
@@ -1264,9 +1305,9 @@ 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.as_str() == "$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 >= &0, Ok(Number::Integer(n)) => &*n >= &0,
@@ -1290,9 +1331,7 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
self.state_stack.push(TokenOrRedirect::Close); self.state_stack.push(TokenOrRedirect::Close);
} }
let ct = ClauseType::from(name, arity); if self.format_clause(max_depth, arity, name, Some(op_desc)) && add_brackets {
if self.format_clause(max_depth, arity, ct, Some(op_desc)) && add_brackets {
self.state_stack.push(TokenOrRedirect::Open); self.state_stack.push(TokenOrRedirect::Open);
if let Some(ref op) = &op { if let Some(ref op) = &op {
@@ -1306,10 +1345,7 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
#[allow(dead_code)] #[allow(dead_code)]
fn print_tcp_listener(&mut self, tcp_listener: &TcpListener, max_depth: usize) { fn print_tcp_listener(&mut self, tcp_listener: &TcpListener, max_depth: usize) {
let (ip, port) = if let Some(addr) = tcp_listener.local_addr().ok() { let (ip, port) = if let Some(addr) = tcp_listener.local_addr().ok() {
( (addr.ip(), addr.port())
addr.ip(),
Number::arena_from(addr.port() as usize, self.arena),
)
} else { } else {
let disconnected_atom = atom!("$disconnected_tcp_listener"); let disconnected_atom = atom!("$disconnected_tcp_listener");
self.state_stack self.state_stack
@@ -1327,7 +1363,8 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
self.state_stack.pop(); self.state_stack.pop();
self.state_stack.push(TokenOrRedirect::NumberFocus( self.state_stack.push(TokenOrRedirect::NumberFocus(
NumberFocus::Unfocused(port), max_depth,
NumberFocus::Unfocused(Number::Fixnum(Fixnum::build_with(port as i64))),
None, None,
)); ));
self.state_stack.push(TokenOrRedirect::Comma); self.state_stack.push(TokenOrRedirect::Comma);
@@ -1338,6 +1375,31 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
} }
} }
fn print_index_ptr(&mut self, index_ptr: IndexPtr, max_depth: usize) {
if self.format_struct(max_depth, 1, atom!("$index_ptr")) {
let atom = self.state_stack.pop().unwrap();
self.state_stack.pop();
self.state_stack.pop();
let offset = if index_ptr.is_undefined() || index_ptr.is_dynamic_undefined() {
TokenOrRedirect::Atom(atom!("undefined"))
} else {
let idx = index_ptr.p() as i64;
TokenOrRedirect::NumberFocus(
max_depth,
NumberFocus::Unfocused(Number::Fixnum(Fixnum::build_with(idx))),
None,
)
};
self.state_stack.push(offset);
self.state_stack.push(TokenOrRedirect::Open);
self.state_stack.push(atom);
}
}
fn print_stream(&mut self, stream: Stream, max_depth: usize) { fn print_stream(&mut self, stream: Stream, max_depth: usize) {
if let Some(alias) = stream.options().get_alias() { if let Some(alias) = stream.options().get_alias() {
self.print_atom(alias); self.print_atom(alias);
@@ -1395,8 +1457,7 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
); );
} else { } else {
push_space_if_amb!(self, name.as_str(), { push_space_if_amb!(self, name.as_str(), {
let ct = ClauseType::from(name, arity); self.format_clause(max_depth, arity, name, None);
self.format_clause(max_depth, arity, ct, None);
}); });
} }
} else if fetch_op_spec(name, arity, self.op_dir).is_some() { } else if fetch_op_spec(name, arity, self.op_dir).is_some() {
@@ -1441,16 +1502,15 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
); );
} else { } else {
push_space_if_amb!(self, name.as_str(), { push_space_if_amb!(self, name.as_str(), {
let ct = ClauseType::from(name, arity); self.format_clause(max_depth, arity, name, None);
self.format_clause(max_depth, arity, ct, None);
}); });
} }
} }
(HeapCellValueTag::Fixnum, n) => { (HeapCellValueTag::Fixnum, n) => {
self.print_number(NumberFocus::Unfocused(Number::Fixnum(n)), &op); self.print_number(max_depth, NumberFocus::Unfocused(Number::Fixnum(n)), &op);
} }
(HeapCellValueTag::F64, f) => { (HeapCellValueTag::F64, f) => {
self.print_number(NumberFocus::Unfocused(Number::Float(**f)), &op); self.print_number(max_depth, NumberFocus::Unfocused(Number::Float(*f)), &op);
} }
(HeapCellValueTag::CStr | HeapCellValueTag::PStr | HeapCellValueTag::PStrOffset) => { (HeapCellValueTag::CStr | HeapCellValueTag::PStr | HeapCellValueTag::PStrOffset) => {
self.print_list_like(max_depth); self.print_list_like(max_depth);
@@ -1477,20 +1537,23 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
} }
(HeapCellValueTag::Cons, c) => { (HeapCellValueTag::Cons, c) => {
match_untyped_arena_ptr!(c, match_untyped_arena_ptr!(c,
(ArenaHeaderTag::F64, f) => {
self.print_number(NumberFocus::Unfocused(Number::Float(*f)), &op);
}
(ArenaHeaderTag::Integer, n) => { (ArenaHeaderTag::Integer, n) => {
self.print_number(NumberFocus::Unfocused(Number::Integer(n)), &op); self.print_number(max_depth, NumberFocus::Unfocused(Number::Integer(n)), &op);
} }
(ArenaHeaderTag::Rational, r) => { (ArenaHeaderTag::Rational, r) => {
self.print_number(NumberFocus::Unfocused(Number::Rational(r)), &op); self.print_number(max_depth, NumberFocus::Unfocused(Number::Rational(r)), &op);
} }
(ArenaHeaderTag::Stream, stream) => { (ArenaHeaderTag::Stream, stream) => {
self.print_stream(stream, max_depth); self.print_stream(stream, max_depth);
} }
(ArenaHeaderTag::OssifiedOpDir, _op_dir) => { (ArenaHeaderTag::OssifiedOpDir, _op_dir) => {
append_str!(self, "$ossified_op_dir"); self.print_atom(atom!("$ossified_op_dir"));
}
(ArenaHeaderTag::Dropped, _value) => {
self.print_atom(atom!("$dropped_value"));
}
(ArenaHeaderTag::IndexPtr, index_ptr) => {
self.print_index_ptr(*index_ptr, max_depth);
} }
_ => { _ => {
} }
@@ -1516,8 +1579,10 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
} }
pub fn print(mut self) -> Outputter { pub fn print(mut self) -> Outputter {
loop { let spec = self.toplevel_spec.take();
if let Some(loc_data) = self.state_stack.pop() { self.handle_heap_term(spec, false, self.max_depth);
while let Some(loc_data) = self.state_stack.pop() {
match loc_data { match loc_data {
TokenOrRedirect::Atom(atom) => self.print_atom(atom), TokenOrRedirect::Atom(atom) => self.print_atom(atom),
TokenOrRedirect::BarAsOp => append_str!(self, " | "), TokenOrRedirect::BarAsOp => append_str!(self, " | "),
@@ -1527,6 +1592,9 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
TokenOrRedirect::CompositeRedirect(max_depth, op) => { TokenOrRedirect::CompositeRedirect(max_depth, op) => {
self.handle_heap_term(Some(op), false, max_depth) self.handle_heap_term(Some(op), false, max_depth)
} }
TokenOrRedirect::CurlyBracketRedirect(max_depth) => {
self.handle_heap_term(None, false, max_depth)
}
TokenOrRedirect::FunctorRedirect(max_depth) => { TokenOrRedirect::FunctorRedirect(max_depth) => {
self.handle_heap_term(None, true, max_depth) self.handle_heap_term(None, true, max_depth)
} }
@@ -1548,18 +1616,14 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
} }
} }
TokenOrRedirect::HeadTailSeparator => append_str!(self, "|"), TokenOrRedirect::HeadTailSeparator => append_str!(self, "|"),
TokenOrRedirect::NumberFocus(n, op) => self.print_number(n, &op), TokenOrRedirect::NumberFocus(max_depth, n, op) => {
self.print_number(max_depth, n, &op);
}
TokenOrRedirect::Comma => append_str!(self, ","), TokenOrRedirect::Comma => append_str!(self, ","),
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, '}'),
} }
} else if !self.iter.stack_is_empty() {
let spec = self.toplevel_spec.take();
self.handle_heap_term(spec, false, self.max_depth);
} else {
break;
}
} }
self.outputter self.outputter
@@ -1586,7 +1650,6 @@ mod tests {
{ {
let printer = HCPrinter::new( let printer = HCPrinter::new(
&mut wam.machine_st.heap, &mut wam.machine_st.heap,
&mut wam.machine_st.arena,
&wam.op_dir, &wam.op_dir,
PrinterOutputter::new(), PrinterOutputter::new(),
heap_loc_as_cell!(0) heap_loc_as_cell!(0)
@@ -1614,7 +1677,6 @@ mod tests {
{ {
let printer = HCPrinter::new( let printer = HCPrinter::new(
&mut wam.machine_st.heap, &mut wam.machine_st.heap,
&mut wam.machine_st.arena,
&wam.op_dir, &wam.op_dir,
PrinterOutputter::new(), PrinterOutputter::new(),
heap_loc_as_cell!(0) heap_loc_as_cell!(0)
@@ -1637,7 +1699,6 @@ mod tests {
{ {
let printer = HCPrinter::new( let printer = HCPrinter::new(
&mut wam.machine_st.heap, &mut wam.machine_st.heap,
&mut wam.machine_st.arena,
&wam.op_dir, &wam.op_dir,
PrinterOutputter::new(), PrinterOutputter::new(),
heap_loc_as_cell!(0) heap_loc_as_cell!(0)
@@ -1649,7 +1710,6 @@ 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.arena,
&wam.op_dir, &wam.op_dir,
PrinterOutputter::new(), PrinterOutputter::new(),
heap_loc_as_cell!(0) heap_loc_as_cell!(0)
@@ -1681,7 +1741,6 @@ mod tests {
{ {
let printer = HCPrinter::new( let printer = HCPrinter::new(
&mut wam.machine_st.heap, &mut wam.machine_st.heap,
&mut wam.machine_st.arena,
&wam.op_dir, &wam.op_dir,
PrinterOutputter::new(), PrinterOutputter::new(),
heap_loc_as_cell!(0), heap_loc_as_cell!(0),
@@ -1699,7 +1758,6 @@ mod tests {
{ {
let printer = HCPrinter::new( let printer = HCPrinter::new(
&mut wam.machine_st.heap, &mut wam.machine_st.heap,
&mut wam.machine_st.arena,
&wam.op_dir, &wam.op_dir,
PrinterOutputter::new(), PrinterOutputter::new(),
heap_loc_as_cell!(0), heap_loc_as_cell!(0),
@@ -1715,7 +1773,6 @@ 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.arena,
&wam.op_dir, &wam.op_dir,
PrinterOutputter::new(), PrinterOutputter::new(),
heap_loc_as_cell!(0) heap_loc_as_cell!(0)
@@ -1746,7 +1803,6 @@ 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.arena,
&wam.op_dir, &wam.op_dir,
PrinterOutputter::new(), PrinterOutputter::new(),
heap_loc_as_cell!(0) heap_loc_as_cell!(0)
@@ -1768,7 +1824,6 @@ mod tests {
{ {
let printer = HCPrinter::new( let printer = HCPrinter::new(
&mut wam.machine_st.heap, &mut wam.machine_st.heap,
&mut wam.machine_st.arena,
&wam.op_dir, &wam.op_dir,
PrinterOutputter::new(), PrinterOutputter::new(),
pstr_loc_as_cell!(0) pstr_loc_as_cell!(0)
@@ -1795,7 +1850,6 @@ mod tests {
{ {
let printer = HCPrinter::new( let printer = HCPrinter::new(
&mut wam.machine_st.heap, &mut wam.machine_st.heap,
&mut wam.machine_st.arena,
&wam.op_dir, &wam.op_dir,
PrinterOutputter::new(), PrinterOutputter::new(),
heap_loc_as_cell!(0), heap_loc_as_cell!(0),

25
src/http.rs Normal file
View File

@@ -0,0 +1,25 @@
use std::sync::Arc;
use std::convert::Infallible;
use hyper::{Response, Request, Body};
use tokio::sync::Mutex;
use tokio::sync::mpsc::{channel, Receiver, Sender};
pub struct HttpListener {
pub incoming: Receiver<HttpRequest>
}
#[derive(Debug)]
pub struct HttpRequest {
pub request: Request<Body>,
pub response: HttpResponse,
}
pub type HttpResponse = Sender<Response<Body>>;
pub async fn serve_req(req: Request<Body>, tx: Arc<Mutex<Sender<HttpRequest>>>) -> Result<Response<Body>, Infallible> {
let (response_tx, mut rx) = channel(1);
let http_request = HttpRequest { request: req, response: response_tx };
tx.lock().await.send(http_request).await.unwrap();
Ok(rx.recv().await.unwrap())
}

View File

@@ -4,8 +4,8 @@ use crate::parser::ast::*;
use crate::forms::*; use crate::forms::*;
use crate::instructions::*; use crate::instructions::*;
use fxhash::FxBuildHasher;
use indexmap::IndexMap; use indexmap::IndexMap;
use slice_deque::{sdeq, SliceDeque};
use std::collections::VecDeque; use std::collections::VecDeque;
use std::hash::Hash; use std::hash::Hash;
@@ -108,7 +108,7 @@ impl<'a> IndexingCodeMergingPtr<'a> {
self.append_or_prepend, self.append_or_prepend,
); );
let mut constants = IndexMap::new(); let mut constants = IndexMap::with_hasher(FxBuildHasher::default());
match constant_key { match constant_key {
Some(OptArgIndexKey::Literal(_, _, constant, _)) => { Some(OptArgIndexKey::Literal(_, _, constant, _)) => {
@@ -148,15 +148,15 @@ impl<'a> IndexingCodeMergingPtr<'a> {
index: usize, index: usize,
) { ) {
let third_level_index = if self.append_or_prepend.is_append() { let third_level_index = if self.append_or_prepend.is_append() {
sdeq![ vec![
IndexedChoiceInstruction::Try(external), IndexedChoiceInstruction::Try(external),
IndexedChoiceInstruction::Trust(index) IndexedChoiceInstruction::Trust(index)
] ].into()
} else { } else {
sdeq![ vec![
IndexedChoiceInstruction::Try(index), IndexedChoiceInstruction::Try(index),
IndexedChoiceInstruction::Trust(external) IndexedChoiceInstruction::Trust(external)
] ].into()
}; };
let indexing_code_len = self.indexing_code.len(); let indexing_code_len = self.indexing_code.len();
@@ -182,9 +182,9 @@ impl<'a> IndexingCodeMergingPtr<'a> {
index: usize, index: usize,
) { ) {
let third_level_index = if self.append_or_prepend.is_append() { let third_level_index = if self.append_or_prepend.is_append() {
sdeq![external, index] vec![external, index].into()
} else { } else {
sdeq![index, external] vec![index, external].into()
}; };
let indexing_code_len = self.indexing_code.len(); let indexing_code_len = self.indexing_code.len();
@@ -208,11 +208,11 @@ impl<'a> IndexingCodeMergingPtr<'a> {
IndexingLine::IndexedChoice(ref mut indexed_choice_instrs) IndexingLine::IndexedChoice(ref mut indexed_choice_instrs)
if self.append_or_prepend.is_append() => if self.append_or_prepend.is_append() =>
{ {
uncap_choice_seq_with_trust(indexed_choice_instrs); uncap_choice_seq_with_trust(indexed_choice_instrs.make_contiguous());
indexed_choice_instrs.push_back(IndexedChoiceInstruction::Trust(index)); indexed_choice_instrs.push_back(IndexedChoiceInstruction::Trust(index));
} }
IndexingLine::IndexedChoice(ref mut indexed_choice_instrs) => { IndexingLine::IndexedChoice(ref mut indexed_choice_instrs) => {
uncap_choice_seq_with_try(indexed_choice_instrs); uncap_choice_seq_with_try(indexed_choice_instrs.make_contiguous());
indexed_choice_instrs.push_front(IndexedChoiceInstruction::Try(index)); indexed_choice_instrs.push_front(IndexedChoiceInstruction::Try(index));
} }
IndexingLine::DynamicIndexedChoice(ref mut indexed_choice_instrs) IndexingLine::DynamicIndexedChoice(ref mut indexed_choice_instrs)
@@ -250,7 +250,7 @@ impl<'a> IndexingCodeMergingPtr<'a> {
break; break;
} }
IndexingCodePtr::DynamicExternal(_) | IndexingCodePtr::External(_) => { IndexingCodePtr::DynamicExternal(_) | IndexingCodePtr::External(_) => {
let mut constants = IndexMap::new(); let mut constants = IndexMap::with_hasher(FxBuildHasher::default());
constants.insert(orig_constant, *c); constants.insert(orig_constant, *c);
*c = IndexingCodePtr::Internal(indexing_code_len); *c = IndexingCodePtr::Internal(indexing_code_len);
@@ -390,7 +390,7 @@ impl<'a> IndexingCodeMergingPtr<'a> {
self.append_or_prepend, self.append_or_prepend,
); );
let mut structures = IndexMap::new(); let mut structures = IndexMap::with_hasher(FxBuildHasher::default());
match structure_key { match structure_key {
Some(OptArgIndexKey::Structure(_, _, name, arity)) => { Some(OptArgIndexKey::Structure(_, _, name, arity)) => {
@@ -430,15 +430,15 @@ impl<'a> IndexingCodeMergingPtr<'a> {
index: usize, index: usize,
) { ) {
let third_level_index = if self.append_or_prepend.is_append() { let third_level_index = if self.append_or_prepend.is_append() {
sdeq![ vec![
IndexedChoiceInstruction::Try(external), IndexedChoiceInstruction::Try(external),
IndexedChoiceInstruction::Trust(index) IndexedChoiceInstruction::Trust(index)
] ].into()
} else { } else {
sdeq![ vec![
IndexedChoiceInstruction::Try(index), IndexedChoiceInstruction::Try(index),
IndexedChoiceInstruction::Trust(external) IndexedChoiceInstruction::Trust(external)
] ].into()
}; };
let indexing_code_len = self.indexing_code.len(); let indexing_code_len = self.indexing_code.len();
@@ -464,9 +464,9 @@ impl<'a> IndexingCodeMergingPtr<'a> {
index: usize, index: usize,
) { ) {
let third_level_index = if self.append_or_prepend.is_append() { let third_level_index = if self.append_or_prepend.is_append() {
sdeq![external, index] vec![external, index].into()
} else { } else {
sdeq![index, external] vec![index, external].into()
}; };
let indexing_code_len = self.indexing_code.len(); let indexing_code_len = self.indexing_code.len();
@@ -570,9 +570,9 @@ impl<'a> IndexingCodeMergingPtr<'a> {
*l = IndexingCodePtr::Internal(indexing_code_len - self.offset); *l = IndexingCodePtr::Internal(indexing_code_len - self.offset);
let third_level_index = if self.append_or_prepend.is_append() { let third_level_index = if self.append_or_prepend.is_append() {
sdeq![o, index] vec![o, index].into()
} else { } else {
sdeq![index, o] vec![index, o].into()
}; };
self.indexing_code self.indexing_code
@@ -582,15 +582,15 @@ impl<'a> IndexingCodeMergingPtr<'a> {
*l = IndexingCodePtr::Internal(indexing_code_len - self.offset); *l = IndexingCodePtr::Internal(indexing_code_len - self.offset);
let third_level_index = if self.append_or_prepend.is_append() { let third_level_index = if self.append_or_prepend.is_append() {
sdeq![ vec![
IndexedChoiceInstruction::Try(o), IndexedChoiceInstruction::Try(o),
IndexedChoiceInstruction::Trust(index) IndexedChoiceInstruction::Trust(index)
] ].into()
} else { } else {
sdeq![ vec![
IndexedChoiceInstruction::Try(index), IndexedChoiceInstruction::Try(index),
IndexedChoiceInstruction::Trust(o) IndexedChoiceInstruction::Trust(o)
] ].into()
}; };
self.indexing_code self.indexing_code
@@ -1122,15 +1122,6 @@ pub(crate) fn constant_key_alternatives(
}).unwrap(); }).unwrap();
} }
} }
/*
Literal::Usize(n) => {
constants.push(Literal::Integer(Rc::new(Integer::from(*n))));
if let Ok(n) = isize::try_from(*n) {
constants.push(Literal::Fixnum(n));
}
}
*/
_ => {} _ => {}
} }
@@ -1139,16 +1130,16 @@ pub(crate) fn constant_key_alternatives(
#[derive(Debug)] #[derive(Debug)]
pub(crate) struct StaticCodeIndices { pub(crate) struct StaticCodeIndices {
constants: IndexMap<Literal, VecDeque<IndexedChoiceInstruction>>, constants: IndexMap<Literal, VecDeque<IndexedChoiceInstruction>, FxBuildHasher>,
lists: VecDeque<IndexedChoiceInstruction>, lists: VecDeque<IndexedChoiceInstruction>,
structures: IndexMap<(Atom, usize), VecDeque<IndexedChoiceInstruction>>, structures: IndexMap<(Atom, usize), VecDeque<IndexedChoiceInstruction>, FxBuildHasher>,
} }
#[derive(Debug)] #[derive(Debug)]
pub(crate) struct DynamicCodeIndices { pub(crate) struct DynamicCodeIndices {
constants: IndexMap<Literal, VecDeque<usize>>, constants: IndexMap<Literal, VecDeque<usize>, FxBuildHasher>,
lists: VecDeque<usize>, lists: VecDeque<usize>,
structures: IndexMap<(Atom, usize), VecDeque<usize>>, structures: IndexMap<(Atom, usize), VecDeque<usize>, FxBuildHasher>,
} }
pub(crate) trait Indexer { pub(crate) trait Indexer {
@@ -1156,20 +1147,20 @@ pub(crate) trait Indexer {
fn new() -> Self; fn new() -> Self;
fn constants(&mut self) -> &mut IndexMap<Literal, VecDeque<Self::ThirdLevelIndex>>; 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>>; 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) -> Self::ThirdLevelIndex;
fn second_level_index<IndexKey: Eq + Hash>( fn second_level_index<IndexKey: Eq + Hash>(
indices: IndexMap<IndexKey, VecDeque<Self::ThirdLevelIndex>>, indices: IndexMap<IndexKey, VecDeque<Self::ThirdLevelIndex>, FxBuildHasher>,
prelude: &mut VecDeque<IndexingLine>, prelude: &mut VecDeque<IndexingLine>,
) -> IndexMap<IndexKey, IndexingCodePtr>; ) -> IndexMap<IndexKey, IndexingCodePtr, FxBuildHasher>;
fn switch_on<IndexKey: Eq + Hash>( fn switch_on<IndexKey: Eq + Hash>(
instr_fn: impl FnMut(IndexMap<IndexKey, IndexingCodePtr>) -> IndexingInstruction, instr_fn: impl FnMut(IndexMap<IndexKey, IndexingCodePtr, FxBuildHasher>) -> IndexingInstruction,
index: &mut IndexMap<IndexKey, VecDeque<Self::ThirdLevelIndex>>, index: &mut IndexMap<IndexKey, VecDeque<Self::ThirdLevelIndex>, FxBuildHasher>,
prelude: &mut VecDeque<IndexingLine>, prelude: &mut VecDeque<IndexingLine>,
) -> IndexingCodePtr; ) -> IndexingCodePtr;
@@ -1178,7 +1169,7 @@ pub(crate) trait Indexer {
prelude: &mut VecDeque<IndexingLine>, prelude: &mut VecDeque<IndexingLine>,
) -> IndexingCodePtr; ) -> IndexingCodePtr;
fn remove_instruction_with_offset(code: &mut SliceDeque<Self::ThirdLevelIndex>, offset: usize); fn remove_instruction_with_offset(code: &mut VecDeque<Self::ThirdLevelIndex>, offset: usize);
fn var_offset_wrapper(var_offset: usize) -> IndexingCodePtr; fn var_offset_wrapper(var_offset: usize) -> IndexingCodePtr;
} }
@@ -1189,14 +1180,14 @@ impl Indexer for StaticCodeIndices {
#[inline] #[inline]
fn new() -> Self { fn new() -> Self {
Self { Self {
constants: IndexMap::new(), constants: IndexMap::with_hasher(FxBuildHasher::default()),
lists: VecDeque::new(), lists: VecDeque::new(),
structures: IndexMap::new(), structures: IndexMap::with_hasher(FxBuildHasher::default()),
} }
} }
#[inline] #[inline]
fn constants(&mut self) -> &mut IndexMap<Literal, VecDeque<IndexedChoiceInstruction>> { fn constants(&mut self) -> &mut IndexMap<Literal, VecDeque<IndexedChoiceInstruction>, FxBuildHasher> {
&mut self.constants &mut self.constants
} }
@@ -1206,7 +1197,7 @@ impl Indexer for StaticCodeIndices {
} }
#[inline] #[inline]
fn structures(&mut self) -> &mut IndexMap<(Atom, usize), VecDeque<IndexedChoiceInstruction>> { fn structures(&mut self) -> &mut IndexMap<(Atom, usize), VecDeque<IndexedChoiceInstruction>, FxBuildHasher> {
&mut self.structures &mut self.structures
} }
@@ -1219,10 +1210,10 @@ impl Indexer for StaticCodeIndices {
} }
fn second_level_index<IndexKey: Eq + Hash>( fn second_level_index<IndexKey: Eq + Hash>(
indices: IndexMap<IndexKey, VecDeque<IndexedChoiceInstruction>>, indices: IndexMap<IndexKey, VecDeque<IndexedChoiceInstruction>, FxBuildHasher>,
prelude: &mut VecDeque<IndexingLine>, prelude: &mut VecDeque<IndexingLine>,
) -> IndexMap<IndexKey, IndexingCodePtr> { ) -> IndexMap<IndexKey, IndexingCodePtr, FxBuildHasher> {
let mut index_locs = IndexMap::new(); let mut index_locs = IndexMap::with_hasher(FxBuildHasher::default());
for (key, mut code) in indices.into_iter() { for (key, mut code) in indices.into_iter() {
if code.len() > 1 { if code.len() > 1 {
@@ -1240,11 +1231,11 @@ impl Indexer for StaticCodeIndices {
} }
fn switch_on<IndexKey: Eq + Hash>( fn switch_on<IndexKey: Eq + Hash>(
mut instr_fn: impl FnMut(IndexMap<IndexKey, IndexingCodePtr>) -> IndexingInstruction, mut instr_fn: impl FnMut(IndexMap<IndexKey, IndexingCodePtr, FxBuildHasher>) -> IndexingInstruction,
index: &mut IndexMap<IndexKey, VecDeque<IndexedChoiceInstruction>>, index: &mut IndexMap<IndexKey, VecDeque<IndexedChoiceInstruction>, FxBuildHasher>,
prelude: &mut VecDeque<IndexingLine>, prelude: &mut VecDeque<IndexingLine>,
) -> IndexingCodePtr { ) -> IndexingCodePtr {
let index = mem::replace(index, IndexMap::new()); let index = mem::replace(index, IndexMap::with_hasher(FxBuildHasher::default()));
let index = Self::second_level_index(index, prelude); let index = Self::second_level_index(index, prelude);
if index.len() > 1 { if index.len() > 1 {
@@ -1281,13 +1272,13 @@ impl Indexer for StaticCodeIndices {
#[inline] #[inline]
fn remove_instruction_with_offset( fn remove_instruction_with_offset(
code: &mut SliceDeque<IndexedChoiceInstruction>, code: &mut VecDeque<IndexedChoiceInstruction>,
offset: usize, offset: usize,
) { ) {
for (index, line) in code.iter().enumerate() { for (index, line) in code.iter().enumerate() {
if offset == line.offset() { if offset == line.offset() {
code.remove(index); code.remove(index);
cap_choice_seq(code); cap_choice_seq(code.make_contiguous());
return; return;
} }
} }
@@ -1305,14 +1296,14 @@ impl Indexer for DynamicCodeIndices {
#[inline] #[inline]
fn new() -> Self { fn new() -> Self {
Self { Self {
constants: IndexMap::new(), constants: IndexMap::with_hasher(FxBuildHasher::default()),
lists: VecDeque::new(), lists: VecDeque::new(),
structures: IndexMap::new(), structures: IndexMap::with_hasher(FxBuildHasher::default()),
} }
} }
#[inline] #[inline]
fn constants(&mut self) -> &mut IndexMap<Literal, VecDeque<usize>> { fn constants(&mut self) -> &mut IndexMap<Literal, VecDeque<usize>, FxBuildHasher> {
&mut self.constants &mut self.constants
} }
@@ -1322,7 +1313,7 @@ impl Indexer for DynamicCodeIndices {
} }
#[inline] #[inline]
fn structures(&mut self) -> &mut IndexMap<(Atom, usize), VecDeque<usize>> { fn structures(&mut self) -> &mut IndexMap<(Atom, usize), VecDeque<usize>, FxBuildHasher> {
&mut self.structures &mut self.structures
} }
@@ -1332,10 +1323,10 @@ impl Indexer for DynamicCodeIndices {
} }
fn second_level_index<IndexKey: Eq + Hash>( fn second_level_index<IndexKey: Eq + Hash>(
indices: IndexMap<IndexKey, VecDeque<usize>>, indices: IndexMap<IndexKey, VecDeque<usize>, FxBuildHasher>,
prelude: &mut VecDeque<IndexingLine>, prelude: &mut VecDeque<IndexingLine>,
) -> IndexMap<IndexKey, IndexingCodePtr> { ) -> IndexMap<IndexKey, IndexingCodePtr, FxBuildHasher> {
let mut index_locs = IndexMap::new(); let mut index_locs = IndexMap::with_hasher(FxBuildHasher::default());
for (key, code) in indices.into_iter() { for (key, code) in indices.into_iter() {
if code.len() > 1 { if code.len() > 1 {
@@ -1352,11 +1343,11 @@ impl Indexer for DynamicCodeIndices {
} }
fn switch_on<IndexKey: Eq + Hash>( fn switch_on<IndexKey: Eq + Hash>(
mut instr_fn: impl FnMut(IndexMap<IndexKey, IndexingCodePtr>) -> IndexingInstruction, mut instr_fn: impl FnMut(IndexMap<IndexKey, IndexingCodePtr, FxBuildHasher>) -> IndexingInstruction,
index: &mut IndexMap<IndexKey, VecDeque<usize>>, index: &mut IndexMap<IndexKey, VecDeque<usize>, FxBuildHasher>,
prelude: &mut VecDeque<IndexingLine>, prelude: &mut VecDeque<IndexingLine>,
) -> IndexingCodePtr { ) -> IndexingCodePtr {
let index = mem::replace(index, IndexMap::new()); let index = mem::replace(index, IndexMap::with_hasher(FxBuildHasher::default()));
let index = Self::second_level_index(index, prelude); let index = Self::second_level_index(index, prelude);
if index.len() > 1 { if index.len() > 1 {
@@ -1390,7 +1381,7 @@ impl Indexer for DynamicCodeIndices {
} }
#[inline] #[inline]
fn remove_instruction_with_offset(code: &mut SliceDeque<usize>, offset: usize) { fn remove_instruction_with_offset(code: &mut VecDeque<usize>, offset: usize) {
for (index, line) in code.iter().enumerate() { for (index, line) in code.iter().enumerate() {
if offset == *line { if offset == *line {
code.remove(index); code.remove(index);
@@ -1475,17 +1466,20 @@ impl<I: Indexer> CodeOffsets<I> {
atom_tbl: &mut AtomTable, atom_tbl: &mut AtomTable,
) { ) {
match optimal_arg { match optimal_arg {
&Term::Clause(_, atom!("."), ref terms) if terms.len() == 2 => {
clause_index_info.opt_arg_index_key = OptArgIndexKey::List(self.optimal_index, 0);
self.index_list(index);
}
&Term::Cons(..) | &Term::Literal(_, Literal::String(_)) | &Term::PartialString(..) => {
clause_index_info.opt_arg_index_key = OptArgIndexKey::List(self.optimal_index, 0);
self.index_list(index);
}
&Term::Clause(_, name, ref terms) => { &Term::Clause(_, name, ref terms) => {
clause_index_info.opt_arg_index_key = clause_index_info.opt_arg_index_key =
OptArgIndexKey::Structure(self.optimal_index, 0, name.clone(), terms.len()); OptArgIndexKey::Structure(self.optimal_index, 0, name.clone(), terms.len());
self.index_structure(name, terms.len(), index); self.index_structure(name, terms.len(), index);
} }
&Term::Cons(..) | &Term::Literal(_, Literal::String(_)) | &Term::PartialString(..) => {
clause_index_info.opt_arg_index_key = OptArgIndexKey::List(self.optimal_index, 0);
self.index_list(index);
}
&Term::Literal(_, constant) => { &Term::Literal(_, constant) => {
let overlapping_constants = self.index_constant(atom_tbl, constant, index); let overlapping_constants = self.index_constant(atom_tbl, constant, index);

View File

@@ -1,7 +1,6 @@
use crate::atom_table::*; use crate::atom_table::*;
use crate::forms::*; use crate::forms::*;
use crate::instructions::*; use crate::instructions::*;
use crate::machine::machine_indices::*;
use crate::parser::ast::*; use crate::parser::ast::*;
use std::cell::Cell; use std::cell::Cell;
@@ -16,8 +15,9 @@ pub(crate) enum TermRef<'a> {
AnonVar(Level), AnonVar(Level),
Cons(Level, &'a Cell<RegType>, &'a Term, &'a Term), Cons(Level, &'a Cell<RegType>, &'a Term, &'a Term),
Literal(Level, &'a Cell<RegType>, &'a Literal), Literal(Level, &'a Cell<RegType>, &'a Literal),
Clause(Level, &'a Cell<RegType>, ClauseType, &'a Vec<Term>), Clause(Level, &'a Cell<RegType>, Atom, &'a Vec<Term>),
PartialString(Level, &'a Cell<RegType>, Atom, &'a Option<Box<Term>>), PartialString(Level, &'a Cell<RegType>, &'a String, &'a Box<Term>),
CompleteString(Level, &'a Cell<RegType>, Atom),
Var(Level, &'a Cell<VarReg>, Rc<String>), Var(Level, &'a Cell<VarReg>, Rc<String>),
} }
@@ -28,8 +28,9 @@ impl<'a> TermRef<'a> {
| TermRef::Cons(lvl, ..) | TermRef::Cons(lvl, ..)
| TermRef::Literal(lvl, ..) | TermRef::Literal(lvl, ..)
| TermRef::Var(lvl, ..) | TermRef::Var(lvl, ..)
| TermRef::Clause(lvl, ..) => lvl, | TermRef::Clause(lvl, ..)
TermRef::PartialString(lvl, ..) => lvl, | TermRef::CompleteString(lvl, ..)
| TermRef::PartialString(lvl, ..) => lvl,
} }
} }
} }
@@ -38,11 +39,12 @@ impl<'a> TermRef<'a> {
pub(crate) enum TermIterState<'a> { pub(crate) enum TermIterState<'a> {
AnonVar(Level), AnonVar(Level),
Literal(Level, &'a Cell<RegType>, &'a Literal), Literal(Level, &'a Cell<RegType>, &'a Literal),
Clause(Level, usize, &'a Cell<RegType>, ClauseType, &'a Vec<Term>), Clause(Level, usize, &'a Cell<RegType>, Atom, &'a Vec<Term>),
InitialCons(Level, &'a Cell<RegType>, &'a Term, &'a Term), InitialCons(Level, &'a Cell<RegType>, &'a Term, &'a Term),
FinalCons(Level, &'a Cell<RegType>, &'a Term, &'a Term), FinalCons(Level, &'a Cell<RegType>, &'a Term, &'a Term),
InitialPartialString(Level, &'a Cell<RegType>, Atom, &'a Option<Box<Term>>), InitialPartialString(Level, &'a Cell<RegType>, &'a String, &'a Box<Term>),
FinalPartialString(Level, &'a Cell<RegType>, Atom, &'a Option<Box<Term>>), FinalPartialString(Level, &'a Cell<RegType>, &'a String, &'a Box<Term>),
CompleteString(Level, &'a Cell<RegType>, Atom),
Var(Level, &'a Cell<VarReg>, Rc<String>), Var(Level, &'a Cell<VarReg>, Rc<String>),
} }
@@ -51,15 +53,17 @@ impl<'a> TermIterState<'a> {
match term { match term {
Term::AnonVar => TermIterState::AnonVar(lvl), Term::AnonVar => TermIterState::AnonVar(lvl),
Term::Clause(cell, name, subterms) => { Term::Clause(cell, name, subterms) => {
let ct = ClauseType::Named(subterms.len(), *name, CodeIndex::default()); TermIterState::Clause(lvl, 0, cell, *name, subterms)
TermIterState::Clause(lvl, 0, cell, ct, subterms)
} }
Term::Cons(cell, head, tail) => { Term::Cons(cell, head, tail) => {
TermIterState::InitialCons(lvl, cell, head.as_ref(), tail.as_ref()) TermIterState::InitialCons(lvl, cell, head.as_ref(), tail.as_ref())
} }
Term::Literal(cell, constant) => TermIterState::Literal(lvl, cell, constant), Term::Literal(cell, constant) => TermIterState::Literal(lvl, cell, constant),
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) => {
TermIterState::CompleteString(lvl, cell, *atom)
} }
Term::Var(cell, var) => TermIterState::Var(lvl, cell, var.clone()), Term::Var(cell, var) => TermIterState::Var(lvl, cell, var.clone()),
} }
@@ -89,7 +93,8 @@ 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::PartialString(..) => { Term::AnonVar | Term::Cons(..) | Term::Literal(..) |
Term::PartialString(..) | Term::CompleteString(..) => {
return QueryIterator { return QueryIterator {
state_stack: vec![], state_stack: vec![],
} }
@@ -98,7 +103,7 @@ impl<'a> QueryIterator<'a> {
Level::Root, Level::Root,
0, 0,
r, r,
ClauseType::from(*name, terms.len()), *name,
terms, terms,
), ),
Term::Var(cell, var) => TermIterState::Var(Level::Root, cell, var.clone()), Term::Var(cell, var) => TermIterState::Var(Level::Root, cell, var.clone()),
@@ -111,14 +116,14 @@ impl<'a> QueryIterator<'a> {
fn new(term: &'a QueryTerm) -> Self { fn new(term: &'a QueryTerm) -> Self {
match term { match term {
&QueryTerm::Clause(ref cell, ClauseType::CallN(arity), ref terms, _) => { &QueryTerm::Clause(ref cell, ClauseType::CallN(_), ref terms, _) => {
let state = TermIterState::Clause(Level::Root, 1, cell, ClauseType::CallN(arity), terms); let state = TermIterState::Clause(Level::Root, 1, cell, atom!("$call"), terms);
QueryIterator { QueryIterator {
state_stack: vec![state], state_stack: vec![state],
} }
} }
&QueryTerm::Clause(ref cell, ref ct, ref terms, _) => { &QueryTerm::Clause(ref cell, ref ct, ref terms, _) => {
let state = TermIterState::Clause(Level::Root, 0, cell, ct.clone(), terms); let state = TermIterState::Clause(Level::Root, 0, cell, ct.name(), terms);
QueryIterator { QueryIterator {
state_stack: vec![state], state_stack: vec![state],
} }
@@ -160,28 +165,25 @@ impl<'a> Iterator for QueryIterator<'a> {
TermIterState::AnonVar(lvl) => { TermIterState::AnonVar(lvl) => {
return Some(TermRef::AnonVar(lvl)); return Some(TermRef::AnonVar(lvl));
} }
TermIterState::Clause(lvl, child_num, cell, ct, child_terms) => { TermIterState::Clause(lvl, child_num, cell, name, child_terms) => {
if child_num == child_terms.len() { if child_num == child_terms.len() {
match ct { match name {
ClauseType::CallN(_) => { atom!("$call") if lvl == Level::Root => {
self.push_subterm(Level::Shallow, &child_terms[0]); self.push_subterm(Level::Shallow, &child_terms[0]);
} }
ClauseType::Named(..) => { _ => {
return match lvl { return match lvl {
Level::Root => None, Level::Root => None,
lvl => Some(TermRef::Clause(lvl, cell, ct, child_terms)), lvl => Some(TermRef::Clause(lvl, cell, name, child_terms)),
} }
} }
_ => {
return None;
}
}; };
} else { } else {
self.state_stack.push(TermIterState::Clause( self.state_stack.push(TermIterState::Clause(
lvl, lvl,
child_num + 1, child_num + 1,
cell, cell,
ct, name,
child_terms, child_terms,
)); ));
@@ -196,13 +198,13 @@ impl<'a> Iterator for QueryIterator<'a> {
} }
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));
if let Some(tail) = tail {
self.push_subterm(lvl.child_level(), tail); self.push_subterm(lvl.child_level(), tail);
} }
TermIterState::FinalPartialString(lvl, cell, atom, tail) => {
return Some(TermRef::PartialString(lvl, cell, atom, tail));
} }
TermIterState::FinalPartialString(lvl, cell, string, tail) => { TermIterState::CompleteString(lvl, cell, atom) => {
return Some(TermRef::PartialString(lvl, cell, string, tail)); return Some(TermRef::CompleteString(lvl, cell, atom));
} }
TermIterState::FinalCons(lvl, cell, head, tail) => { TermIterState::FinalCons(lvl, cell, head, tail) => {
return Some(TermRef::Cons(lvl, cell, head, tail)); return Some(TermRef::Cons(lvl, cell, head, tail));
@@ -250,8 +252,7 @@ impl<'a> FactIterator<'a> {
vec![TermIterState::AnonVar(Level::Root)] vec![TermIterState::AnonVar(Level::Root)]
} }
Term::Clause(cell, name, terms) => { Term::Clause(cell, name, terms) => {
let ct = ClauseType::from(*name, terms.len()); vec![TermIterState::Clause(Level::Root, 0, cell, *name, terms)]
vec![TermIterState::Clause(Level::Root, 0, cell, ct, terms)]
} }
Term::Cons(cell, head, tail) => vec![TermIterState::InitialCons( Term::Cons(cell, head, tail) => vec![TermIterState::InitialCons(
Level::Root, Level::Root,
@@ -259,12 +260,19 @@ impl<'a> FactIterator<'a> {
head.as_ref(), head.as_ref(),
tail.as_ref(), tail.as_ref(),
)], )],
Term::PartialString(cell, string_buf, tail_opt) => { Term::PartialString(cell, string_buf, tail) => {
vec![TermIterState::InitialPartialString( vec![TermIterState::InitialPartialString(
Level::Root, Level::Root,
cell, cell,
*string_buf, string_buf,
tail_opt, tail,
)]
}
Term::CompleteString(cell, atom) => {
vec![TermIterState::CompleteString(
Level::Root,
cell,
*atom,
)] )]
} }
Term::Literal(cell, constant) => { Term::Literal(cell, constant) => {
@@ -291,14 +299,14 @@ impl<'a> Iterator for FactIterator<'a> {
TermIterState::AnonVar(lvl) => { TermIterState::AnonVar(lvl) => {
return Some(TermRef::AnonVar(lvl)); return Some(TermRef::AnonVar(lvl));
} }
TermIterState::Clause(lvl, _, cell, ct, child_terms) => { TermIterState::Clause(lvl, _, cell, name, child_terms) => {
for child_term in child_terms { for child_term in child_terms {
self.push_subterm(lvl.child_level(), child_term); self.push_subterm(lvl.child_level(), child_term);
} }
match lvl { match lvl {
Level::Root if !self.iterable_root => continue, Level::Root if !self.iterable_root => continue,
_ => return Some(TermRef::Clause(lvl, cell, ct, child_terms)), _ => return Some(TermRef::Clause(lvl, cell, name, child_terms)),
}; };
} }
TermIterState::InitialCons(lvl, cell, head, tail) => { TermIterState::InitialCons(lvl, cell, head, tail) => {
@@ -307,12 +315,12 @@ impl<'a> Iterator for FactIterator<'a> {
return Some(TermRef::Cons(lvl, cell, head, tail)); return Some(TermRef::Cons(lvl, cell, head, tail));
} }
TermIterState::InitialPartialString(lvl, cell, string_buf, tail_opt) => { TermIterState::InitialPartialString(lvl, cell, string_buf, tail) => {
if let Some(tail) = tail_opt {
self.push_subterm(Level::Deep, tail); self.push_subterm(Level::Deep, tail);
return Some(TermRef::PartialString(lvl, cell, string_buf, tail));
} }
TermIterState::CompleteString(lvl, cell, atom) => {
return Some(TermRef::PartialString(lvl, cell, string_buf, tail_opt)); return Some(TermRef::CompleteString(lvl, cell, atom));
} }
TermIterState::Literal(lvl, cell, constant) => { TermIterState::Literal(lvl, cell, constant) => {
return Some(TermRef::Literal(lvl, cell, constant)) return Some(TermRef::Literal(lvl, cell, constant))
@@ -407,16 +415,7 @@ impl<'a> ChunkedIterator<'a> {
} }
})) }))
} }
/*
pub(crate) fn from_term_sequence(terms: &'a [QueryTerm]) -> Self {
ChunkedIterator {
chunk_num: 0,
iter: Box::new(terms.iter().map(|t| ChunkedTerm::BodyTerm(t))),
deep_cut_encountered: false,
cut_var_in_head: false,
}
}
*/
pub(crate) fn from_rule_body(p1: &'a QueryTerm, clauses: &'a Vec<QueryTerm>) -> Self { pub(crate) fn from_rule_body(p1: &'a QueryTerm, clauses: &'a Vec<QueryTerm>) -> Self {
let inner_iter = Box::new(once(ChunkedTerm::BodyTerm(p1))); let inner_iter = Box::new(once(ChunkedTerm::BodyTerm(p1)));
let iter = inner_iter.chain(clauses.iter().map(|t| ChunkedTerm::BodyTerm(t))); let iter = inner_iter.chain(clauses.iter().map(|t| ChunkedTerm::BodyTerm(t)));

View File

@@ -19,6 +19,7 @@ mod fixtures;
mod forms; mod forms;
mod heap_iter; mod heap_iter;
pub mod heap_print; pub mod heap_print;
mod http;
mod indexing; mod indexing;
#[macro_use] #[macro_use]
pub mod instructions { pub mod instructions {
@@ -28,6 +29,7 @@ mod iterators;
pub mod machine; pub mod machine;
mod raw_block; mod raw_block;
pub mod read; pub mod read;
mod repl_helper;
mod targets; mod targets;
pub mod types; pub mod types;

File diff suppressed because it is too large Load Diff

View File

@@ -251,7 +251,7 @@ chars_base64(Cs, Bs, Options) :-
'$chars_base64'(Cs, Bs, Padding, Charset) '$chars_base64'(Cs, Bs, Padding, Charset)
; must_be(chars, Cs), ; must_be(chars, Cs),
( '$first_non_octet'(Cs, N) -> ( '$first_non_octet'(Cs, N) ->
domain_error(byte_char, N, chars_base64/3) domain_error(octet_character, N, chars_base64/3)
; '$chars_base64'(Cs, Bs, Padding, Charset) ; '$chars_base64'(Cs, Bs, Padding, Charset)
) )
). ).

View File

@@ -1122,6 +1122,8 @@ indomain(1).
% CountAnd = 1. % CountAnd = 1.
% == % ==
sat_count(Sat0, N) :- sat_count(Sat0, N) :-
catch((parse_sat(Sat0, Sat), catch((parse_sat(Sat0, Sat),
sat_bdd(Sat, BDD), sat_bdd(Sat, BDD),

View File

@@ -3,7 +3,7 @@
Author: Markus Triska Author: Markus Triska
E-mail: triska@metalevel.at E-mail: triska@metalevel.at
WWW: https://www.metalevel.at WWW: https://www.metalevel.at
Copyright (C): 2016-2021 Markus Triska Copyright (C): 2016-2022 Markus Triska
This library provides CLP(): This library provides CLP():
@@ -123,6 +123,8 @@
:- use_module(library(si)). :- use_module(library(si)).
:- use_module(library(freeze)). :- use_module(library(freeze)).
:- use_module(library(arithmetic)). :- use_module(library(arithmetic)).
:- use_module(library(debug)).
:- use_module(library(format)).
% :- use_module(library(types)). % :- use_module(library(types)).
@@ -194,6 +196,8 @@ type_error(Expectation, Term) :-
type_error(Expectation, Term, unknown(Term)-1). type_error(Expectation, Term, unknown(Term)-1).
:- 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).
@@ -214,6 +218,8 @@ partition_([X|Xs], Pred, Ls0, Es0, Gs0) :-
include/3 and exclude/3 include/3 and exclude/3
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
:- meta_predicate(include(1, ?, ?)).
include(Goal, Ls0, Ls) :- include(Goal, Ls0, Ls) :-
include_(Ls0, Goal, Ls). include_(Ls0, Goal, Ls).
@@ -226,6 +232,7 @@ include_([L|Ls0], Goal, Ls) :-
include_(Ls0, Goal, Rest). include_(Ls0, Goal, Rest).
:- meta_predicate(exclude(1, ?, ?)).
exclude(Goal, Ls0, Ls) :- exclude(Goal, Ls0, Ls) :-
exclude_(Ls0, Goal, Ls). exclude_(Ls0, Goal, Ls).
@@ -390,6 +397,7 @@ In total, the arithmetic constraints are:
| Expr `mod` Expr | Modulo induced by floored division | | Expr `mod` Expr | Modulo induced by floored division |
| Expr `rem` Expr | Modulo induced by truncated division | | Expr `rem` Expr | Modulo induced by truncated division |
| abs(Expr) | Absolute value | | abs(Expr) | Absolute value |
| sign(Expr) | Sign (-1, 0, 1) of Expr |
| Expr // Expr | Truncated integer division | | Expr // Expr | Truncated integer division |
| Expr div Expr | Floored integer division | | Expr div Expr | Floored integer division |
@@ -2235,8 +2243,8 @@ all_distinct(Ls) :-
fd_must_be_list(Ls, all_distinct(Ls)-1), fd_must_be_list(Ls, all_distinct(Ls)-1),
maplist(fd_variable, Ls), maplist(fd_variable, Ls),
make_propagator(pdistinct(Ls), Prop), make_propagator(pdistinct(Ls), Prop),
distinct_attach(Ls, Prop, []), new_queue(Q0),
trigger_once(Prop). phrase((distinct_attach(Ls, Prop, []),trigger_prop(Prop),do_queue), [Q0], _).
%% nvalue(?N, +Vars). %% nvalue(?N, +Vars).
% %
@@ -2564,6 +2572,7 @@ parse_clpz(E, R,
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))],
m(sign(A)) => [g(R in -1..1), p(psign(A, R))],
% bitwise operations % bitwise operations
m(\A) => [p(pfunction(\, A, R))], m(\A) => [p(pfunction(\, A, R))],
m(msb(A)) => [p(pfunction(msb, A, R))], m(msb(A)) => [p(pfunction(msb, A, R))],
@@ -4043,12 +4052,13 @@ trigger_props(fd_props(Gs,Bs,Os)) -->
trigger_props_([]) --> []. trigger_props_([]) --> [].
trigger_props_([P|Ps]) --> trigger_prop(P), trigger_props_(Ps). trigger_props_([P|Ps]) --> trigger_prop(P), trigger_props_(Ps).
trigger_prop(_P) :- true. % TODO: What to do? trigger_prop(P) :- trigger_once(P).
trigger_prop(Propagator) --> trigger_prop(Propagator) -->
{ propagator_state(Propagator, State) }, { propagator_state(Propagator, State) },
( { State == dead } -> [] ( { State == dead } -> []
; { get_attr(State, clpz_aux, queued) } -> [] ; { get_attr(State, clpz_aux, queued) } -> []
; { bb_get('$clpz_current_propagator', C), C == State } -> []
; % passive ; % passive
%{ format("triggering: ~w\n", [Propagator]) }, %{ format("triggering: ~w\n", [Propagator]) },
{ put_attr(State, clpz_aux, queued) }, { put_attr(State, clpz_aux, queued) },
@@ -4141,12 +4151,13 @@ no_reactivation(pgcc_single(_,_)).
%no_reactivation(scalar_product(_,_,_,_)). %no_reactivation(scalar_product(_,_,_,_)).
activate_propagator(propagator(P,State)) --> activate_propagator(propagator(P,State)) -->
% { portray_clause(running(P)) },
( State == dead -> [] ( State == dead -> []
; { del_attr(State, clpz_aux) }, ; { del_attr(State, clpz_aux) },
( { no_reactivation(P) } -> ( { no_reactivation(P) } ->
%b_setval('$clpz_current_propagator', State), TODO { bb_b_put('$clpz_current_propagator', State) },
run_propagator(P, State) run_propagator(P, State),
%b_setval('$clpz_current_propagator', []) { bb_b_put('$clpz_current_propagator', []) }
; run_propagator(P, State) ; run_propagator(P, State)
) )
). ).
@@ -4192,7 +4203,8 @@ queue_get_arg_(Queue, Which, Element) :-
). ).
queue_enabled --> state(queue(_,_,_,Aux)), { \+ get_atts(Aux, +enabled(false)) }. queue_enabled --> state(queue(_,_,_,Aux)), { \+ get_atts(Aux, +enabled(false)) }.
disable_queue --> state(queue(_,_,_,Aux)), { put_atts(Aux, +enabled(false)) }.
enable_queue --> state(queue(_,_,_,Aux)), { put_atts(Aux, +enabled(true)) }.
portray_propagator(propagator(P,_), F) :- functor(P, F, _). portray_propagator(propagator(P,_), F) :- functor(P, F, _).
@@ -4387,14 +4399,14 @@ run_propagator(pdifferent(Left,Right,X,_), MState) -->
run_propagator(pexclude(Left,Right,X), MState). run_propagator(pexclude(Left,Right,X), MState).
run_propagator(pexclude(Left,Right,X), _) --> run_propagator(pexclude(Left,Right,X), _) -->
{ ( ground(X) -> ( ground(X) ->
disable_queue, disable_queue,
exclude_fire(Left, Right, X), exclude_fire(Left, Right, X),
enable_queue enable_queue
; true ; true
) }. ).
run_propagator(pdistinct(Ls), _MState) --> { distinct(Ls) }. run_propagator(pdistinct(Ls), _MState) --> distinct(Ls).
run_propagator(pnvalue(N, Vars), _MState) --> { propagate_nvalue(N, Vars) }. run_propagator(pnvalue(N, Vars), _MState) --> { propagate_nvalue(N, Vars) }.
@@ -4428,8 +4440,8 @@ run_propagator(pgcc(Vs, _, Pairs), _) --> { gcc_global(Vs, Pairs) }.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
run_propagator(pcircuit(Vs), _MState) --> run_propagator(pcircuit(Vs), _MState) -->
{ distinct(Vs), distinct(Vs),
propagate_circuit(Vs) }. { propagate_circuit(Vs) }.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -5134,7 +5146,6 @@ run_propagator(pmodz(X,Y,Z), MState) -->
domain_remove_smaller_than(ZD3, ZMin, ZD5) }, domain_remove_smaller_than(ZD3, ZMin, ZD5) },
fd_put(Z, ZD5, ZPs) fd_put(Z, ZD5, ZPs)
% queue_goal(Z in ZMin..ZMax) % queue_goal(Z in ZMin..ZMax)
%/* This doesn't work very well.
; { fd_get(Y, _, _, n(YU), _), YU > 0 } -> ; { fd_get(Y, _, _, n(YU), _), YU > 0 } ->
{ fd_get(Z, ZD1, ZPs), { fd_get(Z, ZD1, ZPs),
ZMax is YU - 1, ZMax is YU - 1,
@@ -5147,7 +5158,6 @@ run_propagator(pmodz(X,Y,Z), MState) -->
domain_remove_smaller_than(ZD1, ZMin, ZD3) }, domain_remove_smaller_than(ZD1, ZMin, ZD3) },
fd_put(Z, ZD3, ZPs) fd_put(Z, ZD3, ZPs)
% queue_goal(Z #> YL) % queue_goal(Z #> YL)
% * /
; true ; true
) )
) )
@@ -5484,6 +5494,21 @@ run_propagator(pexp(X,Y,Z), MState) -->
; true ; true
). ).
%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% % Y = sign(X)
run_propagator(psign(X,Y), MState) -->
( nonvar(X) -> kill(MState), queue_goal(Y is sign(X))
; Y == -1 -> kill(MState), queue_goal(X #< 0)
; Y == 0 -> kill(MState), queue_goal(X = 0)
; Y == 1 -> kill(MState), queue_goal(X #> 0)
; { fd_get(X, _, XL, XU, _) },
( { XL = n(L), L > 0 } -> kill(MState), queue_goal(Y = 1)
; { XU = n(U), U < 0 } -> kill(MState), queue_goal(Y = -1)
; true
)
).
%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% % Y = popcount(X) %% % Y = popcount(X)
@@ -5913,12 +5938,12 @@ max_factor(L1, U1, L2, U2, Max) :-
CSPs", AAAI-94, Seattle, WA, USA, pp 362--367, 1994 CSPs", AAAI-94, Seattle, WA, USA, pp 362--367, 1994
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
distinct_attach([], _, _). distinct_attach([], _, _) --> [].
distinct_attach([X|Xs], Prop, Right) :- distinct_attach([X|Xs], Prop, Right) -->
( var(X) -> ( var(X) ->
init_propagator(X, Prop), { init_propagator(X, Prop),
make_propagator(pexclude(Xs,Right,X), P1), make_propagator(pexclude(Xs,Right,X), P1),
init_propagator(X, P1), init_propagator(X, P1) },
trigger_prop(P1) trigger_prop(P1)
; exclude_fire(Xs, Right, X) ; exclude_fire(Xs, Right, X)
), ),
@@ -6087,59 +6112,26 @@ put_free(F) :- put_attr(F, free, true).
free_node(F) :- get_attr(F, free, true). free_node(F) :- get_attr(F, free, true).
del_vars_attr(Vars, Attr) :- maplist(del_attr(Attr), Vars).
%del_attr_(Attr, Var) :- del_attr(Var, Attr).
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
This needs to be spelt out.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
% del_attr_(edges, Var) :- del_attr(Var, edges).
% del_attr_(parent, Var) :- del_attr(Var, parent).
% del_attr_(g0_edges, Var) :- del_attr(Var, g0_edges).
% del_attr_(index, Var) :- del_attr(Var, index).
% del_attr_(visited, Var) :- del_attr(Var, visited).
del_all_attrs(Var) :-
( var(Var) ->
Atts = [clpz,
clpz_aux,
clpz_relation,
edges,
flow,
parent,
free,
g0_edges,
used,
lowlink,
value,
visited,
index,
in_stack,
clpz_gcc_vs,
clpz_gcc_num,
clpz_gcc_occurred],
maplist(remove_attr(Var), Atts)
; true
).
remove_attr(Var, Attr) :-
functor(Term, Attr, 1),
put_atts(Var, -Term).
:- meta_predicate with_local_attributes(?, 0, ?). :- meta_predicate with_local_attributes(?, 0, ?).
:- dynamic(nat_copy/1).
with_local_attributes(Vars, Goal, Result) :- with_local_attributes(Vars, Goal, Result) :-
catch((Goal, catch((Goal,
maplist(del_all_attrs, Vars), % Create a copy where all attributes are removed. Only
% reset all attributes, only the result matters % the result and its relation to Vars matters. We throw
throw(local_attributes(Result,Vars))), % an exception to undo all modifications to attributes
local_attributes(Result,Vars), % we made during propagation, and unify the variables
% in the thrown copy with Vars in order to get the
% intended variables in Result.
asserta(nat_copy(Vars-Result)),
retract(nat_copy(Copy)),
throw(local_attributes(Copy))),
local_attributes(Vars-Result),
true). true).
distinct(Vars) :- distinct(Vars) -->
with_local_attributes(Vars, { with_local_attributes(Vars,
( difference_arcs(Vars, FreeLeft, FreeRight0), ( difference_arcs(Vars, FreeLeft, FreeRight0),
length(FreeLeft, LFL), length(FreeLeft, LFL),
length(FreeRight0, LFR), length(FreeRight0, LFR),
@@ -6150,11 +6142,16 @@ distinct(Vars) :-
maplist(g_g0, FreeLeft), maplist(g_g0, FreeLeft),
scc(FreeLeft, g0_successors), scc(FreeLeft, g0_successors),
maplist(dfs_used, FreeRight), maplist(dfs_used, FreeRight),
phrase(distinct_goals(FreeLeft), Gs)), Gs), phrase(distinct_goals(FreeLeft), Gs)), Gs) },
disable_queue, disable_queue,
maplist(call, Gs), neq_nums(Gs),
enable_queue. enable_queue.
neq_nums([]) --> [].
neq_nums([neq_num(V,N)|VNs]) -->
% { portray_clause(neq_num(V, N)) },
neq_num(V, N), neq_nums(VNs).
distinct_goals([]) --> []. distinct_goals([]) --> [].
distinct_goals([V|Vs]) --> distinct_goals([V|Vs]) -->
{ get_attr(V, edges, Es) }, { get_attr(V, edges, Es) },
@@ -6169,7 +6166,7 @@ distinct_goals_([flow_to(F,To)|Es], V) -->
get_attr(To, lowlink, L2), get_attr(To, lowlink, L2),
L1 =\= L2 } -> L1 =\= L2 } ->
{ get_attr(To, value, N) }, { get_attr(To, value, N) },
[clpz:neq_num(V, N)] [neq_num(V, N)]
; [] ; []
), ),
distinct_goals_(Es, V). distinct_goals_(Es, V).
@@ -6361,6 +6358,10 @@ exclude_fire(Left, Right, E) :-
all_neq(Left, E), all_neq(Left, E),
all_neq(Right, E). all_neq(Right, E).
exclude_fire(Left, Right, E) -->
all_neq(Left, E),
all_neq(Right, E).
list_contains([X|Xs], Y) :- list_contains([X|Xs], Y) :-
( X == Y -> true ( X == Y -> true
; list_contains(Xs, Y) ; list_contains(Xs, Y)
@@ -6922,6 +6923,11 @@ vs_key_min_others([V|Vs], Key, Min0, Min, Others) :-
) )
). ).
all_neq([], _) --> [].
all_neq([X|Xs], C) -->
neq_num(X, C),
all_neq(Xs, C).
all_neq([], _). all_neq([], _).
all_neq([X|Xs], C) :- all_neq([X|Xs], C) :-
neq_num(X, C), neq_num(X, C),
@@ -6953,8 +6959,8 @@ circuit(Vs) :-
( L =:= 1 -> true ( L =:= 1 -> true
; neq_index(Vs, 1), ; neq_index(Vs, 1),
make_propagator(pcircuit(Vs), Prop), make_propagator(pcircuit(Vs), Prop),
distinct_attach(Vs, Prop, []), new_queue(Q0),
trigger_once(Prop) phrase((distinct_attach(Vs, Prop, []),trigger_prop(Prop),do_queue), [Q0], _)
). ).
neq_index([], _). neq_index([], _).
@@ -7134,10 +7140,6 @@ contribution_at(T, Task, Offset-Bs, Contribution) :-
?(Contribution) #= B*C ?(Contribution) #= B*C
). ).
nth1(I, Es, E) :-
I0 is I-1,
nth0(I0, Es, E).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% disjoint2(+Rectangles) %% disjoint2(+Rectangles)
@@ -7696,6 +7698,7 @@ attribute_goal_(ptzdiv(X,Y,Z)) --> [?(X) // ?(Y) #= ?(Z)].
attribute_goal_(pdiv(X,Y,Z)) --> [?(X) div ?(Y) #= ?(Z)]. attribute_goal_(pdiv(X,Y,Z)) --> [?(X) div ?(Y) #= ?(Z)].
attribute_goal_(prdiv(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_(pexp(X,Y,Z)) --> [?(X) ^ ?(Y) #= ?(Z)].
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)].
attribute_goal_(prem(X,Y,Z)) --> [?(X) rem ?(Y) #= ?(Z)]. attribute_goal_(prem(X,Y,Z)) --> [?(X) rem ?(Y) #= ?(Z)].

View File

@@ -8,7 +8,7 @@
In Scryer Prolog, lists of characters are very efficiently represented, In Scryer Prolog, lists of characters are very efficiently represented,
and strings have the advantage that the atom table remains unmodified. and strings have the advantage that the atom table remains unmodified.
Especially for cryptographic applications, it as an advantage that Especially for cryptographic applications, it is an advantage that
using strings leaves little trace of what was processed in the system. using strings leaves little trace of what was processed in the system.
For predicates that accept an encoding/1 option to specify the encoding For predicates that accept an encoding/1 option to specify the encoding
@@ -65,8 +65,7 @@
hex_bytes(Hs, Bytes) :- hex_bytes(Hs, Bytes) :-
( ground(Hs) -> ( ground(Hs) ->
must_be(list, Hs), must_be(chars, Hs),
maplist(must_be(atom), Hs),
( phrase(hex_bytes(Hs), Bytes) -> ( phrase(hex_bytes(Hs), Bytes) ->
true true
; domain_error(hex_encoding, Hs, hex_bytes/2) ; domain_error(hex_encoding, Hs, hex_bytes/2)
@@ -104,10 +103,10 @@ must_be_bytes(Bytes, Context) :-
). ).
must_be_byte_chars(Chars, Context) :- must_be_octet_chars(Chars, Context) :-
must_be(chars, Chars), must_be(chars, Chars),
( '$first_non_octet'(Chars, F) -> ( '$first_non_octet'(Chars, F) ->
domain_error(byte_char, F, Context) domain_error(octet_character, F, Context)
; true ; true
). ).
@@ -611,7 +610,7 @@ encoding_chars(octet, Bs, Cs) :-
maplist(char_code, Cs, Bs) maplist(char_code, Cs, Bs)
; Bs = Cs ; Bs = Cs
), ),
must_be_byte_chars(Cs, crypto_encoding). must_be_octet_chars(Cs, crypto_encoding).
encoding_chars(utf8, Cs, Cs) :- encoding_chars(utf8, Cs, Cs) :-
must_be(chars, Cs). must_be(chars, Cs).
@@ -652,17 +651,17 @@ ed25519_new_keypair(Pair) :-
'$ed25519_new_keypair'(Pair). '$ed25519_new_keypair'(Pair).
ed25519_keypair_public_key(Pair, PublicKey) :- ed25519_keypair_public_key(Pair, PublicKey) :-
must_be_byte_chars(Pair, ed25519_keypair_public_key), must_be_octet_chars(Pair, ed25519_keypair_public_key),
'$ed25519_keypair_public_key'(Pair, PublicKey). '$ed25519_keypair_public_key'(Pair, PublicKey).
ed25519_sign(Key, Data0, Signature, Options) :- ed25519_sign(Key, Data0, Signature, Options) :-
must_be_byte_chars(Key, ed25519_sign), must_be_octet_chars(Key, ed25519_sign),
options_data_chars(Options, Data0, Data, Encoding), options_data_chars(Options, Data0, Data, Encoding),
'$ed25519_sign'(Key, Data, Encoding, Signature0), '$ed25519_sign'(Key, Data, Encoding, Signature0),
hex_bytes(Signature, Signature0). hex_bytes(Signature, Signature0).
ed25519_verify(Key, Data0, Signature0, Options) :- ed25519_verify(Key, Data0, Signature0, Options) :-
must_be_byte_chars(Key, ed25519_verify), must_be_octet_chars(Key, ed25519_verify),
options_data_chars(Options, Data0, Data, Encoding), options_data_chars(Options, Data0, Data, Encoding),
hex_bytes(Signature0, Signature), hex_bytes(Signature0, Signature),
'$ed25519_verify'(Key, Data, Encoding, Signature). '$ed25519_verify'(Key, Data, Encoding, Signature).
@@ -714,12 +713,17 @@ curve25519_scalar_mult(Scalar, Point, Result) :-
'$curve25519_scalar_mult'(ScalarBytes, PointBytes, Result). '$curve25519_scalar_mult'(ScalarBytes, PointBytes, Result).
bytes_integer(Bs, N) :- bytes_integer(Bs, N) :-
foldl(pow, Bs, 0-0, N-_). foldl(pow, Bs, t(0,0,N), t(N,_,_)).
pow(B, N0-I0, N-I) :- pow(B, t(N0,P0,I0), t(N,P,I)) :-
( integer(I0) ->
B #= I0 mod 256,
I #= I0 >> 8
; true
),
B in 0..255, B in 0..255,
N #= N0 + B*256^I0, N #= N0 + B*256^P0,
I #= I0 + 1. P #= P0 + 1.
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Operations on Elliptic Curves Operations on Elliptic Curves
@@ -762,11 +766,15 @@ crypto_curve_scalar_mult(Curve, Scalar, point(X,Y), point(RX, RY)) :-
curve_name(Curve, Name), curve_name(Curve, Name),
curve_field_length(Curve, L0), curve_field_length(Curve, L0),
L #= 2*L0, % for hex encoding L #= 2*L0, % for hex encoding
phrase(format_("04~|~`0t~16r~*+~`0t~16r~*+", [X,L,Y,L]), Hex), phrase(format_("04~|~`0t~16r~*+~`0t~16r~*+", [X,L,Y,L]), PointHex),
hex_bytes(Hex, Bytes), hex_bytes(PointHex, PointBytes),
'$crypto_curve_scalar_mult'(Name, Scalar, Bytes, SX, SY), once(bytes_integer(ScalarBytes, Scalar)),
number_chars(RX, SX), '$crypto_curve_scalar_mult'(Name, ScalarBytes, PointBytes, [_|Us]),
number_chars(RY, SY). maplist(char_code, Us, Bs),
length(XBs, 32),
append(XBs, YBs, Bs),
maplist(reverse, [XBs,YBs], RBs),
maplist(bytes_integer, RBs, [RX,RY]).
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
?- crypto_name_curve(secp256k1, Curve), ?- crypto_name_curve(secp256k1, Curve),
@@ -818,16 +826,6 @@ fitting_exponent(N, E0, E) :-
fitting_exponent(N, E1, E) fitting_exponent(N, E1, E)
). ).
crypto_name_curve(secp112r1,
curve(secp112r1,
0x00db7c2abf62e35e668076bead208b,
0x00db7c2abf62e35e668076bead2088,
0x659ef8ba043916eede8911702b22,
point(0x09487239995a5ee76b55f9c2f098,
0xa89ce5af8724c0a23e0e0ff77500),
0x00db7c2abf62e35e7628dfac6561c5,
14,
1)).
crypto_name_curve(secp256k1, crypto_name_curve(secp256k1,
curve(secp256k1, curve(secp256k1,
0x00fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f, 0x00fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f,

View File

@@ -8,19 +8,10 @@
]). ]).
:- use_module(library(error)). :- use_module(library(error)).
:- use_module(library(iso_ext)).
:- use_module(library(lists), [append/3, member/2]). :- use_module(library(lists), [append/3, member/2]).
:- use_module(library(loader), [strip_module/3]). :- use_module(library(loader), [strip_module/3]).
load_context(GRBody, Module, GRBody0) :-
strip_module(GRBody, Module, GRBody0),
( nonvar(Module) ->
true
; prolog_load_context(module, Module) ->
true
; true
).
:- meta_predicate phrase(2, ?). :- meta_predicate phrase(2, ?).
:- meta_predicate phrase(2, ?, ?). :- meta_predicate phrase(2, ?, ?).
@@ -29,12 +20,14 @@ phrase(GRBody, S0) :-
phrase(GRBody, S0, []). phrase(GRBody, S0, []).
phrase(GRBody, S0, S) :- phrase(GRBody, S0, S) :-
load_context(GRBody, Module, GRBody0), strip_module(GRBody, M, GRBody1),
( var(GRBody0) -> ( var(GRBody) ->
instantiation_error(phrase/3) instantiation_error(phrase/3)
; dcg_body(GRBody0, S0, S, GRBody1, Module) -> ; nonvar(GRBody1),
call(GRBody1) dcg_constr(GRBody1),
; type_error(callable, GRBody0, phrase/3) dcg_body(GRBody1, S0, S, GRBody2) ->
call(M:GRBody2)
; call(M:GRBody1, S0, S)
). ).
@@ -47,25 +40,25 @@ module_call_qualified(M, Call, Call1) :-
% The same version of the below two dcg_rule clauses, but with module scoping. % The same version of the below two dcg_rule clauses, but with module scoping.
dcg_rule(( M:NonTerminal, Terminals --> GRBody ), ( M:Head :- Body )) :- dcg_rule(( M:NonTerminal, Terminals --> GRBody ), ( M:Head :- Body )) :-
dcg_non_terminal(NonTerminal, S0, S, Head), dcg_non_terminal(NonTerminal, S0, S, Head),
dcg_body(GRBody, S0, S1, Goal1, _), dcg_body(GRBody, S0, S1, Goal1),
dcg_terminals(Terminals, S, S1, Goal2), dcg_terminals(Terminals, S, S1, Goal2),
Body = ( Goal1, Goal2 ). Body = ( Goal1, Goal2 ).
dcg_rule(( M:NonTerminal --> GRBody ), ( M:Head :- Body )) :- dcg_rule(( M:NonTerminal --> GRBody ), ( M:Head :- Body )) :-
NonTerminal \= ( _, _ ), NonTerminal \= ( _, _ ),
dcg_non_terminal(NonTerminal, S0, S, Head), dcg_non_terminal(NonTerminal, S0, S, Head),
dcg_body(GRBody, S0, S, Body, _). dcg_body(GRBody, S0, S, Body).
% This program uses append/3 as defined in the Prolog prologue. % This program uses append/3 as defined in the Prolog prologue.
% Expands a DCG rule into a Prolog rule, when no error condition applies. % Expands a DCG rule into a Prolog rule, when no error condition applies.
dcg_rule(( NonTerminal, Terminals --> GRBody ), ( Head :- Body )) :- dcg_rule(( NonTerminal, Terminals --> GRBody ), ( Head :- Body )) :-
dcg_non_terminal(NonTerminal, S0, S, Head), dcg_non_terminal(NonTerminal, S0, S, Head),
dcg_body(GRBody, S0, S1, Goal1, _), dcg_body(GRBody, S0, S1, Goal1),
dcg_terminals(Terminals, S, S1, Goal2), dcg_terminals(Terminals, S, S1, Goal2),
Body = ( Goal1, Goal2 ). Body = ( Goal1, Goal2 ).
dcg_rule(( NonTerminal --> GRBody ), ( Head :- Body )) :- dcg_rule(( NonTerminal --> GRBody ), ( Head :- Body )) :-
NonTerminal \= ( _, _ ), NonTerminal \= ( _, _ ),
dcg_non_terminal(NonTerminal, S0, S, Head), dcg_non_terminal(NonTerminal, S0, S, Head),
dcg_body(GRBody, S0, S, Body, _). dcg_body(GRBody, S0, S, Body).
dcg_non_terminal(NonTerminal, S0, S, Goal) :- dcg_non_terminal(NonTerminal, S0, S, Goal) :-
NonTerminal =.. NonTerminalUniv, NonTerminal =.. NonTerminalUniv,
@@ -75,21 +68,21 @@ dcg_non_terminal(NonTerminal, S0, S, Goal) :-
dcg_terminals(Terminals, S0, S, S0 = List) :- dcg_terminals(Terminals, S0, S, S0 = List) :-
append(Terminals, S, List). append(Terminals, S, List).
dcg_body(Var, S0, S, Body, M) :- dcg_body(Var, S0, S, Body) :-
var(Var), var(Var),
module_call_qualified(M, Var, Var1), Body = phrase(Var, S0, S).
Body = phrase(Var1, S0, S). dcg_body(GRBody, S0, S, Body) :-
dcg_body(GRBody, S0, S, Body, M) :-
nonvar(GRBody), nonvar(GRBody),
dcg_constr(GRBody), dcg_constr(GRBody),
dcg_cbody(GRBody, S0, S, Body, M). dcg_cbody(GRBody, S0, S, Body).
dcg_body(NonTerminal, S0, S, Goal1, M) :- dcg_body(NonTerminal, S0, S, Goal1) :-
nonvar(NonTerminal), nonvar(NonTerminal),
\+ dcg_constr(NonTerminal), \+ dcg_constr(NonTerminal),
NonTerminal \= ( _ -> _ ), NonTerminal \= ( _ -> _ ),
NonTerminal \= ( \+ _ ), NonTerminal \= ( \+ _ ),
module_call_qualified(M, Goal, Goal1), loader:strip_module(NonTerminal, M, NonTerminal0),
dcg_non_terminal(NonTerminal, S0, S, Goal). dcg_non_terminal(NonTerminal0, S0, S, Goal0),
module_call_qualified(M, Goal0, Goal1).
% The following constructs in a grammar rule body % The following constructs in a grammar rule body
% are defined in the corresponding subclauses. % are defined in the corresponding subclauses.
@@ -107,42 +100,44 @@ dcg_constr((_->_)). % 7.14.12 - if-then (existence implementation dep.)
% The principal functor of the first argument indicates % The principal functor of the first argument indicates
% the construct to be expanded. % the construct to be expanded.
dcg_cbody([], S0, S, S0 = S, _M). dcg_cbody([], S0, S, S0 = S).
dcg_cbody([T|Ts], S0, S, Goal, _M) :- dcg_cbody([T|Ts], S0, S, Goal) :-
must_be(list, [T|Ts]), must_be(list, [T|Ts]),
dcg_terminals([T|Ts], S0, S, Goal). dcg_terminals([T|Ts], S0, S, Goal).
dcg_cbody(( GRFirst, GRSecond ), S0, S, ( First, Second ), M) :- dcg_cbody(( GRFirst, GRSecond ), S0, S, ( First, Second )) :-
dcg_body(GRFirst, S0, S1, First, M), dcg_body(GRFirst, S0, S1, First),
dcg_body(GRSecond, S1, S, Second, M). dcg_body(GRSecond, S1, S, Second).
dcg_cbody(( GREither ; GROr ), S0, S, ( Either ; Or ), M) :- dcg_cbody(( GREither ; GROr ), S0, S, ( Either ; Or )) :-
\+ subsumes_term(( _ -> _ ), GREither), \+ subsumes_term(( _ -> _ ), GREither),
dcg_body(GREither, S0, S, Either, M), dcg_body(GREither, S0, S, Either),
dcg_body(GROr, S0, S, Or, M). dcg_body(GROr, S0, S, Or).
dcg_cbody(( GRCond ; GRElse ), S0, S, ( Cond ; Else ), M) :- dcg_cbody(( GRCond ; GRElse ), S0, S, ( Cond ; Else )) :-
subsumes_term(( _GRIf -> _GRThen ), GRCond), subsumes_term(( _GRIf -> _GRThen ), GRCond),
dcg_cbody(GRCond, S0, S, Cond, M), dcg_cbody(GRCond, S0, S, Cond),
dcg_body(GRElse, S0, S, Else, M). dcg_body(GRElse, S0, S, Else).
dcg_cbody(( GREither '|' GROr ), S0, S, ( Either ; Or ), M) :- dcg_cbody(( GREither '|' GROr ), S0, S, ( Either ; Or )) :-
dcg_body(GREither, S0, S, Either, M), dcg_body(GREither, S0, S, Either),
dcg_body(GROr, S0, S, Or, M). dcg_body(GROr, S0, S, Or).
dcg_cbody({Goal}, S0, S, ( Goal1, S0 = S ), M) :- dcg_cbody({Goal}, S0, S, ( Goal, S0 = S )).
module_call_qualified(M, Goal, Goal1). dcg_cbody(call(Cont), S0, S, call(Cont, S0, S)).
dcg_cbody(call(Cont), S0, S, call(Cont1, S0, S), M) :- dcg_cbody(phrase(Body), S0, S, phrase(Body, S0, S)).
module_call_qualified(M, Cont, Cont1). dcg_cbody(!, S0, S, ( !, S0 = S )).
dcg_cbody(phrase(Body), S0, S, phrase(Body1, S0, S), M) :- dcg_cbody(\+ GRBody, S0, S, ( \+ phrase(GRBody,S0,_), S0 = S )).
module_call_qualified(M, Body, Body1). dcg_cbody(( GRIf -> GRThen ), S0, S, ( If -> Then )) :-
dcg_cbody(!, S0, S, ( !, S0 = S ), _M). dcg_body(GRIf, S0, S1, If),
dcg_cbody(\+ GRBody, S0, S, ( \+ phrase(GRBody1,S0,_), S0 = S ), M) :- dcg_body(GRThen, S1, S, Then).
module_call_qualified(M, GRBody, GRBody1).
dcg_cbody(( GRIf -> GRThen ), S0, S, ( If -> Then ), M) :-
dcg_body(GRIf, S0, S1, If, M),
dcg_body(GRThen, S1, S, Then, M).
user:term_expansion(Term0, Term) :- user:term_expansion(Term0, Term) :-
nonvar(Term0), nonvar(Term0),
dcg_rule(Term0, Term). dcg_rule(Term0, Term).
% Describes a sequence % Describes a sequence
seq(Xs, Cs0,Cs) :-
var(Xs),
Cs0 == [],
!,
Xs = [],
Cs0 = Cs.
seq([]) --> []. seq([]) --> [].
seq([E|Es]) --> [E], seq(Es). seq([E|Es]) --> [E], seq(Es).
@@ -151,14 +146,23 @@ seqq([]) --> [].
seqq([Es|Ess]) --> seq(Es), seqq(Ess). seqq([Es|Ess]) --> seq(Es), seqq(Ess).
% Describes an arbitrary number of elements % Describes an arbitrary number of elements
...(Cs0,Cs) :-
Cs0 == [],
!,
Cs0 = Cs.
... --> [] | [_], ... . ... --> [] | [_], ... .
user:goal_expansion(phrase(GRBody, S, S0), GRBody1) :- error_goal(error(E, must_be/2), error(E, must_be/2)).
load_context(GRBody, M, GRBody0), error_goal(error(E, (=..)/2), error(E, (=..)/2)).
error_goal(E, _) :- throw(E).
user:goal_expansion(phrase(GRBody, S, S0), GRBody2) :-
loader:strip_module(GRBody, M, GRBody0),
nonvar(GRBody0), nonvar(GRBody0),
catch(dcgs:dcg_body(GRBody0, S, S0, GRBody1, M), catch(dcgs:dcg_body(GRBody0, S, S0, GRBody1),
error(E, must_be/2), E,
( GRBody1 = throw(error(E, must_be/2)) ) dcgs:error_goal(E, GRBody1)
). ),
module_call_qualified(M, GRBody1, GRBody2).
user:goal_expansion(phrase(GRBody, S), phrase(GRBody, S, [])). user:goal_expansion(phrase(GRBody, S), phrase(GRBody, S, [])).

View File

@@ -1,5 +1,5 @@
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Written September 2018 by Markus Triska (triska@metalevel.at) Written 2018-2022 by Markus Triska (triska@metalevel.at)
I place this code in the public domain. Use it in any way you want. I place this code in the public domain. Use it in any way you want.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
@@ -10,6 +10,10 @@
type_error/3 type_error/3
]). ]).
:- meta_predicate check_(1, ?, ?).
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
must_be(Type, Term) must_be(Type, Term)
@@ -28,8 +32,12 @@
- boolean - boolean
- character - character
- chars - chars
- in_character
- integer - integer
- list - list
- octet_character
- octet_chars
- term
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
must_be(Type, Term) :- must_be(Type, Term) :-
@@ -44,9 +52,16 @@ must_be_(var, Term) :-
; throw(error(uninstantiation_error(Term), must_be/2)) ; throw(error(uninstantiation_error(Term), must_be/2))
). ).
must_be_(integer, Term) :- check_(integer, integer, Term). must_be_(integer, Term) :- check_(integer, integer, Term).
must_be_(not_less_than_zero, N) :-
must_be(integer, N),
( N >= 0 -> true
; domain_error(not_less_than_zero, N, must_be/2)
).
must_be_(atom, Term) :- check_(atom, atom, Term). must_be_(atom, Term) :- check_(atom, atom, Term).
must_be_(character, T) :- check_(error:character, character, T). must_be_(character, T) :- check_(error:character, character, T).
must_be_(in_character, T) :- check_(error:in_character, in_character, T).
must_be_(chars, Ls) :- must_be_(chars, Ls) :-
can_be(chars, Ls), % prioritize type errors over instantiation errors
must_be(list, Ls), must_be(list, Ls),
( '$is_partial_string'(Ls) -> ( '$is_partial_string'(Ls) ->
% The expected case (success) uses a very fast test. % The expected case (success) uses a very fast test.
@@ -55,9 +70,27 @@ must_be_(chars, Ls) :-
true true
; all_characters(Ls) ; all_characters(Ls)
). ).
must_be_(octet_character, C) :-
must_be(character, C),
( octet_character(C) -> true
; domain_error(octet_character, C, must_be/2)
).
must_be_(octet_chars, Cs) :-
must_be(chars, Cs),
( '$first_non_octet'(Cs, C) ->
domain_error(octet_character, C, must_be/2)
; true
).
must_be_(list, Term) :- check_(error:ilist, list, Term). must_be_(list, Term) :- check_(error:ilist, list, Term).
must_be_(type, Term) :- check_(error:type, type, Term). must_be_(type, Term) :- check_(error:type, type, Term).
must_be_(boolean, Term) :- check_(error:boolean, boolean, Term). must_be_(boolean, Term) :- check_(error:boolean, boolean, Term).
must_be_(term, Term) :-
( \+ ground(Term) ->
instantiation_error(must_be/2)
; \+ acyclic_term(Term) ->
type_error(term, Term, must_be/2)
; true
).
% We cannot use maplist(must_be(character), Cs), because library(lists) % We cannot use maplist(must_be(character), Cs), because library(lists)
% uses library(error), so importing it would create a cyclic dependency. % uses library(error), so importing it would create a cyclic dependency.
@@ -79,6 +112,15 @@ character(C) :-
atom(C), atom(C),
atom_length(C, 1). atom_length(C, 1).
octet_character(C) :-
char_code(C, Code),
0 =< Code, Code =< 0xff.
in_character(C) :-
( character(C)
; C == end_of_file
).
ilist(Ls) :- ilist(Ls) :-
'$skip_max_list'(_, _, Ls, Rs), '$skip_max_list'(_, _, Ls, Rs),
( var(Rs) -> ( var(Rs) ->
@@ -90,10 +132,15 @@ type(type).
type(integer). type(integer).
type(atom). type(atom).
type(character). type(character).
type(in_character).
type(octet_character).
type(octet_chars).
type(chars). type(chars).
type(list). type(list).
type(var). type(var).
type(boolean). type(boolean).
type(term).
type(not_less_than_zero).
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
can_be(Type, Term) can_be(Type, Term)
@@ -117,11 +164,45 @@ can_be(Type, Term) :-
). ).
can_(integer, Term) :- integer(Term). can_(integer, Term) :- integer(Term).
can_(not_less_than_zero, N) :-
( integer(N) ->
( N >= 0 -> true
; domain_error(not_less_than_zero, N, can_be/2)
)
; type_error(integer, N, can_be/2)
).
can_(atom, Term) :- atom(Term). can_(atom, Term) :- atom(Term).
can_(character, T) :- character(T). can_(character, T) :- character(T).
can_(chars, Ls) :- '$is_partial_string'(Ls). can_(in_character, T) :- in_character(T).
can_(chars, Ls) :-
( '$is_partial_string'(Ls) -> true
; can_be(list, Ls),
can_be_chars(Ls)
).
can_(octet_character, C) :-
( octet_character(C) -> true
; domain_error(octet_character, C, can_be/2)
).
can_(octet_chars, Cs) :-
can_be(chars, Cs),
( '$skip_max_list'(_, _, Cs, []), % temporarily turn Cs into a list
'$first_non_octet'(Cs, C) ->
domain_error(octet_character, C, can_be/2)
; true
).
can_(list, Term) :- list_or_partial_list(Term). can_(list, Term) :- list_or_partial_list(Term).
can_(boolean, Term) :- boolean(Term). can_(boolean, Term) :- boolean(Term).
can_(term, Term) :-
( acyclic_term(Term) ->
true
; type_error(term, Term, can_be/2)
).
can_be_chars(Var) :- var(Var), !.
can_be_chars([]).
can_be_chars([X|Xs]) :-
can_be(character, X),
can_be_chars(Xs).
list_or_partial_list(Ls) :- list_or_partial_list(Ls) :-
'$skip_max_list'(_, _, Ls, Rs), '$skip_max_list'(_, _, Ls, Rs),

View File

@@ -1,5 +1,5 @@
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Written June 2020 by Markus Triska (triska@metalevel.at) Written 2020, 2022 by Markus Triska (triska@metalevel.at)
Part of Scryer Prolog. Part of Scryer Prolog.
Predicates for reasoning about files and directories. Predicates for reasoning about files and directories.
@@ -65,52 +65,46 @@
:- use_module(library(error)). :- use_module(library(error)).
:- use_module(library(lists)). :- use_module(library(lists)).
:- use_module(library(charsio)). :- use_module(library(charsio)).
:- use_module(library(dcgs)).
list_of_chars(Cs) :-
must_be(list, Cs),
maplist(must_be(character), Cs).
directory_files(Directory, Files) :- directory_files(Directory, Files) :-
list_of_chars(Directory), must_be(chars, Directory),
can_be(list, Files), can_be(list, Files),
'$directory_files'(Directory, Files). '$directory_files'(Directory, Files).
file_size(File, Size) :- file_size(File, Size) :-
file_must_exist(File, file_size/2), file_must_exist(File, file_size/2),
list_of_chars(File),
can_be(integer, Size), can_be(integer, Size),
'$file_size'(File, Size). '$file_size'(File, Size).
file_exists(File) :- file_exists(File) :-
list_of_chars(File), must_be(chars, File),
'$file_exists'(File). '$file_exists'(File).
directory_exists(Directory) :- directory_exists(Directory) :-
list_of_chars(Directory), must_be(chars, Directory),
'$directory_exists'(Directory). '$directory_exists'(Directory).
make_directory(Directory) :- make_directory(Directory) :-
list_of_chars(Directory), must_be(chars, Directory),
'$make_directory'(Directory). '$make_directory'(Directory).
make_directory_path(Directory) :- make_directory_path(Directory) :-
list_of_chars(Directory), must_be(chars, Directory),
'$make_directory_path'(Directory). '$make_directory_path'(Directory).
delete_file(File) :- delete_file(File) :-
file_must_exist(File, delete_file/1), file_must_exist(File, delete_file/1),
list_of_chars(File),
'$delete_file'(File). '$delete_file'(File).
rename_file(File, Renamed) :- rename_file(File, Renamed) :-
file_must_exist(File, rename_file/2), file_must_exist(File, rename_file/2),
list_of_chars(File), must_be(chars, Renamed),
list_of_chars(Renamed),
'$rename_file'(File, Renamed). '$rename_file'(File, Renamed).
delete_directory(Directory) :- delete_directory(Directory) :-
directory_must_exist(Directory, delete_directory/1), directory_must_exist(Directory, delete_directory/1),
list_of_chars(Directory), must_be(chars, Directory),
'$delete_directory'(Directory). '$delete_directory'(Directory).
file_must_exist(File, Context) :- file_must_exist(File, Context) :-
@@ -150,8 +144,7 @@ working_directory(Dir0, Dir) :-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
path_canonical(Ps, Cs) :- path_canonical(Ps, Cs) :-
must_be(list, Ps), must_be(chars, Ps),
maplist(must_be(character), Ps),
can_be(list, Cs), can_be(list, Cs),
'$path_canonical'(Ps, Cs). '$path_canonical'(Ps, Cs).
@@ -205,20 +198,20 @@ path_segments(Path, Segments) :-
'$directory_separator'(Sep), '$directory_separator'(Sep),
( var(Path) -> ( var(Path) ->
must_be(list, Segments), must_be(list, Segments),
maplist(list_of_chars, Segments), maplist(must_be(chars), Segments),
append_with_separator(Segments, Sep, Path) phrase(append_with_separator(Segments, Sep), Path)
; list_of_chars(Path), ; must_be(chars, Path),
path_to_segments(Path, Sep, Segments) path_to_segments(Path, Sep, Segments)
). ).
append_with_separator([], _, []). append_with_separator([], _) --> [].
append_with_separator([Segment|Segments], Sep, Path) :- append_with_separator([Segment|Segments], Sep) -->
append_with_separator_(Segments, Segment, Sep, Path). append_with_separator_(Segments, Segment, Sep).
append_with_separator_([], Segment, _, Segment). append_with_separator_([], Segment, _) --> seq(Segment).
append_with_separator_([Segment|Segments], Prev, Sep, Path) :- append_with_separator_([Segment|Segments], Prev, Sep) -->
append(Prev, [Sep|Rest], Path), seq(Prev), [Sep],
append_with_separator_(Segments, Segment, Sep, Rest). append_with_separator_(Segments, Segment, Sep).
path_to_segments(Path, Sep, Segments) :- path_to_segments(Path, Sep, Segments) :-
( append(Front, [Sep|Ps], Path) -> ( append(Front, [Sep|Ps], Path) ->

View File

@@ -3,7 +3,7 @@
:- use_module(library(atts)). :- use_module(library(atts)).
:- use_module(library(dcgs)). :- use_module(library(dcgs)).
:- meta_predicate freeze(?, 0). :- meta_predicate freeze(-, 0).
:- attribute frozen/1. :- attribute frozen/1.

View File

@@ -1,5 +1,5 @@
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Written 2020, 2021 by Markus Triska (triska@metalevel.at) Written 2022 by Adrián Arroyo Calle (adrian.arroyocalle@gmail.com)
Part of Scryer Prolog. Part of Scryer Prolog.
http_open(+Address, -Stream, +Options) http_open(+Address, -Stream, +Options)
@@ -7,12 +7,16 @@
Yields Stream to read the body of an HTTP reply from Address. Yields Stream to read the body of an HTTP reply from Address.
Address is a list of characters, and includes the method. Both HTTP Address is a list of characters, and includes the method. Both HTTP
and HTTPS are supported. Redirects are followed. and HTTPS are supported.
Currently, Options must be the empty list. Options may be Options supported:
added in the future to give more control over the connection.
We use HTTP/1.0 until we can read chunked transfer-encoding. * method(+Method): Sets the HTTP method of the call. Method can be get (default), head, delete, post, put or patch.
* data(+Data): Data to be sent in the request. Useful for POST, PUT and PATCH operations.
* size(-Size): Unifies with the value of the Content-Length header
* request_headers(+RequestHeaders): Headers to be used in the request
* headers(-ListHeaders): Unifies with a list with all headers returned in the response
* status_code(-Code): Unifies with the status code of the request (200, 201, 404, ...)
Example: Example:
@@ -23,62 +27,42 @@
:- module(http_open, [http_open/3]). :- module(http_open, [http_open/3]).
:- use_module(library(sockets)). :- use_module(library(lists)).
:- use_module(library(error)).
:- use_module(library(format)).
:- use_module(library(charsio)).
:- use_module(library(dcgs)).
:- use_module(library(lists), [member/2]).
:- use_module(library(tls)).
http_open(Address, Stream, Options) :- http_open(Address, Response, Options) :-
must_be(list, Options), parse_http_options(Options, OptionValues),
must_be(list, Address), ( member(method(Method), OptionValues) -> true; Method = get),
once(phrase((seq(SchemeCs), "://", seq(Rest)), Address)), ( member(data(Data), OptionValues) -> true; Data = []),
atom_chars(Scheme, SchemeCs), ( member(request_headers(RequestHeaders), OptionValues) -> true; RequestHeaders = ['user-agent'("Scryer Prolog")]),
chars_host_url(Rest, Host, URL), ( member(status_code(Code), OptionValues) -> true; true),
connect(Scheme, Host, Stream0), ( member(headers(Headers), OptionValues) -> true; true),
format(Stream0, "\ ( member(size(Size), OptionValues) -> member('content-length'(Size), Headers); true),
GET ~s HTTP/1.0\r\n\ '$http_open'(Address, Response, Method, Code, Data, Headers, RequestHeaders).
Host: ~w\r\n\
User-Agent: Scryer Prolog\r\n\
Connection: close\r\n\r\n\
", [URL,Host]),
read_line_to_chars(Stream0, StatusLine, []),
once(phrase(("HTTP/1.",(['0']|['1'])," ",[D1]), StatusLine, _)),
read_header_lines(Stream0, HeaderLines),
handle_response(D1, HeaderLines, Stream0, Stream).
handle_response('2', _, Stream, Stream). % ok parse_http_options(Options, OptionValues) :-
handle_response('3', HeaderLines, Stream0, Stream) :- % redirect maplist(parse_http_options_, Options, OptionValues).
close(Stream0),
once((member(Line, HeaderLines),
phrase(("Location: ",seq(Location),"\r\n"), Line))),
http_open(Location, Stream, []).
% Status-Line = HTTP-Version SP Status-Code SP Reason-Phrase CRLF parse_http_options_(method(Method), method(Method)) :-
( var(Method) ->
read_header_lines(Stream, Hs) :- throw(error(instantiation_error, http_open/3))
read_line_to_chars(Stream, Cs, []), ;
( Cs == "" -> Hs = [] member(Method, [get, post, put, delete, patch, head]) -> true
; Cs == "\r\n" -> Hs = [] ;
; Hs = [Cs|Rest], throw(error(domain_error(http_option, method(Method)), _))
read_header_lines(Stream, Rest)
). ).
chars_host_url(Cs, Host, [/|Us]) :- parse_http_options_(data(Data), data(Data)) :-
( phrase((seq(Hs),"/",seq(Us)), Cs) -> ( var(Data) ->
true throw(error(instantiation_error, http_open/3))
; Hs = Cs, ; true
Us = [] ).
),
atom_chars(Host, Hs).
connect(https, Host, Stream) :- parse_http_options_(request_headers(Headers), request_headers(Headers)) :-
socket_client_open(Host:443, Stream0, []), ( var(Headers) ->
atom_chars(Host, HostChars), throw(error(instantiation_error, http_open/3))
tls_client_context(Context, [hostname(HostChars)]), ; true
tls_client_negotiate(Context, Stream0, Stream). ).
connect(http, Host, Stream) :-
socket_client_open(Host:80, Stream, []).
parse_http_options_(size(Size), size(Size)).
parse_http_options_(status_code(Code), status_code(Code)).
parse_http_options_(headers(Headers), headers(Headers)).

View File

@@ -1,11 +1,11 @@
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Written in December 2020 by Adrián Arroyo (adrian.arroyocalle@gmail.com) Written in December 2020 by Adrián Arroyo (adrian.arroyocalle@gmail.com)
Updated in March 2022 by Adrián Arroyo to use the Hyper backend
Part of Scryer Prolog Part of Scryer Prolog
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 currently implements a subset of HTTP/1.0. It is recommended to put a reverse It is based on Hyper, which allows for HTTP/1.0, HTTP/1.1 and HTTP/2. However,
proxy like nginx in front of this server to have access to more advanced features some advanced features that Hyper provides are still not accesible.
(gzip compression, HTTPS, ...)
Usage Usage
========== ==========
@@ -41,37 +41,36 @@
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 - HTTP Basic Auth
- Keep-Alive support
- Session handling via cookies - Session handling via cookies
- HTML Templating - HTML Templating
I place this code in the public domain. Use it in any way you want. I place this code in the public domain. Use it in any way you want.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
:- module(http_server, [ :- module(http_server, [
http_listen/2, http_listen/2,
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
url_decode//1
]). ]).
:- meta_predicate http_listen(?, 2). :- meta_predicate http_listen(?, :).
:- use_module(library(sockets)).
:- use_module(library(dcgs)).
:- use_module(library(format)).
:- use_module(library(error)).
:- use_module(library(charsio)). :- use_module(library(charsio)).
:- use_module(library(lists)).
:- use_module(library(iso_ext)).
:- use_module(library(time)).
:- use_module(library(crypto)). :- use_module(library(crypto)).
:- use_module(library(error)).
:- use_module(library(format)).
:- use_module(library(iso_ext)).
:- use_module(library(lists)).
:- use_module(library(pio)).
:- use_module(library(time)).
% Module prefix workaround with meta_predicate
http_listen(Port, Module:Handlers0) :- http_listen(Port, Module:Handlers0) :-
must_be(integer, Port),
must_be(list, Handlers0),
maplist(module_qualification(Module), Handlers0, Handlers), maplist(module_qualification(Module), Handlers0, Handlers),
http_listen_(Port, Handlers). http_listen_(Port, Handlers).
@@ -79,49 +78,84 @@ module_qualification(M, H0, H) :-
H0 =.. [Method, Path, Goal], H0 =.. [Method, Path, Goal],
H =.. [Method, Path, M:Goal]. H =.. [Method, Path, M:Goal].
% Server initialization
http_listen_(Port, Handlers) :- http_listen_(Port, Handlers) :-
must_be(integer, Port), phrase(format_("0.0.0.0:~d", [Port]), Addr),
must_be(list, Handlers), '$http_listen'(Addr, HttpListener),!,
once(socket_server_open(Port, Socket)), format("Listening at ~s\n", [Addr]),
format("Listening at port ~d\n", [Port]), http_loop(HttpListener, Handlers).
accept_loop(Socket, Handlers).
% Server loop http_loop(HttpListener, Handlers) :-
accept_loop(Socket, Handlers) :- '$http_accept'(HttpListener, RequestMethod, RequestPath, RequestHeaders, RequestQuery, RequestStream, ResponseHandle),
setup_call_cleanup(socket_server_accept(Socket, _Client, Stream, [type(binary)]),
(
read_header_lines(Stream, Lines),
[Request|Headers] = Lines,
(
(phrase(parse_request(_Version, Method, Path, Queries), Request), maplist(map_parse_header, Headers, HeadersKV)) -> (
(
member("content-length"-ContentLength, HeadersKV) ->
(number_chars(ContentLengthN, ContentLength), get_bytes(Stream, ContentLengthN, Body))
;true
),
current_time(Time), current_time(Time),
phrase(format_time("%Y-%m-%d (%H:%M:%S)", Time), TimeString), phrase(format_time("%Y-%m-%d (%H:%M:%S)", Time), TimeString),
format("~s ~w ~s\n", [TimeString, Method, Path]), format("~s ~w ~s\n", [TimeString, RequestMethod, RequestPath]),
maplist(map_header_kv, RequestHeaders, RequestHeadersKV),
phrase(parse_queries(RequestQueries), RequestQuery),
( (
match_handler(Handlers, Method, Path, Handler) -> match_handler(Handlers, RequestMethod, RequestPath, Handler) ->
( (
HttpRequest = http_request(HeadersKV, binary(Body), Queries), HttpRequest = http_request(RequestHeadersKV, stream(RequestStream), RequestQueries),
HttpResponse = http_response(_, _, _), HttpResponse = http_response(_, _, _),
(call(Handler, HttpRequest, HttpResponse) -> (call(Handler, HttpRequest, HttpResponse) ->
send_response(Stream, HttpResponse) send_response(ResponseHandle, HttpResponse)
; format(Stream, "HTTP/1.0 500 Internal Server Error\r\n\r\n", []) ; (
'$http_answer'(ResponseHandle, 500, [], ResponseStream),
call_cleanup(format(ResponseStream, "Internal Server Error", []), close(ResponseStream)))
) )
) )
; format(Stream, "HTTP/1.0 404 Not Found\r\n\r\n", []) ; (
) '$http_answer'(ResponseHandle, 404, [], ResponseStream),
);( call_cleanup(format(ResponseStream, "Not Found"), close(ResponseStream)))
format(Stream, "HTTP/1.0 400 Bad Request\r\n\r\n", []) % bad format
)
), ),
! % Remove http_loop(HttpListener, Handlers).
), close(Stream)),
accept_loop(Socket, Handlers). send_response(ResponseHandle, http_response(StatusCode0, text(ResponseText), ResponseHeaders0)) :-
default(StatusCode0, 200, StatusCode),
maplist(map_header_kv_2, ResponseHeaders, ResponseHeaders0),
'$http_answer'(ResponseHandle, StatusCode, ResponseHeaders, ResponseStream),
call_cleanup(
format(ResponseStream, "~s", [ResponseText]),
close(ResponseStream)
).
send_response(ResponseHandle, http_response(StatusCode0, bytes(ResponseBytes), ResponseHeaders0)) :-
default(StatusCode0, 200, StatusCode),
maplist(map_header_kv_2, ResponseHeaders, ResponseHeaders0),
'$http_answer'(ResponseHandle, StatusCode, ResponseHeaders, ResponseStream),
call_cleanup(
format(ResponseStream, "~s", [ResponseBytes]),
close(ResponseStream)
).
send_response(ResponseHandle, http_response(StatusCode0, file(Filename), ResponseHeaders0)) :-
default(StatusCode0, 200, StatusCode),
maplist(map_header_kv_2, ResponseHeaders, ResponseHeaders0),
'$http_answer'(ResponseHandle, StatusCode, ResponseHeaders, ResponseStream),
call_cleanup(
setup_call_cleanup(
open(Filename, read, FileStream, [type(binary)]),
(
get_n_chars(FileStream, _, FileCs),
format(ResponseStream, "~s", [FileCs])
),
close(FileStream)
),
close(ResponseStream)
).
default(Var, Default, Out) :-
(var(Var) -> Out = Default
; Var = Out
).
map_header_kv(T, K-V) :-
T =.. [K0, V],
atom_chars(K0, K).
map_header_kv_2(T, K-V) :-
atom_chars(K0, K),
T =.. [K0, V].
match_handler(Handlers, Method, "/", Handler) :- match_handler(Handlers, Method, "/", Handler) :-
member(H, Handlers), member(H, Handlers),
@@ -139,27 +173,6 @@ match_handler(Handlers, Method, Path, Handler) :-
var(Var), var(Var),
Var = Path. Var = Path.
% Helper and recommended predicates
http_headers(http_request(Headers, _, _), Headers).
http_headers(http_response(_, _, Headers), Headers).
http_body(http_request(_, binary(ByteBody), _), text(TextBody)) :- chars_utf8bytes(TextBody, ByteBody).
http_body(http_request(Headers, binary(ByteBody), _), form(FormBody)) :-
member("content-type"-"application/x-www-form-urlencoded", Headers),
chars_utf8bytes(TextBody, ByteBody),
phrase(parse_queries(FormBody), TextBody).
http_body(http_request(_, Body, _), Body).
http_body(http_response(_, Body, _), Body).
http_status_code(http_response(StatusCode, _, _), StatusCode).
http_redirect(http_response(307, text("Moved Temporarily"), ["Location"-Uri]), Uri).
http_query(http_request(_, _, Queries), Key, Value) :- member(Key-Value, Queries).
% Route matching
path(Pattern) --> path(Pattern) -->
{ {
Pattern =.. Parts, Pattern =.. Parts,
@@ -183,76 +196,31 @@ path(Pattern) -->
path([]) --> []. path([]) --> [].
% Send responses string_without(Not, [Char|String]) -->
send_response(Stream, http_response(StatusCode0, file(Filename), Headers)) :- [Char],
default(StatusCode0, 200, StatusCode), {
format(Stream, "HTTP/1.0 ~d\r\n", [StatusCode]), \+ member(Char, Not)
overwrite_header("connection"-"Close", Headers, Headers0), },
write_headers(Stream, Headers0), string_without(Not, String).
format(Stream, "\r\n", []),
setup_call_cleanup(
open(Filename, read, FileStream, [type(binary)]),
pipe_bytes(FileStream, Stream),
close(FileStream)
).
send_response(Stream, http_response(StatusCode0, text(TextResponse), Headers)) :- string_without(_, []) -->
default(StatusCode0, 200, StatusCode), [].
format(Stream, "HTTP/1.0 ~d\r\n", [StatusCode]),
overwrite_header("content-type"-"text/plain", Headers, Headers0),
overwrite_header("connection"-"Close", Headers0, Headers1),
write_headers(Stream, Headers1),
format(Stream, "\r\n~s", [TextResponse]).
send_response(Stream, http_response(StatusCode0, binary(BinaryResponse), Headers)) :- http_headers(http_request(Headers, _, _), Headers).
default(StatusCode0, 200, StatusCode), http_headers(http_response(_, _, Headers), Headers).
format(Stream, "HTTP/1.0 ~d\r\n", [StatusCode]),
overwrite_header("connection"-"Close", Headers, Headers0),
write_headers(Stream, Headers0),
format(Stream, "\r\n", []),
put_bytes(Stream, BinaryResponse).
default(Var, Default, Out) :- http_body(http_request(_, stream(StreamBody), _), bytes(BytesBody)) :- get_n_chars(StreamBody, _, BytesBody).
(var(Var) -> Out = Default http_body(http_request(_, stream(StreamBody), _), text(TextBody)) :- get_n_chars(StreamBody, _, TextBody).
; Var = Out http_body(http_request(Headers, stream(StreamBody), _), form(FormBody)) :-
). member("content-type"-"application/x-www-form-urlencoded", Headers),
get_n_chars(StreamBody, _, TextBody),
phrase(parse_queries(FormBody), TextBody).
http_body(http_request(_, Body, _), Body).
http_body(http_response(_, Body, _), Body).
header([]) --> []. http_status_code(http_response(StatusCode, _, _), StatusCode).
header([Key-Value|Headers]) --> http_redirect(http_response(307, text("Moved Temporarily"), ["Location"-Uri]), Uri).
format_("~s: ~s\r\n", [Key, Value]), http_query(http_request(_, _, Queries), Key, Value) :- member(Key-Value, Queries).
header(Headers).
write_headers(Stream, Headers) :-
phrase(header(Headers), Cs),
format(Stream, "~s", [Cs]).
overwrite_header(Key-Value, [], [Key-Value]).
overwrite_header(Key-Value, [Header|Headers], [Header|HeadersOut]) :-
Header = Key0-_,
Key0 \= Key,
overwrite_header(Key-Value, Headers, HeadersOut).
overwrite_header(Key-Value, [Header|Headers], [NewHeader|Headers]) :-
Header = Key-_,
NewHeader = Key-Value.
parse_request(http_version(Major, Minor), Method, Path, Queries) -->
method(Method),
" ",
parse_path(Path, Queries),
" ",
"HTTP/",
natural(Major),
".",
natural(Minor),
"\r\n".
parse_path(Path, Queries) -->
string_without("?", Path),
"?",
parse_queries(Queries).
parse_path(Path, []) -->
string_without(" ", Path).
parse_queries([Key-Value|Queries]) --> parse_queries([Key-Value|Queries]) -->
string_without("=", Key0), string_without("=", Key0),
@@ -278,94 +246,9 @@ parse_queries([Key-Value]) -->
phrase(url_decode(Value), Value0) phrase(url_decode(Value), Value0)
}. }.
map_parse_header(Header, HeaderKV) :- parse_queries([]) -->
phrase(parse_header(HeaderKV), Header).
parse_header(Key-Value) -->
string_without(":", Key0),
{
chars_lower(Key0, Key)
},
": ",
string_without("\r", Value),
"\r\n".
method(options) --> "OPTIONS".
method(get) --> "GET".
method(head) --> "HEAD".
method(post) --> "POST".
method(put) --> "PUT".
method(delete) --> "DELETE".
string_without(Not, [Char|String]) -->
[Char],
{
\+ member(Char, Not)
},
string_without(Not, String).
string_without(_, []) -->
[]. [].
natural(Nat) -->
natural_(NatChars),
{
number_chars(Nat, NatChars)
}.
natural_([Nat|Nats]) -->
[Nat],
{
char_type(Nat, decimal_digit)
},
natural_(Nats).
natural_([]) -->
[].
read_header_lines(Stream, Hs) :-
read_line_to_chars(Stream, Cs, []),
( Cs == "" -> Hs = []
; Cs == "\r\n" -> Hs = []
; Hs = [Cs|Rest],
read_header_lines(Stream, Rest)
).
get_bytes(Stream, Length, Res) :- get_bytes(Stream, Length, [], Res).
get_bytes(Stream, Length, Acc, Res) :-
(Length > 0 -> (
get_byte(Stream, B),
B =\= -1,
get_bytes(Stream, Length - 1, [B|Acc], Res)
); reverse(Acc, Res)).
put_bytes(_, []).
put_bytes(Stream, [Byte|Bytes]) :-
put_byte(Stream, Byte),
put_bytes(Stream, Bytes).
pipe_bytes(StreamIn, StreamOut) :-
get_byte(StreamIn, Byte),
(
Byte =\= -1 ->
(
put_byte(StreamOut, Byte),
pipe_bytes(StreamIn, StreamOut)
)
; true).
% WARNING: This only works for ASCII chars. This code can be modified to support
% Latin1 characters also but a completely different approach is needed for other
% languages. Since HTTP internals are ASCII, this is fine for this usecase.
chars_lower(Chars, Lower) :-
maplist(char_lower, Chars, Lower).
char_lower(Char, Lower) :-
char_code(Char, Code),
((Code >= 65,Code =< 90) ->
LowerCode is Code + 32,
char_code(Lower, LowerCode)
; Char = Lower).
% Decodes a UTF-8 URL Encoded string: RFC-1738 % Decodes a UTF-8 URL Encoded string: RFC-1738
url_decode([Char|Chars]) --> url_decode([Char|Chars]) -->
[Char], [Char],

View File

@@ -1,8 +1,3 @@
%% for builtins that are not part of the ISO standard.
%% must be loaded at the REPL with
%% ?- use_module(library(iso_ext)).
:- module(iso_ext, [bb_b_put/2, :- module(iso_ext, [bb_b_put/2,
bb_get/2, bb_get/2,
bb_put/2, bb_put/2,
@@ -14,8 +9,9 @@
partial_string_tail/2, partial_string_tail/2,
setup_call_cleanup/3, setup_call_cleanup/3,
call_nth/2, call_nth/2,
% variant/2, copy_term_nat/2,
copy_term_nat/2]). asserta/2,
assertz/2]).
:- use_module(library(error), [can_be/2, :- use_module(library(error), [can_be/2,
domain_error/3, domain_error/3,
@@ -60,59 +56,64 @@ call_cleanup(G, C) :- setup_call_cleanup(true, G, C).
:- meta_predicate(setup_call_cleanup(0, 0, 0)). :- meta_predicate(setup_call_cleanup(0, 0, 0)).
:- non_counted_backtracking setup_call_cleanup/3.
setup_call_cleanup(S, G, C) :- setup_call_cleanup(S, G, C) :-
'$get_b_value'(B), '$get_b_value'(B),
'$call'(S), '$call_with_inference_counting'(call(S)),
'$set_cp_by_default'(B), '$set_cp_by_default'(B),
'$get_current_block'(Bb), '$get_current_block'(Bb),
( C = _:CC, ( C = _:CC,
'$call_with_default_policy'(var(CC)) -> var(CC) ->
instantiation_error(setup_call_cleanup/3) instantiation_error(setup_call_cleanup/3)
; '$call_with_default_policy'(scc_helper(C, G, Bb)) ; scc_helper(C, G, Bb)
). ).
:- meta_predicate(scc_helper(?,0,?)). :- meta_predicate(scc_helper(?,0,?)).
:- non_counted_backtracking scc_helper/3. :- non_counted_backtracking scc_helper/3.
scc_helper(C, G, Bb) :- scc_helper(C, G, Bb) :-
'$get_cp'(Cp), '$get_cp'(Cp),
'$install_scc_cleaner'(C, NBb), '$install_scc_cleaner'(C, NBb),
call(G), '$call_with_inference_counting'(call(G)),
( '$check_cp'(Cp) -> ( '$check_cp'(Cp) ->
'$reset_block'(Bb), '$reset_block'(Bb),
'$call_with_default_policy'(run_cleaners_without_handling(Cp)) run_cleaners_without_handling(Cp)
; '$call_with_default_policy'(true) ; true
; '$reset_block'(NBb), ; '$reset_block'(NBb),
'$fail' '$fail'
). ).
scc_helper(_, _, Bb) :- scc_helper(_, _, Bb) :-
'$reset_block'(Bb), '$reset_block'(Bb),
'$get_ball'(Ball), '$push_ball_stack',
'$erase_ball', run_cleaners_with_handling,
'$call_with_default_policy'(run_cleaners_with_handling), '$pop_from_ball_stack',
'$call_with_default_policy'(throw(Ball)). '$unwind_stack'.
scc_helper(_, _, _) :- scc_helper(_, _, _) :-
'$get_cp'(Cp), '$get_cp'(Cp),
'$call_with_default_policy'(run_cleaners_without_handling(Cp)), run_cleaners_without_handling(Cp),
'$fail'. '$fail'.
:- non_counted_backtracking run_cleaners_with_handling/0. :- non_counted_backtracking run_cleaners_with_handling/0.
run_cleaners_with_handling :- run_cleaners_with_handling :-
'$get_scc_cleaner'(C), '$get_scc_cleaner'(C),
'$get_level'(B), '$get_level'(B),
'$call_with_default_policy'(catch(C, _, true)), catch(C, _, true),
'$set_cp_by_default'(B), '$set_cp_by_default'(B),
'$call_with_default_policy'(run_cleaners_with_handling). run_cleaners_with_handling.
run_cleaners_with_handling :- run_cleaners_with_handling :-
'$restore_cut_policy'. '$restore_cut_policy'.
:- non_counted_backtracking run_cleaners_without_handling/1. :- non_counted_backtracking run_cleaners_without_handling/1.
run_cleaners_without_handling(Cp) :- run_cleaners_without_handling(Cp) :-
'$get_scc_cleaner'(C), '$get_scc_cleaner'(C),
'$get_level'(B), '$get_level'(B),
call(C), call(C),
'$set_cp_by_default'(B), '$set_cp_by_default'(B),
'$call_with_default_policy'(run_cleaners_without_handling(Cp)). run_cleaners_without_handling(Cp).
run_cleaners_without_handling(Cp) :- run_cleaners_without_handling(Cp) :-
'$set_cp_by_default'(Cp), '$set_cp_by_default'(Cp),
'$restore_cut_policy'. '$restore_cut_policy'.
@@ -120,6 +121,7 @@ run_cleaners_without_handling(Cp) :-
% call_with_inference_limit % call_with_inference_limit
:- non_counted_backtracking end_block/4. :- non_counted_backtracking end_block/4.
end_block(_, Bb, NBb, _L) :- end_block(_, Bb, NBb, _L) :-
'$clean_up_block'(NBb), '$clean_up_block'(NBb),
'$reset_block'(Bb). '$reset_block'(Bb).
@@ -129,13 +131,19 @@ end_block(B, _Bb, NBb, L) :-
'$fail'. '$fail'.
:- non_counted_backtracking handle_ile/3. :- non_counted_backtracking handle_ile/3.
handle_ile(B, inference_limit_exceeded(B), inference_limit_exceeded) :- !.
handle_ile(B, E, _) :- handle_ile(B, inference_limit_exceeded(B), inference_limit_exceeded) :-
!,
'$pop_ball_stack'.
handle_ile(B, _, _) :-
'$remove_call_policy_check'(B), '$remove_call_policy_check'(B),
'$call_with_default_policy'(throw(E)). '$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.
call_with_inference_limit(G, L, R) :- call_with_inference_limit(G, L, R) :-
( integer(L) -> ( integer(L) ->
( L < 0 -> ( L < 0 ->
@@ -148,7 +156,7 @@ call_with_inference_limit(G, L, R) :-
), ),
'$get_current_block'(Bb), '$get_current_block'(Bb),
'$get_b_value'(B), '$get_b_value'(B),
'$call_with_default_policy'(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) :-
@@ -161,22 +169,22 @@ 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'(B, L, Count0),
'$call'(G), '$call_with_inference_counting'(call(G)),
'$inference_level'(R, B), '$inference_level'(R, B),
'$remove_inference_counter'(B, Count1), '$remove_inference_counter'(B, Count1),
'$call_with_default_policy'(is(Diff, L - (Count1 - Count0))), Diff is L - (Count1 - Count0),
'$call_with_default_policy'(end_block(B, Bb, NBb, Diff)). end_block(B, Bb, NBb, Diff).
call_with_inference_limit(_, _, R, Bb, B) :- call_with_inference_limit(_, _, R, Bb, B) :-
'$reset_block'(Bb), '$reset_block'(Bb),
'$remove_inference_counter'(B, _), '$remove_inference_counter'(B, _),
( '$get_ball'(Ball), ( '$get_ball'(Ball),
'$push_ball_stack',
'$get_level'(Cp), '$get_level'(Cp),
'$set_cp_by_default'(Cp) '$set_cp_by_default'(Cp)
; '$remove_call_policy_check'(B), ; '$remove_call_policy_check'(B),
'$fail' '$fail'
), ),
'$erase_ball', handle_ile(B, Ball, R).
'$call_with_default_policy'(handle_ile(B, Ball, R)).
partial_string(String, L, L0) :- partial_string(String, L, L0) :-
( String == [] -> ( String == [] ->
@@ -203,33 +211,55 @@ partial_string_tail(String, Tail) :-
call_nth(Goal, N) :- call_nth(Goal, N) :-
can_be(integer, N), can_be(integer, N),
( integer(N), N =< 0, ( integer(N) ->
domain_error(positive_integer, N, call_nth/2) ( N < 0 ->
domain_error(not_less_than_zero, N, call_nth/2)
; N > 0
)
; true ; true
), ),
setup_call_cleanup(call_nth_nesting(ID), setup_call_cleanup(call_nth_nesting(C, ID),
( Goal, ( Goal,
retract(i_call_nth_nesting(ID,N0)), bb_get(ID, N0),
N1 is N0 + 1, N1 is N0 + 1,
asserta(i_call_nth_nesting(ID,N1)), bb_put(ID, N1),
( integer(N) -> ( integer(N) ->
N = N1, N = N1,
! !
; N = N1 ; N = N1
) )
), ),
( retract(i_call_nth_nesting(ID,_)), ( bb_get(i_call_nth_counter, C) ->
retract(i_call_nth_counter(ID)) C1 is C - 1,
bb_put(i_call_nth_counter, C1)
; true
)). )).
call_nth_nesting(ID) :- call_nth_nesting(C, ID) :-
( i_call_nth_counter(ID0) -> ( bb_get(i_call_nth_counter, C0) ->
ID is ID0 + 1 C is C0 + 1
; ID = 0 ; C = 0
), ),
asserta(i_call_nth_nesting(ID, 0)), number_chars(C, Cs),
asserta(i_call_nth_counter(ID)). atom_chars(Atom, Cs),
atom_concat(i_call_nth_nesting_, Atom, ID),
bb_put(ID, 0),
bb_put(i_call_nth_counter, C).
copy_term_nat(Source, Dest) :- copy_term_nat(Source, Dest) :-
'$copy_term_without_attr_vars'(Source, Dest). '$copy_term_without_attr_vars'(Source, Dest).
asserta(Module, (Head :- Body)) :-
!,
'$asserta'(Module, Head, Body).
asserta(Module, Fact) :-
'$asserta'(Module, Fact, true).
assertz(Module, (Head :- Body)) :-
!,
'$assertz'(Module, Head, Body).
assertz(Module, Fact) :-
'$assertz'(Module, Fact, true).

View File

@@ -1,7 +1,7 @@
:- module(lists, [member/2, select/3, append/2, append/3, foldl/4, foldl/5, :- module(lists, [member/2, select/3, append/2, append/3, foldl/4, foldl/5,
memberchk/2, reverse/2, length/2, maplist/2, memberchk/2, reverse/2, length/2, maplist/2,
maplist/3, maplist/4, maplist/5, maplist/6, maplist/3, maplist/4, maplist/5, maplist/6,
maplist/7, maplist/8, maplist/9, same_length/2, nth0/3, maplist/7, maplist/8, maplist/9, same_length/2, nth0/3, nth0/4, nth1/3, nth1/4,
sum_list/2, transpose/2, list_to_set/2, list_max/2, sum_list/2, transpose/2, list_to_set/2, list_max/2,
list_min/2, permutation/2]). list_min/2, permutation/2]).
@@ -50,13 +50,20 @@
:- meta_predicate foldl(3, ?, ?, ?). :- meta_predicate foldl(3, ?, ?, ?).
:- meta_predicate foldl(4, ?, ?, ?, ?). :- meta_predicate foldl(4, ?, ?, ?, ?).
:- use_module(library(error)).
:- meta_predicate(resource_error(+,:)).
resource_error(Resource, Context) :-
throw(error(resource_error(Resource), Context)).
length(Xs0, N) :- length(Xs0, N) :-
'$skip_max_list'(M, N, Xs0,Xs), '$skip_max_list'(M, N, Xs0,Xs),
!, !,
( Xs == [] -> N = M ( Xs == [] -> N = M
; nonvar(Xs) -> var(N), Xs = [_|_], throw(error(resource_error(finite_memory),length/2)) ; nonvar(Xs) -> var(N), Xs = [_|_], resource_error(finite_memory,length/2)
; nonvar(N) -> R is N-M, length_rundown(Xs, R) ; nonvar(N) -> R is N-M, length_rundown(Xs, R)
; N == Xs -> throw(error(resource_error(finite_memory),length/2)) ; N == Xs -> failingvarskip(Xs), resource_error(finite_memory,length/2)
; length_addendum(Xs, N, M) ; length_addendum(Xs, N, M)
). ).
length(_, N) :- length(_, N) :-
@@ -65,16 +72,29 @@ length(_, N) :-
length(_, N) :- length(_, N) :-
type_error(integer, N, length/2). type_error(integer, N, length/2).
length_rundown(Xs, 0) :- !, Xs = [].
length_rundown(Vs, N) :-
\+ \+ '$project_atts':copy_term(Vs,Vs,[]), % unconstrained
!,
'$det_length_rundown'(Vs, N).
length_rundown([_|Xs], N) :- % force unification
N1 is N-1,
length(Xs, N1). % maybe some new info on Xs
failingvarskip(Xs) :-
\+ \+ '$project_atts':copy_term(Xs,Xs,[]), % unconstrained
!.
failingvarskip([_|Xs0]) :- % force unification
'$skip_max_list'(_, _, Xs0,Xs),
( nonvar(Xs) -> Xs = [_|_]
; failingvarskip(Xs)
).
length_addendum([], N, N). length_addendum([], N, N).
length_addendum([_|Xs], N, M) :- length_addendum([_|Xs], N, M) :-
M1 is M + 1, M1 is M + 1,
length_addendum(Xs, N, M1). length_addendum(Xs, N, M1).
length_rundown(Xs, 0) :- !, Xs = [].
length_rundown([_|Xs], N) :-
N1 is N-1,
length_rundown(Xs, N1).
member(X, [X|_]). member(X, [X|_]).
member(X, [_|Xs]) :- member(X, Xs). member(X, [_|Xs]) :- member(X, Xs).
@@ -223,27 +243,82 @@ unify_same(E-V, Prev-Var, E-V) :-
). ).
nth0(N, Es, E) :- nth0(N, Es0, E) :-
can_be(integer, N), nonvar(N),
can_be(list, Es), '$skip_max_list'(Skip, N, Es0,Es1),
( integer(N) -> !,
nth0_index(N, Es, E) ( Skip == N
; nth0_search(N, Es, E) -> Es1 = [E|_]
; ( var(Es1) ; Es1 = [_|_] ) % a partial or infinite list
-> R is N-Skip,
skipn(R,Es1,Es2),
Es2 = [E|_]
). ).
nth0(N, Es0, E) :-
can_be(not_less_than_zero, N),
Es0 = [E0|Es1],
nth0_el(0,N, E0,E, Es1).
nth0_index(0, [E|_], E) :- !. skipn(N0, Es0,Es) :-
nth0_index(N, [_|Es], E) :- N0>0,
N > 0, !, % should not be necessary #1028
N1 is N - 1, N1 is N0-1,
nth0_index(N1, Es, E). Es0 = [_|Es1],
skipn(N1, Es1,Es).
skipn(0, Es,Es).
nth0_search(N, Es, E) :- nth0_el(N0,N, E0,E, Es0) :-
nth0_search(0, N, Es, E). Es0 == [],
!, % indexing
N0 = N,
E0 = E.
nth0_el(N,N, E,E, _).
nth0_el(N0,N, _,E, [E0|Es0]) :-
N1 is N0+1,
nth0_el(N1,N, E0,E, Es0).
nth0_search(N, N, [E|_], E). nth1(N, Es0, E) :-
nth0_search(N0, N, [_|Es], E) :- N \== 0,
N1 is N0 + 1, nth0(N, [_|Es0], E),
nth0_search(N1, N, Es, E). N \== 0.
skipn(N0, Es0,Es, Xs0,Xs) :-
N0>0,
!, % should not be necessary #1028
N1 is N0-1,
Es0 = [E|Es1],
Xs0 = [E|Xs1],
skipn(N1, Es1,Es, Xs1,Xs).
skipn(0, Es,Es, Xs,Xs).
nth0(N, Es0, E, Es) :-
integer(N),
N >= 0,
!,
skipn(N, Es0,Es1, Es,Es2),
Es1 = [E|Es2].
nth0(N, Es0, E, Es) :-
can_be(not_less_than_zero, N),
Es0 = [E0|Es1],
nth0_elx(0,N, E0,E, Es1, Es).
nth0_elx(N0,N, E0,E, Es0, Es) :-
Es0 == [],
!,
N0 = N,
E0 = E,
Es0 = Es.
nth0_elx(N,N, E,E, Es, Es).
nth0_elx(N0,N, E0,E, [E1|Es0], [E0|Es]) :-
N1 is N0+1,
nth0_elx(N1,N, E1,E, Es0, Es).
% p.p.8.5
nth1(N, Es0, E, Es) :-
N \== 0,
nth0(N, [_|Es0], E, [_|Es]),
N \== 0.
list_max([N|Ns], Max) :- list_max([N|Ns], Max) :-

View File

@@ -5,7 +5,7 @@
map_list_to_pairs/3]). map_list_to_pairs/3]).
:- meta_predicate map_list_to_pairs(0, ?, ?). :- meta_predicate map_list_to_pairs(2, ?, ?).
pairs_keys_values([], [], []). pairs_keys_values([], [], []).
pairs_keys_values([A-B|ABs], [A|As], [B|Bs]) :- pairs_keys_values([A-B|ABs], [A|As], [B|Bs]) :-

View File

@@ -4,9 +4,9 @@
Our goal is to encourage the use of definite clause grammars (DCGs) Our goal is to encourage the use of definite clause grammars (DCGs)
for describing strings. The predicates phrase_from_file/[2,3], for describing strings. The predicates phrase_from_file/[2,3],
phrase_to_file/2 and phrase_to_stream/2 let us apply DCGs transparently phrase_to_file/[2,3] and phrase_to_stream/2 let us apply DCGs
to files and streams, and therefore decouple side-effects from transparently to files and streams, and therefore decouple side-effects
declarative descriptions. from declarative descriptions.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
:- module(pio, [phrase_from_file/2, :- module(pio, [phrase_from_file/2,
@@ -26,6 +26,7 @@
:- 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_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, ?)).
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@@ -90,7 +91,7 @@ phrase_to_stream(GRBody, Stream) :-
must_be(chars, Cs), must_be(chars, Cs),
( stream_property(Stream, type(binary)) -> ( stream_property(Stream, type(binary)) ->
( '$first_non_octet'(Cs, N) -> ( '$first_non_octet'(Cs, N) ->
domain_error(byte_char, N, phrase_to_stream/2) domain_error(octet_character, N, phrase_to_stream/2)
; true ; true
) )
; true ; true

View File

@@ -30,13 +30,10 @@ non(false, true).
:- meta_predicate(tfilter(2, ?, ?)). :- meta_predicate(tfilter(2, ?, ?)).
tfilter(C_2, Es, Fs) :- tfilter(_, [], []).
i_tfilter(Es, C_2, Fs). tfilter(C_2, [E|Es], Fs0) :-
i_tfilter([], _, []).
i_tfilter([E|Es], C_2, Fs0) :-
if_(call(C_2, E), Fs0 = [E|Fs], Fs0 = Fs), if_(call(C_2, E), Fs0 = [E|Fs], Fs0 = Fs),
i_tfilter(Es, C_2, Fs). tfilter(C_2, Es, Fs).
:- meta_predicate(tpartition(2, ?, ?, ?)). :- meta_predicate(tpartition(2, ?, ?, ?)).

View File

@@ -1,6 +1,6 @@
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Predicates for parsing HTML and XML documents. Predicates for parsing HTML and XML documents.
Written June 2020 by Markus Triska (triska@metalevel.at) Written 2020-2022 by Markus Triska (triska@metalevel.at)
Part of Scryer Prolog. Part of Scryer Prolog.
Currently, two predicates are provided: Currently, two predicates are provided:
@@ -10,16 +10,18 @@
These predicates parse HTML and XML documents, respectively. These predicates parse HTML and XML documents, respectively.
Source must be a stream, specified as stream(S), or a file, Source must be one of:
specified as file(Name), where Name is a list of characters, or a
list of characters with the document contents. - a list of characters with the document contents
- stream(S), specifying a stream S from which to read the content
- file(Name), where Name is a list of characters specifying a file name.
Es is unified with the abstract syntax tree of the parsed document, Es is unified with the abstract syntax tree of the parsed document,
represented as a list of elements where each is of the form: represented as a list of elements where each is of the form:
* a list of characters, representing text * a list of characters, representing text
* element(Name, Attrs, Children) * element(Name, Attrs, Children)
- Name is the name of the tag - Name, an atom, is the name of the tag
- Attrs is a list of Key=Value pairs: - Attrs is a list of Key=Value pairs:
Key is an atom, and Value is a list of characters Key is an atom, and Value is a list of characters
- Children is a list of elements as specified here. - Children is a list of elements as specified here.
@@ -61,21 +63,32 @@
:- use_module(library(charsio)). :- use_module(library(charsio)).
load_html(Source, Es, Options) :- load_html(Source, Es, Options) :-
must_be_source(Source, load_html/3),
must_be(list, Options),
load_structure_(Source, Es, Options, html). load_structure_(Source, Es, Options, html).
load_xml(Source, Es, Options) :- load_xml(Source, Es, Options) :-
must_be_source(Source, load_xml/3),
must_be(list, Options),
load_structure_(Source, Es, Options, xml). load_structure_(Source, Es, Options, xml).
must_be_source(Source, Context) :-
( var(Source) -> instantiation_error(Context)
; is_sgml_source(Source) -> true
; domain_error(sgml_source, Source, Context)
).
is_sgml_source(file(Fs)) :- must_be(chars, Fs).
is_sgml_source(stream(_)).
is_sgml_source([]).
is_sgml_source([C|Cs]) :- must_be(chars, [C|Cs]).
load_structure_([], [], _, _). load_structure_([], [], _, _).
load_structure_([C|Cs], [E], Options, What) :- load_structure_([C|Cs], [E], Options, What) :-
load_(What, [C|Cs], E, Options). load_(What, [C|Cs], E, Options).
load_structure_(file(Fs), [E], Options, What) :- load_structure_(file(Fs), [E], Options, What) :-
must_be(list, Options), once(phrase_from_file(seq(Cs), Fs)),
must_be(list, Fs),
atom_chars(File, Fs),
once(phrase_from_file(seq(Cs), File)),
load_(What, Cs, E, Options). load_(What, Cs, E, Options).
load_structure_(stream(Stream), [E], Options, What) :- load_structure_(stream(Stream), [E], Options, What) :-
must_be(list, Options),
get_n_chars(Stream, _, Cs), get_n_chars(Stream, _, Cs),
load_(What, Cs, E, Options). load_(What, Cs, E, Options).

View File

@@ -27,7 +27,8 @@
:- module(si, [atom_si/1, :- module(si, [atom_si/1,
integer_si/1, integer_si/1,
atomic_si/1, atomic_si/1,
list_si/1]). list_si/1,
chars_si/1]).
:- use_module(library(lists)). :- use_module(library(lists)).
@@ -42,6 +43,16 @@ integer_si(I) :-
atomic_si(AC) :- atomic_si(AC) :-
functor(AC,_,0). functor(AC,_,0).
list_si(L) :- % list_si(L) :-
\+ \+ length(L, _), % \+ \+ length(L, _),
sort(L, _). % sort(L, _).
list_si(L0) :-
'$skip_max_list'(_,_, L0,L),
( nonvar(L) -> L = []
; throw(error(instantiation_error, list_si/1))
).
chars_si(Cs) :-
list_si(Cs),
'$is_partial_string'(Cs).

1379
src/lib/simplex.pl Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -67,7 +67,7 @@ table_and_status_for_variant(V,T,S) :-
tbd_table_status(T,S). tbd_table_status(T,S).
:- meta_predicate start_tabling(?, 0). :- meta_predicate start_tabling(?, :).
start_tabling(Wrapper,Worker) :- start_tabling(Wrapper,Worker) :-
put_new_trie_table_link, put_new_trie_table_link,

View File

@@ -119,7 +119,7 @@ report_time(ID) :-
time_state(ID, T0), time_state(ID, T0),
'$cpu_now'(T), '$cpu_now'(T),
Time is T - T0, Time is T - T0,
( bb_get('$first_answer', true) -> ( bb_get('$answer_count', 0) ->
Pre = " ", Post = "" Pre = " ", Post = ""
; Pre = "", Post = " " ; Pre = "", Post = " "
), ),

View File

@@ -26,22 +26,22 @@
:- use_module(library(http/http_open)). :- use_module(library(http/http_open)).
:- use_module(library(sgml)). :- use_module(library(sgml)).
:- use_module(library(lists)).
:- use_module(library(xpath)). :- use_module(library(xpath)).
:- use_module(library(dcgs)).
link_to_pl_file(File) :- link_to_pl_file(File) :-
http_open("https://github.com/mthom/scryer-prolog", S, []), http_open("https://github.com/mthom/scryer-prolog", S, []),
load_html(stream(S), DOM, []), load_html(stream(S), DOM, []),
xpath(DOM, //a(@href), File), xpath(DOM, //a(@href), File),
append(_, ".pl", File). phrase((...,".pl"), File).
Yielding: Yielding:
?- link_to_pl_file(File). ?- link_to_pl_file(File).
%@ File = "/mthom/scryer-prolog/blob/master/src/lib/tabling.pl" %@ File = "/mthom/scryer-prolog/blob/master/src/lib/dcgs.pl"
%@ ; File = "/mthom/scryer-prolog/blob/master/src/lib/dif.pl" %@ ; File = "/mthom/scryer-prolog/blob/master/src/lib/pio.pl"
%@ ; File = "/mthom/scryer-prolog/blob/master/src/lib/freeze.pl" %@ ; File = "/mthom/scryer-prolog/blob/master/src/lib/tabling.pl"
%@ ; ... %@ ; ... .
Parts of the original functionality may not yet work. Please Parts of the original functionality may not yet work. Please
consider such parts opportunities for improvements, and file consider such parts opportunities for improvements, and file

File diff suppressed because it is too large Load Diff

16
src/machine/args.rs Normal file
View File

@@ -0,0 +1,16 @@
use std::collections::BTreeSet;
use std::env;
#[derive(Debug)]
pub struct MachineArgs {
pub add_history: bool,
}
impl MachineArgs {
pub fn new() -> Self {
let args: BTreeSet<String> = env::args().collect();
Self {
add_history: !args.contains("--no-add-history"),
}
}
}

View File

@@ -82,16 +82,6 @@ fn numerical_type_error(
}) })
} }
pub(crate) fn sign(n: Number) -> Number {
if n.is_positive() {
Number::Fixnum(Fixnum::build_with(1))
} else if n.is_negative() {
Number::Fixnum(Fixnum::build_with(-1))
} else {
Number::Fixnum(Fixnum::build_with(0))
}
}
fn isize_gcd(n1: isize, n2: isize) -> Option<isize> { fn isize_gcd(n1: isize, n2: isize) -> Option<isize> {
if n1 == 0 { if n1 == 0 {
return n2.checked_abs().map(|n| n as isize); return n2.checked_abs().map(|n| n as isize);
@@ -291,8 +281,8 @@ pub(crate) fn div(n1: Number, n2: Number) -> Result<Number, MachineStubGen> {
} }
pub(crate) fn float_pow(n1: Number, n2: Number) -> Result<Number, MachineStubGen> { pub(crate) fn float_pow(n1: Number, n2: Number) -> Result<Number, MachineStubGen> {
let f1 = result_f(&n1, rnd_f); let f1 = result_f(&n1);
let f2 = result_f(&n2, rnd_f); let f2 = result_f(&n2);
let stub_gen = || { let stub_gen = || {
let pow_atom = atom!("**"); let pow_atom = atom!("**");
@@ -302,7 +292,7 @@ pub(crate) fn float_pow(n1: Number, n2: Number) -> Result<Number, MachineStubGen
let f1 = try_numeric_result!(f1, stub_gen)?; let f1 = try_numeric_result!(f1, stub_gen)?;
let f2 = try_numeric_result!(f2, stub_gen)?; let f2 = try_numeric_result!(f2, stub_gen)?;
let result = result_f(&Number::Float(OrderedFloat(f1.powf(f2))), rnd_f); let result = result_f(&Number::Float(OrderedFloat(f1.powf(f2))));
Ok(Number::Float(OrderedFloat(try_numeric_result!( Ok(Number::Float(OrderedFloat(try_numeric_result!(
result, stub_gen result, stub_gen
@@ -400,7 +390,6 @@ pub(crate) fn int_pow(n1: Number, n2: Number, arena: &mut Arena) -> Result<Numbe
pub(crate) fn pow(n1: Number, n2: Number, culprit: Atom) -> Result<Number, MachineStubGen> { pub(crate) fn pow(n1: Number, n2: Number, culprit: Atom) -> Result<Number, MachineStubGen> {
if n2.is_negative() && n1.is_zero() { if n2.is_negative() && n1.is_zero() {
let stub_gen = move || functor_stub(culprit, 2); let stub_gen = move || functor_stub(culprit, 2);
return Err(undefined_eval_error(stub_gen)); return Err(undefined_eval_error(stub_gen));
} }
@@ -414,7 +403,7 @@ pub(crate) fn float(n: Number) -> Result<f64, MachineStubGen> {
functor_stub(is_atom, 2) functor_stub(is_atom, 2)
}; };
try_numeric_result!(result_f(&n, rnd_f), stub_gen) try_numeric_result!(result_f(&n), stub_gen)
} }
#[inline] #[inline]
@@ -430,8 +419,8 @@ where
functor_stub(is_atom, 2) functor_stub(is_atom, 2)
}; };
let f1 = try_numeric_result!(result_f(&n1, rnd_f), stub_gen)?; let f1 = try_numeric_result!(result_f(&n1), stub_gen)?;
let f1 = result_f(&Number::Float(OrderedFloat(f(f1))), rnd_f); let f1 = result_f(&Number::Float(OrderedFloat(f(f1))));
try_numeric_result!(f1, stub_gen) try_numeric_result!(f1, stub_gen)
} }
@@ -472,8 +461,8 @@ pub(crate) fn max(n1: Number, n2: Number) -> Result<Number, MachineStubGen> {
functor_stub(max_atom, 2) functor_stub(max_atom, 2)
}; };
let f1 = try_numeric_result!(result_f(&n1, rnd_f), stub_gen)?; let f1 = try_numeric_result!(result_f(&n1), stub_gen)?;
let f2 = try_numeric_result!(result_f(&n2, rnd_f), stub_gen)?; let f2 = try_numeric_result!(result_f(&n2), stub_gen)?;
Ok(Number::Float(cmp::max(OrderedFloat(f1), OrderedFloat(f2)))) Ok(Number::Float(cmp::max(OrderedFloat(f1), OrderedFloat(f2))))
} }
@@ -516,8 +505,8 @@ pub(crate) fn min(n1: Number, n2: Number) -> Result<Number, MachineStubGen> {
functor_stub(min_atom, 2) functor_stub(min_atom, 2)
}; };
let f1 = try_numeric_result!(result_f(&n1, rnd_f), stub_gen)?; let f1 = try_numeric_result!(result_f(&n1), stub_gen)?;
let f2 = try_numeric_result!(result_f(&n2, rnd_f), stub_gen)?; let f2 = try_numeric_result!(result_f(&n2), stub_gen)?;
Ok(Number::Float(cmp::min(OrderedFloat(f1), OrderedFloat(f2)))) Ok(Number::Float(cmp::min(OrderedFloat(f1), OrderedFloat(f2))))
} }
@@ -803,7 +792,8 @@ pub(crate) fn xor(n1: Number, n2: Number, arena: &mut Arena) -> Result<Number, M
(Number::Integer(_), n2) | (Number::Fixnum(_), n2) => { (Number::Integer(_), n2) | (Number::Fixnum(_), n2) => {
Err(numerical_type_error(ValidType::Integer, n2, stub_gen)) Err(numerical_type_error(ValidType::Integer, n2, stub_gen))
} }
_ => Err(numerical_type_error(ValidType::Integer, n2, stub_gen)), (n1, Number::Integer(_)) => Err(numerical_type_error(ValidType::Integer, n1, stub_gen)),
_ => Err(numerical_type_error(ValidType::Integer, n1, stub_gen)),
} }
} }
@@ -1108,35 +1098,43 @@ impl MachineState {
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 = stackless_post_order_iter(&mut self.heap, value); let mut iter = stackful_post_order_iter(&mut self.heap, value);
while let Some(value) = iter.next() { while let Some(value) = iter.next() {
if value.is_forwarded() { if value.get_forwarding_bit() {
std::mem::drop(iter);
let (name, arity) = read_heap_cell!(value, let (name, arity) = read_heap_cell!(value,
(HeapCellValueTag::Atom, (name, arity)) => { (HeapCellValueTag::Atom, (name, arity)) => {
(name, arity) (name, arity)
} }
(HeapCellValueTag::Lis | HeapCellValueTag::PStr) => { (HeapCellValueTag::Str, s) => {
cell_as_atom_cell!(self.heap[s]).get_name_and_arity()
}
(HeapCellValueTag::Lis | HeapCellValueTag::PStr | HeapCellValueTag::PStrOffset |
HeapCellValueTag::PStrLoc) => {
(atom!("."), 2) (atom!("."), 2)
} }
(HeapCellValueTag::AttrVar | HeapCellValueTag::Var) => {
let err = self.instantiation_error();
return Err(self.error_form(err, stub_gen()));
}
_ => { _ => {
unreachable!() unreachable!()
} }
); );
std::mem::drop(iter);
let evaluable_error = self.evaluable_error(name, arity); let evaluable_error = self.evaluable_error(name, arity);
let stub = stub_gen(); return Err(self.error_form(evaluable_error, stub_gen()));
return Err(self.error_form(evaluable_error, stub));
} }
let value = unmark_cell_bits!(value);
read_heap_cell!(value, read_heap_cell!(value,
(HeapCellValueTag::Atom, (name, arity)) => { (HeapCellValueTag::Atom, (name, arity)) => {
if arity == 2 { if arity == 2 {
let a1 = self.interms.pop().unwrap();
let a2 = self.interms.pop().unwrap(); let a2 = self.interms.pop().unwrap();
let a1 = self.interms.pop().unwrap();
match name { match name {
atom!("+") => self.interms.push(drop_iter_on_err!( atom!("+") => self.interms.push(drop_iter_on_err!(
@@ -1184,7 +1182,7 @@ impl MachineState {
let result = arena_alloc!( let result = arena_alloc!(
drop_iter_on_err!(self, iter, rdiv(r1, r2)), drop_iter_on_err!(self, iter, rdiv(r1, r2)),
self.arena &mut self.arena
); );
self.interms.push(Number::Rational(result)); self.interms.push(Number::Rational(result));
@@ -1278,7 +1276,7 @@ impl MachineState {
atom!("\\") => self.interms.push( atom!("\\") => self.interms.push(
drop_iter_on_err!(self, iter, bitwise_complement(a1, &mut self.arena)) drop_iter_on_err!(self, iter, bitwise_complement(a1, &mut self.arena))
), ),
atom!("sign") => self.interms.push(sign(a1)), atom!("sign") => self.interms.push(a1.sign()),
_ => { _ => {
let evaluable_stub = functor_stub(name, 1); let evaluable_stub = functor_stub(name, 1);
std::mem::drop(iter); std::mem::drop(iter);
@@ -1324,7 +1322,7 @@ impl MachineState {
self.interms.push(Number::Fixnum(n)); self.interms.push(Number::Fixnum(n));
} }
(HeapCellValueTag::F64, fl) => { (HeapCellValueTag::F64, fl) => {
self.interms.push(Number::Float(**fl)); self.interms.push(Number::Float(*fl));
} }
(HeapCellValueTag::Cons, ptr) => { (HeapCellValueTag::Cons, ptr) => {
match_untyped_arena_ptr!(ptr, match_untyped_arena_ptr!(ptr,
@@ -1334,9 +1332,6 @@ impl MachineState {
(ArenaHeaderTag::Rational, r) => { (ArenaHeaderTag::Rational, r) => {
self.interms.push(Number::Rational(r)); self.interms.push(Number::Rational(r));
} }
(ArenaHeaderTag::F64, fl) => {
self.interms.push(Number::Float(*fl));
}
_ => { _ => {
std::mem::drop(iter); std::mem::drop(iter);

View File

@@ -28,11 +28,13 @@ call_verify_attributes([Attr|Attrs], Var, Value, ListOfGoalLists) :-
sort(Modules0, Modules), sort(Modules0, Modules),
verify_attrs(Modules, Var, Value, ListOfGoalLists). verify_attrs(Modules, Var, Value, ListOfGoalLists).
error_handler(M, evaluation_error((M:verify_attributes)/3), []).
% error_handler(_, existence_error(procedure, verify_attributes/3), []).
verify_attrs([Module|Modules], Var, Value, [Module-Goals|ListOfGoalLists]) :- verify_attrs([Module|Modules], Var, Value, [Module-Goals|ListOfGoalLists]) :-
catch(Module:verify_attributes(Var, Value, Goals), catch(Module:verify_attributes(Var, Value, Goals),
error(evaluation_error((Module:verify_attributes)/3), verify_attributes/3), error(E, verify_attributes/3),
Goals = []), error_handler(Module, E, Goals)),
verify_attrs(Modules, Var, Value, ListOfGoalLists). verify_attrs(Modules, Var, Value, ListOfGoalLists).
verify_attrs([], _, _, []). verify_attrs([], _, _, []).

View File

@@ -1,6 +1,5 @@
use crate::atom_table::*; use crate::atom_table::*;
use crate::codegen::*; use crate::codegen::*;
use crate::debray_allocator::*;
use crate::forms::*; use crate::forms::*;
use crate::indexing::{merge_clause_index, remove_index}; use crate::indexing::{merge_clause_index, remove_index};
use crate::instructions::*; use crate::instructions::*;
@@ -12,8 +11,6 @@ use crate::machine::term_stream::*;
use crate::machine::*; use crate::machine::*;
use crate::parser::ast::*; use crate::parser::ast::*;
use slice_deque::{sdeq, SliceDeque};
use std::cell::Cell; use std::cell::Cell;
use std::collections::VecDeque; use std::collections::VecDeque;
use std::mem; use std::mem;
@@ -49,13 +46,13 @@ pub(super) fn bootstrapping_compile(
// throw errors if declaration or query found. // throw errors if declaration or query found.
pub(super) fn compile_relation( pub(super) fn compile_relation(
cg: &mut CodeGenerator<DebrayAllocator>, cg: &mut CodeGenerator,
tl: &TopLevel, tl: &TopLevel,
) -> Result<Code, CompilationError> { ) -> Result<Code, CompilationError> {
match tl { match tl {
&TopLevel::Query(_) => Err(CompilationError::ExpectedRel), &TopLevel::Query(_) => Err(CompilationError::ExpectedRel),
&TopLevel::Predicate(ref clauses) => cg.compile_predicate(&clauses), &TopLevel::Predicate(ref clauses) => cg.compile_predicate(&clauses),
&TopLevel::Fact(ref fact, ..) => Ok(cg.compile_fact(fact)), &TopLevel::Fact(ref fact, ..) => cg.compile_fact(fact),
&TopLevel::Rule(ref rule, ..) => cg.compile_rule(rule), &TopLevel::Rule(ref rule, ..) => cg.compile_rule(rule),
} }
} }
@@ -89,7 +86,7 @@ pub(super) fn compile_appendix(
non_counted_bt, non_counted_bt,
}; };
let mut cg = CodeGenerator::<DebrayAllocator>::new(atom_tbl, settings); let mut cg = CodeGenerator::new(atom_tbl, settings);
let tl = queue.pop_front().unwrap(); let tl = queue.pop_front().unwrap();
let decl_code = compile_relation(&mut cg, &tl)?; let decl_code = compile_relation(&mut cg, &tl)?;
@@ -409,7 +406,7 @@ fn merge_indexed_subsequences(
*o = 0; *o = 0;
return Some(IndexPtr::Index(outer_threaded_choice_instr_loc + 1)); return Some(IndexPtr::index(outer_threaded_choice_instr_loc + 1));
} }
_ => {} _ => {}
}, },
@@ -425,8 +422,8 @@ fn delete_from_skeleton(
target_pos: usize, target_pos: usize,
retraction_info: &mut RetractionInfo, retraction_info: &mut RetractionInfo,
) -> usize { ) -> usize {
let clause_index_info = skeleton.clauses.remove(target_pos); let clause_index_info = skeleton.clauses.remove(target_pos).unwrap();
let clause_clause_loc = skeleton.core.clause_clause_locs.remove(target_pos); let clause_clause_loc = skeleton.core.clause_clause_locs.remove(target_pos).unwrap();
if target_pos < skeleton.core.clause_assert_margin { if target_pos < skeleton.core.clause_assert_margin {
skeleton.core.clause_assert_margin -= 1; skeleton.core.clause_assert_margin -= 1;
@@ -788,7 +785,7 @@ fn remove_non_leading_clause(
*o = 0; *o = 0;
Some(IndexPtr::Index(preceding_choice_instr_loc + 1)) Some(IndexPtr::index(preceding_choice_instr_loc + 1))
} }
_ => { _ => {
unreachable!(); unreachable!();
@@ -823,7 +820,7 @@ fn finalize_retract(
retraction_info, retraction_info,
&compilation_target, &compilation_target,
key, key,
&code_index, code_index,
index_ptr, index_ptr,
); );
} }
@@ -852,9 +849,9 @@ fn remove_leading_unindexed_clause(
retraction_info, retraction_info,
); );
Some(IndexPtr::Index(index_ptr)) Some(IndexPtr::index(index_ptr))
} else { } else {
Some(IndexPtr::DynamicUndefined) Some(IndexPtr::dynamic_undefined())
} }
} }
_ => { _ => {
@@ -887,7 +884,7 @@ fn prepend_compiled_clause(
global_clock_tick: usize, global_clock_tick: usize,
) -> IndexPtr { ) -> IndexPtr {
let clause_loc = code.len(); let clause_loc = code.len();
let mut prepend_queue = sdeq![]; let mut prepend_queue = VecDeque::new();
let target_arg_num = skeleton.clauses[0].opt_arg_index_key.arg_num(); let target_arg_num = skeleton.clauses[0].opt_arg_index_key.arg_num();
let head_arg_num = skeleton.clauses[1].opt_arg_index_key.arg_num(); let head_arg_num = skeleton.clauses[1].opt_arg_index_key.arg_num();
@@ -995,7 +992,7 @@ fn prepend_compiled_clause(
merge_clause_index( merge_clause_index(
target_indexing_line, target_indexing_line,
&mut skeleton.clauses, skeleton.clauses.make_contiguous(),
&skeleton.core.retracted_dynamic_clauses, &skeleton.core.retracted_dynamic_clauses,
clause_loc + 2, // == skeleton.clauses[0].clause_start clause_loc + 2, // == skeleton.clauses[0].clause_start
AppendOrPrepend::Prepend, AppendOrPrepend::Prepend,
@@ -1134,9 +1131,9 @@ fn prepend_compiled_clause(
}; };
if skeleton.core.is_dynamic { if skeleton.core.is_dynamic {
IndexPtr::DynamicIndex(clause_loc) IndexPtr::dynamic_index(clause_loc)
} else { } else {
IndexPtr::Index(clause_loc) IndexPtr::index(clause_loc)
} }
} }
@@ -1189,7 +1186,7 @@ fn append_compiled_clause(
merge_clause_index( merge_clause_index(
target_indexing_line, target_indexing_line,
&mut skeleton.clauses[lower_bound..], &mut skeleton.clauses.make_contiguous()[lower_bound..],
&skeleton.core.retracted_dynamic_clauses, &skeleton.core.retracted_dynamic_clauses,
clause_loc, clause_loc,
AppendOrPrepend::Append, AppendOrPrepend::Append,
@@ -1212,7 +1209,11 @@ fn append_compiled_clause(
); );
if lower_bound == 0 && !skeleton.core.is_dynamic { if lower_bound == 0 && !skeleton.core.is_dynamic {
code_ptr_opt = Some(target_pos_clause_start); code_ptr_opt = Some(if index_loc < target_pos_clause_start {
index_loc
} else {
target_pos_clause_start
});
} }
} }
@@ -1267,9 +1268,9 @@ fn append_compiled_clause(
code_ptr_opt.map(|p| { code_ptr_opt.map(|p| {
if skeleton.core.is_dynamic { if skeleton.core.is_dynamic {
IndexPtr::DynamicIndex(p) IndexPtr::dynamic_index(p)
} else { } else {
IndexPtr::Index(p) IndexPtr::index(p)
} }
}) })
} }
@@ -1305,8 +1306,8 @@ fn print_overwrite_warning(
} }
} }
match code_ptr { match code_ptr.tag() {
IndexPtr::DynamicUndefined | IndexPtr::Undefined => return, IndexPtrTag::DynamicUndefined | IndexPtrTag::Undefined => return,
_ if is_dynamic => return, _ if is_dynamic => return,
_ => {} _ => {}
} }
@@ -1338,12 +1339,12 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
term: Term, term: Term,
settings: CodeGenSettings, settings: CodeGenSettings,
) -> Result<StandaloneCompileResult, SessionError> { ) -> Result<StandaloneCompileResult, SessionError> {
let mut preprocessor = Preprocessor::new(); let mut preprocessor = Preprocessor::new(settings);
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::<DebrayAllocator>::new( let mut cg = CodeGenerator::new(
&mut LS::machine_st(&mut self.payload).atom_tbl, &mut LS::machine_st(&mut self.payload).atom_tbl,
settings, settings,
); );
@@ -1378,7 +1379,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
let mut code_ptr = code_len; let mut code_ptr = code_len;
let mut clauses = vec![]; let mut clauses = vec![];
let mut preprocessor = Preprocessor::new(); let mut preprocessor = Preprocessor::new(settings);
for term in predicates.predicates.drain(0..) { for term in predicates.predicates.drain(0..) {
clauses.push(self.try_term_to_tl(term, &mut preprocessor)?); clauses.push(self.try_term_to_tl(term, &mut preprocessor)?);
@@ -1386,7 +1387,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
let queue = preprocessor.parse_queue(self)?; let queue = preprocessor.parse_queue(self)?;
let mut cg = CodeGenerator::<DebrayAllocator>::new( let mut cg = CodeGenerator::new(
&mut LS::machine_st(&mut self.payload).atom_tbl, &mut LS::machine_st(&mut self.payload).atom_tbl,
settings, settings,
); );
@@ -1402,7 +1403,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
)?; )?;
if settings.is_extensible { if settings.is_extensible {
let mut clause_clause_locs = sdeq![]; let mut clause_clause_locs = VecDeque::new();
for clause_index_info in cg.skeleton.clauses.iter_mut() { for clause_index_info in cg.skeleton.clauses.iter_mut() {
clause_index_info.clause_start += code_len; clause_index_info.clause_start += code_len;
@@ -1430,7 +1431,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
skeleton skeleton
.core .core
.clause_clause_locs .clause_clause_locs
.extend_from_slice(&clause_clause_locs[0..]); .extend(&clause_clause_locs.make_contiguous()[0..]);
self.payload.retraction_info self.payload.retraction_info
.push_record(RetractionRecord::SkeletonClauseTruncateBack( .push_record(RetractionRecord::SkeletonClauseTruncateBack(
@@ -1443,7 +1444,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
cg.skeleton cg.skeleton
.core .core
.clause_clause_locs .clause_clause_locs
.extend_from_slice(&clause_clause_locs[0..]); .extend(&clause_clause_locs.make_contiguous()[0..]);
let skeleton = cg.skeleton; let skeleton = cg.skeleton;
@@ -1470,16 +1471,16 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
); );
let index_ptr = if settings.is_dynamic() { let index_ptr = if settings.is_dynamic() {
IndexPtr::DynamicIndex(code_ptr) IndexPtr::dynamic_index(code_ptr)
} else { } else {
IndexPtr::Index(code_ptr) IndexPtr::index(code_ptr)
}; };
set_code_index( set_code_index(
&mut self.payload.retraction_info, &mut self.payload.retraction_info,
&predicates.compilation_target, &predicates.compilation_target,
key, key,
&code_index, code_index,
index_ptr, index_ptr,
); );
@@ -1491,7 +1492,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
&mut self, &mut self,
compilation_target: &CompilationTarget, compilation_target: &CompilationTarget,
key: &PredicateKey, key: &PredicateKey,
clause_clause_locs: SliceDeque<usize>, mut clause_clause_locs: VecDeque<usize>,
) { ) {
let listing_src_file_name = self.listing_src_file_name(); let listing_src_file_name = self.listing_src_file_name();
@@ -1515,7 +1516,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
skeleton skeleton
.clause_clause_locs .clause_clause_locs
.extend_from_slice(&clause_clause_locs[0..]); .extend(&clause_clause_locs.make_contiguous()[0..]);
} }
None => { None => {
let mut skeleton = LocalPredicateSkeleton::new(); let mut skeleton = LocalPredicateSkeleton::new();
@@ -1703,7 +1704,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
&mut self.payload.retraction_info, &mut self.payload.retraction_info,
&compilation_target, &compilation_target,
key, key,
&code_index, code_index,
new_code_ptr, new_code_ptr,
); );
} }
@@ -1744,7 +1745,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
&mut self.payload.retraction_info, &mut self.payload.retraction_info,
&compilation_target, &compilation_target,
key, key,
&code_index, code_index,
new_code_ptr, new_code_ptr,
); );
@@ -1869,7 +1870,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
skeleton.clauses[target_pos].clause_start; skeleton.clauses[target_pos].clause_start;
let index_ptr_opt = if target_pos == 0 { let index_ptr_opt = if target_pos == 0 {
Some(IndexPtr::Index(clause_loc)) Some(IndexPtr::index(clause_loc))
} else { } else {
None None
}; };
@@ -1968,7 +1969,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
code, code,
later_indexing_loc, later_indexing_loc,
0..target_pos - lower_bound, 0..target_pos - lower_bound,
&mut skeleton.clauses[lower_bound..], &mut skeleton.clauses.make_contiguous()[lower_bound..],
&skeleton.core.retracted_dynamic_clauses, &skeleton.core.retracted_dynamic_clauses,
&mut self.payload.retraction_info, &mut self.payload.retraction_info,
); );
@@ -1993,7 +1994,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
code, code,
target_indexing_loc, target_indexing_loc,
target_pos + 1 - lower_bound..skeleton.clauses.len() - lower_bound, target_pos + 1 - lower_bound..skeleton.clauses.len() - lower_bound,
&mut skeleton.clauses[lower_bound..], &mut skeleton.clauses.make_contiguous()[lower_bound..],
&skeleton.core.retracted_dynamic_clauses, &skeleton.core.retracted_dynamic_clauses,
&mut self.payload.retraction_info, &mut self.payload.retraction_info,
); );
@@ -2192,15 +2193,17 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
{ {
Some(skeleton) if append_or_prepend.is_append() => { Some(skeleton) if append_or_prepend.is_append() => {
let tail_num = skeleton.core.clause_clause_locs.len() - num_clause_predicates; let tail_num = skeleton.core.clause_clause_locs.len() - num_clause_predicates;
skeleton.core.clause_clause_locs[tail_num..] skeleton.core.clause_clause_locs.make_contiguous()[tail_num..]
.iter() .iter()
.cloned() .cloned()
.collect() .collect()
} }
Some(skeleton) => skeleton.core.clause_clause_locs[0..num_clause_predicates] Some(skeleton) => {
skeleton.core.clause_clause_locs.make_contiguous()[0..num_clause_predicates]
.iter() .iter()
.cloned() .cloned()
.collect(), .collect()
}
None => { None => {
unreachable!() unreachable!()
} }
@@ -2381,13 +2384,15 @@ 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).or_insert(code_index); let code_index = module.code_dir.entry(key)
.or_insert(code_index)
.clone();
set_code_index( set_code_index(
&mut self.payload.retraction_info, &mut self.payload.retraction_info,
&CompilationTarget::Module(filename), &CompilationTarget::Module(filename),
key, key,
&code_index, code_index,
index_ptr, index_ptr,
); );
} }
@@ -2415,3 +2420,54 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
Ok(()) Ok(())
} }
} }
// standalone functions for compiling auxiliary goals used by expand_goal.
impl Machine {
pub(crate) fn get_or_insert_qualified_code_index(
&mut self,
module_name: HeapCellValue,
key: PredicateKey,
) -> CodeIndex {
let mut loader: Loader<'_, InlineLoadState<'_>> = Loader::new(
self,
InlineTermStream {},
);
let module_name = if module_name.get_tag() == HeapCellValueTag::Atom {
cell_as_atom!(module_name)
} else {
atom!("user")
};
loader.get_or_insert_qualified_code_index(module_name, key)
}
pub(crate) fn compile_standalone_clause(
&mut self,
term_loc: RegType,
vars: &[Term],
) -> Result<(), SessionError> {
let mut compile = || {
let mut loader: Loader<'_, InlineLoadState<'_>> = Loader::new(
self,
InlineTermStream {},
);
let term = loader.read_term_from_heap(term_loc)?;
let clause = build_rule_body(vars, term);
let settings = CodeGenSettings {
global_clock_tick: None,
is_extensible: false,
non_counted_bt: true,
};
loader.compile_standalone_clause(clause, settings)
};
let StandaloneCompileResult { clause_code, .. } = compile()?;
self.code.extend(clause_code.into_iter());
Ok(())
}
}

View File

@@ -1,4 +1,5 @@
use crate::atom_table::*; use crate::atom_table::*;
use crate::machine::get_structure_index;
use crate::machine::stack::*; use crate::machine::stack::*;
use crate::types::*; use crate::types::*;
@@ -248,6 +249,14 @@ impl<T: CopierTarget> CopyTermState<T> {
let hcv = self.target[addr + 1 + i]; let hcv = self.target[addr + 1 + i];
self.target.push(hcv); self.target.push(hcv);
} }
let index_cell = self.target[addr + 1 + arity];
if get_structure_index(index_cell).is_some() {
// copy the index pointer trailing this
// inlined or expanded goal.
self.target.push(index_cell);
}
} }
(HeapCellValueTag::Str, h) => { (HeapCellValueTag::Str, h) => {
*self.value_at_scan() = str_loc_as_cell!(h); *self.value_at_scan() = str_loc_as_cell!(h);

View File

@@ -57,19 +57,28 @@ impl MachineState {
let a2 = self.registers[2]; let a2 = self.registers[2];
let a3 = self.registers[3]; let a3 = self.registers[3];
let check_atom = |machine_st: &mut MachineState, name: Atom, arity: usize| -> Result<(), MachineStub> {
match name {
atom!(">") | atom!("<") | atom!("=") if arity == 0 => {
Ok(())
}
_ => {
let err = machine_st.domain_error(DomainErrorType::Order, a1);
Err(machine_st.error_form(err, stub_gen()))
}
}
};
read_heap_cell!(a1, read_heap_cell!(a1,
(HeapCellValueTag::Atom, (name, arity)) => {
debug_assert_eq!(arity, 0);
check_atom(self, name, arity)?;
}
(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();
match name { check_atom(self, name, arity)?;
atom!(">") | atom!("<") | atom!("=") if arity == 2 => {
}
_ => {
let err = self.domain_error(DomainErrorType::Order, a1);
return Err(self.error_form(err, stub_gen()));
}
}
} }
(HeapCellValueTag::AttrVar | HeapCellValueTag::Var | HeapCellValueTag::StackVar) => { (HeapCellValueTag::AttrVar | HeapCellValueTag::Var | HeapCellValueTag::StackVar) => {
} }
@@ -164,8 +173,7 @@ impl MachineState {
match self.get_number(&at)? { match self.get_number(&at)? {
Number::Fixnum(n) => self.unify_fixnum(n, n1), Number::Fixnum(n) => self.unify_fixnum(n, n1),
Number::Float(n) => { Number::Float(n) => {
// TODO: argghh.. allocate floats to their own area. let n = float_alloc!(n.into_inner(), self.arena);
let n = arena_alloc!(n, &mut self.arena);
self.unify_f64(n, n1) self.unify_f64(n, n1)
} }
Number::Integer(n) => self.unify_big_int(n, n1), Number::Integer(n) => self.unify_big_int(n, n1),
@@ -190,7 +198,7 @@ impl Machine {
let value = self.machine_st.registers[2]; let value = self.machine_st.registers[2];
unify_fn!(&mut self.machine_st, value, heap_loc_as_cell!(offset.heap_loc)); unify_fn!(&mut self.machine_st, value, heap_loc_as_cell!(offset.heap_loc));
} }
Err(ParserError::UnexpectedEOF) => { Err(CompilationError::ParserError(ParserError::UnexpectedEOF)) => {
let value = self.machine_st.registers[2]; let value = self.machine_st.registers[2];
self.machine_st.unify_atom(atom!("end_of_file"), value); self.machine_st.unify_atom(atom!("end_of_file"), value);
} }
@@ -362,13 +370,19 @@ impl Machine {
debug_assert!(arity == 0); debug_assert!(arity == 0);
c c
} }
(HeapCellValueTag::Str) => { (HeapCellValueTag::Str, st) => {
s let (name, arity) = cell_as_atom_cell!(self.machine_st.heap[st])
.get_name_and_arity();
match (name, arity) {
(atom!("."), 2) => l,
(_, 0) => c,
_ => s,
}
} }
(HeapCellValueTag::Cons, ptr) => { (HeapCellValueTag::Cons, ptr) => {
match ptr.get_tag() { match ptr.get_tag() {
ArenaHeaderTag::Rational | ArenaHeaderTag::Integer | ArenaHeaderTag::Rational | ArenaHeaderTag::Integer => {
ArenaHeaderTag::F64 => {
c c
} }
_ => { _ => {
@@ -418,20 +432,20 @@ impl Machine {
Literal::Fixnum(n) Literal::Fixnum(n)
} }
(HeapCellValueTag::F64, f) => { (HeapCellValueTag::F64, f) => {
Literal::Float(f) Literal::Float(f.as_offset())
} }
(HeapCellValueTag::Atom, (atom, arity)) => { (HeapCellValueTag::Atom, (atom, arity)) => {
debug_assert_eq!(arity, 0); debug_assert_eq!(arity, 0);
Literal::Atom(atom) Literal::Atom(atom)
} }
(HeapCellValueTag::Str, s) => {
Literal::Atom(cell_as_atom_cell!(self.machine_st.heap[s]).get_name())
}
(HeapCellValueTag::Cons, cons_ptr) => { (HeapCellValueTag::Cons, cons_ptr) => {
match_untyped_arena_ptr!(cons_ptr, match_untyped_arena_ptr!(cons_ptr,
(ArenaHeaderTag::Rational, r) => { (ArenaHeaderTag::Rational, r) => {
Literal::Rational(r) Literal::Rational(r)
} }
(ArenaHeaderTag::F64, f) => {
Literal::Float(F64Ptr(f))
}
(ArenaHeaderTag::Integer, n) => { (ArenaHeaderTag::Integer, n) => {
Literal::Integer(n) Literal::Integer(n)
} }
@@ -603,6 +617,7 @@ impl Machine {
&mut self.machine_st, &mut self.machine_st,
try_numeric_result!(sub(n1, n2, &mut self.machine_st.arena), stub_gen) try_numeric_result!(sub(n1, n2, &mut self.machine_st.arena), stub_gen)
); );
self.machine_st.p += 1; self.machine_st.p += 1;
} }
&Instruction::Mul(ref a1, ref a2, t) => { &Instruction::Mul(ref a1, ref a2, t) => {
@@ -681,7 +696,7 @@ impl Machine {
self.machine_st.interms[t - 1] = Number::Rational(arena_alloc!( self.machine_st.interms[t - 1] = Number::Rational(arena_alloc!(
try_or_throw_gen!(&mut self.machine_st, rdiv(r1, r2)), try_or_throw_gen!(&mut self.machine_st, rdiv(r1, r2)),
self.machine_st.arena &mut self.machine_st.arena
)); ));
self.machine_st.p += 1; self.machine_st.p += 1;
@@ -694,6 +709,7 @@ impl Machine {
&mut self.machine_st, &mut self.machine_st,
int_floor_div(n1, n2, &mut self.machine_st.arena) int_floor_div(n1, n2, &mut self.machine_st.arena)
); );
self.machine_st.p += 1; self.machine_st.p += 1;
} }
&Instruction::IDiv(ref a1, ref a2, t) => { &Instruction::IDiv(ref a1, ref a2, t) => {
@@ -704,6 +720,7 @@ impl Machine {
&mut self.machine_st, &mut self.machine_st,
idiv(n1, n2, &mut self.machine_st.arena) idiv(n1, n2, &mut self.machine_st.arena)
); );
self.machine_st.p += 1; self.machine_st.p += 1;
} }
&Instruction::Abs(ref a1, t) => { &Instruction::Abs(ref a1, t) => {
@@ -715,7 +732,7 @@ impl Machine {
&Instruction::Sign(ref a1, t) => { &Instruction::Sign(ref a1, t) => {
let n = try_or_throw!(self.machine_st, self.machine_st.get_number(a1)); let n = try_or_throw!(self.machine_st, self.machine_st.get_number(a1));
self.machine_st.interms[t - 1] = sign(n); self.machine_st.interms[t - 1] = n.sign();
self.machine_st.p += 1; self.machine_st.p += 1;
} }
&Instruction::Neg(ref a1, t) => { &Instruction::Neg(ref a1, t) => {
@@ -1004,23 +1021,14 @@ impl Machine {
match self.find_living_dynamic_else(p + next_i) { match self.find_living_dynamic_else(p + next_i) {
Some(_) => { Some(_) => {
self.retry_me_else(next_i); self.retry_me_else(next_i);
try_or_throw!(
self.machine_st,
(self.machine_st.increment_call_count_fn)(&mut self.machine_st)
);
} }
None => { None => {
self.trust_me(); self.trust_me();
try_or_throw!(
self.machine_st,
(self.machine_st.increment_call_count_fn)(&mut self.machine_st)
);
} }
} }
} else { } else {
self.trust_me(); self.trust_me();
}
try_or_throw!( try_or_throw!(
self.machine_st, self.machine_st,
@@ -1029,7 +1037,6 @@ impl Machine {
} }
} }
} }
}
None => { None => {
self.machine_st.fail = true; self.machine_st.fail = true;
} }
@@ -1085,23 +1092,14 @@ impl Machine {
match self.find_living_dynamic_else(p + next_i) { match self.find_living_dynamic_else(p + next_i) {
Some(_) => { Some(_) => {
self.retry_me_else(next_i); self.retry_me_else(next_i);
try_or_throw!(
self.machine_st,
(self.machine_st.increment_call_count_fn)(&mut self.machine_st)
);
} }
None => { None => {
self.trust_me(); self.trust_me();
try_or_throw!(
self.machine_st,
(self.machine_st.increment_call_count_fn)(&mut self.machine_st)
);
} }
} }
} else { } else {
self.trust_me(); self.trust_me();
}
try_or_throw!( try_or_throw!(
self.machine_st, self.machine_st,
@@ -1110,7 +1108,6 @@ impl Machine {
} }
} }
} }
}
None => { None => {
self.machine_st.fail = true; self.machine_st.fail = true;
} }
@@ -1148,17 +1145,7 @@ impl Machine {
); );
} }
&Instruction::NeckCut => { &Instruction::NeckCut => {
let b = self.machine_st.b; self.machine_st.neck_cut();
let b0 = self.machine_st.b0;
if b > b0 {
self.machine_st.b = b0;
if b > self.machine_st.e {
self.machine_st.stack.truncate(b);
}
}
self.machine_st.p += 1; self.machine_st.p += 1;
} }
&Instruction::GetLevel(r) => { &Instruction::GetLevel(r) => {
@@ -1324,7 +1311,6 @@ impl Machine {
} }
&Instruction::DefaultCallRead(_) => { &Instruction::DefaultCallRead(_) => {
try_or_throw!(self.machine_st, self.read()); try_or_throw!(self.machine_st, self.read());
step_or_fail!(self, self.machine_st.p += 1); step_or_fail!(self, self.machine_st.p += 1);
} }
&Instruction::DefaultExecuteRead(_) => { &Instruction::DefaultExecuteRead(_) => {
@@ -2380,6 +2366,16 @@ impl Machine {
self.machine_st.backtrack(); self.machine_st.backtrack();
} }
} }
(HeapCellValueTag::Str, s) => {
let arity = cell_as_atom_cell!(self.machine_st.heap[s])
.get_arity();
if arity == 0 {
self.machine_st.p += 1;
} else {
self.machine_st.backtrack();
}
}
(HeapCellValueTag::Char) => { (HeapCellValueTag::Char) => {
self.machine_st.p += 1; self.machine_st.p += 1;
} }
@@ -2399,6 +2395,16 @@ impl Machine {
self.machine_st.backtrack(); self.machine_st.backtrack();
} }
} }
(HeapCellValueTag::Str, s) => {
let arity = cell_as_atom_cell!(self.machine_st.heap[s])
.get_arity();
if arity == 0 {
self.machine_st.p = self.machine_st.cp;
} else {
self.machine_st.backtrack();
}
}
(HeapCellValueTag::Char) => { (HeapCellValueTag::Char) => {
self.machine_st.p = self.machine_st.cp; self.machine_st.p = self.machine_st.cp;
} }
@@ -2422,6 +2428,16 @@ impl Machine {
self.machine_st.backtrack(); self.machine_st.backtrack();
} }
} }
(HeapCellValueTag::Str, s) => {
let arity = cell_as_atom_cell!(self.machine_st.heap[s])
.get_arity();
if arity == 0 {
self.machine_st.p += 1;
} else {
self.machine_st.backtrack();
}
}
_ => { _ => {
self.machine_st.backtrack(); self.machine_st.backtrack();
} }
@@ -2442,6 +2458,16 @@ impl Machine {
self.machine_st.backtrack(); self.machine_st.backtrack();
} }
} }
(HeapCellValueTag::Str, s) => {
let arity = cell_as_atom_cell!(self.machine_st.heap[s])
.get_arity();
if arity == 0 {
self.machine_st.p = self.machine_st.cp;
} else {
self.machine_st.backtrack();
}
}
_ => { _ => {
self.machine_st.backtrack(); self.machine_st.backtrack();
} }
@@ -2451,10 +2477,21 @@ impl Machine {
let d = self.machine_st.store(self.machine_st.deref(self.machine_st[r])); let d = self.machine_st.store(self.machine_st.deref(self.machine_st[r]));
read_heap_cell!(d, read_heap_cell!(d,
(HeapCellValueTag::Str | HeapCellValueTag::Lis | (HeapCellValueTag::Lis |
HeapCellValueTag::PStrLoc | HeapCellValueTag::CStr) => { HeapCellValueTag::PStrLoc |
HeapCellValueTag::CStr) => {
self.machine_st.p += 1; self.machine_st.p += 1;
} }
(HeapCellValueTag::Str, s) => {
let arity = cell_as_atom_cell!(self.machine_st.heap[s])
.get_arity();
if arity > 0 {
self.machine_st.p += 1;
} else {
self.machine_st.backtrack();
}
}
(HeapCellValueTag::Atom, (_name, arity)) => { (HeapCellValueTag::Atom, (_name, arity)) => {
if arity > 0 { if arity > 0 {
self.machine_st.p += 1; self.machine_st.p += 1;
@@ -2471,10 +2508,21 @@ impl Machine {
let d = self.machine_st.store(self.machine_st.deref(self.machine_st[r])); let d = self.machine_st.store(self.machine_st.deref(self.machine_st[r]));
read_heap_cell!(d, read_heap_cell!(d,
(HeapCellValueTag::Str | HeapCellValueTag::Lis | (HeapCellValueTag::Lis |
HeapCellValueTag::PStrLoc | HeapCellValueTag::CStr) => { HeapCellValueTag::PStrLoc |
HeapCellValueTag::CStr) => {
self.machine_st.p = self.machine_st.cp; self.machine_st.p = self.machine_st.cp;
} }
(HeapCellValueTag::Str, s) => {
let arity = cell_as_atom_cell!(self.machine_st.heap[s])
.get_arity();
if arity > 0 {
self.machine_st.p = self.machine_st.cp;
} else {
self.machine_st.backtrack();
}
}
(HeapCellValueTag::Atom, (_name, arity)) => { (HeapCellValueTag::Atom, (_name, arity)) => {
if arity > 0 { if arity > 0 {
self.machine_st.p = self.machine_st.cp; self.machine_st.p = self.machine_st.cp;
@@ -2529,16 +2577,9 @@ impl Machine {
let d = self.machine_st.store(self.machine_st.deref(self.machine_st[r])); let d = self.machine_st.store(self.machine_st.deref(self.machine_st[r]));
match Number::try_from(d) { match Number::try_from(d) {
Ok(Number::Fixnum(_) | Number::Integer(_) | Number::Float(_)) => { Ok(_) => {
self.machine_st.p += 1; self.machine_st.p += 1;
} }
Ok(Number::Rational(n)) => {
if n.denom() == &1 {
self.machine_st.p += 1;
} else {
self.machine_st.backtrack();
}
}
_ => { _ => {
self.machine_st.backtrack(); self.machine_st.backtrack();
} }
@@ -2548,16 +2589,9 @@ impl Machine {
let d = self.machine_st.store(self.machine_st.deref(self.machine_st[r])); let d = self.machine_st.store(self.machine_st.deref(self.machine_st[r]));
match Number::try_from(d) { match Number::try_from(d) {
Ok(Number::Fixnum(_) | Number::Integer(_) | Number::Float(_)) => { Ok(_) => {
self.machine_st.p = self.machine_st.cp; self.machine_st.p = self.machine_st.cp;
} }
Ok(Number::Rational(n)) => {
if n.denom() == &1 {
self.machine_st.p = self.machine_st.cp;
} else {
self.machine_st.backtrack();
}
}
_ => { _ => {
self.machine_st.backtrack(); self.machine_st.backtrack();
} }
@@ -2784,6 +2818,19 @@ impl Machine {
self.machine_st.s_offset = 0; self.machine_st.s_offset = 0;
self.machine_st.mode = MachineMode::Read; self.machine_st.mode = MachineMode::Read;
} }
(HeapCellValueTag::Str, s) => {
let (name, arity) = cell_as_atom_cell!(self.machine_st.heap[s])
.get_name_and_arity();
if name == atom!(".") && arity == 2 {
self.machine_st.s = HeapPtr::HeapCell(s+1);
self.machine_st.s_offset = 0;
self.machine_st.mode = MachineMode::Read;
} else {
self.machine_st.backtrack();
continue;
}
}
(HeapCellValueTag::Lis, l) => { (HeapCellValueTag::Lis, l) => {
self.machine_st.s = HeapPtr::HeapCell(l); self.machine_st.s = HeapPtr::HeapCell(l);
self.machine_st.s_offset = 0; self.machine_st.s_offset = 0;
@@ -2810,12 +2857,25 @@ impl Machine {
let store_v = self.machine_st.store(deref_v); let store_v = self.machine_st.store(deref_v);
read_heap_cell!(store_v, read_heap_cell!(store_v,
(HeapCellValueTag::Str | HeapCellValueTag::Lis | (HeapCellValueTag::Str |
HeapCellValueTag::PStrLoc | HeapCellValueTag::AttrVar | HeapCellValueTag::Lis |
HeapCellValueTag::StackVar | HeapCellValueTag::Var | HeapCellValueTag::PStrLoc |
HeapCellValueTag::CStr) => { HeapCellValueTag::CStr) => {
self.machine_st.match_partial_string(store_v, string, has_tail); self.machine_st.match_partial_string(store_v, string, has_tail);
} }
(HeapCellValueTag::AttrVar |
HeapCellValueTag::StackVar |
HeapCellValueTag::Var) => {
let target_cell = self.machine_st.push_str_to_heap(
string.as_str(),
has_tail,
);
self.machine_st.bind(
store_v.as_var().unwrap(),
target_cell,
);
}
_ => { _ => {
self.machine_st.backtrack(); self.machine_st.backtrack();
continue; continue;
@@ -3527,7 +3587,10 @@ impl Machine {
self.dynamic_module_resolution(arity - 2) self.dynamic_module_resolution(arity - 2)
); );
try_or_throw!(self.machine_st, self.call_clause(module_name, key)); try_or_throw!(
self.machine_st,
self.call_clause(module_name, key)
);
if self.machine_st.fail { if self.machine_st.fail {
self.machine_st.backtrack(); self.machine_st.backtrack();
@@ -3539,7 +3602,10 @@ impl Machine {
self.dynamic_module_resolution(arity - 2) self.dynamic_module_resolution(arity - 2)
); );
try_or_throw!(self.machine_st, self.execute_clause(module_name, key)); try_or_throw!(
self.machine_st,
self.execute_clause(module_name, key)
);
if self.machine_st.fail { if self.machine_st.fail {
self.machine_st.backtrack(); self.machine_st.backtrack();
@@ -4059,14 +4125,6 @@ impl Machine {
self.clean_up_block(); self.clean_up_block();
self.machine_st.p = self.machine_st.cp; self.machine_st.p = self.machine_st.cp;
} }
&Instruction::CallEraseBall(_) => {
self.erase_ball();
self.machine_st.p += 1;
}
&Instruction::ExecuteEraseBall(_) => {
self.erase_ball();
self.machine_st.p = self.machine_st.cp;
}
&Instruction::CallFail(_) | &Instruction::ExecuteFail(_) => { &Instruction::CallFail(_) | &Instruction::ExecuteFail(_) => {
self.machine_st.backtrack(); self.machine_st.backtrack();
} }
@@ -4134,6 +4192,46 @@ impl Machine {
self.cpu_now(); self.cpu_now();
step_or_fail!(self, self.machine_st.p = self.machine_st.cp); step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
} }
&Instruction::CallDeterministicLengthRundown(_) => {
try_or_throw!(self.machine_st, self.det_length_rundown());
step_or_fail!(self, self.machine_st.p += 1);
}
&Instruction::ExecuteDeterministicLengthRundown(_) => {
try_or_throw!(self.machine_st, self.det_length_rundown());
step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
}
&Instruction::CallHttpOpen(_) => {
try_or_throw!(self.machine_st, self.http_open());
step_or_fail!(self, self.machine_st.p += 1);
}
&Instruction::ExecuteHttpOpen(_) => {
try_or_throw!(self.machine_st, self.http_open());
step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
}
&Instruction::CallHttpListen(_) => {
try_or_throw!(self.machine_st, self.http_listen());
step_or_fail!(self, self.machine_st.p += 1);
}
&Instruction::ExecuteHttpListen(_) => {
try_or_throw!(self.machine_st, self.http_listen());
step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
}
&Instruction::CallHttpAccept(_) => {
try_or_throw!(self.machine_st, self.http_accept());
step_or_fail!(self, self.machine_st.p += 1);
}
&Instruction::ExecuteHttpAccept(_) => {
try_or_throw!(self.machine_st, self.http_accept());
step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
}
&Instruction::CallHttpAnswer(_) => {
try_or_throw!(self.machine_st, self.http_answer());
step_or_fail!(self, self.machine_st.p += 1);
}
&Instruction::ExecuteHttpAnswer(_) => {
try_or_throw!(self.machine_st, self.http_answer());
step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
}
&Instruction::CallCurrentTime(_) => { &Instruction::CallCurrentTime(_) => {
self.current_time(); self.current_time();
step_or_fail!(self, self.machine_st.p += 1); step_or_fail!(self, self.machine_st.p += 1);
@@ -4178,6 +4276,30 @@ impl Machine {
self.set_ball(); self.set_ball();
self.machine_st.p = self.machine_st.cp; self.machine_st.p = self.machine_st.cp;
} }
&Instruction::CallPushBallStack(_) => {
self.push_ball_stack();
step_or_fail!(self, self.machine_st.p += 1);
}
&Instruction::ExecutePushBallStack(_) => {
self.push_ball_stack();
step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
}
&Instruction::CallPopBallStack(_) => {
self.pop_ball_stack();
self.machine_st.p += 1;
}
&Instruction::ExecutePopBallStack(_) => {
self.pop_ball_stack();
self.machine_st.p = self.machine_st.cp;
}
&Instruction::CallPopFromBallStack(_) => {
self.pop_from_ball_stack();
self.machine_st.p += 1;
}
&Instruction::ExecutePopFromBallStack(_) => {
self.pop_from_ball_stack();
self.machine_st.p = self.machine_st.cp;
}
&Instruction::CallSetCutPointByDefault(r, _) => { &Instruction::CallSetCutPointByDefault(r, _) => {
self.set_cut_point_by_default(r); self.set_cut_point_by_default(r);
step_or_fail!(self, self.machine_st.p += 1); step_or_fail!(self, self.machine_st.p += 1);
@@ -4703,11 +4825,11 @@ impl Machine {
step_or_fail!(self, self.machine_st.p = self.machine_st.cp); step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
} }
&Instruction::CallLoadContextModule(_) => { &Instruction::CallLoadContextModule(_) => {
self.load_context_module(); self.load_context_module(self.machine_st.registers[1]);
step_or_fail!(self, self.machine_st.p += 1); step_or_fail!(self, self.machine_st.p += 1);
} }
&Instruction::ExecuteLoadContextModule(_) => { &Instruction::ExecuteLoadContextModule(_) => {
self.load_context_module(); self.load_context_module(self.machine_st.registers[1]);
step_or_fail!(self, self.machine_st.p = self.machine_st.cp); step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
} }
&Instruction::CallLoadContextStream(_) => { &Instruction::CallLoadContextStream(_) => {
@@ -4862,6 +4984,118 @@ impl Machine {
try_or_throw!(self.machine_st, self.add_non_counted_backtracking()); try_or_throw!(self.machine_st, self.add_non_counted_backtracking());
self.machine_st.p = self.machine_st.cp; self.machine_st.p = self.machine_st.cp;
} }
&Instruction::CallPredicateDefined(_) => {
self.machine_st.fail = !self.predicate_defined();
step_or_fail!(self, self.machine_st.p += 1);
}
&Instruction::ExecutePredicateDefined(_) => {
self.machine_st.fail = !self.predicate_defined();
step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
}
&Instruction::CallStripModule(_) => {
let (module_loc, qualified_goal) = self.machine_st.strip_module(
self.machine_st.registers[1],
self.machine_st.registers[2],
);
let target_module_loc = self.machine_st.registers[2];
unify_fn!(
&mut self.machine_st,
module_loc,
target_module_loc
);
let target_qualified_goal = self.machine_st.registers[3];
unify_fn!(
&mut self.machine_st,
qualified_goal,
target_qualified_goal
);
step_or_fail!(self, self.machine_st.p += 1);
}
&Instruction::ExecuteStripModule(_) => {
let (module_loc, qualified_goal) = self.machine_st.strip_module(
self.machine_st.registers[1],
self.machine_st.registers[2],
);
let target_module_loc = self.machine_st.registers[2];
unify_fn!(
&mut self.machine_st,
module_loc,
target_module_loc
);
let target_qualified_goal = self.machine_st.registers[3];
unify_fn!(
&mut self.machine_st,
qualified_goal,
target_qualified_goal
);
step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
}
&Instruction::CallPrepareCallClause(arity, _) => {
try_or_throw!(self.machine_st, self.prepare_call_clause(arity));
step_or_fail!(self, self.machine_st.p += 1);
}
&Instruction::ExecutePrepareCallClause(arity, _) => {
try_or_throw!(self.machine_st, self.prepare_call_clause(arity));
step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
}
&Instruction::CallCompileInlineOrExpandedGoal(_) => {
try_or_throw!(self.machine_st, self.compile_inline_or_expanded_goal());
step_or_fail!(self, self.machine_st.p += 1);
}
&Instruction::ExecuteCompileInlineOrExpandedGoal(_) => {
try_or_throw!(self.machine_st, self.compile_inline_or_expanded_goal());
step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
}
&Instruction::CallIsExpandedOrInlined(_) => {
self.machine_st.fail = !self.is_expanded_or_inlined();
step_or_fail!(self, self.machine_st.p += 1);
}
&Instruction::ExecuteIsExpandedOrInlined(_) => {
self.machine_st.fail = !self.is_expanded_or_inlined();
step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
}
&Instruction::CallInlineCallN(arity, _) => {
let call_at_index = |wam: &mut Machine, name, arity, ptr| {
wam.try_call(name, arity, ptr)
};
try_or_throw!(self.machine_st, self.call_inline(arity, call_at_index));
if self.machine_st.fail {
self.machine_st.backtrack();
} else {
try_or_throw!(
self.machine_st,
(self.machine_st.increment_call_count_fn)(&mut self.machine_st)
);
}
}
&Instruction::ExecuteInlineCallN(arity, _) => {
let call_at_index = |wam: &mut Machine, name, arity, ptr| {
wam.try_execute(name, arity, ptr)
};
try_or_throw!(self.machine_st, self.call_inline(arity, call_at_index));
if self.machine_st.fail {
self.machine_st.backtrack();
} else {
try_or_throw!(
self.machine_st,
(self.machine_st.increment_call_count_fn)(&mut self.machine_st)
);
}
}
} }
} }

View File

@@ -2,10 +2,13 @@ use crate::atom_table::*;
use crate::machine::heap::*; use crate::machine::heap::*;
use crate::types::*; use crate::types::*;
#[cfg(test)]
use crate::heap_iter::FocusedHeapIter;
use core::marker::PhantomData; use core::marker::PhantomData;
pub(crate) trait UnmarkPolicy { pub(crate) trait UnmarkPolicy {
fn unmark(heap: &mut [HeapCellValue], current: usize) -> bool; fn unmark(heap: &mut [HeapCellValue], current: usize);
fn mark(heap: &mut [HeapCellValue], current: usize); fn mark(heap: &mut [HeapCellValue], current: usize);
fn forward_attr_var(iter: &mut StacklessPreOrderHeapIter<Self>) -> Option<HeapCellValue> fn forward_attr_var(iter: &mut StacklessPreOrderHeapIter<Self>) -> Option<HeapCellValue>
where where
@@ -16,9 +19,8 @@ pub(crate) struct IteratorUMP;
impl UnmarkPolicy for IteratorUMP { impl UnmarkPolicy for IteratorUMP {
#[inline(always)] #[inline(always)]
fn unmark(heap: &mut [HeapCellValue], current: usize) -> bool { fn unmark(heap: &mut [HeapCellValue], current: usize) {
heap[current].set_mark_bit(false); heap[current].set_mark_bit(false);
false
} }
#[inline(always)] #[inline(always)]
@@ -34,7 +36,7 @@ struct MarkerUMP {}
impl UnmarkPolicy for MarkerUMP { impl UnmarkPolicy for MarkerUMP {
#[inline(always)] #[inline(always)]
fn unmark(_heap: &mut [HeapCellValue], _current: usize) -> bool { true } fn unmark(_heap: &mut [HeapCellValue], _current: usize) {}
#[inline(always)] #[inline(always)]
fn mark(heap: &mut [HeapCellValue], current: usize) { fn mark(heap: &mut [HeapCellValue], current: usize) {
@@ -43,7 +45,7 @@ impl UnmarkPolicy for MarkerUMP {
#[inline(always)] #[inline(always)]
fn forward_attr_var(iter: &mut StacklessPreOrderHeapIter<Self>) -> Option<HeapCellValue> { fn forward_attr_var(iter: &mut StacklessPreOrderHeapIter<Self>) -> Option<HeapCellValue> {
if iter.heap[iter.current + 1].get_mark_bit() { if iter.heap[iter.current + 1].get_forwarding_bit() {
return iter.forward_var(); return iter.forward_var();
} }
@@ -53,10 +55,9 @@ impl UnmarkPolicy for MarkerUMP {
iter.current += 1; iter.current += 1;
iter.next = iter.heap[iter.current].get_value(); iter.next = iter.heap[iter.current].get_value();
iter.heap[iter.current].set_value(temp); iter.heap[iter.current].set_value(temp);
iter.heap[iter.current].set_mark_bit(true);
iter.heap[iter.current].set_forwarding_bit(true); // forward the attr vars list.
None None
} }
} }
@@ -71,6 +72,14 @@ pub(crate) struct StacklessPreOrderHeapIter<'a, UMP: UnmarkPolicy> {
_marker: PhantomData<UMP>, _marker: PhantomData<UMP>,
} }
#[cfg(test)]
impl<'a> FocusedHeapIter for StacklessPreOrderHeapIter<'a, IteratorUMP> {
#[inline]
fn focus(&self) -> usize {
self.current
}
}
impl<'a, UMP: UnmarkPolicy> Drop for StacklessPreOrderHeapIter<'a, UMP> { impl<'a, UMP: UnmarkPolicy> Drop for StacklessPreOrderHeapIter<'a, UMP> {
fn drop(&mut self) { fn drop(&mut self) {
if self.current == self.start { if self.current == self.start {
@@ -84,15 +93,14 @@ impl<'a, UMP: UnmarkPolicy> Drop for StacklessPreOrderHeapIter<'a, UMP> {
} }
} }
impl<'a, UMP: UnmarkPolicy> StacklessPreOrderHeapIter<'a, UMP> { impl<'a> StacklessPreOrderHeapIter<'a, MarkerUMP> {
pub(crate) fn new(heap: &'a mut Vec<HeapCellValue>, cell: HeapCellValue) -> Self { pub(crate) fn new(heap: &'a mut Vec<HeapCellValue>, cell: HeapCellValue) -> Self {
let orig_heap_len = heap.len(); let orig_heap_len = heap.len();
let start = orig_heap_len + 1; let start = orig_heap_len;
heap.push(cell); heap.push(cell);
heap.push(heap_loc_as_cell!(orig_heap_len));
heap[start].set_mark_bit(true); heap[start].set_forwarding_bit(true);
let next = heap[start].get_value(); let next = heap[start].get_value();
Self { Self {
@@ -104,11 +112,39 @@ impl<'a, UMP: UnmarkPolicy> StacklessPreOrderHeapIter<'a, UMP> {
_marker: PhantomData, _marker: PhantomData,
} }
} }
}
impl<'a> StacklessPreOrderHeapIter<'a, IteratorUMP> {
#[cfg(test)]
pub(crate) fn new(heap: &'a mut Vec<HeapCellValue>, cell: HeapCellValue) -> Self {
let orig_heap_len = heap.len();
let start = orig_heap_len + 1;
heap.push(cell);
heap.push(heap_loc_as_cell!(orig_heap_len));
heap[start].set_forwarding_bit(true);
let next = heap[start].get_value();
Self {
heap,
orig_heap_len,
start,
current: start,
next,
_marker: PhantomData,
}
}
}
impl<'a, UMP: UnmarkPolicy> StacklessPreOrderHeapIter<'a, UMP> {
fn backward_and_return(&mut self) -> Option<HeapCellValue> { fn backward_and_return(&mut self) -> Option<HeapCellValue> {
let current = self.current; let current = self.current;
if self.backward() { 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(true); self.heap[self.current].set_forwarding_bit(true);
self.heap[self.current].set_mark_bit(true); self.heap[self.current].set_mark_bit(true);
} }
@@ -117,13 +153,7 @@ impl<'a, UMP: UnmarkPolicy> StacklessPreOrderHeapIter<'a, UMP> {
} }
fn forward_var(&mut self) -> Option<HeapCellValue> { fn forward_var(&mut self) -> Option<HeapCellValue> {
if self.heap[self.next].get_mark_bit() { if self.heap[self.next].get_forwarding_bit() {
return self.backward_and_return();
}
self.heap[self.current].set_forwarding_bit(true);
if self.heap[self.next].get_forwarding_bit() == Some(true) {
return self.backward_and_return(); return self.backward_and_return();
} }
@@ -138,29 +168,36 @@ impl<'a, UMP: UnmarkPolicy> StacklessPreOrderHeapIter<'a, UMP> {
fn forward(&mut self) -> Option<HeapCellValue> { fn forward(&mut self) -> Option<HeapCellValue> {
loop { loop {
if self.heap[self.current].get_forwarding_bit() != Some(true) { if !self.heap[self.current].get_mark_bit() {
self.heap[self.current].set_mark_bit(true);
match self.heap[self.current].get_tag() { match self.heap[self.current].get_tag() {
HeapCellValueTag::AttrVar => { HeapCellValueTag::AttrVar => {
if let Some(cell) = UMP::forward_attr_var(self) { return Some(cell); } if let Some(cell) = UMP::forward_attr_var(self) { return Some(cell); }
if self.heap[self.next].get_mark_bit() {
return Some(attr_var_as_cell!(self.current));
}
} }
HeapCellValueTag::Var => { HeapCellValueTag::Var => {
if let Some(cell) = self.forward_var() { return Some(cell); } if let Some(cell) = self.forward_var() { return Some(cell); }
if self.heap[self.next].get_mark_bit() {
return Some(heap_loc_as_cell!(self.current));
}
} }
HeapCellValueTag::Str => { HeapCellValueTag::Str => {
if self.heap[self.next + 1].get_mark_bit() { if self.heap[self.next + 1].get_forwarding_bit() {
return self.backward_and_return(); return self.backward_and_return();
} }
let h = self.next; let h = self.next;
let cell = self.heap[h]; let cell = self.heap[h];
self.heap[h].set_forwarding_bit(true);
self.heap[self.current].set_forwarding_bit(true);
let arity = cell_as_atom_cell!(self.heap[h]).get_arity(); let arity = cell_as_atom_cell!(self.heap[h]).get_arity();
for cell in &mut self.heap[h + 1 .. h + arity + 1] { for cell in &mut self.heap[h + 1 .. h + arity + 1] {
cell.set_mark_bit(true); cell.set_forwarding_bit(true);
} }
let last_cell_loc = h + arity; let last_cell_loc = h + arity;
@@ -172,14 +209,13 @@ impl<'a, UMP: UnmarkPolicy> StacklessPreOrderHeapIter<'a, UMP> {
return Some(cell); return Some(cell);
} }
HeapCellValueTag::Lis => { HeapCellValueTag::Lis => {
if self.heap[self.next + 1].get_mark_bit() { let last_cell_loc = self.next + 1;
if self.heap[last_cell_loc].get_forwarding_bit() {
return self.backward_and_return(); return self.backward_and_return();
} }
self.heap[self.current].set_forwarding_bit(true); self.heap[last_cell_loc].set_forwarding_bit(true);
self.heap[self.next+1].set_mark_bit(true);
let last_cell_loc = self.next + 1;
self.next = self.heap[last_cell_loc].get_value(); self.next = self.heap[last_cell_loc].get_value();
self.heap[last_cell_loc].set_value(self.current); self.heap[last_cell_loc].set_value(self.current);
@@ -191,20 +227,17 @@ impl<'a, UMP: UnmarkPolicy> StacklessPreOrderHeapIter<'a, UMP> {
let h = self.next; let h = self.next;
let cell = self.heap[h]; let cell = self.heap[h];
self.heap[self.current].set_forwarding_bit(true); if self.heap[h+1].get_forwarding_bit() {
if self.heap[h+1].get_mark_bit() {
return self.backward_and_return(); return self.backward_and_return();
} }
if self.heap[h].get_tag() == HeapCellValueTag::PStr { if self.heap[h].get_tag() == HeapCellValueTag::PStr {
self.heap[h+1].set_mark_bit(true); let last_cell_loc = h+1;
self.heap[last_cell_loc].set_forwarding_bit(true);
self.next = self.heap[h+1].get_value(); self.next = self.heap[last_cell_loc].get_value();
self.heap[h+1].set_value(self.current); self.heap[last_cell_loc].set_value(self.current);
self.heap[h].set_forwarding_bit(true); self.current = last_cell_loc;
self.current = h+1;
} else { } else {
debug_assert!(self.heap[h].get_tag() == HeapCellValueTag::PStrOffset); debug_assert!(self.heap[h].get_tag() == HeapCellValueTag::PStrOffset);
@@ -212,7 +245,7 @@ impl<'a, UMP: UnmarkPolicy> StacklessPreOrderHeapIter<'a, UMP> {
self.heap[h].set_value(self.current); self.heap[h].set_value(self.current);
self.current = h; self.current = h;
if self.heap[h].get_forwarding_bit() == Some(true) { if self.heap[h].get_mark_bit() {
continue; continue;
} }
} }
@@ -221,20 +254,23 @@ impl<'a, UMP: UnmarkPolicy> StacklessPreOrderHeapIter<'a, UMP> {
} }
HeapCellValueTag::PStrOffset => { HeapCellValueTag::PStrOffset => {
let h = self.next; let h = self.next;
let cell = self.heap[h];
// mark the Fixnum offset.
UMP::mark(self.heap, self.current+1); UMP::mark(self.heap, self.current+1);
if self.heap[h].get_tag() == HeapCellValueTag::PStr { let last_cell_loc = h+1;
if self.heap[h+1].get_mark_bit() {
if self.heap[last_cell_loc].get_forwarding_bit() {
return self.backward_and_return(); return self.backward_and_return();
} }
self.heap[h+1].set_mark_bit(true); if self.heap[h].get_tag() == HeapCellValueTag::PStr {
self.heap[self.current].set_forwarding_bit(true); self.heap[last_cell_loc].set_forwarding_bit(true);
self.next = self.heap[h+1].get_value(); self.next = self.heap[last_cell_loc].get_value();
self.heap[h+1].set_value(self.current); self.heap[last_cell_loc].set_value(self.current);
self.current = h+1; self.current = last_cell_loc;
} else { } else {
debug_assert!(self.heap[h].get_tag() == HeapCellValueTag::CStr); debug_assert!(self.heap[h].get_tag() == HeapCellValueTag::CStr);
@@ -242,23 +278,25 @@ impl<'a, UMP: UnmarkPolicy> StacklessPreOrderHeapIter<'a, UMP> {
self.heap[h].set_value(self.current); self.heap[h].set_value(self.current);
self.current = h; self.current = h;
} }
}
HeapCellValueTag::StackVar => {
let cell = self.heap[self.current];
self.heap[self.current].set_forwarding_bit(true);
return Some(cell); return Some(cell);
} }
_ => { tag @ HeapCellValueTag::Atom => {
if self.heap[self.current].get_mark_bit() { let cell = HeapCellValue::build_with(tag, self.next as u64);
let current = self.current; let arity = AtomCell::from_bytes(cell.into_bytes()).get_arity();
if arity == 0 {
return self.backward_and_return();
} else if self.backward() {
return None;
}
}
HeapCellValueTag::PStr => {
if self.backward() { if self.backward() {
return None; return None;
} }
return Some(self.heap[current]);
} }
_ => {
return self.backward_and_return(); return self.backward_and_return();
} }
} }
@@ -271,42 +309,23 @@ impl<'a, UMP: UnmarkPolicy> StacklessPreOrderHeapIter<'a, UMP> {
} }
fn backward(&mut self) -> bool { fn backward(&mut self) -> bool {
while !self.heap[self.current].get_mark_bit() { while !self.heap[self.current].get_forwarding_bit() {
let temp = self.heap[self.current].get_value(); let temp = self.heap[self.current].get_value();
UMP::mark(self.heap, self.current); UMP::unmark(self.heap, self.current);
self.heap[self.current].set_forwarding_bit(false);
self.heap[self.current].set_value(self.next); self.heap[self.current].set_value(self.next);
self.next = self.current; self.next = self.current;
self.current = temp; self.current = temp;
} }
self.heap[self.current].set_forwarding_bit(false); self.heap[self.current].set_forwarding_bit(false);
UMP::unmark(self.heap, self.current);
let unmark_is_no_op = UMP::unmark(self.heap, self.current);
if self.current == self.start { if self.current == self.start {
return true; return true;
} }
if unmark_is_no_op { // if true, the marker is running.
let cell = self.heap[self.current];
// a cyclic root must be handled specially when marking.
if self.next >= self.orig_heap_len && cell.is_ref() {
debug_assert!(cell.get_tag() != HeapCellValueTag::PStrOffset);
self.heap[self.current].set_mark_bit(false);
let prev_current = self.heap[self.current].get_value();
if !self.heap[prev_current].is_forwarded() {
return self.backward();
}
}
}
self.current -= 1; self.current -= 1;
let temp = self.heap[self.current+1].get_value(); let temp = self.heap[self.current+1].get_value();
@@ -713,7 +732,7 @@ mod tests {
assert!(wam.machine_st.heap[8].get_mark_bit()); assert!(wam.machine_st.heap[8].get_mark_bit());
for cell in &wam.machine_st.heap { for cell in &wam.machine_st.heap {
assert!(cell.get_forwarding_bit() != Some(true)); assert!(!cell.get_forwarding_bit());
} }
assert_eq!(unmark_cell_bits!(wam.machine_st.heap[0]), atom_as_cell!(atom!("irrelevant stuff"))); assert_eq!(unmark_cell_bits!(wam.machine_st.heap[0]), atom_as_cell!(atom!("irrelevant stuff")));
@@ -743,7 +762,7 @@ mod tests {
assert!(wam.machine_st.heap[8].get_mark_bit()); assert!(wam.machine_st.heap[8].get_mark_bit());
for cell in &wam.machine_st.heap { for cell in &wam.machine_st.heap {
assert!(cell.get_forwarding_bit() != Some(true)); assert!(!cell.get_forwarding_bit());
} }
assert_eq!(unmark_cell_bits!(wam.machine_st.heap[0]), atom_as_cell!(atom!("irrelevant stuff"))); assert_eq!(unmark_cell_bits!(wam.machine_st.heap[0]), atom_as_cell!(atom!("irrelevant stuff")));
@@ -773,7 +792,7 @@ mod tests {
assert!(wam.machine_st.heap[8].get_mark_bit()); assert!(wam.machine_st.heap[8].get_mark_bit());
for cell in &wam.machine_st.heap { for cell in &wam.machine_st.heap {
assert!(cell.get_forwarding_bit() != Some(true)); assert!(!cell.get_forwarding_bit());
} }
assert_eq!(unmark_cell_bits!(wam.machine_st.heap[0]), atom_as_cell!(atom!("irrelevant stuff"))); assert_eq!(unmark_cell_bits!(wam.machine_st.heap[0]), atom_as_cell!(atom!("irrelevant stuff")));
@@ -803,7 +822,7 @@ mod tests {
assert!(wam.machine_st.heap[8].get_mark_bit()); assert!(wam.machine_st.heap[8].get_mark_bit());
for cell in &wam.machine_st.heap { for cell in &wam.machine_st.heap {
assert!(cell.get_forwarding_bit() != Some(true)); assert!(!cell.get_forwarding_bit());
} }
assert_eq!(unmark_cell_bits!(wam.machine_st.heap[0]), atom_as_cell!(atom!("irrelevant stuff"))); assert_eq!(unmark_cell_bits!(wam.machine_st.heap[0]), atom_as_cell!(atom!("irrelevant stuff")));
@@ -922,7 +941,6 @@ mod tests {
wam.machine_st.heap.push(list_loc_as_cell!(9)); wam.machine_st.heap.push(list_loc_as_cell!(9));
wam.machine_st.heap.push(heap_loc_as_cell!(9)); wam.machine_st.heap.push(heap_loc_as_cell!(9));
wam.machine_st.heap.push(empty_list_as_cell!()); wam.machine_st.heap.push(empty_list_as_cell!());
wam.machine_st.heap.push(attr_var_as_cell!(11)); // linked from 7. wam.machine_st.heap.push(attr_var_as_cell!(11)); // linked from 7.
wam.machine_st.heap.push(heap_loc_as_cell!(12)); wam.machine_st.heap.push(heap_loc_as_cell!(12));
@@ -1096,5 +1114,88 @@ mod tests {
assert_eq!(unmark_cell_bits!(wam.machine_st.heap[0]), atom_as_cell!(atom!("f"), 2)); assert_eq!(unmark_cell_bits!(wam.machine_st.heap[0]), atom_as_cell!(atom!("f"), 2));
assert_eq!(unmark_cell_bits!(wam.machine_st.heap[1]), heap_loc_as_cell!(1)); assert_eq!(unmark_cell_bits!(wam.machine_st.heap[1]), heap_loc_as_cell!(1));
assert_eq!(unmark_cell_bits!(wam.machine_st.heap[2]), heap_loc_as_cell!(1)); assert_eq!(unmark_cell_bits!(wam.machine_st.heap[2]), heap_loc_as_cell!(1));
wam.machine_st.heap.clear();
// representation of one of the heap terms as in issue #1384.
wam.machine_st.heap.push(list_loc_as_cell!(1));
wam.machine_st.heap.push(empty_list_as_cell!());
wam.machine_st.heap.push(list_loc_as_cell!(3));
wam.machine_st.heap.push(heap_loc_as_cell!(0));
wam.machine_st.heap.push(heap_loc_as_cell!(0));
wam.machine_st.heap.push(empty_list_as_cell!());
wam.machine_st.heap.push(heap_loc_as_cell!(2));
mark_cells(&mut wam.machine_st.heap, list_loc_as_cell!(5));
all_cells_marked_and_unforwarded(&wam.machine_st.heap);
assert_eq!(unmark_cell_bits!(wam.machine_st.heap[0]), list_loc_as_cell!(1));
assert_eq!(unmark_cell_bits!(wam.machine_st.heap[1]), empty_list_as_cell!());
assert_eq!(unmark_cell_bits!(wam.machine_st.heap[2]), list_loc_as_cell!(3));
assert_eq!(unmark_cell_bits!(wam.machine_st.heap[3]), heap_loc_as_cell!(0));
assert_eq!(unmark_cell_bits!(wam.machine_st.heap[4]), heap_loc_as_cell!(0));
assert_eq!(unmark_cell_bits!(wam.machine_st.heap[5]), empty_list_as_cell!());
assert_eq!(unmark_cell_bits!(wam.machine_st.heap[6]), heap_loc_as_cell!(2));
wam.machine_st.heap.clear();
// representation of one of the heap terms as in issue #1384.
wam.machine_st.heap.push(list_loc_as_cell!(7));
wam.machine_st.heap.push(heap_loc_as_cell!(0));
wam.machine_st.heap.push(list_loc_as_cell!(3)); // A = [B|[]].
wam.machine_st.heap.push(list_loc_as_cell!(5)); // B = [A|A].
wam.machine_st.heap.push(empty_list_as_cell!());
wam.machine_st.heap.push(heap_loc_as_cell!(2));
wam.machine_st.heap.push(heap_loc_as_cell!(2));
wam.machine_st.heap.push(empty_list_as_cell!()); // C = [[]|B].
wam.machine_st.heap.push(heap_loc_as_cell!(3));
mark_cells(&mut wam.machine_st.heap, heap_loc_as_cell!(0));
assert!(wam.machine_st.heap[0].get_mark_bit());
assert!(!wam.machine_st.heap[1].get_mark_bit());
all_cells_marked_and_unforwarded(&wam.machine_st.heap[2 ..]);
assert_eq!(unmark_cell_bits!(wam.machine_st.heap[0]), list_loc_as_cell!(7));
assert_eq!(unmark_cell_bits!(wam.machine_st.heap[1]), heap_loc_as_cell!(0));
assert_eq!(unmark_cell_bits!(wam.machine_st.heap[2]), list_loc_as_cell!(3));
assert_eq!(unmark_cell_bits!(wam.machine_st.heap[3]), list_loc_as_cell!(5));
assert_eq!(unmark_cell_bits!(wam.machine_st.heap[4]), empty_list_as_cell!());
assert_eq!(unmark_cell_bits!(wam.machine_st.heap[5]), heap_loc_as_cell!(2));
assert_eq!(unmark_cell_bits!(wam.machine_st.heap[6]), heap_loc_as_cell!(2));
assert_eq!(unmark_cell_bits!(wam.machine_st.heap[7]), empty_list_as_cell!());
assert_eq!(unmark_cell_bits!(wam.machine_st.heap[8]), heap_loc_as_cell!(3));
wam.machine_st.heap.clear();
wam.machine_st.heap.push(str_loc_as_cell!(1));
wam.machine_st.heap.push(atom_as_cell!(atom!("+"), 2));
wam.machine_st.heap.push(str_loc_as_cell!(4));
wam.machine_st.heap.push(fixnum_as_cell!(Fixnum::build_with(2)));
wam.machine_st.heap.push(atom_as_cell!(atom!("-"), 2));
wam.machine_st.heap.push(str_loc_as_cell!(7));
wam.machine_st.heap.push(fixnum_as_cell!(Fixnum::build_with(1)));
wam.machine_st.heap.push(atom_as_cell!(atom!("+"), 2));
wam.machine_st.heap.push(fixnum_as_cell!(Fixnum::build_with(3)));
wam.machine_st.heap.push(fixnum_as_cell!(Fixnum::build_with(4)));
mark_cells(&mut wam.machine_st.heap, heap_loc_as_cell!(0));
all_cells_marked_and_unforwarded(&wam.machine_st.heap);
assert_eq!(unmark_cell_bits!(wam.machine_st.heap[0]), str_loc_as_cell!(1));
assert_eq!(unmark_cell_bits!(wam.machine_st.heap[1]), atom_as_cell!(atom!("+"), 2));
assert_eq!(unmark_cell_bits!(wam.machine_st.heap[2]), str_loc_as_cell!(4));
assert_eq!(unmark_cell_bits!(wam.machine_st.heap[3]), fixnum_as_cell!(Fixnum::build_with(2)));
assert_eq!(unmark_cell_bits!(wam.machine_st.heap[4]), atom_as_cell!(atom!("-"), 2));
assert_eq!(unmark_cell_bits!(wam.machine_st.heap[5]), str_loc_as_cell!(7));
assert_eq!(unmark_cell_bits!(wam.machine_st.heap[6]), fixnum_as_cell!(Fixnum::build_with(1)));
assert_eq!(unmark_cell_bits!(wam.machine_st.heap[7]), atom_as_cell!(atom!("+"), 2));
assert_eq!(unmark_cell_bits!(wam.machine_st.heap[8]), fixnum_as_cell!(Fixnum::build_with(3)));
assert_eq!(unmark_cell_bits!(wam.machine_st.heap[9]), fixnum_as_cell!(Fixnum::build_with(4)));
} }
} }

View File

@@ -1,12 +1,12 @@
use crate::arena::*; use crate::arena::*;
use crate::atom_table::*; use crate::atom_table::*;
use crate::forms::*; use crate::forms::*;
use crate::machine::machine_indices::*;
use crate::machine::partial_string::*; use crate::machine::partial_string::*;
use crate::parser::ast::*; use crate::parser::ast::*;
use crate::types::*; use crate::types::*;
use ordered_float::OrderedFloat; use crate::parser::rug::{Integer, Rational};
use rug::{Integer, Rational};
use std::convert::TryFrom; use std::convert::TryFrom;
@@ -18,6 +18,9 @@ impl From<Literal> for HeapCellValue {
match literal { match literal {
Literal::Atom(name) => atom_as_cell!(name), Literal::Atom(name) => atom_as_cell!(name),
Literal::Char(c) => char_as_cell!(c), Literal::Char(c) => char_as_cell!(c),
Literal::CodeIndex(ptr) => {
untyped_arena_ptr_as_cell!(UntypedArenaPtr::from(ptr))
}
Literal::Fixnum(n) => fixnum_as_cell!(n), Literal::Fixnum(n) => fixnum_as_cell!(n),
Literal::Integer(bigint_ptr) => { Literal::Integer(bigint_ptr) => {
typed_arena_ptr_as_cell!(bigint_ptr) typed_arena_ptr_as_cell!(bigint_ptr)
@@ -25,7 +28,7 @@ impl From<Literal> for HeapCellValue {
Literal::Rational(bigint_ptr) => { Literal::Rational(bigint_ptr) => {
typed_arena_ptr_as_cell!(bigint_ptr) typed_arena_ptr_as_cell!(bigint_ptr)
} }
Literal::Float(f) => HeapCellValue::from(f), Literal::Float(f) => HeapCellValue::from(f.as_ptr()),
Literal::String(s) => { Literal::String(s) => {
if s == atom!("") { if s == atom!("") {
empty_list_as_cell!() empty_list_as_cell!()
@@ -56,7 +59,7 @@ impl TryFrom<HeapCellValue> for Literal {
Ok(Literal::Fixnum(n)) Ok(Literal::Fixnum(n))
} }
(HeapCellValueTag::F64, f) => { (HeapCellValueTag::F64, f) => {
Ok(Literal::Float(f)) Ok(Literal::Float(f.as_offset()))
} }
(HeapCellValueTag::Cons, cons_ptr) => { (HeapCellValueTag::Cons, cons_ptr) => {
match_untyped_arena_ptr!(cons_ptr, match_untyped_arena_ptr!(cons_ptr,
@@ -66,9 +69,8 @@ impl TryFrom<HeapCellValue> for Literal {
(ArenaHeaderTag::Rational, n) => { (ArenaHeaderTag::Rational, n) => {
Ok(Literal::Rational(n)) Ok(Literal::Rational(n))
} }
(ArenaHeaderTag::F64, f) => { (ArenaHeaderTag::IndexPtr, _ip) => {
// remove this redundancy. Ok(Literal::CodeIndex(CodeIndex::from(cons_ptr)))
Ok(Literal::Float(F64Ptr(f)))
} }
_ => { _ => {
Err(()) Err(())

View File

@@ -10,8 +10,8 @@ use crate::parser::ast::*;
use fxhash::FxBuildHasher; use fxhash::FxBuildHasher;
use indexmap::IndexSet; use indexmap::IndexSet;
use ref_thread_local::RefThreadLocal; use ref_thread_local::RefThreadLocal;
use slice_deque::{sdeq, SliceDeque};
use std::collections::VecDeque;
use std::fs::File; use std::fs::File;
use std::mem; use std::mem;
@@ -21,12 +21,12 @@ pub(super) fn set_code_index(
retraction_info: &mut RetractionInfo, retraction_info: &mut RetractionInfo,
compilation_target: &CompilationTarget, compilation_target: &CompilationTarget,
key: PredicateKey, key: PredicateKey,
code_index: &CodeIndex, mut code_index: CodeIndex,
code_ptr: IndexPtr, code_ptr: IndexPtr,
) { ) {
let record = match compilation_target { let record = match compilation_target {
CompilationTarget::User => { CompilationTarget::User => {
if IndexPtr::Undefined == code_index.get() { if IndexPtrTag::Undefined == code_index.get().tag() {
code_index.set(code_ptr); code_index.set(code_ptr);
RetractionRecord::AddedUserPredicate(key) RetractionRecord::AddedUserPredicate(key)
} else { } else {
@@ -35,7 +35,7 @@ pub(super) fn set_code_index(
} }
} }
CompilationTarget::Module(ref module_name) => { CompilationTarget::Module(ref module_name) => {
if IndexPtr::Undefined == code_index.get() { if IndexPtrTag::Undefined == code_index.get().tag() {
code_index.set(code_ptr); code_index.set(code_ptr);
RetractionRecord::AddedModulePredicate(*module_name, key) RetractionRecord::AddedModulePredicate(*module_name, key)
} else { } else {
@@ -48,12 +48,10 @@ pub(super) fn set_code_index(
retraction_info.push_record(record); retraction_info.push_record(record);
} }
fn add_op_decl_as_module_export( fn add_op_decl_as_module_export<'a, LS: LoadState<'a>>(
payload: &mut LS::LoaderFieldType,
module_op_dir: &mut OpDir, module_op_dir: &mut OpDir,
compilation_target: &CompilationTarget,
retraction_info: &mut RetractionInfo,
wam_op_dir: &mut OpDir, wam_op_dir: &mut OpDir,
module_op_exports: &mut ModuleOpExports,
op_decl: &OpDecl, op_decl: &OpDecl,
) { ) {
/* /*
@@ -65,20 +63,21 @@ fn add_op_decl_as_module_export(
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) => {
retraction_info.push_record(RetractionRecord::ReplacedUserOp( payload.retraction_info.push_record(RetractionRecord::ReplacedUserOp(
*op_decl, *op_decl,
op_desc, op_desc,
)); ));
module_op_exports.push((*op_decl, Some(op_desc))); payload.module_op_exports.push((*op_decl, Some(op_desc)));
} }
None => { None => {
retraction_info.push_record(RetractionRecord::AddedUserOp(*op_decl)); payload.retraction_info.push_record(RetractionRecord::AddedUserOp(*op_decl));
module_op_exports.push((*op_decl, None)); payload.module_op_exports.push((*op_decl, None));
} }
} }
add_op_decl(retraction_info, compilation_target, module_op_dir, op_decl); let compilation_target = payload.compilation_target;
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(
@@ -117,8 +116,8 @@ pub(super) fn add_op_decl(
} }
} }
pub(super) fn import_module_exports( pub(super) fn import_module_exports<'a, LS: LoadState<'a>>(
retraction_info: &mut RetractionInfo, payload: &mut LS::LoaderFieldType,
compilation_target: &CompilationTarget, compilation_target: &CompilationTarget,
imported_module: &Module, imported_module: &Module,
code_dir: &mut CodeDir, code_dir: &mut CodeDir,
@@ -135,16 +134,18 @@ pub(super) fn import_module_exports(
} }
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 target_code_index = code_dir let target_code_index = code_dir
.entry(key) .entry(key)
.or_insert_with(|| CodeIndex::new(IndexPtr::Undefined)) .or_insert_with(|| CodeIndex::default(arena))
.clone(); .clone();
set_code_index( set_code_index(
retraction_info, &mut payload.retraction_info,
compilation_target, compilation_target,
key, key,
&target_code_index, target_code_index,
src_code_index.get(), src_code_index.get(),
); );
} else { } else {
@@ -155,7 +156,7 @@ pub(super) fn import_module_exports(
} }
} }
ModuleExport::OpDecl(ref op_decl) => { ModuleExport::OpDecl(ref op_decl) => {
add_op_decl(retraction_info, compilation_target, op_dir, op_decl); add_op_decl(&mut payload.retraction_info, compilation_target, op_dir, op_decl);
} }
} }
} }
@@ -163,15 +164,14 @@ pub(super) fn import_module_exports(
Ok(()) Ok(())
} }
fn import_module_exports_into_module( fn import_module_exports_into_module<'a, LS: LoadState<'a>>(
retraction_info: &mut RetractionInfo, payload: &mut LS::LoaderFieldType,
compilation_target: &CompilationTarget, compilation_target: &CompilationTarget,
imported_module: &Module, imported_module: &Module,
code_dir: &mut CodeDir, code_dir: &mut CodeDir,
op_dir: &mut OpDir, op_dir: &mut OpDir,
meta_predicates: &mut MetaPredicateDir, meta_predicates: &mut MetaPredicateDir,
wam_op_dir: &mut OpDir, wam_op_dir: &mut OpDir,
module_op_exports: &mut ModuleOpExports,
) -> Result<(), SessionError> { ) -> Result<(), SessionError> {
for export in imported_module.module_decl.exports.iter() { for export in imported_module.module_decl.exports.iter() {
match export { match export {
@@ -183,16 +183,18 @@ fn import_module_exports_into_module(
} }
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 target_code_index = code_dir let target_code_index = code_dir
.entry(key) .entry(key)
.or_insert_with(|| CodeIndex::new(IndexPtr::Undefined)) .or_insert_with(|| CodeIndex::default(arena))
.clone(); .clone();
set_code_index( set_code_index(
retraction_info, &mut payload.retraction_info,
compilation_target, compilation_target,
key, key,
&target_code_index, target_code_index,
src_code_index.get(), src_code_index.get(),
); );
} else { } else {
@@ -203,12 +205,10 @@ fn import_module_exports_into_module(
} }
} }
ModuleExport::OpDecl(ref op_decl) => { ModuleExport::OpDecl(ref op_decl) => {
add_op_decl_as_module_export( add_op_decl_as_module_export::<LS>(
payload,
op_dir, op_dir,
compilation_target,
retraction_info,
wam_op_dir, wam_op_dir,
module_op_exports,
op_decl, op_decl,
); );
} }
@@ -218,14 +218,12 @@ fn import_module_exports_into_module(
Ok(()) Ok(())
} }
fn import_qualified_module_exports( fn import_qualified_module_exports<'a, LS: LoadState<'a>>(
retraction_info: &mut RetractionInfo, payload: &mut LS::LoaderFieldType,
compilation_target: &CompilationTarget, compilation_target: &CompilationTarget,
imported_module: &Module, imported_module: &Module,
exports: &IndexSet<ModuleExport>, exports: &IndexSet<ModuleExport>,
code_dir: &mut CodeDir, wam_prelude: &mut MachinePreludeView,
op_dir: &mut OpDir,
meta_predicates: &mut MetaPredicateDir,
) -> Result<(), SessionError> { ) -> Result<(), SessionError> {
for export in imported_module.module_decl.exports.iter() { for export in imported_module.module_decl.exports.iter() {
if !exports.contains(export) { if !exports.contains(export) {
@@ -237,20 +235,22 @@ fn import_qualified_module_exports(
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) {
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 target_code_index = code_dir let arena = &mut LS::machine_st(payload).arena;
let target_code_index = wam_prelude.indices.code_dir
.entry(key.clone()) .entry(key.clone())
.or_insert_with(|| CodeIndex::new(IndexPtr::Undefined)) .or_insert_with(|| CodeIndex::new(IndexPtr::undefined(), arena))
.clone(); .clone();
set_code_index( set_code_index(
retraction_info, &mut payload.retraction_info,
compilation_target, compilation_target,
key, key,
&target_code_index, target_code_index,
src_code_index.get(), src_code_index.get(),
); );
} else { } else {
@@ -261,7 +261,12 @@ fn import_qualified_module_exports(
} }
} }
ModuleExport::OpDecl(ref op_decl) => { ModuleExport::OpDecl(ref op_decl) => {
add_op_decl(retraction_info, compilation_target, op_dir, op_decl); add_op_decl(
&mut payload.retraction_info,
compilation_target,
&mut wam_prelude.indices.op_dir,
op_decl,
);
} }
} }
} }
@@ -269,17 +274,17 @@ fn import_qualified_module_exports(
Ok(()) Ok(())
} }
fn import_qualified_module_exports_into_module( fn import_qualified_module_exports_into_module<'a, LS: LoadState<'a>>(
retraction_info: &mut RetractionInfo, payload: &mut LS::LoaderFieldType,
compilation_target: &CompilationTarget,
imported_module: &Module, imported_module: &Module,
exports: &IndexSet<ModuleExport>, exports: &IndexSet<ModuleExport>,
code_dir: &mut CodeDir, code_dir: &mut CodeDir,
op_dir: &mut OpDir, op_dir: &mut OpDir,
meta_predicates: &mut MetaPredicateDir, meta_predicates: &mut MetaPredicateDir,
wam_op_dir: &mut OpDir, wam_op_dir: &mut OpDir,
module_op_exports: &mut ModuleOpExports,
) -> Result<(), SessionError> { ) -> Result<(), SessionError> {
let payload_compilation_target = payload.compilation_target;
for export in imported_module.module_decl.exports.iter() { for export in imported_module.module_decl.exports.iter() {
if !exports.contains(export) { if !exports.contains(export) {
continue; continue;
@@ -294,16 +299,18 @@ fn import_qualified_module_exports_into_module(
} }
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 target_code_index = code_dir let target_code_index = code_dir
.entry(key) .entry(key)
.or_insert_with(|| CodeIndex::new(IndexPtr::Undefined)) .or_insert_with(|| CodeIndex::new(IndexPtr::undefined(), arena))
.clone(); .clone();
set_code_index( set_code_index(
retraction_info, &mut payload.retraction_info,
compilation_target, &payload_compilation_target,
key, key,
&target_code_index, target_code_index,
src_code_index.get(), src_code_index.get(),
); );
} else { } else {
@@ -314,12 +321,10 @@ fn import_qualified_module_exports_into_module(
} }
} }
ModuleExport::OpDecl(ref op_decl) => { ModuleExport::OpDecl(ref op_decl) => {
add_op_decl_as_module_export( add_op_decl_as_module_export::<LS>(
payload,
op_dir, op_dir,
compilation_target,
retraction_info,
wam_op_dir, wam_op_dir,
module_op_exports,
op_decl, op_decl,
); );
} }
@@ -334,12 +339,12 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
&mut self, &mut self,
compilation_target: CompilationTarget, compilation_target: CompilationTarget,
key: PredicateKey, key: PredicateKey,
clause_locs: &SliceDeque<usize>, clause_locs: &VecDeque<usize>,
) { ) {
let result_opt = self let result_opt = self
.wam_prelude .wam_prelude
.indices .indices
.get_predicate_skeleton(&compilation_target, &key) .get_predicate_skeleton_mut(&compilation_target, &key)
.map(|skeleton| { .map(|skeleton| {
( (
clause_locs clause_locs
@@ -396,7 +401,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
pub(super) fn retract_local_clause_clauses( pub(super) fn retract_local_clause_clauses(
&mut self, &mut self,
clause_clause_compilation_target: CompilationTarget, clause_clause_compilation_target: CompilationTarget,
clause_locs: &SliceDeque<usize>, clause_locs: &VecDeque<usize>,
) { ) {
let key = (atom!("$clause"), 2); let key = (atom!("$clause"), 2);
let listing_src_file_name = self.listing_src_file_name(); let listing_src_file_name = self.listing_src_file_name();
@@ -415,7 +420,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
payload_compilation_target, payload_compilation_target,
clause_clause_compilation_target, clause_clause_compilation_target,
key, key,
mem::replace(&mut skeleton.clause_clause_locs, sdeq![]), mem::replace(&mut skeleton.clause_clause_locs, VecDeque::new()),
), ),
); );
@@ -464,7 +469,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
None => return, None => return,
}; };
for (key, code_index) in &removed_module.code_dir { for (key, code_index) in removed_module.code_dir.iter_mut() {
match removed_module match removed_module
.local_extensible_predicates .local_extensible_predicates
.get(&(CompilationTarget::User, *key)) .get(&(CompilationTarget::User, *key))
@@ -473,7 +478,7 @@ 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(
@@ -512,11 +517,11 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
for export in removed_module.module_decl.exports.iter() { for export in removed_module.module_decl.exports.iter() {
match export { match export {
ModuleExport::PredicateKey(ref key) => { ModuleExport::PredicateKey(ref key) => {
match (removed_module.code_dir.get(key), code_dir.get(key)) { match (removed_module.code_dir.get(key), code_dir.get_mut(key)) {
(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 = target_code_index.replace(IndexPtr::undefined());
retraction_info.push_record(predicate_retractor(*key, old_index_ptr)); retraction_info.push_record(predicate_retractor(*key, old_index_ptr));
} }
_ => {} _ => {}
@@ -584,7 +589,10 @@ 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(IndexPtr::Undefined)) .or_insert_with(|| CodeIndex::new(
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);
@@ -593,7 +601,10 @@ 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(IndexPtr::Undefined)) .or_insert_with(|| CodeIndex::new(
IndexPtr::undefined(),
&mut LS::machine_st(&mut self.payload).arena,
))
.clone(), .clone(),
None => { None => {
unreachable!() unreachable!()
@@ -608,13 +619,15 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
key: PredicateKey, key: PredicateKey,
compilation_target: CompilationTarget, compilation_target: CompilationTarget,
) -> CodeIndex { ) -> CodeIndex {
let arena = &mut LS::machine_st(&mut self.payload).arena;
match compilation_target { match compilation_target {
CompilationTarget::User => self CompilationTarget::User => self
.wam_prelude .wam_prelude
.indices .indices
.code_dir .code_dir
.entry(key) .entry(key)
.or_insert_with(|| CodeIndex::new(IndexPtr::Undefined)) .or_insert_with(|| CodeIndex::new(IndexPtr::undefined(), arena))
.clone(), .clone(),
CompilationTarget::Module(module_name) => { CompilationTarget::Module(module_name) => {
self.get_or_insert_local_code_index(module_name, key) self.get_or_insert_local_code_index(module_name, key)
@@ -627,13 +640,15 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
module_name: Atom, module_name: Atom,
key: PredicateKey, key: PredicateKey,
) -> CodeIndex { ) -> CodeIndex {
let arena = &mut LS::machine_st(&mut self.payload).arena;
if module_name == atom!("user") { if module_name == atom!("user") {
return self return self
.wam_prelude .wam_prelude
.indices .indices
.code_dir .code_dir
.entry(key) .entry(key)
.or_insert_with(|| CodeIndex::new(IndexPtr::Undefined)) .or_insert_with(|| CodeIndex::new(IndexPtr::undefined(), arena))
.clone(); .clone();
} else { } else {
self.get_or_insert_local_code_index(module_name, key) self.get_or_insert_local_code_index(module_name, key)
@@ -732,14 +747,10 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
CompilationTarget::Module(ref module_name) => { CompilationTarget::Module(ref module_name) => {
match self.wam_prelude.indices.modules.get_mut(module_name) { match self.wam_prelude.indices.modules.get_mut(module_name) {
Some(ref mut module) => { Some(ref mut module) => {
let payload: &mut LoadStatePayload<_> = &mut self.payload; add_op_decl_as_module_export::<LS>(
&mut self.payload,
add_op_decl_as_module_export(
&mut module.op_dir, &mut module.op_dir,
&payload.compilation_target,
&mut payload.retraction_info,
&mut self.wam_prelude.indices.op_dir, &mut self.wam_prelude.indices.op_dir,
&mut payload.module_op_exports,
op_decl, op_decl,
); );
} }
@@ -752,7 +763,9 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
} }
pub(super) fn get_clause_type(&mut self, name: Atom, arity: usize) -> ClauseType { pub(super) fn get_clause_type(&mut self, name: Atom, arity: usize) -> ClauseType {
match ClauseType::from(name, arity) { let arena = &mut LS::machine_st(&mut self.payload).arena;
match ClauseType::from(name, arity, arena) {
ClauseType::Named(arity, name, _) => { ClauseType::Named(arity, name, _) => {
let payload_compilation_target = self.payload.compilation_target; let payload_compilation_target = self.payload.compilation_target;
@@ -773,7 +786,9 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
name: Atom, name: Atom,
arity: usize, arity: usize,
) -> ClauseType { ) -> ClauseType {
match ClauseType::from(name, arity) { let arena = &mut LS::machine_st(&mut self.payload).arena;
match ClauseType::from(name, arity, arena) {
ClauseType::Named(arity, name, _) => { ClauseType::Named(arity, name, _) => {
let key = (name, arity); let key = (name, arity);
let idx = self.get_or_insert_qualified_code_index(module_name, key); let idx = self.get_or_insert_qualified_code_index(module_name, key);
@@ -784,6 +799,16 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
} }
} }
pub(super) fn get_meta_specs(&self, name: Atom, arity: usize) -> Option<&Vec<MetaSpec>> {
self.wam_prelude
.indices
.get_meta_predicate_spec(
name,
arity,
&self.payload.compilation_target,
)
}
pub(super) fn add_meta_predicate_record( pub(super) fn add_meta_predicate_record(
&mut self, &mut self,
module_name: Atom, module_name: Atom,
@@ -894,8 +919,8 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
return; return;
} }
import_module_exports( import_module_exports::<LS>(
&mut self.payload.retraction_info, &mut self.payload,
&module_compilation_target, &module_compilation_target,
builtins, builtins,
code_dir, code_dir,
@@ -992,14 +1017,10 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
for export in &module.module_decl.exports { for export in &module.module_decl.exports {
if let ModuleExport::OpDecl(ref op_decl) = export { if let ModuleExport::OpDecl(ref op_decl) = export {
let payload: &mut LoadStatePayload<_> = &mut self.payload; add_op_decl_as_module_export::<LS>(
&mut self.payload,
add_op_decl_as_module_export(
&mut module.op_dir, &mut module.op_dir,
&payload.compilation_target, // this is a Module.
&mut payload.retraction_info,
&mut self.wam_prelude.indices.op_dir, &mut self.wam_prelude.indices.op_dir,
&mut payload.module_op_exports,
op_decl, op_decl,
); );
} }
@@ -1018,8 +1039,8 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
match &payload_compilation_target { match &payload_compilation_target {
CompilationTarget::User => { CompilationTarget::User => {
import_module_exports( import_module_exports::<LS>(
&mut self.payload.retraction_info, &mut self.payload,
&payload_compilation_target, &payload_compilation_target,
&module, &module,
&mut self.wam_prelude.indices.code_dir, &mut self.wam_prelude.indices.code_dir,
@@ -1030,17 +1051,14 @@ 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) => {
let payload: &mut LoadStatePayload<_> = &mut self.payload; import_module_exports_into_module::<LS>(
&mut self.payload,
import_module_exports_into_module(
&mut payload.retraction_info,
&payload_compilation_target, &payload_compilation_target,
&module, &module,
&mut target_module.code_dir, &mut target_module.code_dir,
&mut target_module.op_dir, &mut target_module.op_dir,
&mut target_module.meta_predicates, &mut target_module.meta_predicates,
&mut self.wam_prelude.indices.op_dir, &mut self.wam_prelude.indices.op_dir,
&mut payload.module_op_exports,
)?; )?;
} }
None => { None => {
@@ -1070,47 +1088,38 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
if let Some(module) = self.wam_prelude.indices.modules.remove(&module_name) { if let Some(module) = self.wam_prelude.indices.modules.remove(&module_name) {
let payload_compilation_target = self.payload.compilation_target; let payload_compilation_target = self.payload.compilation_target;
match &payload_compilation_target { let result = match &payload_compilation_target {
CompilationTarget::User => { CompilationTarget::User => {
import_qualified_module_exports( import_qualified_module_exports::<LS>(
&mut self.payload.retraction_info, &mut self.payload,
&payload_compilation_target, &payload_compilation_target,
&module, &module,
&exports, &exports,
&mut self.wam_prelude.indices.code_dir, &mut self.wam_prelude,
&mut self.wam_prelude.indices.op_dir, )
&mut self.wam_prelude.indices.meta_predicates,
)?;
} }
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) => {
let payload: &mut LoadStatePayload<_> = &mut self.payload; import_qualified_module_exports_into_module::<LS>(
&mut self.payload,
import_qualified_module_exports_into_module(
&mut payload.retraction_info,
&payload_compilation_target,
&module, &module,
&exports, &exports,
&mut target_module.code_dir, &mut target_module.code_dir,
&mut target_module.op_dir, &mut target_module.op_dir,
&mut target_module.meta_predicates, &mut target_module.meta_predicates,
&mut self.wam_prelude.indices.op_dir, &mut self.wam_prelude.indices.op_dir,
&mut payload.module_op_exports, )
)?;
} }
None => { None => {
// we find ourselves here because we're trying to import Err(SessionError::ModuleCannotImportSelf(module_name))
// a module into itself as it is being defined.
self.wam_prelude.indices.modules.insert(module_name, module);
return Err(SessionError::ModuleCannotImportSelf(module_name));
}
} }
} }
} }
};
self.wam_prelude.indices.modules.insert(module_name, module); self.wam_prelude.indices.modules.insert(module_name, module);
Ok(()) result
} else { } else {
Err(SessionError::ExistenceError(ExistenceError::Module(module_name))) Err(SessionError::ExistenceError(ExistenceError::Module(module_name)))
} }
@@ -1168,7 +1177,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
indices: self.wam_prelude.indices, indices: self.wam_prelude.indices,
code: self.wam_prelude.code, code: self.wam_prelude.code,
load_contexts: self.wam_prelude.load_contexts, load_contexts: self.wam_prelude.load_contexts,
} },
}; };
subloader.load()? subloader.load()?
@@ -1231,7 +1240,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
indices: self.wam_prelude.indices, indices: self.wam_prelude.indices,
code: self.wam_prelude.code, code: self.wam_prelude.code,
load_contexts: self.wam_prelude.load_contexts, load_contexts: self.wam_prelude.load_contexts,
} },
}; };
subloader.load()? subloader.load()?

View File

@@ -14,9 +14,9 @@ use crate::parser::ast::*;
use crate::types::*; use crate::types::*;
use indexmap::IndexSet; use indexmap::IndexSet;
use slice_deque::{sdeq, SliceDeque};
use std::cell::Cell; use std::cell::Cell;
use std::collections::VecDeque;
use std::convert::TryFrom; use std::convert::TryFrom;
use std::fmt; use std::fmt;
use std::mem; use std::mem;
@@ -96,7 +96,7 @@ pub(crate) enum RetractionRecord {
CompilationTarget, CompilationTarget,
CompilationTarget, CompilationTarget,
PredicateKey, PredicateKey,
SliceDeque<usize>, VecDeque<usize>,
), ),
RemovedSkeleton(CompilationTarget, PredicateKey, PredicateSkeleton), RemovedSkeleton(CompilationTarget, PredicateKey, PredicateSkeleton),
ReplacedDynamicElseOffset(usize, usize), ReplacedDynamicElseOffset(usize, usize),
@@ -390,6 +390,64 @@ impl<'a> LoadState<'a> for BootstrappingLoadState<'a> {
} }
} }
pub struct InlineLoadState<'a> {
machine_st: &'a mut MachineState,
pub payload: LoadStatePayload<InlineTermStream>,
}
impl<'a> Deref for InlineLoadState<'a> {
type Target = LoadStatePayload<InlineTermStream>;
#[inline(always)]
fn deref(&self) -> &Self::Target {
&self.payload
}
}
impl<'a> DerefMut for InlineLoadState<'a> {
#[inline(always)]
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.payload
}
}
impl<'a> LoadState<'a> for InlineLoadState<'a> {
type TS = InlineTermStream;
type LoaderFieldType = InlineLoadState<'a>;
type Evacuable = ();
#[inline(always)]
fn new(machine_st: &'a mut MachineState, payload: LoadStatePayload<Self::TS>) -> Self::LoaderFieldType {
InlineLoadState { machine_st, payload }
}
fn evacuate(_loader: Loader<'a, Self>) -> Result<Self::Evacuable, SessionError> {
Ok(())
}
#[inline(always)]
fn should_drop_load_state(_loader: &Loader<'a, Self>) -> bool {
false
}
#[inline(always)]
fn reset_machine(_loader: &mut Loader<'a, Self>) {
}
#[inline(always)]
fn machine_st(load_state: &mut Self::LoaderFieldType) -> &mut MachineState {
&mut load_state.machine_st
}
#[inline(always)]
fn err_on_builtin_overwrite(
_loader: &Loader<'a, Self>,
_key: PredicateKey,
) -> Result<(), SessionError> {
Ok(())
}
}
pub struct Loader<'a, LS: LoadState<'a>> { pub struct Loader<'a, LS: LoadState<'a>> {
pub(super) payload: LS::LoaderFieldType, pub(super) payload: LS::LoaderFieldType,
pub(super) wam_prelude: MachinePreludeView<'a>, pub(super) wam_prelude: MachinePreludeView<'a>,
@@ -485,10 +543,21 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
read_heap_cell!(addr, read_heap_cell!(addr,
(HeapCellValueTag::Lis) => { (HeapCellValueTag::Lis) => {
use crate::parser::parser::as_partial_string;
let tail = term_stack.pop().unwrap(); let tail = term_stack.pop().unwrap();
let head = term_stack.pop().unwrap(); let head = term_stack.pop().unwrap();
term_stack.push(Term::Cons(Cell::default(), Box::new(head), Box::new(tail))); match as_partial_string(head, tail) {
Ok((string, Some(tail))) => {
term_stack.push(Term::PartialString(Cell::default(), string, tail));
}
Ok((string, None)) => {
let atom = machine_st.atom_tbl.build_with(&string);
term_stack.push(Term::CompleteString(Cell::default(), atom));
}
Err(cons_term) => term_stack.push(cons_term),
}
} }
(HeapCellValueTag::Var | HeapCellValueTag::AttrVar | HeapCellValueTag::StackVar, h) => { (HeapCellValueTag::Var | HeapCellValueTag::AttrVar | HeapCellValueTag::StackVar, h) => {
let offset_string = format!("_{}", h); let offset_string = format!("_{}", h);
@@ -499,6 +568,27 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
term_stack.push(Term::Literal(Cell::default(), Literal::try_from(addr).unwrap())); term_stack.push(Term::Literal(Cell::default(), Literal::try_from(addr).unwrap()));
} }
(HeapCellValueTag::Atom, (name, arity)) => { (HeapCellValueTag::Atom, (name, arity)) => {
let h = iter.focus();
let mut arity = arity;
if iter.heap.len() > h + arity + 1 {
let value = iter.heap[h + arity + 1];
if let Some(idx) = get_structure_index(value) {
// in the second condition, arity == 0,
// meaning idx cannot pertain to this atom
// if it is the direct subterm of a larger
// structure.
if arity > 0 || !iter.direct_subterm_of_str(h) {
term_stack.push(
Term::Literal(Cell::default(), Literal::CodeIndex(idx))
);
arity += 1;
}
}
}
if arity == 0 { if arity == 0 {
term_stack.push(Term::Literal(Cell::default(), Literal::Atom(name))); term_stack.push(Term::Literal(Cell::default(), Literal::Atom(name)));
} else { } else {
@@ -509,31 +599,27 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
term_stack.push(Term::Clause(Cell::default(), name, subterms)); term_stack.push(Term::Clause(Cell::default(), name, subterms));
} }
} }
(HeapCellValueTag::PStr, string) => { (HeapCellValueTag::PStr, atom) => {
let tail = term_stack.pop().unwrap(); let tail = term_stack.pop().unwrap();
if let Term::Literal(_, Literal::Atom(atom!("[]"))) = &tail { if let Term::Literal(_, Literal::Atom(atom!("[]"))) = &tail {
term_stack.push(Term::PartialString( term_stack.push(Term::CompleteString(Cell::default(), atom));
Cell::default(),
string,
None,
));
} else { } else {
term_stack.push(Term::PartialString( term_stack.push(Term::PartialString(
Cell::default(), Cell::default(),
string, atom.as_str().to_owned(),
Some(Box::new(tail)), Box::new(tail),
)); ));
} }
} }
(HeapCellValueTag::PStrLoc, h) => { (HeapCellValueTag::PStrLoc, h) => {
let string = cell_as_atom_cell!(iter.heap[h]).get_name(); let atom = cell_as_atom_cell!(iter.heap[h]).get_name();
let tail = term_stack.pop().unwrap(); let tail = term_stack.pop().unwrap();
term_stack.push(Term::PartialString( term_stack.push(Term::PartialString(
Cell::default(), Cell::default(),
string, atom.as_str().to_owned(),
Some(Box::new(tail)), Box::new(tail),
)); ));
} }
_ => { _ => {
@@ -701,7 +787,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
module module
.code_dir .code_dir
.get_mut(&key) .get_mut(&key)
.map(|code_idx| code_idx.replace(old_code_idx)); .map(|code_idx| code_idx.set(old_code_idx));
} }
None => {} None => {}
} }
@@ -726,10 +812,9 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
.indices .indices
.code_dir .code_dir
.get_mut(&key) .get_mut(&key)
.map(|code_idx| code_idx.replace(old_code_idx)); .map(|code_idx| code_idx.set(old_code_idx));
} }
RetractionRecord::AddedIndex(index_key, clause_loc) => { RetractionRecord::AddedIndex(index_key, clause_loc) => {
// WAS: inner_index_locs) => {
if let Some(index_loc) = index_key.switch_on_term_loc() { if let Some(index_loc) = index_key.switch_on_term_loc() {
let indexing_code = match &mut self.wam_prelude.code[index_loc] { let indexing_code = match &mut self.wam_prelude.code[index_loc] {
Instruction::IndexingCode(indexing_code) => indexing_code, Instruction::IndexingCode(indexing_code) => indexing_code,
@@ -900,7 +985,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
key, key,
) { ) {
Some(skeleton) => { Some(skeleton) => {
skeleton.clause_clause_locs.truncate_back(len); skeleton.clause_clause_locs.truncate(len);
} }
None => {} None => {}
} }
@@ -912,8 +997,8 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
.get_predicate_skeleton_mut(&compilation_target, &key) .get_predicate_skeleton_mut(&compilation_target, &key)
{ {
Some(skeleton) => { Some(skeleton) => {
skeleton.clauses.truncate_back(len); skeleton.clauses.truncate(len);
skeleton.core.clause_clause_locs.truncate_back(len); skeleton.core.clause_clause_locs.truncate(len);
} }
None => {} None => {}
} }
@@ -1264,13 +1349,13 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
let code_index = self.get_or_insert_code_index(key, compilation_target); let code_index = self.get_or_insert_code_index(key, compilation_target);
if let IndexPtr::Undefined = code_index.get() { if code_index.is_undefined() {
set_code_index( set_code_index(
&mut self.payload.retraction_info, &mut self.payload.retraction_info,
&compilation_target, &compilation_target,
key, key,
&code_index, code_index,
IndexPtr::DynamicUndefined, IndexPtr::dynamic_undefined(),
); );
} }
} }
@@ -1358,7 +1443,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
*key, *key,
) { ) {
Some(skeleton) if !skeleton.clause_clause_locs.is_empty() => { Some(skeleton) if !skeleton.clause_clause_locs.is_empty() => {
mem::replace(&mut skeleton.clause_clause_locs, sdeq![]) mem::replace(&mut skeleton.clause_clause_locs, VecDeque::new())
} }
_ => return, _ => return,
}; };
@@ -1484,7 +1569,6 @@ impl Machine {
let mut loader = self.loader_from_heap_evacuable(temp_v!(3)); let mut loader = self.loader_from_heap_evacuable(temp_v!(3));
let declare_module = || { let declare_module = || {
// let export_list = export_list?;
let exports = loader.extract_module_export_list_from_heap(temp_v!(2))?; let exports = loader.extract_module_export_list_from_heap(temp_v!(2))?;
let module_decl = ModuleDecl { let module_decl = ModuleDecl {
@@ -1837,7 +1921,7 @@ impl Machine {
return; return;
} }
_ => { _ => {
return self.load_context_module(); return self.load_context_module(self.machine_st.registers[1]);
} }
} }
} }
@@ -1859,9 +1943,9 @@ impl Machine {
self.machine_st.fail = true; self.machine_st.fail = true;
} }
pub(crate) fn load_context_module(&mut self) { pub(crate) fn load_context_module(&mut self, target: HeapCellValue) {
if let Some(load_context) = self.load_contexts.last() { if let Some(load_context) = self.load_contexts.last() {
self.machine_st.unify_atom(load_context.module, self.machine_st.registers[1]); self.machine_st.unify_atom(load_context.module, target);
} else { } else {
self.machine_st.fail = true; self.machine_st.fail = true;
} }
@@ -1878,13 +1962,10 @@ impl Machine {
} }
} }
pub(crate) fn compile_assert<'a>(&'a mut self, append_or_prepend: AppendOrPrepend) -> CallResult { pub(crate) fn compile_assert(&mut self, append_or_prepend: AppendOrPrepend) -> CallResult
let key = self {
.machine_st
.read_predicate_key(self.machine_st[temp_v!(3)], self.machine_st[temp_v!(4)]);
let module_name = cell_as_atom!( let module_name = cell_as_atom!(
self.machine_st.store(self.machine_st.deref(self.machine_st.registers[5])) self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]))
); );
let compilation_target = match module_name { let compilation_target = match module_name {
@@ -1892,14 +1973,62 @@ impl Machine {
_ => CompilationTarget::Module(module_name), _ => CompilationTarget::Module(module_name),
}; };
let stub_gen = || {
match append_or_prepend {
AppendOrPrepend::Append => functor_stub(atom!("assertz"), 1),
AppendOrPrepend::Prepend => functor_stub(atom!("asserta"), 1),
}
};
let mut compile_assert = || { let mut compile_assert = || {
let mut loader: Loader<'_, LiveLoadAndMachineState<'_>> = let mut loader: Loader<'_, LiveLoadAndMachineState<'_>> =
Loader::new(self, LiveTermStream::new(ListingSource::User)); Loader::new(self, LiveTermStream::new(ListingSource::User));
loader.payload.compilation_target = compilation_target; loader.payload.compilation_target = compilation_target;
let head = loader.read_term_from_heap(temp_v!(1))?; let head = loader.read_term_from_heap(temp_v!(2))?;
let body = loader.read_term_from_heap(temp_v!(2))?;
let name = if let Some(name) = head.name() {
name
} else {
return Err(SessionError::from(CompilationError::InvalidRuleHead));
};
let arity = head.arity();
let is_dynamic_predicate = loader
.wam_prelude
.indices
.is_dynamic_predicate(
module_name,
(name, arity),
);
let no_such_predicate =
if !is_dynamic_predicate && !ClauseType::is_inbuilt(name, arity) {
let idx_tag = loader
.wam_prelude
.indices
.get_predicate_code_index(
name,
arity,
module_name,
)
.map(|code_idx| code_idx.get_tag())
.unwrap_or(IndexPtrTag::DynamicUndefined);
idx_tag == IndexPtrTag::DynamicUndefined ||
idx_tag == IndexPtrTag::Undefined
} else {
is_dynamic_predicate
};
if !no_such_predicate {
LiveLoadAndMachineState::machine_st(&mut loader.payload).fail = true;
return LiveLoadAndMachineState::evacuate(loader);
}
let body = loader.read_term_from_heap(temp_v!(3))?;
let asserted_clause = Term::Clause( let asserted_clause = Term::Clause(
Cell::default(), Cell::default(),
@@ -1908,10 +2037,10 @@ impl Machine {
); );
// if a new predicate was just created, make it dynamic. // if a new predicate was just created, make it dynamic.
loader.add_dynamic_predicate(compilation_target, key.0, key.1)?; loader.add_dynamic_predicate(compilation_target, name, arity)?;
loader.incremental_compile_clause( loader.incremental_compile_clause(
key, (name, arity),
asserted_clause, asserted_clause,
compilation_target, compilation_target,
false, false,
@@ -1922,7 +2051,7 @@ impl Machine {
LiveLoadAndMachineState::machine_st(&mut loader.payload).global_clock += 1; LiveLoadAndMachineState::machine_st(&mut loader.payload).global_clock += 1;
loader.compile_clause_clauses( loader.compile_clause_clauses(
key, (name, arity),
compilation_target, compilation_target,
std::iter::once((head, body)), std::iter::once((head, body)),
append_or_prepend, append_or_prepend,
@@ -1933,14 +2062,30 @@ impl Machine {
match compile_assert() { match compile_assert() {
Ok(_) => Ok(()), Ok(_) => Ok(()),
Err(e) => { Err(SessionError::CompilationError(
let stub = match append_or_prepend { CompilationError::InvalidRuleHead |
AppendOrPrepend::Append => functor_stub(atom!("assertz"), 1), CompilationError::InadmissibleFact
AppendOrPrepend::Prepend => functor_stub(atom!("asserta"), 1), )) => {
}; let err = self.machine_st.type_error(
let err = self.machine_st.session_error(e); ValidType::Callable,
self.machine_st.registers[2],
);
Err(self.machine_st.error_form(err, stub)) Err(self.machine_st.error_form(err, stub_gen()))
}
Err(SessionError::CompilationError(
CompilationError::InadmissibleQueryTerm
)) => {
let err = self.machine_st.type_error(
ValidType::Callable,
self.machine_st.registers[3],
);
Err(self.machine_st.error_form(err, stub_gen()))
}
Err(e) => {
let err = self.machine_st.session_error(e);
Err(self.machine_st.error_form(err, stub_gen()))
} }
} }
} }
@@ -1973,18 +2118,17 @@ impl Machine {
let mut clause_clause_target_poses: Vec<_> = loader let mut clause_clause_target_poses: Vec<_> = loader
.wam_prelude .wam_prelude
.indices .indices
.get_predicate_skeleton(&compilation_target, &key) .remove_predicate_skeleton(&compilation_target, &key)
.map(|skeleton| { .map(|skeleton| {
loader let mut clause_clause_skeleton = loader
.wam_prelude .wam_prelude
.indices .indices
.get_predicate_skeleton( .remove_predicate_skeleton(
&clause_clause_compilation_target, &clause_clause_compilation_target,
&(atom!("$clause"), 2), &(atom!("$clause"), 2),
) ).unwrap();
.map(|clause_clause_skeleton| {
skeleton let result = skeleton.core
.core
.clause_clause_locs .clause_clause_locs
.iter() .iter()
.map(|clause_clause_loc| { .map(|clause_clause_loc| {
@@ -1992,30 +2136,31 @@ impl Machine {
.target_pos_of_clause_clause_loc(*clause_clause_loc) .target_pos_of_clause_clause_loc(*clause_clause_loc)
.unwrap() .unwrap()
}) })
.collect() .collect();
})
.unwrap()
})
.unwrap();
loader loader.add_extensible_predicate(
.wam_prelude key,
skeleton,
compilation_target,
);
loader.add_extensible_predicate(
(atom!("$clause"), 2),
clause_clause_skeleton,
clause_clause_compilation_target,
);
result
}).unwrap();
loader.wam_prelude
.indices .indices
.remove_predicate_skeleton(&compilation_target, &key); .remove_predicate_skeleton(&compilation_target, &key);
let code_index = loader let mut code_index = loader
.get_or_insert_code_index(key, compilation_target); .get_or_insert_code_index(key, compilation_target);
code_index.set(IndexPtr::Undefined); code_index.set(IndexPtr::undefined());
/*
loader
.wam_prelude
.indices
.get_predicate_skeleton_mut(&compilation_target, &key)
.map(|skeleton| skeleton.reset());
*/
loader.payload.compilation_target = clause_clause_compilation_target; loader.payload.compilation_target = clause_clause_compilation_target;
@@ -2076,7 +2221,7 @@ impl Machine {
// the global clock is incremented after each retraction. // the global clock is incremented after each retraction.
LiveLoadAndMachineState::machine_st(&mut loader.payload).global_clock += 1; LiveLoadAndMachineState::machine_st(&mut loader.payload).global_clock += 1;
let target_pos = match loader.wam_prelude.indices.get_predicate_skeleton( let target_pos = match loader.wam_prelude.indices.get_predicate_skeleton_mut(
&clause_clause_compilation_target, &clause_clause_compilation_target,
&(atom!("$clause"), 2), &(atom!("$clause"), 2),
) { ) {
@@ -2180,7 +2325,7 @@ impl Machine {
let (predicate_name, arity) = self let (predicate_name, arity) = self
.machine_st .machine_st
.read_predicate_key(self.machine_st[temp_v!(2)], self.machine_st[temp_v!(3)]); .read_predicate_key(self.machine_st.registers[2], self.machine_st.registers[3]);
let compilation_target = match module_name { let compilation_target = match module_name {
atom!("user") => CompilationTarget::User, atom!("user") => CompilationTarget::User,
@@ -2192,21 +2337,25 @@ impl Machine {
.get_meta_predicate_spec(predicate_name, arity, &compilation_target) .get_meta_predicate_spec(predicate_name, arity, &compilation_target)
{ {
Some(meta_specs) => { Some(meta_specs) => {
let list_loc = iter_to_heap_list( let term_loc = self.machine_st.heap.len();
&mut self.machine_st.heap,
self.machine_st.heap.push(atom_as_cell!(predicate_name, arity));
self.machine_st.heap.extend(
meta_specs.iter().map(|meta_spec| match meta_spec { meta_specs.iter().map(|meta_spec| match meta_spec {
MetaSpec::Minus => atom_as_cell!(atom!("+")), MetaSpec::Minus => atom_as_cell!(atom!("+")),
MetaSpec::Plus => atom_as_cell!(atom!("-")), MetaSpec::Plus => atom_as_cell!(atom!("-")),
MetaSpec::Either => atom_as_cell!(atom!("?")), MetaSpec::Either => atom_as_cell!(atom!("?")),
MetaSpec::Colon => atom_as_cell!(atom!(":")),
MetaSpec::RequiresExpansionWithArgument(ref arg_num) => { MetaSpec::RequiresExpansionWithArgument(ref arg_num) => {
fixnum_as_cell!(Fixnum::build_with(*arg_num as i64)) fixnum_as_cell!(Fixnum::build_with(*arg_num as i64))
} }
})); })
);
let heap_loc = self.machine_st.heap.len(); let heap_loc = self.machine_st.heap.len();
self.machine_st.heap.push(atom_as_cell!(atom!("meta_predicate"), 1)); self.machine_st.heap.push(atom_as_cell!(atom!("meta_predicate"), 1));
self.machine_st.heap.push(heap_loc_as_cell!(list_loc)); self.machine_st.heap.push(str_loc_as_cell!(term_loc));
unify!(self.machine_st, str_loc_as_cell!(heap_loc), self.machine_st.registers[4]); unify!(self.machine_st, str_loc_as_cell!(heap_loc), self.machine_st.registers[4]);
} }
@@ -2298,22 +2447,16 @@ impl Machine {
} }
pub(crate) fn builtin_property(&mut self) { pub(crate) fn builtin_property(&mut self) {
let key = self let (name, arity) = self
.machine_st .machine_st
.read_predicate_key(self.machine_st.registers[1], self.machine_st.registers[2]); .read_predicate_key(self.machine_st.registers[1], self.machine_st.registers[2]);
match ClauseType::from(key.0, key.1) { if !ClauseType::is_inbuilt(name, arity) { // ClauseType::from(key.0, key.1, &mut self.machine_st.arena) {
ClauseType::BuiltIn(_) | ClauseType::Inlined(..) | ClauseType::CallN(_) => {
return;
}
ClauseType::Named(arity, name, _) => {
if let Some(module) = self.indices.modules.get(&(atom!("builtins"))) { if let Some(module) = self.indices.modules.get(&(atom!("builtins"))) {
self.machine_st.fail = !module.code_dir.contains_key(&(name, arity)); self.machine_st.fail = !module.code_dir.contains_key(&(name, arity));
return; return;
} }
} }
_ => {}
}
self.machine_st.fail = true; self.machine_st.fail = true;
} }
@@ -2344,14 +2487,19 @@ impl<'a> Loader<'a, LiveLoadAndMachineState<'a>> {
#[inline] #[inline]
pub(super) fn load_module( pub(super) fn load_module(
machine_st: &mut MachineState,
code_dir: &mut CodeDir, code_dir: &mut CodeDir,
op_dir: &mut OpDir, op_dir: &mut OpDir,
meta_predicate_dir: &mut MetaPredicateDir, meta_predicate_dir: &mut MetaPredicateDir,
compilation_target: &CompilationTarget, compilation_target: &CompilationTarget,
module: &Module, module: &Module,
) { ) {
import_module_exports( let ts = LiveTermStream::new(ListingSource::User);
&mut RetractionInfo::new(0), let payload = LoadStatePayload::new(0, ts);
let mut payload = LiveLoadAndMachineState::new(machine_st, payload);
import_module_exports::<LiveLoadAndMachineState>(
&mut payload,
&compilation_target, &compilation_target,
module, module,
code_dir, code_dir,

View File

@@ -257,6 +257,19 @@ impl MachineState {
} }
} }
pub(super) fn resource_error(&mut self, value: HeapCellValue) -> MachineError {
let stub = functor!(
atom!("resource_error"),
[atom(atom!("finite_memory")), cell(value)]
);
MachineError {
stub,
location: None,
from: ErrorProvenance::Received,
}
}
pub(super) fn type_error<T: TypeError>( pub(super) fn type_error<T: TypeError>(
&mut self, &mut self,
valid_type: ValidType, valid_type: ValidType,
@@ -439,6 +452,9 @@ impl MachineState {
SessionError::OpIsInfixAndPostFix(op) => { SessionError::OpIsInfixAndPostFix(op) => {
self.permission_error(Permission::Create, atom!("operator"), functor!(op)) self.permission_error(Permission::Create, atom!("operator"), functor!(op))
} }
SessionError::CompilationError(CompilationError::ExceededMaxArity) => {
self.representation_error(RepFlag::MaxArity)
}
SessionError::CompilationError(err) => self.syntax_error(err), SessionError::CompilationError(err) => self.syntax_error(err),
SessionError::PredicateNotMultifileOrDiscontiguous(compilation_target, key) => { SessionError::PredicateNotMultifileOrDiscontiguous(compilation_target, key) => {
let functor_stub = functor_stub(key.0, key.1); let functor_stub = functor_stub(key.0, key.1);
@@ -572,16 +588,12 @@ impl MachineError {
pub enum CompilationError { pub enum CompilationError {
Arithmetic(ArithmeticError), Arithmetic(ArithmeticError),
ParserError(ParserError), ParserError(ParserError),
// BadPendingByte,
CannotParseCyclicTerm, CannotParseCyclicTerm,
// ExpandedTermsListNotAList, ExceededMaxArity,
ExpectedRel, ExpectedRel,
// ExpectedTopLevelTerm,
InadmissibleFact, InadmissibleFact,
InadmissibleQueryTerm, InadmissibleQueryTerm,
InconsistentEntry, InconsistentEntry,
// InvalidDoubleQuotesDecl,
// InvalidHook,
InvalidMetaPredicateDecl, InvalidMetaPredicateDecl,
InvalidModuleDecl, InvalidModuleDecl,
InvalidModuleExport, InvalidModuleExport,
@@ -618,31 +630,24 @@ impl CompilationError {
&CompilationError::Arithmetic(..) => { &CompilationError::Arithmetic(..) => {
functor!(atom!("arithmetic_error")) functor!(atom!("arithmetic_error"))
} }
// &CompilationError::BadPendingByte =>
// functor!(atom_from_ss!("bad_pending_byte"), atom_tbl),
&CompilationError::CannotParseCyclicTerm => { &CompilationError::CannotParseCyclicTerm => {
functor!(atom!("cannot_parse_cyclic_term")) functor!(atom!("cannot_parse_cyclic_term"))
} }
// &CompilationError::ExpandedTermsListNotAList => &CompilationError::ExceededMaxArity => {
// functor!(atom_tbl.build_with_static_str("expanded_terms_list_is_not_a_list")), functor!(atom!("exceeded_max_arity"))
}
&CompilationError::ExpectedRel => { &CompilationError::ExpectedRel => {
functor!(atom!("expected_relation")) functor!(atom!("expected_relation"))
} }
// &CompilationError::ExpectedTopLevelTerm => &CompilationError::InadmissibleFact => { // TODO: type_error(callable, _).
// functor!(atom_from_ss!("expected_atom_or_cons_or_clause"), atom_tbl),
&CompilationError::InadmissibleFact => {
functor!(atom!("inadmissible_fact")) functor!(atom!("inadmissible_fact"))
} }
&CompilationError::InadmissibleQueryTerm => { &CompilationError::InadmissibleQueryTerm => { // TODO: type_error(callable, _).
functor!(atom!("inadmissible_query_term")) functor!(atom!("inadmissible_query_term"))
} }
&CompilationError::InconsistentEntry => { &CompilationError::InconsistentEntry => {
functor!(atom!("inconsistent_entry")) functor!(atom!("inconsistent_entry"))
} }
// &CompilationError::InvalidDoubleQuotesDecl =>
// functor!(atom_from_ss!("invalid_double_quotes_declaration"), atom_tbl),
// &CompilationError::InvalidHook =>
// functor!(atom_from_ss!("invalid_hook"), atom_tbl),
&CompilationError::InvalidMetaPredicateDecl => { &CompilationError::InvalidMetaPredicateDecl => {
functor!(atom!("invalid_meta_predicate_decl")) functor!(atom!("invalid_meta_predicate_decl"))
} }
@@ -656,7 +661,8 @@ impl CompilationError {
functor!(atom!("no_such_module"), [atom(module_name)]) functor!(atom!("no_such_module"), [atom(module_name)])
} }
&CompilationError::InvalidRuleHead => { &CompilationError::InvalidRuleHead => {
functor!(atom!("invalid_head_of_rule"))
functor!(atom!("invalid_head_of_rule")) // TODO: type_error(callable, _).
} }
&CompilationError::InvalidUseModuleDecl => { &CompilationError::InvalidUseModuleDecl => {
functor!(atom!("invalid_use_module_declaration")) functor!(atom!("invalid_use_module_declaration"))
@@ -785,14 +791,14 @@ impl MachineState {
let stub_gen = || functor_stub(atom!("sort"), 2); let stub_gen = || functor_stub(atom!("sort"), 2);
let list = self.store(self.deref(self.registers[1])); let list = self.store(self.deref(self.registers[1]));
let sorted = self.registers[2]; let sorted = self.store(self.deref(self.registers[2]));
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::NotList(..) | CycleSearchResult::Cyclic(_) => {
let err = self.type_error(ValidType::List, list); let err = self.type_error(ValidType::List, list);
return Err(self.error_form(err, stub_gen())); return Err(self.error_form(err, stub_gen()));
} }
@@ -800,7 +806,7 @@ impl MachineState {
}; };
match BrentAlgState::detect_cycles(&self.heap, sorted) { match BrentAlgState::detect_cycles(&self.heap, sorted) {
CycleSearchResult::NotList(..) if !sorted.is_var() => { CycleSearchResult::NotList(..) | CycleSearchResult::Cyclic(_) if !sorted.is_var() => {
let err = self.type_error(ValidType::List, sorted); let err = self.type_error(ValidType::List, sorted);
Err(self.error_form(err, stub_gen())) Err(self.error_form(err, stub_gen()))
} }
@@ -812,7 +818,7 @@ impl MachineState {
let stub_gen = || functor_stub(atom!("keysort"), 2); let stub_gen = || functor_stub(atom!("keysort"), 2);
match BrentAlgState::detect_cycles(&self.heap, list) { match BrentAlgState::detect_cycles(&self.heap, list) {
CycleSearchResult::NotList(..) if !list.is_var() => { CycleSearchResult::NotList(..) | CycleSearchResult::Cyclic(_) if !list.is_var() => {
let err = self.type_error(ValidType::List, list); let err = self.type_error(ValidType::List, list);
Err(self.error_form(err, stub_gen())) Err(self.error_form(err, stub_gen()))
} }
@@ -878,7 +884,7 @@ impl MachineState {
let err = self.instantiation_error(); let err = self.instantiation_error();
Err(self.error_form(err, stub_gen())) Err(self.error_form(err, stub_gen()))
} }
CycleSearchResult::NotList(..) => { CycleSearchResult::NotList(..) | CycleSearchResult::Cyclic(_) => {
let err = self.type_error(ValidType::List, pairs); let err = self.type_error(ValidType::List, pairs);
Err(self.error_form(err, stub_gen())) Err(self.error_form(err, stub_gen()))
} }
@@ -902,9 +908,7 @@ pub enum ExistenceError {
pub enum SessionError { pub enum SessionError {
CompilationError(CompilationError), CompilationError(CompilationError),
CannotOverwriteBuiltIn(PredicateKey), CannotOverwriteBuiltIn(PredicateKey),
// CannotOverwriteImport(Atom),
ExistenceError(ExistenceError), ExistenceError(ExistenceError),
// InvalidFileName(Atom),
ModuleDoesNotContainExport(Atom, PredicateKey), ModuleDoesNotContainExport(Atom, PredicateKey),
ModuleCannotImportSelf(Atom), ModuleCannotImportSelf(Atom),
NamelessEntry, NamelessEntry,

View File

@@ -4,18 +4,18 @@ use crate::arena::*;
use crate::atom_table::*; use crate::atom_table::*;
use crate::fixtures::*; use crate::fixtures::*;
use crate::forms::*; use crate::forms::*;
use crate::instructions::*;
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 fxhash::FxBuildHasher; use fxhash::FxBuildHasher;
use indexmap::IndexMap; use indexmap::IndexMap;
use modular_bitfield::{BitfieldSpecifier, bitfield};
use modular_bitfield::specifiers::*;
use std::cell::Cell;
use std::cmp::Ordering; use std::cmp::Ordering;
use std::collections::BTreeSet; use std::collections::BTreeSet;
use std::ops::Deref; use std::ops::{Deref, DerefMut};
use std::rc::Rc; use std::rc::Rc;
use crate::types::*; use crate::types::*;
@@ -59,9 +59,6 @@ impl PartialOrd<Ref> for HeapCellValue {
} }
} }
(HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h1) => { (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h1) => {
// _ if self.is_ref() => {
// let h1 = self.get_value();
match r.get_tag() { match r.get_tag() {
RefTag::StackCell => Some(Ordering::Less), RefTag::StackCell => Some(Ordering::Less),
_ => { _ => {
@@ -77,52 +74,157 @@ impl PartialOrd<Ref> for HeapCellValue {
} }
} }
#[derive(Debug, Clone, Copy, Eq, Hash, Ord, PartialEq, PartialOrd)] #[derive(BitfieldSpecifier, Copy, Clone, Debug, PartialEq)]
pub enum IndexPtr { #[bits = 7]
DynamicUndefined, // a predicate, declared as dynamic, whose location in code is as yet undefined. pub enum IndexPtrTag {
DynamicIndex(usize), DynamicUndefined = 0b1000101, // a predicate, declared as dynamic, whose location in code is as yet undefined.
Index(usize), DynamicIndex = 0b1000110,
Undefined, Index = 0b1000111,
Undefined = 0b1001000,
} }
#[derive(Debug, Clone, Ord, PartialOrd, Eq, PartialEq)] #[bitfield]
pub struct CodeIndex(pub(crate) Rc<Cell<IndexPtr>>); #[derive(Debug, Clone, Copy, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct IndexPtr {
pub p: B56,
#[allow(unused)] m: bool,
pub tag: IndexPtrTag,
}
impl IndexPtr {
#[inline(always)]
pub(crate) fn dynamic_undefined() -> Self {
IndexPtr::new()
.with_p(0)
.with_m(false)
.with_tag(IndexPtrTag::DynamicUndefined)
}
#[inline(always)]
pub(crate) fn undefined() -> Self {
IndexPtr::new()
.with_p(0)
.with_m(false)
.with_tag(IndexPtrTag::Undefined)
}
#[inline(always)]
pub(crate) fn dynamic_index(p: usize) -> Self {
IndexPtr::new()
.with_p(p as u64)
.with_m(false)
.with_tag(IndexPtrTag::DynamicIndex)
}
#[inline(always)]
pub(crate) fn index(p: usize) -> Self {
IndexPtr::new()
.with_p(p as u64)
.with_m(false)
.with_tag(IndexPtrTag::Index)
}
#[inline(always)]
pub(crate) fn is_undefined(&self) -> bool {
match self.tag() {
IndexPtrTag::Undefined => true,
_ => false,
}
}
#[inline(always)]
pub(crate) fn is_dynamic_undefined(&self) -> bool {
match self.tag() {
IndexPtrTag::DynamicUndefined => true,
_ => false,
}
}
}
#[derive(Debug, Clone, Copy, Ord, Hash, PartialOrd, Eq, PartialEq)]
pub struct CodeIndex(TypedArenaPtr<IndexPtr>);
const_assert!(std::mem::align_of::<CodeIndex>() == 8);
impl Deref for CodeIndex { impl Deref for CodeIndex {
type Target = Cell<IndexPtr>; type Target = TypedArenaPtr<IndexPtr>;
#[inline] #[inline(always)]
fn deref(&self) -> &Self::Target { fn deref(&self) -> &TypedArenaPtr<IndexPtr> {
self.0.deref() &self.0
}
}
impl DerefMut for CodeIndex {
#[inline(always)]
fn deref_mut(&mut self) -> &mut TypedArenaPtr<IndexPtr> {
&mut self.0
}
}
impl From<CodeIndex> for UntypedArenaPtr {
#[inline(always)]
fn from(ptr: CodeIndex) -> UntypedArenaPtr {
unsafe { std::mem::transmute(ptr.0.as_ptr()) }
}
}
impl From<UntypedArenaPtr> for CodeIndex {
#[inline(always)]
fn from(ptr: UntypedArenaPtr) -> CodeIndex {
CodeIndex(TypedArenaPtr::new(ptr.get_ptr() as *mut IndexPtr))
}
}
impl From<TypedArenaPtr<IndexPtr>> for CodeIndex {
#[inline(always)]
fn from(ptr: TypedArenaPtr<IndexPtr>) -> CodeIndex {
CodeIndex(ptr)
} }
} }
impl CodeIndex { impl CodeIndex {
#[inline] #[inline]
pub(super) fn new(ptr: IndexPtr) -> Self { pub(crate) fn new(ptr: IndexPtr, arena: &mut Arena) -> Self {
CodeIndex(Rc::new(Cell::new(ptr))) CodeIndex(arena_alloc!(ptr, arena))
} }
#[inline] #[inline(always)]
pub(crate) fn is_undefined(&self) -> bool { pub(crate) fn default(arena: &mut Arena) -> Self {
match self.0.get() { CodeIndex::new(IndexPtr::undefined(), arena)
IndexPtr::Undefined => true, // | &IndexPtr::DynamicUndefined => true,
_ => false,
}
} }
pub(crate) fn local(&self) -> Option<usize> { pub(crate) fn local(&self) -> Option<usize> {
match self.0.get() { match self.0.tag() {
IndexPtr::Index(i) => Some(i), IndexPtrTag::Index => Some(self.0.p() as usize),
IndexPtr::DynamicIndex(i) => Some(i), IndexPtrTag::DynamicIndex => Some(self.0.p() as usize),
_ => None, _ => None,
} }
} }
}
impl Default for CodeIndex { #[inline(always)]
fn default() -> Self { pub(crate) fn get(&self) -> IndexPtr {
CodeIndex(Rc::new(Cell::new(IndexPtr::Undefined))) *self.0.deref()
}
#[inline(always)]
pub(crate) fn set(&mut self, value: IndexPtr) {
*self.0.deref_mut() = value;
}
#[inline(always)]
pub(crate) fn get_tag(self) -> IndexPtrTag {
self.0.tag()
}
#[inline(always)]
pub(crate) fn replace(&mut self, value: IndexPtr) -> IndexPtr {
std::mem::replace(self.0.deref_mut(), value)
}
#[inline(always)]
pub(crate) fn as_ptr(&self) -> *const IndexPtr {
self.0.as_ptr()
} }
} }
@@ -269,19 +371,22 @@ impl IndexStore {
module: Atom, module: Atom,
) -> Option<CodeIndex> { ) -> Option<CodeIndex> {
if module == atom!("user") { if module == atom!("user") {
match ClauseType::from(name, arity) { /*match ClauseType::from(name, arity) {
ClauseType::Named(arity, name, _) => self.code_dir.get(&(name, arity)).cloned(), ClauseType::Named(arity, name, _) => */
_ => None, self.code_dir.get(&(name, arity)).cloned()
} /* _ => None,
}*/
} else { } else {
self.modules self.modules
.get(&module) .get(&module)
.and_then(|module| match ClauseType::from(name, arity) { .and_then(|module|/* |module| match ClauseType::from(name, arity) {
ClauseType::Named(arity, name, _) => { ClauseType::Named(arity, name, _) => { */
module.code_dir.get(&(name, arity)).cloned() module.code_dir.get(&(name, arity)).cloned()
/*
} }
_ => None, _ => None,
}) } */
)
} }
} }

View File

@@ -75,6 +75,7 @@ pub struct MachineState {
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) 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) lifted_heap: Heap, pub(super) lifted_heap: Heap,
pub(super) interms: Vec<Number>, // intermediate numbers. pub(super) interms: Vec<Number>, // intermediate numbers.
// locations of cleaners, cut points, the previous block. for setup_call_cleanup. // locations of cleaners, cut points, the previous block. for setup_call_cleanup.
@@ -113,6 +114,7 @@ impl fmt::Debug for MachineState {
.field("hb", &self.hb) .field("hb", &self.hb)
.field("block", &self.block) .field("block", &self.block)
.field("ball", &self.ball) .field("ball", &self.ball)
.field("ball_stack", &self.ball_stack)
.field("lifted_heap", &self.lifted_heap) .field("lifted_heap", &self.lifted_heap)
.field("interms", &self.interms) .field("interms", &self.interms)
.field("flags", &self.flags) .field("flags", &self.flags)
@@ -418,6 +420,17 @@ impl MachineState {
} }
} }
} }
(HeapCellValueTag::Str, s) => {
let (name, arity) = cell_as_atom_cell!(self.heap[s])
.get_name_and_arity();
if arity == 0 {
if let Some(c) = name.as_char() {
chars.push(c);
continue;
}
}
}
_ => { _ => {
} }
); );
@@ -454,6 +467,37 @@ impl MachineState {
self.b0 = self.b; self.b0 = self.b;
} }
#[inline(always)]
pub fn neck_cut(&mut self) {
let b = self.b;
let b0 = self.b0;
if b > b0 {
self.b = b0;
if b > self.e {
self.stack.truncate(b);
}
}
}
// Safety: the atom_tbl lives for the lifetime of the machine, as does the helper, so the ptr
// will always be valid.
pub fn read_term_from_user_input(&mut self, stream: Stream, indices: &mut IndexStore) -> CallResult {
let atoms_ptr = (&self.atom_tbl.table) as *const indexmap::IndexSet<Atom>;
if let Stream::Readline(ptr) = stream {
unsafe {
let readline = ptr.as_ptr().as_mut().unwrap();
readline.set_atoms_for_completion(atoms_ptr);
let ret = self.read_term(stream, indices);
return ret
}
}
unreachable!("Stream must be a Stream::Readline(_)")
}
pub fn read_term(&mut self, stream: Stream, indices: &mut IndexStore) -> CallResult { pub fn read_term(&mut self, stream: Stream, indices: &mut IndexStore) -> CallResult {
fn push_var_eq_functors<'a>( fn push_var_eq_functors<'a>(
heap: &mut Heap, heap: &mut Heap,
@@ -494,7 +538,7 @@ impl MachineState {
loop { loop {
match self.read(stream, &indices.op_dir) { match self.read(stream, &indices.op_dir) {
Ok(term_write_result) => { Ok(mut term_write_result) => {
let heap_loc = read_heap_cell!(self.heap[term_write_result.heap_loc], let heap_loc = read_heap_cell!(self.heap[term_write_result.heap_loc],
(HeapCellValueTag::PStr | HeapCellValueTag::PStrOffset) => { (HeapCellValueTag::PStr | HeapCellValueTag::PStrOffset) => {
pstr_loc_as_cell!(term_write_result.heap_loc) pstr_loc_as_cell!(term_write_result.heap_loc)
@@ -526,6 +570,10 @@ impl MachineState {
} }
} }
for var in term_write_result.var_dict.values_mut() {
*var = heap_bound_deref(&self.heap, *var);
}
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(|(_, binding)| { term_write_result.var_dict.iter().filter(|(_, binding)| {
@@ -585,7 +633,7 @@ impl MachineState {
return Ok(unify_fn!(*self, var_names_offset, var_names_addr)); return Ok(unify_fn!(*self, var_names_offset, var_names_addr));
} }
Err(err) => { Err(err) => {
if let ParserError::UnexpectedEOF = err { if let CompilationError::ParserError(ParserError::UnexpectedEOF) = err {
self.eof_action( self.eof_action(
self.registers[2], self.registers[2],
stream, stream,
@@ -641,7 +689,25 @@ impl MachineState {
continue; continue;
} }
var_names.insert(var, Rc::new(cell_as_atom!(atom).as_str().to_owned())); read_heap_cell!(atom,
(HeapCellValueTag::Char, c) => {
var_names.insert(var, Rc::new(c.to_string()));
}
(HeapCellValueTag::Atom, (name, _arity)) => {
debug_assert_eq!(_arity, 0);
var_names.insert(var, Rc::new(name.as_str().to_owned()));
}
(HeapCellValueTag::Str, s) => {
let (name, arity) = cell_as_atom_cell!(self.heap[s])
.get_name_and_arity();
debug_assert_eq!(arity, 0);
var_names.insert(var, Rc::new(name.as_str().to_owned()));
}
_ => {
unreachable!();
}
);
} }
} }
_ => { _ => {
@@ -649,34 +715,64 @@ impl MachineState {
); );
} }
let ignore_ops = read_heap_cell!(ignore_ops,
(HeapCellValueTag::Atom, (name, _arity)) => {
name == atom!("true")
}
(HeapCellValueTag::Str, s) => {
let (name, arity) = cell_as_atom_cell!(self.heap[s])
.get_name_and_arity();
debug_assert_eq!(arity, 0);
name == atom!("true")
}
_ => {
unreachable!()
}
);
let numbervars = read_heap_cell!(numbervars,
(HeapCellValueTag::Atom, (name, _arity)) => {
name == atom!("true")
}
(HeapCellValueTag::Str, s) => {
let (name, arity) = cell_as_atom_cell!(self.heap[s])
.get_name_and_arity();
debug_assert_eq!(arity, 0);
name == atom!("true")
}
_ => {
unreachable!()
}
);
let quoted = read_heap_cell!(quoted,
(HeapCellValueTag::Atom, (name, _arity)) => {
name == atom!("true")
}
(HeapCellValueTag::Str, s) => {
let (name, arity) = cell_as_atom_cell!(self.heap[s])
.get_name_and_arity();
debug_assert_eq!(arity, 0);
name == atom!("true")
}
_ => {
unreachable!()
}
);
let mut printer = HCPrinter::new( let mut printer = HCPrinter::new(
&mut self.heap, &mut self.heap,
&mut self.arena,
op_dir, op_dir,
PrinterOutputter::new(), PrinterOutputter::new(),
term_to_be_printed, term_to_be_printed,
); );
if let HeapCellValueTag::Atom = ignore_ops.get_tag() { printer.ignore_ops = ignore_ops;
let name = cell_as_atom!(ignore_ops); printer.numbervars = numbervars;
printer.ignore_ops = name == atom!("true"); printer.quoted = quoted;
} else {
unreachable!();
}
if let HeapCellValueTag::Atom = numbervars.get_tag() {
let name = cell_as_atom!(numbervars);
printer.numbervars = name == atom!("true");
} else {
unreachable!();
}
if let HeapCellValueTag::Atom = quoted.get_tag() {
let name = cell_as_atom!(quoted);
printer.quoted = name == atom!("true");
} else {
unreachable!();
}
match Number::try_from(max_depth) { match Number::try_from(max_depth) {
Ok(Number::Fixnum(n)) => { Ok(Number::Fixnum(n)) => {

File diff suppressed because it is too large Load Diff

View File

@@ -39,14 +39,14 @@ impl MockWAM {
pub fn write_parsed_term_to_heap( pub fn write_parsed_term_to_heap(
&mut self, &mut self,
input_stream: Stream, input_stream: Stream,
) -> Result<TermWriteResult, ParserError> { ) -> Result<TermWriteResult, CompilationError> {
self.machine_st.read(input_stream, &self.op_dir) self.machine_st.read(input_stream, &self.op_dir)
} }
pub fn parse_and_write_parsed_term_to_heap( pub fn parse_and_write_parsed_term_to_heap(
&mut self, &mut self,
term_string: &'static str, term_string: &'static str,
) -> Result<TermWriteResult, ParserError> { ) -> Result<TermWriteResult, CompilationError> {
let stream = Stream::from_static_string(term_string, &mut self.machine_st.arena); let stream = Stream::from_static_string(term_string, &mut self.machine_st.arena);
self.write_parsed_term_to_heap(stream) self.write_parsed_term_to_heap(stream)
} }
@@ -54,14 +54,13 @@ impl MockWAM {
pub fn parse_and_print_term( pub fn parse_and_print_term(
&mut self, &mut self,
term_string: &'static str, term_string: &'static str,
) -> Result<String, ParserError> { ) -> Result<String, CompilationError> {
let term_write_result = self.parse_and_write_parsed_term_to_heap(term_string)?; let term_write_result = self.parse_and_write_parsed_term_to_heap(term_string)?;
print_heap_terms(self.machine_st.heap.iter(), term_write_result.heap_loc); print_heap_terms(self.machine_st.heap.iter(), term_write_result.heap_loc);
let mut printer = HCPrinter::new( let mut printer = HCPrinter::new(
&mut self.machine_st.heap, &mut self.machine_st.heap,
&mut self.machine_st.arena,
&self.op_dir, &self.op_dir,
PrinterOutputter::new(), PrinterOutputter::new(),
heap_loc_as_cell!(term_write_result.heap_loc), heap_loc_as_cell!(term_write_result.heap_loc),
@@ -168,7 +167,7 @@ pub fn all_cells_marked_and_unforwarded(heap: &[HeapCellValue]) {
idx idx
); );
assert!( assert!(
cell.get_forwarding_bit() != Some(true), !cell.get_forwarding_bit(),
"cell {:?} at index {} is forwarded", "cell {:?} at index {} is forwarded",
cell, cell,
idx idx
@@ -187,7 +186,7 @@ pub fn all_cells_unmarked(heap: &Heap) {
); );
assert!( assert!(
cell.get_forwarding_bit() != Some(true), !cell.get_forwarding_bit(),
"cell {:?} at index {} is still forwarded", "cell {:?} at index {} is still forwarded",
cell, cell,
idx idx
@@ -200,7 +199,7 @@ pub(crate) fn write_parsed_term_to_heap(
machine_st: &mut MachineState, machine_st: &mut MachineState,
input_stream: Stream, input_stream: Stream,
op_dir: &OpDir, op_dir: &OpDir,
) -> Result<TermWriteResult, ParserError> { ) -> Result<TermWriteResult, CompilationError> {
machine_st.read(input_stream, op_dir) machine_st.read(input_stream, op_dir)
} }
@@ -209,7 +208,7 @@ pub(crate) fn parse_and_write_parsed_term_to_heap(
machine_st: &mut MachineState, machine_st: &mut MachineState,
term_string: &'static str, term_string: &'static str,
op_dir: &OpDir, op_dir: &OpDir,
) -> Result<TermWriteResult, ParserError> { ) -> Result<TermWriteResult, CompilationError> {
let stream = Stream::from_static_string(term_string, &mut machine_st.arena); let stream = Stream::from_static_string(term_string, &mut machine_st.arena);
write_parsed_term_to_heap(machine_st, stream, op_dir) write_parsed_term_to_heap(machine_st, stream, op_dir)
} }
@@ -224,6 +223,11 @@ impl Machine {
let user_output = Stream::from_owned_string("".to_owned(), &mut machine_st.arena); let user_output = Stream::from_owned_string("".to_owned(), &mut machine_st.arena);
let user_error = Stream::stderr(&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 { let mut wam = Machine {
machine_st, machine_st,
indices: IndexStore::new(), indices: IndexStore::new(),
@@ -232,6 +236,7 @@ impl Machine {
user_output, user_output,
user_error, user_error,
load_contexts: vec![], load_contexts: vec![],
runtime
}; };
let mut lib_path = current_dir(); let mut lib_path = current_dir();
@@ -266,6 +271,7 @@ impl Machine {
if let Some(ref mut builtins) = wam.indices.modules.get_mut(&atom!("builtins")) { if let Some(ref mut builtins) = wam.indices.modules.get_mut(&atom!("builtins")) {
load_module( load_module(
&mut wam.machine_st,
&mut wam.indices.code_dir, &mut wam.indices.code_dir,
&mut wam.indices.op_dir, &mut wam.indices.op_dir,
&mut wam.indices.meta_predicates, &mut wam.indices.meta_predicates,
@@ -291,6 +297,7 @@ impl Machine {
if let Some(loader) = wam.indices.modules.get(&atom!("loader")) { if let Some(loader) = wam.indices.modules.get(&atom!("loader")) {
load_module( load_module(
&mut wam.machine_st,
&mut wam.indices.code_dir, &mut wam.indices.code_dir,
&mut wam.indices.op_dir, &mut wam.indices.op_dir,
&mut wam.indices.meta_predicates, &mut wam.indices.meta_predicates,
@@ -603,7 +610,6 @@ mod tests {
#[test] #[test]
fn test_term_compare() { fn test_term_compare() {
use ordered_float::OrderedFloat;
use std::cmp::Ordering; use std::cmp::Ordering;
let mut wam = MachineState::new(); let mut wam = MachineState::new();
@@ -771,9 +777,7 @@ mod tests {
Some(Ordering::Greater) Some(Ordering::Greater)
); );
let one_p_one = typed_arena_ptr_as_cell!( let one_p_one = HeapCellValue::from(float_alloc!(1.1, &mut wam.arena));
arena_alloc!(OrderedFloat(1.1), &mut wam.arena)
);
assert_eq!( assert_eq!(
compare_term_test!( compare_term_test!(

View File

@@ -1,3 +1,4 @@
pub mod args;
pub mod arithmetic_ops; pub mod arithmetic_ops;
pub mod attributed_variables; pub mod attributed_variables;
pub mod code_walker; pub mod code_walker;
@@ -21,10 +22,12 @@ pub mod streams;
pub mod system_calls; pub mod system_calls;
pub mod term_stream; pub mod term_stream;
use crate::arena::*;
use crate::arithmetic::*; use crate::arithmetic::*;
use crate::atom_table::*; use crate::atom_table::*;
use crate::forms::*; use crate::forms::*;
use crate::instructions::*; use crate::instructions::*;
use crate::machine::args::*;
use crate::machine::compile::*; use crate::machine::compile::*;
use crate::machine::copier::*; use crate::machine::copier::*;
use crate::machine::heap::*; use crate::machine::heap::*;
@@ -46,6 +49,7 @@ use std::cmp::Ordering;
use std::env; use std::env;
use std::path::PathBuf; use std::path::PathBuf;
use std::sync::atomic::AtomicBool; use std::sync::atomic::AtomicBool;
use tokio::runtime::Runtime;
lazy_static! { lazy_static! {
pub static ref INTERRUPT: AtomicBool = AtomicBool::new(false); pub static ref INTERRUPT: AtomicBool = AtomicBool::new(false);
@@ -60,6 +64,7 @@ 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,
} }
#[derive(Debug)] #[derive(Debug)]
@@ -156,6 +161,24 @@ pub(crate) fn import_builtin_impls(code_dir: &CodeDir, builtins: &mut Module) {
} }
} }
#[inline]
pub(crate) fn get_structure_index(value: HeapCellValue) -> Option<CodeIndex> {
read_heap_cell!(value,
(HeapCellValueTag::Cons, cons_ptr) => {
match_untyped_arena_ptr!(cons_ptr,
(ArenaHeaderTag::IndexPtr, ip) => {
return Some(CodeIndex::from(ip));
}
_ => {}
);
}
_ => {
}
);
None
}
impl Machine { impl Machine {
#[inline] #[inline]
pub fn prelude_view_and_machine_st(&mut self) -> (MachinePreludeView, &mut MachineState) { pub fn prelude_view_and_machine_st(&mut self) -> (MachinePreludeView, &mut MachineState) {
@@ -216,6 +239,7 @@ impl Machine {
if let Some(toplevel) = self.indices.modules.get(&atom!("$toplevel")) { if let Some(toplevel) = self.indices.modules.get(&atom!("$toplevel")) {
load_module( load_module(
&mut self.machine_st,
&mut self.indices.code_dir, &mut self.indices.code_dir,
&mut self.indices.op_dir, &mut self.indices.op_dir,
&mut self.indices.meta_predicates, &mut self.indices.meta_predicates,
@@ -283,7 +307,7 @@ impl Machine {
} }
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) { 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);
@@ -291,7 +315,7 @@ impl Machine {
Some(src_code_index) => { Some(src_code_index) => {
let target_code_index = target_code_dir let target_code_index = target_code_dir
.entry(key) .entry(key)
.or_insert_with(|| CodeIndex::new(IndexPtr::Undefined)); .or_insert_with(|| CodeIndex::new(IndexPtr::undefined(), arena));
target_code_index.set(src_code_index.get()); target_code_index.set(src_code_index.get());
} }
@@ -307,6 +331,7 @@ impl Machine {
// Import loader's exports into the builtins module so they will be // Import loader's exports into the builtins module so they will be
// implicitly included in every further module. // implicitly included in every further module.
load_module( load_module(
&mut self.machine_st,
&mut builtins.code_dir, &mut builtins.code_dir,
&mut builtins.op_dir, &mut builtins.op_dir,
&mut builtins.meta_predicates, &mut builtins.meta_predicates,
@@ -327,10 +352,10 @@ 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); 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); 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 {
@@ -389,19 +414,26 @@ impl Machine {
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(key, CodeIndex::new(IndexPtr::Index(p + impls_offset))); self.indices.code_dir.insert(
key,
CodeIndex::new(IndexPtr::index(p + impls_offset), &mut self.machine_st.arena),
);
} }
} }
pub fn new() -> Self { pub fn new() -> Self {
use ref_thread_local::RefThreadLocal; use ref_thread_local::RefThreadLocal;
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); let user_input = Stream::stdin(&mut machine_st.arena, args.add_history);
let user_output = Stream::stdout(&mut machine_st.arena); let user_output = Stream::stdout(&mut machine_st.arena);
let user_error = Stream::stderr(&mut machine_st.arena); let user_error = Stream::stderr(&mut machine_st.arena);
let runtime = tokio::runtime::Runtime::new()
.unwrap();
let mut wam = Machine { let mut wam = Machine {
machine_st, machine_st,
indices: IndexStore::new(), indices: IndexStore::new(),
@@ -410,6 +442,7 @@ impl Machine {
user_output, user_output,
user_error, user_error,
load_contexts: vec![], load_contexts: vec![],
runtime,
}; };
let mut lib_path = current_dir(); let mut lib_path = current_dir();
@@ -444,6 +477,7 @@ impl Machine {
if let Some(builtins) = wam.indices.modules.get_mut(&atom!("builtins")) { if let Some(builtins) = wam.indices.modules.get_mut(&atom!("builtins")) {
load_module( load_module(
&mut wam.machine_st,
&mut wam.indices.code_dir, &mut wam.indices.code_dir,
&mut wam.indices.op_dir, &mut wam.indices.op_dir,
&mut wam.indices.meta_predicates, &mut wam.indices.meta_predicates,
@@ -469,6 +503,7 @@ impl Machine {
if let Some(loader) = wam.indices.modules.get(&atom!("loader")) { if let Some(loader) = wam.indices.modules.get(&atom!("loader")) {
load_module( load_module(
&mut wam.machine_st,
&mut wam.indices.code_dir, &mut wam.indices.code_dir,
&mut wam.indices.op_dir, &mut wam.indices.op_dir,
&mut wam.indices.meta_predicates, &mut wam.indices.meta_predicates,
@@ -655,18 +690,20 @@ impl Machine {
#[inline(always)] #[inline(always)]
fn try_call(&mut self, name: Atom, arity: usize, idx: IndexPtr) -> CallResult { fn try_call(&mut self, name: Atom, arity: usize, idx: IndexPtr) -> CallResult {
match idx { let compiled_tl_index = idx.p() as usize;
IndexPtr::DynamicUndefined => {
match idx.tag() {
IndexPtrTag::DynamicUndefined => {
self.machine_st.fail = true; self.machine_st.fail = true;
} }
IndexPtr::Undefined => { IndexPtrTag::Undefined => {
return Err(self.machine_st.throw_undefined_error(name, arity)); return Err(self.machine_st.throw_undefined_error(name, arity));
} }
IndexPtr::DynamicIndex(compiled_tl_index) => { IndexPtrTag::DynamicIndex => {
self.machine_st.dynamic_mode = FirstOrNext::First; self.machine_st.dynamic_mode = FirstOrNext::First;
self.machine_st.call_at_index(arity, compiled_tl_index); self.machine_st.call_at_index(arity, compiled_tl_index);
} }
IndexPtr::Index(compiled_tl_index) => { IndexPtrTag::Index => {
self.machine_st.call_at_index(arity, compiled_tl_index); self.machine_st.call_at_index(arity, compiled_tl_index);
} }
} }
@@ -676,18 +713,20 @@ impl Machine {
#[inline(always)] #[inline(always)]
fn try_execute(&mut self, name: Atom, arity: usize, idx: IndexPtr) -> CallResult { fn try_execute(&mut self, name: Atom, arity: usize, idx: IndexPtr) -> CallResult {
match idx { let compiled_tl_index = idx.p() as usize;
IndexPtr::DynamicUndefined => {
match idx.tag() {
IndexPtrTag::DynamicUndefined => {
self.machine_st.fail = true; self.machine_st.fail = true;
} }
IndexPtr::Undefined => { IndexPtrTag::Undefined => {
return Err(self.machine_st.throw_undefined_error(name, arity)); return Err(self.machine_st.throw_undefined_error(name, arity));
} }
IndexPtr::DynamicIndex(compiled_tl_index) => { IndexPtrTag::DynamicIndex => {
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);
} }
IndexPtr::Index(compiled_tl_index) => { IndexPtrTag::Index => {
self.machine_st.execute_at_index(arity, compiled_tl_index) self.machine_st.execute_at_index(arity, compiled_tl_index)
} }
} }
@@ -826,12 +865,12 @@ impl Machine {
self.machine_st.heap[h] = heap_loc_as_cell!(h); self.machine_st.heap[h] = heap_loc_as_cell!(h);
} }
TrailEntryTag::TrailedAttrVarListLink => { TrailEntryTag::TrailedAttrVarListLink => {
let value = HeapCellValue::from_bytes( let l = self.machine_st.trail[i + 1].get_value() as usize;
self.machine_st.trail[i + 1].into_bytes()
);
if value.get_value() < self.machine_st.hb { if l < self.machine_st.hb {
self.machine_st.heap[h] = value; self.machine_st.heap[h] = list_loc_as_cell!(l);
} else {
self.machine_st.heap[h] = heap_loc_as_cell!(h);
} }
} }
TrailEntryTag::TrailedBlackboardEntry => { TrailEntryTag::TrailedBlackboardEntry => {

View File

@@ -109,6 +109,12 @@ impl<'a> HeapPStrIter<'a> {
self.brent_st.num_steps() self.brent_st.num_steps()
} }
#[inline(always)]
pub fn chars(mut self) -> PStrCharsIter<'a> {
let item = self.next();
PStrCharsIter { iter: self, item }
}
pub fn compare_pstr_to_string(&mut self, s: &str) -> Option<PStrPrefixCmpResult> { pub fn compare_pstr_to_string(&mut self, s: &str) -> Option<PStrPrefixCmpResult> {
let mut result = PStrPrefixCmpResult { let mut result = PStrPrefixCmpResult {
focus: self.brent_st.hare, focus: self.brent_st.hare,
@@ -116,7 +122,12 @@ impl<'a> HeapPStrIter<'a> {
prefix_len: 0, prefix_len: 0,
}; };
while let Some(iteratee) = self.next() { let mut final_result = None;
while let Some(PStrIterStep { iteratee, next_hare }) = self.step(self.brent_st.hare) {
self.brent_st.hare = next_hare;
self.focus = self.heap[iteratee.focus()];
result.focus = iteratee.focus(); result.focus = iteratee.focus();
result.offset = iteratee.offset(); result.offset = iteratee.offset();
@@ -130,7 +141,8 @@ impl<'a> HeapPStrIter<'a> {
result.offset += c1.len_utf8(); result.offset += c1.len_utf8();
} }
} else { } else {
return Some(result); final_result = Some(result);
break;
} }
} }
PStrIteratee::PStrSegment(_, pstr_atom, n) => { PStrIteratee::PStrSegment(_, pstr_atom, n) => {
@@ -149,7 +161,8 @@ impl<'a> HeapPStrIter<'a> {
result.prefix_len += s.len(); result.prefix_len += s.len();
result.offset += s.len(); result.offset += s.len();
return Some(result); final_result = Some(result);
break;
} else { } else {
return None; return None;
} }
@@ -157,17 +170,27 @@ impl<'a> HeapPStrIter<'a> {
} }
if s.len() == result.prefix_len { if s.len() == result.prefix_len {
return Some(result); final_result = Some(result);
break;
} }
} }
Some(result) if let Some(result) = &final_result {
if self.at_string_terminator() {
self.focus = empty_list_as_cell!();
self.brent_st.hare = result.focus;
} else {
read_heap_cell!(self.heap[result.focus],
(HeapCellValueTag::Lis | HeapCellValueTag::Str) => {
self.focus = self.heap[self.brent_st.hare];
}
_ => {
}
);
}
} }
#[inline] final_result
pub fn chars(mut self) -> PStrCharsIter<'a> {
let item = self.next();
PStrCharsIter { iter: self, item }
} }
fn walk_hare_to_cycle_end(&mut self) { fn walk_hare_to_cycle_end(&mut self) {
@@ -223,7 +246,13 @@ impl<'a> HeapPStrIter<'a> {
return name == atom!(".") && arity == 2; return name == atom!(".") && arity == 2;
} }
(HeapCellValueTag::Lis, h) => { (HeapCellValueTag::Lis, h) => {
return read_heap_cell!(self.heap[h], let value = self.heap[h];
let value = heap_bound_store(
self.heap,
heap_bound_deref(self.heap, 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()
} }
@@ -309,7 +338,7 @@ impl<'a> HeapPStrIter<'a> {
}) })
} else { } else {
None None
} };
} }
(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])
@@ -362,7 +391,7 @@ impl<'a> HeapPStrIter<'a> {
self.focus = self.heap[iteratee.focus()]; self.focus = self.heap[iteratee.focus()];
if self.focus.is_string_terminator(self.heap) { if self.at_string_terminator() {
self.focus = empty_list_as_cell!(); self.focus = empty_list_as_cell!();
self.brent_st.hare = iteratee.focus(); self.brent_st.hare = iteratee.focus();
@@ -533,7 +562,6 @@ pub fn compare_pstr_prefixes<'a>(
#[inline(always)] #[inline(always)]
fn step(iter: &mut HeapPStrIter, hare: usize) -> Option<PStrIterStep> { fn step(iter: &mut HeapPStrIter, hare: usize) -> Option<PStrIterStep> {
let result = iter.step(hare); let result = iter.step(hare);
iter.focus = iter.heap[hare]; iter.focus = iter.heap[hare];
if iter.focus.is_string_terminator(iter.heap) { if iter.focus.is_string_terminator(iter.heap) {
@@ -622,7 +650,7 @@ pub fn compare_pstr_prefixes<'a>(
if let Some(c1) = pstr.as_str_from(n).chars().next() { if let Some(c1) = pstr.as_str_from(n).chars().next() {
if c1 != c2 { if c1 != c2 {
return PStrCmpResult::Ordered(c2.cmp(&c1)); return PStrCmpResult::Ordered(c1.cmp(&c2));
} }
let n1 = n + c1.len_utf8(); let n1 = n + c1.len_utf8();

View File

@@ -1,4 +1,5 @@
use crate::atom_table::*; use crate::atom_table::*;
use crate::codegen::CodeGenSettings;
use crate::forms::*; use crate::forms::*;
use crate::instructions::*; use crate::instructions::*;
use crate::iterators::*; use crate::iterators::*;
@@ -112,30 +113,6 @@ fn setup_predicate_indicator(term: &mut Term) -> Result<PredicateKey, Compilatio
} }
} }
/*
fn setup_scoped_predicate_indicator(term: &mut Term) -> Result<ScopedPredicateKey, CompilationError>
{
match term {
Term::Clause(_, ref name, ref mut terms, Some(_))
if name.as_str() == ":" && terms.len() == 2 =>
{
let mut predicate_indicator = *terms.pop().unwrap();
let module_name = *terms.pop().unwrap();
let module_name = module_name
.to_constant()
.and_then(|c| c.to_atom())
.ok_or(CompilationError::InvalidModuleExport)?;
let key = setup_predicate_indicator(&mut predicate_indicator)?;
Ok((module_name, key))
}
_ => Err(CompilationError::InvalidModuleExport),
}
}
*/
fn setup_module_export( fn setup_module_export(
mut term: Term, mut term: Term,
atom_tbl: &mut AtomTable, atom_tbl: &mut AtomTable,
@@ -279,6 +256,7 @@ fn setup_qualified_import(
* - * -
* ? * ?
*/ */
fn setup_meta_predicate<'a, LS: LoadState<'a>>( fn setup_meta_predicate<'a, LS: LoadState<'a>>(
mut terms: Vec<Term>, mut terms: Vec<Term>,
loader: &mut Loader<'a, LS>, loader: &mut Loader<'a, LS>,
@@ -296,6 +274,7 @@ fn setup_meta_predicate<'a, LS: LoadState<'a>>(
atom!("+") => MetaSpec::Plus, atom!("+") => MetaSpec::Plus,
atom!("-") => MetaSpec::Minus, atom!("-") => MetaSpec::Minus,
atom!("?") => MetaSpec::Either, atom!("?") => MetaSpec::Either,
atom!(":") => MetaSpec::Colon,
_ => return Err(CompilationError::InvalidMetaPredicateDecl), _ => return Err(CompilationError::InvalidMetaPredicateDecl),
}; };
@@ -491,14 +470,142 @@ pub(super) fn setup_declaration<'a, LS: LoadState<'a>>(
} }
} }
fn build_meta_predicate_clause<'a, LS: LoadState<'a>>(
loader: &mut Loader<'a, LS>,
module_name: Atom,
terms: Vec<Term>,
meta_specs: Vec<MetaSpec>,
) -> Vec<Term> {
let mut arg_terms = Vec::with_capacity(terms.len());
for (term, meta_spec) in terms.into_iter().zip(meta_specs.iter()) {
if let MetaSpec::RequiresExpansionWithArgument(supp_args) = meta_spec {
if let Some(name) = term.name() {
if name == atom!("$call") {
arg_terms.push(term);
continue;
}
let arity = term.arity();
fn get_qualified_name(
module_term: &Term,
qualified_term: &Term,
) -> Option<(Atom, Atom)> {
if let Term::Literal(_, Literal::Atom(module_name)) = module_term {
if let Some(name) = qualified_term.name() {
return Some((*module_name, name));
}
}
None
}
fn identity_fn(_module_name: Atom, term: Term) -> Term {
term
}
fn tag_with_module_name(module_name: Atom, term: Term) -> Term {
Term::Clause(Cell::default(), atom!(":"), vec![
Term::Literal(Cell::default(), Literal::Atom(module_name)),
term
])
}
let process_term: fn(Atom, Term) -> Term;
let (module_name, key, term) = match term {
Term::Clause(cell, atom!(":"), mut terms) if terms.len() == 2 => {
if let Some((module_name, name)) = get_qualified_name(&terms[0], &terms[1]) {
process_term = tag_with_module_name;
(module_name, (name, terms[1].arity() + supp_args), terms.pop().unwrap())
} else {
arg_terms.push(Term::Clause(cell, atom!(":"), terms));
continue;
}
}
term => {
process_term = identity_fn;
(module_name, (name, arity + supp_args), term)
}
};
let term = match term {
Term::Clause(cell, name, mut terms) => {
if let Some(Term::Literal(_, Literal::CodeIndex(_))) = terms.last() {
arg_terms.push(process_term(
module_name,
Term::Clause(cell, name, terms),
));
continue;
}
let idx = loader.get_or_insert_qualified_code_index(module_name, key);
terms.push(Term::Literal(Cell::default(), Literal::CodeIndex(idx)));
process_term(module_name, Term::Clause(cell, name, terms))
}
Term::Literal(cell, Literal::Atom(name)) => {
let idx = loader.get_or_insert_qualified_code_index(module_name, key);
process_term(module_name, Term::Clause(
cell,
name,
vec![Term::Literal(Cell::default(), Literal::CodeIndex(idx))],
))
}
term => term,
};
arg_terms.push(term);
continue;
}
}
arg_terms.push(term);
}
arg_terms
}
#[inline] #[inline]
fn clause_to_query_term<'a, LS: LoadState<'a>>( fn clause_to_query_term<'a, LS: LoadState<'a>>(
loader: &mut Loader<'a, LS>, loader: &mut Loader<'a, LS>,
name: Atom, name: Atom,
terms: Vec<Term>, mut terms: Vec<Term>,
call_policy: CallPolicy,
) -> QueryTerm { ) -> QueryTerm {
let ct = loader.get_clause_type(name, terms.len()); if let Some(Term::Literal(_, Literal::CodeIndex(_))) = terms.last() {
QueryTerm::Clause(Cell::default(), ct, terms, false) // supplementary code vector indices are unnecessary for
// root-level clauses.
terms.pop();
}
let mut ct = loader.get_clause_type(name, terms.len());
if let ClauseType::Named(arity, name, idx) = ct {
if let Some(meta_specs) = loader.get_meta_specs(name, arity).cloned() {
let module_name = loader.payload.compilation_target.module_name();
let terms = build_meta_predicate_clause(
loader,
module_name,
terms,
meta_specs,
);
return QueryTerm::Clause(
Cell::default(),
ClauseType::Named(arity, name, idx),
terms,
call_policy,
);
}
ct = ClauseType::Named(arity, name, idx);
}
QueryTerm::Clause(Cell::default(), ct, terms, call_policy)
} }
#[inline] #[inline]
@@ -506,32 +613,41 @@ fn qualified_clause_to_query_term<'a, LS: LoadState<'a>>(
loader: &mut Loader<'a, LS>, loader: &mut Loader<'a, LS>,
module_name: Atom, module_name: Atom,
name: Atom, name: Atom,
terms: Vec<Term>, mut terms: Vec<Term>,
call_policy: CallPolicy,
) -> QueryTerm { ) -> QueryTerm {
let ct = loader.get_qualified_clause_type(module_name, name, terms.len()); if let Some(Term::Literal(_, Literal::CodeIndex(_))) = terms.last() {
QueryTerm::Clause(Cell::default(), ct, terms, false) // supplementary code vector indices are unnecessary for
// root-level clauses.
terms.pop();
}
let mut ct = loader.get_qualified_clause_type(module_name, name, terms.len());
if let ClauseType::Named(arity, name, idx) = ct {
if let Some(meta_specs) = loader.get_meta_specs(name, arity).cloned() {
let terms = build_meta_predicate_clause(
loader,
module_name,
terms,
meta_specs,
);
return QueryTerm::Clause(
Cell::default(),
ClauseType::Named(arity, name, idx),
terms,
call_policy,
);
}
ct = ClauseType::Named(arity, name, idx);
}
QueryTerm::Clause(Cell::default(), ct, terms, call_policy)
} }
#[derive(Debug)] fn compute_head(term: &Term) -> Vec<Term> {
pub(crate) struct Preprocessor {
queue: VecDeque<VecDeque<Term>>,
}
impl Preprocessor {
pub(super) fn new() -> Self {
Preprocessor {
queue: VecDeque::new(),
}
}
fn setup_fact(&mut self, term: Term) -> Result<Term, CompilationError> {
match term {
Term::Clause(..) | Term::Literal(_, Literal::Atom(..)) => Ok(term),
_ => Err(CompilationError::InadmissibleFact),
}
}
fn compute_head(&self, term: &Term) -> Vec<Term> {
let mut vars = IndexSet::new(); let mut vars = IndexSet::new();
for term in post_order_iter(term) { for term in post_order_iter(term) {
@@ -544,29 +660,29 @@ impl Preprocessor {
vars.into_iter() vars.into_iter()
.map(|v| Term::Var(Cell::default(), v)) .map(|v| Term::Var(Cell::default(), v))
.collect() .collect()
} }
fn fabricate_rule_body(&self, vars: &Vec<Term>, body_term: Term) -> Term { pub(crate) fn build_rule_body(vars: &[Term], body_term: Term) -> Term {
let head_term = Term::Clause(Cell::default(), atom!(""), vars.clone()); let head_term = Term::Clause(Cell::default(), atom!(""), vars.iter().cloned().collect());
let rule = vec![head_term, body_term]; let rule = vec![head_term, body_term];
Term::Clause(Cell::default(), atom!(":-"), rule) Term::Clause(Cell::default(), atom!(":-"), rule)
} }
// the terms form the body of the rule. We create a head, by // the terms form the body of the rule. We create a head, by
// gathering variables from the body of terms and recording them // gathering variables from the body of terms and recording them
// in the head clause. // in the head clause.
fn fabricate_rule(&self, body_term: Term) -> (JumpStub, VecDeque<Term>) { fn build_rule(body_term: Term) -> (JumpStub, VecDeque<Term>) {
// collect the vars of body_term into a head, return the num_vars // collect the vars of body_term into a head, return the num_vars
// (the arity) as well. // (the arity) as well.
let vars = self.compute_head(&body_term); let vars = compute_head(&body_term);
let rule = self.fabricate_rule_body(&vars, body_term); let rule = build_rule_body(&vars, body_term);
(vars, VecDeque::from(vec![rule])) (vars, VecDeque::from(vec![rule]))
} }
fn fabricate_disjunct(&self, body_term: Term) -> (JumpStub, VecDeque<Term>) { fn build_disjunct(body_term: Term) -> (JumpStub, VecDeque<Term>) {
let vars = self.compute_head(&body_term); let vars = compute_head(&body_term);
let results = unfold_by_str(body_term, atom!(";")) let results = unfold_by_str(body_term, atom!(";"))
.into_iter() .into_iter()
.map(|term| { .map(|term| {
@@ -578,14 +694,14 @@ impl Preprocessor {
let term = subterms.pop().unwrap(); let term = subterms.pop().unwrap();
let clause = fold_by_str(subterms.into_iter(), term, atom!(",")); let clause = fold_by_str(subterms.into_iter(), term, atom!(","));
self.fabricate_rule_body(&vars, clause) build_rule_body(&vars, clause)
}) })
.collect(); .collect();
(vars, results) (vars, results)
} }
fn fabricate_if_then(&self, prec: Term, conq: Term) -> (JumpStub, VecDeque<Term>) { fn build_if_then(prec: Term, conq: Term) -> (JumpStub, VecDeque<Term>) {
let mut prec_seq = unfold_by_str(prec, atom!(",")); let mut prec_seq = unfold_by_str(prec, atom!(","));
let comma_sym = atom!(","); let comma_sym = atom!(",");
let cut_sym = Literal::Atom(atom!("!")); let cut_sym = Literal::Atom(atom!("!"));
@@ -608,7 +724,28 @@ impl Preprocessor {
vec![front_term, back_term], vec![front_term, back_term],
); );
self.fabricate_rule(fold_by_str(prec_seq.into_iter(), body_term, comma_sym)) build_rule(fold_by_str(prec_seq.into_iter(), body_term, comma_sym))
}
#[derive(Debug)]
pub(crate) struct Preprocessor {
queue: VecDeque<VecDeque<Term>>,
settings: CodeGenSettings,
}
impl Preprocessor {
pub(super) fn new(settings: CodeGenSettings) -> Self {
Preprocessor {
queue: VecDeque::new(),
settings,
}
}
fn setup_fact(&mut self, term: Term) -> Result<Term, CompilationError> {
match term {
Term::Clause(..) | Term::Literal(_, Literal::Atom(..)) => Ok(term),
_ => Err(CompilationError::InadmissibleFact),
}
} }
fn to_query_term<'a, LS: LoadState<'a>>( fn to_query_term<'a, LS: LoadState<'a>>(
@@ -621,7 +758,12 @@ impl Preprocessor {
if name == atom!("!") || name == atom!("blocked_!") { if name == atom!("!") || name == atom!("blocked_!") {
Ok(QueryTerm::BlockedCut) Ok(QueryTerm::BlockedCut)
} else { } else {
Ok(clause_to_query_term(loader, name, vec![])) Ok(clause_to_query_term(
loader,
name,
vec![],
self.settings.default_call_policy(),
))
} }
} }
Term::Literal(_, Literal::Char('!')) => Ok(QueryTerm::BlockedCut), Term::Literal(_, Literal::Char('!')) => Ok(QueryTerm::BlockedCut),
@@ -632,7 +774,7 @@ impl Preprocessor {
(atom!(";"), 2) => { (atom!(";"), 2) => {
let term = Term::Clause(r, name, terms); let term = Term::Clause(r, name, terms);
let (stub, clauses) = self.fabricate_disjunct(term); let (stub, clauses) = build_disjunct(term);
self.queue.push_back(clauses); self.queue.push_back(clauses);
Ok(QueryTerm::Jump(stub)) Ok(QueryTerm::Jump(stub))
@@ -641,7 +783,7 @@ impl Preprocessor {
let conq = terms.pop().unwrap(); let conq = terms.pop().unwrap();
let prec = terms.pop().unwrap(); let prec = terms.pop().unwrap();
let (stub, clauses) = self.fabricate_if_then(prec, conq); let (stub, clauses) = build_if_then(prec, conq);
self.queue.push_back(clauses); self.queue.push_back(clauses);
Ok(QueryTerm::Jump(stub)) Ok(QueryTerm::Jump(stub))
@@ -658,7 +800,7 @@ impl Preprocessor {
let terms = vec![prec, conq]; let terms = vec![prec, conq];
let term = Term::Clause(Cell::default(), atom!(";"), terms); let term = Term::Clause(Cell::default(), atom!(";"), terms);
let (stub, clauses) = self.fabricate_disjunct(term); let (stub, clauses) = build_disjunct(term);
debug_assert!(clauses.len() > 0); debug_assert!(clauses.len() > 0);
self.queue.push_back(clauses); self.queue.push_back(clauses);
@@ -685,6 +827,7 @@ impl Preprocessor {
module_name, module_name,
predicate_name, predicate_name,
vec![], vec![],
self.settings.default_call_policy(),
)), )),
( (
Term::Literal(_, Literal::Atom(module_name)), Term::Literal(_, Literal::Atom(module_name)),
@@ -694,22 +837,29 @@ impl Preprocessor {
module_name, module_name,
name, name,
terms, terms,
self.settings.default_call_policy()
)), )),
(module_name, predicate_name) => { (module_name, predicate_name) => {
terms.push(module_name); terms.push(module_name);
terms.push(predicate_name); terms.push(predicate_name);
Ok(clause_to_query_term(loader, name, terms)) Ok(clause_to_query_term(
loader,
atom!("call"),
vec![Term::Clause(r, name, terms)],
self.settings.default_call_policy(),
))
} }
} }
} }
_ => Ok(clause_to_query_term(loader, name, terms)), _ => Ok(clause_to_query_term(loader, name, terms,
self.settings.default_call_policy())),
}, },
Term::Var(..) => Ok(QueryTerm::Clause( Term::Var(..) => Ok(QueryTerm::Clause(
Cell::default(), Cell::default(),
ClauseType::CallN(1), ClauseType::CallN(1),
vec![term], vec![term],
false, self.settings.default_call_policy(),
)), )),
_ => Err(CompilationError::InadmissibleQueryTerm), _ => Err(CompilationError::InadmissibleQueryTerm),
} }
@@ -722,10 +872,10 @@ impl Preprocessor {
) -> Result<QueryTerm, CompilationError> { ) -> Result<QueryTerm, CompilationError> {
match term { match term {
Term::Clause(r, name, mut subterms) => { Term::Clause(r, name, mut subterms) => {
if subterms.len() == 1 && name == atom!("$call_with_default_policy") { if subterms.len() == 1 && name == atom!("$call_with_inference_counting") {
self.to_query_term(loader, subterms.pop().unwrap()) self.to_query_term(loader, subterms.pop().unwrap())
.map(|mut query_term| { .map(|mut query_term| {
query_term.set_default_caller(); query_term.set_call_policy(CallPolicy::Counted);
query_term query_term
}) })
} else { } else {

View File

@@ -10,8 +10,7 @@ project_attributes(QueryVars, AttrVars) :-
; E = error(evaluation_error((Module:project_attributes)/2), _) ; E = error(evaluation_error((Module:project_attributes)/2), _)
) -> ) ->
true true
; write_term('caught: ', [quoted(false)]), ; loader:write_error(E),
writeq(E),
nl nl
). ).
@@ -33,9 +32,9 @@ call_attribute_goals([Module|Modules], GoalCaller, AttrVars) :-
'$print_attribute_goals_exception'(Module, E) :- '$print_attribute_goals_exception'(Module, E) :-
( E = error(evaluation_error((Module:attribute_goals)/3), attribute_goals/3) ( E = error(evaluation_error((Module:attribute_goals)/3), attribute_goals/3)
; E = error(existence_error(procedure, attribute_goals/3), attribute_goals/3)
-> true -> true
; write_term('caught: ', [quoted(false)]), ; loader:write_error(E),
writeq(E),
nl nl
). ).

View File

@@ -15,16 +15,18 @@ pub use modular_bitfield::prelude::*;
use std::cmp::Ordering; use std::cmp::Ordering;
use std::error::Error; use std::error::Error;
use std::fmt; use std::fmt;
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::{Cursor, ErrorKind, Read, Seek, SeekFrom, Write}; use std::io::{BufRead, Cursor, ErrorKind, Read, Seek, SeekFrom, Write};
use std::mem; use std::mem;
use std::net::{TcpStream, Shutdown}; use std::net::{TcpStream, Shutdown};
use std::ops::{Deref, DerefMut}; use std::ops::{Deref, DerefMut};
use std::ptr; use std::ptr;
use native_tls::TlsStream; use native_tls::TlsStream;
use hyper::body::{Bytes, Sender};
#[derive(Debug, BitfieldSpecifier, Clone, Copy, PartialEq, Eq, Hash)] #[derive(Debug, BitfieldSpecifier, Clone, Copy, PartialEq, Eq, Hash)]
#[bits = 1] #[bits = 1]
@@ -138,6 +140,17 @@ impl Read for InputFileStream {
} }
} }
impl StreamLayout<CharReader<InputFileStream>> {
#[inline]
fn position(&mut self) -> Option<u64> {
// stream is the internal CharReader. subtract
// its pending buffer length from position.
self.get_mut().file.seek(SeekFrom::Current(0))
.map(|pos| pos - self.stream.rem_buf_len() as u64)
.ok()
}
}
#[derive(Debug)] #[derive(Debug)]
pub struct OutputFileStream { pub struct OutputFileStream {
file_name: Atom, file_name: Atom,
@@ -237,6 +250,51 @@ impl Write for NamedTlsStream {
} }
} }
pub struct HttpReadStream {
url: Atom,
body_reader: Box<dyn BufRead>,
}
impl Debug for HttpReadStream {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "Http Read Stream [{}]", self.url.as_str())
}
}
impl Read for HttpReadStream {
#[inline]
fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
self.body_reader.read(buf)
}
}
pub struct HttpWriteStream {
body_writer: Sender,
}
impl Debug for HttpWriteStream {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "Http Write Stream")
}
}
impl Write for HttpWriteStream {
#[inline]
fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
let bytes = Bytes::copy_from_slice(buf);
let len = bytes.len();
match self.body_writer.try_send_data(bytes) {
Ok(()) => Ok(len),
Err(_) => Err(std::io::Error::from(ErrorKind::Interrupted))
}
}
#[inline]
fn flush(&mut self) -> std::io::Result<()> {
Ok(())
}
}
#[derive(Debug)] #[derive(Debug)]
pub struct StandardOutputStream {} pub struct StandardOutputStream {}
@@ -375,6 +433,8 @@ arena_allocated_impl_for_stream!(CharReader<InputFileStream>, InputFileStream);
arena_allocated_impl_for_stream!(OutputFileStream, OutputFileStream); arena_allocated_impl_for_stream!(OutputFileStream, OutputFileStream);
arena_allocated_impl_for_stream!(CharReader<NamedTcpStream>, NamedTcpStream); arena_allocated_impl_for_stream!(CharReader<NamedTcpStream>, NamedTcpStream);
arena_allocated_impl_for_stream!(CharReader<NamedTlsStream>, NamedTlsStream); arena_allocated_impl_for_stream!(CharReader<NamedTlsStream>, NamedTlsStream);
arena_allocated_impl_for_stream!(CharReader<HttpReadStream>, HttpReadStream);
arena_allocated_impl_for_stream!(CharReader<HttpWriteStream>, HttpWriteStream);
arena_allocated_impl_for_stream!(ReadlineStream, ReadlineStream); arena_allocated_impl_for_stream!(ReadlineStream, ReadlineStream);
arena_allocated_impl_for_stream!(StaticStringStream, StaticStringStream); arena_allocated_impl_for_stream!(StaticStringStream, StaticStringStream);
arena_allocated_impl_for_stream!(StandardOutputStream, StandardOutputStream); arena_allocated_impl_for_stream!(StandardOutputStream, StandardOutputStream);
@@ -388,6 +448,8 @@ pub enum Stream {
StaticString(TypedArenaPtr<StreamLayout<StaticStringStream>>), StaticString(TypedArenaPtr<StreamLayout<StaticStringStream>>),
NamedTcp(TypedArenaPtr<StreamLayout<CharReader<NamedTcpStream>>>), NamedTcp(TypedArenaPtr<StreamLayout<CharReader<NamedTcpStream>>>),
NamedTls(TypedArenaPtr<StreamLayout<CharReader<NamedTlsStream>>>), NamedTls(TypedArenaPtr<StreamLayout<CharReader<NamedTlsStream>>>),
HttpRead(TypedArenaPtr<StreamLayout<CharReader<HttpReadStream>>>),
HttpWrite(TypedArenaPtr<StreamLayout<CharReader<HttpWriteStream>>>),
Null(StreamOptions), Null(StreamOptions),
Readline(TypedArenaPtr<StreamLayout<ReadlineStream>>), Readline(TypedArenaPtr<StreamLayout<ReadlineStream>>),
StandardOutput(TypedArenaPtr<StreamLayout<StandardOutputStream>>), StandardOutput(TypedArenaPtr<StreamLayout<StandardOutputStream>>),
@@ -426,9 +488,9 @@ impl Stream {
} }
#[inline] #[inline]
pub fn stdin(arena: &mut Arena) -> Stream { pub fn stdin(arena: &mut Arena, add_history: bool) -> Stream {
Stream::Readline(arena_alloc!( Stream::Readline(arena_alloc!(
StreamLayout::new(ReadlineStream::new("")), StreamLayout::new(ReadlineStream::new("", add_history)),
arena arena
)) ))
} }
@@ -442,6 +504,8 @@ impl Stream {
} }
ArenaHeaderTag::NamedTcpStream => Stream::NamedTcp(TypedArenaPtr::new(ptr as *mut _)), ArenaHeaderTag::NamedTcpStream => Stream::NamedTcp(TypedArenaPtr::new(ptr as *mut _)),
ArenaHeaderTag::NamedTlsStream => Stream::NamedTls(TypedArenaPtr::new(ptr as *mut _)), ArenaHeaderTag::NamedTlsStream => Stream::NamedTls(TypedArenaPtr::new(ptr as *mut _)),
ArenaHeaderTag::HttpReadStream => Stream::HttpRead(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 _))
@@ -452,7 +516,9 @@ impl Stream {
ArenaHeaderTag::StandardErrorStream => { ArenaHeaderTag::StandardErrorStream => {
Stream::StandardError(TypedArenaPtr::new(ptr as *mut _)) Stream::StandardError(TypedArenaPtr::new(ptr as *mut _))
} }
ArenaHeaderTag::NullStream => Stream::Null(StreamOptions::default()), ArenaHeaderTag::Dropped | ArenaHeaderTag::NullStream => {
Stream::Null(StreamOptions::default())
}
_ => unreachable!(), _ => unreachable!(),
} }
} }
@@ -492,6 +558,8 @@ impl Stream {
Stream::StaticString(ptr) => ptr.header_ptr(), Stream::StaticString(ptr) => ptr.header_ptr(),
Stream::NamedTcp(ptr) => ptr.header_ptr(), Stream::NamedTcp(ptr) => ptr.header_ptr(),
Stream::NamedTls(ptr) => ptr.header_ptr(), Stream::NamedTls(ptr) => ptr.header_ptr(),
Stream::HttpRead(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(),
@@ -507,6 +575,8 @@ impl Stream {
Stream::StaticString(ref ptr) => &ptr.options, Stream::StaticString(ref ptr) => &ptr.options,
Stream::NamedTcp(ref ptr) => &ptr.options, Stream::NamedTcp(ref ptr) => &ptr.options,
Stream::NamedTls(ref ptr) => &ptr.options, Stream::NamedTls(ref ptr) => &ptr.options,
Stream::HttpRead(ref ptr) => &ptr.options,
Stream::HttpWrite(ref ptr) => &ptr.options,
Stream::Null(ref options) => options, Stream::Null(ref options) => options,
Stream::Readline(ref ptr) => &ptr.options, Stream::Readline(ref ptr) => &ptr.options,
Stream::StandardOutput(ref ptr) => &ptr.options, Stream::StandardOutput(ref ptr) => &ptr.options,
@@ -522,6 +592,8 @@ impl Stream {
Stream::StaticString(ref mut ptr) => &mut ptr.options, Stream::StaticString(ref mut ptr) => &mut ptr.options,
Stream::NamedTcp(ref mut ptr) => &mut ptr.options, Stream::NamedTcp(ref mut ptr) => &mut ptr.options,
Stream::NamedTls(ref mut ptr) => &mut ptr.options, Stream::NamedTls(ref mut ptr) => &mut ptr.options,
Stream::HttpRead(ref mut ptr) => &mut ptr.options,
Stream::HttpWrite(ref mut ptr) => &mut ptr.options,
Stream::Null(ref mut options) => options, Stream::Null(ref mut options) => options,
Stream::Readline(ref mut ptr) => &mut ptr.options, Stream::Readline(ref mut ptr) => &mut ptr.options,
Stream::StandardOutput(ref mut ptr) => &mut ptr.options, Stream::StandardOutput(ref mut ptr) => &mut ptr.options,
@@ -538,6 +610,8 @@ impl Stream {
Stream::StaticString(ptr) => ptr.lines_read += incr_num_lines_read, Stream::StaticString(ptr) => ptr.lines_read += incr_num_lines_read,
Stream::NamedTcp(ptr) => ptr.lines_read += incr_num_lines_read, Stream::NamedTcp(ptr) => ptr.lines_read += incr_num_lines_read,
Stream::NamedTls(ptr) => ptr.lines_read += incr_num_lines_read, Stream::NamedTls(ptr) => ptr.lines_read += incr_num_lines_read,
Stream::HttpRead(ptr) => ptr.lines_read += incr_num_lines_read,
Stream::HttpWrite(_) => {}
Stream::Null(_) => {} Stream::Null(_) => {}
Stream::Readline(ptr) => ptr.lines_read += incr_num_lines_read, Stream::Readline(ptr) => ptr.lines_read += incr_num_lines_read,
Stream::StandardOutput(ptr) => ptr.lines_read += incr_num_lines_read, Stream::StandardOutput(ptr) => ptr.lines_read += incr_num_lines_read,
@@ -554,6 +628,8 @@ impl Stream {
Stream::StaticString(ptr) => ptr.lines_read = value, Stream::StaticString(ptr) => ptr.lines_read = value,
Stream::NamedTcp(ptr) => ptr.lines_read = value, Stream::NamedTcp(ptr) => ptr.lines_read = value,
Stream::NamedTls(ptr) => ptr.lines_read = value, Stream::NamedTls(ptr) => ptr.lines_read = value,
Stream::HttpRead(ptr) => ptr.lines_read = value,
Stream::HttpWrite(_) => {}
Stream::Null(_) => {} Stream::Null(_) => {}
Stream::Readline(ptr) => ptr.lines_read = value, Stream::Readline(ptr) => ptr.lines_read = value,
Stream::StandardOutput(ptr) => ptr.lines_read = value, Stream::StandardOutput(ptr) => ptr.lines_read = value,
@@ -570,6 +646,8 @@ impl Stream {
Stream::StaticString(ptr) => ptr.lines_read, Stream::StaticString(ptr) => ptr.lines_read,
Stream::NamedTcp(ptr) => ptr.lines_read, Stream::NamedTcp(ptr) => ptr.lines_read,
Stream::NamedTls(ptr) => ptr.lines_read, Stream::NamedTls(ptr) => ptr.lines_read,
Stream::HttpRead(ptr) => ptr.lines_read,
Stream::HttpWrite(_) => 0,
Stream::Null(_) => 0, Stream::Null(_) => 0,
Stream::Readline(ptr) => ptr.lines_read, Stream::Readline(ptr) => ptr.lines_read,
Stream::StandardOutput(ptr) => ptr.lines_read, Stream::StandardOutput(ptr) => ptr.lines_read,
@@ -584,12 +662,14 @@ impl CharRead for Stream {
Stream::InputFile(file) => (*file).peek_char(), Stream::InputFile(file) => (*file).peek_char(),
Stream::NamedTcp(tcp_stream) => (*tcp_stream).peek_char(), Stream::NamedTcp(tcp_stream) => (*tcp_stream).peek_char(),
Stream::NamedTls(tls_stream) => (*tls_stream).peek_char(), Stream::NamedTls(tls_stream) => (*tls_stream).peek_char(),
Stream::HttpRead(http_stream) => (*http_stream).peek_char(),
Stream::Readline(rl_stream) => (*rl_stream).peek_char(), Stream::Readline(rl_stream) => (*rl_stream).peek_char(),
Stream::StaticString(src) => (*src).peek_char(), Stream::StaticString(src) => (*src).peek_char(),
Stream::Byte(cursor) => (*cursor).peek_char(), Stream::Byte(cursor) => (*cursor).peek_char(),
Stream::OutputFile(_) | Stream::OutputFile(_) |
Stream::StandardError(_) | Stream::StandardError(_) |
Stream::StandardOutput(_) | Stream::StandardOutput(_) |
Stream::HttpWrite(_) |
Stream::Null(_) => Some(Err(std::io::Error::new( Stream::Null(_) => Some(Err(std::io::Error::new(
ErrorKind::PermissionDenied, ErrorKind::PermissionDenied,
StreamError::ReadFromOutputStream, StreamError::ReadFromOutputStream,
@@ -602,12 +682,14 @@ impl CharRead for Stream {
Stream::InputFile(file) => (*file).read_char(), Stream::InputFile(file) => (*file).read_char(),
Stream::NamedTcp(tcp_stream) => (*tcp_stream).read_char(), Stream::NamedTcp(tcp_stream) => (*tcp_stream).read_char(),
Stream::NamedTls(tls_stream) => (*tls_stream).read_char(), Stream::NamedTls(tls_stream) => (*tls_stream).read_char(),
Stream::HttpRead(http_stream) => (*http_stream).read_char(),
Stream::Readline(rl_stream) => (*rl_stream).read_char(), Stream::Readline(rl_stream) => (*rl_stream).read_char(),
Stream::StaticString(src) => (*src).read_char(), Stream::StaticString(src) => (*src).read_char(),
Stream::Byte(cursor) => (*cursor).read_char(), Stream::Byte(cursor) => (*cursor).read_char(),
Stream::OutputFile(_) | Stream::OutputFile(_) |
Stream::StandardError(_) | Stream::StandardError(_) |
Stream::StandardOutput(_) | Stream::StandardOutput(_) |
Stream::HttpWrite(_) |
Stream::Null(_) => Some(Err(std::io::Error::new( Stream::Null(_) => Some(Err(std::io::Error::new(
ErrorKind::PermissionDenied, ErrorKind::PermissionDenied,
StreamError::ReadFromOutputStream, StreamError::ReadFromOutputStream,
@@ -620,12 +702,14 @@ impl CharRead for Stream {
Stream::InputFile(file) => file.put_back_char(c), Stream::InputFile(file) => file.put_back_char(c),
Stream::NamedTcp(tcp_stream) => tcp_stream.put_back_char(c), Stream::NamedTcp(tcp_stream) => tcp_stream.put_back_char(c),
Stream::NamedTls(tls_stream) => tls_stream.put_back_char(c), Stream::NamedTls(tls_stream) => tls_stream.put_back_char(c),
Stream::HttpRead(http_stream) => http_stream.put_back_char(c),
Stream::Readline(rl_stream) => rl_stream.put_back_char(c), Stream::Readline(rl_stream) => rl_stream.put_back_char(c),
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),
Stream::OutputFile(_) | Stream::OutputFile(_) |
Stream::StandardError(_) | Stream::StandardError(_) |
Stream::StandardOutput(_) | Stream::StandardOutput(_) |
Stream::HttpWrite(_) |
Stream::Null(_) => {} Stream::Null(_) => {}
} }
} }
@@ -635,12 +719,14 @@ impl CharRead for Stream {
Stream::InputFile(ref mut file) => file.consume(nread), Stream::InputFile(ref mut file) => file.consume(nread),
Stream::NamedTcp(ref mut tcp_stream) => tcp_stream.consume(nread), Stream::NamedTcp(ref mut tcp_stream) => tcp_stream.consume(nread),
Stream::NamedTls(ref mut tls_stream) => tls_stream.consume(nread), Stream::NamedTls(ref mut tls_stream) => tls_stream.consume(nread),
Stream::HttpRead(ref mut http_stream) => http_stream.consume(nread),
Stream::Readline(ref mut rl_stream) => rl_stream.consume(nread), Stream::Readline(ref mut rl_stream) => rl_stream.consume(nread),
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),
Stream::OutputFile(_) | Stream::OutputFile(_) |
Stream::StandardError(_) | Stream::StandardError(_) |
Stream::StandardOutput(_) | Stream::StandardOutput(_) |
Stream::HttpWrite(_) |
Stream::Null(_) => {} Stream::Null(_) => {}
} }
} }
@@ -653,12 +739,14 @@ impl Read for Stream {
Stream::InputFile(file) => (*file).read(buf), Stream::InputFile(file) => (*file).read(buf),
Stream::NamedTcp(tcp_stream) => (*tcp_stream).read(buf), Stream::NamedTcp(tcp_stream) => (*tcp_stream).read(buf),
Stream::NamedTls(tls_stream) => (*tls_stream).read(buf), Stream::NamedTls(tls_stream) => (*tls_stream).read(buf),
Stream::HttpRead(http_stream) => (*http_stream).read(buf),
Stream::Readline(rl_stream) => (*rl_stream).read(buf), Stream::Readline(rl_stream) => (*rl_stream).read(buf),
Stream::StaticString(src) => (*src).read(buf), Stream::StaticString(src) => (*src).read(buf),
Stream::Byte(cursor) => (*cursor).read(buf), Stream::Byte(cursor) => (*cursor).read(buf),
Stream::OutputFile(_) Stream::OutputFile(_)
| Stream::StandardError(_) | Stream::StandardError(_)
| Stream::StandardOutput(_) | Stream::StandardOutput(_)
| Stream::HttpWrite(_)
| Stream::Null(_) => Err(std::io::Error::new( | Stream::Null(_) => Err(std::io::Error::new(
ErrorKind::PermissionDenied, ErrorKind::PermissionDenied,
StreamError::ReadFromOutputStream, StreamError::ReadFromOutputStream,
@@ -678,6 +766,8 @@ impl Write for Stream {
Stream::Byte(ref mut cursor) => cursor.get_mut().write(buf), Stream::Byte(ref mut cursor) => cursor.get_mut().write(buf),
Stream::StandardOutput(stream) => stream.write(buf), Stream::StandardOutput(stream) => stream.write(buf),
Stream::StandardError(stream) => stream.write(buf), Stream::StandardError(stream) => stream.write(buf),
Stream::HttpWrite(ref mut stream) => stream.get_mut().write(buf),
Stream::HttpRead(_) |
Stream::StaticString(_) | Stream::StaticString(_) |
Stream::Readline(_) | Stream::Readline(_) |
Stream::InputFile(..) | Stream::InputFile(..) |
@@ -696,6 +786,8 @@ impl Write for Stream {
Stream::Byte(ref mut cursor) => cursor.stream.get_mut().flush(), Stream::Byte(ref mut cursor) => cursor.stream.get_mut().flush(),
Stream::StandardError(stream) => stream.stream.flush(), Stream::StandardError(stream) => stream.stream.flush(),
Stream::StandardOutput(stream) => stream.stream.flush(), Stream::StandardOutput(stream) => stream.stream.flush(),
Stream::HttpWrite(ref mut stream) => stream.stream.get_mut().flush(),
Stream::HttpRead(_) |
Stream::StaticString(_) | Stream::StaticString(_) |
Stream::Readline(_) | Stream::Readline(_) |
Stream::InputFile(_) | Stream::InputFile(_) |
@@ -776,8 +868,8 @@ impl Stream {
pub(crate) fn position(&mut self) -> Option<(u64, usize)> { pub(crate) fn position(&mut self) -> Option<(u64, usize)> {
// returns lines_read, position. // returns lines_read, position.
let result = match self { let result = match self {
Stream::InputFile(ref mut file_stream) => { Stream::InputFile(file_stream) => {
file_stream.get_mut().file.seek(SeekFrom::Current(0)).ok() file_stream.position()
} }
Stream::NamedTcp(..) Stream::NamedTcp(..)
| Stream::NamedTls(..) | Stream::NamedTls(..)
@@ -801,6 +893,7 @@ 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.
if let Ok(metadata) = stream.get_ref().file.metadata() { if let Ok(metadata) = stream.get_ref().file.metadata() {
*past_end_of_stream = position > metadata.len(); *past_end_of_stream = position > metadata.len();
@@ -816,10 +909,11 @@ impl Stream {
Stream::Byte(stream) => stream.past_end_of_stream, Stream::Byte(stream) => stream.past_end_of_stream,
Stream::InputFile(stream) => stream.past_end_of_stream, Stream::InputFile(stream) => stream.past_end_of_stream,
Stream::OutputFile(stream) => stream.past_end_of_stream, Stream::OutputFile(stream) => stream.past_end_of_stream,
// Stream::PausedProlog(stream) => stream.paused_stream.past_end_of_stream(),
Stream::StaticString(stream) => stream.past_end_of_stream, Stream::StaticString(stream) => stream.past_end_of_stream,
Stream::NamedTcp(stream) => stream.past_end_of_stream, Stream::NamedTcp(stream) => stream.past_end_of_stream,
Stream::NamedTls(stream) => stream.past_end_of_stream, Stream::NamedTls(stream) => stream.past_end_of_stream,
Stream::HttpRead(stream) => stream.past_end_of_stream,
Stream::HttpWrite(stream) => stream.past_end_of_stream,
Stream::Null(_) => false, Stream::Null(_) => false,
Stream::Readline(stream) => stream.past_end_of_stream, Stream::Readline(stream) => stream.past_end_of_stream,
Stream::StandardOutput(stream) => stream.past_end_of_stream, Stream::StandardOutput(stream) => stream.past_end_of_stream,
@@ -841,6 +935,8 @@ impl Stream {
Stream::StaticString(stream) => stream.past_end_of_stream = value, Stream::StaticString(stream) => stream.past_end_of_stream = value,
Stream::NamedTcp(stream) => stream.past_end_of_stream = value, Stream::NamedTcp(stream) => stream.past_end_of_stream = value,
Stream::NamedTls(stream) => stream.past_end_of_stream = value, Stream::NamedTls(stream) => stream.past_end_of_stream = value,
Stream::HttpRead(stream) => stream.past_end_of_stream = value,
Stream::HttpWrite(stream) => stream.past_end_of_stream = value,
Stream::Null(_) => {} Stream::Null(_) => {}
Stream::Readline(stream) => stream.past_end_of_stream = value, Stream::Readline(stream) => stream.past_end_of_stream = value,
Stream::StandardOutput(stream) => stream.past_end_of_stream = value, Stream::StandardOutput(stream) => stream.past_end_of_stream = value,
@@ -855,6 +951,8 @@ impl Stream {
} }
if let Stream::InputFile(stream_layout) = self { if let Stream::InputFile(stream_layout) = self {
let position = stream_layout.position();
let StreamLayout { let StreamLayout {
past_end_of_stream, past_end_of_stream,
stream, stream,
@@ -863,7 +961,7 @@ impl Stream {
match stream.get_ref().file.metadata() { match stream.get_ref().file.metadata() {
Ok(metadata) => { Ok(metadata) => {
if let Ok(position) = stream.get_mut().file.seek(SeekFrom::Current(0)) { if let Some(position) = position {
return match position.cmp(&metadata.len()) { return match position.cmp(&metadata.len()) {
Ordering::Equal => AtEndOfStream::At, Ordering::Equal => AtEndOfStream::At,
Ordering::Less => AtEndOfStream::Not, Ordering::Less => AtEndOfStream::Not,
@@ -904,10 +1002,11 @@ impl Stream {
Stream::Byte(_) Stream::Byte(_)
| Stream::Readline(_) | Stream::Readline(_)
| Stream::StaticString(_) | Stream::StaticString(_)
| Stream::HttpRead(_)
| Stream::InputFile(..) => atom!("read"), | Stream::InputFile(..) => atom!("read"),
Stream::NamedTcp(..) | Stream::NamedTls(..) => atom!("read_append"), Stream::NamedTcp(..) | Stream::NamedTls(..) => atom!("read_append"),
Stream::OutputFile(file) if file.is_append => atom!("append"), Stream::OutputFile(file) if file.is_append => atom!("append"),
Stream::OutputFile(_) | Stream::StandardError(_) | Stream::StandardOutput(_) => atom!("write"), Stream::OutputFile(_) | Stream::StandardError(_) | Stream::StandardOutput(_) | Stream::HttpWrite(_) => atom!("write"),
Stream::Null(_) => atom!(""), Stream::Null(_) => atom!(""),
} }
} }
@@ -961,6 +1060,34 @@ impl Stream {
)) ))
} }
#[inline]
pub(crate) fn from_http_stream(
url: Atom,
http_stream: Box<dyn BufRead>,
arena: &mut Arena,
) -> Self {
Stream::HttpRead(arena_alloc!(
StreamLayout::new(CharReader::new(HttpReadStream {
url,
body_reader: http_stream
})),
arena
))
}
#[inline]
pub(crate) fn from_http_sender(
body_writer: Sender,
arena: &mut Arena,
) -> Self {
Stream::HttpWrite(arena_alloc!(
StreamLayout::new(CharReader::new(HttpWriteStream {
body_writer
})),
arena
))
}
#[inline] #[inline]
pub(crate) fn from_file_as_output( pub(crate) fn from_file_as_output(
file_name: Atom, file_name: Atom,
@@ -988,18 +1115,51 @@ impl Stream {
#[inline] #[inline]
pub(crate) fn close(&mut self) -> Result<(), std::io::Error> { pub(crate) fn close(&mut self) -> Result<(), std::io::Error> {
let result = match self { let mut stream = std::mem::replace(self, Stream::Null(StreamOptions::default()));
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)
}, },
Stream::NamedTls(ref mut tls_stream) => { Stream::NamedTls(ref mut tls_stream) => {
tls_stream.inner_mut().tls_stream.shutdown() tls_stream.inner_mut().tls_stream.shutdown()
} }
_ => Ok(()) Stream::HttpRead(ref mut http_stream) => {
}; unsafe {
http_stream.set_tag(ArenaHeaderTag::Dropped);
std::ptr::drop_in_place(&mut http_stream.inner_mut().body_reader as *mut _);
}
*self = Stream::Null(StreamOptions::default()); Ok(())
result }
Stream::HttpWrite(ref mut http_stream) => {
unsafe {
http_stream.set_tag(ArenaHeaderTag::Dropped);
std::ptr::drop_in_place(&mut http_stream.inner_mut().body_writer as *mut _);
}
Ok(())
}
Stream::InputFile(mut file_stream) => {
// close the stream by dropping the inner File.
unsafe {
file_stream.set_tag(ArenaHeaderTag::Dropped);
std::ptr::drop_in_place(&mut file_stream.inner_mut().file as *mut _);
}
Ok(())
}
Stream::OutputFile(mut file_stream) => {
// close the stream by dropping the inner File.
unsafe {
file_stream.set_tag(ArenaHeaderTag::Dropped);
std::ptr::drop_in_place(&mut file_stream.file as *mut _);
}
Ok(())
}
_ => Ok(())
}
} }
#[inline] #[inline]
@@ -1016,6 +1176,7 @@ impl Stream {
match self { match self {
Stream::NamedTcp(..) Stream::NamedTcp(..)
| Stream::NamedTls(..) | Stream::NamedTls(..)
| Stream::HttpRead(..)
| Stream::Byte(_) | Stream::Byte(_)
| Stream::Readline(_) | Stream::Readline(_)
| Stream::StaticString(_) | Stream::StaticString(_)
@@ -1031,6 +1192,7 @@ impl Stream {
| Stream::StandardOutput(_) | Stream::StandardOutput(_)
| Stream::NamedTcp(..) | Stream::NamedTcp(..)
| Stream::NamedTls(..) | Stream::NamedTls(..)
| Stream::HttpWrite(..)
| Stream::Byte(_) | Stream::Byte(_)
| Stream::OutputFile(..) => true, | Stream::OutputFile(..) => true,
_ => false, _ => false,
@@ -1160,6 +1322,18 @@ impl MachineState {
None None
} }
} }
(HeapCellValueTag::Str, s) => {
let (name, arity) = cell_as_atom_cell!(self.heap[s])
.get_name_and_arity();
debug_assert_eq!(arity, 0);
if name != atom!("[]") {
Some(name)
} else {
None
}
}
_ => { _ => {
None None
} }
@@ -1176,6 +1350,19 @@ impl MachineState {
_ => unreachable!(), _ => unreachable!(),
} }
} }
(HeapCellValueTag::Str, s) => {
let (name, arity) = cell_as_atom_cell!(self.heap[s])
.get_name_and_arity();
debug_assert_eq!(arity, 0);
match name {
atom!("eof_code") => EOFAction::EOFCode,
atom!("error") => EOFAction::Error,
atom!("reset") => EOFAction::Reset,
_ => unreachable!(),
}
}
_ => { _ => {
unreachable!() unreachable!()
} }
@@ -1186,6 +1373,13 @@ impl MachineState {
debug_assert_eq!(arity, 0); debug_assert_eq!(arity, 0);
name == atom!("true") name == atom!("true")
} }
(HeapCellValueTag::Str, s) => {
let (name, arity) = cell_as_atom_cell!(self.heap[s])
.get_name_and_arity();
debug_assert_eq!(arity, 0);
name == atom!("true")
}
_ => { _ => {
unreachable!() unreachable!()
} }
@@ -1200,6 +1394,17 @@ impl MachineState {
_ => unreachable!(), _ => unreachable!(),
} }
} }
(HeapCellValueTag::Str, s) => {
let (name, arity) = cell_as_atom_cell!(self.heap[s])
.get_name_and_arity();
debug_assert_eq!(arity, 0);
match name {
atom!("text") => StreamType::Text,
atom!("binary") => StreamType::Binary,
_ => unreachable!(),
}
}
_ => { _ => {
unreachable!() unreachable!()
} }
@@ -1240,6 +1445,24 @@ impl MachineState {
} }
}; };
} }
(HeapCellValueTag::Str, s) => {
let (name, arity) = cell_as_atom_cell!(self.heap[s])
.get_name_and_arity();
debug_assert_eq!(arity, 0);
return match stream_aliases.get(&name) {
Some(stream) if !stream.is_null_stream() => Ok(*stream),
_ => {
let stub = functor_stub(caller, arity);
let addr = atom_as_cell!(name);
let existence_error = self.existence_error(ExistenceError::Stream(addr));
Err(self.error_form(existence_error, stub))
}
};
}
(HeapCellValueTag::Cons, ptr) => { (HeapCellValueTag::Cons, ptr) => {
match_untyped_arena_ptr!(ptr, match_untyped_arena_ptr!(ptr,
(ArenaHeaderTag::Stream, stream) => { (ArenaHeaderTag::Stream, stream) => {
@@ -1249,6 +1472,12 @@ impl MachineState {
Ok(stream) Ok(stream)
}; };
} }
(ArenaHeaderTag::Dropped, _value) => {
let stub = functor_stub(caller, arity);
let err = self.existence_error(ExistenceError::Stream(addr));
return Err(self.error_form(err, stub));
}
_ => { _ => {
} }
); );
@@ -1304,7 +1533,7 @@ impl MachineState {
let stub = functor_stub(caller, arity); let stub = functor_stub(caller, arity);
let err = self.permission_error(perm, err_atom, stream_as_cell!(stream)); let err = self.permission_error(perm, err_atom, stream_as_cell!(stream));
return self.error_form(err, stub); self.error_form(err, stub)
} }
#[inline] #[inline]
@@ -1332,7 +1561,7 @@ impl MachineState {
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);
return self.error_form(err, stub); self.error_form(err, stub)
} }
pub(crate) fn occupied_alias_permission_error( pub(crate) fn occupied_alias_permission_error(
@@ -1342,24 +1571,22 @@ 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 alias_name = atom!("alias");
let err = self.permission_error( let err = self.permission_error(
Permission::Open, Permission::Open,
atom!("source_sink"), atom!("source_sink"),
functor!(alias_name, [atom(alias)]), functor!(atom!("alias"), [atom(alias)]),
); );
return self.error_form(err, stub); self.error_form(err, stub)
} }
pub(crate) fn reposition_error(&mut self, stub_name: Atom, stub_arity: usize) -> MachineStub { pub(crate) fn reposition_error(&mut self, stub_name: Atom, stub_arity: usize) -> MachineStub {
let stub = functor_stub(stub_name, stub_arity); let stub = functor_stub(stub_name, stub_arity);
let rep_stub = functor!(atom!("reposition"), [atom(atom!("true"))]); let rep_stub = functor!(atom!("reposition"), [atom(atom!("true"))]);
let err = self.permission_error(Permission::Open, atom!("source_sink"), rep_stub); let err = self.permission_error(Permission::Open, atom!("source_sink"), rep_stub);
return self.error_form(err, stub); self.error_form(err, stub)
} }
pub(crate) fn check_stream_properties( pub(crate) fn check_stream_properties(

File diff suppressed because it is too large Load Diff

View File

@@ -119,3 +119,21 @@ impl TermStream for LiveTermStream {
&self.listing_src &self.listing_src
} }
} }
pub struct InlineTermStream {
}
impl TermStream for InlineTermStream {
fn next(&mut self, _: &CompositeOpDir) -> Result<Term, CompilationError> {
Err(CompilationError::from(ParserError::UnexpectedEOF))
}
fn eof(&mut self) -> Result<bool, CompilationError> {
Ok(true)
}
fn listing_src(&self) -> &ListingSource {
&ListingSource::User
}
}

View File

@@ -87,10 +87,8 @@ macro_rules! cell_as_atom_cell {
macro_rules! cell_as_f64_ptr { macro_rules! cell_as_f64_ptr {
($cell:expr) => {{ ($cell:expr) => {{
let ptr_u64 = ConsPtr::from_bytes($cell.into_bytes()); let offset = $cell.get_value();
F64Ptr(TypedArenaPtr::new( F64Ptr::from_offset(offset)
ptr_u64.as_ptr() as *mut OrderedFloat<f64>
))
}}; }};
} }
@@ -246,13 +244,6 @@ macro_rules! match_untyped_arena_ptr_pat_body {
#[allow(unused_braces)] #[allow(unused_braces)]
$code $code
}}; }};
($ptr:ident, F64, $n:ident, $code:expr) => {{
let payload_ptr =
unsafe { std::mem::transmute::<_, *mut OrderedFloat<f64>>($ptr.payload_offset()) };
let $n = TypedArenaPtr::new(payload_ptr);
#[allow(unused_braces)]
$code
}};
($ptr:ident, Rational, $n:ident, $code:expr) => {{ ($ptr:ident, Rational, $n:ident, $code:expr) => {{
let payload_ptr = unsafe { std::mem::transmute::<_, *mut Rational>($ptr.payload_offset()) }; let payload_ptr = unsafe { std::mem::transmute::<_, *mut Rational>($ptr.payload_offset()) };
let $n = TypedArenaPtr::new(payload_ptr); let $n = TypedArenaPtr::new(payload_ptr);
@@ -281,6 +272,26 @@ macro_rules! match_untyped_arena_ptr_pat_body {
#[allow(unused_braces)] #[allow(unused_braces)]
$code $code
}}; }};
($ptr:ident, HttpListener, $listener:ident, $code:expr) => {{
let payload_ptr = unsafe { std::mem::transmute::<_, *mut HttpListener>($ptr.payload_offset()) };
#[allow(unused_mut)]
let mut $listener = TypedArenaPtr::new(payload_ptr);
#[allow(unused_braces)]
$code
}};
($ptr:ident, HttpResponse, $listener:ident, $code:expr) => {{
let payload_ptr = unsafe { std::mem::transmute::<_, *mut HttpResponse>($ptr.payload_offset()) };
#[allow(unused_mut)]
let mut $listener = TypedArenaPtr::new(payload_ptr);
#[allow(unused_braces)]
$code
}};
($ptr:ident, IndexPtr, $ip:ident, $code:expr) => {{
#[allow(unused_mut)]
let mut $ip = TypedArenaPtr::new(unsafe { std::mem::transmute::<_, *mut IndexPtr>($ptr.get_ptr()) });
#[allow(unused_braces)]
$code
}};
($ptr:ident, $($tags:tt)|+, $s:ident, $code:expr) => {{ ($ptr:ident, $($tags:tt)|+, $s:ident, $code:expr) => {{
let $s = Stream::from_tag($ptr.get_tag(), $ptr.payload_offset()); let $s = Stream::from_tag($ptr.get_tag(), $ptr.payload_offset());
#[allow(unused_braces)] #[allow(unused_braces)]
@@ -294,12 +305,20 @@ macro_rules! match_untyped_arena_ptr_pat {
| ArenaHeaderTag::OutputFileStream | ArenaHeaderTag::OutputFileStream
| ArenaHeaderTag::NamedTcpStream | ArenaHeaderTag::NamedTcpStream
| ArenaHeaderTag::NamedTlsStream | ArenaHeaderTag::NamedTlsStream
| ArenaHeaderTag::HttpReadStream
| ArenaHeaderTag::HttpWriteStream
| ArenaHeaderTag::ReadlineStream | ArenaHeaderTag::ReadlineStream
| ArenaHeaderTag::StaticStringStream | ArenaHeaderTag::StaticStringStream
| ArenaHeaderTag::ByteStream | ArenaHeaderTag::ByteStream
| ArenaHeaderTag::StandardOutputStream | ArenaHeaderTag::StandardOutputStream
| ArenaHeaderTag::StandardErrorStream | ArenaHeaderTag::StandardErrorStream
}; };
(IndexPtr) => {
ArenaHeaderTag::IndexPtrUndefined |
ArenaHeaderTag::IndexPtrDynamicUndefined |
ArenaHeaderTag::IndexPtrDynamicIndex |
ArenaHeaderTag::IndexPtrIndex
};
($tag:ident) => { ($tag:ident) => {
ArenaHeaderTag::$tag ArenaHeaderTag::$tag
}; };

View File

@@ -1,5 +1,6 @@
use crate::arena::*; use crate::arena::*;
use crate::atom_table::*; use crate::atom_table::*;
use crate::machine::machine_indices::*;
use crate::parser::char_reader::*; use crate::parser::char_reader::*;
use crate::types::HeapCellValueTag; use crate::types::HeapCellValueTag;
@@ -11,7 +12,7 @@ use std::ops::Neg;
use std::rc::Rc; use std::rc::Rc;
use std::vec::Vec; use std::vec::Vec;
use rug::{Integer, Rational}; use crate::parser::rug::{Integer, Rational};
use fxhash::FxBuildHasher; use fxhash::FxBuildHasher;
use indexmap::IndexMap; use indexmap::IndexMap;
@@ -234,12 +235,22 @@ pub enum GenContext {
} }
impl GenContext { impl GenContext {
#[inline]
pub fn chunk_num(self) -> usize { pub fn chunk_num(self) -> usize {
match self { match self {
GenContext::Head => 0, GenContext::Head => 0,
GenContext::Mid(cn) | GenContext::Last(cn) => cn, GenContext::Mid(cn) | GenContext::Last(cn) => cn,
} }
} }
#[inline]
pub fn is_last(self) -> bool {
if let GenContext::Last(_) = self {
true
} else {
false
}
}
} }
#[bitfield] #[bitfield]
@@ -361,28 +372,28 @@ pub enum ArithmeticError {
#[derive(Debug)] #[derive(Debug)]
pub enum ParserError { pub enum ParserError {
BackQuotedString(usize, usize), BackQuotedString(usize, usize),
UnexpectedChar(char, usize, usize),
UnexpectedEOF,
IO(IOError), IO(IOError),
IncompleteReduction(usize, usize), IncompleteReduction(usize, usize),
InvalidSingleQuotedCharacter(char), InvalidSingleQuotedCharacter(char),
LexicalError(lexical::Error),
MissingQuote(usize, usize), MissingQuote(usize, usize),
NonPrologChar(usize, usize), NonPrologChar(usize, usize),
ParseBigInt(usize, usize), ParseBigInt(usize, usize),
LexicalError(lexical::Error), UnexpectedChar(char, usize, usize),
UnexpectedEOF,
Utf8Error(usize, usize), Utf8Error(usize, usize),
} }
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::UnexpectedChar(_, 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::Utf8Error(line_num, col_num) => Some((line_num, col_num)), &ParserError::Utf8Error(line_num, col_num) => Some((line_num, col_num)),
_ => None, _ => None,
} }
} }
@@ -390,8 +401,6 @@ impl ParserError {
pub fn as_atom(&self) -> Atom { pub fn as_atom(&self) -> Atom {
match self { match self {
ParserError::BackQuotedString(..) => atom!("back_quoted_string"), ParserError::BackQuotedString(..) => atom!("back_quoted_string"),
ParserError::UnexpectedChar(..) => atom!("unexpected_char"),
ParserError::UnexpectedEOF => atom!("unexpected_end_of_file"),
ParserError::IncompleteReduction(..) => atom!("incomplete_reduction"), ParserError::IncompleteReduction(..) => atom!("incomplete_reduction"),
ParserError::InvalidSingleQuotedCharacter(..) => atom!("invalid_single_quoted_character"), ParserError::InvalidSingleQuotedCharacter(..) => atom!("invalid_single_quoted_character"),
ParserError::IO(_) => atom!("input_output_error"), ParserError::IO(_) => atom!("input_output_error"),
@@ -399,6 +408,8 @@ impl ParserError {
ParserError::MissingQuote(..) => atom!("missing_quote"), ParserError::MissingQuote(..) => atom!("missing_quote"),
ParserError::NonPrologChar(..) => atom!("non_prolog_character"), ParserError::NonPrologChar(..) => atom!("non_prolog_character"),
ParserError::ParseBigInt(..) => atom!("cannot_parse_big_int"), ParserError::ParseBigInt(..) => atom!("cannot_parse_big_int"),
ParserError::UnexpectedChar(..) => atom!("unexpected_char"),
ParserError::UnexpectedEOF => atom!("unexpected_end_of_file"),
ParserError::Utf8Error(..) => atom!("utf8_conversion_error"), ParserError::Utf8Error(..) => atom!("utf8_conversion_error"),
} }
} }
@@ -466,7 +477,8 @@ pub enum Fixity {
#[repr(u64)] #[repr(u64)]
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
pub struct Fixnum { pub struct Fixnum {
num: B57, num: B56,
#[allow(unused)] f: bool,
#[allow(unused)] m: bool, #[allow(unused)] m: bool,
#[allow(unused)] tag: B6, #[allow(unused)] tag: B6,
} }
@@ -475,22 +487,23 @@ impl Fixnum {
#[inline] #[inline]
pub fn build_with(num: i64) -> Self { pub fn build_with(num: i64) -> Self {
Fixnum::new() Fixnum::new()
.with_num(u64::from_ne_bytes(num.to_ne_bytes()) & ((1 << 57) - 1)) .with_num(u64::from_ne_bytes(num.to_ne_bytes()) & ((1 << 56) - 1))
.with_tag(HeapCellValueTag::Fixnum as u8) .with_tag(HeapCellValueTag::Fixnum as u8)
.with_m(false) .with_m(false)
//num as u64).with__m(false) .with_f(false)
} }
#[inline] #[inline]
pub fn build_with_checked(num: i64) -> Result<Self, OutOfBounds> { pub fn build_with_checked(num: i64) -> Result<Self, OutOfBounds> {
const UPPER_BOUND: i64 = (1 << 56) - 1; const UPPER_BOUND: i64 = (1 << 55) - 1;
const LOWER_BOUND: i64 = -(1 << 56); const LOWER_BOUND: i64 = -(1 << 55);
if LOWER_BOUND <= num && num <= UPPER_BOUND { if LOWER_BOUND <= num && num <= UPPER_BOUND {
Ok(Fixnum::new() Ok(Fixnum::new()
.with_m(false) .with_m(false)
.with_f(false)
.with_tag(HeapCellValueTag::Fixnum as u8) .with_tag(HeapCellValueTag::Fixnum as u8)
.with_num(u64::from_ne_bytes(num.to_ne_bytes()) & ((1 << 57) - 1))) //num as u64 & ((1 << 57) - 1))) .with_num(u64::from_ne_bytes(num.to_ne_bytes()) & ((1 << 56) - 1)))
} else { } else {
Err(OutOfBounds {}) Err(OutOfBounds {})
} }
@@ -499,7 +512,7 @@ impl Fixnum {
#[inline] #[inline]
pub fn get_num(self) -> i64 { pub fn get_num(self) -> i64 {
let n = self.num() as i64; let n = self.num() as i64;
let (n, overflowed) = (n << 7).overflowing_shr(7); // sign-extend the 57-bit signed fixnum. let (n, overflowed) = (n << 8).overflowing_shr(8);
debug_assert_eq!(overflowed, false); debug_assert_eq!(overflowed, false);
n n
} }
@@ -518,30 +531,34 @@ impl Neg for Fixnum {
pub enum Literal { pub enum Literal {
Atom(Atom), Atom(Atom),
Char(char), Char(char),
CodeIndex(CodeIndex),
Fixnum(Fixnum), Fixnum(Fixnum),
Integer(TypedArenaPtr<Integer>), Integer(TypedArenaPtr<Integer>),
Rational(TypedArenaPtr<Rational>), Rational(TypedArenaPtr<Rational>),
Float(F64Ptr), Float(F64Offset),
String(Atom), String(Atom),
} }
impl From<F64Ptr> for Literal {
#[inline(always)]
fn from(ptr: F64Ptr) -> Literal {
Literal::Float(ptr.as_offset())
}
}
impl fmt::Display for Literal { impl fmt::Display for Literal {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self { match self {
Literal::Atom(ref atom) => { Literal::Atom(ref atom) => {
// if atom.as_str().chars().any(|c| "`.$'\" ".contains(c)) {
// write!(f, "'{}'", atom)
// } else {
write!(f, "{}", atom.flat_index()) write!(f, "{}", atom.flat_index())
// }
} }
Literal::Char(c) => write!(f, "'{}'", *c as u32), Literal::Char(c) => write!(f, "'{}'", *c as u32),
Literal::CodeIndex(i) => write!(f, "{:x}", i.as_ptr() as u64),
Literal::Fixnum(n) => write!(f, "{}", n.get_num()), Literal::Fixnum(n) => write!(f, "{}", n.get_num()),
Literal::Integer(ref n) => write!(f, "{}", n), Literal::Integer(ref n) => write!(f, "{}", n),
Literal::Rational(ref n) => write!(f, "{}", n), Literal::Rational(ref n) => write!(f, "{}", n),
Literal::Float(ref n) => write!(f, "{}", *n), Literal::Float(ref n) => write!(f, "{}", *n),
Literal::String(ref s) => write!(f, "\"{}\"", s.as_str()), Literal::String(ref s) => write!(f, "\"{}\"", s.as_str()),
// Literal::Usize(integer) => write!(f, "u{}", integer),
} }
} }
} }
@@ -561,7 +578,10 @@ pub enum Term {
Clause(Cell<RegType>, Atom, Vec<Term>), Clause(Cell<RegType>, Atom, Vec<Term>),
Cons(Cell<RegType>, Box<Term>, Box<Term>), Cons(Cell<RegType>, Box<Term>, Box<Term>),
Literal(Cell<RegType>, Literal), Literal(Cell<RegType>, Literal),
PartialString(Cell<RegType>, Atom, Option<Box<Term>>), // PartialString wraps a String in anticipation of it absorbing
// other PartialString variants in as_partial_string.
PartialString(Cell<RegType>, String, Box<Term>),
CompleteString(Cell<RegType>, Atom),
Var(Cell<VarReg>, Rc<String>), Var(Cell<VarReg>, Rc<String>),
} }

View File

@@ -61,6 +61,14 @@ impl<R> CharReader<R> {
pub fn inner_mut(&mut self) -> &mut R { pub fn inner_mut(&mut self) -> &mut R {
&mut self.inner &mut self.inner
} }
// Return the number of bytes remaining to be read. Useful for,
// e.g., determining the position relative to the end of the
// owning stream.
#[inline]
pub fn rem_buf_len(&self) -> usize {
self.buf.len() - self.pos
}
} }
pub trait CharRead { pub trait CharRead {
@@ -96,7 +104,7 @@ impl<R> CharReader<R> {
self.inner self.inner
} }
fn reset_buffer(&mut self) { pub fn reset_buffer(&mut self) {
self.buf.clear(); self.buf.clear();
self.pos = 0; self.pos = 0;
} }
@@ -246,33 +254,6 @@ impl<R: Read> CharRead for CharReader<R> {
} }
} }
/*
impl<R: Seek> BufReader<R> {
/// Seeks relative to the current position. If the new position lies within the buffer,
/// the buffer will not be flushed, allowing for more efficient seeks.
/// This method does not return the location of the underlying reader, so the caller
/// must track this information themselves if it is required.
#[stable(feature = "bufreader_seek_relative", since = "1.53.0")]
pub fn seek_relative(&mut self, offset: i64) -> io::Result<()> {
let pos = self.pos as u64;
if offset < 0 {
if let Some(new_pos) = pos.checked_sub((-offset) as u64) {
self.pos = new_pos as usize;
return Ok(());
}
} else {
if let Some(new_pos) = pos.checked_add(offset as u64) {
if new_pos <= self.cap as u64 {
self.pos = new_pos as usize;
return Ok(());
}
}
}
self.seek(SeekFrom::Current(offset)).map(drop)
}
}
*/
impl<R: Read> Read for CharReader<R> { impl<R: Read> Read for CharReader<R> {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
// // If we don't have any buffered data and we're doing a massive read // // If we don't have any buffered data and we're doing a massive read
@@ -377,108 +358,6 @@ where
} }
} }
/*
#[stable(feature = "rust1", since = "1.0.0")]
impl<R: Seek> Seek for BufReader<R> {
/// Seek to an offset, in bytes, in the underlying reader.
///
/// The position used for seeking with [`SeekFrom::Current`]`(_)` is the
/// position the underlying reader would be at if the `BufReader<R>` had no
/// internal buffer.
///
/// Seeking always discards the internal buffer, even if the seek position
/// would otherwise fall within it. This guarantees that calling
/// [`BufReader::into_inner()`] immediately after a seek yields the underlying reader
/// at the same position.
///
/// To seek without discarding the internal buffer, use [`BufReader::seek_relative`].
///
/// See [`std::io::Seek`] for more details.
///
/// Note: In the edge case where you're seeking with [`SeekFrom::Current`]`(n)`
/// where `n` minus the internal buffer length overflows an `i64`, two
/// seeks will be performed instead of one. If the second seek returns
/// [`Err`], the underlying reader will be left at the same position it would
/// have if you called `seek` with [`SeekFrom::Current`]`(0)`.
///
/// [`std::io::Seek`]: Seek
fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> {
let result: u64;
if let SeekFrom::Current(n) = pos {
let remainder = (self.cap - self.pos) as i64;
// it should be safe to assume that remainder fits within an i64 as the alternative
// means we managed to allocate 8 exbibytes and that's absurd.
// But it's not out of the realm of possibility for some weird underlying reader to
// support seeking by i64::MIN so we need to handle underflow when subtracting
// remainder.
if let Some(offset) = n.checked_sub(remainder) {
result = self.inner.seek(SeekFrom::Current(offset))?;
} else {
// seek backwards by our remainder, and then by the offset
self.inner.seek(SeekFrom::Current(-remainder))?;
self.discard_buffer();
result = self.inner.seek(SeekFrom::Current(n))?;
}
} else {
// Seeking with Start/End doesn't care about our buffer length.
result = self.inner.seek(pos)?;
}
self.discard_buffer();
Ok(result)
}
/// Returns the current seek position from the start of the stream.
///
/// The value returned is equivalent to `self.seek(SeekFrom::Current(0))`
/// but does not flush the internal buffer. Due to this optimization the
/// function does not guarantee that calling `.into_inner()` immediately
/// afterwards will yield the underlying reader at the same position. Use
/// [`BufReader::seek`] instead if you require that guarantee.
///
/// # Panics
///
/// This function will panic if the position of the inner reader is smaller
/// than the amount of buffered data. That can happen if the inner reader
/// has an incorrect implementation of [`Seek::stream_position`], or if the
/// position has gone out of sync due to calling [`Seek::seek`] directly on
/// the underlying reader.
///
/// # Example
///
/// ```no_run
/// use std::{
/// io::{self, BufRead, BufReader, Seek},
/// fs::File,
/// };
///
/// fn main() -> io::Result<()> {
/// let mut f = BufReader::new(File::open("foo.txt")?);
///
/// let before = f.stream_position()?;
/// f.read_line(&mut String::new())?;
/// let after = f.stream_position()?;
///
/// println!("The first line was {} bytes long", after - before);
/// Ok(())
/// }
/// ```
fn stream_position(&mut self) -> io::Result<u64> {
let remainder = (self.cap - self.pos) as u64;
self.inner.stream_position().map(|pos| {
pos.checked_sub(remainder).expect(
"overflow when subtracting remaining buffer size from inner stream position",
)
})
}
}
*/
/*
impl<T> SizeHint for CharReader<T> {
fn lower_bound(&self) -> usize {
self.buffer().len()
}
}
*/
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {

View File

@@ -1,6 +1,6 @@
use lexical::parse_lossy; use lexical::parse_lossy;
use ordered_float::*;
use crate::arena::ArenaAllocated;
use crate::atom_table::*; use crate::atom_table::*;
pub use crate::machine::machine_state::*; pub use crate::machine::machine_state::*;
use crate::parser::ast::*; use crate::parser::ast::*;
@@ -367,7 +367,7 @@ 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::UnexpectedChar(c, self.line_num, self.col_num)) Err(ParserError::IncompleteReduction(self.line_num, self.col_num))
} }
} }
@@ -400,11 +400,7 @@ impl<'a, R: CharRead> Lexer<'a, R> {
}, },
) )
} else { } else {
// on failure, restore the token characters and backslash. Err(ParserError::IncompleteReduction(self.line_num, self.col_num))
// self.reader.put_back_all(token.chars().map(Ok));
// self.reader.put_back(Ok('\\'));
Err(ParserError::UnexpectedChar(c, self.line_num, self.col_num))
} }
} }
@@ -637,12 +633,8 @@ impl<'a, R: CharRead> Lexer<'a, R> {
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 result = OrderedFloat(parse_lossy::<f64, _>(token.as_bytes())?); Ok(Token::Literal(Literal::from(float_alloc!(n, self.machine_st.arena))))
Ok(Token::Literal(Literal::Float(arena_alloc!(
result,
&mut self.machine_st.arena
))))
} }
fn skip_underscore_in_number(&mut self) -> Result<char, ParserError> { fn skip_underscore_in_number(&mut self) -> Result<char, ParserError> {
@@ -752,20 +744,18 @@ impl<'a, R: CharRead> Lexer<'a, R> {
} }
} }
let n = OrderedFloat(parse_lossy::<f64, _>(token.as_bytes())?); let n = parse_lossy::<f64, _>(token.as_bytes())?;
Ok(Token::Literal(Literal::Float(arena_alloc!( Ok(Token::Literal(Literal::from(
n, float_alloc!(n, self.machine_st.arena)
&mut self.machine_st.arena )))
))))
} else { } else {
return Ok(self.vacate_with_float(token)?); return Ok(self.vacate_with_float(token)?);
} }
} else { } else {
let n = OrderedFloat(parse_lossy::<f64, _>(token.as_bytes())?); let n = parse_lossy::<f64, _>(token.as_bytes())?;
Ok(Token::Literal(Literal::Float(arena_alloc!( Ok(Token::Literal(Literal::from(
n, float_alloc!(n, self.machine_st.arena)
&mut self.machine_st.arena )))
))))
} }
} else { } else {
self.return_char('.'); self.return_char('.');

View File

@@ -7,28 +7,7 @@ macro_rules! char_class {
#[macro_export] #[macro_export]
macro_rules! alpha_char { macro_rules! alpha_char {
($c: expr) => { ($c: expr) => {
match $c { $c.is_alphabetic() || $c == '_'
'a'..='z' => true,
'A'..='Z' => true,
'_' => true,
'\u{00A0}'..='\u{00BF}' => true,
'\u{00C0}'..='\u{00D6}' => true,
'\u{00D8}'..='\u{00F6}' => true,
'\u{00F8}'..='\u{00FF}' => true,
'\u{0100}'..='\u{017F}' => true, // Latin Extended-A
'\u{0180}'..='\u{024F}' => true, // Latin Extended-B
'\u{0250}'..='\u{02AF}' => true, // IPA Extensions
'\u{02B0}'..='\u{02FF}' => true, // Spacing Modifier Letters
'\u{0300}'..='\u{036F}' => true, // Combining Diacritical Marks
'\u{0370}'..='\u{03FF}' => true, // Greek/Coptic
'\u{0400}'..='\u{04FF}' => true, // Cyrillic
'\u{0500}'..='\u{052F}' => true, // Cyrillic Supplement
'\u{0530}'..='\u{058F}' => true, // Armenian
'\u{0590}'..='\u{05FF}' => true, // Hebrew
'\u{0600}'..='\u{06FF}' => true, // Arabic
'\u{0700}'..='\u{074F}' => true, // Syriac
_ => false,
}
}; };
} }
@@ -63,7 +42,7 @@ macro_rules! octet_char {
#[macro_export] #[macro_export]
macro_rules! capital_letter_char { macro_rules! capital_letter_char {
($c: expr) => { ($c: expr) => {
('A'..='Z').contains(&$c) $c.is_uppercase()
}; };
} }
@@ -174,7 +153,7 @@ macro_rules! octal_digit_char {
#[macro_export] #[macro_export]
macro_rules! binary_digit_char { macro_rules! binary_digit_char {
($c: expr) => { ($c: expr) => {
$c >= '0' && $c <= '1' $c == '0' || $c == '1'
}; };
} }
@@ -213,7 +192,7 @@ macro_rules! single_quote_char {
#[macro_export] #[macro_export]
macro_rules! small_letter_char { macro_rules! small_letter_char {
($c: expr) => { ($c: expr) => {
('a'..='z').contains(&$c) $c.is_alphabetic() && !$c.is_uppercase()
}; };
} }

View File

@@ -1,5 +1,6 @@
#[cfg(feature = "num-rug-adapter")] #[cfg(feature = "num-rug-adapter")]
use num_rug_adapter as rug; pub use num_rug_adapter as rug;
#[cfg(feature = "rug")] #[cfg(feature = "rug")]
pub use rug; pub use rug;

View File

@@ -4,9 +4,7 @@ use crate::parser::ast::*;
use crate::parser::char_reader::*; use crate::parser::char_reader::*;
use crate::parser::lexer::*; use crate::parser::lexer::*;
use ordered_float::OrderedFloat; use crate::parser::rug::ops::NegAssign;
use rug::ops::NegAssign;
use std::cell::Cell; use std::cell::Cell;
use std::mem; use std::mem;
@@ -51,11 +49,10 @@ struct TokenDesc {
spec: u32, spec: u32,
} }
fn is_partial_string( pub(crate) fn as_partial_string(
head: Term, head: Term,
mut tail: Term, mut tail: Term,
atom_tbl: &mut AtomTable, ) -> Result<(String, Option<Box<Term>>), Term> {
) -> Result<(Atom, Option<Box<Term>>), Term> {
let mut string = match &head { let mut string = match &head {
Term::Literal(_, Literal::Atom(atom)) => { Term::Literal(_, Literal::Atom(atom)) => {
if let Some(c) = atom.as_char() { if let Some(c) = atom.as_char() {
@@ -94,6 +91,15 @@ fn is_partial_string(
tail_ref = succ; tail_ref = succ;
} }
Term::PartialString(_, pstr, tail) => {
string += &pstr;
tail_ref = tail;
}
Term::CompleteString(_, cstr) => {
string += cstr.as_str();
tail = Term::Literal(Cell::default(), Literal::Atom(atom!("[]")));
break;
}
tail_ref => { tail_ref => {
tail = mem::replace(tail_ref, Term::AnonVar); tail = mem::replace(tail_ref, Term::AnonVar);
break; break;
@@ -103,21 +109,17 @@ fn is_partial_string(
match &tail { match &tail {
Term::AnonVar | Term::Var(..) => { Term::AnonVar | Term::Var(..) => {
let pstr_atom = atom_tbl.build_with(&string); Ok((string, Some(Box::new(tail))))
Ok((pstr_atom, Some(Box::new(tail))))
} }
Term::Literal(_, Literal::Atom(atom!("[]"))) => { Term::Literal(_, Literal::Atom(atom!("[]"))) => {
let pstr_atom = atom_tbl.build_with(&string); Ok((string, None))
Ok((pstr_atom, None))
} }
Term::Literal(_, Literal::String(tail)) => { Term::Literal(_, Literal::String(tail)) => {
string += tail.as_str(); string += tail.as_str();
let pstr_atom = atom_tbl.build_with(&string); Ok((string, None))
Ok((pstr_atom, None))
} }
_ => { _ => {
let pstr_atom = atom_tbl.build_with(&string); Ok((string, Some(Box::new(tail))))
Ok((pstr_atom, Some(Box::new(tail))))
} }
} }
} }
@@ -414,7 +416,7 @@ impl<'a, R: CharRead> Parser<'a, R> {
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::PartialString(Cell::default(), s, None)); self.terms.push(Term::CompleteString(Cell::default(), s));
TokenType::Term TokenType::Term
} }
Token::Literal(c) => { Token::Literal(c) => {
@@ -566,24 +568,19 @@ impl<'a, R: CharRead> Parser<'a, R> {
let head = subterms.pop().unwrap(); let head = subterms.pop().unwrap();
self.terms.push( self.terms.push(
match is_partial_string(head, tail, &mut self.lexer.machine_st.atom_tbl) { match as_partial_string(head, tail) {
Ok((string_buf, tail_opt)) => { Ok((string_buf, Some(tail))) => {
Term::PartialString(Cell::default(), string_buf, tail_opt) 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, Err(term) => term,
}, },
); );
/*
self.terms.push(Term::Cons(
Cell::default(),
Box::new(head),
Box::new(tail),
));
*/
} else { } else {
self.terms self.terms.push(Term::Clause(Cell::default(), name, subterms));
.push(Term::Clause(Cell::default(), name, subterms));
} }
if let Some(&mut TokenDesc { if let Some(&mut TokenDesc {
@@ -743,9 +740,13 @@ impl<'a, R: CharRead> Parser<'a, R> {
self.terms.push(match list { self.terms.push(match list {
Term::Cons(_, head, tail) => { Term::Cons(_, head, tail) => {
match is_partial_string(*head, *tail, &mut self.lexer.machine_st.atom_tbl) { match as_partial_string(*head, *tail) {
Ok((string_buf, tail_opt)) => { Ok((string_buf, Some(tail))) => {
Term::PartialString(Cell::default(), string_buf, tail_opt) 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, Err(term) => term,
} }
@@ -823,13 +824,13 @@ impl<'a, R: CharRead> Parser<'a, R> {
self.reduce_op(1400); self.reduce_op(1400);
if self.stack.len() == 1 { if self.stack.len() <= 1 {
return false; return false;
} }
let idx = self.stack.len() - 2; let idx = self.stack.len() - 2;
let td = self.stack.remove(idx); let td = self.stack.remove(idx);
match td.tt { match td.tt {
TokenType::Open | TokenType::OpenCT => { TokenType::Open | TokenType::OpenCT => {
if self.stack[idx].tt == TokenType::Comma { if self.stack[idx].tt == TokenType::Comma {
@@ -948,9 +949,9 @@ impl<'a, R: CharRead> Parser<'a, R> {
self.negate_number(n, negate_rc, |r, _| Literal::Rational(r)) self.negate_number(n, negate_rc, |r, _| Literal::Rational(r))
} }
Token::Literal(Literal::Float(n)) => self.negate_number( Token::Literal(Literal::Float(n)) => self.negate_number(
**n, **n.as_ptr(),
|n| OrderedFloat(-n.into_inner()), |n| -n,
|n, arena| Literal::Float(arena_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) { if let Some(name) = atomize_constant(&mut self.lexer.machine_st.atom_tbl, c) {

View File

@@ -58,13 +58,6 @@ impl<T: RawBlockTraits> RawBlock<T> {
} }
} }
/*
#[inline]
pub fn take(&mut self) -> Self {
mem::replace(self, Self::empty_block())
}
*/
#[inline] #[inline]
pub fn size(&self) -> usize { pub fn size(&self) -> usize {
self.top as usize - self.base as usize self.top as usize - self.base as usize

View File

@@ -1,29 +1,29 @@
use crate::parser::ast::*; use crate::parser::ast::*;
use crate::parser::parser::*; use crate::parser::parser::*;
use crate::arena::*;
use crate::atom_table::*; use crate::atom_table::*;
use crate::forms::*; use crate::forms::*;
use crate::iterators::*; use crate::iterators::*;
use crate::machine::heap::*; use crate::machine::heap::*;
use crate::machine::machine_errors::*;
use crate::machine::machine_indices::*; use crate::machine::machine_indices::*;
use crate::machine::machine_state::MachineState; use crate::machine::machine_state::MachineState;
use crate::machine::streams::*; use crate::machine::streams::*;
use crate::parser::char_reader::*; use crate::parser::char_reader::*;
use crate::repl_helper::Helper;
use crate::types::*; use crate::types::*;
use fxhash::FxBuildHasher; use fxhash::FxBuildHasher;
use indexmap::IndexSet;
use rustyline::error::ReadlineError; use rustyline::error::ReadlineError;
use rustyline::{Cmd, Config, Editor, KeyEvent}; use rustyline::{Config, Editor};
use std::collections::VecDeque; use std::collections::VecDeque;
use std::io::{Cursor, Error, ErrorKind, Read}; use std::io::{Cursor, Error, ErrorKind, Read};
type SubtermDeque = VecDeque<(usize, usize)>; type SubtermDeque = VecDeque<(usize, usize)>;
// pub(crate) type PrologStream = ParsingStream<Stream>;
impl MachineState { impl MachineState {
pub(crate) fn devour_whitespace( pub(crate) fn devour_whitespace(
&mut self, &mut self,
@@ -41,19 +41,21 @@ impl MachineState {
&mut self, &mut self,
mut inner: Stream, mut inner: Stream,
op_dir: &OpDir, op_dir: &OpDir,
) -> Result<TermWriteResult, ParserError> { ) -> Result<TermWriteResult, CompilationError> {
let (term, num_lines_read) = { let (term, num_lines_read) = {
let prior_num_lines_read = inner.lines_read(); let prior_num_lines_read = inner.lines_read();
let mut parser = Parser::new(inner, self); let mut parser = Parser::new(inner, self);
parser.add_lines_read(prior_num_lines_read); parser.add_lines_read(prior_num_lines_read);
let term = parser.read_term(&CompositeOpDir::new(op_dir, None))?; let term = parser.read_term(&CompositeOpDir::new(op_dir, None))
.map_err(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);
Ok(write_term_to_heap(&term, &mut self.heap, &mut self.atom_tbl)) write_term_to_heap(&term, &mut self.heap, &mut self.atom_tbl)
} }
} }
@@ -78,23 +80,21 @@ fn get_prompt() -> &'static str {
} }
} }
#[inline]
pub fn input_stream(arena: &mut Arena) -> Stream {
let input_stream = ReadlineStream::new("");
Stream::from_readline_stream(input_stream, arena)
}
#[derive(Debug)] #[derive(Debug)]
pub struct ReadlineStream { pub struct ReadlineStream {
rl: Editor<()>, rl: Editor<Helper>,
pending_input: Cursor<String>, pending_input: Cursor<String>,
add_history: bool,
} }
impl ReadlineStream { impl ReadlineStream {
#[inline] #[inline]
pub fn new(pending_input: &str) -> Self { pub fn new(pending_input: &str, add_history: bool) -> Self {
let config = Config::builder().check_cursor_position(true).build(); let config = Config::builder().check_cursor_position(true).build();
let mut rl = Editor::<()>::with_config(config); let helper = Helper::new();
let mut rl = Editor::with_config(config);
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);
@@ -103,14 +103,20 @@ impl ReadlineStream {
} }
} }
rl.bind_sequence(KeyEvent::from('\t'), Cmd::Insert(1, "\t".to_string())); // rl.bind_sequence(KeyEvent::from('\t'), Cmd::Insert(1, "\t".to_string()));
ReadlineStream { ReadlineStream {
rl, rl,
pending_input: Cursor::new(pending_input.to_owned()), pending_input: Cursor::new(pending_input.to_owned()),
add_history: add_history,
} }
} }
pub fn set_atoms_for_completion(&mut self, atoms: *const IndexSet<Atom>) {
let helper = self.rl.helper_mut().unwrap();
helper.atoms = atoms;
}
#[inline] #[inline]
pub fn reset(&mut self) { pub fn reset(&mut self) {
self.pending_input.get_mut().clear(); self.pending_input.get_mut().clear();
@@ -143,6 +149,9 @@ impl ReadlineStream {
} }
fn save_history(&mut self) { fn save_history(&mut self) {
if !self.add_history {
return;
};
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() { if path.exists() {
@@ -239,7 +248,7 @@ pub(crate) fn write_term_to_heap(
term: &Term, term: &Term,
heap: &mut Heap, heap: &mut Heap,
atom_tbl: &mut AtomTable, atom_tbl: &mut AtomTable,
) -> TermWriteResult { ) -> 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)
} }
@@ -290,7 +299,7 @@ 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::PartialString(_, _, ref src, None) => &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 {
@@ -305,7 +314,7 @@ impl<'a, 'b> TermWriter<'a, 'b> {
} }
} }
fn write_term_to_heap(mut self, term: &'a Term) -> TermWriteResult { fn write_term_to_heap(mut self, term: &'a Term) -> Result<TermWriteResult, CompilationError> {
let heap_loc = self.heap.len(); let heap_loc = self.heap.len();
for term in breadth_first_iter(term, true) { for term in breadth_first_iter(term, true) {
@@ -327,7 +336,11 @@ impl<'a, 'b> TermWriter<'a, 'b> {
self.push_stub_addr(); self.push_stub_addr();
self.push_stub_addr(); self.push_stub_addr();
} }
&TermRef::Clause(Level::Root, _, ref ct, subterms) => { &TermRef::Clause(Level::Root, _, name, subterms) => {
if subterms.len() > MAX_ARITY {
return Err(CompilationError::ExceededMaxArity);
}
self.heap.push(if subterms.len() == 0 { self.heap.push(if subterms.len() == 0 {
heap_loc_as_cell!(heap_loc + 1) heap_loc_as_cell!(heap_loc + 1)
} else { } else {
@@ -335,7 +348,7 @@ impl<'a, 'b> TermWriter<'a, 'b> {
}); });
self.queue.push_back((subterms.len(), h + 2)); self.queue.push_back((subterms.len(), h + 2));
let named = atom_as_cell!(ct.name(), subterms.len()); let named = atom_as_cell!(name, subterms.len());
self.heap.push(named); self.heap.push(named);
@@ -345,9 +358,9 @@ impl<'a, 'b> TermWriter<'a, 'b> {
continue; continue;
} }
&TermRef::Clause(_, _, ref ct, subterms) => { &TermRef::Clause(_, _, name, subterms) => {
self.queue.push_back((subterms.len(), h + 1)); self.queue.push_back((subterms.len(), h + 1));
let named = atom_as_cell!(ct.name(), subterms.len()); let named = atom_as_cell!(name, subterms.len());
self.heap.push(named); self.heap.push(named);
@@ -373,14 +386,18 @@ impl<'a, 'b> TermWriter<'a, 'b> {
continue; continue;
} }
&TermRef::PartialString(lvl, _, ref src, tail) => { &TermRef::CompleteString(_, _, ref src) => {
if tail.is_some() {
allocate_pstr(self.heap, src.as_str(), self.atom_tbl);
} else {
put_complete_string(self.heap, src.as_str(), self.atom_tbl); put_complete_string(self.heap, src.as_str(), self.atom_tbl);
} }
&TermRef::PartialString(lvl, _, ref src, _) => {
if let Level::Root = lvl {
// Var tags can't refer directly to partial strings,
// so a PStrLoc cell must be pushed.
self.heap.push(pstr_loc_as_cell!(heap_loc + 1));
}
allocate_pstr(self.heap, src.as_str(), self.atom_tbl);
if tail.is_some() {
let h = self.heap.len(); let h = self.heap.len();
self.queue.push_back((1, h - 1)); self.queue.push_back((1, h - 1));
@@ -388,7 +405,6 @@ impl<'a, 'b> TermWriter<'a, 'b> {
continue; continue;
} }
} }
}
&TermRef::Var(_, _, ref var) => { &TermRef::Var(_, _, ref var) => {
if let Some((arity, site_h)) = self.queue.pop_front() { if let Some((arity, site_h)) = self.queue.pop_front() {
if let Some(addr) = self.var_dict.get(var).cloned() { if let Some(addr) = self.var_dict.get(var).cloned() {
@@ -410,9 +426,9 @@ impl<'a, 'b> TermWriter<'a, 'b> {
self.modify_head_of_queue(&term, h); self.modify_head_of_queue(&term, h);
} }
TermWriteResult { Ok(TermWriteResult {
heap_loc, heap_loc,
var_dict: self.var_dict, var_dict: self.var_dict,
} })
} }
} }

110
src/repl_helper.rs Normal file
View File

@@ -0,0 +1,110 @@
use indexmap::IndexSet;
use rustyline::completion::{Completer, Candidate};
use rustyline::hint::Hinter;
use rustyline::validate::Validator;
use rustyline::highlight::{MatchingBracketHighlighter, Highlighter};
use rustyline::{Helper as RlHelper, Result, Context};
use crate::atom_table::{Atom, STATIC_ATOMS_MAP};
// TODO: Maybe add validation to the helper
pub struct Helper {
highligher: MatchingBracketHighlighter,
pub atoms: *const IndexSet<Atom>,
}
impl Helper {
pub fn new() -> Self {
Self {
highligher: MatchingBracketHighlighter::new(),
atoms: std::ptr::null(),
}
}
}
impl RlHelper for Helper {}
fn get_prefix(line: &str, pos: usize) -> Option<usize> {
let mut start_of_atom = None;
let mut first_letter = true;
for (i, char) in line.chars().enumerate() {
if first_letter {
if char.is_alphabetic() && char.is_lowercase() {
start_of_atom = Some(i);
}
first_letter = false;
}
if !char.is_alphanumeric() && char != '_' {
first_letter = true;
start_of_atom = None;
}
if i == pos {
break
}
}
if first_letter || pos == 0 {
start_of_atom = Some(pos)
}
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 {
type Candidate = StrPtr;
fn complete(&self, line: &str, pos: usize, _ctx: &Context<'_>) -> Result<(usize, Vec<Self::Candidate>)> {
let start_of_prefix = get_prefix(line, pos);
if let Some(idx) = start_of_prefix {
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()));
matching
}))
} else {
Ok((0, vec![]))
}
}
}
impl Highlighter for Helper {
fn highlight<'l>(&self, line: &'l str, pos: usize) -> std::borrow::Cow<'l, str> {
self.highligher.highlight(line, pos)
}
fn highlight_char(&self, line: &str, pos: usize) -> bool {
self.highligher.highlight_char(line, pos)
}
}
impl Validator for Helper {}
impl Hinter for Helper {
type Hint = String;
}

View File

@@ -100,7 +100,7 @@ run :-
Dss Dss
), ),
E, E,
( write('caught: '), write(E), nl, ( loader:write_error(E), nl,
portray_clause([N, Settings, Vs, Gs4, Dss]), nl, portray_clause([N, Settings, Vs, Gs4, Dss]), nl,
false false
) )

View File

@@ -12,15 +12,15 @@ test_queries_on_setup_call_cleanup :-
catch(setup_call_cleanup(X=throw(ex), true, X), ex, true), catch(setup_call_cleanup(X=throw(ex), true, X), ex, true),
findall([S,G,C], setup_call_cleanup(S = 1, G = 2, C = 3), [[1,2,3]]), findall([S,G,C], setup_call_cleanup(S = 1, G = 2, C = 3), [[1,2,3]]),
findall([S,G,C], setup_call_cleanup((S=1;S=2), G=3, C=4), [[1,3,4]]), findall([S,G,C], setup_call_cleanup((S=1;S=2), G=3, C=4), [[1,3,4]]),
findall([S,G], setup_call_cleanup(S=1, G=2, writeq(S+G)), [[1,2]]), findall([S,G], setup_call_cleanup(S=1, G=2, write_term(S+G, [variable_names(['S'=S,'G'=G])])), [[1,2]]),
findall([S,G], setup_call_cleanup(S=1, (G=2;G=3), writeq(S+G)), [[1,2],[1,3]]), findall([S,G], setup_call_cleanup(S=1, (G=2;G=3), write_term(S+G, [variable_names(['S'=S,'G'=G])])), [[1,2],[1,3]]),
findall([S,G], (setup_call_cleanup(S=1, G=2, writeq(S+G>A+B)), A = 3, B = 4), [[1,2]]), findall([S,G], (setup_call_cleanup(S=1, G=2, write_term(S+G>A+B, [variable_names(['S'=S,'G'=G,'A'=A,'B'=B])])), A = 3, B = 4), [[1,2]]),
findall([S,G,E], catch(setup_call_cleanup(S=1, (G=2;G=3,throw(x)), writeq(S+G)), E, true), [[1,2,_],[_,_,x]]), findall([S,G,E], catch(setup_call_cleanup(S=1, (G=2;G=3,throw(x)), write_term(S+G, [variable_names(['S'=S,'G'=G])])), E, true), [[1,2,_],[_,_,x]]),
findall([S,B,G], (setup_call_cleanup(S=1, (G=2;G=3),writeq(S+G>B)), B=4, !), [[1,4,2]]), findall([S,B,G], (setup_call_cleanup(S=1, (G=2;G=3),write_term(S+G>B, [variable_names(['S'=S,'G'=G,'B'=B])])), B=4, !), [[1,4,2]]),
findall([S,G,B], (setup_call_cleanup(S=1,G=2,writeq(S+G>B)),B=3,!), [[1,2,3]]), findall([S,G,B], (setup_call_cleanup(S=1,G=2,write_term(S+G>B, [variable_names(['S'=S,'G'=G,'B'=B])])),B=3,!), [[1,2,3]]),
findall([S,G,B], (setup_call_cleanup(S=1,(G=2;false),writeq(S+G>B)),B=3,!), [[1,2,3]]), findall([S,G,B], (setup_call_cleanup(S=1,(G=2;false),write_term(S+G>B, [variable_names(['S'=S,'G'=G,'B'=B])])),B=3,!), [[1,2,3]]),
findall([S,G,B], (setup_call_cleanup(S=1,(G=2;S=2),writeq(S+G>B)), B=3, !), [[1,2,3]]), findall([S,G,B], (setup_call_cleanup(S=1,(G=2;S=2),write_term(S+G>B, [variable_names(['S'=S,'G'=G,'B'=B])])), B=3, !), [[1,2,3]]),
catch((setup_call_cleanup(S=1,(G=2;G=3), writeq(S+G>B)), B=4, !, throw(x)), x, true), catch((setup_call_cleanup(S=1,(G=2;G=3), write_term(S+G>B, [variable_names(['S'=S,'G'=G,'B'=B])])), B=4, !, throw(x)), x, true),
findall(Pat, catch(setup_call_cleanup(true,throw(goal),throw(cl)), Pat, true), [goal]), findall(Pat, catch(setup_call_cleanup(true,throw(goal),throw(cl)), Pat, true), [goal]),
findall(Pat, catch(( setup_call_cleanup(true,(G=1;G=2),throw(cl)), throw(cont)), Pat, true), [cont]), findall(Pat, catch(( setup_call_cleanup(true,(G=1;G=2),throw(cl)), throw(cont)), Pat, true), [cont]),
findall([X,Y], (setup_call_cleanup(true, (X=1;X=2), writeq(a)), setup_call_cleanup(true,(Y=1;Y=2),writeq(b)), !), [[1,1]]). findall([X,Y], (setup_call_cleanup(true, (X=1;X=2), writeq(a)), setup_call_cleanup(true,(Y=1;Y=2),writeq(b)), !), [[1,1]]).

View File

@@ -57,6 +57,7 @@ delegate_task([Arg0|Args], Goals0) :-
; member(Arg0, ["-v", "--version"]) -> print_version ; member(Arg0, ["-v", "--version"]) -> print_version
; member(Arg0, ["-g", "--goal"]) -> gather_goal(g, Args, Goals0) ; member(Arg0, ["-g", "--goal"]) -> gather_goal(g, Args, Goals0)
; member(Arg0, ["-f"]) -> disable_init_file ; member(Arg0, ["-f"]) -> disable_init_file
; member(Arg0, ["--no-add-history"]) -> ignore_machine_arg
; atom_chars(Mod, Arg0), ; atom_chars(Mod, Arg0),
catch(consult(Mod), E, print_exception(E)) catch(consult(Mod), E, print_exception(E))
), ),
@@ -73,7 +74,9 @@ print_help :-
write(' -g, --goal GOAL '), write(' -g, --goal GOAL '),
write('Run the query GOAL'), nl, write('Run the query GOAL'), nl,
write(' -f '), write(' -f '),
write('Fast startup. Do not load initialization file (~/.scryerrc)'),nl, write('Fast startup. Do not load initialization file (~/.scryerrc)'), nl,
write(' --no-add-history '),
write('Prevent adding input to history file (~/.scryer_history)'), nl,
% write(' '), % write(' '),
halt. halt.
@@ -94,6 +97,8 @@ gather_goal(Type, Args0, Goals) :-
disable_init_file :- disable_init_file :-
asserta('disabled_init_file'). asserta('disabled_init_file').
ignore_machine_arg.
arg_type(g). arg_type(g).
arg_type(t). arg_type(t).
arg_type(g(_)). arg_type(g(_)).
@@ -124,8 +129,8 @@ run_goals([g(Gs0)|Goals]) :-
), ),
run_goals(Goals). run_goals(Goals).
run_goals([Goal|_]) :- run_goals([Goal|_]) :-
write('caught: '), loader:write_error(error(domain_error(arg_type, Goal), run_goals/1)),
write(error(domain_error(arg_type, Goal), run_goals/1)), nl, nl,
halt. halt.
repl :- repl :-
@@ -175,23 +180,26 @@ submit_query_and_print_results_(Term, VarList) :-
'$get_b_value'(B), '$get_b_value'(B),
bb_put('$report_all', false), bb_put('$report_all', false),
bb_put('$report_n_more', 0), bb_put('$report_n_more', 0),
'$call'(Term), call(user:Term),
write_eqs_and_read_input(B, VarList), write_eqs_and_read_input(B, VarList),
!. !.
submit_query_and_print_results_(_, _) :- submit_query_and_print_results_(_, _) :-
( bb_get('$answer_count', 0) ->
write(' ')
; true
),
write('false.'), write('false.'),
nl. nl.
submit_query_and_print_results(Term0, VarList) :- submit_query_and_print_results(Term, VarList) :-
( functor(Term0, call, _) -> % ( functor(Term0, call, _) ->
Term = Term0 % prevent pre-mature expansion of incomplete goal % Term = Term0 % prevent pre-mature expansion of incomplete goal
% in the first argument, which is done by call/N % % in the first argument, which is done by call/N
; expand_goal(Term0, user, Term) % ; expand_goal(Term0, user, Term)
), % ),
setup_call_cleanup(bb_put('$first_answer', true), bb_put('$answer_count', 0),
submit_query_and_print_results_(Term, VarList), submit_query_and_print_results_(Term, VarList).
bb_put('$first_answer', false)).
needs_bracketing(Value, Op) :- needs_bracketing(Value, Op) :-
@@ -293,14 +301,17 @@ write_eqs_and_read_input(B, VarList) :-
append(Equations, AttrGoals, Goals), append(Equations, AttrGoals, Goals),
% one layer of depth added for (=/2) functor % one layer of depth added for (=/2) functor
maplist(\Term^Vs^term_variables_under_max_depth(Term, 22, Vs), Equations, EquationVars), maplist(\Term^Vs^term_variables_under_max_depth(Term, 22, Vs), Equations, EquationVars),
% maplist(term_variables_under_max_depth(22), Equations, EquationVars),
append([AttrGoalVars | EquationVars], Vars1), append([AttrGoalVars | EquationVars], Vars1),
term_variables(Vars1, Vars2), % deduplicate vars of Vars1 but preserve their order. term_variables(Vars1, Vars2), % deduplicate vars of Vars1 but preserve their order.
charsio:extend_var_list(Vars2, VarList, NewVarList0, fabricated), charsio:extend_var_list(Vars2, VarList, NewVarList0, fabricated),
( bb_get('$first_answer', true) -> bb_get('$answer_count', Count),
write(' '), ( Count =:= 0 ->
bb_put('$first_answer', false) write(' ')
; true ; true
), ),
Count1 is Count + 1,
bb_put('$answer_count', Count1),
( B0 == B -> ( B0 == B ->
( Goals == [] -> ( Goals == [] ->
write('true.'), nl write('true.'), nl
@@ -344,7 +355,9 @@ read_input(ThreadedGoals, NewVarList) :-
bb_put('$report_all', true), bb_put('$report_all', true),
nl, write('; '), false nl, write('; '), false
; C = f -> ; C = f ->
bb_put('$report_n_more', 5), bb_get('$answer_count', Count),
More is 5 - Count mod 5,
bb_put('$report_n_more', More),
nl, write('; '), false nl, write('; '), false
; read_input(ThreadedGoals, NewVarList) ; read_input(ThreadedGoals, NewVarList)
). ).
@@ -408,8 +421,7 @@ print_exception(E) :-
% "^C". % "^C".
; true ; true
), ),
write_term('caught: ', [quoted(false), max_depth(20)]), loader:write_error(E),
writeq(E),
nl. nl.
print_exception_with_check(E) :- print_exception_with_check(E) :-

View File

@@ -5,9 +5,6 @@ use crate::machine::machine_indices::*;
use crate::machine::partial_string::PartialString; use crate::machine::partial_string::PartialString;
use crate::machine::streams::*; use crate::machine::streams::*;
use crate::parser::ast::Fixnum; use crate::parser::ast::Fixnum;
use crate::parser::rug::{Integer, Rational};
use ordered_float::OrderedFloat;
use std::cmp::Ordering; use std::cmp::Ordering;
use std::convert::TryFrom; use std::convert::TryFrom;
@@ -18,58 +15,55 @@ use std::ops::{Add, Sub, SubAssign};
#[derive(BitfieldSpecifier, Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] #[derive(BitfieldSpecifier, Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
#[bits = 6] #[bits = 6]
pub enum HeapCellValueTag { pub enum HeapCellValueTag {
// non-constants / tags with adjoining forwarding bits. Str = 0b000011,
Cons = 0b00, Lis = 0b000101,
F64 = 0b01, Var = 0b000111,
Str = 0b000010, StackVar = 0b001001,
Lis = 0b000011, AttrVar = 0b001011,
Var = 0b000110, PStrLoc = 0b001101,
StackVar = 0b000111, PStrOffset = 0b001111,
AttrVar = 0b010011,
PStrLoc = 0b111111,
PStrOffset = 0b001110,
// constants. // constants.
Fixnum = 0b010010, Cons = 0b0,
Char = 0b011011, F64 = 0b010001,
Atom = 0b001010, Fixnum = 0b010011,
PStr = 0b001011, Char = 0b010101,
CStr = 0b010110, // a complete string. Atom = 0b010111,
PStr = 0b011001,
CStr = 0b011011,
} }
#[derive(BitfieldSpecifier, Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] #[derive(BitfieldSpecifier, Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
#[bits = 6] #[bits = 6]
pub enum HeapCellValueView { pub enum HeapCellValueView {
// non-constants / tags with adjoining forwarding bits. Str = 0b000011,
Cons = 0b00, Lis = 0b000101,
F64 = 0b01, Var = 0b000111,
Str = 0b000010, StackVar = 0b001001,
Lis = 0b000011, AttrVar = 0b001011,
Var = 0b000110, PStrLoc = 0b001101,
StackVar = 0b000111, PStrOffset = 0b001111,
AttrVar = 0b010011,
PStrLoc = 0b111111,
PStrOffset = 0b001110,
// constants. // constants.
Fixnum = 0b010010, Cons = 0b0,
Char = 0b011011, F64 = 0b010001,
Atom = 0b001010, Fixnum = 0b010011,
PStr = 0b001011, Char = 0b010101,
CStr = 0b010110, Atom = 0b010111,
PStr = 0b011001,
CStr = 0b011011,
// trail elements. // trail elements.
TrailedHeapVar = 0b011110, TrailedHeapVar = 0b011101,
TrailedStackVar = 0b011111, TrailedStackVar = 0b011111,
TrailedAttrVarHeapLink = 0b101110, TrailedAttrVarHeapLink = 0b100001,
TrailedAttrVarListLink = 0b100010, TrailedAttrVarListLink = 0b100011,
TrailedAttachedValue = 0b101010, TrailedAttachedValue = 0b100101,
TrailedBlackboardEntry = 0b100110, TrailedBlackboardEntry = 0b100111,
TrailedBlackboardOffset = 0b100111, TrailedBlackboardOffset = 0b101001,
} }
#[derive(BitfieldSpecifier, Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] #[derive(BitfieldSpecifier, Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
#[bits = 2] #[bits = 1]
pub enum ConsPtrMaskTag { pub enum ConsPtrMaskTag {
Cons = 0b00, Cons = 0b0,
F64 = 0b01,
} }
#[bitfield] #[bitfield]
@@ -77,6 +71,7 @@ pub enum ConsPtrMaskTag {
#[derive(Copy, Clone, Debug)] #[derive(Copy, Clone, Debug)]
pub struct ConsPtr { pub struct ConsPtr {
ptr: B61, ptr: B61,
f: bool,
m: bool, m: bool,
tag: ConsPtrMaskTag, tag: ConsPtrMaskTag,
} }
@@ -86,22 +81,28 @@ impl ConsPtr {
pub fn build_with(ptr: *const ArenaHeader, tag: ConsPtrMaskTag) -> Self { pub fn build_with(ptr: *const ArenaHeader, tag: ConsPtrMaskTag) -> Self {
ConsPtr::new() ConsPtr::new()
.with_ptr(ptr as *const u8 as u64) .with_ptr(ptr as *const u8 as u64)
.with_f(false)
.with_m(false) .with_m(false)
.with_tag(tag) .with_tag(tag)
} }
#[inline] #[inline(always)]
pub fn as_ptr(self) -> *mut u8 { pub fn as_ptr(self) -> *mut u8 {
self.ptr() as *mut _ self.ptr() as *mut _
} }
#[inline(always)]
pub fn get_tag(self) -> ConsPtrMaskTag {
self.tag()
}
} }
#[derive(BitfieldSpecifier, Copy, Clone, Debug)] #[derive(BitfieldSpecifier, Copy, Clone, Debug)]
#[bits = 6] #[bits = 6]
pub(crate) enum RefTag { pub(crate) enum RefTag {
HeapCell = 0b0110, HeapCell = 0b000111,
StackCell = 0b111, StackCell = 0b001001,
AttrVar = 0b10011, AttrVar = 0b001011,
} }
#[bitfield] #[bitfield]
@@ -244,66 +245,25 @@ pub struct HeapCellValue {
tag: HeapCellValueTag, tag: HeapCellValueTag,
} }
impl fmt::Display for HeapCellValue {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
read_heap_cell!(*self,
(HeapCellValueTag::Atom, (name, arity)) => {
if arity == 0 {
write!(f, "{}", name.as_str())
} else {
write!(
f,
"{}/{}",
name.as_str(),
arity
)
}
}
(HeapCellValueTag::PStr, pstr_atom) => {
let pstr = PartialString::from(pstr_atom);
write!(
f,
"pstr ( \"{}\", )",
pstr.as_str_from(0)
)
}
(HeapCellValueTag::Cons, c) => {
match_untyped_arena_ptr!(c,
(ArenaHeaderTag::Integer, n) => {
write!(f, "{}", n)
}
(ArenaHeaderTag::Rational, r) => {
write!(f, "{}", r)
}
(ArenaHeaderTag::F64, fl) => {
write!(f, "{}", fl)
}
(ArenaHeaderTag::Stream, stream) => {
write!(f, "$stream({})", stream.as_ptr() as usize)
}
_ => {
write!(f, "")
}
)
}
_ => {
unreachable!()
}
)
}
}
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() {
tag @ (HeapCellValueTag::Cons | HeapCellValueTag::F64) => { HeapCellValueTag::F64 => {
f.debug_struct("HeapCellValue")
.field("tag", &HeapCellValueTag::F64)
.field("offset", &self.get_value())
.field("m", &self.m())
.field("f", &self.f())
.finish()
}
HeapCellValueTag::Cons => {
let cons_ptr = ConsPtr::from_bytes(self.into_bytes()); let cons_ptr = ConsPtr::from_bytes(self.into_bytes());
f.debug_struct("HeapCellValue") f.debug_struct("HeapCellValue")
.field("tag", &tag) .field("tag", &HeapCellValueTag::Cons)
.field("ptr", &cons_ptr.ptr()) .field("ptr", &cons_ptr.ptr())
.field("m", &cons_ptr.m()) .field("m", &cons_ptr.m())
.field("f", &cons_ptr.f())
.finish() .finish()
} }
HeapCellValueTag::Atom => { HeapCellValueTag::Atom => {
@@ -341,7 +301,7 @@ impl fmt::Debug for HeapCellValue {
} }
} }
impl<T> From<TypedArenaPtr<T>> for HeapCellValue { impl<T: ArenaAllocated> From<TypedArenaPtr<T>> for HeapCellValue {
#[inline] #[inline]
fn from(arena_ptr: TypedArenaPtr<T>) -> HeapCellValue { fn from(arena_ptr: TypedArenaPtr<T>) -> HeapCellValue {
HeapCellValue::from(arena_ptr.header_ptr() as u64) HeapCellValue::from(arena_ptr.header_ptr() as u64)
@@ -351,11 +311,9 @@ impl<T> 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::from_bytes( HeapCellValue::build_with(
ConsPtr::from(f64_ptr.as_ptr() as u64) HeapCellValueTag::F64,
.with_tag(ConsPtrMaskTag::F64) f64_ptr.as_offset().to_u64(),
.with_m(false)
.into_bytes(),
) )
} }
} }
@@ -375,8 +333,10 @@ impl From<ConsPtr> for HeapCellValue {
impl<'a> From<(Number, &mut Arena)> for HeapCellValue { impl<'a> From<(Number, &mut Arena)> for HeapCellValue {
#[inline(always)] #[inline(always)]
fn from((n, arena): (Number, &mut Arena)) -> HeapCellValue { fn from((n, arena): (Number, &mut Arena)) -> HeapCellValue {
use ordered_float::OrderedFloat;
match n { match n {
Number::Float(n) => HeapCellValue::from(arena_alloc!(n, arena)), Number::Float(OrderedFloat(n)) => HeapCellValue::from(float_alloc!(n, arena)),
Number::Integer(n) => HeapCellValue::from(n), Number::Integer(n) => HeapCellValue::from(n),
Number::Rational(n) => HeapCellValue::from(n), Number::Rational(n) => HeapCellValue::from(n),
Number::Fixnum(n) => fixnum_as_cell!(n), Number::Fixnum(n) => fixnum_as_cell!(n),
@@ -430,11 +390,6 @@ impl HeapCellValue {
} }
} }
#[inline(always)]
pub fn is_forwarded(self) -> bool {
self.get_forwarding_bit().unwrap_or(false)
}
#[inline] #[inline]
pub fn is_ref(self) -> bool { pub fn is_ref(self) -> bool {
match self.get_tag() { match self.get_tag() {
@@ -486,14 +441,16 @@ impl HeapCellValue {
} }
#[inline] #[inline]
pub fn is_compound(self) -> bool { pub fn is_compound(self, heap: &[HeapCellValue]) -> bool {
match self.get_tag() { match self.get_tag() {
HeapCellValueTag::Str HeapCellValueTag::Str => {
| HeapCellValueTag::Lis cell_as_atom_cell!(heap[self.get_value()]).get_arity() > 0
| HeapCellValueTag::CStr }
| HeapCellValueTag::PStr HeapCellValueTag::Lis |
| HeapCellValueTag::PStrLoc HeapCellValueTag::CStr |
| HeapCellValueTag::PStrOffset => { HeapCellValueTag::PStr |
HeapCellValueTag::PStrLoc |
HeapCellValueTag::PStrOffset => {
true true
} }
HeapCellValueTag::Atom => { HeapCellValueTag::Atom => {
@@ -549,7 +506,6 @@ impl HeapCellValue {
Ok(tag) => tag, Ok(tag) => tag,
Err(_) => match ConsPtr::from_bytes(self.into_bytes()).tag() { Err(_) => match ConsPtr::from_bytes(self.into_bytes()).tag() {
ConsPtrMaskTag::Cons => HeapCellValueTag::Cons, ConsPtrMaskTag::Cons => HeapCellValueTag::Cons,
ConsPtrMaskTag::F64 => HeapCellValueTag::F64,
}, },
} }
} }
@@ -588,46 +544,39 @@ impl HeapCellValue {
} }
} }
#[inline] #[inline(always)]
pub fn get_forwarding_bit(self) -> Option<bool> { pub fn get_forwarding_bit(self) -> bool {
match self.get_tag() { match self.get_tag() {
HeapCellValueTag::Cons // the list of non-forwardable cell tags. HeapCellValueTag::Cons => ConsPtr::from_bytes(self.into_bytes()).f(),
| HeapCellValueTag::F64 _ => self.f()
// | HeapCellValueTag::Atom
// | HeapCellValueTag::PStr
| HeapCellValueTag::Fixnum
| HeapCellValueTag::Char => None,
_ => Some(self.f()),
} }
} }
#[inline] #[inline(always)]
pub fn set_forwarding_bit(&mut self, f: bool) { pub fn set_forwarding_bit(&mut self, f: bool) {
match self.get_tag() { match self.get_tag() {
HeapCellValueTag::Cons // the list of non-forwardable cell tags. HeapCellValueTag::Cons => {
| HeapCellValueTag::F64 let value = ConsPtr::from_bytes(self.into_bytes()).with_f(f);
// | HeapCellValueTag::Atom *self = HeapCellValue::from_bytes(value.into_bytes());
// | HeapCellValueTag::PStr }
| HeapCellValueTag::Fixnum
| HeapCellValueTag::Char => {}
_ => self.set_f(f), _ => self.set_f(f),
} }
} }
#[inline] #[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::F64 => { HeapCellValueTag::Cons => {
ConsPtr::from_bytes(self.into_bytes()).m() ConsPtr::from_bytes(self.into_bytes()).m()
} }
_ => self.m(), _ => self.m(),
} }
} }
#[inline] #[inline(always)]
pub fn set_mark_bit(&mut self, m: bool) { pub fn set_mark_bit(&mut self, m: bool) {
match self.get_tag() { match self.get_tag() {
HeapCellValueTag::Cons | HeapCellValueTag::F64 => { HeapCellValueTag::Cons => {
let value = ConsPtr::from_bytes(self.into_bytes()).with_m(m); let value = ConsPtr::from_bytes(self.into_bytes()).with_m(m);
*self = HeapCellValue::from_bytes(value.into_bytes()); *self = HeapCellValue::from_bytes(value.into_bytes());
} }
@@ -635,7 +584,7 @@ impl HeapCellValue {
} }
} }
pub fn order_category(self) -> Option<TermOrderCategory> { pub fn order_category(self, heap: &[HeapCellValue]) -> Option<TermOrderCategory> {
match Number::try_from(self).ok() { match Number::try_from(self).ok() {
Some(Number::Integer(_)) | Some(Number::Fixnum(_)) | Some(Number::Rational(_)) => { Some(Number::Integer(_)) | Some(Number::Fixnum(_)) | Some(Number::Rational(_)) => {
Some(TermOrderCategory::Integer) Some(TermOrderCategory::Integer)
@@ -654,9 +603,19 @@ impl HeapCellValue {
}) })
} }
HeapCellValueTag::Lis | HeapCellValueTag::PStrLoc | HeapCellValueTag::Lis | HeapCellValueTag::PStrLoc |
HeapCellValueTag::CStr | HeapCellValueTag::Str => { HeapCellValueTag::CStr => {
Some(TermOrderCategory::Compound) Some(TermOrderCategory::Compound)
} }
HeapCellValueTag::Str => {
let value = heap[self.get_value()];
let arity = cell_as_atom_cell!(value).get_arity();
if arity == 0 {
Some(TermOrderCategory::Atom)
} else {
Some(TermOrderCategory::Compound)
}
}
_ => { _ => {
None None
} }
@@ -681,7 +640,7 @@ const_assert!(mem::size_of::<HeapCellValue>() == 8);
#[bitfield] #[bitfield]
#[repr(u64)] #[repr(u64)]
#[derive(Copy, Clone, Debug)] #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
pub struct UntypedArenaPtr { pub struct UntypedArenaPtr {
ptr: B61, ptr: B61,
m: bool, m: bool,
@@ -697,6 +656,13 @@ impl From<*const ArenaHeader> for UntypedArenaPtr {
} }
} }
impl From<*const IndexPtr> for UntypedArenaPtr {
#[inline]
fn from(ptr: *const IndexPtr) -> UntypedArenaPtr {
unsafe { mem::transmute(ptr) }
}
}
impl From<UntypedArenaPtr> for *const ArenaHeader { impl From<UntypedArenaPtr> for *const ArenaHeader {
#[inline] #[inline]
fn from(ptr: UntypedArenaPtr) -> *const ArenaHeader { fn from(ptr: UntypedArenaPtr) -> *const ArenaHeader {

View File

@@ -65,6 +65,7 @@ pub fn run_top_level_test_with_args<
Command::cargo_bin(SCRYER_PROLOG) Command::cargo_bin(SCRYER_PROLOG)
.unwrap() .unwrap()
.arg("-f") .arg("-f")
.arg("--no-add-history")
.args(args) .args(args)
.write_stdin(stdin) .write_stdin(stdin)
.assert() .assert()

View File

@@ -29,12 +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",
caught: e\n\
false.\n\
caught: e\n\
false.\n\
",
); );
} }
@@ -57,10 +52,10 @@ fn handle_residual_goal() {
", ",
" \ " \
true.\n \ true.\n \
true.\n\ true.\n \
false.\n \ false.\n \
X = - X.\n \ X = - X.\n \
dif:dif(- X,X).\n\ dif:dif(- X,X).\n \
false.\n \ false.\n \
Vars = [X], dif:dif(- X,X).\n \ Vars = [X], dif:dif(- X,X).\n \
true.\n \ true.\n \
@@ -79,7 +74,7 @@ fn occurs_check_flag() {
f(X, X).\n\ f(X, X).\n\
halt.\n\ halt.\n\
", ",
"false.\n", " false.\n",
) )
} }
@@ -95,10 +90,10 @@ fn occurs_check_flag2() {
halt.\n\ halt.\n\
", ",
" \ " \
true.\n\ true.\n \
false.\n \
true.\n \
false.\n \ false.\n \
true.\n\
false.\n\
false.\n\ false.\n\
", ",
) )
@@ -136,7 +131,7 @@ fn no_stutter() {
run_top_level_test_no_args("write(a), write(b), false.\n\ run_top_level_test_no_args("write(a), write(b), false.\n\
halt.\n\ halt.\n\
", ",
"abfalse.\n") "ab false.\n")
} }
/* /*
@@ -170,6 +165,6 @@ fn ignored_constraint() {
fn call_0() { fn call_0() {
load_module_test( load_module_test(
"tests-pl/issue831-call0.pl", "tests-pl/issue831-call0.pl",
"caught: error(existence_error(procedure,call/0),call/0)\n", " error(existence_error(procedure,call/0),call/0).\n",
); );
} }

View File

@@ -30,7 +30,7 @@ fn hello_world() {
fn syntax_error() { fn syntax_error() {
load_module_test( load_module_test(
"tests-pl/syntax_error.pl", "tests-pl/syntax_error.pl",
"caught: error(syntax_error(incomplete_reduction),read_term/3:6)\n", " error(syntax_error(incomplete_reduction),read_term/3:6).\n",
); );
} }
@@ -51,7 +51,7 @@ fn rules() {
fn setup_call_cleanup_load() { fn setup_call_cleanup_load() {
load_module_test( load_module_test(
"src/tests/setup_call_cleanup.pl", "src/tests/setup_call_cleanup.pl",
"1+21+31+2>_17737+_177381+_158071+2>41+2>_177381+2>31+2>31+2>4ba" "1+21+31+2>A+B1+G1+2>41+2>B1+2>31+2>31+2>4ba",
); );
} }
@@ -60,7 +60,7 @@ fn setup_call_cleanup_process() {
run_top_level_test_with_args( run_top_level_test_with_args(
&["src/tests/setup_call_cleanup.pl", "-f", "-g", "halt"], &["src/tests/setup_call_cleanup.pl", "-f", "-g", "halt"],
"", "",
"1+21+31+2>_19590+_195911+_176601+2>41+2>_195911+2>31+2>31+2>4ba" "1+21+31+2>A+B1+G1+2>41+2>B1+2>31+2>31+2>4ba",
); );
} }