139 Commits

Author SHA1 Message Date
Mark Thom
3fc5be0d03 reconcile '[]' and [] (#644), solve remaining conformity issues (#648), move (-->) from dcgs.pl to builtins.pl (#649) 2020-08-02 23:33:37 -06:00
Mark Thom
357ae7a8aa Merge pull request #647 from notoria/newline
Improved readline
2020-07-31 18:19:12 -03:00
notoria
ac00ae4daf Improved readline 2020-07-31 21:16:33 +02:00
Mark Thom
249f034a38 Merge pull request #645 from triska/curve25519
ADDED: library(crypto): ECDH key exchange over Curve25519 (X25519)
2020-07-30 10:29:20 -03:00
Markus Triska
32c612b747 ADDED: library(crypto): ECDH key exchange over Curve25519 (X25519) 2020-07-29 23:51:11 +02:00
Mark Thom
386f7cf65d the indexer now categorizes partial strings only as lists (#623, #642) 2020-07-27 16:43:43 -06:00
Mark Thom
320802633f Merge pull request #639 from triska/flush_output
ENHANCED: flush output for impure I/O (format/[2,3], portray_clause/1 etc.)
2020-07-25 13:20:45 -03:00
Markus Triska
dcc4b91b35 ENHANCED: flush output for impure I/O (format/[2,3], portray_clause/1 etc.)
Without this, we do not get a (timely) prompt in cases like:

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

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

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

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

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

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

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

Yielding:

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

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

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

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

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

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

I call this raven: *Cryer*. Cryer is an archaic spelling for "crier",
an officer who makes public announcements in a court of justice.
The Prolog top-level likewise makes announcements about what is true.
2020-05-26 22:13:51 +02:00
Mark Thom
fe0bf6f2ef Merge pull request #524 from matt2xu/decode_utf8
Add decoding of UTF-8 sequences
2020-05-26 13:42:42 -03:00
Mark Thom
828c19d478 Merge pull request #563 from triska/master
ADDED: halt/1, halting with specified exit code
2020-05-23 16:02:05 -03:00
Mark Thom
15db77558c throw evaluable type error for unrecognized atoms in arith_eval_by_metacall 2020-05-23 13:33:05 -06:00
Mark Thom
18cf4a3bd3 Add type errors where appropriate in arith_eval_by_metacall (#392) 2020-05-23 13:07:40 -06:00
Mark Thom
e0378acfc2 throw type_error(number, E) in arith_eval_by_metacall (#392) 2020-05-23 12:39:29 -06:00
Mark Thom
53cb2af202 (**)/2 should always evaluate to floating point (#558) 2020-05-23 12:24:00 -06:00
Mark Thom
f74005a166 update (^)/2 in light of Draft Technical Corrigendum 3 (#559) 2020-05-23 12:13:48 -06:00
Markus Triska
b0df981b01 ADDED: halt/1, halting with specified exit code 2020-05-23 19:28:17 +02:00
Matthieu Wipliez
cc9d6587a3 Implementation of UTF-8 bytes to chars 2020-05-22 23:33:12 +02:00
105 changed files with 6111 additions and 2236 deletions

703
Cargo.lock generated
View File

@@ -27,6 +27,12 @@ version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cff77d8686867eceff3105329d4698d96c2391c176d5d03adc90c7389162b5b8"
[[package]]
name = "autocfg"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1d49d90015b3c36167a20fe2810c5cd875ad504b39cff3d4eae7977e6b7c1cb2"
[[package]]
name = "autocfg"
version = "1.0.0"
@@ -45,6 +51,27 @@ version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b41b7ea54a0c9d92199de89e20e58d49f02f8e699814ef3fdf266f6f748d15c7"
[[package]]
name = "base64"
version = "0.12.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3441f0f7b02788e948e47f457ca01f1d7e6d92c693bc132c22b087d3141c03ff"
[[package]]
name = "bit-set"
version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6e11e16035ea35e4e5997b393eacbf6f63983188f7a2ad25bfb13465f5ad59de"
dependencies = [
"bit-vec",
]
[[package]]
name = "bit-vec"
version = "0.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5f0dc55f2d8a1a85650ac47858bb001b4c0dd73d79e3c455a842925e68d29cd3"
[[package]]
name = "bitflags"
version = "1.2.1"
@@ -125,6 +152,17 @@ version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
[[package]]
name = "chrono"
version = "0.4.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "80094f509cf8b5ae86a4966a39b3ff66cd7e2a3e594accec3743ff3fabeab5b2"
dependencies = [
"num-integer",
"num-traits 0.2.11",
"time",
]
[[package]]
name = "cloudabi"
version = "0.0.3"
@@ -140,6 +178,22 @@ version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc"
[[package]]
name = "core-foundation"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "57d24c7a13c43e870e37c1556b74555437870a04514f7685f5b354e090567171"
dependencies = [
"core-foundation-sys",
"libc",
]
[[package]]
name = "core-foundation-sys"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b3a71ab494c0b5b860bdc8407ae08978052417070c2ced38573a9157ad75b8ac"
[[package]]
name = "cpu-time"
version = "1.0.0"
@@ -156,7 +210,7 @@ version = "0.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8"
dependencies = [
"autocfg",
"autocfg 1.0.0",
"cfg-if",
"lazy_static",
]
@@ -239,6 +293,27 @@ version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4bb454f0228b18c7f4c3b0ebbee346ed9c52e7443b0999cd543ff3571205701d"
[[package]]
name = "foreign-types"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1"
dependencies = [
"foreign-types-shared",
]
[[package]]
name = "foreign-types-shared"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
[[package]]
name = "fuchsia-cprng"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba"
[[package]]
name = "fuchsia-zircon"
version = "0.3.3"
@@ -255,6 +330,16 @@ version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7"
[[package]]
name = "futf"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7c9c1ce3fa9336301af935ab852c437817d14cd33690446569392e65170aac3b"
dependencies = [
"mac",
"new_debug_unreachable",
]
[[package]]
name = "generic-array"
version = "0.12.3"
@@ -292,9 +377,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "34a97a52fdee1870a34fa6e4b77570cba531b27d1838874fef4429a791a3d657"
dependencies = [
"proc-macro-hack",
"proc-macro2",
"quote",
"syn",
"proc-macro2 1.0.10",
"quote 1.0.3",
"syn 1.0.18",
]
[[package]]
@@ -318,13 +403,27 @@ dependencies = [
"winapi 0.3.8",
]
[[package]]
name = "html5ever"
version = "0.23.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5ce65ac8028cf5a287a7dbf6c4e0a6cf2dcf022ed5b167a81bae66ebf599a8b7"
dependencies = [
"log",
"mac",
"markup5ever",
"proc-macro2 0.4.30",
"quote 0.6.13",
"syn 0.15.44",
]
[[package]]
name = "indexmap"
version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "076f042c5b7b98f31d205f1249267e12a6518c1481e9dae9764af19b707d2292"
dependencies = [
"autocfg",
"autocfg 1.0.0",
]
[[package]]
@@ -336,6 +435,12 @@ dependencies = [
"libc",
]
[[package]]
name = "itoa"
version = "0.4.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc6f3ad7b9d11a0c00842ff8de1b60ee58661048eb8049ed33c73594f359d7e6"
[[package]]
name = "js-sys"
version = "0.3.39"
@@ -397,6 +502,17 @@ version = "0.2.69"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "99e85c08494b21a9054e7fe1374a732aeadaff3980b6990b94bfd3a70f690005"
[[package]]
name = "libsodium-sys"
version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a685b64f837b339074115f2e7f7b431ac73681d08d75b389db7498b8892b8a58"
dependencies = [
"cc",
"libc",
"pkg-config",
]
[[package]]
name = "lock_api"
version = "0.3.4"
@@ -415,6 +531,29 @@ dependencies = [
"cfg-if",
]
[[package]]
name = "mac"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c41e0c4fef86961ac6d6f8a82609f55f31b05e4fce149ac5710e439df7619ba4"
[[package]]
name = "markup5ever"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f1af46a727284117e09780d05038b1ce6fc9c76cc6df183c3dae5a8955a25e21"
dependencies = [
"log",
"phf",
"phf_codegen",
"serde",
"serde_derive",
"serde_json",
"string_cache",
"string_cache_codegen",
"tendril",
]
[[package]]
name = "match_cfg"
version = "0.1.0"
@@ -464,6 +603,24 @@ dependencies = [
"ws2_32-sys",
]
[[package]]
name = "native-tls"
version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2b0d88c06fe90d5ee94048ba40409ef1d9315d86f6f38c2efdaad4fb50c58b2d"
dependencies = [
"lazy_static",
"libc",
"log",
"openssl",
"openssl-probe",
"openssl-sys",
"schannel",
"security-framework",
"security-framework-sys",
"tempfile",
]
[[package]]
name = "net2"
version = "0.2.33"
@@ -475,6 +632,12 @@ dependencies = [
"winapi 0.3.8",
]
[[package]]
name = "new_debug_unreachable"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e4a24736216ec316047a1fc4252e27dabb04218aa4a3f37c6e7ddbf1f9782b54"
[[package]]
name = "nix"
version = "0.15.0"
@@ -513,7 +676,7 @@ version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "090c7f9998ee0ff65aa5b723e4009f7b217707f1fb5ea551329cc4d6231fb304"
dependencies = [
"autocfg",
"autocfg 1.0.0",
"num-integer",
"num-traits 0.2.11",
]
@@ -524,7 +687,7 @@ version = "0.1.42"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f6ea62e9d81a77cd3ee9a2a5b9b609447857f3d358704331e4ef39eb247fcba"
dependencies = [
"autocfg",
"autocfg 1.0.0",
"num-traits 0.2.11",
]
@@ -534,7 +697,7 @@ version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c000134b5dbf44adc5cb772486d335293351644b801551abe8f75c84cfa4aef"
dependencies = [
"autocfg",
"autocfg 1.0.0",
"num-bigint",
"num-integer",
"num-traits 0.2.11",
@@ -568,7 +731,7 @@ version = "0.2.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c62be47e61d1842b9170f0fdeec8eba98e60e90e5446449a0545e5152acd7096"
dependencies = [
"autocfg",
"autocfg 1.0.0",
]
[[package]]
@@ -583,6 +746,49 @@ version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c"
[[package]]
name = "openssl"
version = "0.10.29"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cee6d85f4cb4c4f59a6a85d5b68a233d280c82e29e822913b9c8b129fbf20bdd"
dependencies = [
"bitflags",
"cfg-if",
"foreign-types",
"lazy_static",
"libc",
"openssl-sys",
]
[[package]]
name = "openssl-probe"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "77af24da69f9d9341038eba93a073b1fdaaa1b788221b00a69bce9e762cb32de"
[[package]]
name = "openssl-src"
version = "111.9.0+1.1.1g"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a2dbe10ddd1eb335aba3780eb2eaa13e1b7b441d2562fd962398740927f39ec4"
dependencies = [
"cc",
]
[[package]]
name = "openssl-sys"
version = "0.9.58"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a842db4709b604f0fe5d1170ae3565899be2ad3d9cbc72dedc789ac0511f78de"
dependencies = [
"autocfg 1.0.0",
"cc",
"libc",
"openssl-src",
"pkg-config",
"vcpkg",
]
[[package]]
name = "ordered-float"
version = "0.5.2"
@@ -617,26 +823,91 @@ dependencies = [
"winapi 0.3.8",
]
[[package]]
name = "phf"
version = "0.7.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b3da44b85f8e8dfaec21adae67f95d93244b2ecf6ad2a692320598dcc8e6dd18"
dependencies = [
"phf_shared",
]
[[package]]
name = "phf_codegen"
version = "0.7.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b03e85129e324ad4166b06b2c7491ae27fe3ec353af72e72cd1654c7225d517e"
dependencies = [
"phf_generator",
"phf_shared",
]
[[package]]
name = "phf_generator"
version = "0.7.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09364cc93c159b8b06b1f4dd8a4398984503483891b0c26b867cf431fb132662"
dependencies = [
"phf_shared",
"rand 0.6.5",
]
[[package]]
name = "phf_shared"
version = "0.7.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "234f71a15de2288bcb7e3b6515828d22af7ec8598ee6d24c3b526fa0a80b67a0"
dependencies = [
"siphasher",
]
[[package]]
name = "pkg-config"
version = "0.3.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "05da548ad6865900e60eaba7f589cc0783590a92e940c26953ff81ddbab2d677"
[[package]]
name = "ppv-lite86"
version = "0.2.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "237a5ed80e274dbc66f86bd59c1e25edc039660be53194b5fe0a482e0f2612ea"
[[package]]
name = "precomputed-hash"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c"
[[package]]
name = "proc-macro-hack"
version = "0.5.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0d659fe7c6d27f25e9d80a1a094c223f5246f6a6596453e09d7229bf42750b63"
[[package]]
name = "proc-macro2"
version = "0.4.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759"
dependencies = [
"unicode-xid 0.1.0",
]
[[package]]
name = "proc-macro2"
version = "1.0.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "df246d292ff63439fea9bc8c0a270bed0e390d5ebd4db4ba15aba81111b5abe3"
dependencies = [
"unicode-xid",
"unicode-xid 0.2.0",
]
[[package]]
name = "prolog_parser"
version = "0.8.59"
version = "0.8.65"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "029a4682cf40923b8eb05c4b943d1d6be73775e7bf80bcb0866b5ef29abb0802"
checksum = "fdcfe8260335a150812e36b171ff985ce88f02de16c05f4a13fe4f10e8c247f8"
dependencies = [
"lexical",
"num-rug-adapter",
@@ -645,13 +916,178 @@ dependencies = [
"unicode_reader",
]
[[package]]
name = "quote"
version = "0.6.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6ce23b6b870e8f94f81fb0a363d65d86675884b34a09043c81e5562f11c1f8e1"
dependencies = [
"proc-macro2 0.4.30",
]
[[package]]
name = "quote"
version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2bdc6c187c65bca4260c9011c9e3132efe4909da44726bad24cf7572ae338d7f"
dependencies = [
"proc-macro2",
"proc-macro2 1.0.10",
]
[[package]]
name = "rand"
version = "0.6.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca"
dependencies = [
"autocfg 0.1.7",
"libc",
"rand_chacha 0.1.1",
"rand_core 0.4.2",
"rand_hc 0.1.0",
"rand_isaac",
"rand_jitter",
"rand_os",
"rand_pcg",
"rand_xorshift",
"winapi 0.3.8",
]
[[package]]
name = "rand"
version = "0.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03"
dependencies = [
"getrandom",
"libc",
"rand_chacha 0.2.2",
"rand_core 0.5.1",
"rand_hc 0.2.0",
]
[[package]]
name = "rand_chacha"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef"
dependencies = [
"autocfg 0.1.7",
"rand_core 0.3.1",
]
[[package]]
name = "rand_chacha"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402"
dependencies = [
"ppv-lite86",
"rand_core 0.5.1",
]
[[package]]
name = "rand_core"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b"
dependencies = [
"rand_core 0.4.2",
]
[[package]]
name = "rand_core"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc"
[[package]]
name = "rand_core"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19"
dependencies = [
"getrandom",
]
[[package]]
name = "rand_hc"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7b40677c7be09ae76218dc623efbf7b18e34bced3f38883af07bb75630a21bc4"
dependencies = [
"rand_core 0.3.1",
]
[[package]]
name = "rand_hc"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c"
dependencies = [
"rand_core 0.5.1",
]
[[package]]
name = "rand_isaac"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ded997c9d5f13925be2a6fd7e66bf1872597f759fd9dd93513dd7e92e5a5ee08"
dependencies = [
"rand_core 0.3.1",
]
[[package]]
name = "rand_jitter"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1166d5c91dc97b88d1decc3285bb0a99ed84b05cfd0bc2341bdf2d43fc41e39b"
dependencies = [
"libc",
"rand_core 0.4.2",
"winapi 0.3.8",
]
[[package]]
name = "rand_os"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7b75f676a1e053fc562eafbb47838d67c84801e38fc1ba459e8f180deabd5071"
dependencies = [
"cloudabi",
"fuchsia-cprng",
"libc",
"rand_core 0.4.2",
"rdrand",
"winapi 0.3.8",
]
[[package]]
name = "rand_pcg"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "abf9b09b01790cfe0364f52bf32995ea3c39f4d2dd011eac241d2914146d0b44"
dependencies = [
"autocfg 0.1.7",
"rand_core 0.4.2",
]
[[package]]
name = "rand_xorshift"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cbf7e9e623549b0e21f6e97cf8ecf247c1a8fd2e8a992ae265314300b2455d5c"
dependencies = [
"rand_core 0.3.1",
]
[[package]]
name = "rdrand"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2"
dependencies = [
"rand_core 0.3.1",
]
[[package]]
@@ -677,6 +1113,15 @@ version = "0.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d813022b2e00774a48eaf43caaa3c20b45f040ba8cbf398e2e8911a06668dbe6"
[[package]]
name = "remove_dir_all"
version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4a83fa3702a688b9359eccba92d153ac33fd2e8462f9e0e3fdf155239ea7792e"
dependencies = [
"winapi 0.3.8",
]
[[package]]
name = "ring"
version = "0.16.13"
@@ -703,6 +1148,15 @@ dependencies = [
"opaque-debug",
]
[[package]]
name = "roxmltree"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d5001f134077069d87f77c8b9452b690df2445f7a43f1c7ca4a1af8dd505789d"
dependencies = [
"xmlparser",
]
[[package]]
name = "rug"
version = "1.8.0"
@@ -720,7 +1174,7 @@ version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2bc8af4bda8e1ff4932523b94d3dd20ee30a87232323eda55903ffd71d2fb017"
dependencies = [
"base64",
"base64 0.11.0",
"blake2b_simd",
"constant_time_eq",
"crossbeam-utils",
@@ -760,6 +1214,16 @@ version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed3d612bc64430efeb3f7ee6ef26d590dce0c43249217bddc62112540c7941e1"
[[package]]
name = "schannel"
version = "0.1.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f05ba609c234e60bee0d547fe94a4c7e9da733d1c962cf6e59efa4cd9c8bc75"
dependencies = [
"lazy_static",
"winapi 0.3.8",
]
[[package]]
name = "scopeguard"
version = "1.1.0"
@@ -768,9 +1232,11 @@ checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
[[package]]
name = "scryer-prolog"
version = "0.8.123"
version = "0.8.126"
dependencies = [
"base64 0.12.3",
"blake2",
"chrono",
"cpu-time",
"crossterm",
"dirs",
@@ -781,19 +1247,57 @@ dependencies = [
"indexmap",
"lazy_static",
"libc",
"native-tls",
"nix 0.15.0",
"num-rug-adapter",
"openssl",
"ordered-float",
"prolog_parser",
"ref_thread_local",
"ring",
"ripemd160",
"roxmltree",
"rug",
"rustyline",
"select",
"sha3",
"sodiumoxide",
"unicode_reader",
]
[[package]]
name = "security-framework"
version = "0.4.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "64808902d7d99f78eaddd2b4e2509713babc3dc3c85ad6f4c447680f3c01e535"
dependencies = [
"bitflags",
"core-foundation",
"core-foundation-sys",
"libc",
"security-framework-sys",
]
[[package]]
name = "security-framework-sys"
version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "17bf11d99252f512695eb468de5516e5cf75455521e69dfe343f3b74e4748405"
dependencies = [
"core-foundation-sys",
"libc",
]
[[package]]
name = "select"
version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac645958c62108d11f90f8d34e4dc2799c838fc995ed4c2075867a2a8d5be76b"
dependencies = [
"bit-set",
"html5ever",
]
[[package]]
name = "semver"
version = "0.9.0"
@@ -809,6 +1313,34 @@ version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
[[package]]
name = "serde"
version = "1.0.114"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5317f7588f0a5078ee60ef675ef96735a1442132dc645eb1d12c018620ed8cd3"
[[package]]
name = "serde_derive"
version = "1.0.113"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "93c5eaa17d0954cb481cdcfffe9d84fcfa7a1a9f2349271e678677be4c26ae31"
dependencies = [
"proc-macro2 1.0.10",
"quote 1.0.3",
"syn 1.0.18",
]
[[package]]
name = "serde_json"
version = "1.0.55"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec2c5d7e739bc07a3e73381a39d61fdb5f671c60c1df26a130690665803d8226"
dependencies = [
"itoa",
"ryu",
"serde",
]
[[package]]
name = "sha3"
version = "0.8.2"
@@ -843,6 +1375,12 @@ dependencies = [
"libc",
]
[[package]]
name = "siphasher"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b8de496cf83d4ed58b6be86c3a275b8602f6ffe98d3024a869e124147a9a3ac"
[[package]]
name = "slab"
version = "0.4.2"
@@ -864,6 +1402,17 @@ version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c7cb5678e1615754284ec264d9bb5b4c27d2018577fd90ac0ceb578591ed5ee4"
[[package]]
name = "sodiumoxide"
version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7038b67c941e23501573cb7242ffb08709abe9b11eb74bceff875bbda024a6a8"
dependencies = [
"libc",
"libsodium-sys",
"serde",
]
[[package]]
name = "spin"
version = "0.5.2"
@@ -876,21 +1425,101 @@ version = "0.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f3eb36b47e512f8f1c9e3d10c2c1965bc992bd9cdb024fa581e2194501c83d3"
[[package]]
name = "string_cache"
version = "0.7.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "89c058a82f9fd69b1becf8c274f412281038877c553182f1d02eb027045a2d67"
dependencies = [
"lazy_static",
"new_debug_unreachable",
"phf_shared",
"precomputed-hash",
"serde",
"string_cache_codegen",
"string_cache_shared",
]
[[package]]
name = "string_cache_codegen"
version = "0.4.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f0f45ed1b65bf9a4bf2f7b7dc59212d1926e9eaf00fa998988e420fd124467c6"
dependencies = [
"phf_generator",
"phf_shared",
"proc-macro2 1.0.10",
"quote 1.0.3",
"string_cache_shared",
]
[[package]]
name = "string_cache_shared"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b1884d1bc09741d466d9b14e6d37ac89d6909cbcac41dd9ae982d4d063bbedfc"
[[package]]
name = "subtle"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2d67a5a62ba6e01cb2192ff309324cb4875d0c451d55fe2319433abe7a05a8ee"
[[package]]
name = "syn"
version = "0.15.44"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9ca4b3b69a77cbe1ffc9e198781b7acb0c7365a883670e8f1c1bc66fba79a5c5"
dependencies = [
"proc-macro2 0.4.30",
"quote 0.6.13",
"unicode-xid 0.1.0",
]
[[package]]
name = "syn"
version = "1.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "410a7488c0a728c7ceb4ad59b9567eb4053d02e8cc7f5c0e0eeeb39518369213"
dependencies = [
"proc-macro2",
"quote",
"unicode-xid",
"proc-macro2 1.0.10",
"quote 1.0.3",
"unicode-xid 0.2.0",
]
[[package]]
name = "tempfile"
version = "3.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9"
dependencies = [
"cfg-if",
"libc",
"rand 0.7.3",
"redox_syscall",
"remove_dir_all",
"winapi 0.3.8",
]
[[package]]
name = "tendril"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "707feda9f2582d5d680d733e38755547a3e8fb471e7ba11452ecfd9ce93a5d3b"
dependencies = [
"futf",
"mac",
"utf-8",
]
[[package]]
name = "time"
version = "0.1.43"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ca8a50ef2360fbd1eeb0ecd46795a87a19024eb4b53c5dc916ca1fd95fe62438"
dependencies = [
"libc",
"winapi 0.3.8",
]
[[package]]
@@ -911,6 +1540,12 @@ version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "caaa9d531767d1ff2150b9332433f32a24622147e5ebb1f26409d5da67afd479"
[[package]]
name = "unicode-xid"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc"
[[package]]
name = "unicode-xid"
version = "0.2.0"
@@ -942,12 +1577,24 @@ version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a"
[[package]]
name = "utf-8"
version = "0.7.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "05e42f7c18b8f902290b009cde6d651262f956c98bc51bca4cd1d511c9cd85c7"
[[package]]
name = "utf8parse"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "936e4b492acfd135421d8dca4b1aa80a7bfc26e702ef3af710e0752684df5372"
[[package]]
name = "vcpkg"
version = "0.2.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "55d1e41d56121e07f1e223db0a4def204e45c85425f6a16d462fd07c8d10d74c"
[[package]]
name = "void"
version = "1.0.2"
@@ -979,9 +1626,9 @@ dependencies = [
"bumpalo",
"lazy_static",
"log",
"proc-macro2",
"quote",
"syn",
"proc-macro2 1.0.10",
"quote 1.0.3",
"syn 1.0.18",
"wasm-bindgen-shared",
]
@@ -991,7 +1638,7 @@ version = "0.2.62"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2cd85aa2c579e8892442954685f0d801f9129de24fa2136b2c6a539c76b65776"
dependencies = [
"quote",
"quote 1.0.3",
"wasm-bindgen-macro-support",
]
@@ -1001,9 +1648,9 @@ version = "0.2.62"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8eb197bd3a47553334907ffd2f16507b4f4f01bbec3ac921a7719e0decdfe72a"
dependencies = [
"proc-macro2",
"quote",
"syn",
"proc-macro2 1.0.10",
"quote 1.0.3",
"syn 1.0.18",
"wasm-bindgen-backend",
"wasm-bindgen-shared",
]
@@ -1067,3 +1714,9 @@ dependencies = [
"winapi 0.2.8",
"winapi-build",
]
[[package]]
name = "xmlparser"
version = "0.13.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "52613e655f6f11f63c0fe7d1c3b5ef69e44d96df9b65dab296b441ed0e1125f5"

View File

@@ -1,13 +1,13 @@
[package]
name = "scryer-prolog"
version = "0.8.123"
version = "0.8.127"
authors = ["Mark Thom <markjordanthom@gmail.com>"]
edition = "2018"
description = "A modern Prolog implementation written mostly in Rust."
readme = "README.md"
repository = "https://github.com/mthom/scryer-prolog"
license = "BSD-3-Clause"
keywords = ["prolog", "prolog-interpreter", "prolog-implementation"]
keywords = ["prolog", "prolog-interpreter", "prolog-system"]
categories = ["command-line-utilities"]
build = "build.rs"
@@ -32,7 +32,7 @@ libc = "0.2.62"
nix = "0.15.0"
num-rug-adapter = { optional = true, version = "0.1.3" }
ordered-float = "0.5.0"
prolog_parser = { version = "0.8.59", default-features = false }
prolog_parser = { version = "0.8.65", default-features = false }
ref_thread_local = "0.0.0"
rug = { version = "1.4.0", optional = true }
rustyline = "6.0.0"
@@ -41,3 +41,10 @@ ring = "0.16.13"
ripemd160 = "0.8.0"
sha3 = "0.8.2"
blake2 = "0.8.1"
openssl = { version = "0.10.29", features = ["vendored"] }
native-tls = "0.2.4"
chrono = "0.4.11"
select = "0.4.3"
roxmltree = "0.11.0"
base64 = "0.12.3"
sodiumoxide = "0.2.6"

142
README.md
View File

@@ -5,6 +5,8 @@ source industrial strength production environment that is also a
testbed for bleeding edge research in logic and constraint
programming, which is itself written in a high-level language.
![Scryer Logo: Cryer](logo/scryer.png)
## Phase 1
Produce an implementation of the Warren Abstract Machine in Rust, done
@@ -269,8 +271,13 @@ the above example, posting <tt>Ls0&nbsp;=&nbsp;[a,b,c|Ls]</tt> yields
the exact same internal representation, and has the advantage that
only the standard predicate&nbsp;`(=)/2` is used.
Definite clause grammars as provided by `library(dcgs)` are ideally
suited for reasoning about strings.
Definite clause grammars as provided by
[`library(dcgs)`](src/lib/lists.pl), and the predicates from
[`library(lists)`](src/lib/lists.pl), are ideally suited for reasoning
about strings.
Partial strings were first proposed by Ulrich Neumerkel in issue
[#95](https://github.com/mthom/scryer-prolog/issues/95).
### Tabling (SLG resolution)
@@ -287,7 +294,7 @@ even if one exists.
Scryer Prolog supports an alternative execution strategy which is
called *tabling* and also known as tabled&nbsp;execution and
SLG&nbsp;resolution. To enable tabled execution for a predicate, use
[`library(tabling)`](src/prolog/lib/tabling.pl) and add a `(table)/1`
[`library(tabling)`](src/lib/tabling.pl) and add a `(table)/1`
directive for the desired predicate indicator. For example, if we
write:
@@ -312,14 +319,14 @@ Scryer Prolog provides excellent support for Constraint Logic
Programming&nbsp;(CLP), which is the amalgamation of
Logic&nbsp;Programming&nbsp;(LP) and Constraints.
In addition to built-in support for [`dif/2`](src/prolog/lib/dif.pl),
[`freeze/2`](src/prolog/lib/freeze.pl),
[CLP(B)](src/prolog/lib/clpb.pl) and [CLP()](src/prolog/lib/clpz.pl),
In addition to built-in support for [`dif/2`](src/lib/dif.pl),
[`freeze/2`](src/lib/freeze.pl),
[CLP(B)](src/lib/clpb.pl) and [CLP()](src/lib/clpz.pl),
Scryer provides a convenient way to implement new user-defined
constraints: *Attributed variables* are available via
[`library(atts)`](src/prolog/lib/atts.pl) as in SICStus&nbsp;Prolog,
[`library(atts)`](src/lib/atts.pl) as in SICStus&nbsp;Prolog,
which is one of the most sophisticated and fastest constraint systems
in existence. In [`library(iso_ext)`](src/prolog/lib/iso_ext.pl),
in existence. In [`library(iso_ext)`](src/lib/iso_ext.pl),
Scryer provides predicates for backtrackable (`bb_b_put/2`) and
non-backtrackable (`bb_put/2`) global variables, which are needed to
implement certain types of constraint&nbsp;solvers.
@@ -332,7 +339,7 @@ learning and developing portable CLP&nbsp;applications.
Scryer has a simple predicate-based module system. It provides a
way to separate units of code into distinct namespaces, for both
predicates and operators. See the files
[`src/prolog/lib/*.pl`](src/prolog/lib) for
[`src/lib/*.pl`](src/lib) for
examples.
At the time of this writing, many predicates reside in their own
@@ -340,31 +347,31 @@ modules that need to be imported before they can be used.
The modules that ship with Scryer&nbsp;Prolog are also called
*library*&nbsp;modules or *libraries*, and include:
* [`lists`](src/prolog/lib/lists.pl)
* [`lists`](src/lib/lists.pl)
providing `length/2`, `member/2`, `select/3`, `append/[2,3]`,
`foldl/[4,5]`, `maplist/[2-9]`, `same_length/2`, `transpose/2` etc.
* [`dcgs`](src/prolog/lib/dcgs.pl)
* [`dcgs`](src/lib/dcgs.pl)
Definite Clause Grammars (DCGs), a built-in grammar mechanism
that uses the operator `(-->)/2` to define grammar rules,
and the predicates `phrase/[2,3]` to invoke them.
* [`dif`](src/prolog/lib/dif.pl)
* [`dif`](src/lib/dif.pl)
The predicate `dif/2` provides declarative disequality:
It is true if and only if its arguments are different, and
delays the test until a sound decision can be made.
* [`reif`](src/prolog/lib/reif.pl)
* [`reif`](src/lib/reif.pl)
providing `if_/3`, `tfilter/3` and related predicates
as described in *Indexing&nbsp;dif/2*.
* [`clpz`](src/prolog/lib/clpz.pl)
* [`clpz`](src/lib/clpz.pl)
CLP(): Constraint Logic Programming over Integers,
providing declarative integer arithmetic via `(#=)/2`, `(#\=)/2`,
`(#>=)/2` etc., and various global constraints and
enumeration predicates for solving combinatorial tasks.
* [`pairs`](src/prolog/lib/pairs.pl)
* [`pairs`](src/lib/pairs.pl)
By convention, *pairs* are Prolog terms with
principal&nbsp;functor `(-)/2`, written as `Key-Value`.
This library provides `pairs_keys_values/3`,
`pairs_keys/2`, and other predicates to reason about pairs.
* [`si`](src/prolog/lib/si.pl)
* [`si`](src/lib/si.pl)
The predicates `atom_si/1`, `integer_si/1`, `atomic_si/1`
and `list_si/1` implement sound type checks. They raise
instantiation errors if no decision can be made.
@@ -373,51 +380,84 @@ The modules that ship with Scryer&nbsp;Prolog are also called
write `integer_si(X)` to ensure soundness of your programs.
"si" stands for *sufficiently instantiated*, and also for
*sound&nbsp;inference*.
* [`error`](src/prolog/lib/error.pl)
`must_be/2` and `can_be/2` complement the type checks provided
by `library(si)`, and are especially useful for Prolog library
authors.
* [`tabling`](src/prolog/lib/tabling.pl)
* [`debug`](src/lib/debug.pl)
Various predicates that allow for declarative debugging.
* [`pio`](src/lib/pio.pl)
`phrase_from_file/2` applies a DCG nonterminal to the contents of a
file, reading lazily only as much as is needed. Due to the compact
internal string representation, also extremely large files can be
efficiently processed with Scryer&nbsp;Prolog in this way.
* [`charsio`](src/lib/charsio.pl) Various predicates that are useful
for parsing and reasoning about characters, notably `char_type/2` to
classify characters according to their type, and conversion
predicates for different encodings of strings.
* [`error`](src/lib/error.pl)
`must_be/2` and `can_be/2` complement the type checks provided by
[`library(si)`](src/lib/si.pl), and are especially useful for
Prolog library authors.
* [`tabling`](src/lib/tabling.pl)
The operator `(table)/1` is used in directives that prepare
predicates for tabled execution (SLG&nbsp;resolution).
* [`format`](src/prolog/lib/format.pl)
* [`format`](src/lib/format.pl)
The nonterminal `format_//2` is used to describe formatted output,
arranging arguments according to a given format&nbsp;string.
The predicates `format/[2,3]`, `portray_clause/1` and `listing/1`
The predicates `format/[2,3]`, `portray_clause/[1,2]` and `listing/1`
provide formatted *impure* output.
* [`assoc`](src/prolog/lib/assoc.pl)
* [`assoc`](src/lib/assoc.pl)
providing `empty_assoc/1`, `get_assoc/3`, `put_assoc/4` etc.
to manage elements in AVL&nbsp;trees which ensure
*O*(log(*N*))&nbsp;access.
* [`ordsets`](src/prolog/lib/ordsets.pl)
* [`ordsets`](src/lib/ordsets.pl)
represents ordered sets as lists.
* [`clpb`](src/prolog/lib/clpb.pl)
* [`clpb`](src/lib/clpb.pl)
CLP(B): Constraint Logic Programming over Boolean variables,
a BDD-based SAT&nbsp;solver provided via the predicates
`sat/1`, `taut/2`, `labeling/1` etc.
* [`arithmetic`](src/prolog/lib/arithmetic.pl)
* [`arithmetic`](src/lib/arithmetic.pl)
Arithmetic predicates such as `lsb/2`, `msb/2` and
`number_to_rational/2`.
* [`time`](src/prolog/lib/time.pl)
`time/1` reports the CPU&nbsp;time of a goal. It is useful
for measuring the performance of your code.
* [`cont`](src/prolog/lib/cont.pl)
* [`time`](src/lib/time.pl) Predicates for reasoning about
time, including `time/1` to measure the CPU&nbsp;time of a goal,
`current_time/1` to obtain the current system time, the nonterminal
`format_time//2` to describe strings with dates and times, and
`sleep/1` to slow down a computation.
* [`files`](src/lib/files.pl)
Predicates for reasoning about files and directories, such as
`directory_files/2`, `file_exists/1` and `file_size/2`.
* [`cont`](src/lib/cont.pl)
Provides *delimited continuations* via `reset/3` and `shift/1`.
* [`random`](src/prolog/lib/random.pl)
* [`random`](src/lib/random.pl)
Probabilistic predicates and random number generators.
* [`sockets`](src/prolog/lib/sockets.pl)
* [`http/http_open`](src/lib/http/http_open.pl) Open a stream to
read answers from web&nbsp;servers. HTTPS is also supported.
* [`sgml`](src/lib/sgml.pl)
`load_html/3` and `load_xml/3` represent HTML and XML&nbsp;documents
as Prolog&nbsp;terms for convenient and efficient reasoning. Use
[`library(xpath)`](src/lib/iso_ext.pl) to extract information from
parsed documents.
* [`csv`](src/lib/csv.pl)
`parse_csv//1` and `parse_csv//2` can be used with [`phrase_from_file/2`](src/lib/pio.pl)
or [`phrase/2`](src/lib/dcgs.pl) to parse csv
* [`xpath`](src/lib/xpath.pl)
The predicate `xpath/3` is used for convenient reasoning about HTML
and XML&nbsp;documents, inspired by the XPath language. This library
is often used together with [`library(sgml)`](src/lib/sgml.pl).
* [`sockets`](src/lib/sockets.pl)
Predicates for opening and accepting TCP connections as streams.
* [`crypto`](src/prolog/lib/crypto.pl)
Cryptographically secure random numbers and hashes, HMAC-based
key derivation (HKDF), password-based key derivation (PBKDF2),
public key signatures and signature verification with Ed25519,
authenticated encryption, and reasoning about elliptic curves.
To read contents of external files, use `phrase_from_file/2` from
[`library(pio)`](src/prolog/lib/pio.pl) to apply a&nbsp;DCG to
file&nbsp;contents. The predicates in
[`library(charsio)`](src/prolog/lib/charsio.pl) are also useful for
parsing.
TLS negotiation is performed via the option `tls(true)` in
`socket_client_open/3`, yielding secure encrypted connections.
* [`os`](src/lib/os.pl)
Predicates for reasoning about environment&nbsp;variables.
* [`iso_ext`](src/lib/iso_ext.pl)
Conforming extensions to and candidates for inclusion in the Prolog
ISO&nbsp;standard, such as `setup_call_cleanup/3` and
`call_with_inference_limit/3`.
* [`crypto`](src/lib/crypto.pl)
Cryptographically secure random numbers and hashes, HMAC-based key
derivation&nbsp;(HKDF), password-based key derivation&nbsp;(PBKDF2),
public key signatures and signature verification with&nbsp;Ed25519,
ECDH key&nbsp;exchange over Curve25519 (X25519), authenticated symmetric
encryption with ChaCha20-Poly1305, and reasoning about elliptic curves.
To use predicates provided by the `lists` library, write:
@@ -462,3 +502,17 @@ local_member(X, Xs) :- member(X, Xs).
The user listing can also be terminated by placing `end_of_file.` at
the end of the stream.
### Configuration file
At startup, Scryer Prolog consults the file `~/.scryerrc`, if the file
exists. This file is useful to automatically load libraries and define
predicates that you need often.
For example, a sensible starting point for `~/.scryerrc` is:
```
:- use_module(library(lists)).
:- use_module(library(dcgs)).
:- use_module(library(reif)).
```

View File

@@ -1,60 +1,55 @@
extern crate indexmap;
use indexmap::IndexSet;
use std::env;
use std::fs::{File, copy, read_dir};
use std::fs;
use std::fs::File;
use std::io::Write;
use std::path::Path;
fn main()
{
fn find_prolog_files(libraries: &mut File, prefix: &str, current_dir: &Path) {
let entries = match current_dir.read_dir() {
Ok(entries) => entries,
Err(_) => return,
};
for entry in entries.filter_map(Result::ok).map(|e| e.path()) {
if entry.is_dir() {
if let Some(file_name) = entry.file_name() {
let new_prefix =
prefix.to_owned() + file_name.to_str().unwrap() + "/";
find_prolog_files(libraries, &new_prefix, &entry);
}
} else if entry.is_file() {
let ext = std::ffi::OsStr::new("pl");
if entry.extension() == Some(ext) {
let contain =
String::from_utf8(fs::read(&entry).unwrap()).unwrap();
let name = entry.file_stem().unwrap().to_str().unwrap();
let line = format!(
" m.insert(\"{}\",\n{:?});\n",
prefix.to_owned() + name,
contain
);
libraries.write_all(line.as_bytes()).unwrap();
}
}
}
}
fn main() {
let out_dir = env::var("OUT_DIR").unwrap();
let dest_path = Path::new(&out_dir).join("libraries.rs");
let mut libraries = File::create(&dest_path).unwrap();
let mut library_index = IndexSet::new();
let lib_path = Path::new("src/lib");
let paths = read_dir("./src/prolog/lib").unwrap();
for item in paths {
let item = item.unwrap().path();
if let Some(file_name) = item.file_name() {
if let Some(ext) = item.extension() {
if ext == "pl" {
let file_stem = item.file_stem().unwrap();
let file_str = file_stem.to_string_lossy().to_uppercase();
let dest = Path::new(&out_dir).join(file_name);
match copy(&item, dest) {
Ok(_) => {},
Err(e) => panic!("die: {:?}", e)
};
let include_line = format!("static {}: &str = include_str!(\"{}.pl\");\n",
file_str, file_stem.to_string_lossy());
libraries.write_all(include_line.as_bytes()).unwrap();
library_index.insert(file_stem.to_string_lossy().to_string());
}
}
}
}
libraries.write_all(b"\nref_thread_local! {
libraries
.write_all(
b"ref_thread_local! {
pub static managed LIBRARIES: IndexMap<&'static str, &'static str> = {
let mut m = IndexMap::new();\n").unwrap();
for item in library_index {
let line = format!("\n m.insert(\"{}\", {});", item, item.to_uppercase());
libraries.write_all(line.as_bytes()).unwrap();
}
libraries.write_all(b"\n\n m\n };
}\n").unwrap();
libraries.write_all(b"\npub static PROJECT_DIR: &'static str = \"").unwrap();
libraries.write_all(env::var("CARGO_MANIFEST_DIR").unwrap().as_bytes()).unwrap();
libraries.write_all(b"\";\n").unwrap();
let mut m = IndexMap::new();\n",
)
.unwrap();
find_prolog_files(&mut libraries, "", &lib_path);
libraries.write_all(b"\n m\n };\n}\n").unwrap();
}

BIN
logo/scryer.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 128 KiB

896
logo/scryer.svg Normal file
View File

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

After

Width:  |  Height:  |  Size: 54 KiB

View File

@@ -1,9 +1,9 @@
use prolog_parser::ast::*;
use crate::prolog_parser::ast::*;
use crate::prolog::fixtures::*;
use crate::prolog::forms::*;
use crate::prolog::machine::machine_indices::*;
use crate::prolog::targets::*;
use crate::fixtures::*;
use crate::forms::*;
use crate::machine::machine_indices::*;
use crate::targets::*;
use std::cell::Cell;
use std::rc::Rc;

View File

@@ -1,18 +1,18 @@
use prolog_parser::ast::*;
use crate::prolog_parser::ast::*;
use crate::prolog::clause_types::*;
use crate::prolog::fixtures::*;
use crate::prolog::forms::*;
use crate::prolog::instructions::*;
use crate::prolog::iterators::*;
use crate::clause_types::*;
use crate::fixtures::*;
use crate::forms::*;
use crate::instructions::*;
use crate::iterators::*;
use crate::prolog::machine::heap::*;
use crate::prolog::machine::machine_errors::*;
use crate::prolog::machine::machine_indices::*;
use crate::machine::heap::*;
use crate::machine::machine_errors::*;
use crate::machine::machine_indices::*;
use crate::prolog::ordered_float::*;
use crate::prolog::rug::ops::PowAssign;
use crate::prolog::rug::{Assign, Integer, Rational};
use crate::ordered_float::*;
use crate::rug::ops::PowAssign;
use crate::rug::{Assign, Integer, Rational};
use std::cell::Cell;
use std::cmp::{max, min, Ordering};

View File

@@ -1,10 +1,10 @@
use prolog_parser::ast::*;
use crate::prolog_parser::ast::*;
use crate::prolog::forms::Number;
use crate::prolog::machine::machine_indices::*;
use crate::prolog::rug::rand::RandState;
use crate::forms::Number;
use crate::machine::machine_indices::*;
use crate::rug::rand::RandState;
use ref_thread_local::RefThreadLocal;
use crate::ref_thread_local::RefThreadLocal;
use std::collections::BTreeMap;
@@ -171,6 +171,16 @@ pub enum SystemClauseType {
CurrentHostname,
CurrentInput,
CurrentOutput,
DirectoryFiles,
FileSize,
FileExists,
DirectoryExists,
DirectorySeparator,
MakeDirectory,
DeleteFile,
WorkingDirectory,
PathCanonical,
FileTime,
DeleteAttribute,
DeleteHeadAttribute,
DynamicModuleResolution(usize),
@@ -180,11 +190,11 @@ pub enum SystemClauseType {
ExpandTerm,
FetchGlobalVar,
FetchGlobalVarWithOffset,
FileToChars,
FirstStream,
FlushOutput,
GetByte,
GetChar,
GetNChars,
GetCode,
GetSingleChar,
ResetAttrVarState,
@@ -229,8 +239,8 @@ pub enum SystemClauseType {
PeekCode,
PointsToContinuationResetMarker,
PutByte,
PutBytes,
PutChar,
PutChars,
PutCode,
REPL(REPLCodePtr),
ReadQueryTerm,
@@ -261,6 +271,7 @@ pub enum SystemClauseType {
InstallNewBlock,
Maybe,
CpuNow,
CurrentTime,
QuotedToken,
ReadTermFromChars,
ResetBlock,
@@ -293,10 +304,18 @@ pub enum SystemClauseType {
CryptoPasswordHash,
CryptoDataEncrypt,
CryptoDataDecrypt,
CryptoCurveScalarMult,
Ed25519Sign,
Ed25519Verify,
Ed25519NewKeyPair,
Ed25519KeyPairPublicKey
Ed25519KeyPairPublicKey,
Curve25519ScalarMult,
LoadHTML,
LoadXML,
GetEnv,
SetEnv,
UnsetEnv,
CharsBase64,
}
impl SystemClauseType {
@@ -324,6 +343,16 @@ impl SystemClauseType {
&SystemClauseType::CurrentInput => clause_name!("$current_input"),
&SystemClauseType::CurrentHostname => clause_name!("$current_hostname"),
&SystemClauseType::CurrentOutput => clause_name!("$current_output"),
&SystemClauseType::DirectoryFiles => clause_name!("$directory_files"),
&SystemClauseType::FileSize => clause_name!("$file_size"),
&SystemClauseType::FileExists => clause_name!("$file_exists"),
&SystemClauseType::DirectoryExists => clause_name!("$directory_exists"),
&SystemClauseType::DirectorySeparator => clause_name!("$directory_separator"),
&SystemClauseType::MakeDirectory => clause_name!("$make_directory"),
&SystemClauseType::DeleteFile => clause_name!("$delete_file"),
&SystemClauseType::WorkingDirectory => clause_name!("$working_directory"),
&SystemClauseType::PathCanonical => clause_name!("$path_canonical"),
&SystemClauseType::FileTime => clause_name!("$file_time"),
&SystemClauseType::REPL(REPLCodePtr::CompileBatch) => clause_name!("$compile_batch"),
&SystemClauseType::REPL(REPLCodePtr::UseModule) => clause_name!("$use_module"),
&SystemClauseType::REPL(REPLCodePtr::UseQualifiedModule) => {
@@ -348,11 +377,11 @@ impl SystemClauseType {
&SystemClauseType::FetchGlobalVarWithOffset => {
clause_name!("$fetch_global_var_with_offset")
}
&SystemClauseType::FileToChars => clause_name!("$file_to_chars"),
&SystemClauseType::FirstStream => clause_name!("$first_stream"),
&SystemClauseType::FlushOutput => clause_name!("$flush_output"),
&SystemClauseType::GetByte => clause_name!("$get_byte"),
&SystemClauseType::GetChar => clause_name!("$get_char"),
&SystemClauseType::GetNChars => clause_name!("$get_n_chars"),
&SystemClauseType::GetCode => clause_name!("$get_code"),
&SystemClauseType::GetSingleChar => clause_name!("$get_single_char"),
&SystemClauseType::ResetAttrVarState => clause_name!("$reset_attr_var_state"),
@@ -397,6 +426,7 @@ impl SystemClauseType {
&SystemClauseType::LiftedHeapLength => clause_name!("$lh_length"),
&SystemClauseType::Maybe => clause_name!("maybe"),
&SystemClauseType::CpuNow => clause_name!("$cpu_now"),
&SystemClauseType::CurrentTime => clause_name!("$current_time"),
&SystemClauseType::ModuleAssertDynamicPredicateToFront => {
clause_name!("$module_asserta")
}
@@ -416,12 +446,12 @@ impl SystemClauseType {
&SystemClauseType::PutByte => {
clause_name!("$put_byte")
}
&SystemClauseType::PutBytes => {
clause_name!("$put_bytes")
}
&SystemClauseType::PutChar => {
clause_name!("$put_char")
}
&SystemClauseType::PutChars => {
clause_name!("$put_chars")
}
&SystemClauseType::PutCode => {
clause_name!("$put_code")
}
@@ -488,10 +518,18 @@ impl SystemClauseType {
&SystemClauseType::CryptoPasswordHash => clause_name!("$crypto_password_hash"),
&SystemClauseType::CryptoDataEncrypt => clause_name!("$crypto_data_encrypt"),
&SystemClauseType::CryptoDataDecrypt => clause_name!("$crypto_data_decrypt"),
&SystemClauseType::CryptoCurveScalarMult => clause_name!("$crypto_curve_scalar_mult"),
&SystemClauseType::Ed25519Sign => clause_name!("$ed25519_sign"),
&SystemClauseType::Ed25519Verify => clause_name!("$ed25519_verify"),
&SystemClauseType::Ed25519NewKeyPair => clause_name!("$ed25519_new_keypair"),
&SystemClauseType::Ed25519KeyPairPublicKey => clause_name!("$ed25519_keypair_public_key")
&SystemClauseType::Ed25519KeyPairPublicKey => clause_name!("$ed25519_keypair_public_key"),
&SystemClauseType::Curve25519ScalarMult => clause_name!("$curve25519_scalar_mult"),
&SystemClauseType::LoadHTML => clause_name!("$load_html"),
&SystemClauseType::LoadXML => clause_name!("$load_xml"),
&SystemClauseType::GetEnv => clause_name!("$getenv"),
&SystemClauseType::SetEnv => clause_name!("$setenv"),
&SystemClauseType::UnsetEnv => clause_name!("$unsetenv"),
&SystemClauseType::CharsBase64 => clause_name!("$chars_base64"),
}
}
@@ -545,9 +583,9 @@ impl SystemClauseType {
("$expand_goal", 2) => Some(SystemClauseType::ExpandGoal),
("$fetch_global_var", 2) => Some(SystemClauseType::FetchGlobalVar),
("$fetch_global_var_with_offset", 3) => Some(SystemClauseType::FetchGlobalVarWithOffset),
("$file_to_chars", 3) => Some(SystemClauseType::FileToChars),
("$get_byte", 2) => Some(SystemClauseType::GetByte),
("$get_char", 2) => Some(SystemClauseType::GetChar),
("$get_n_chars", 3) => Some(SystemClauseType::GetNChars),
("$get_code", 2) => Some(SystemClauseType::GetCode),
("$get_single_char", 1) => Some(SystemClauseType::GetSingleChar),
("$points_to_cont_reset_marker", 1) => {
@@ -556,12 +594,12 @@ impl SystemClauseType {
("$put_byte", 2) => {
Some(SystemClauseType::PutByte)
}
("$put_bytes", 2) => {
Some(SystemClauseType::PutBytes)
}
("$put_char", 2) => {
Some(SystemClauseType::PutChar)
}
("$put_chars", 2) => {
Some(SystemClauseType::PutChars)
}
("$put_code", 2) => {
Some(SystemClauseType::PutCode)
}
@@ -580,13 +618,14 @@ impl SystemClauseType {
("$get_lh_from_offset_diff", 3) => Some(SystemClauseType::GetLiftedHeapFromOffsetDiff),
("$get_double_quotes", 1) => Some(SystemClauseType::GetDoubleQuotes),
("$get_scc_cleaner", 1) => Some(SystemClauseType::GetSCCCleaner),
("$halt", 0) => Some(SystemClauseType::Halt),
("$halt", 1) => Some(SystemClauseType::Halt),
("$head_is_dynamic", 1) => Some(SystemClauseType::HeadIsDynamic),
("$install_scc_cleaner", 2) => Some(SystemClauseType::InstallSCCCleaner),
("$install_inference_counter", 3) => Some(SystemClauseType::InstallInferenceCounter),
("$lh_length", 1) => Some(SystemClauseType::LiftedHeapLength),
("$maybe", 0) => Some(SystemClauseType::Maybe),
("$cpu_now", 1) => Some(SystemClauseType::CpuNow),
("$current_time", 1) => Some(SystemClauseType::CurrentTime),
("$module_exists", 1) => Some(SystemClauseType::ModuleExists),
("$module_of", 2) => Some(SystemClauseType::ModuleOf),
("$module_retract_clause", 5) => Some(SystemClauseType::ModuleRetractClause),
@@ -633,7 +672,7 @@ impl SystemClauseType {
("$set_seed", 1) => Some(SystemClauseType::SetSeed),
("$skip_max_list", 4) => Some(SystemClauseType::SkipMaxList),
("$sleep", 1) => Some(SystemClauseType::Sleep),
("$socket_client_open", 7) => Some(SystemClauseType::SocketClientOpen),
("$socket_client_open", 8) => Some(SystemClauseType::SocketClientOpen),
("$socket_server_open", 3) => Some(SystemClauseType::SocketServerOpen),
("$socket_server_accept", 7) => Some(SystemClauseType::SocketServerAccept),
("$socket_server_close", 1) => Some(SystemClauseType::SocketServerClose),
@@ -645,6 +684,16 @@ impl SystemClauseType {
("$unwind_environments", 0) => Some(SystemClauseType::UnwindEnvironments),
("$unwind_stack", 0) => Some(SystemClauseType::UnwindStack),
("$unify_with_occurs_check", 2) => Some(SystemClauseType::UnifyWithOccursCheck),
("$directory_files", 2) => Some(SystemClauseType::DirectoryFiles),
("$file_size", 2) => Some(SystemClauseType::FileSize),
("$file_exists", 1) => Some(SystemClauseType::FileExists),
("$directory_exists", 1) => Some(SystemClauseType::DirectoryExists),
("$directory_separator", 1) => Some(SystemClauseType::DirectorySeparator),
("$make_directory", 1) => Some(SystemClauseType::MakeDirectory),
("$delete_file", 1) => Some(SystemClauseType::DeleteFile),
("$working_directory", 2) => Some(SystemClauseType::WorkingDirectory),
("$path_canonical", 2) => Some(SystemClauseType::PathCanonical),
("$file_time", 3) => Some(SystemClauseType::FileTime),
("$use_module", 1) => Some(SystemClauseType::REPL(REPLCodePtr::UseModule)),
("$use_module_from_file", 1) =>
Some(SystemClauseType::REPL(REPLCodePtr::UseModuleFromFile)),
@@ -658,15 +707,23 @@ impl SystemClauseType {
("$write_term_to_chars", 7) => Some(SystemClauseType::WriteTermToChars),
("$scryer_prolog_version", 1) => Some(SystemClauseType::ScryerPrologVersion),
("$crypto_random_byte", 1) => Some(SystemClauseType::CryptoRandomByte),
("$crypto_data_hash", 3) => Some(SystemClauseType::CryptoDataHash),
("$crypto_data_hkdf", 6) => Some(SystemClauseType::CryptoDataHKDF),
("$crypto_data_hash", 4) => Some(SystemClauseType::CryptoDataHash),
("$crypto_data_hkdf", 7) => Some(SystemClauseType::CryptoDataHKDF),
("$crypto_password_hash", 4) => Some(SystemClauseType::CryptoPasswordHash),
("$crypto_data_encrypt", 5) => Some(SystemClauseType::CryptoDataEncrypt),
("$crypto_data_decrypt", 5) => Some(SystemClauseType::CryptoDataDecrypt),
("$ed25519_sign", 3) => Some(SystemClauseType::Ed25519Sign),
("$ed25519_verify", 3) => Some(SystemClauseType::Ed25519Verify),
("$crypto_data_encrypt", 6) => Some(SystemClauseType::CryptoDataEncrypt),
("$crypto_data_decrypt", 6) => Some(SystemClauseType::CryptoDataDecrypt),
("$crypto_curve_scalar_mult", 5) => Some(SystemClauseType::CryptoCurveScalarMult),
("$ed25519_sign", 5) => Some(SystemClauseType::Ed25519Sign),
("$ed25519_verify", 5) => Some(SystemClauseType::Ed25519Verify),
("$ed25519_new_keypair", 1) => Some(SystemClauseType::Ed25519NewKeyPair),
("$ed25519_keypair_public_key", 2) => Some(SystemClauseType::Ed25519KeyPairPublicKey),
("$ed25519_keypair_public_key", 3) => Some(SystemClauseType::Ed25519KeyPairPublicKey),
("$curve25519_scalar_mult", 3) => Some(SystemClauseType::Curve25519ScalarMult),
("$load_html", 3) => Some(SystemClauseType::LoadHTML),
("$load_xml", 3) => Some(SystemClauseType::LoadXML),
("$getenv", 2) => Some(SystemClauseType::GetEnv),
("$setenv", 2) => Some(SystemClauseType::SetEnv),
("$unsetenv", 1) => Some(SystemClauseType::UnsetEnv),
("$chars_base64", 4) => Some(SystemClauseType::CharsBase64),
_ => None,
}
}

View File

@@ -1,17 +1,17 @@
use prolog_parser::ast::*;
use crate::prolog_parser::ast::*;
use crate::prolog::allocator::*;
use crate::prolog::arithmetic::*;
use crate::prolog::clause_types::*;
use crate::prolog::fixtures::*;
use crate::prolog::forms::*;
use crate::prolog::indexing::*;
use crate::prolog::instructions::*;
use crate::prolog::iterators::*;
use crate::prolog::machine::machine_indices::*;
use crate::prolog::targets::*;
use crate::allocator::*;
use crate::arithmetic::*;
use crate::clause_types::*;
use crate::fixtures::*;
use crate::forms::*;
use crate::indexing::*;
use crate::instructions::*;
use crate::iterators::*;
use crate::machine::machine_indices::*;
use crate::targets::*;
use indexmap::{IndexMap, IndexSet};
use crate::indexmap::{IndexMap, IndexSet};
use std::cell::Cell;
use std::rc::Rc;

View File

@@ -1,12 +1,12 @@
use indexmap::IndexMap;
use crate::indexmap::IndexMap;
use prolog_parser::ast::*;
use crate::prolog_parser::ast::*;
use crate::prolog::allocator::*;
use crate::prolog::fixtures::*;
use crate::prolog::forms::*;
use crate::prolog::machine::machine_indices::*;
use crate::prolog::targets::*;
use crate::allocator::*;
use crate::fixtures::*;
use crate::forms::*;
use crate::machine::machine_indices::*;
use crate::targets::*;
use std::cell::Cell;
use std::collections::BTreeSet;

View File

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

View File

@@ -1,4 +1,4 @@
:- module(bimetatrans_ruleml, [parse_ruleml/3]).
:- module(bimetatrans, [parse_ruleml/3]).
:- use_module(library(dcgs)).
:- use_module(library(iso_ext)).
@@ -19,28 +19,34 @@
* all indentation stripped out. "Indented XML" contains indentation
* and newlines, and is usually formatted for human readers.
*
* parse_ruleml/3 is the sole public predicate of BiMetaTrans(RuleML,
* Prolog), a bidirectional translator capable of parsing well-formed
* parse_ruleml/3 is the sole public predicate of BiMetaTrans(Prolog,
* RuleML), a bidirectional translator capable of parsing well-formed
* RuleML/XML (valid w.r.t. a proposed anchor schema nafhornlogeq
* defining a sublanguage of the existing anchor schema naffologeq) to
* an equivalent Prolog/'$V' term and back to RuleML/xmL. It has the
* modes
*
* +AssertItem, +QueryItems, ?XML (Prolog->RuleML)
* ?AssertItem, ?QueryItems, +XML (RuleML->Prolog)
* +AssertItems, +QueryItems, ?XML (Prolog->RuleML)
* ?AssertItems, ?QueryItems, +XML (RuleML->Prolog)
*
* The modes constrain the inputs to fit one of two patterns, the
* first where AssertItem and QueryItem are instantiated and XML is
* first where AssertItems and QueryItems are instantiated and XML is
* possibly a variable, and conversely for the second. Instantiated
* inputs are expected to be ground, meaning they should not contain
* free variables.
*
* A RuleML/XML document is assumed to contain an optional Assert
* element (with zero or more children) and zero or more Query
* elements. The children of the Assert element are the Items of
* AssertItems, while the Items of QueryItems each correspond to a
* single Query element.
*
* parse_ruleml/3 is meant to subsume an invertible function in the
* sense that the top-level query
*
* ?- parse_ruleml(AssertItem, QueryItems, XML0), % Prolog->RuleML
* parse_ruleml(AssertItem0, QueryItems0, XML), % RuleML->Prolog
* AssertItem0 == AssertItem, % Test for expected round-trip results.
* ?- parse_ruleml(AssertItems, QueryItems, XML0), % Prolog->RuleML
* parse_ruleml(AssertItems0, QueryItems0, XML), % RuleML->Prolog
* AssertItems0 == AssertItems, % Test for expected round-trip results.
* QueryItems0 == QueryItems,
* XML0 == XML.
*
@@ -48,10 +54,11 @@
* not 0-appended are instantiated and therefore ground.
*/
parse_ruleml(AssertItem, QueryItem, XML) :-
( ( var(AssertItem) ; var(QueryItem) ), var(XML) ->
parse_ruleml(AssertItems, QueryItems, XML) :-
( ( var(AssertItems) ; var(QueryItems) ), var(XML) ->
throw(error(instantiation_error, parse_ruleml/2))
; phrase(ruleml_top_level_items(AssertItem, QueryItem), XML)
; phrase(ruleml_top_level_items(AssertItems, QueryItems), XML),
!
).
@@ -82,24 +89,15 @@ parse_header -->
*
* The two arguments are (un)instantiated depending on the direction
* in which parse_ruleml/2 operates. In either direction, once
* ruleml_query_item(QueryItems) or ruleml_assert(AssertItem)
* succeeds:
*
* 1) AssertItem/QueryItems is a fully ground list of terms,
* corresponding to an Assert/Query performative of the RuleML/XML KB.
*
* 2) It would not be meaningful to backtrack after the last success,
* thus undoing its effects; that is because we have already refuted
* the possibility of there being further items for the grammar to
* consume. Hence we see that the cut (!) does not restrict the
* generality of the grammar.
* ruleml_query_item(QueryItems) or ruleml_assert(AssertItems)
* succeeds, AssertItems and QueryItems are ground lists of terms,
* corresponding to Assert/Query performative(s) of the RuleML/XML KB.
*/
ruleml_top_level_items(AssertItem, QueryItems) -->
( ruleml_assert(AssertItem),
ruleml_query_items(QueryItems),
!
; { AssertItem = [] },
ruleml_top_level_items(AssertItems, QueryItems) -->
( ruleml_assert(AssertItems),
ruleml_query_items(QueryItems)
; { AssertItems = [] },
ruleml_query_items(QueryItems)
).
@@ -169,22 +167,16 @@ ruleml_top_level_items(AssertItem, QueryItems) -->
* outset of ruleml_assert//1 will cause it to fail, meaning that
* an empty <Assert></Assert> element is never emitted to the output
* RuleML/xmL.
*
* The two cuts are green cuts, meaning they do not change the meaning
* or output of the program, they simply prevent needless
* backtracking.
*/
ruleml_assert(Items) -->
( { var(Items) } ->
list_ws("<Assert mapClosure=\"universal\">"),
ruleml_assert_items(Items),
!,
list_ws("</Assert>")
; "<Assert mapClosure=\"universal\">",
{ Items \== [] },
ruleml_assert_items(Items),
!,
"</Assert>"
).
@@ -206,7 +198,6 @@ ruleml_assert(Items) -->
ruleml_assert_items([Item | Items]) -->
ruleml_assert_item(Item),
!,
ruleml_assert_items(Items).
ruleml_assert_items([]) --> [].
@@ -214,7 +205,6 @@ ruleml_assert_items([]) --> [].
ruleml_query_items(Items) -->
( { var(Items) } ->
ruleml_query_item(Item),
!,
( { var(Item) } ->
ruleml_query_items(Items)
; { Items = [Item | Items0] },
@@ -222,7 +212,6 @@ ruleml_query_items(Items) -->
)
; { Items = [Item | Items0] },
ruleml_query_item(Item),
!,
ruleml_query_items(Items0)
).
ruleml_query_items([]) --> [].
@@ -279,7 +268,7 @@ space(' ') --> " ".
decimal_point('.') --> ".".
sign('-') --> "-", !.
sign('-') --> "-".
sign('+') --> "+".
double_quote('"') --> "\"".
@@ -332,7 +321,6 @@ ruleml_condition(Item) -->
ruleml_item_conjunction([Item | Items]) -->
ruleml_condition(Item),
!,
ruleml_item_conjunction(Items).
ruleml_item_conjunction([]) --> [].
@@ -404,7 +392,6 @@ ruleml_conjunction_of_items(Items) -->
ruleml_item_disjunction([Item | Items]) -->
ruleml_condition(Item),
!,
ruleml_item_disjunction(Items).
ruleml_item_disjunction([]) --> [].
@@ -549,7 +536,6 @@ ruleml_naf(Item) -->
ruleml_atoms([Item|Items]) -->
ruleml_atom(Item),
!,
ruleml_atoms(Items).
ruleml_atoms([]) --> [].
@@ -652,7 +638,6 @@ ruleml_expr(Item) -->
( list_ws("<repo>"),
ruleml_item(RepoItem),
list_ws("</repo>"),
!,
{ fold_commas(Args, ArgsCommas) },
{ Item =.. [Name, (ArgsCommas | RepoItem)] }
; { Item =.. [Name | Args] }
@@ -823,15 +808,12 @@ ruleml_data(Name) -->
* converting from lists of characters (here denoted as Cs) to the
* named data type in ISO Prolog. The type information is given
* in the first argument.
*
* Grammatically, ruleml_data_contents//3 is a disjoint union of its
* subgrammars, justifying the cut at the end of the first two rules.
*/
ruleml_data_contents(number, Cs) -->
ruleml_number(Cs), !.
ruleml_number(Cs).
ruleml_data_contents(symbol, Cs) -->
ruleml_symbol(Cs), !.
ruleml_symbol(Cs).
ruleml_data_contents(string, Cs) -->
ruleml_string(Cs).
@@ -1195,8 +1177,7 @@ fold_semicolons(List, Output) :-
* complicated by Scryer's current lack of multi-argument indexing.
*/
fold_list([Item], _, Item) :-
!.
fold_list([Item], _, Item).
fold_list([Item|Items], F, Form) :-
Form =.. [F, Item, Fs],
fold_list(Items, F, Fs).

View File

@@ -11,11 +11,12 @@
*/
:- module(least_time, [find_min_time/2,
write_time_nl/1]).
write_time_nl/1]).
:- use_module(library(dcgs)).
:- use_module(library(format)).
:- use_module(library(lists)).
:- use_module(library(reif)).
@@ -32,10 +33,10 @@ valid_time([H1,H2,M1,M2], T) :-
memberd_t(M2, [0,1,2,3,4,5,6,7,8,9], TM2),
( maplist(=(true), [TH1, TH2, TM1, TM2]) ->
( H1 =:= 2 ->
( H2 =< 3 ->
T = true
; T = false
)
( H2 =< 3 ->
T = true
; T = false
)
; T = true
)
; T = false
@@ -49,15 +50,7 @@ permuted_times(Time, PermutedTimes) :-
find_min_time(Time, Min) :-
valid_time(Time, true),
permuted_times(Time, PermutedTimes),
find_min_time_(PermutedTimes, Time, Min).
find_min_time_([], Min, Min).
find_min_time_([Time|Times], MinSoFar, Min) :-
( Time @< MinSoFar ->
find_min_time_(Times, Time, Min)
; find_min_time_(Times, MinSoFar, Min)
).
permuted_times(Time, [Min|_]).
write_time_nl(Time) :-

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

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

View File

@@ -1,10 +1,10 @@
use prolog_parser::ast::*;
use crate::prolog_parser::ast::*;
use crate::prolog::forms::*;
use crate::prolog::instructions::*;
use crate::prolog::iterators::*;
use crate::forms::*;
use crate::instructions::*;
use crate::iterators::*;
use indexmap::{IndexMap, IndexSet};
use crate::indexmap::{IndexMap, IndexSet};
use std::cell::Cell;
use std::collections::BTreeSet;

View File

@@ -1,14 +1,14 @@
use prolog_parser::ast::*;
use prolog_parser::parser::OpDesc;
use prolog_parser::tabled_rc::*;
use crate::prolog_parser::ast::*;
use crate::prolog_parser::parser::OpDesc;
use crate::prolog_parser::tabled_rc::*;
use crate::prolog::clause_types::*;
use crate::prolog::machine::machine_errors::*;
use crate::prolog::machine::machine_indices::*;
use crate::prolog::ordered_float::OrderedFloat;
use crate::prolog::rug::{Integer, Rational};
use crate::clause_types::*;
use crate::machine::machine_errors::*;
use crate::machine::machine_indices::*;
use crate::ordered_float::OrderedFloat;
use crate::rug::{Integer, Rational};
use indexmap::IndexMap;
use crate::indexmap::IndexMap;
use std::cell::Cell;
use std::collections::VecDeque;
@@ -505,11 +505,11 @@ pub fn fetch_atom_op_spec(
spec: Option<SharedOpDesc>,
op_dir: &OpDir,
) -> Option<SharedOpDesc> {
fetch_op_spec(name.clone(), 1, spec.clone(), op_dir)
.or_else(|| fetch_op_spec(name, 2, spec, op_dir))
fetch_op_spec_from_existing(name.clone(), 1, spec.clone(), op_dir)
.or_else(|| fetch_op_spec_from_existing(name, 2, spec, op_dir))
}
pub fn fetch_op_spec(
pub fn fetch_op_spec_from_existing(
name: ClauseName,
arity: usize,
spec: Option<SharedOpDesc>,
@@ -524,7 +524,15 @@ pub fn fetch_op_spec(
}
}
spec.or_else(|| match arity {
spec.or_else(|| fetch_op_spec(name, arity, op_dir))
}
pub fn fetch_op_spec(
name: ClauseName,
arity: usize,
op_dir: &OpDir,
) -> Option<SharedOpDesc> {
match arity {
2 => op_dir
.get(&(name, Fixity::In))
.and_then(|OpDirValue(spec, _)| {
@@ -542,7 +550,7 @@ pub fn fetch_op_spec(
}
op_dir
.get(&(name.clone(), Fixity::Post))
.get(&(name, Fixity::Post))
.and_then(|OpDirValue(spec, _)| {
if spec.prec() > 0 {
Some(spec.clone())
@@ -551,8 +559,10 @@ pub fn fetch_op_spec(
}
})
}
_ => None,
})
_ => {
None
}
}
}
pub type ModuleDir = IndexMap<ClauseName, Module>;

View File

@@ -1,7 +1,7 @@
use crate::prolog::machine::machine_indices::*;
use crate::prolog::machine::machine_state::*;
use crate::machine::machine_indices::*;
use crate::machine::machine_state::*;
use indexmap::IndexSet;
use crate::indexmap::IndexSet;
use std::cmp::Ordering;
use std::ops::Deref;
@@ -93,21 +93,19 @@ impl<'a> HCPreOrderIterator<'a> {
}
Addr::Con(h) => {
if let &HeapCellValue::PartialString(ref pstr, has_tail) = &self.machine_st.heap[h] {
if !self.machine_st.flags.double_quotes.is_atom() {
return if let Some(c) = pstr.range_from(0 ..).next() {
self.state_stack.push(Addr::PStrLocation(h, c.len_utf8()));
self.state_stack.push(Addr::Char(c));
if let Some(c) = pstr.range_from(0 ..).next() {
self.state_stack.push(Addr::PStrLocation(h, c.len_utf8()));
self.state_stack.push(Addr::Char(c));
Addr::PStrLocation(h, 0)
} else if has_tail {
self.follow(Addr::HeapCell(h + 1))
} else {
Addr::EmptyList
};
Addr::PStrLocation(h, 0)
} else if has_tail {
self.follow(Addr::HeapCell(h + 1))
} else {
Addr::EmptyList
}
} else {
Addr::Con(h)
}
Addr::Con(h)
}
da => {
da

View File

@@ -1,16 +1,16 @@
use prolog_parser::ast::*;
use crate::prolog_parser::ast::*;
use crate::prolog::clause_types::*;
use crate::prolog::forms::*;
use crate::prolog::heap_iter::*;
use crate::prolog::machine::heap::*;
use crate::prolog::machine::machine_indices::*;
use crate::prolog::machine::machine_state::*;
use crate::prolog::machine::streams::*;
use crate::prolog::ordered_float::OrderedFloat;
use crate::prolog::rug::{Integer, Rational};
use crate::clause_types::*;
use crate::forms::*;
use crate::heap_iter::*;
use crate::machine::heap::*;
use crate::machine::machine_indices::*;
use crate::machine::machine_state::*;
use crate::machine::streams::*;
use crate::ordered_float::OrderedFloat;
use crate::rug::{Integer, Rational};
use indexmap::{IndexMap, IndexSet};
use crate::indexmap::{IndexMap, IndexSet};
use std::cell::Cell;
use std::convert::TryFrom;
@@ -449,8 +449,6 @@ fn non_quoted_token<Iter: Iterator<Item = char>>(mut iter: Iter) -> bool {
if let Some(c) = iter.next() {
if small_letter_char!(c) {
iter.all(|c| alpha_numeric_char!(c))
} else if c == '.' {
iter.next().is_some()
} else if graphic_token_char!(c) {
non_quoted_graphic_token(iter, c)
} else if semicolon_char!(c) {
@@ -1173,7 +1171,7 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
let at_cdr = self.at_cdr(",");
if !at_cdr && Addr::EmptyList == end_addr {
if self.machine_st.flags.double_quotes.is_chars() && !self.ignore_ops {
if !self.ignore_ops {
self.print_proper_string(buf, max_depth);
return;
}
@@ -1190,18 +1188,6 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
let mut byte_len = 0;
let char_printer = |printer: &mut Self, c| {
if printer.machine_st.flags.double_quotes.is_codes() {
let s = (c as u32).to_string();
push_space_if_amb!(printer, &s, {
printer.append_str(&s);
});
} else {
printer.print_char(printer.quoted, c);
}
};
if self.ignore_ops {
let mut char_count = 0;
@@ -1209,7 +1195,7 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
self.append_str("'.'");
self.push_char('(');
char_printer(self, c);
self.print_char(self.quoted, c);
self.push_char(',');
char_count += 1;
@@ -1235,7 +1221,7 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
};
for c in buf_iter {
char_printer(self, c);
self.print_char(self.quoted, c);
self.push_char(',');
byte_len += c.len_utf8();
@@ -1312,6 +1298,7 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
!iter.immediate_leaf_has_property(|addr, heap| {
match heap.index_addr(&addr).as_ref() {
&HeapCellValue::Integer(ref n) => &**n >= &0,
&HeapCellValue::Addr(Addr::Fixnum(n)) => n >= 0,
&HeapCellValue::Addr(Addr::Float(f)) => f >= OrderedFloat(0f64),
&HeapCellValue::Rational(ref r) => &**r >= &0,
_ => false
@@ -1422,7 +1409,7 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
match self.machine_st.heap.index_addr(&addr).as_ref() {
&HeapCellValue::NamedStr(arity, ref name, ref spec) => {
let spec = fetch_op_spec(name.clone(), arity, spec.clone(), self.op_dir);
let spec = fetch_op_spec_from_existing(name.clone(), arity, spec.clone(), self.op_dir);
if let Some(spec) = spec {
self.handle_op_as_struct(

View File

@@ -1,10 +1,10 @@
use prolog_parser::ast::*;
use prolog_parser::tabled_rc::*;
use crate::prolog_parser::ast::*;
use crate::prolog_parser::tabled_rc::*;
use crate::prolog::instructions::*;
use crate::prolog::rug::Integer;
use crate::instructions::*;
use crate::rug::Integer;
use indexmap::IndexMap;
use crate::indexmap::IndexMap;
use std::collections::VecDeque;
use std::convert::TryFrom;
@@ -123,10 +123,6 @@ impl CodeOffsets {
code.push(Self::add_index(code.is_empty(), index));
}
}
&Constant::String(_) => {
let is_initial_index = self.lists.is_empty();
self.lists.push(Self::add_index(is_initial_index, index));
}
&Constant::Usize(n) => {
let code = self.constants
.entry(Constant::Integer(Rc::new(Integer::from(n))))
@@ -158,7 +154,7 @@ impl CodeOffsets {
let is_initial_index = code.is_empty();
code.push(Self::add_index(is_initial_index, index));
}
&Term::Cons(..) => {
&Term::Cons(..) | &Term::Constant(_, Constant::String(_)) => {
let is_initial_index = self.lists.is_empty();
self.lists.push(Self::add_index(is_initial_index, index));
}
@@ -172,7 +168,8 @@ impl CodeOffsets {
let is_initial_index = code.is_empty();
code.push(Self::add_index(is_initial_index, index));
}
_ => {}
_ => {
}
};
}

View File

@@ -1,13 +1,13 @@
use prolog_parser::ast::*;
use crate::prolog_parser::ast::*;
use crate::prolog::clause_types::*;
use crate::prolog::forms::*;
use crate::prolog::machine::heap::*;
use crate::prolog::machine::machine_errors::MachineStub;
use crate::prolog::machine::machine_indices::*;
use crate::prolog::rug::Integer;
use crate::clause_types::*;
use crate::forms::*;
use crate::machine::heap::*;
use crate::machine::machine_errors::MachineStub;
use crate::machine::machine_indices::*;
use crate::rug::Integer;
use indexmap::IndexMap;
use crate::indexmap::IndexMap;
use std::collections::VecDeque;
use std::rc::Rc;

View File

@@ -1,8 +1,8 @@
use prolog_parser::ast::*;
use crate::prolog_parser::ast::*;
use crate::prolog::clause_types::*;
use crate::prolog::forms::*;
use crate::prolog::machine::machine_indices::*;
use crate::clause_types::*;
use crate::forms::*;
use crate::machine::machine_indices::*;
use std::cell::Cell;
use std::collections::VecDeque;

View File

@@ -24,6 +24,8 @@ user:term_expansion((:- op(Pred, Spec, [Op | OtherOps])), OpResults) :-
:- op(400, yfx, [div, //, rdiv, <<, >>, mod, rem]).
:- op(200, fy, [+, -, \]).
:- op(1200, xfx, -->).
% arithmetic comparison operators.
:- op(700, xfx, [>, <, =\=, =:=, >=, =<]).
@@ -52,7 +54,7 @@ user:term_expansion((:- op(Pred, Spec, [Op | OtherOps])), OpResults) :-
findall/3, findall/4, flush_output/0,
flush_output/1, get_byte/1, get_byte/2,
get_char/1, get_char/2, get_code/1, get_code/2,
halt/0, max_arity/1, number_chars/2,
halt/0, halt/1, max_arity/1, number_chars/2,
number_codes/2, once/1, op/3, open/3, open/4,
peek_byte/1, peek_byte/2, peek_char/1,
peek_char/2, peek_code/1, peek_code/2,
@@ -912,7 +914,14 @@ op(Priority, OpSpec, Op) :-
; throw(error(type_error(list, Op), op/3)) % 8.14.3.3 f)
).
halt :- '$halt'.
halt :- halt(0).
halt(N) :-
( -2^31 =< N, N =< 2^31 - 1 ->
'$halt'(N)
; throw(error(domain_error(exit_code, N), halt/1))
).
atom_length(Atom, Length) :-
( var(Atom) -> throw(error(instantiation_error, atom_length/2)) % 8.16.1.3 a)

View File

@@ -1,8 +1,10 @@
:- module(charsio, [char_type/2,
chars_utf8bytes/2,
get_single_char/1,
read_line_to_chars/3,
read_term_from_chars/2,
write_term_to_chars/3]).
write_term_to_chars/3,
chars_base64/3]).
:- use_module(library(dcgs)).
:- use_module(library(iso_ext)).
@@ -140,7 +142,6 @@ write_term_to_chars(Term, Options, Chars) :-
'$write_term_to_chars'(Chars, Term, IgnoreOps, NumberVars, Quoted, NewVarNames, MaxDepth).
% Encodes Ch character to list of Bytes.
% TODO: if Ch is variable, decode Bytes to Char.
char_utf8bytes(Ch, Bytes) :-
char_code(Ch, Code),
phrase(code_to_utf8(Code), Bytes).
@@ -155,10 +156,87 @@ encode(Code, Prefix, Nb) -->
{ Nb1 is Nb - 1, Byte is Prefix \/ ((Code >> (6 * Nb1)) /\ 0x3F) },
[Byte], encode(Code, 0x80, Nb1).
% Encodes a list of characters Cs to a list of UTF-8 bytes Bs.
% TODO: if Cs is variable, decode bytes to chars instead.
% Maps characters and UTF-8 bytes.
% If Cs is a variable, parses Bs as a list of UTF-8 bytes.
% Otherwise, transform the list of characters Cs to UTF-8 bytes.
chars_utf8bytes(Cs, Bs) :-
must_be(list, Cs),
maplist(must_be(atom), Cs),
maplist(char_utf8bytes, Cs, Bss),
append(Bss, Bs).
var(Cs), must_be(list, Bs) ->
once(phrase(decode_utf8(Cs), Bs))
; (must_be(list, Cs),
maplist(must_be(atom), Cs),
maplist(char_utf8bytes, Cs, Bss),
append(Bss, Bs)).
decode_utf8([]) --> [].
decode_utf8(Chars) --> leading(Nb, Code), continuation(Code, Chars, Nb).
leading(1, Byte) --> [Byte], {Byte /\ 0x80 =:= 0}.
leading(2, Code) --> [Byte], {Byte /\ 0xE0 =:= 0xC0, Code is Byte - 0xC0}.
leading(3, Code) --> [Byte], {Byte /\ 0xF0 =:= 0xE0, Code is Byte - 0xE0}.
leading(4, Code) --> [Byte], {Byte /\ 0xF8 =:= 0xF0, Code is Byte - 0xF0}.
leading(1, 0xFFFD) --> [_]. % invalid first byte
continuation(Code, [H|T], 1) --> {char_code(H, Code)}, decode_utf8(T).
continuation(Code, Chars, Nb) --> [Byte],
{Nb1 is Nb - 1, Byte /\ 0xC0 =:= 0x80, NextCode is (Code << 6) \/ (Byte - 0x80)},
continuation(NextCode, Chars, Nb1).
% invalid continuation byte
% each remaining continuation byte (if any) will raise 0xFFFD too
continuation(_, ['\xFFFD\'|T], _) --> [_], decode_utf8(T).
read_line_to_chars(Stream, Cs0, Cs) :-
'$get_n_chars'(Stream, 1, Char), % this also works for binary streams
( Char == [] -> Cs0 = Cs
; Char = [C],
Cs0 = [C|Rest],
( C == '\n' -> Rest = Cs
; read_line_to_chars(Stream, Rest, Cs)
)
).
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Relation between a list of characters Cs and its Base64 encoding Bs,
also a list of characters.
At least one of the arguments must be instantiated.
Options are:
- padding(Boolean)
Whether to use padding: true (the default) or false.
- charset(C)
Either 'standard' (RFC 4648 §4, the default) or 'url' (RFC 4648 §5).
Example:
?- chars_base64("hello", Bs, []).
Bs = "aGVsbG8="
; false.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
chars_base64(Cs, Bs, Options) :-
must_be(list, Options),
( member(O, Options), var(O) ->
instantiation_error(chars_base64/3)
; ( member(padding(Padding), Options) -> true
; Padding = true
),
( member(charset(Charset), Options) -> true
; Charset = standard
)
),
must_be(boolean, Padding),
must_be(atom, Charset),
( member(Charset, [standard,url]) -> true
; domain_error(charset, Charset, chars_base64/3)
),
( var(Cs) ->
must_be(list, Bs),
maplist(must_be(character), Bs),
'$chars_base64'(Cs, Bs, Padding, Charset)
; must_be(list, Cs),
maplist(must_be(character), Cs),
'$chars_base64'(Cs, Bs, Padding, Charset)
).

View File

@@ -29,6 +29,8 @@
ed25519_keypair_public_key/2, % +KeyPair, +PublicKey
ed25519_sign/4, % +KeyPair, +Data, -Signature, +Options
ed25519_verify/4, % +PublicKey, +Data, +Signature, +Options
curve25519_generator/1, % -Generator
curve25519_scalar_mult/3, % +Scalar, +Point, -Result
crypto_name_curve/2, % +Name, -Curve
crypto_curve_order/2, % +Curve, -Order
crypto_curve_generator/2, % +Curve, -Generator
@@ -43,6 +45,7 @@
:- use_module(library(arithmetic)).
:- use_module(library(format)).
:- use_module(library(charsio)).
:- use_module(library(si)).
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
hex_bytes(?Hex, ?Bytes) is det.
@@ -76,13 +79,13 @@ hex_bytes([]) --> [].
hex_bytes([H1,H2|Hs]) --> [Byte],
{ char_hexval(H1, High),
char_hexval(H2, Low),
Byte is High*16 + Low },
Byte #= High*16 + Low },
hex_bytes(Hs).
bytes_hex([]) --> [].
bytes_hex([B|Bs]) --> [C0,C1],
{ High is B>>4,
Low is B /\ 0xf,
{ High #= B>>4,
Low #= B /\ 0xf,
char_hexval(C0, High),
char_hexval(C1, Low)
},
@@ -101,6 +104,16 @@ must_be_bytes(Bytes, Context) :-
).
must_be_byte_chars(Chars, Context) :-
must_be(list, Chars),
( member(Char, Chars),
char_code(Char, Code),
\+ between(0, 255, Code) ->
domain_error(byte_char, Char, Context)
; true
).
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Cryptographically secure random numbers
=======================================
@@ -191,18 +204,18 @@ crypto_random_byte(B) :- '$crypto_random_byte'(B).
crypto_data_hash(Data0, Hash, Options0) :-
must_be(list, Options0),
options_data_bytes(Options0, Data0, Data),
options_data_chars(Options0, Data0, Data, Encoding),
functor_hash_options(algorithm, A, Options0, _),
( hash_algorithm(A) -> true
; domain_error(hash_algorithm, A, crypto_data_hash/3)
),
'$crypto_data_hash'(Data, HashBytes, A),
'$crypto_data_hash'(Data, Encoding, HashBytes, A),
hex_bytes(Hash, HashBytes).
options_data_bytes(Options, Data, Bytes) :-
options_data_chars(Options, Data, Chars, Encoding) :-
option(encoding(Encoding), Options, utf8),
must_be(atom, Encoding),
encoding_bytes(Encoding, Data, Bytes).
encoding_chars(Encoding, Data, Chars).
default_hash(sha256).
@@ -270,12 +283,12 @@ crypto_data_hkdf(Data0, L, Bytes, Options0) :-
),
must_be(integer, L),
L >= 0,
options_data_bytes(Options, Data0, Data),
options_data_chars(Options, Data0, Data, Encoding),
option(salt(SaltBytes), Options, []),
must_be_bytes(SaltBytes, crypto_data_hkdf/4),
option(info(Info0), Options, []),
chars_bytes_(Info0, Info, crypto_data_hkdf/4),
'$crypto_data_hkdf'(Data, SaltBytes, Info, Algorithm, L, Bytes).
'$crypto_data_hkdf'(Data, Encoding, SaltBytes, Info, Algorithm, L, Bytes).
hkdf_algorithm(sha256).
hkdf_algorithm(sha384).
@@ -416,61 +429,17 @@ crypto_password_hash(Password0, Hash, Options) :-
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Bidirectional Bytes <-> Base64 conversion
=========================================
This implements Base64 conversion *without padding*.
Bidirectional Bytes <-> Base64 conversion *without padding*.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
n_base64(0 , 'A'). n_base64(1 , 'B'). n_base64(2 , 'C'). n_base64(3 , 'D').
n_base64(4 , 'E'). n_base64(5 , 'F'). n_base64(6 , 'G'). n_base64(7 , 'H').
n_base64(8 , 'I'). n_base64(9 , 'J'). n_base64(10, 'K'). n_base64(11, 'L').
n_base64(12, 'M'). n_base64(13, 'N'). n_base64(14, 'O'). n_base64(15, 'P').
n_base64(16, 'Q'). n_base64(17, 'R'). n_base64(18, 'S'). n_base64(19, 'T').
n_base64(20, 'U'). n_base64(21, 'V'). n_base64(22, 'W'). n_base64(23, 'X').
n_base64(24, 'Y'). n_base64(25, 'Z'). n_base64(26, 'a'). n_base64(27, 'b').
n_base64(28, 'c'). n_base64(29, 'd'). n_base64(30, 'e'). n_base64(31, 'f').
n_base64(32, 'g'). n_base64(33, 'h'). n_base64(34, 'i'). n_base64(35, 'j').
n_base64(36, 'k'). n_base64(37, 'l'). n_base64(38, 'm'). n_base64(39, 'n').
n_base64(40, 'o'). n_base64(41, 'p'). n_base64(42, 'q'). n_base64(43, 'r').
n_base64(44, 's'). n_base64(45, 't'). n_base64(46, 'u'). n_base64(47, 'v').
n_base64(48, 'w'). n_base64(49, 'x'). n_base64(50, 'y'). n_base64(51, 'z').
n_base64(52, '0'). n_base64(53, '1'). n_base64(54, '2'). n_base64(55, '3').
n_base64(56, '4'). n_base64(57, '5'). n_base64(58, '6'). n_base64(59, '7').
n_base64(60, '8'). n_base64(61, '9'). n_base64(62, '+'). n_base64(63, '/').
bytes_base64(Ls, Bs) :-
( list(Bs), maplist(atom, Bs) ->
maplist(n_base64, Is, Bs),
phrase(bytes_base64_(Ls), Is),
Ls ins 0..255
; phrase(bytes_base64_(Ls), Is),
Is ins 0..63,
maplist(n_base64, Is, Bs)
bytes_base64(Bytes, Base64) :-
( var(Bytes) ->
chars_base64(Chars, Base64, [padding(false)]),
maplist(char_code, Chars, Bytes)
; maplist(char_code, Chars, Bytes),
chars_base64(Chars, Base64, [padding(false)])
).
list(Ls) :-
nonvar(Ls),
( Ls = [] -> true
; Ls = [_|Rest],
list(Rest)
).
bytes_base64_([]) --> [].
bytes_base64_([A]) --> [W,X],
{ A #= W*4 + X//16,
X #= 16*_ }.
bytes_base64_([A,B]) --> [W,X,Y],
{ A #= W*4 + X//16,
B #= (X mod 16)*16 + Y//4,
Y #= 4*_ }.
bytes_base64_([A,B,C|Ls]) --> [W,X,Y,Z],
{ A #= W*4 + X//16,
B #= (X mod 16)*16 + Y//4,
C #= (Y mod 4)*64 + Z },
bytes_base64_(Ls).
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
crypto_data_encrypt(+PlainText,
+Algorithm,
@@ -558,7 +527,7 @@ bytes_base64_([A,B,C|Ls]) --> [W,X,Y,Z],
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
crypto_data_encrypt(PlainText0, Algorithm, Key, IV, CipherText, Options) :-
options_data_bytes(Options, PlainText0, PlainText),
options_data_chars(Options, PlainText0, PlainText, Encoding),
option(tag(Tag), Options, _),
( nonvar(Tag) ->
must_be_bytes(Tag, crypto_data_encrypt/6)
@@ -570,7 +539,7 @@ crypto_data_encrypt(PlainText0, Algorithm, Key, IV, CipherText, Options) :-
( Algorithm = 'chacha20-poly1305' -> true
; domain_error('chacha20-poly1305', Algorithm, crypto_data_encrypt/6)
),
'$crypto_data_encrypt'(PlainText, Key, IV, Tag, CipherText).
'$crypto_data_encrypt'(PlainText, Encoding, Key, IV, Tag, CipherText).
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
crypto_data_decrypt(+CipherText,
@@ -610,26 +579,25 @@ crypto_data_decrypt(CipherText0, Algorithm, Key, IV, PlainText, Options) :-
must_be(atom, Encoding),
member(Encoding, [utf8,octet]),
must_be(list, CipherText0),
encoding_bytes(octet, CipherText0, CipherText1),
append(CipherText1, Tag, CipherText),
encoding_chars(octet, CipherText0, CipherText1),
maplist(char_code, TagChars, Tag),
append(CipherText1, TagChars, CipherText),
( Algorithm = 'chacha20-poly1305' -> true
; domain_error('chacha20-poly1305', Algorithm, crypto_data_decrypt/6)
),
'$crypto_data_decrypt'(CipherText, Key, IV, Encoding, PlainText).
'$crypto_data_decrypt'(CipherText, octet, Key, IV, Encoding, PlainText).
encoding_bytes(octet, Bs0, Bs) :-
must_be(list, Bs0),
( maplist(integer, Bs0) ->
Bs0 = Bs
; maplist(char_code, Bs0, Bs)
encoding_chars(octet, Bs, Cs) :-
must_be(list, Bs),
( maplist(integer, Bs) ->
maplist(char_code, Cs, Bs)
; Bs = Cs
),
must_be_bytes(Bs, crypto_encoding).
encoding_bytes(utf8, Cs, Bs) :-
must_be_byte_chars(Cs, crypto_encoding).
encoding_chars(utf8, Cs, Cs) :-
must_be(list, Cs),
( maplist(atom, Cs) ->
chars_bytes_(Cs, Bs, crypto_encoding)
; domain_error(encryption_encoding, Cs, crypto)
).
maplist(must_be(character), Cs).
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Digital signatures with Ed25519
@@ -667,60 +635,77 @@ encoding_bytes(utf8, Cs, Bs) :-
ed25519_new_keypair(Pair) :-
'$ed25519_new_keypair'(Pair).
ed25519_keypair_public_key(Pair0, PublicKey) :-
encoding_bytes(octet, Pair0, Pair),
'$ed25519_keypair_public_key'(Pair, PublicKey).
ed25519_keypair_public_key(Pair, PublicKey) :-
must_be_byte_chars(Pair, ed25519_keypair_public_key),
'$ed25519_keypair_public_key'(Pair, octet, PublicKey).
ed25519_sign(Key0, Data0, Signature, Options) :-
options_data_bytes(Options, Data0, Data),
encoding_bytes(octet, Key0, Key),
'$ed25519_sign'(Key, Data, Signature0),
ed25519_sign(Key, Data0, Signature, Options) :-
must_be_byte_chars(Key, ed25519_sign),
options_data_chars(Options, Data0, Data, Encoding),
'$ed25519_sign'(Key, octet, Data, Encoding, Signature0),
hex_bytes(Signature, Signature0).
ed25519_verify(Key0, Data0, Signature0, Options) :-
options_data_bytes(Options, Data0, Data),
encoding_bytes(octet, Key0, Key),
ed25519_verify(Key, Data0, Signature0, Options) :-
must_be_byte_chars(Key, ed25519_verify),
options_data_chars(Options, Data0, Data, Encoding),
hex_bytes(Signature0, Signature),
'$ed25519_verify'(Key, Data, Signature).
'$ed25519_verify'(Key, octet, Data, Encoding, Signature).
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Modular multiplicative inverse.
X25519: ECDH key exchange over Curve25519
=========================================
Compute Y = X^(-1) mod p, using the extended Euclidean algorithm.
Points on Curve25519 are represented as lists of characters that denote
the u-coordinate of the Montgomery curve.
- curve25519_generator(-Gs)
Gs is the generator point of Curve25519.
- curve25519_scalar_mult(+Scalar, +Ps, -Rs)
Scalar must be an integer between 0 and 2^256-1,
or a list of 32 bytes, and Ps must be a point on the curve.
Computes the point Rs = Scalar*Ps as mandated by X25519.
Alice and Bob can use this to establish a shared secret as follows,
where Gs is the generator point of Curve25519:
1. Alice creates a random integer a and sends As = a*Gs to Bob.
2. Bob creates a random integer b and sends Bs = b*Gs to Alice.
3. Alice computes Rs = a*Bs.
4. Bob computes Rs = b*As.
5. Alice and Bob use crypto_data_hkdf/4 on Rs with suitable
(same) parameters to obtain lists of bytes that can be used as
keys and initialization vectors for symmetric encryption.
If a and b are kept secret, this method is considered very secure.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
multiplicative_inverse_modulo_p(X, P, Y) :-
eea(X, P, _, _, Y),
R #= X*Y mod P,
zcompare(C, 1, R),
must_be_one(C, X, P, Y).
curve25519_generator(Gs) :-
length(Gs0, 32),
Gs0 = [9|Zs],
maplist(=(0), Zs),
maplist(char_code, Gs, Gs0).
must_be_one(=, _, _, _).
must_be_one(>, X, P, Y) :- throw(multiplicative_inverse_modulo_p(X,P,Y)).
must_be_one(<, X, P, Y) :- throw(multiplicative_inverse_modulo_p(X,P,Y)).
curve25519_scalar_mult(Scalar, Point, Result) :-
( integer_si(Scalar) ->
Scalar #>= 0,
Scalar #< 2^256,
length(ScalarBytes, 32),
bytes_integer(ScalarBytes, Scalar)
; ScalarBytes = Scalar,
must_be_bytes(ScalarBytes, curve25519_scalar_mult/3),
length(ScalarBytes, 32)
),
maplist(char_code, Point, PointBytes),
'$curve25519_scalar_mult'(ScalarBytes, PointBytes, Result).
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Extended Euclidean algorithm.
Computes the GCD and the Bézout coefficients S and T.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
eea(I, J, G, S, T) :-
State0 = state(1,0,0,1),
eea_loop(I, J, State0, G, S, T).
eea_loop(I, J, State0, G, S, T) :-
zcompare(C, 0, J),
eea_(C, I, J, State0, G, S, T).
eea_(=, I, _, state(_,_,U,V), I, U, V).
eea_(<, I0, J0, state(S0,T0,U0,V0), I, U, V) :-
Q #= I0 // J0,
R #= I0 mod J0,
S1 #= U0 - (Q*S0),
T1 #= V0 - (Q*T0),
eea_loop(J0, R, state(S1,T1,S0,T0), I, U, V).
bytes_integer(Bs, N) :-
foldl(pow, Bs, 0-0, N-_).
pow(B, N0-I0, N-I) :-
B in 0..255,
N #= N0 + B*256^I0,
I #= I0 + 1.
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Operations on Elliptic Curves
@@ -728,7 +713,7 @@ eea_(<, I0, J0, state(S0,T0,U0,V0), I, U, V) :-
Sample use: Establishing a shared secret S, using ECDH key exchange.
?- crypto_name_curve(Name, C),
?- crypto_name_curve(secp256k1, C),
crypto_curve_generator(C, Generator),
PrivateKey = 10,
crypto_curve_scalar_mult(C, PrivateKey, Generator, PublicKey),
@@ -737,95 +722,44 @@ eea_(<, I0, J0, state(S0,T0,U0,V0), I, U, V) :-
crypto_curve_scalar_mult(C, Random, PublicKey, S),
crypto_curve_scalar_mult(C, PrivateKey, R, S).
For better security, new code should use Curve25519 instead.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
An elliptic curve over a prime field F_p is represented as:
curve(P,A,B,point(X,Y),Order,Cofactor).
curve(Name,P,A,B,point(X,Y),Order,FieldLength,Cofactor).
First, we define suitable accessors.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
curve_p(curve(P,_,_,_,_,_), P).
curve_a(curve(_,A,_,_,_,_), A).
curve_b(curve(_,_,B,_,_,_), B).
curve_name(curve(Name,_,_,_,_,_,_,_), Name).
curve_p(curve(_,P,_,_,_,_,_,_), P).
curve_a(curve(_,_,A,_,_,_,_,_), A).
curve_b(curve(_,_,_,B,_,_,_,_), B).
curve_field_length(curve(_,_,_,_,_,_,FieldLength,_), FieldLength).
crypto_curve_order(curve(_,_,_,_,Order,_), Order).
crypto_curve_generator(curve(_,_,_,G,_,_), G).
crypto_curve_generator(curve(_,_,_,_,G,_,_,_), G).
crypto_curve_order(curve(_,_,_,_,_,Order,_,_), Order).
crypto_curve_scalar_mult(Curve, Scalar, point(X,Y), point(RX, RY)) :-
must_be(integer, Scalar),
must_be_on_curve(Curve, point(X,Y)),
curve_name(Curve, Name),
curve_field_length(Curve, L0),
L #= 2*L0, % for hex encoding
phrase(format_("04~|~`0t~16r~*+~`0t~16r~*+", [X,L,Y,L]), Hex),
hex_bytes(Hex, Bytes),
'$crypto_curve_scalar_mult'(Name, Scalar, Bytes, SX, SY),
number_chars(RX, SX),
number_chars(RY, SY).
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Scalar point multiplication.
R = k*Q.
The Montgomery ladder method is used to mitigate side-channel
attacks such as timing attacks, since the number of multiplications
and additions is independent of the private key K. This method does
not even reveal the key's Hamming weight (number of 1s).
?- crypto_name_curve(secp256k1, Curve),
crypto_curve_generator(Curve, G),
crypto_curve_scalar_mult(Curve, 2, G, R).
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
crypto_curve_scalar_mult(Curve, K, Q, R) :-
msb(K, Upper),
scalar_multiplication(Curve, K, Upper, ml(null,Q)-R),
must_be_on_curve(Curve, R).
scalar_multiplication(Curve, K, I, R0-R) :-
zcompare(C, -1, I),
scalar_mult_(C, Curve, K, I, R0-R).
scalar_mult_(=, _, _, _, ml(R,_)-R).
scalar_mult_(<, Curve, K, I0, ML0-R) :-
BitSet #= K /\ (1 << I0),
zcompare(C, 0, BitSet),
montgomery_step(C, Curve, ML0, ML1),
I1 #= I0 - 1,
scalar_multiplication(Curve, K, I1, ML1-R).
montgomery_step(=, Curve, ml(R0,S0), ml(R,S)) :-
curve_points_addition(Curve, R0, S0, S),
curve_point_double(Curve, R0, R).
montgomery_step(<, Curve, ml(R0,S0), ml(R,S)) :-
curve_points_addition(Curve, R0, S0, R),
curve_point_double(Curve, S0, S).
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Doubling a point: R = A + A.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
curve_point_double(_, null, null).
curve_point_double(Curve, point(AX,AY), R) :-
curve_p(Curve, P),
curve_a(Curve, A),
Numerator #= (3*AX^2 + A) mod P,
Denom0 #= 2*AY mod P,
multiplicative_inverse_modulo_p(Denom0, P, Denom),
S #= (Numerator*Denom) mod P,
R = point(RX,RY),
RX #= (S^2 - 2*AX) mod P,
RY #= (S*(AX - RX) - AY) mod P,
must_be_on_curve(Curve, R).
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Adding two points.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
curve_points_addition(Curve, P, Q, R) :-
curve_points_addition_(P, Curve, Q, R).
curve_points_addition_(null, _, P, P).
curve_points_addition_(P, _, null, P).
curve_points_addition_(point(AX,AY), Curve, point(BX,BY), R) :-
curve_p(Curve, P),
Numerator #= (AY - BY) mod P,
Denom0 #= (AX - BX) mod P,
multiplicative_inverse_modulo_p(Denom0, P, Denom),
S #= (Numerator * Denom) mod P,
R = point(RX,RY),
RX #= (S^2 - AX - BX) mod P,
RY #= (S*(AX - RX) - AY) mod P,
must_be_on_curve(Curve, R).
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Validation.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
@@ -838,7 +772,7 @@ curve_contains_point(Curve, point(QX,QY)) :-
must_be_on_curve(Curve, P) :-
\+ curve_contains_point(Curve, P),
throw(not_on_curve(P)).
domain_error(point_on_curve, P, crypto_elliptic_curves).
must_be_on_curve(Curve, P) :- curve_contains_point(Curve, P).
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@@ -855,21 +789,38 @@ must_be_on_curve(Curve, P) :- curve_contains_point(Curve, P).
-text -no_seed -name secp256k1
You must remove the leading "04:" from the generator.
The field length depends on the order of the curve and can be computed
with order_field_length/2.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
order_field_length(Order, L) :-
fitting_exponent(Order, 0, E),
L #= (E + 7) // 8.
fitting_exponent(N, E0, E) :-
( 2^E0 #>= N -> E #= E0
; E1 #= E0 + 1,
fitting_exponent(N, E1, E)
).
crypto_name_curve(secp112r1,
curve(0x00db7c2abf62e35e668076bead208b,
curve(secp112r1,
0x00db7c2abf62e35e668076bead208b,
0x00db7c2abf62e35e668076bead2088,
0x659ef8ba043916eede8911702b22,
point(0x09487239995a5ee76b55f9c2f098,
0xa89ce5af8724c0a23e0e0ff77500),
0x00db7c2abf62e35e7628dfac6561c5,
14,
1)).
crypto_name_curve(secp256k1,
curve(0x00fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f,
curve(secp256k1,
0x00fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f,
0x0,
0x7,
point(0x79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798,
0x483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8),
0x00fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141,
32,
1)).

238
src/lib/csv.pl Normal file
View File

@@ -0,0 +1,238 @@
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Predicates for parsing CSV data
Read csv files
Only two options with default values :
- token_separator(',')
- with_header(true)
Examples
* parsing a csv string:
?- use_module(library(csv)).
?- use_module(library(dcgs)).
?- phrase(parse_csv(Data), "col1,col2,col3,col4\none,2,,three").
Data = frame(["col1","col2","col3","col4"],[["one",2,[],"three"]]).
* with some options:
?- phrase(parse_csv(Data, [with_header(false), token_separator(';')]), "one;2;;three").
Data = frame([],[["one",2,[],"three"]]).
* parsing a csv file:
?- use_module(library(csv)).
?- use_module(library(pio)).
?- phrase_from_file(parse_csv(frame(Header, Rows)), './test.csv').
Write csv files
Four options with default values :
- line_separator('\n')
- token_separator(',')
- with_header(true)
- null_value(empty)
Examples
* writing a csv file:
?- use_module(library(csv)).
?- write_csv('./test.csv', frame(["col1","col2","col3","col4"], [["one",2,[],"three"]])).
* with some options
?- use_module(library(csv)).
?- write_csv('./test.csv', frame(["col1","col2","col3","col4"], [["one",2,[],"three"]]), [with_header(false), line_separator('\r\n'), token_separator(';'), null_value('\\N')]).
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
:- module(csv, [
parse_csv//1,
parse_csv//2,
write_csv/2,
write_csv/3
]).
:- use_module(library(format)).
:- use_module(library(dcgs)).
:- use_module(library(iso_ext)).
:- use_module(library(lists)).
option(W, O) :-
( member(W, O) -> true
; throw(error(domain_error(csv_option, W), option/2))).
option_extends([], Opt, Opt).
option_extends([X | Y], Opt0, Opt) :-
functor(X, Name, 1),
F0 =.. [Name, _],
( select(F0, Opt0, R) ->
option_extends(Y, [X | R], Opt)
; option_extends(Y, [X | Opt0], Opt) ).
%% -- write --
escaped_field([], []).
escaped_field(['"' | Y], ['"', '"' | R]) :-
escaped_field(Y, R).
escaped_field([X | Y], [X | R]) :-
X \== '"',
escaped_field(Y, R).
ensure_escaped(Field, Field) :-
(atom(Field); integer(Field); float(Field)).
ensure_escaped([X | Y], Field) :-
escaped_field([X | Y], Field).
write_field(Out, Field, Opt) :-
( Field \== [] ->
ensure_escaped(Field, Field0),
format(Out, "~w", [Field0])
; option(null_value(Null_Value), Opt),
( Null_Value == empty -> true
; format(Out, "~w", [Null_Value]))).
write_row(Out, [Field], Opt) :-
write_field(Out, Field, Opt).
write_row(Out, [Field, X | Y], Opt) :-
write_field(Out, Field, Opt),
option(token_separator(Tk_Sep), Opt),
format(Out, "~w", [Tk_Sep]),
write_row(Out, [X | Y], Opt).
write_rows(Out, [Row], Opt) :-
write_row(Out, Row, Opt).
write_rows(Out, [Row, X | Y], Opt) :-
option(line_separator(Line_Sep), Opt),
write_row(Out, Row, Opt),
format(Out, "~w", [Line_Sep]),
write_rows(Out, [X | Y], Opt).
write_csv_(Out, frame(Header, Rows), Opt) :-
option(with_header(With_Header), Opt),
( With_Header == true ->
write_row(Out, Header, Opt),
option(line_separator(Line_Sep), Opt),
format(Out, "~w", [Line_Sep])
; true),
write_rows(Out, Rows, Opt).
write_csv(File_Name, Frm, Opt) :-
option_extends(Opt, [
null_value(empty),
token_separator(','),
with_header(true),
line_separator('\n')
], Opt0),
setup_call_cleanup(
open(File_Name, write, Out),
write_csv_(Out, Frm, Opt0),
close(Out)).
write_csv(File_Name, Frm) :-
write_csv(File_Name, Frm, []).
%% -- read --
tokens([], Opt), [Tk_Sep] -->
{ option(token_separator(Tk_Sep), Opt) },
[Tk_Sep],
!.
tokens([], _), "\r\n" -->
"\r\n",
!.
tokens([], _), "\n" -->
"\n",
!.
tokens([], _), "\r" -->
"\r",
!.
tokens([X | Y], Opt) -->
[X],
!,
tokens(Y, Opt).
tokens([], _) --> [].
field(R, Opt) -->
"\"",
!,
string_tokens(R, Opt).
field(R, Opt) -->
tokens(R0, Opt),
{ R0 \== [],
catch(number_chars(R, R0), _, R = R0)
}.
field([], _) --> [].
string_tokens(R, Opt) -->
[X],
( { X == '"' } ->
( "\"" ->
{ R = [X | Y] },
string_tokens(Y, Opt)
; { R = [] })
; { R = [X | Y] },
string_tokens(Y, Opt)).
end_token --> "\r\n".
end_token --> "\n".
end_token --> "\r".
end_token --> [].
separator(Opt) -->
{ option(token_separator(Tk_Sep), Opt) },
[Tk_Sep].
row([X | Y], Opt) -->
field(X, Opt),
!,
( separator(Opt) ->
row(Y, Opt)
; end_token ->
{ Y = [] }).
rows(R, Opt) -->
row(X, Opt),
!,
( { X \== [[]] } ->
rows(Y, Opt),
{ R = [X | Y] }
; { R = [] }).
parse_csv(frame(Header, Rows), Opt) -->
{ option_extends(Opt, [
with_header(true),
token_separator(',')
], Opt0)
},
( { option(with_header(With_Header), Opt0),
With_Header == true } ->
row(Header, Opt0),
{ Header \== [[]] },
end_token
; { Header = [] }),
rows(Rows, Opt0).
parse_csv(R) -->
parse_csv(R, []).

View File

@@ -1,7 +1,7 @@
:- module(dcgs, [op(1200, xfx, -->),
op(1105, xfy, '|'),
phrase/2,
phrase/3]).
:- module(dcgs,
[op(1105, xfy, '|'),
phrase/2,
phrase/3]).
:- use_module(library(error)).
:- use_module(library(lists), [append/3]).

22
src/lib/debug.pl Normal file
View File

@@ -0,0 +1,22 @@
% Source: https://stackoverflow.com/a/30791637
:- module(debug, [
op(900, fx, $),
op(900, fx, $-),
op(950, fy, *),
(*)/1,
($)/1,
($-)/1
]).
:- use_module(library(format), [portray_clause/1]).
$-(G_0) :-
catch(G_0, Ex, ( portray_clause(exception:Ex:G_0), throw(Ex) ) ).
$(G_0) :-
portray_clause(call:G_0),
$-G_0,
portray_clause(exit:G_0).
*(_).

View File

@@ -27,7 +27,8 @@
- integer
- atom
- list.
- list
- boolean
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
must_be(Type, Term) :-
@@ -43,8 +44,10 @@ must_be_(var, Term) :-
).
must_be_(integer, Term) :- check_(integer, integer, Term).
must_be_(atom, Term) :- check_(atom, atom, Term).
must_be_(character, T) :- check_(character, character, T).
must_be_(list, Term) :- check_(ilist, list, Term).
must_be_(type, Term) :- check_(type, type, Term).
must_be_(boolean, Term) :- check_(boolean, boolean, Term).
check_(Pred, Type, Term) :-
( var(Term) -> instantiation_error(must_be/2)
@@ -52,6 +55,12 @@ check_(Pred, Type, Term) :-
; type_error(Type, Term, must_be/2)
).
boolean(B) :- ( B == true ; B == false ).
character(C) :-
atom(C),
atom_length(C, 1).
ilist(V) :- var(V), instantiation_error(must_be/2).
ilist([]).
ilist([_|Ls]) :- ilist(Ls).
@@ -59,8 +68,10 @@ ilist([_|Ls]) :- ilist(Ls).
type(type).
type(integer).
type(atom).
type(character).
type(list).
type(var).
type(boolean).
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
can_be(Type, Term)
@@ -85,7 +96,9 @@ can_be(Type, Term) :-
can_(integer, Term) :- integer(Term).
can_(atom, Term) :- atom(Term).
can_(character, T) :- character(T).
can_(list, Term) :- list_or_partial_list(Term).
can_(boolean, Term) :- boolean(Term).
list_or_partial_list(Var) :- var(Var).
list_or_partial_list([]).

200
src/lib/files.pl Normal file
View File

@@ -0,0 +1,200 @@
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Written June 2020 by Markus Triska (triska@metalevel.at)
Part of Scryer Prolog.
Predicates for reasoning about files and directories.
In this library, directories and files are represented as
*lists of characters*. This is an ideal representation:
-) Lists of characters can be conveniently reasoned about with DCGs
and built-in Prolog predicates from library(lists). This alone
is already a very compelling argument to use them.
-) Other Scryer libraries such as library(http/http_open) also already
use lists of characters to represent paths.
-) File names are mostly ephemeral, so it is good for efficiency
that they can quickly allocated transiently on the heap, leaving the
atom table mostly unaffected. Indexing is almost never needed
for file names. If needed, it should be added to the engine.
-) The previous point is also good for security, since the system
leaves little trace of which files were even accessed.
-) Scryer Prolog represents lists of characters extremely compactly.
Some Prolog programmers will likely find this representation quite
unusual, because files are represented as *atoms* in many systems.
However, the ISO standard only demands that sources and sinks be
*ground* terms, so lists of characters are completely admissible:
A source/sink is specified as an implementation defined
ground term in a call of open/4 (8.11.5). All subsequent
references to the source/sink are made by referring to a
stream-term (7.10.2) or alias (7.10.2.2).
I believe that with the advent of Scryer Prolog and its efficient
representation of strings as lists of characters, we should take
this opportunity for improvement, and in fact extend the use of
lists of characters also to other predicates like open/3.
Please note that we *cannot* simply accept *both* representations,
because that would invalidate the type errors raised by this library,
and make future extensions for type checking impossible.
So I ask you: Please try out this representation for a few months.
It simplifies working with files considerably. Once we have collected
more experience with this representations, please let us consider
how to proceed in such a way that we can call it an improvement.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
:- module(files, [directory_files/2,
file_size/2,
file_exists/1,
directory_exists/1,
delete_file/1,
make_directory/1,
working_directory/2,
path_canonical/2,
path_segments/2,
file_modification_time/2,
file_creation_time/2,
file_access_time/2]).
:- use_module(library(error)).
:- use_module(library(lists)).
:- use_module(library(charsio)).
list_of_chars(Cs) :-
must_be(list, Cs),
maplist(must_be(character), Cs).
directory_files(Directory, Files) :-
list_of_chars(Directory),
can_be(list, Files),
'$directory_files'(Directory, Files).
file_size(File, Size) :-
list_of_chars(File),
can_be(integer, Size),
'$file_size'(File, Size).
file_exists(File) :-
list_of_chars(File),
'$file_exists'(File).
directory_exists(Directory) :-
list_of_chars(Directory),
'$directory_exists'(Directory).
make_directory(Directory) :-
list_of_chars(Directory),
'$make_directory'(Directory).
delete_file(File) :-
list_of_chars(File),
'$delete_file'(File).
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Dir0 is the current working directory, and the working directory
is changed to Dir.
Use working_directory(Ds, Ds) to determine the current working directory,
and leave it as is.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
working_directory(Dir0, Dir) :-
can_be(list, Dir0),
can_be(list, Dir),
'$working_directory'(Dir0, Dir).
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
True iff Cs is the canonical, absolute path of Ps.
All intermediate components are normalized, and all symbolic links
are resolved.
The predicate fails in the following situations, though not
necessarily *only* in these cases:
1. Ps is a path that does not exist.
2. A non-final component in Ps is not a directory.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
path_canonical(Ps, Cs) :-
must_be(list, Ps),
maplist(must_be(character), Ps),
can_be(list, Cs),
'$path_canonical'(Ps, Cs).
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
T is, respectively, the modification, access or creation time of File.
T is a time stamp, suitable for use in format_time//2 in library(time).
For two time stamps A and B, if A precedes B, then A @< B holds.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
file_modification_time(File, T) :-
file_time_(File, modification, T).
file_access_time(File, T) :-
file_time_(File, access, T).
file_creation_time(File, T) :-
file_time_(File, creation, T).
file_time_(File, Which, T) :-
'$file_time'(File, Which, T0),
read_term_from_chars(T0, T).
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
path_segments(Ps, Segments): True iff Segments are the segments of Ps.
Segments is the list of components of the path Ps that are
separated by the platform-specific directory separator. Each
segment is a list of characters.
At least one of the arguments must be instantiated.
Examples:
?- path_segments("/hello/there", Segments).
Segments = [[],"hello","there"]
; false.
?- path_segments(Path, ["hello","there"]).
Path = "hello/there"
; false.
To obtain the platform-specific directory separator, you can use:
?- path_segments(Separator, ["",""]).
Separator = "/"
; false.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
path_segments(Path, Segments) :-
'$directory_separator'(Sep),
( var(Path) ->
must_be(list, Segments),
maplist(list_of_chars, Segments),
append_with_separator(Segments, Sep, Path)
; list_of_chars(Path),
path_to_segments(Path, Sep, Segments)
).
append_with_separator([], _, []).
append_with_separator([Segment|Segments], Sep, Path) :-
append_with_separator_(Segments, Segment, Sep, Path).
append_with_separator_([], Segment, _, Segment).
append_with_separator_([Segment|Segments], Prev, Sep, Path) :-
append(Prev, [Sep|Rest], Path),
append_with_separator_(Segments, Segment, Sep, Rest).
path_to_segments(Path, Sep, Segments) :-
( append(Front, [Sep|Ps], Path) ->
Segments = [Front|Rest],
path_to_segments(Ps, Sep, Rest)
; Segments = [Path]
).

View File

@@ -3,7 +3,7 @@
Part of Scryer Prolog.
This library provides the nonterminal format_//2 to describe
formatted strings. format/2 is provided for impure output.
formatted strings. format/[2,3] are provided for impure output.
Usage:
======
@@ -74,6 +74,7 @@
format/2,
format/3,
portray_clause/1,
portray_clause/2,
listing/1
]).
@@ -158,7 +159,7 @@ element_gluevar(glue(_,V), N, N) --> [V].
cells([], Args, Tab, Es) -->
( { Args == [] } -> cell(Tab, Tab, Es)
; { domain_error(no_remaining_arguments, Args, format_//2) }
; { domain_error(empty_list, Args, format_//2) }
).
cells([~,~|Fs], Args, Tab, Es) --> !,
cells(Fs, Args, Tab, [chars("~")|Es]).
@@ -172,9 +173,11 @@ cells([~,a|Fs], [Arg|Args], Tab, Es) --> !,
{ atom_chars(Arg, Chars) },
cells(Fs, Args, Tab, [chars(Chars)|Es]).
cells([~|Fs0], Args0, Tab, Es) -->
{ numeric_argument(Fs0, Num, [d|Fs], Args0, [Arg|Args]) },
{ numeric_argument(Fs0, Num, [d|Fs], Args0, [Arg0|Args]) },
!,
{ number_chars(Arg, Cs0) },
{ Arg is Arg0, % evaluate compound expression
must_be(integer, Arg),
number_chars(Arg, Cs0) },
( { Num =:= 0 } -> { Cs = Cs0 }
; { length(Cs0, L),
( L =< Num ->
@@ -216,12 +219,12 @@ cells([~|Fs0], Args0, Tab, Es) -->
cells([~,s|Fs], [Arg|Args], Tab, Es) --> !,
cells(Fs, Args, Tab, [chars(Arg)|Es]).
cells([~,f|Fs], [Arg|Args], Tab, Es) --> !,
{ number_chars(Arg, Chars) },
{ format_number_chars(Arg, Chars) },
cells(Fs, Args, Tab, [chars(Chars)|Es]).
cells([~|Fs0], Args0, Tab, Es) -->
{ numeric_argument(Fs0, Num, [f|Fs], Args0, [Arg|Args]) },
!,
{ number_chars(Arg, Cs0),
{ format_number_chars(Arg, Cs0),
phrase(upto_what(Bs, .), Cs0, Cs),
( Num =:= 0 -> Chars = Bs
; ( Cs = ['.'|Rest] ->
@@ -279,6 +282,10 @@ cells(Fs0, Args, Tab, Es) -->
Fs1 = [_|_] },
cells(Fs, Args, Tab, [chars(Fs1)|Es]).
format_number_chars(N0, Chars) :-
N is N0, % evaluate compound expression
number_chars(N, Chars).
n_newlines(0) --> !.
n_newlines(N0) --> { N0 > 0, N is N0 - 1 }, [newline], n_newlines(N).
@@ -327,7 +334,8 @@ pow10(D, N0-Pow0, N-Pow) :-
N is N0 + D*10^Pow0,
Pow is Pow0 + 1.
integer_to_radix(I, R, Which, Cs) :-
integer_to_radix(I0, R, Which, Cs) :-
I is I0, % evaluate compound expression
must_be(integer, I),
must_be(integer, R),
( \+ between(2, 36, R) ->
@@ -361,28 +369,16 @@ digits(uppercase, "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ").
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
format(Fs, Args) :-
phrase(format_(Fs, Args), Cs),
maplist(write, Cs).
current_output(Stream),
format(Stream, Fs, Args).
format(Stream, Fs, Args) :-
phrase(format_(Fs, Args), Cs),
( stream_property(Stream, type(binary)) ->
% maplist(char_code, Cs, Bytes) is currently a lot slower
% than first converting Cs to an atom, and then to codes.
% In the future, we can ideally avoid creating an atom here,
% since an atom leaves traces in the system.
atom_chars(A, Cs),
atom_codes(A, Bytes),
( member(NonByte, Bytes), NonByte > 255 ->
char_code(Char, NonByte),
throw(error(representation_error(Char), format/3))
; true
),
% For binary streams, we use a specialised internal predicate
% that uses only a single "write" operation for efficiency.
'$put_bytes'(Stream, Bytes)
; maplist(put_char(Stream), Cs)
).
% we use a specialised internal predicate that uses only a
% single "write" operation for efficiency. It is equivalent to
% maplist(put_char(Stream), Cs). It also works for binary streams.
'$put_chars'(Stream, Cs),
flush_output(Stream).
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
?- phrase(cells("hello", [], 0, []), Cs).
@@ -458,8 +454,12 @@ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
portray_clause(Term) :-
current_output(Out),
portray_clause(Out, Term).
portray_clause(Stream, Term) :-
phrase(portray_clause_(Term), Ls),
maplist(write, Ls).
format(Stream, "~s", [Ls]).
portray_clause_(Term) -->
{ term_variables(Term, Vs),

84
src/lib/http/http_open.pl Normal file
View File

@@ -0,0 +1,84 @@
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Written June 2020 by Markus Triska (triska@metalevel.at)
Part of Scryer Prolog.
http_open(+Address, -Stream, +Options)
======================================
Yields Stream to read the body of an HTTP reply from Address.
Address is a list of characters, and includes the method. Both HTTP
and HTTPS are supported. Redirects are followed.
Currently, Options must be the empty list. Options may be
added in the future to give more control over the connection.
We use HTTP/1.0 until we can read chunked transfer-encoding.
Example:
?- http_open("https://github.com/mthom/scryer-prolog", S, []).
%@ S = '$stream'(0x7f86f94a6cd0)
%@ ; false.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
:- module(http_open, [http_open/3]).
:- use_module(library(sockets)).
:- use_module(library(error)).
:- use_module(library(format)).
:- use_module(library(charsio)).
:- use_module(library(dcgs)).
:- use_module(library(lists), [member/2]).
http_open(Address, Stream, Options) :-
must_be(list, Options),
must_be(list, Address),
once(phrase((list(SchemeCs), "://", list(Rest)), Address)),
atom_chars(Scheme, SchemeCs),
chars_host_url(Rest, Host, URL),
connect(Scheme, Host, Stream0),
format(Stream0, "\
GET ~s HTTP/1.0\r\n\
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).
list([]) --> [].
list([L|Ls]) --> [L], list(Ls).
handle_response('2', _, Stream, Stream). % ok
handle_response('3', HeaderLines, Stream0, Stream) :- % redirect
close(Stream0),
once((member(Line, HeaderLines),
phrase(("Location: ",list(Location),"\r\n"), Line))),
http_open(Location, Stream, []).
% Status-Line = HTTP-Version SP Status-Code SP Reason-Phrase CRLF
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)
).
chars_host_url(Cs, Host, [/|Us]) :-
( phrase((list(Hs),"/",list(Us)), Cs) ->
true
; Hs = Cs,
Us = []
),
atom_chars(Host, Hs).
connect(https, Host, Stream) :-
socket_client_open(Host:443, Stream, [tls(true)]).
connect(http, Host, Stream) :-
socket_client_open(Host:80, Stream, []).

58
src/lib/os.pl Normal file
View File

@@ -0,0 +1,58 @@
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Predicates for reasoning about the operating system (OS) environment.
Written July 2020 by Markus Triska (triska@metalevel.at).
Lists of characters are used throughout to represent keys and values.
Example:
?- getenv("LANG", Ls).
Ls = "en_US.UTF-8"
; false.
Public domain code.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
:- module(os, [getenv/2,
setenv/2,
unsetenv/1]).
:- use_module(library(error)).
:- use_module(library(charsio)).
:- use_module(library(lists)).
getenv(Key, Value) :-
must_be_env_var(Key),
'$getenv'(Key, Value).
setenv(Key, Value) :-
must_be_env_var(Key),
must_be_chars(Value),
'$setenv'(Key, Value).
unsetenv(Key) :-
must_be_env_var(Key),
'$unsetenv'(Key).
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
For now, we only support a restricted subset of variable names.
The reason is that Rust may panic if a key is empty, contains an
ASCII equals sign '=' or the NUL character '\0', or when the value
contains the NUL character.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
must_be_env_var(Cs) :-
must_be_chars(Cs),
Cs = [_|_],
( maplist(permitted, Cs) -> true
; domain_error(env_var, Cs, os)
).
permitted(C) :- char_type(C, alnum).
permitted(C) :- char_type(C, ascii_punctuation).
permitted('_').
must_be_chars(Cs) :-
must_be(list, Cs),
maplist(must_be(character), Cs).

42
src/lib/pio.pl Normal file
View File

@@ -0,0 +1,42 @@
:- module(pio, [phrase_from_file/2,
phrase_from_file/3]).
:- use_module(library(dcgs)).
:- use_module(library(error)).
:- use_module(library(freeze)).
:- use_module(library(iso_ext), [setup_call_cleanup/3, partial_string/3]).
:- use_module(library(lists), [member/2]).
phrase_from_file(NT, File) :-
phrase_from_file(NT, File, []).
phrase_from_file(NT, File, Options) :-
( var(File) -> instantiation_error(phrase_from_file/3)
; (\+ atom(File) ; File = []) ->
domain_error(source_sink, File, phrase_from_file/3)
; must_be(list, Options),
( member(Var, Options), var(Var) -> instantiation_error(phrase_from_file/3)
; member(type(Type), Options) ->
must_be(atom, Type),
member(Type, [text,binary])
; Type = text
),
setup_call_cleanup(open(File, read, Stream, [reposition(true)|Options]),
( stream_to_lazy_list(Stream, Xs),
phrase(NT, Xs) ),
close(Stream))
).
stream_to_lazy_list(Stream, Xs) :-
stream_property(Stream, position(Pos)),
freeze(Xs, reader_step(Stream, Pos, Xs)).
reader_step(Stream, Pos, Xs0) :-
set_stream_position(Stream, Pos),
( at_end_of_stream(Stream)
-> Xs0 = []
; '$get_n_chars'(Stream, 4096, Cs),
partial_string(Cs, Xs0, Xs),
stream_to_lazy_list(Stream, Xs)
).

92
src/lib/sgml.pl Normal file
View File

@@ -0,0 +1,92 @@
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Predicates for parsing HTML and XML documents.
Written June 2020 by Markus Triska (triska@metalevel.at)
Part of Scryer Prolog.
Currently, two predicates are provided:
- load_html(+Source, -Es, +Options)
- load_xml(+Source, -Es, +Options)
These predicates parse HTML and XML documents, respectively.
Source must be a stream, specified as stream(S), or a file,
specified as file(Name), where Name is a list of characters, or a
list of characters with the document contents.
Es is unified with the abstract syntax tree of the parsed document,
represented as a list of elements where each is of the form:
* a list of characters, representing text
* element(Name, Attrs, Children)
- Name is the name of the tag
- Attrs is a list of Key=Value pairs:
Key is an atom, and Value is a list of characters
- Children is a list of elements as specified here.
Currently, Options are ignored. In the future, more options may be
provided to control parsing.
Example:
?- load_html("<html><head><title>Hello!</title></head></html>", Es, []).
Yielding:
Es = [element(html,[],
[element(head,[],
[element(title,[],
["Hello!"])]),
element(body,[],[])])].
library(xpath) provides convenient reasoning about parsed documents.
For example, to fetch the title of the document above, we can use:
?- load_html("<html><head><title>Hello!</title></head></html>", Es, []),
xpath(Es, //title(text), T).
Yielding T = "Hello!".
Use http_open/3 from library(http/http_open) to read answers from
web servers via streams.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
:- module(sgml, [load_html/3,
load_xml/3]).
:- use_module(library(iso_ext)).
:- use_module(library(error)).
:- use_module(library(dcgs)).
:- use_module(library(pio)).
load_html(Source, Es, Options) :-
load_structure_(Source, Es, Options, html).
load_xml(Source, Es, Options) :-
load_structure_(Source, Es, Options, xml).
list([]) --> [].
list([L|Ls]) --> [L], list(Ls).
load_structure_([], [], _, _).
load_structure_([C|Cs], [E], Options, What) :-
load_(What, [C|Cs], E, Options).
load_structure_(file(Fs), [E], Options, What) :-
must_be(list, Options),
must_be(list, Fs),
atom_chars(File, Fs),
once(phrase_from_file(list(Cs), File)),
load_(What, Cs, E, Options).
load_structure_(stream(Stream), [E], Options, What) :-
must_be(list, Options),
read_to_end(Stream, Cs),
load_(What, Cs, E, Options).
load_(html, Cs, E, Options) :- '$load_html'(Cs, E, Options).
load_(xml, Cs, E, Options) :- '$load_xml'(Cs, E, Options).
read_to_end(Stream, Cs) :-
'$get_n_chars'(Stream, 4096, Cs0),
( Cs0 = [] -> Cs = []
; partial_string(Cs0, Cs, Rest),
read_to_end(Stream, Rest)
).

View File

@@ -6,7 +6,16 @@
current_hostname/1]).
:- use_module(library(error)).
:- use_module(library(lists)).
parse_socket_options_(tls(TLS), tls-TLS) :-
must_be(boolean, TLS), !.
parse_socket_options_(Option, OptionPair) :-
builtins:parse_stream_options_(Option, OptionPair).
parse_socket_options(Options, OptionValues, Stub) :-
DefaultOptions = [alias-[], eof_action-eof_code, reposition-false, tls-false, type-text],
builtins:parse_options_list(Options, parse_socket_options_, DefaultOptions, OptionValues, Stub).
socket_client_open(Addr, Stream, Options) :-
( var(Addr) ->
@@ -23,10 +32,10 @@ socket_client_open(Addr, Stream, Options) :-
;
throw(error(type_error(socket_address, Addr), socket_client_open/3))
),
builtins:parse_stream_options(Options,
[Alias, EOFAction, Reposition, Type],
socket_client_open/3),
'$socket_client_open'(Address, Port, Stream, Alias, EOFAction, Reposition, Type).
parse_socket_options(Options,
[Alias, EOFAction, Reposition, TLS, Type],
socket_client_open/3),
'$socket_client_open'(Address, Port, Stream, Alias, EOFAction, Reposition, Type, TLS).
socket_server_open(Addr, ServerSocket) :-

View File

@@ -8,12 +8,12 @@
op(1150, fx, table)
]).
:- use_module('tabling/double_linked_list').
:- use_module('tabling/table_data_structure').
:- use_module('tabling/batched_worklist').
:- use_module('tabling/wrapper').
:- use_module('tabling/global_worklist').
:- use_module('tabling/table_link_manager').
:- use_module(library(tabling/double_linked_list)).
:- use_module(library(tabling/table_data_structure)).
:- use_module(library(tabling/batched_worklist)).
:- use_module(library(tabling/wrapper)).
:- use_module(library(tabling/global_worklist)).
:- use_module(library(tabling/table_link_manager)).
:- use_module(library(cont)).
:- use_module(library(lists)).

View File

@@ -45,8 +45,8 @@
wkl_worklist_work_done/1 % +WorkList
]).
:- use_module(global_worklist).
:- use_module(double_linked_list).
:- use_module(library(tabling/global_worklist)).
:- use_module(library(tabling/double_linked_list)).
:- use_module(library(atts)).
:- use_module(library(lists)).

View File

@@ -15,8 +15,8 @@
get_nb_identifiers/3 % +Table, -NbWorklistID, -NbAnswerTreeID
]).
:- use_module(table_link_manager).
:- use_module(trie).
:- use_module(library(tabling/table_link_manager)).
:- use_module(library(tabling/trie)).
/* Part of SWI-Prolog
@@ -53,7 +53,7 @@
POSSIBILITY OF SUCH DAMAGE.
*/
:- use_module(batched_worklist).
:- use_module(library(tabling/batched_worklist)).
:- use_module(library(atts)).
:- use_module(library(gensym)).

View File

@@ -47,7 +47,7 @@
:- use_module(library(iso_ext)).
:- use_module(library(terms)).
:- use_module(trie).
:- use_module(library(tabling/trie)).
:- attribute trie_table_link/1.

View File

@@ -66,7 +66,7 @@
% p_trie_arity_univ(+Term,-FunctorData,-ArgumentsList).
p_trie_arity_univ(Term,functor_data(Name,Arity),Arguments) :-
( var(Term) ->
Name = var,
Name = Term,
Arity = 0,
Arguments = []
; Term =.. [Name|Arguments],

129
src/lib/time.pl Normal file
View File

@@ -0,0 +1,129 @@
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Written 2020 by Markus Triska (triska@metalevel.at)
Part of Scryer Prolog.
This library provides predicates for reasoning about time.
current_time(T) yields the current system time in an opaque form,
called a time stamp. Use format_time//2 to describe strings that
contain attributes of the time stamp.
The nonterminal format_time//2 describes a list of characters that
are formatted according to a format string. Usage:
phrase(format_time(FormatString, TimeStamp), Cs)
TimeStamp represents a moment in time in an opaque form, as for
example obtained by current_time/1.
FormatString is a list of characters that are interpreted literally,
except for the following specifiers (and possibly more in the future):
%Y year of the time stamp. Example: 2020.
%m month number (01-12), zero-padded to 2 digits
%d day number (01-31), zero-padded to 2 digits
%H hour number (00-24), zero-padded to 2 digits
%M minute number (00-59), zero-padded to 2 digits
%S second number (00-60), zero-padded to 2 digits
%b abbreviated month name, always 3 letters
%a abbreviated weekday name, always 3 letters
%A full weekday name
%j day of the year (001-366), zero-padded to 3 digits
%% the literal %
Example:
?- current_time(T), phrase(format_time("%d.%m.%Y (%H:%M:%S)", T), Cs).
T = [...], Cs = "11.06.2020 (00:24:32)"
; false.
sleep(S) sleeps for S seconds (a floating point number).
time(Goal) reports the execution time of Goal.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
:- module(time, [max_sleep_time/1, sleep/1, time/1, current_time/1, format_time//2]).
:- use_module(library(format)).
:- use_module(library(iso_ext)).
:- use_module(library(error)).
:- use_module(library(dcgs)).
:- use_module(library(lists)).
:- use_module(library(charsio), [read_term_from_chars/2]).
current_time(T) :-
'$current_time'(T0),
read_term_from_chars(T0, T).
format_time([], _) --> [].
format_time(['%','%'|Fs], T) --> !, "%", format_time(Fs, T).
format_time(['%',Spec|Fs], T) --> !,
( { member(Spec=Value, T) } ->
list(Value)
; { domain_error(time_specifier, Spec, format_time//2) }
),
format_time(Fs, T).
format_time([F|Fs], T) --> [F], format_time(Fs, T).
list([]) --> [].
list([L|Ls]) --> [L], list(Ls).
max_sleep_time(0xfffffffffffffbff).
sleep(T) :-
builtins:must_be_number(T, sleep),
( T < 0 ->
domain_error(not_less_than_zero, T, sleep/1)
; max_sleep_time(N), T > N ->
throw(error(representation_error(max_sleep_time), sleep/1))
; '$sleep'(T)
).
% '$cpu_now' can be replaced by statistics/2 once that is implemented.
time(Goal) :-
'$cpu_now'(T0),
setup_call_cleanup(true,
( Goal,
report_time(T0)
),
report_time(T0)).
report_time(T0) :-
'$cpu_now'(T),
Time is T - T0,
( bb_get('$first_answer', true) ->
format(" % CPU time: ~3f seconds~n", [Time])
; format("% CPU time: ~3f seconds~n ", [Time])
).
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
?- time((true;false)).
% CPU time: 0.000 seconds
true
; % CPU time: 0.001 seconds
false.
:- time(use_module(library(clpz))).
% CPU time: 2.762 seconds
true
; false.
:- time(use_module(library(lists))).
% CPU time: 0.000 seconds
true
; % CPU time: 0.001 seconds
false.
?- time(member(X, [a,b,c])).
% CPU time: 0.000 seconds
X = a
; % CPU time: 0.002 seconds
X = b
; % CPU time: 0.004 seconds
X = c
; % CPU time: 0.007 seconds
false.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */

642
src/lib/xpath.pl Normal file
View File

@@ -0,0 +1,642 @@
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
The original copyright and licence information is shown below.
Adapted in June 2020 by Markus Triska (triska@metalevel.at)
Part of Scryer Prolog.
In order to improve portability and reliability of this library, I
have changed various parts of the original code to make it
conforming to the Prolog ISO standard. I have removed all
occurrences of proprietary non-standard ad hoc data types.
In Scryer Prolog, we represent strings as lists of characters.
This makes them amenable to processing with DCGs and other
built-in mechanisms such as existing predicates on lists.
Scryer Prolog represents lists of characters very compactly,
making it an ideal representation for large amounts of text. It
fully conforms to the ISO standard and is very portable.
This library is intended to be used in tandem with load_html/3
from library(sgml), which creates DOM trees from markup documents.
It can be combined with http_open/3 from library(http/http_open)
to read such documents directly from network connections.
For instance, to inspect all links to Prolog files (*.pl) on
Scryer Prolog's project page, we can use:
:- use_module(library(http/http_open)).
:- use_module(library(sgml)).
:- use_module(library(lists)).
:- use_module(library(xpath)).
link_to_pl_file(File) :-
http_open("https://github.com/mthom/scryer-prolog", S, []),
load_html(stream(S), DOM, []),
xpath(DOM, //a(@href), File),
append(_, ".pl", File).
Yielding:
?- link_to_pl_file(File).
%@ File = "/mthom/scryer-prolog/blob/master/src/lib/tabling.pl"
%@ ; File = "/mthom/scryer-prolog/blob/master/src/lib/dif.pl"
%@ ; File = "/mthom/scryer-prolog/blob/master/src/lib/freeze.pl"
%@ ; ...
Parts of the original functionality may not yet work. Please
consider such parts opportunities for improvements, and file
issues in case you need additional features.
The original copyright information follows.
======================================================================
Author: Jan Wielemaker
E-mail: J.Wielemaker@vu.nl
WWW: http://www.swi-prolog.org
Copyright (c) 2009-2019, University of Amsterdam
VU University Amsterdam
CWI, Amsterdam
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
:- module(xpath,
[ xpath/3, % +DOM, +Spec, -Value
xpath_chk/3, % +DOM, +Spec, -Value
op(400, fx, //),
op(400, fx, /),
op(200, fy, @)
]).
:- use_module(library(lists),[member/2,memberchk/2]).
:- use_module(library(error)).
:- use_module(library(dcgs)).
:- use_module(library(si)).
/** <module> Select nodes in an XML DOM
The library xpath.pl provides predicates to select nodes from an XML DOM
tree as produced by library(sgml) based on descriptions inspired by the
XPath language.
The predicate xpath/3 selects a sub-structure of the DOM
non-deterministically based on an XPath-like specification. Not all
selectors of XPath are implemented, but the ability to mix xpath/3 calls
with arbitrary Prolog code provides a powerful tool for extracting
information from XML parse-trees.
@see http://www.w3.org/TR/xpath
*/
element_name(element(Name,_,_), Name).
element_attributes(element(_,Attributes,_), Attributes).
element_content(element(_,_,Content), Content).
%! xpath_chk(+DOM, +Spec, ?Content) is semidet.
%
% Semi-deterministic version of xpath/3.
xpath_chk(DOM, Spec, Content) :-
xpath(DOM, Spec, Content),
!.
%! xpath(+DOM, +Spec, ?Content) is nondet.
%
% Match an element in a DOM structure. The syntax is inspired by
% XPath, using () rather than [] to select inside an element.
% First we can construct paths using / and //:
%
% $ =|//|=Term :
% Select any node in the DOM matching term.
% $ =|/|=Term :
% Match the root against Term.
% $ Term :
% Select the immediate children of the root matching Term.
%
% The Terms above are of type _callable_. The functor specifies
% the element name. The element name '*' refers to any element.
% The name =self= refers to the top-element itself and is often
% used for processing matches of an earlier xpath/3 query. A term
% NS:Term refers to an XML name in the namespace NS. Optional
% arguments specify additional constraints and functions. The
% arguments are processed from left to right. Defined conditional
% argument values are:
%
% $ index(?Index) :
% True if the element is the Index-th child of its parent,
% where 1 denotes the first child. Index can be one of:
% $ `Var` :
% `Var` is unified with the index of the matched element.
% $ =last= :
% True for the last element.
% $ =last= - `IntExpr` :
% True for the last-minus-nth element. For example,
% `last-1` is the element directly preceding the last one.
% $ `IntExpr` :
% True for the element whose index equals `IntExpr`.
% $ Integer :
% The N-th element with the given name, with 1 denoting the
% first element. Same as index(Integer).
% $ =last= :
% The last element with the given name. Same as
% index(last).
% $ =last= - IntExpr :
% The IntExpr-th element before the last.
% Same as index(last-IntExpr).
%
% Defined function argument values are:
%
% $ =self= :
% Evaluate to the entire element
% $ =content= :
% Evaluate to the content of the element (a list)
% $ =text= :
% Evaluates to all text from the sub-tree, represented
% as a list of characters.
% $ `text(atom)` :
% Evaluates to all text from the sub-tree as an atom.
% $ =normalize_space= :
% As =text=, but uses normalize_space/2 to normalise
% white-space in the output
% $ =number= :
% Extract an integer or float from the value. Ignores
% leading and trailing white-space
% $ =|@|=Attribute :
% Evaluates to the value of the given attribute. Attribute
% can be a compound term. In this case the functor name
% denotes the element and arguments perform transformations
% on the attribute value. Defined transformations are:
%
% - number
% Translate the value into a number using
% xsd_number_chars/2.
% - integer
% As `number`, but subsequently transform the value
% into an integer using the round/1 function.
% - float
% As `number`, but subsequently transform the value
% into a float using the float/1 function.
% - lower
% Translate the value to lower case, preserving
% the type.
% - upper
% Translate the value to upper case, preserving
% the type.
%
% In addition, the argument-list can be _conditions_:
%
% $ Left = Right :
% Succeeds if the left-hand unifies with the right-hand.
% If the left-hand side is a function, this is evaluated.
% The right-hand side is _never_ evaluated, and thus the
% condition `content = content` defines that the content
% of the element is the atom `content`.
% The functions `lower_case` and `upper_case` can be applied
% to Right (see example below).
% $ contains(Haystack, Needle) :
% Succeeds if Needle is a sub-list of Haystack.
% $ XPath :
% Succeeds if XPath matches in the currently selected
% sub-DOM. For example, the following expression finds
% an =h3= element inside a =div= element, where the =div=
% element itself contains an =h2= child with a =strong=
% child.
%
% ==
% //div(h2/strong)/h3
% ==
%
% This is equivalent to the conjunction of XPath goals below.
%
% ==
% ...,
% xpath(DOM, //(div), Div),
% xpath(Div, h2/strong, _),
% xpath(Div, h3, Result)
% ==
%
% **Examples**:
%
% Match each table-row in DOM:
%
% ==
% xpath(DOM, //tr, TR)
% ==
%
% Match the last cell of each tablerow in DOM. This example
% illustrates that a result can be the input of subsequent xpath/3
% queries. Using multiple queries on the intermediate TR term
% guarantee that all results come from the same table-row:
%
% ==
% xpath(DOM, //tr, TR),
% xpath(TR, /td(last), TD)
% ==
%
% Match each =href= attribute in an <a> element
%
% ==
% xpath(DOM, //a(@href), HREF)
% ==
%
% Suppose we have a table containing rows where each first column
% is the name of a product with a link to details and the second
% is the price (a number). The following predicate matches the
% name, URL and price:
%
% ==
% product(DOM, Name, URL, Price) :-
% xpath(DOM, //tr, TR),
% xpath(TR, td(1), C1),
% xpath(C1, /self(normalize_space), Name),
% xpath(C1, a(@href), URL),
% xpath(TR, td(2, number), Price).
% ==
%
% Suppose we want to select books with genre="thriller" from a
% tree containing elements =|<book genre=...>|=
%
% ==
% thriller(DOM, Book) :-
% xpath(DOM, //book(@genre=thiller), Book).
% ==
%
% Match the elements =|<table align="center">|= _and_ =|<table
% align="CENTER">|=:
%
% ```prolog
% //table(@align(lower) = center)
% ```
%
% Get the `width` and `height` of a `div` element as a number,
% and the `div` node itself:
%
% ==
% xpath(DOM, //div(@width(number)=W, @height(number)=H), Div)
% ==
%
% Note that `div` is an infix operator, so parentheses must be
% used in cases like the following:
%
% ==
% xpath(DOM, //(div), Div)
% ==
xpath(DOM, Spec, Content) :-
in_dom(Spec, DOM, Content).
in_dom(//Spec, DOM, Value) :-
!,
element_spec(Spec, Name, Modifiers),
sub_dom(I, Len, Name, E, DOM),
modifiers(Modifiers, I, Len, E, Value).
in_dom(/Spec, E, Value) :-
!,
element_spec(Spec, Name, Modifiers),
( Name == self
-> true
; element_name(E, Name)
),
modifiers(Modifiers, 1, 1, E, Value).
in_dom(A/B, DOM, Value) :-
!,
in_dom(A, DOM, Value0),
in_dom(B, Value0, Value).
in_dom(A//B, DOM, Value) :-
!,
in_dom(A, DOM, Value0),
in_dom(//B, Value0, Value).
in_dom(Spec, element(_, _, Content), Value) :-
element_spec(Spec, Name, Modifiers),
count_named_elements(Content, Name, CLen),
CLen > 0,
nth_element(N, Name, E, Content),
modifiers(Modifiers, N, CLen, E, Value).
element_spec(Var, _, _) :-
var(Var),
!,
instantiation_error(Var).
element_spec(NS:Term, NS:Name, Modifiers) :-
!,
callable_name_arguments(Term, Name0, Modifiers),
star(Name0, Name).
element_spec(Term, Name, Modifiers) :-
!,
callable_name_arguments(Term, Name0, Modifiers),
star(Name0, Name).
callable_name_arguments(Atom, Name, Arguments) :-
atom(Atom),
!,
Name = Atom, Arguments = [].
callable_name_arguments(Compound, Name, Arguments) :-
Compound =.. [Name|Arguments].
star(*, _) :- !.
star(Name, Name).
%! sub_dom(-Index, -Count, +Name, -Sub, +DOM) is nondet.
%
% Sub is a node in DOM with Name.
%
% @param Count is the total number of nodes in the content
% list Sub appears that have the same name.
% @param Index is the 1-based index of Sub of nodes with
% Name.
sub_dom(1, 1, Name, DOM, DOM) :-
element_name(DOM, Name0),
\+ Name \= Name0.
sub_dom(N, Len, Name, E, element(_,_,Content)) :-
!,
sub_dom_2(N, Len, Name, E, Content).
sub_dom(N, Len, Name, E, Content) :-
list_si(Content),
sub_dom_2(N, Len, Name, E, Content).
sub_dom_2(N, Len, Name, Element, Content) :-
( count_named_elements(Content, Name, Len),
nth_element(N, Name, Element, Content)
; member(element(_,_,C2), Content),
sub_dom_2(N, Len, Name, Element, C2)
).
%! count_named_elements(+Content, +Name, -Count) is det.
%
% Count is the number of nodes with Name in Content.
count_named_elements(Content, Name, Count) :-
count_named_elements(Content, Name, 0, Count).
count_named_elements([], _, Count, Count).
count_named_elements([element(Name,_,_)|T], Name0, C0, C) :-
\+ Name \= Name0,
!,
C1 is C0+1,
count_named_elements(T, Name0, C1, C).
count_named_elements([_|T], Name, C0, C) :-
count_named_elements(T, Name, C0, C).
%! nth_element(?N, +Name, -Element, +Content:list) is nondet.
%
% True if Element is the N-th element with name in Content.
nth_element(N, Name, Element, Content) :-
nth_element_(1, N, Name, Element, Content).
nth_element_(I, N, Name, E, [H|T]) :-
element_name(H, Name0),
\+ Name \= Name0,
!,
( N = I,
E = H
; I2 is I + 1,
( nonvar(N), I2 > N
-> !, fail
; true
),
nth_element_(I2, N, Name, E, T)
).
nth_element_(I, N, Name, E, [_|T]) :-
nth_element_(I, N, Name, E, T).
%! modifiers(+Modifiers, +I, +Clen, +DOM, -Value)
%
%
modifiers([], _, _, Value, Value).
modifiers([H|T], I, L, Value0, Value) :-
modifier(H, I, L, Value0, Value1),
modifiers(T, I, L, Value1, Value).
modifier(M, _, _, _, _) :-
var(M),
!,
instantiation_error(M).
modifier(Index, I, L, Value0, Value) :-
implicit_index_modifier(Index),
!,
Value = Value0,
index_modifier(Index, I, L).
modifier(index(Index), I, L, Value, Value) :-
!,
index_modifier(Index, I, L).
modifier(Function, _, _, In, Out) :-
xpath_function(Function),
!,
xpath_function(Function, In, Out).
modifier(Function, _, _, In, Out) :-
xpath_condition(Function, In),
Out = In.
implicit_index_modifier(I) :-
integer(I),
!.
implicit_index_modifier(last).
implicit_index_modifier(last-_Expr).
index_modifier(Var, I, _L) :-
var(Var),
!,
Var = I.
index_modifier(last, I, L) :-
!,
I =:= L.
index_modifier(last-Expr, I, L) :-
!,
I =:= L-Expr.
index_modifier(N, I, _) :-
N =:= I.
xpath_function(self, DOM, DOM). % self
xpath_function(content, Element, Value) :- % content
element_content(Element, Value).
xpath_function(text, DOM, Text) :- % text
text_of_dom(DOM, chars, Text).
xpath_function(text(As), DOM, Text) :- % text(atom)
text_of_dom(DOM, As, Text).
xpath_function(normalize_space, DOM, Text) :- % normalize_space
text_of_dom(DOM, chars, Text0),
normalize_space(Text0, Text).
xpath_function(number, DOM, Number) :- % number
text_of_dom(DOM, chars, Text0),
normalize_space(Text0, Text),
catch(xsd_number_chars(Number, Text), _, fail).
xpath_function(@Name, element(_, Attrs, _), Value) :- % @Name
( atom(Name)
-> memberchk(Name=Value, Attrs)
; compound(Name)
-> Name =.. [AName|AOps],
memberchk(AName=Value0, Attrs),
translate_attribute(AOps, Value0, Value)
; member(Name=Value, Attrs)
).
xpath_function(quote(Value), _, Value). % quote(Value)
xpath_function(self).
xpath_function(content).
xpath_function(text).
xpath_function(text(_)).
xpath_function(normalize_space).
xpath_function(number).
xpath_function(@_).
xpath_function(quote(_)).
translate_attribute([], Value, Value).
translate_attribute([H|T], Value0, Value) :-
translate_attr(H, Value0, Value1),
translate_attribute(T, Value1, Value).
translate_attr(number, Value0, Value) :-
xsd_number_chars(Value, Value0).
translate_attr(integer, Value0, Value) :-
xsd_number_chars(Value1, Value0),
Value is round(Value1).
translate_attr(float, Value0, Value) :-
xsd_number_chars(Value1, Value0),
Value is float(Value1).
% The implementation of these translations is left for later.
% translate_attr(lower, Value0, Value) :- ...
% translate_attr(upper, Value0, Value) :- ...
xpath_condition(Left = Right, Value) :- % =
!,
var_or_function(Left, Value, LeftValue),
process_equality(LeftValue, Right).
xpath_condition(contains(Haystack, Needle), Value) :- % contains(Haystack, Needle)
!,
val_or_function(Haystack, Value, HaystackValue),
val_or_function(Needle, Value, NeedleValue),
( phrase((list(_),list(NeedleValue),list(_)), HaystackValue)
-> true
).
xpath_condition(Spec, Dom) :-
in_dom(Spec, Dom, _).
%! process_equality(+Left, +Right) is semidet.
%
% Provides (very) partial support for XSLT functions that can be
% applied according to the XPath 2 specification.
%
% For example the XPath expression in [1], and the equivalent
% Prolog expression in [2], would both match the HTML element in
% [3].
%
% ==
% [1] //table[align=lower-case(center)]
% [2] //table(@align=lower_case(center))
% [3] <table align="CENTER">
% ==
process_equality(Left, Right) :-
var(Right),
!,
Left = Right.
process_equality(Left, lower_case(Right)) :-
!,
downcase_atom(Left, Right).
process_equality(Left, upper_case(Right)) :-
!,
upcase_atom(Left, Right).
process_equality(Left, Right) :-
Left = Right.
var_or_function(Arg, _, Arg) :-
var(Arg),
!.
var_or_function(Func, Value0, Value) :-
xpath_function(Func),
!,
xpath_function(Func, Value0, Value).
var_or_function(Value, _, Value).
val_or_function(Arg, _, Arg) :-
var(Arg),
!,
instantiation_error(Arg).
val_or_function(Func, Value0, Value) :- % TBD
xpath_function(Func, Value0, Value),
!.
val_or_function(Value, _, Value).
%! text_of_dom(+DOM, +As, -Text:(chars | atom)) is det.
%
% Text is the joined textual content of DOM.
text_of_dom(DOM, As, Text) :-
phrase(text_of(DOM), Text0),
( As == chars ->
Text = Text0
; As == atom ->
atom_chars(Text, Text0)
; domain_error(As, atom_or_chars, xpath)
).
text_of(element(_,_,Content)) -->
text_of_list(Content).
text_of([]) -->
[].
text_of([H|T]) -->
text_of(H),
text_of(T).
text_of_list([]) -->
[].
text_of_list([H|T]) -->
text_of_1(H),
text_of_list(T).
text_of_1(element(_,_,Content)) -->
text_of_list(Content).
text_of_1([C|Cs]) --> list([C|Cs]).
list([]) --> [].
list([L|Ls]) --> [L], list(Ls).
% For now, we use number_chars/2 to parse XML numbers.
% If the need arises, we can extend this to additional
% float constants and syntax that may occur in XML files.
xsd_number_chars(Number, Chars) :-
number_chars(Number, Chars).
normalize_space(Text0, Text) :-
Text0 = Text. % no conversion for the moment.

View File

@@ -2,14 +2,14 @@ use crate::divrem::*;
use crate::prolog_parser::ast::*;
use crate::prolog::arithmetic::*;
use crate::prolog::clause_types::*;
use crate::prolog::forms::*;
use crate::prolog::machine::machine_errors::*;
use crate::prolog::machine::machine_indices::*;
use crate::prolog::machine::machine_state::*;
use crate::prolog::ordered_float::*;
use crate::prolog::rug::{Integer, Rational};
use crate::arithmetic::*;
use crate::clause_types::*;
use crate::forms::*;
use crate::machine::machine_errors::*;
use crate::machine::machine_indices::*;
use crate::machine::machine_state::*;
use crate::ordered_float::*;
use crate::rug::{Integer, Rational};
use std::cmp;
use std::convert::TryFrom;
@@ -143,12 +143,10 @@ impl MachineState {
pub(crate)
fn arith_eval_by_metacall(&self, r: RegType) -> Result<Number, MachineStub> {
let a = self[r].clone();
let caller = MachineError::functor_stub(clause_name!("(is)"), 2);
let caller = MachineError::functor_stub(clause_name!("is"), 2);
let mut interms: Vec<Number> = Vec::with_capacity(64);
for addr in self.post_order_iter(a) {
for addr in self.post_order_iter(self[r]) {
match self.heap.index_addr(&addr).as_ref() {
&HeapCellValue::NamedStr(2, ref name, _) => {
let a2 = interms.pop().unwrap();
@@ -159,7 +157,7 @@ impl MachineState {
"-" => interms.push(try_numeric_result!(self, a1 - a2, caller)?),
"*" => interms.push(try_numeric_result!(self, a1 * a2, caller)?),
"/" => interms.push(self.div(a1, a2)?),
"**" => interms.push(self.pow(a1, a2, "(is)")?),
"**" => interms.push(self.pow(a1, a2, "is")?),
"^" => interms.push(self.int_pow(a1, a2)?),
"max" => interms.push(self.max(a1, a2)?),
"min" => interms.push(self.min(a1, a2)?),
@@ -191,7 +189,16 @@ impl MachineState {
"atan2" => interms.push(Number::Float(OrderedFloat(self.atan2(a1, a2)?))),
"gcd" => interms.push(self.gcd(a1, a2)?),
_ => {
return Err(self.error_form(MachineError::instantiation_error(), caller))
let evaluable_stub = MachineError::functor_stub(name.clone(), 2);
return Err(self.error_form(
MachineError::type_error(
self.heap.h(),
ValidType::Evaluable,
evaluable_stub,
),
caller,
));
}
}
}
@@ -219,7 +226,16 @@ impl MachineState {
"\\" => interms.push(self.bitwise_complement(a1)?),
"sign" => interms.push(self.sign(a1)),
_ => {
return Err(self.error_form(MachineError::instantiation_error(), caller));
let evaluable_stub = MachineError::functor_stub(name.clone(), 1);
return Err(self.error_form(
MachineError::type_error(
self.heap.h(),
ValidType::Evaluable,
evaluable_stub,
),
caller,
));
}
}
}
@@ -241,12 +257,44 @@ impl MachineState {
&HeapCellValue::Atom(ref name, _) if name.as_str() == "pi" => {
interms.push(Number::Float(OrderedFloat(f64::consts::PI)))
}
_ => {
&HeapCellValue::NamedStr(arity, ref name, _) => {
let evaluable_stub = MachineError::functor_stub(name.clone(), arity);
return Err(self.error_form(
MachineError::type_error(
self.heap.h(),
ValidType::Evaluable,
evaluable_stub,
),
caller,
));
}
&HeapCellValue::Atom(ref name, _) => {
let evaluable_stub = MachineError::functor_stub(name.clone(), 0);
return Err(self.error_form(
MachineError::type_error(
self.heap.h(),
ValidType::Evaluable,
evaluable_stub,
),
caller,
));
}
&HeapCellValue::Addr(addr) if addr.is_ref() => {
return Err(self.error_form(
MachineError::instantiation_error(),
caller,
));
}
val => {
return Err(self.type_error(
ValidType::Number,
val.context_free_clone(),
clause_name!("is"),
2,
));
}
}
}
@@ -377,7 +425,7 @@ impl MachineState {
pub(crate)
fn atan2(&self, n1: Number, n2: Number) -> Result<f64, MachineStub> {
let stub = MachineError::functor_stub(clause_name!("(is)"), 2);
let stub = MachineError::functor_stub(clause_name!("is"), 2);
if n1.is_zero() && n2.is_zero() {
Err(self.error_form(MachineError::evaluation_error(EvalError::Undefined), stub))
@@ -392,13 +440,13 @@ impl MachineState {
pub(crate)
fn int_pow(&self, n1: Number, n2: Number) -> Result<Number, MachineStub> {
if n1.is_zero() && n2.is_negative() {
let stub = MachineError::functor_stub(clause_name!("(is)"), 2);
let stub = MachineError::functor_stub(clause_name!("is"), 2);
return Err(self.error_form(MachineError::evaluation_error(EvalError::Undefined), stub));
}
match (n1, n2) {
(Number::Fixnum(n1), Number::Fixnum(n2)) => {
if n1 != 1 && n2 < -1 {
if !(n1 == 1 || n1 == 0 || n1 == -1) && n2 < 0 {
let n = Number::from(n1);
let stub = MachineError::functor_stub(clause_name!("^"), 2);
@@ -424,7 +472,7 @@ impl MachineState {
}
}
(Number::Fixnum(n1), Number::Integer(n2)) => {
if n1 != 1 && &*n2 < &-1 {
if !(n1 == 1 || n1 == 0 || n1 == -1) && &*n2 < &0 {
let n = Number::from(n1);
let stub = MachineError::functor_stub(clause_name!("^"), 2);
@@ -442,7 +490,7 @@ impl MachineState {
}
}
(Number::Integer(n1), Number::Fixnum(n2)) => {
if &*n1 != &1 && n2 < -1 {
if !(&*n1 == &1 || &*n1 == &0 || &*n1 == &-1) && n2 < 0 {
let n = Number::Integer(n1);
let stub = MachineError::functor_stub(clause_name!("^"), 2);
@@ -460,7 +508,7 @@ impl MachineState {
}
}
(Number::Integer(n1), Number::Integer(n2)) => {
if &*n1 != &1 && &*n2 < &-1 {
if !(&*n1 == &1 || &*n1 == &0 || &*n1 == &-1) && &*n2 < &0 {
let n = Number::Integer(n1);
let stub = MachineError::functor_stub(clause_name!("^"), 2);
@@ -487,7 +535,7 @@ impl MachineState {
let f2 = self.float(n2)?;
if n1.is_negative() && f2 != f2.floor() {
let stub = MachineError::functor_stub(clause_name!("(is)"), 2);
let stub = MachineError::functor_stub(clause_name!("is"), 2);
return Err(
self.error_form(MachineError::evaluation_error(EvalError::Undefined), stub)
);
@@ -571,34 +619,7 @@ impl MachineState {
return Err(self.error_form(MachineError::evaluation_error(EvalError::Undefined), stub));
}
match (n1, n2) {
(Number::Fixnum(n1), Number::Fixnum(n2)) => {
if let Ok(n2) = u32::try_from(n2) {
if let Some(result) = n1.checked_pow(n2) {
return Ok(Number::from(result));
}
}
let n1 = Integer::from(n1);
let n2 = Integer::from(n2);
Ok(Number::from(binary_pow(n1, &n2)))
}
(Number::Fixnum(n1), Number::Integer(n2)) => {
let n1 = Integer::from(n1);
Ok(Number::from(binary_pow(n1, n2.as_ref())))
}
(Number::Integer(n1), Number::Fixnum(n2)) => {
let n2 = Integer::from(n2);
Ok(Number::from(binary_pow(n1.as_ref().clone(), &n2)))
}
(Number::Integer(n1), Number::Integer(n2)) => {
Ok(Number::from(binary_pow(n1.as_ref().clone(), &*n2)))
}
(n1, n2) => {
self.float_pow(n1, n2)
}
}
self.float_pow(n1, n2)
}
#[inline]
@@ -607,7 +628,7 @@ impl MachineState {
where
FloatFn: Fn(f64) -> f64,
{
let stub = MachineError::functor_stub(clause_name!("(is)"), 2);
let stub = MachineError::functor_stub(clause_name!("is"), 2);
let f1 = try_numeric_result!(self, result_f(&n1, rnd_f), stub)?;
let f1 = result_f(&Number::Float(OrderedFloat(f(f1))), rnd_f);
@@ -667,7 +688,7 @@ impl MachineState {
pub(crate)
fn sqrt(&self, n1: Number) -> Result<f64, MachineStub> {
if n1.is_negative() {
let stub = MachineError::functor_stub(clause_name!("(is)"), 2);
let stub = MachineError::functor_stub(clause_name!("is"), 2);
return Err(self.error_form(MachineError::evaluation_error(EvalError::Undefined), stub));
}
@@ -677,7 +698,7 @@ impl MachineState {
#[inline]
pub(crate)
fn float(&self, n: Number) -> Result<f64, MachineStub> {
let stub = MachineError::functor_stub(clause_name!("(is)"), 2);
let stub = MachineError::functor_stub(clause_name!("is"), 2);
try_numeric_result!(self, result_f(&n, rnd_f), stub)
}
@@ -705,7 +726,7 @@ impl MachineState {
pub(crate)
fn round(&self, n: Number) -> Result<Number, MachineStub> {
let stub = MachineError::functor_stub(clause_name!("(is)"), 2);
let stub = MachineError::functor_stub(clause_name!("is"), 2);
let result = n + Number::Float(OrderedFloat(0.5f64));
let result = try_numeric_result!(self, result, stub)?;

View File

@@ -1,5 +1,5 @@
use crate::prolog::heap_iter::*;
use crate::prolog::machine::*;
use crate::heap_iter::*;
use crate::machine::*;
use crate::indexmap::IndexSet;

View File

@@ -1,13 +1,13 @@
use crate::prolog::clause_types::*;
use crate::prolog::codegen::*;
use crate::prolog::debray_allocator::*;
use crate::prolog::forms::*;
use crate::prolog::instructions::*;
use crate::prolog::machine::compile::*;
use crate::prolog::machine::machine_errors::*;
use crate::prolog::machine::machine_indices::*;
use crate::clause_types::*;
use crate::codegen::*;
use crate::debray_allocator::*;
use crate::forms::*;
use crate::instructions::*;
use crate::machine::compile::*;
use crate::machine::machine_errors::*;
use crate::machine::machine_indices::*;
use indexmap::IndexSet;
use crate::indexmap::IndexSet;
use std::collections::VecDeque;
use std::mem;

View File

@@ -1,4 +1,4 @@
use crate::prolog::instructions::*;
use crate::instructions::*;
use std::collections::VecDeque;

View File

@@ -1,22 +1,22 @@
use prolog_parser::ast::*;
use prolog_parser::parser::get_desc;
use prolog_parser::tabled_rc::TabledData;
use crate::prolog_parser::ast::*;
use crate::prolog_parser::parser::get_desc;
use crate::prolog_parser::tabled_rc::TabledData;
use crate::prolog::codegen::*;
use crate::prolog::debray_allocator::*;
use crate::prolog::forms::*;
use crate::prolog::instructions::*;
use crate::prolog::iterators::*;
use crate::prolog::machine::code_walker::*;
use crate::prolog::machine::machine_errors::*;
use crate::prolog::machine::machine_indices::*;
use crate::prolog::machine::term_expansion::ExpansionAdditionResult;
use crate::prolog::machine::toplevel::*;
use crate::prolog::machine::*;
use crate::codegen::*;
use crate::debray_allocator::*;
use crate::forms::*;
use crate::instructions::*;
use crate::iterators::*;
use crate::machine::code_walker::*;
use crate::machine::machine_errors::*;
use crate::machine::machine_indices::*;
use crate::machine::term_expansion::ExpansionAdditionResult;
use crate::machine::toplevel::*;
use crate::machine::*;
use indexmap::{IndexMap, IndexSet};
use crate::indexmap::{IndexMap, IndexSet};
use ref_thread_local::RefThreadLocal;
use crate::ref_thread_local::RefThreadLocal;
use std::cell::Cell;
use std::collections::VecDeque;
@@ -469,6 +469,7 @@ impl ClauseCodeGenerator {
vec![Box::new(head.clone()), Box::new(tail.clone())],
None,
);
PredicateClause::Fact(clause, 0, 0)
})
.collect(),
@@ -601,12 +602,7 @@ fn load_library(
) -> Result<ClauseName, SessionError> {
match LIBRARIES.borrow().get(name.as_str()) {
Some(code) => {
let mut lib_path = current_dir();
lib_path.pop();
lib_path.push("lib");
let listing_src = ListingSource::from_file_and_path(name, lib_path);
let listing_src = ListingSource::User;
load_module(
wam,

View File

@@ -1,5 +1,5 @@
use crate::prolog::machine::machine_indices::*;
use crate::prolog::machine::stack::*;
use crate::machine::machine_indices::*;
use crate::machine::stack::*;
use std::mem;
use std::ops::IndexMut;
@@ -104,7 +104,7 @@ impl<T: CopierTarget> CopyTermState<T> {
fn copy_partial_string(&mut self, addr: usize, n: usize) {
if let &HeapCellValue::Addr(Addr::PStrLocation(h, _)) = &self.target[addr] {
if h >= self.old_h {
*self.value_at_scan() = HeapCellValue::Addr(Addr::PStrLocation(h, 0));
*self.value_at_scan() = HeapCellValue::Addr(Addr::PStrLocation(h, n));
self.scan += 1;
return;
@@ -114,14 +114,14 @@ impl<T: CopierTarget> CopyTermState<T> {
let threshold = self.target.threshold();
*self.value_at_scan() =
HeapCellValue::Addr(Addr::PStrLocation(threshold, 0));
HeapCellValue::Addr(Addr::PStrLocation(threshold, n));
self.scan += 1;
let (pstr, has_tail) =
match &self.target[addr] {
&HeapCellValue::PartialString(ref pstr, has_tail) => {
(pstr.clone_from_offset(n), has_tail)
(pstr.clone_from_offset(0), has_tail)
}
_ => {
unreachable!()
@@ -130,7 +130,7 @@ impl<T: CopierTarget> CopyTermState<T> {
self.target.push(HeapCellValue::PartialString(pstr, has_tail));
let replacement = HeapCellValue::Addr(Addr::PStrLocation(threshold, 0));
let replacement = HeapCellValue::Addr(Addr::PStrLocation(threshold, n));
let trail_item = mem::replace(
&mut self.target[addr],

View File

@@ -1,10 +1,10 @@
use prolog_parser::ast::*;
use crate::prolog_parser::ast::*;
use crate::prolog::heap_print::*;
use crate::prolog::machine::*;
use crate::prolog::machine::compile::*;
use crate::prolog::machine::machine_errors::*;
use crate::prolog::machine::streams::*;
use crate::heap_print::*;
use crate::machine::*;
use crate::machine::compile::*;
use crate::machine::machine_errors::*;
use crate::machine::streams::*;
use std::convert::TryFrom;
@@ -66,6 +66,9 @@ impl Machine {
}
}
}
Addr::Fixnum(arity) => {
usize::try_from(arity).unwrap()
}
Addr::Usize(n) => {
n
}
@@ -98,6 +101,18 @@ impl Machine {
}
fn make_undefined(&mut self, name: ClauseName, arity: usize) {
let module_name = name.owning_module();
match self.indices.modules.get(&module_name) {
Some(ref module) => {
if let Some(idx) = module.code_dir.get(&(name.clone(), arity)) {
set_code_index!(idx, IndexPtr::DynamicUndefined, module_name);
}
}
None => {
}
}
if let Some(idx) = self.indices.code_dir.get(&(name, arity)) {
set_code_index!(idx, IndexPtr::DynamicUndefined, clause_name!("user"));
}
@@ -258,7 +273,12 @@ impl Machine {
unreachable!()
}
}
_ => unreachable!(),
Addr::Fixnum(arity) => {
usize::try_from(arity).unwrap()
}
_ => {
unreachable!()
}
};
let (mut name, arity) = self.get_predicate_key(temp_v!(1), temp_v!(2));

View File

@@ -2,9 +2,9 @@ use core::marker::PhantomData;
use crate::prolog_parser::ast::Constant;
use crate::prolog::machine::machine_indices::*;
use crate::prolog::machine::partial_string::*;
use crate::prolog::machine::raw_block::*;
use crate::machine::machine_indices::*;
use crate::machine::partial_string::*;
use crate::machine::raw_block::*;
use std::convert::TryFrom;
use std::mem;

View File

@@ -1,10 +1,10 @@
use prolog_parser::ast::*;
use crate::prolog_parser::ast::*;
use crate::prolog::forms::{ModuleSource, Number, PredicateKey};
use crate::prolog::machine::heap::*;
use crate::prolog::machine::machine_indices::*;
use crate::prolog::machine::machine_state::*;
use crate::prolog::rug::Integer;
use crate::forms::{ModuleSource, Number, PredicateKey};
use crate::machine::heap::*;
use crate::machine::machine_indices::*;
use crate::machine::machine_state::*;
use crate::rug::Integer;
use std::rc::Rc;
@@ -43,6 +43,21 @@ impl TypeError for Addr {
}
}
impl TypeError for HeapCellValue {
fn type_error(self, _: usize, valid_type: ValidType) -> MachineError {
let stub = functor!(
"type_error",
[atom(valid_type.as_str()), value(self)]
);
MachineError {
stub,
location: None,
from: ErrorProvenance::Received
}
}
}
impl TypeError for MachineStub {
fn type_error(self, h: usize, valid_type: ValidType) -> MachineError {
let stub = functor!(
@@ -502,7 +517,7 @@ pub enum ValidType {
InCharacter,
Integer,
List,
// Number,
Number,
Pair,
// PredicateIndicator,
// Variable
@@ -525,7 +540,7 @@ impl ValidType {
ValidType::InCharacter => "in_character",
ValidType::Integer => "integer",
ValidType::List => "list",
// ValidType::Number => "number",
ValidType::Number => "number",
ValidType::Pair => "pair",
// ValidType::PredicateIndicator => "predicate_indicator",
// ValidType::Variable => "variable"
@@ -560,7 +575,7 @@ impl DomainErrorType {
// from 7.12.2 f) of 13211-1:1995
#[derive(Debug, Clone, Copy)]
pub enum RepFlag {
// Character,
Character,
CharacterCode,
InCharacterCode,
MaxArity,
@@ -571,7 +586,7 @@ pub enum RepFlag {
impl RepFlag {
pub fn as_str(self) -> &'static str {
match self {
// RepFlag::Character => "character",
RepFlag::Character => "character",
RepFlag::CharacterCode => "character_code",
RepFlag::InCharacterCode => "in_character_code",
RepFlag::MaxArity => "max_arity",
@@ -825,5 +840,4 @@ impl From<ParserError> for EvalSession {
fn from(err: ParserError) -> Self {
EvalSession::from(SessionError::ParserError(err))
}
}

View File

@@ -1,21 +1,21 @@
use prolog_parser::ast::*;
use prolog_parser::tabled_rc::*;
use crate::prolog_parser::ast::*;
use crate::prolog_parser::tabled_rc::*;
use crate::prolog::clause_types::*;
use crate::prolog::fixtures::*;
use crate::prolog::forms::*;
use crate::prolog::machine::code_repo::CodeRepo;
use crate::prolog::machine::Ball;
use crate::prolog::machine::heap::*;
use crate::prolog::machine::machine_state::*;
use crate::prolog::machine::partial_string::*;
use crate::prolog::machine::raw_block::RawBlockTraits;
use crate::prolog::machine::streams::Stream;
use crate::prolog::instructions::*;
use crate::prolog::ordered_float::OrderedFloat;
use crate::prolog::rug::{Integer, Rational};
use crate::clause_types::*;
use crate::fixtures::*;
use crate::forms::*;
use crate::machine::code_repo::CodeRepo;
use crate::machine::Ball;
use crate::machine::heap::*;
use crate::machine::machine_state::*;
use crate::machine::partial_string::*;
use crate::machine::raw_block::RawBlockTraits;
use crate::machine::streams::Stream;
use crate::instructions::*;
use crate::ordered_float::OrderedFloat;
use crate::rug::{Integer, Rational};
use indexmap::IndexMap;
use crate::indexmap::IndexMap;
use std::cell::RefCell;
use std::cmp::Ordering;
@@ -118,7 +118,7 @@ impl PartialEq<Ref> for Addr {
}
}
// for use in MachineState::bind.
// for use crate::in MachineState::bind.
impl PartialOrd<Ref> for Addr {
fn partial_cmp(&self, r: &Ref) -> Option<Ordering> {
match self {
@@ -272,19 +272,6 @@ impl Addr {
&Addr::Float(f) => {
Some(Constant::Float(f))
}
&Addr::PStrLocation(h, n) => {
let mut heap_pstr_iter =
machine_st.heap_pstr_iter(Addr::PStrLocation(h, n));
let buf = heap_pstr_iter.to_string();
let end_addr = heap_pstr_iter.focus();
if end_addr == Addr::EmptyList {
Some(Constant::String(Rc::new(buf)))
} else {
None
}
}
&Addr::Usize(n) => {
Some(Constant::Usize(n))
}

View File

@@ -1,22 +1,22 @@
use prolog_parser::ast::*;
use prolog_parser::tabled_rc::*;
use crate::prolog_parser::ast::*;
use crate::prolog_parser::tabled_rc::*;
use crate::prolog::clause_types::*;
use crate::prolog::forms::*;
use crate::prolog::heap_print::*;
use crate::prolog::machine::attributed_variables::*;
use crate::prolog::machine::copier::*;
use crate::prolog::machine::heap::*;
use crate::prolog::machine::machine_errors::*;
use crate::prolog::machine::machine_indices::*;
use crate::prolog::machine::modules::*;
use crate::prolog::machine::stack::*;
use crate::prolog::machine::streams::*;
use crate::prolog::rug::Integer;
use crate::clause_types::*;
use crate::forms::*;
use crate::heap_print::*;
use crate::machine::attributed_variables::*;
use crate::machine::copier::*;
use crate::machine::heap::*;
use crate::machine::machine_errors::*;
use crate::machine::machine_indices::*;
use crate::machine::modules::*;
use crate::machine::stack::*;
use crate::machine::streams::*;
use crate::rug::Integer;
use downcast::Any;
use crate::downcast::Any;
use indexmap::{IndexMap, IndexSet};
use crate::indexmap::{IndexMap, IndexSet};
use std::cmp::Ordering;
use std::convert::TryFrom;
@@ -636,11 +636,10 @@ impl MachineState {
}
let mut orig_stream = stream.clone();
let mut stream = self.open_parsing_stream(stream, "read_term", 3)?;
loop {
match self.read(
&mut stream,
stream.clone(),
indices.atom_tbl.clone(),
&indices.op_dir,
) {
@@ -1337,14 +1336,8 @@ pub(crate) trait CallPolicy: Any + fmt::Debug {
return_from_clause!(machine_st.last_call, machine_st)
}
&BuiltInClauseType::Read => {
let mut stream = machine_st.open_parsing_stream(
current_input_stream.clone(),
"read",
1,
)?;
match machine_st.read(
&mut stream,
current_input_stream.clone(),
indices.atom_tbl.clone(),
&indices.op_dir,
) {

View File

@@ -1,24 +1,24 @@
use prolog_parser::ast::*;
use prolog_parser::tabled_rc::*;
use crate::prolog_parser::ast::*;
use crate::prolog_parser::tabled_rc::*;
use crate::prolog::clause_types::*;
use crate::prolog::forms::*;
use crate::prolog::heap_iter::*;
use crate::prolog::instructions::*;
use crate::prolog::machine::INTERRUPT;
use crate::prolog::machine::attributed_variables::*;
use crate::prolog::machine::code_repo::CodeRepo;
use crate::prolog::machine::copier::*;
use crate::prolog::machine::heap::*;
use crate::prolog::machine::machine_errors::*;
use crate::prolog::machine::machine_indices::*;
use crate::prolog::machine::machine_state::*;
use crate::prolog::machine::stack::*;
use crate::prolog::machine::streams::*;
use crate::prolog::ordered_float::*;
use crate::prolog::rug::Integer;
use crate::clause_types::*;
use crate::forms::*;
use crate::heap_iter::*;
use crate::instructions::*;
use crate::machine::INTERRUPT;
use crate::machine::attributed_variables::*;
use crate::machine::code_repo::CodeRepo;
use crate::machine::copier::*;
use crate::machine::heap::*;
use crate::machine::machine_errors::*;
use crate::machine::machine_indices::*;
use crate::machine::machine_state::*;
use crate::machine::stack::*;
use crate::machine::streams::*;
use crate::ordered_float::*;
use crate::rug::Integer;
use indexmap::{IndexMap, IndexSet};
use crate::indexmap::{IndexMap, IndexSet};
use std::cmp::Ordering;
use std::convert::TryFrom;
@@ -689,7 +689,7 @@ impl MachineState {
&mut HeapPtr::PStrChar(h, ref mut n) |
&mut HeapPtr::PStrLocation(h, ref mut n) => {
match &self.heap[h] {
HeapCellValue::PartialString(ref pstr, _) => {
&HeapCellValue::PartialString(ref pstr, _) => {
for c in pstr.range_from(*n ..).take(rhs) {
*n += c.len_utf8();
}
@@ -697,7 +697,6 @@ impl MachineState {
self.s = HeapPtr::PStrLocation(h, *n);
}
_ => {
unreachable!()
}
}
}
@@ -819,7 +818,7 @@ impl MachineState {
self.bind(addr.as_var().unwrap(), pstr_addr);
}
Addr::Lis(l) if !self.flags.double_quotes.is_atom() => {
Addr::Lis(l) => {
let h = self.heap.h();
let pstr_addr =
@@ -921,7 +920,7 @@ impl MachineState {
self.fail = true;
}
}
Addr::Lis(l) if !self.flags.double_quotes.is_atom() => {
Addr::Lis(l) => {
let addr = self.heap.put_constant(c.clone());
self.unify(Addr::Lis(l), addr);
}
@@ -953,7 +952,7 @@ impl MachineState {
pub(super)
fn execute_arith_instr(&mut self, instr: &ArithmeticInstruction) {
let stub = MachineError::functor_stub(clause_name!("(is)"), 2);
let stub = MachineError::functor_stub(clause_name!("is"), 2);
match instr {
&ArithmeticInstruction::Add(ref a1, ref a2, t) => {
@@ -1405,11 +1404,7 @@ impl MachineState {
v
}
Addr::PStrLocation(..) => {
if !self.flags.double_quotes.is_atom() {
l
} else {
c
}
l
}
Addr::Char(_) | Addr::Con(_) | Addr::CutPoint(_) |
Addr::EmptyList | Addr::Fixnum(_) | Addr::Float(_) | Addr::Usize(_) => {
@@ -1885,11 +1880,10 @@ impl MachineState {
unreachable!()
}
}
(Addr::PStrLocation(..), Addr::Lis(_))
| (Addr::Lis(_), Addr::PStrLocation(..))
if !self.flags.double_quotes.is_atom() => {
continue;
}
(Addr::PStrLocation(..), Addr::Lis(_)) |
(Addr::Lis(_), Addr::PStrLocation(..)) => {
continue;
}
(pstr1 @ Addr::PStrLocation(..), pstr2 @ Addr::PStrLocation(..)) => {
let mut i1 = self.heap_pstr_iter(pstr1);
let mut i2 = self.heap_pstr_iter(pstr2);
@@ -2249,7 +2243,7 @@ impl MachineState {
(
Addr::PStrLocation(..),
Addr::Lis(_),
) if !self.flags.double_quotes.is_atom() => {
) => {
}
(
Addr::Lis(_),
@@ -2278,7 +2272,7 @@ impl MachineState {
(
Addr::PStrLocation(..),
Addr::Str(s),
) if !self.flags.double_quotes.is_atom() => {
) => {
if let &HeapCellValue::NamedStr(a1, ref n1, _) = &self.heap[s] {
if a1 != 2 || n1.as_str() != "." {
return Some(a1.cmp(&2).then_with(|| n1.as_str().cmp(".")));
@@ -2290,7 +2284,7 @@ impl MachineState {
(
Addr::Str(s),
Addr::PStrLocation(..),
) if !self.flags.double_quotes.is_atom() => {
) => {
if let &HeapCellValue::NamedStr(a1, ref n1, _) = &self.heap[s] {
if a1 != 2 || n1.as_str() != "." {
return Some(2.cmp(&a1).then_with(|| ".".cmp(n1.as_str())));
@@ -2376,14 +2370,7 @@ impl MachineState {
}
}
_ => {
match d {
Addr::Char(_) if self.flags.double_quotes.is_codes() => {
self.p += 1;
}
_ => {
self.fail = true;
}
}
self.fail = true;
}
}
}
@@ -2474,22 +2461,29 @@ impl MachineState {
fn try_functor_fabricate_struct(
&mut self,
name: ClauseName,
arity: isize,
arity: usize,
spec: Option<SharedOpDesc>,
op_dir: &OpDir,
r: Ref,
) {
let spec = fetch_atom_op_spec(name.clone(), spec, op_dir);
let spec = spec.and_then(|spec| {
if spec.arity() != arity {
fetch_op_spec(name.clone(), arity, op_dir)
} else {
Some(spec)
}
});
let f_a = if name.as_str() == "." && arity == 2 {
Addr::Lis(self.heap.h())
} else {
self.heap.to_unifiable(HeapCellValue::NamedStr(arity as usize, name, spec))
self.heap.to_unifiable(HeapCellValue::NamedStr(arity, name, spec))
};
for _ in 0..arity {
let h = self.heap.h();
self.heap.push(HeapCellValue::Addr(Addr::HeapCell(h)));
let h = self.heap.h();
for i in 0 .. arity {
self.heap.push(HeapCellValue::Addr(Addr::HeapCell(h + i)));
}
self.bind(r, f_a);
@@ -2510,7 +2504,13 @@ impl MachineState {
}
Addr::Str(o) => match self.heap.clone(o) {
HeapCellValue::NamedStr(arity, name, spec) => {
let spec = fetch_op_spec(name.clone(), arity, spec, &indices.op_dir);
let spec = fetch_op_spec_from_existing(
name.clone(),
arity,
spec,
&indices.op_dir,
);
self.try_functor_compound_case(name, arity, spec)
}
_ => {
@@ -2518,7 +2518,13 @@ impl MachineState {
}
},
Addr::Lis(_) | Addr::PStrLocation(..) => {
let spec = fetch_op_spec(clause_name!("."), 2, None, &indices.op_dir);
let spec = fetch_op_spec_from_existing(
clause_name!("."),
2,
None,
&indices.op_dir,
);
self.try_functor_compound_case(clause_name!("."), 2, spec)
}
Addr::AttrVar(..) | Addr::HeapCell(_) | Addr::StackCell(..) => {
@@ -2589,7 +2595,7 @@ impl MachineState {
if let HeapCellValue::Atom(name, spec) = self.heap.clone(h) {
self.try_functor_fabricate_struct(
name,
arity,
arity as usize,
spec,
&indices.op_dir,
a1.as_var().unwrap(),
@@ -2609,7 +2615,7 @@ impl MachineState {
Addr::Char(c) => {
self.try_functor_fabricate_struct(
clause_name!(c.to_string(), indices.atom_tbl),
arity,
arity as usize,
None,
&indices.op_dir,
a1.as_var().unwrap(),
@@ -2889,7 +2895,7 @@ impl MachineState {
| (
HeapCellValue::Addr(Addr::PStrLocation(..)),
HeapCellValue::Addr(Addr::Lis(_)),
) if !self.flags.double_quotes.is_atom() => {
) => {
}
(
HeapCellValue::NamedStr(ar1, n1, _),

View File

@@ -1,12 +1,12 @@
use prolog_parser::ast::*;
use prolog_parser::tabled_rc::*;
use crate::prolog_parser::ast::*;
use crate::prolog_parser::tabled_rc::*;
use crate::prolog::clause_types::*;
use crate::prolog::forms::*;
use crate::prolog::heap_print::*;
use crate::prolog::instructions::*;
use crate::prolog::machine::heap::*;
use crate::prolog::read::*;
use crate::clause_types::*;
use crate::forms::*;
use crate::heap_print::*;
use crate::instructions::*;
use crate::machine::heap::*;
use crate::read::*;
mod attributed_variables;
pub(super) mod code_repo;
@@ -32,17 +32,17 @@ mod arithmetic_ops;
mod machine_state_impl;
mod system_calls;
use crate::prolog::machine::attributed_variables::*;
use crate::prolog::machine::code_repo::*;
use crate::prolog::machine::compile::*;
use crate::prolog::machine::machine_errors::*;
use crate::prolog::machine::machine_indices::*;
use crate::prolog::machine::machine_state::*;
use crate::prolog::machine::modules::*;
use crate::prolog::machine::streams::*;
use crate::prolog::machine::toplevel::*;
use crate::machine::attributed_variables::*;
use crate::machine::code_repo::*;
use crate::machine::compile::*;
use crate::machine::machine_errors::*;
use crate::machine::machine_indices::*;
use crate::machine::machine_state::*;
use crate::machine::modules::*;
use crate::machine::streams::*;
use crate::machine::toplevel::*;
use indexmap::IndexMap;
use crate::indexmap::IndexMap;
use std::collections::VecDeque;
use std::convert::TryFrom;
@@ -212,17 +212,6 @@ impl SubModuleUser for IndexStore {
}
}
#[inline]
fn current_dir() -> std::path::PathBuf {
let mut path_buf = std::path::PathBuf::from(PROJECT_DIR);
// file!() always produces a path relative to PROJECT_DIR.
path_buf = path_buf.join(std::path::PathBuf::from(file!()));
path_buf.pop();
path_buf
}
include!(concat!(env!("OUT_DIR"), "/libraries.rs"));
static TOPLEVEL: &str = include_str!("../toplevel.pl");
@@ -230,12 +219,7 @@ static TOPLEVEL: &str = include_str!("../toplevel.pl");
impl Machine {
fn compile_special_forms(&mut self)
{
let current_dir = current_dir();
let verify_attrs_src = ListingSource::from_file_and_path(
clause_name!("attributed_variables.pl"),
current_dir.clone(),
);
let verify_attrs_src = ListingSource::User;
match compile_special_form(
self,
@@ -250,10 +234,7 @@ impl Machine {
panic!("Machine::compile_special_forms() failed at VERIFY_ATTRS"),
}
let project_attrs_src = ListingSource::from_file_and_path(
clause_name!("project_attributes.pl"),
current_dir,
);
let project_attrs_src = ListingSource::User;
match compile_special_form(
self,
@@ -273,13 +254,7 @@ impl Machine {
{
self.toplevel_idx = self.code_repo.code.len();
let mut current_dir = current_dir();
current_dir.pop();
let top_lvl_src = ListingSource::from_file_and_path(
clause_name!("toplevel.pl"),
current_dir,
);
let top_lvl_src = ListingSource::User;
compile_user_module(
self,
@@ -371,6 +346,8 @@ impl Machine {
pub fn new(current_input_stream: Stream, current_output_stream: Stream) -> Self
{
use crate::ref_thread_local::RefThreadLocal;
let mut wam = Machine {
machine_st: MachineState::new(),
inner_heap: Heap::new(),
@@ -383,78 +360,59 @@ impl Machine {
};
let atom_tbl = wam.indices.atom_tbl.clone();
let mut lib_path = current_dir();
lib_path.pop();
lib_path.push("lib");
wam.indices.add_term_and_goal_expansion_indices();
compile_listing(
&mut wam,
Stream::from(BUILTINS),
Stream::from(LIBRARIES.borrow()["builtins"]),
default_index_store!(atom_tbl.clone()),
true,
ListingSource::from_file_and_path(
clause_name!("builtins.pl"),
lib_path.clone(),
),
ListingSource::User,
);
wam.compile_special_forms();
compile_user_module(&mut wam,
Stream::from(ERROR),
true,
ListingSource::from_file_and_path(
clause_name!("error"),
lib_path.clone(),
)
compile_user_module(
&mut wam,
Stream::from(LIBRARIES.borrow()["error"]),
true,
ListingSource::User,
);
compile_user_module(&mut wam,
Stream::from(PAIRS),
true,
ListingSource::from_file_and_path(
clause_name!("pairs"),
lib_path.clone(),
)
compile_user_module(
&mut wam,
Stream::from(LIBRARIES.borrow()["pairs"]),
true,
ListingSource::User,
);
compile_user_module(&mut wam,
Stream::from(LISTS),
true,
ListingSource::from_file_and_path(
clause_name!("lists"),
lib_path.clone(),
),
compile_user_module(
&mut wam,
Stream::from(LIBRARIES.borrow()["lists"]),
true,
ListingSource::User,
);
compile_user_module(&mut wam,
Stream::from(ISO_EXT),
true,
ListingSource::from_file_and_path(
clause_name!("iso_ext"),
lib_path.clone(),
)
compile_user_module(
&mut wam,
Stream::from(LIBRARIES.borrow()["iso_ext"]),
true,
ListingSource::User,
);
compile_user_module(&mut wam,
Stream::from(SI),
true,
ListingSource::from_file_and_path(
clause_name!("si"),
lib_path.clone(),
)
compile_user_module(
&mut wam,
Stream::from(LIBRARIES.borrow()["si"]),
true,
ListingSource::User,
);
compile_user_module(&mut wam,
Stream::from(CHARSIO),
true,
ListingSource::from_file_and_path(
clause_name!("si"),
lib_path.clone(),
)
compile_user_module(
&mut wam,
Stream::from(LIBRARIES.borrow()["charsio"]),
true,
ListingSource::User,
);
if wam.compile_top_level().is_err() {
@@ -681,8 +639,15 @@ impl Machine {
name.clone(),
HeapCellValue::Addr(Addr::Char(c)) =>
clause_name!(c.to_string(), self.indices.atom_tbl),
_ =>
unreachable!(),
HeapCellValue::Addr(addr @ Addr::PStrLocation(..)) => {
let mut heap_pstr_iter =
self.machine_st.heap_pstr_iter(*addr);
clause_name!(
heap_pstr_iter.to_string(),
self.indices.atom_tbl
)
}
_ => unreachable!(),
}
};

View File

@@ -1,10 +1,10 @@
use prolog_parser::ast::*;
use prolog_parser::tabled_rc::*;
use crate::prolog_parser::ast::*;
use crate::prolog_parser::tabled_rc::*;
use crate::prolog::forms::*;
use crate::prolog::machine::code_repo::*;
use crate::prolog::machine::machine_errors::*;
use crate::prolog::machine::machine_indices::*;
use crate::forms::*;
use crate::machine::code_repo::*;
use crate::machine::machine_errors::*;
use crate::machine::machine_indices::*;
use std::collections::VecDeque;
use std::mem;

View File

@@ -1,8 +1,8 @@
use crate::prolog::machine::machine_indices::*;
use crate::prolog::machine::raw_block::*;
use core::marker::PhantomData;
use crate::machine::machine_indices::*;
use crate::machine::raw_block::*;
use std::mem;
use std::ops::{Index, IndexMut};
use std::ptr;

View File

@@ -1,22 +1,26 @@
use crate::prolog_parser::ast::*;
use crate::prolog::read::PrologStream;
use crate::prolog::read::readline::*;
use crate::prolog::machine::machine_errors::*;
use crate::prolog::machine::machine_indices::*;
use crate::prolog::machine::machine_state::*;
use crate::read::PrologStream;
use crate::read::readline::*;
use crate::machine::machine_errors::*;
use crate::machine::machine_indices::*;
use crate::machine::machine_state::*;
use std::cmp::Ordering;
use std::cmp::{min, Ordering};
use std::cell::RefCell;
use std::error::Error;
use std::fmt;
use std::fs::File;
use std::io;
use std::io::{stdout, Cursor, ErrorKind, Read, Seek, SeekFrom, Write};
use std::hash::{Hash, Hasher};
use std::mem;
use std::net::{Shutdown, TcpStream};
use std::ops::DerefMut;
use std::rc::Rc;
use crate::native_tls::TlsStream;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum StreamType {
Binary,
@@ -90,17 +94,81 @@ impl EOFAction {
}
}
fn parser_top_to_bytes(mut buf: Vec<io::Result<char>>) -> io::Result<Vec<u8>> {
let mut str_buf = String::new();
while let Some(c) = buf.pop() {
str_buf.push(c?);
}
unsafe {
let array = str_buf.as_bytes_mut();
array.reverse();
Ok(Vec::from(array))
}
}
/* all these streams are closed automatically when the instance is
* dropped. */
pub enum StreamInstance {
Bytes(Cursor<Vec<u8>>),
DynReadSource(Box<dyn Read>),
InputFile(ClauseName, File),
OutputFile(ClauseName, File, bool), // File, append.
Null,
PausedPrologStream(Vec<u8>, Box<StreamInstance>),
ReadlineStream(ReadlineStream),
StaticStr(Cursor<&'static str>),
Stdout,
TcpStream(ClauseName, TcpStream),
TlsStream(ClauseName, TlsStream<TcpStream>)
}
impl StreamInstance {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
match self {
StreamInstance::PausedPrologStream(ref mut put_back, ref mut stream) => {
let mut index = 0;
while index < min(buf.len(), put_back.len()) {
let b = put_back.pop().unwrap();
buf[index] = b;
index += 1;
}
if index == buf.len() {
Ok(buf.len())
} else {
stream.read(&mut buf[index ..])
}
}
StreamInstance::InputFile(_, ref mut file) => {
file.read(buf)
}
StreamInstance::TcpStream(_, ref mut tcp_stream) => {
tcp_stream.read(buf)
}
StreamInstance::TlsStream(_, ref mut tls_stream) => {
tls_stream.read(buf)
}
StreamInstance::ReadlineStream(ref mut rl_stream) => {
rl_stream.read(buf)
}
StreamInstance::StaticStr(ref mut src) => {
src.read(buf)
}
StreamInstance::Bytes(ref mut cursor) => {
cursor.read(buf)
}
StreamInstance::OutputFile(..) |
StreamInstance::Stdout |
StreamInstance::Null => {
Err(std::io::Error::new(
ErrorKind::PermissionDenied,
StreamError::ReadFromOutputStream,
))
}
}
}
}
impl Drop for StreamInstance {
@@ -109,6 +177,9 @@ impl Drop for StreamInstance {
StreamInstance::TcpStream(_, ref mut tcp_stream) => {
discard_result!(tcp_stream.shutdown(Shutdown::Both));
}
StreamInstance::TlsStream(_, ref mut tls_stream) => {
discard_result!(tls_stream.shutdown());
}
_ => {
}
}
@@ -120,17 +191,24 @@ impl fmt::Debug for StreamInstance {
match self {
&StreamInstance::Bytes(ref bytes) =>
write!(fmt, "Bytes({:?})", bytes),
&StreamInstance::DynReadSource(_) =>
write!(fmt, "DynReadSource(_)"), // Hacky solution.
&StreamInstance::InputFile(_, ref file) => write!(fmt, "InputFile({:?})", file),
&StreamInstance::OutputFile(_, ref file, _) => write!(fmt, "OutputFile({:?})", file),
&StreamInstance::Null => write!(fmt, "Null"),
&StreamInstance::StaticStr(_) =>
write!(fmt, "StaticStr(_)"), // Hacky solution.
&StreamInstance::InputFile(_, ref file) =>
write!(fmt, "InputFile({:?})", file),
&StreamInstance::OutputFile(_, ref file, _) =>
write!(fmt, "OutputFile({:?})", file),
&StreamInstance::Null =>
write!(fmt, "Null"),
&StreamInstance::PausedPrologStream(ref put_back, ref stream) =>
write!(fmt, "PausedPrologStream({:?}, {:?})", put_back, stream),
&StreamInstance::ReadlineStream(ref readline_stream) =>
write!(fmt, "ReadlineStream({:?})", readline_stream),
// &StreamInstance::Stdin => write!(fmt, "Stdin"),
&StreamInstance::Stdout => write!(fmt, "Stdout"),
&StreamInstance::Stdout =>
write!(fmt, "Stdout"),
&StreamInstance::TcpStream(_, ref tcp_stream) =>
write!(fmt, "TcpStream({:?})", tcp_stream),
&StreamInstance::TlsStream(_, ref tls_stream) =>
write!(fmt, "TlsStream({:?})", tls_stream),
}
}
}
@@ -274,7 +352,7 @@ impl From<ReadlineStream> for Stream {
impl From<&'static str> for Stream {
fn from(src: &'static str) -> Stream {
Stream::from_inst(StreamInstance::DynReadSource(Box::new(src.as_bytes())))
Stream::from_inst(StreamInstance::StaticStr(Cursor::new(src)))
}
}
@@ -405,12 +483,14 @@ impl Stream {
fn mode(&self) -> &'static str {
match self.stream_inst.0.borrow().1 {
StreamInstance::Bytes(_) |
StreamInstance::PausedPrologStream(..) |
StreamInstance::ReadlineStream(_) |
StreamInstance::DynReadSource(_) |
StreamInstance::StaticStr(_) |
StreamInstance::InputFile(..) => {
"read"
}
StreamInstance::TcpStream(..) => {
StreamInstance::TcpStream(..) |
StreamInstance::TlsStream(..) => {
"read_append"
}
StreamInstance::OutputFile(_, _, true) => {
@@ -449,6 +529,12 @@ impl Stream {
Stream::from_inst(StreamInstance::TcpStream(address, tcp_stream))
}
#[inline]
pub(crate)
fn from_tls_stream(address: ClauseName, tls_stream: TlsStream<TcpStream>) -> Self {
Stream::from_inst(StreamInstance::TlsStream(address, tls_stream))
}
#[inline]
pub(crate)
fn from_file_as_output(name: ClauseName, file: File, in_append_mode: bool) -> Self {
@@ -478,7 +564,6 @@ impl Stream {
pub(crate)
fn is_stdin(&self) -> bool {
match self.stream_inst.0.borrow().1 {
//StreamInstance::Stdin |
StreamInstance::ReadlineStream(_) => {
true
}
@@ -508,11 +593,12 @@ impl Stream {
pub(crate)
fn is_input_stream(&self) -> bool {
match self.stream_inst.0.borrow().1 {
// StreamInstance::Stdin |
StreamInstance::TcpStream(..) |
StreamInstance::TlsStream(..) |
StreamInstance::Bytes(_) |
StreamInstance::PausedPrologStream(..) |
StreamInstance::ReadlineStream(_) |
StreamInstance::DynReadSource(_) |
StreamInstance::StaticStr(_) |
StreamInstance::InputFile(..) => {
true
}
@@ -528,6 +614,7 @@ impl Stream {
match self.stream_inst.0.borrow().1 {
StreamInstance::Stdout
| StreamInstance::TcpStream(..)
| StreamInstance::TlsStream(..)
| StreamInstance::Bytes(_)
| StreamInstance::OutputFile(..) => {
true
@@ -538,27 +625,49 @@ impl Stream {
}
}
fn unpause_stream(&mut self) {
let stream_inst =
match self.stream_inst.0.borrow_mut().1 {
StreamInstance::PausedPrologStream(ref put_back, ref mut stream_inst)
if put_back.is_empty() => {
mem::replace(&mut **stream_inst, StreamInstance::Null)
}
_ => {
return;
}
};
self.stream_inst.0.borrow_mut().1 = stream_inst;
}
// returns true on success.
#[inline]
pub(super)
fn reset(&mut self) -> bool {
self.stream_inst.0.borrow_mut().0 = false;
match self.stream_inst.0.borrow_mut().1 {
StreamInstance::Bytes(ref mut cursor) => {
cursor.set_position(0);
true
}
StreamInstance::InputFile(_, ref mut file) => {
file.seek(SeekFrom::Start(0)).unwrap();
true
}
StreamInstance::ReadlineStream(_) => {
true
}
_ => {
false
loop {
match self.stream_inst.0.borrow_mut().1 {
StreamInstance::Bytes(ref mut cursor) => {
cursor.set_position(0);
return true;
}
StreamInstance::InputFile(_, ref mut file) => {
file.seek(SeekFrom::Start(0)).unwrap();
return true;
}
StreamInstance::PausedPrologStream(ref mut put_back, _) => {
put_back.clear();
}
StreamInstance::ReadlineStream(_) => {
return true;
}
_ => {
return false;
}
}
self.unpause_stream();
}
}
@@ -619,7 +728,7 @@ impl Stream {
#[inline]
pub(crate)
fn peek_char(&mut self) -> std::io::Result<char> {
use unicode_reader::CodePoints;
use crate::unicode_reader::CodePoints;
match self.stream_inst.0.borrow_mut().1 {
StreamInstance::InputFile(_, ref mut file) => {
@@ -670,6 +779,34 @@ impl Stream {
}
}
}
#[inline]
pub(crate)
fn pause_stream(&mut self, buf: Vec<io::Result<char>>) -> io::Result<()> {
match self.stream_inst.0.borrow_mut().1 {
StreamInstance::PausedPrologStream(ref mut inner_buf, _) => {
inner_buf.extend(parser_top_to_bytes(buf)?.into_iter());
return Ok(());
}
_ => {
}
}
if !buf.is_empty() {
let stream_inst = mem::replace(
&mut self.stream_inst.0.borrow_mut().1,
StreamInstance::Null,
);
self.stream_inst.0.borrow_mut().1 =
StreamInstance::PausedPrologStream(
parser_top_to_bytes(buf)?,
Box::new(stream_inst),
);
}
Ok(())
}
}
impl MachineState {
@@ -866,7 +1003,7 @@ impl MachineState {
stub_name: &'static str,
stub_arity: usize,
) -> Result<PrologStream, MachineStub> {
match parsing_stream(stream.clone()) {
match parsing_stream(stream) {
Ok(parsing_stream) => {
Ok(parsing_stream)
}
@@ -1028,35 +1165,11 @@ impl MachineState {
}
impl Read for Stream {
#[inline]
fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
match self.stream_inst.0.borrow_mut().1 {
StreamInstance::InputFile(_, ref mut file) => {
file.read(buf)
}
StreamInstance::TcpStream(_, ref mut tcp_stream) => {
tcp_stream.read(buf)
}
StreamInstance::ReadlineStream(ref mut rl_stream) => {
rl_stream.read(buf)
}
StreamInstance::DynReadSource(ref mut src) => {
src.read(buf)
}
StreamInstance::Bytes(ref mut cursor) => {
cursor.read(buf)
}
/*
StreamInstance::Stdin => {
stdin().read(buf)
}
*/
StreamInstance::OutputFile(..) | StreamInstance::Stdout | StreamInstance::Null => {
Err(std::io::Error::new(
ErrorKind::PermissionDenied,
StreamError::ReadFromOutputStream,
))
}
}
let bytes_read = self.stream_inst.0.borrow_mut().1.read(buf)?;
self.unpause_stream();
Ok(bytes_read)
}
}
@@ -1069,14 +1182,20 @@ impl Write for Stream {
StreamInstance::TcpStream(_, ref mut tcp_stream) => {
tcp_stream.write(buf)
}
StreamInstance::TlsStream(_, ref mut tls_stream) => {
tls_stream.write(buf)
}
StreamInstance::Bytes(ref mut cursor) => {
cursor.write(buf)
}
StreamInstance::Stdout => {
stdout().write(buf)
}
StreamInstance::DynReadSource(_) | StreamInstance::ReadlineStream(_) |
StreamInstance::InputFile(..) | StreamInstance::Null => {
StreamInstance::PausedPrologStream(..) |
StreamInstance::StaticStr(_) |
StreamInstance::ReadlineStream(_) |
StreamInstance::InputFile(..) |
StreamInstance::Null => {
Err(std::io::Error::new(
ErrorKind::PermissionDenied,
StreamError::WriteToInputStream,
@@ -1093,14 +1212,20 @@ impl Write for Stream {
StreamInstance::TcpStream(_, ref mut tcp_stream) => {
tcp_stream.flush()
}
StreamInstance::TlsStream(_, ref mut tls_stream) => {
tls_stream.flush()
}
StreamInstance::Bytes(ref mut cursor) => {
cursor.flush()
}
StreamInstance::Stdout => {
stdout().flush()
}
StreamInstance::DynReadSource(_) | StreamInstance::ReadlineStream(_) |
StreamInstance::InputFile(..) | StreamInstance::Null => {
StreamInstance::PausedPrologStream(..) |
StreamInstance::StaticStr(_) |
StreamInstance::ReadlineStream(_) |
StreamInstance::InputFile(..) |
StreamInstance::Null => {
Err(std::io::Error::new(
ErrorKind::PermissionDenied,
StreamError::FlushToInputStream,

View File

@@ -1,10 +1,10 @@
use prolog_parser::ast::*;
use prolog_parser::parser::*;
use crate::prolog_parser::ast::*;
use crate::prolog_parser::parser::*;
use crate::prolog::machine::machine_indices::HeapCellValue;
use crate::prolog::machine::*;
use crate::prolog::rug::ops::Pow;
use crate::prolog::rug::Integer;
use crate::machine::machine_indices::HeapCellValue;
use crate::machine::*;
use crate::rug::ops::Pow;
use crate::rug::Integer;
use std::cell::Cell;
use std::collections::VecDeque;
@@ -165,7 +165,7 @@ impl<'a> TermStream<'a> {
#[inline]
pub fn eof(&mut self) -> Result<bool, ParserError> {
self.parser.devour_whitespace()?; // eliminate dangling comments before checking for EOF.
self.parser.devour_whitespace()?; // eliminate dangling comments before checking for EOF.
Ok(self.stack.is_empty() && self.parser.eof()?)
}

View File

@@ -1,14 +1,14 @@
use prolog_parser::ast::*;
use prolog_parser::tabled_rc::*;
use crate::prolog_parser::ast::*;
use crate::prolog_parser::tabled_rc::*;
use crate::prolog::forms::*;
use crate::prolog::iterators::*;
use crate::prolog::machine::machine_errors::*;
use crate::prolog::machine::machine_indices::*;
use crate::prolog::machine::term_expansion::*;
use crate::prolog::machine::*;
use crate::forms::*;
use crate::iterators::*;
use crate::machine::machine_errors::*;
use crate::machine::machine_indices::*;
use crate::machine::term_expansion::*;
use crate::machine::*;
use indexmap::{IndexMap, IndexSet};
use crate::indexmap::{IndexMap, IndexSet};
use std::borrow::BorrowMut;
use std::cell::Cell;
@@ -340,16 +340,37 @@ fn setup_module_decl(
}
}
fn setup_use_module_decl(mut terms: Vec<Box<Term>>) -> Result<ModuleSource, ParserError> {
fn read_library_path(
term: Term,
atom_tbl: TabledData<Atom>,
) -> Option<ClauseName> {
match term {
Term::Constant(_, Constant::Atom(atom, _)) => {
Some(atom.defrock_brackets())
}
_ => {
let mut atoms = vec![];
for term in unfold_by_str(term, "/") {
match term {
Term::Constant(_, Constant::Atom(atom, _)) => {
atoms.push(atom.as_str().to_owned());
}
_ => return None,
}
}
Some(clause_name!(atoms.join("/"), atom_tbl))
}
}
}
fn setup_use_module_decl(mut terms: Vec<Box<Term>>, atom_tbl: TabledData<Atom>) -> Result<ModuleSource, ParserError> {
match *terms.pop().unwrap() {
Term::Clause(_, ref name, ref mut terms, None)
if name.as_str() == "library" && terms.len() == 1 =>
{
terms
.pop()
.unwrap()
.to_constant()
.and_then(|c| c.to_atom())
read_library_path(*terms.pop().unwrap(), atom_tbl)
.map(|c| ModuleSource::Library(c))
.ok_or(ParserError::InvalidUseModuleDecl)
}
@@ -396,11 +417,7 @@ fn setup_qualified_import(
Term::Clause(_, ref name, ref mut terms, None)
if name.as_str() == "library" && terms.len() == 1 =>
{
terms
.pop()
.unwrap()
.to_constant()
.and_then(|c| c.to_atom())
read_library_path(*terms.pop().unwrap(), atom_tbl.clone())
.map(|c| ModuleSource::Library(c))
.ok_or(ParserError::InvalidUseModuleDecl)
}
@@ -685,7 +702,7 @@ fn setup_declaration<'a, 'b, 'c>(
}
}
("use_module", 1) => {
Ok(Declaration::UseModule(setup_use_module_decl(terms)?))
Ok(Declaration::UseModule(setup_use_module_decl(terms, indices.atom_tbl())?))
}
("use_module", 2) => {
let (name, exports) = setup_qualified_import(terms, indices.atom_tbl())?;

View File

@@ -121,6 +121,9 @@ macro_rules! functor_term {
(atom($e:expr), $arity:expr, $aux_lens:expr, $addendum: ident) => (
HeapCellValue::Atom(clause_name!($e), None)
);
(value($e:expr), $arity:expr, $aux_lens:expr, $addendum: ident) => (
$e
);
(string($h:expr, $e:expr), $arity:expr, $aux_lens:expr, $addendum: ident) => ({
let len: usize = $aux_lens.iter().sum();
let h = len + $arity + 1 + $addendum.h() + $h;

View File

@@ -1,3 +1,6 @@
extern crate blake2;
extern crate chrono;
extern crate cpu_time;
extern crate crossterm;
extern crate divrem;
#[macro_use]
@@ -8,19 +11,45 @@ extern crate indexmap;
#[macro_use]
extern crate lazy_static;
extern crate libc;
extern crate native_tls;
extern crate nix;
extern crate openssl;
extern crate ordered_float;
#[macro_use]
extern crate prolog_parser;
#[macro_use]
extern crate ref_thread_local;
extern crate ring;
extern crate ripemd160;
extern crate rug;
extern crate rustyline;
extern crate sha3;
extern crate unicode_reader;
use nix::sys::signal;
use crate::nix::sys::signal;
mod prolog;
#[macro_use]
mod macros;
mod allocator;
mod arithmetic;
mod codegen;
mod clause_types;
mod debray_allocator;
mod fixtures;
mod forms;
mod heap_iter;
mod heap_print;
mod indexing;
mod instructions;
mod iterators;
mod machine;
mod read;
mod targets;
mod write;
use crate::prolog::machine::*;
use crate::prolog::machine::streams::*;
use crate::prolog::read::*;
use machine::*;
use machine::streams::*;
use read::*;
use std::sync::atomic::Ordering;

View File

@@ -5,7 +5,6 @@ extern crate prolog_parser;
extern crate rug;
#[cfg(feature = "num-rug-adapter")]
extern crate num_rug_adapter as rug;
extern crate rustyline;
#[macro_use]
mod macros;

View File

@@ -1,15 +0,0 @@
:- use_module(library(charsio)).
:- use_module(library(lists)).
:- initialization(unit_test).
unit_test :-
chars_utf8bytes("a£\x2124\", Bs),
Bs = [97, 194, 163, 226, 132, 164].
write_f :-
open('x.txt', write, Stream, [type(binary)]),
F = put_byte(Stream),
chars_utf8bytes("£\x2124\\x2764\\x1F496\\n", Bs),
maplist(F, Bs),
close(Stream).

View File

@@ -1,24 +0,0 @@
:- module(pio, [phrase_from_file/2,
phrase_from_file/3]).
:- use_module(library(dcgs)).
:- use_module(library(error)).
:- use_module(library(lists), [member/2]).
phrase_from_file(NT, File) :-
phrase_from_file(NT, File, []).
phrase_from_file(NT, File, Options) :-
( var(File) -> instantiation_error(phrase_from_file/3)
; (\+ atom(File) ; File = []) ->
domain_error(source_sink, File, phrase_from_file/3)
; must_be(list, Options),
( member(Var, Options), var(Var) -> instantiation_error(phrase_from_file/3)
; member(type(Type), Options) ->
must_be(atom, Type),
member(Type, [text,binary])
; Type = text
),
'$file_to_chars'(File, Chars, Type),
phrase(NT, Chars)
).

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