Compare commits
639 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3fc5be0d03 | ||
|
|
357ae7a8aa | ||
|
|
ac00ae4daf | ||
|
|
249f034a38 | ||
|
|
32c612b747 | ||
|
|
386f7cf65d | ||
|
|
320802633f | ||
|
|
dcc4b91b35 | ||
|
|
e7c27ed999 | ||
|
|
928c9c9aad | ||
|
|
4a90f13dee | ||
|
|
61dddcee3f | ||
|
|
4c510001ce | ||
|
|
82dfa690d2 | ||
|
|
2768beec4c | ||
|
|
bd0aa16322 | ||
|
|
a1746a5bf1 | ||
|
|
fb502fb66b | ||
|
|
c9a69263b6 | ||
|
|
f0c8056334 | ||
|
|
17dd9239b6 | ||
|
|
6c691d9223 | ||
|
|
920644afaf | ||
|
|
8668aee7fd | ||
|
|
4f386b3e5e | ||
|
|
0f4667d942 | ||
|
|
5705c42820 | ||
|
|
f5f0d00a75 | ||
|
|
ec75e21898 | ||
|
|
94e9e17c79 | ||
|
|
5134e64cae | ||
|
|
53d39ccb4b | ||
|
|
b227e160f0 | ||
|
|
88a2b82f7e | ||
|
|
0016365446 | ||
|
|
0fa8feb475 | ||
|
|
eb872f8fca | ||
|
|
5fd78320dd | ||
|
|
3195042c7d | ||
|
|
b0234fa8b7 | ||
|
|
2a629fee37 | ||
|
|
bf13700a95 | ||
|
|
83268f5ff6 | ||
|
|
1eb42654e0 | ||
|
|
e05c34d1ee | ||
|
|
8325bb11e2 | ||
|
|
c1b577f2c7 | ||
|
|
29a61db275 | ||
|
|
e2c61485a1 | ||
|
|
65f200e02c | ||
|
|
aa9432e24f | ||
|
|
30d1585468 | ||
|
|
376c5263f0 | ||
|
|
bcd6d4e8a7 | ||
|
|
32eb896c56 | ||
|
|
4603163e88 | ||
|
|
b3c9fb2fea | ||
|
|
d66ea07ba4 | ||
|
|
496279c92d | ||
|
|
e0ae925ca3 | ||
|
|
1799c19933 | ||
|
|
94eddd3b42 | ||
|
|
79829cb6d2 | ||
|
|
0d20ca0bf2 | ||
|
|
3ede5ea28f | ||
|
|
cfd15f4e02 | ||
|
|
1f9ff2dd88 | ||
|
|
7740a39a4d | ||
|
|
5eda2dfe0e | ||
|
|
1509c6a471 | ||
|
|
19acd608a5 | ||
|
|
bc81ff28d8 | ||
|
|
ba867e95c3 | ||
|
|
53f99ca434 | ||
|
|
8958ea036e | ||
|
|
d3563c30e7 | ||
|
|
0f017339b7 | ||
|
|
4d3a3d806f | ||
|
|
10a0f708b9 | ||
|
|
409d3c168d | ||
|
|
005220b6d4 | ||
|
|
8462b039d3 | ||
|
|
2e3cabce6b | ||
|
|
2c6b615b8c | ||
|
|
f910e013a6 | ||
|
|
5f1b03261c | ||
|
|
862197fc96 | ||
|
|
44ebd894d5 | ||
|
|
b85ff7db36 | ||
|
|
22fd216de5 | ||
|
|
2f02c428cc | ||
|
|
1732413ee1 | ||
|
|
33325f1574 | ||
|
|
4f288c6fd9 | ||
|
|
5ffb4597b3 | ||
|
|
d9de38b935 | ||
|
|
ad459b83c0 | ||
|
|
d96ea6b815 | ||
|
|
40c3e31955 | ||
|
|
f84c831cda | ||
|
|
904cf97f7d | ||
|
|
791e22dc24 | ||
|
|
c82a0b3d2d | ||
|
|
2fc887724b | ||
|
|
e16762a137 | ||
|
|
4a07ffac69 | ||
|
|
9331c4ce9e | ||
|
|
184ef94e7e | ||
|
|
d67740d44d | ||
|
|
7b30daf88d | ||
|
|
d5e76da475 | ||
|
|
5d91c1af81 | ||
|
|
bb013e78d2 | ||
|
|
c22816de08 | ||
|
|
9bb851d437 | ||
|
|
c8a9f8dcf5 | ||
|
|
e8653ffe32 | ||
|
|
5499df418a | ||
|
|
b586618411 | ||
|
|
3b5730be54 | ||
|
|
961c4a1b9c | ||
|
|
72c5908f09 | ||
|
|
2a588ff943 | ||
|
|
24f11b5ae9 | ||
|
|
1d44d99875 | ||
|
|
eebcdfb24f | ||
|
|
526b56a650 | ||
|
|
20675f56e6 | ||
|
|
e5fbdeb3a9 | ||
|
|
7cc92ec1c1 | ||
|
|
fe0bf6f2ef | ||
|
|
828c19d478 | ||
|
|
15db77558c | ||
|
|
18cf4a3bd3 | ||
|
|
e0378acfc2 | ||
|
|
53cb2af202 | ||
|
|
f74005a166 | ||
|
|
b0df981b01 | ||
|
|
888d844ec5 | ||
|
|
3a7eb9fc0c | ||
|
|
46276aacd9 | ||
|
|
3a7a29868f | ||
|
|
0060c8988a | ||
|
|
458f482c2a | ||
|
|
cc9d6587a3 | ||
|
|
dadf1b6ff9 | ||
|
|
db56bb92f0 | ||
|
|
e82e36f51e | ||
|
|
f9aad34d28 | ||
|
|
b2d720b853 | ||
|
|
c10c05e924 | ||
|
|
8909246725 | ||
|
|
48c0b0ab3c | ||
|
|
cbbed310c5 | ||
|
|
9e9c3b6342 | ||
|
|
fefd262c2e | ||
|
|
1108c99688 | ||
|
|
93da831ef0 | ||
|
|
72bf45912e | ||
|
|
5d94276c4f | ||
|
|
b43f27030e | ||
|
|
2845f55157 | ||
|
|
e254d84710 | ||
|
|
0ef7b5488d | ||
|
|
56b04f8df8 | ||
|
|
2d036c6b25 | ||
|
|
ad3be5c848 | ||
|
|
a0544cc345 | ||
|
|
3245261162 | ||
|
|
21b7348c6a | ||
|
|
54d4dc6e1e | ||
|
|
e00d864199 | ||
|
|
ad6fc89a24 | ||
|
|
fc4823ce8e | ||
|
|
0bd9831eec | ||
|
|
dec2ef70c7 | ||
|
|
d19d8ea770 | ||
|
|
34f7752c0f | ||
|
|
da4d061067 | ||
|
|
85155439be | ||
|
|
dd32e69061 | ||
|
|
1c0c660c32 | ||
|
|
2eac902c33 | ||
|
|
9f5322d309 | ||
|
|
f5c2f6f9e9 | ||
|
|
e0e3b180e7 | ||
|
|
041dc039d4 | ||
|
|
ac755b0ada | ||
|
|
c14259060c | ||
|
|
a423eb5323 | ||
|
|
fd732550d8 | ||
|
|
fac7ba70c8 | ||
|
|
e9f8b35918 | ||
|
|
23034dd4f5 | ||
|
|
70ad44adfd | ||
|
|
95ca8a2630 | ||
|
|
a7fd3c50e5 | ||
|
|
5639f40994 | ||
|
|
33a8262334 | ||
|
|
9b4f7ad696 | ||
|
|
eecd809d9a | ||
|
|
240d3cb8f1 | ||
|
|
5720b7b94c | ||
|
|
3855d7ea02 | ||
|
|
9f3351469d | ||
|
|
2c4a0cf65b | ||
|
|
a8f360c8fd | ||
|
|
b3cff6555f | ||
|
|
69706ecab0 | ||
|
|
05d3b97eae | ||
|
|
a38fb41e37 | ||
|
|
204ae377e3 | ||
|
|
3e5a652874 | ||
|
|
862ae26631 | ||
|
|
9e0208ec71 | ||
|
|
510530973c | ||
|
|
4e69301562 | ||
|
|
df06d4b9a2 | ||
|
|
b60561c3bb | ||
|
|
fffa503968 | ||
|
|
8754157810 | ||
|
|
0763686892 | ||
|
|
50776748a7 | ||
|
|
c07274a6fa | ||
|
|
4084005ee7 | ||
|
|
40fce574cf | ||
|
|
fd761735d4 | ||
|
|
9cb98bdcdc | ||
|
|
b5b1f7ff8a | ||
|
|
a86019d53b | ||
|
|
8cd7d08573 | ||
|
|
6d6f6ed8fc | ||
|
|
c9aed1381f | ||
|
|
49ba5f30c5 | ||
|
|
3c6149fd27 | ||
|
|
23f804eda3 | ||
|
|
4e321db189 | ||
|
|
716fde5784 | ||
|
|
c70b873397 | ||
|
|
4c0da691b8 | ||
|
|
d1d36f9af0 | ||
|
|
56efb4ffba | ||
|
|
540bc71873 | ||
|
|
c1df7ead1a | ||
|
|
d170c807e3 | ||
|
|
50c0abc786 | ||
|
|
c5057127ee | ||
|
|
ea7b1a9592 | ||
|
|
26d483f2d7 | ||
|
|
67fce58708 | ||
|
|
ea5771c442 | ||
|
|
fa8a1faeb3 | ||
|
|
d60a000af6 | ||
|
|
3d68e2b74f | ||
|
|
42f6d48abf | ||
|
|
5587957602 | ||
|
|
1d313ebf25 | ||
|
|
cf92349c1d | ||
|
|
b0ae44bc25 | ||
|
|
0c94124fdf | ||
|
|
22298ddb41 | ||
|
|
6f927b9941 | ||
|
|
dc5626f34d | ||
|
|
2717ec2759 | ||
|
|
d75449ea63 | ||
|
|
034f5b16bd | ||
|
|
ff420f1e67 | ||
|
|
5be771842f | ||
|
|
a131c93a14 | ||
|
|
3da3546ef8 | ||
|
|
47f5223c37 | ||
|
|
b8c50eb0fe | ||
|
|
fe05082ddc | ||
|
|
414acda9e0 | ||
|
|
47e3a5e75a | ||
|
|
573df892bc | ||
|
|
bfced59949 | ||
|
|
9a63b1751b | ||
|
|
53ae8b9bd1 | ||
|
|
bf3cc5a367 | ||
|
|
ac00bc6b70 | ||
|
|
ab62603c5a | ||
|
|
dd247cd541 | ||
|
|
0d7a9f32d6 | ||
|
|
0d85ef4404 | ||
|
|
8e9273a96a | ||
|
|
2dfdaaa4ba | ||
|
|
407094cdcb | ||
|
|
0111db6744 | ||
|
|
a49230c0e1 | ||
|
|
d04abc2021 | ||
|
|
b5368207d6 | ||
|
|
b8400e0c92 | ||
|
|
ef6b6cd279 | ||
|
|
e5903d8d6e | ||
|
|
e2a3db1b82 | ||
|
|
9e220e8416 | ||
|
|
605c233753 | ||
|
|
aafe18c2b5 | ||
|
|
262e8af813 | ||
|
|
75aa4ce8a0 | ||
|
|
a494cdaf92 | ||
|
|
848425418b | ||
|
|
989bed88fe | ||
|
|
99f66200f7 | ||
|
|
b642bd2cfd | ||
|
|
c062b7c9da | ||
|
|
7df7901532 | ||
|
|
9dabce819a | ||
|
|
a019109857 | ||
|
|
46cdf14ecc | ||
|
|
fd5ff20b68 | ||
|
|
81f9666e82 | ||
|
|
aa8659d5c7 | ||
|
|
9df2df0f9f | ||
|
|
98d38d763b | ||
|
|
319a4622b3 | ||
|
|
59b4c6dacb | ||
|
|
ec6d725587 | ||
|
|
6f19649186 | ||
|
|
6a583b9b5b | ||
|
|
6617b79cd8 | ||
|
|
46b695d093 | ||
|
|
de8a017e80 | ||
|
|
b71ec91f57 | ||
|
|
1b7c226779 | ||
|
|
ca5a5b4392 | ||
|
|
6ae7ae0210 | ||
|
|
b911d2fda4 | ||
|
|
847a92f580 | ||
|
|
a346493de1 | ||
|
|
efd5d6efab | ||
|
|
b6df5a4b7f | ||
|
|
34ae56e319 | ||
|
|
5870824d01 | ||
|
|
1dbadbfc35 | ||
|
|
d3f1cd7411 | ||
|
|
a821daadd3 | ||
|
|
a39f4b4487 | ||
|
|
f7b401b9b6 | ||
|
|
c342d18f92 | ||
|
|
e0e52a3090 | ||
|
|
6f92480315 | ||
|
|
490d008edf | ||
|
|
ccee17c573 | ||
|
|
dd4832e40b | ||
|
|
ff5b870a9f | ||
|
|
a371580201 | ||
|
|
b499c575bc | ||
|
|
f5a6268cef | ||
|
|
2df4083602 | ||
|
|
2495fb796d | ||
|
|
f7b49740c1 | ||
|
|
7e765fe726 | ||
|
|
1d339f74d1 | ||
|
|
a3bb288f01 | ||
|
|
0e1226573a | ||
|
|
8151b65d12 | ||
|
|
eefd36b50d | ||
|
|
6f4d769187 | ||
|
|
20b76a703a | ||
|
|
dcc09b7bb5 | ||
|
|
4ea0dee90a | ||
|
|
e61116d35a | ||
|
|
f7256c75d5 | ||
|
|
2696fd1291 | ||
|
|
b139620fba | ||
|
|
97115a9c1c | ||
|
|
36134c61b2 | ||
|
|
77cf0fd87b | ||
|
|
ab77a1cbc0 | ||
|
|
8490892493 | ||
|
|
5f35dffa34 | ||
|
|
89a4b5a6ff | ||
|
|
931de7e39c | ||
|
|
ff41d6aef9 | ||
|
|
8e1ba58551 | ||
|
|
2b1692a860 | ||
|
|
7a2981e21c | ||
|
|
f8717359d7 | ||
|
|
fe395e3a8c | ||
|
|
eb9fe851af | ||
|
|
d61851ad02 | ||
|
|
de7a408903 | ||
|
|
4b0f60fe71 | ||
|
|
a167bcff5e | ||
|
|
fb812e6335 | ||
|
|
3fd557c74a | ||
|
|
9b1272da51 | ||
|
|
ae2402f4a7 | ||
|
|
c98e869564 | ||
|
|
e1a019ec56 | ||
|
|
2d7fcbf23d | ||
|
|
b604177ca1 | ||
|
|
f27597cab5 | ||
|
|
40619c8184 | ||
|
|
b0a5df2838 | ||
|
|
ae9232a2cb | ||
|
|
ad28d0025a | ||
|
|
d6772c5ca5 | ||
|
|
a2400767ed | ||
|
|
1873b655a8 | ||
|
|
e27c2b59c8 | ||
|
|
4b50608642 | ||
|
|
e3a7f9eb7a | ||
|
|
c130b3a92e | ||
|
|
20fb6d6669 | ||
|
|
caf20cd43d | ||
|
|
608d661355 | ||
|
|
31c868818b | ||
|
|
443c4b6cd0 | ||
|
|
ee425bb7f0 | ||
|
|
9d1c026231 | ||
|
|
6d7612ead6 | ||
|
|
b3e31094ff | ||
|
|
c9750fab2c | ||
|
|
5a1348e4d1 | ||
|
|
b64d45a74e | ||
|
|
ba5a4c3945 | ||
|
|
9ba37a932b | ||
|
|
8ce377d033 | ||
|
|
a7f3dafd81 | ||
|
|
fb38b4b906 | ||
|
|
f0a1a90b0e | ||
|
|
fb331d39a6 | ||
|
|
7a3e6e19b1 | ||
|
|
5a063c541d | ||
|
|
eef25ec638 | ||
|
|
7141fb18c1 | ||
|
|
2c92be5e3d | ||
|
|
cae0733149 | ||
|
|
5d6ca7a88e | ||
|
|
23b8a4d364 | ||
|
|
c0df8cb578 | ||
|
|
4693c23a49 | ||
|
|
86364ff278 | ||
|
|
60f1f1cb3d | ||
|
|
ab3c520006 | ||
|
|
3798dcb98d | ||
|
|
9daf290432 | ||
|
|
3438f88c1e | ||
|
|
2c8858ff2d | ||
|
|
45ed9405b0 | ||
|
|
075ca78dd2 | ||
|
|
1d964ef921 | ||
|
|
0c6d9b1d3b | ||
|
|
1713f1222b | ||
|
|
450591d5a9 | ||
|
|
5c4863dfb1 | ||
|
|
c6a82cbc07 | ||
|
|
cc8f074d33 | ||
|
|
196d74c3a0 | ||
|
|
f28e87b240 | ||
|
|
2d77ef4245 | ||
|
|
3f578e24b5 | ||
|
|
fb5ee5e190 | ||
|
|
63e8378310 | ||
|
|
c24ebaf506 | ||
|
|
d3a1f11dfe | ||
|
|
f96e694ff8 | ||
|
|
d5d635e50f | ||
|
|
1ad4ce9822 | ||
|
|
3f971174e4 | ||
|
|
16e257ea32 | ||
|
|
37f1f8ac14 | ||
|
|
474fa9b3ec | ||
|
|
6d7b14ceb5 | ||
|
|
af14832b6c | ||
|
|
9ef185978f | ||
|
|
38bb44664c | ||
|
|
124d924ff5 | ||
|
|
e8091d8add | ||
|
|
500bd53b6a | ||
|
|
6996ca832d | ||
|
|
2e15ab44ab | ||
|
|
2ae5472872 | ||
|
|
98a32790cd | ||
|
|
6dcefcfb71 | ||
|
|
988366e37f | ||
|
|
98a37905b8 | ||
|
|
bd832d0fbb | ||
|
|
1f7e18f2a9 | ||
|
|
105e9c8e88 | ||
|
|
99e1a5f117 | ||
|
|
b35b49f7b3 | ||
|
|
5d064b18e6 | ||
|
|
11ea92288d | ||
|
|
1ea6ae9fd9 | ||
|
|
57d739673a | ||
|
|
4d8f76e922 | ||
|
|
fb41d4ab0f | ||
|
|
023ee688d3 | ||
|
|
5f8f0d8573 | ||
|
|
f56e0a6586 | ||
|
|
2c96420bc4 | ||
|
|
8d95eb57fa | ||
|
|
a9a5e79e85 | ||
|
|
2b720b8d0b | ||
|
|
93a0ab7f0a | ||
|
|
18dd55d1f4 | ||
|
|
c9074d8d96 | ||
|
|
f6c995157e | ||
|
|
a059a9fbdc | ||
|
|
2ac6596ba9 | ||
|
|
2d1f57e839 | ||
|
|
7799ed36f0 | ||
|
|
db5ed345bc | ||
|
|
082c6a9e64 | ||
|
|
b74a4d5225 | ||
|
|
16a572c250 | ||
|
|
6a8a2d6f56 | ||
|
|
237c855f10 | ||
|
|
15d18484e3 | ||
|
|
378e9b5539 | ||
|
|
7a135bd87c | ||
|
|
9e907e36e2 | ||
|
|
9ac71f304d | ||
|
|
ab9b604d02 | ||
|
|
155645307a | ||
|
|
4ca7ac4851 | ||
|
|
02eb24cd57 | ||
|
|
787fbe1bb6 | ||
|
|
7678858bab | ||
|
|
bf7a28f07c | ||
|
|
9e54b1406c | ||
|
|
f52c9772a7 | ||
|
|
ea5203d8c3 | ||
|
|
0fad2f9953 | ||
|
|
d3a9392421 | ||
|
|
208927544d | ||
|
|
7621155a89 | ||
|
|
4ddc4ebf46 | ||
|
|
786f0b5ca2 | ||
|
|
b4ff429bfa | ||
|
|
f2cf0ec459 | ||
|
|
0380d70a46 | ||
|
|
28099b9812 | ||
|
|
2ce4f602c0 | ||
|
|
5e81fb4754 | ||
|
|
c9f1a95343 | ||
|
|
97d8d07947 | ||
|
|
4f0adad78e | ||
|
|
0499005db5 | ||
|
|
aedffb3cfe | ||
|
|
fff96e69db | ||
|
|
abc99c9dd8 | ||
|
|
6e4b76a3b4 | ||
|
|
92d8642133 | ||
|
|
184124586b | ||
|
|
4d32b6976a | ||
|
|
45a99e576d | ||
|
|
fac6d54986 | ||
|
|
036c35729c | ||
|
|
e442fddc66 | ||
|
|
a3c3afba48 | ||
|
|
794ceac440 | ||
|
|
6299d41cda | ||
|
|
2e5ce0249e | ||
|
|
560298655b | ||
|
|
4086df27b2 | ||
|
|
d76ae413c4 | ||
|
|
8b1df2e9ca | ||
|
|
c8855f97e8 | ||
|
|
bbf1aa1668 | ||
|
|
141f3bcec3 | ||
|
|
8f11fd7c62 | ||
|
|
9f960c25a5 | ||
|
|
11a616917a | ||
|
|
a89f03f27d | ||
|
|
3faf36440c | ||
|
|
45d4f46024 | ||
|
|
896f2aeb74 | ||
|
|
7de39611f3 | ||
|
|
7e6be23287 | ||
|
|
cac76d4739 | ||
|
|
194e5dc94e | ||
|
|
f7629362d7 | ||
|
|
ea0c396114 | ||
|
|
057e2d8056 | ||
|
|
487fe21e25 | ||
|
|
54dce9b60e | ||
|
|
f09a3142a6 | ||
|
|
121c8d8a48 | ||
|
|
b9561ec8db | ||
|
|
b1d8eff019 | ||
|
|
f9c4a40d60 | ||
|
|
8e318f76a7 | ||
|
|
7d21ea93a6 | ||
|
|
8630ba4a2d | ||
|
|
17a448e045 | ||
|
|
7ff11dce35 | ||
|
|
e2a4854bcf | ||
|
|
bef96e231d | ||
|
|
325df8a6e3 | ||
|
|
3620f72b6c | ||
|
|
42a90b2d40 | ||
|
|
97aab6950c | ||
|
|
31258247b3 | ||
|
|
beed4e8aa8 | ||
|
|
c60a0bc062 | ||
|
|
733c2d4152 | ||
|
|
79b5857f72 | ||
|
|
7260eba26a | ||
|
|
7e7a1b2caf | ||
|
|
99181e3302 | ||
|
|
d57d2b96d6 | ||
|
|
24bed8c548 | ||
|
|
6c9e704aa8 | ||
|
|
d3eb31e4c3 | ||
|
|
698b01f85a | ||
|
|
4c88e97330 | ||
|
|
25babff827 | ||
|
|
23e833c69e | ||
|
|
22bb3fe876 | ||
|
|
eee10d3ee7 | ||
|
|
c7591045af | ||
|
|
6ddfef6383 | ||
|
|
9852e30b39 | ||
|
|
2d3ce32314 | ||
|
|
d8e0bea110 | ||
|
|
b2cf6a6ea8 | ||
|
|
2ebcd673c8 | ||
|
|
aa5f186a96 | ||
|
|
934f73f696 | ||
|
|
993c6f0e7b | ||
|
|
1d79e22468 | ||
|
|
8ba92d8b99 | ||
|
|
af23258152 | ||
|
|
b2e50b42a3 | ||
|
|
003b4d0218 | ||
|
|
545472f9c4 | ||
|
|
8f781c27f9 | ||
|
|
589dc34b99 | ||
|
|
564622e38b | ||
|
|
d3744d6f66 | ||
|
|
2613ef0633 | ||
|
|
be3cdcd71a | ||
|
|
d48ac09e25 | ||
|
|
e5a0ba7bf3 |
6
.dockerignore
Executable file
6
.dockerignore
Executable file
@@ -0,0 +1,6 @@
|
|||||||
|
target
|
||||||
|
Dockerfile
|
||||||
|
README.md
|
||||||
|
.git
|
||||||
|
.gitignore
|
||||||
|
.gitmodules
|
||||||
41
.travis.yml
41
.travis.yml
@@ -1,14 +1,31 @@
|
|||||||
language: rust
|
language: rust
|
||||||
rust:
|
cache: cargo
|
||||||
- stable
|
os: linux
|
||||||
- beta
|
dist: xenial
|
||||||
- nightly
|
|
||||||
matrix:
|
|
||||||
allow_failures:
|
|
||||||
- rust: nightly
|
|
||||||
fast_finish: true
|
|
||||||
|
|
||||||
script:
|
before_script:
|
||||||
- cargo build --verbose --all
|
- cargo fetch
|
||||||
- cargo test --verbose --all
|
|
||||||
- cargo test --verbose --all --no-default-features --features num
|
jobs:
|
||||||
|
allow_failures:
|
||||||
|
env:
|
||||||
|
- CAN_FAIL=true
|
||||||
|
include:
|
||||||
|
- stage: "Stable: Build"
|
||||||
|
rust: stable
|
||||||
|
script: cargo rustc --verbose -- -D warnings
|
||||||
|
name: "Build Stable"
|
||||||
|
- stage: "Stable: Tests"
|
||||||
|
rust: stable
|
||||||
|
script: cargo test --verbose --all
|
||||||
|
name: "Tests Stable"
|
||||||
|
- stage: "Features"
|
||||||
|
rust: stable
|
||||||
|
script: cargo test --verbose --all --no-default-features --features num
|
||||||
|
name: "num Tests"
|
||||||
|
env: CAN_FAIL=true
|
||||||
|
- stage: "Beta: Build"
|
||||||
|
# - #
|
||||||
|
rust: beta
|
||||||
|
script: cargo rustc --verbose -- -D warnings
|
||||||
|
name: "Build Beta"
|
||||||
|
|||||||
1609
Cargo.lock
generated
1609
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
37
Cargo.toml
37
Cargo.toml
@@ -1,12 +1,15 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "scryer-prolog"
|
name = "scryer-prolog"
|
||||||
version = "0.8.118"
|
version = "0.8.127"
|
||||||
authors = ["Mark Thom <markjordanthom@gmail.com>"]
|
authors = ["Mark Thom <markjordanthom@gmail.com>"]
|
||||||
build = "build.rs"
|
|
||||||
repository = "https://github.com/mthom/scryer-prolog"
|
|
||||||
description = "A modern Prolog implementation written mostly in Rust."
|
|
||||||
license = "BSD-3-Clause"
|
|
||||||
edition = "2018"
|
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-system"]
|
||||||
|
categories = ["command-line-utilities"]
|
||||||
|
build = "build.rs"
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
indexmap = "1.0.2"
|
indexmap = "1.0.2"
|
||||||
@@ -16,16 +19,32 @@ default = ["rug", "prolog_parser/rug"]
|
|||||||
num = ["num-rug-adapter", "prolog_parser/num"]
|
num = ["num-rug-adapter", "prolog_parser/num"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
cpu-time = "1.0.0"
|
||||||
|
crossterm = "0.16.0"
|
||||||
dirs = "2.0.2"
|
dirs = "2.0.2"
|
||||||
|
divrem = "0.1.0"
|
||||||
downcast = "0.10.0"
|
downcast = "0.10.0"
|
||||||
|
git-version = "0.3.4"
|
||||||
|
hostname = "0.3.1"
|
||||||
indexmap = "1.0.2"
|
indexmap = "1.0.2"
|
||||||
lazy_static = "1.4.0"
|
lazy_static = "1.4.0"
|
||||||
libc = "0.2.62"
|
libc = "0.2.62"
|
||||||
nix = "0.15.0"
|
nix = "0.15.0"
|
||||||
num-rug-adapter = { optional = true, version = "0.1.1" }
|
num-rug-adapter = { optional = true, version = "0.1.3" }
|
||||||
ordered-float = "0.5.0"
|
ordered-float = "0.5.0"
|
||||||
prolog_parser = { version = "0.8.40", default-features = false }
|
prolog_parser = { version = "0.8.65", default-features = false }
|
||||||
ref_thread_local = "0.0.0"
|
ref_thread_local = "0.0.0"
|
||||||
rug = { version = "1.4.0", optional = true }
|
rug = { version = "1.4.0", optional = true }
|
||||||
rustyline = "5.0.3"
|
rustyline = "6.0.0"
|
||||||
termion = "1.4.0"
|
unicode_reader = "1.0.0"
|
||||||
|
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"
|
||||||
|
|||||||
30
Dockerfile
Executable file
30
Dockerfile
Executable file
@@ -0,0 +1,30 @@
|
|||||||
|
# Based on https://hub.docker.com/_/rust?tab=description and https://blog.sedrik.se/posts/my-docker-setup-for-rust/
|
||||||
|
|
||||||
|
# The first container is for build purposes only.
|
||||||
|
FROM rust as builder
|
||||||
|
|
||||||
|
WORKDIR /usr/src/scryer-prolog
|
||||||
|
|
||||||
|
# Using a dummy build.rs and src/main.rs with your Cargo.toml lets Docker cache your Rust dependencies and not rebuild
|
||||||
|
# them every time.
|
||||||
|
COPY Cargo.toml .
|
||||||
|
COPY Cargo.lock .
|
||||||
|
RUN mkdir -p src
|
||||||
|
RUN echo "fn main() {}" > src/main.rs
|
||||||
|
RUN echo "fn main() {}" > build.rs
|
||||||
|
RUN cargo build --release
|
||||||
|
|
||||||
|
# We need to touch our real main.rs and build.rs files or else
|
||||||
|
# docker will use the cached ones.
|
||||||
|
COPY . .
|
||||||
|
RUN touch src/main.rs
|
||||||
|
RUN touch build.rs
|
||||||
|
|
||||||
|
RUN cargo build --release
|
||||||
|
|
||||||
|
RUN ls ./target/release
|
||||||
|
|
||||||
|
# Finally, copy the scryer-prolog executable to a slimmer container.
|
||||||
|
FROM debian:buster-slim
|
||||||
|
COPY --from=builder /usr/src/scryer-prolog/target/release/scryer-prolog /usr/local/bin/scryer-prolog
|
||||||
|
CMD ["scryer-prolog"]
|
||||||
403
README.md
403
README.md
@@ -5,6 +5,8 @@ source industrial strength production environment that is also a
|
|||||||
testbed for bleeding edge research in logic and constraint
|
testbed for bleeding edge research in logic and constraint
|
||||||
programming, which is itself written in a high-level language.
|
programming, which is itself written in a high-level language.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
## Phase 1
|
## Phase 1
|
||||||
|
|
||||||
Produce an implementation of the Warren Abstract Machine in Rust, done
|
Produce an implementation of the Warren Abstract Machine in Rust, done
|
||||||
@@ -30,7 +32,7 @@ Extend Scryer Prolog to include the following, among other features:
|
|||||||
- [x] Built-in predicates for list processing and top-level declarative
|
- [x] Built-in predicates for list processing and top-level declarative
|
||||||
control (`setup_call_cleanup/3`, `call_with_inference_limit/3`,
|
control (`setup_call_cleanup/3`, `call_with_inference_limit/3`,
|
||||||
etc.)
|
etc.)
|
||||||
- [x] ~~Default representation of strings as list of chars, using a packed
|
- [x] ~~Default representation of strings as lists of characters, using a packed
|
||||||
internal representation.~~
|
internal representation.~~
|
||||||
- [x] `term_expansion/2` and `goal_expansion/2`.
|
- [x] `term_expansion/2` and `goal_expansion/2`.
|
||||||
- [x] Definite Clause Grammars.
|
- [x] Definite Clause Grammars.
|
||||||
@@ -40,7 +42,7 @@ Extend Scryer Prolog to include the following, among other features:
|
|||||||
- [x] Support for `verify_attributes/3`
|
- [x] Support for `verify_attributes/3`
|
||||||
- [x] Support for `attribute_goals/2` and `project_attributes/2`
|
- [x] Support for `attribute_goals/2` and `project_attributes/2`
|
||||||
- [x] `call_residue_vars/2`
|
- [x] `call_residue_vars/2`
|
||||||
- [x] `if_` and related predicates, following the developments of the
|
- [x] `if_/3` and related predicates, following the developments of the
|
||||||
paper "Indexing `dif/2`".
|
paper "Indexing `dif/2`".
|
||||||
- [x] All-solutions predicates (`findall/{3,4}`, `bagof/3`, `setof/3`, `forall/2`).
|
- [x] All-solutions predicates (`findall/{3,4}`, `bagof/3`, `setof/3`, `forall/2`).
|
||||||
- [x] Clause creation and destruction (`asserta/1`, `assertz/1`,
|
- [x] Clause creation and destruction (`asserta/1`, `assertz/1`,
|
||||||
@@ -52,11 +54,14 @@ Extend Scryer Prolog to include the following, among other features:
|
|||||||
"Delimited Continuations for Prolog").
|
"Delimited Continuations for Prolog").
|
||||||
- [x] Tabling library based on delimited continuations
|
- [x] Tabling library based on delimited continuations
|
||||||
(documented in "Tabling as a Library with Delimited Control").
|
(documented in "Tabling as a Library with Delimited Control").
|
||||||
- [x] A _redone_ representation of strings as difference list of
|
- [x] A _redone_ representation of strings as difference lists of
|
||||||
chars, using a packed internal representation.
|
characters, using a packed internal representation.
|
||||||
- [ ] clp(B) and clp(ℤ) as builtin libraries (_in progress_).
|
- [x] clp(B) and clp(ℤ) as builtin libraries.
|
||||||
- [ ] Streams and predicates for stream control (_in progress_).
|
- [x] Streams and predicates for stream control.
|
||||||
- [ ] An incremental compacting garbage collector satisfying the five
|
- [x] A simple sockets library representing TCP connections as streams.
|
||||||
|
- [ ] Incremental compilation and loading process, newly written,
|
||||||
|
primarily in Prolog. (_in progress_)
|
||||||
|
- [ ] A compacting garbage collector satisfying the five
|
||||||
properties of "Precise Garbage Collection in Prolog."
|
properties of "Precise Garbage Collection in Prolog."
|
||||||
- [ ] Mode declarations.
|
- [ ] Mode declarations.
|
||||||
|
|
||||||
@@ -90,10 +95,18 @@ strings.
|
|||||||
|
|
||||||
## Installing Scryer Prolog
|
## Installing Scryer Prolog
|
||||||
|
|
||||||
|
### Native Install (Unix Only)
|
||||||
|
|
||||||
First, install the latest stable version of
|
First, install the latest stable version of
|
||||||
[Rust](https://www.rust-lang.org/en-US/install.html) using your
|
[Rust](https://www.rust-lang.org/en-US/install.html) using your
|
||||||
preferred method. Then install Scryer Prolog with cargo,
|
preferred method. Scryer tends to use features from newer Rust
|
||||||
like so:
|
releases, whereas Rust packages in Linux distributions, Macports,
|
||||||
|
etc. tend to lag behind. [rustup](http://rustup.rs) will keep your
|
||||||
|
Rust updated to the latest stable release; any existing Rust
|
||||||
|
distribution should be uninstalled from your system before rustup is
|
||||||
|
used.
|
||||||
|
|
||||||
|
Scryer Prolog can be installed with cargo, like so:
|
||||||
|
|
||||||
```
|
```
|
||||||
$> cargo install scryer-prolog
|
$> cargo install scryer-prolog
|
||||||
@@ -117,69 +130,85 @@ $> cargo run [--release]
|
|||||||
The optional `--release` flag will perform various optimizations,
|
The optional `--release` flag will perform various optimizations,
|
||||||
producing a faster executable.
|
producing a faster executable.
|
||||||
|
|
||||||
Note on compatibility: Scryer Prolog should work on Linux, Mac OS X,
|
### Docker Install (All Platforms)
|
||||||
and BSD variants on which Rust runs. Windows support hinges on
|
|
||||||
rustyline and Termion being functional in that environment, which to
|
First, install [Docker](https://docs.docker.com/get-docker/) on Linux,
|
||||||
my knowledge is not presently the case.
|
Windows, or Mac.
|
||||||
|
|
||||||
|
Once Docker is installed, you can download and run Scryer Prolog with a single
|
||||||
|
command:
|
||||||
|
```
|
||||||
|
$> docker run -it mjt128/scryer-prolog
|
||||||
|
```
|
||||||
|
|
||||||
|
To consult your Prolog files, bind mount your programs folder as a
|
||||||
|
[Docker volume](https://docs.docker.com/storage/volumes/):
|
||||||
|
|
||||||
|
```
|
||||||
|
$> docker run -v /home/user/prolog:/mnt -it mjt128/scryer-prolog
|
||||||
|
?- consult('/mnt/program.pl').
|
||||||
|
true.
|
||||||
|
```
|
||||||
|
|
||||||
|
This works on Windows too:
|
||||||
|
|
||||||
|
```
|
||||||
|
$> docker run -v C:\Users\user\Documents\prolog:/mnt -it mjt128/scryer-prolog
|
||||||
|
?- consult('/mnt/program.pl').
|
||||||
|
true.
|
||||||
|
```
|
||||||
|
|
||||||
## Tutorial
|
## Tutorial
|
||||||
To enter a multi-clause predicate, the directive "[user]" is used.
|
|
||||||
|
|
||||||
For example,
|
Prolog files are loaded by specifying them as arguments on the command
|
||||||
```
|
line. For example, to load `program.pl`, use:
|
||||||
?- [user].
|
|
||||||
(type Enter + Ctrl-D to terminate the stream when finished)
|
|
||||||
p(f(f(X)), h(W), Y) :- g(W), h(W), f(X).
|
|
||||||
p(X, Y, Z) :- h(Y), z(Z).
|
|
||||||
?- [user].
|
|
||||||
(type Enter + Ctrl-D to terminate the stream when finished)
|
|
||||||
h(x). h(y).
|
|
||||||
h(z).
|
|
||||||
```
|
|
||||||
In the example, `Enter + Ctrl-D` is used to terminate the standard
|
|
||||||
input stream. The instructive message is always printed.
|
|
||||||
|
|
||||||
Queries are issued as
|
|
||||||
```
|
```
|
||||||
?- p(X, Y, Z).
|
$> scryer-prolog program.pl
|
||||||
```
|
```
|
||||||
|
|
||||||
Pressing `SPACE` will backtrack through other possible answers, if any exist.
|
Loading a Prolog file is also called “consulting” it. The built-in
|
||||||
Pressing `.` will abort the search and return to the prompt.
|
predicate `consult/1` can be used to consult a file from within
|
||||||
|
Prolog:
|
||||||
|
|
||||||
Wildcards work as well:
|
```
|
||||||
|
?- consult('program.pl').
|
||||||
|
```
|
||||||
|
|
||||||
|
As an abbreviation for `consult/1`, you can specify a *list* of
|
||||||
|
program files, given as *atoms*:
|
||||||
|
|
||||||
|
```
|
||||||
|
?- ['program.pl'].
|
||||||
|
```
|
||||||
|
|
||||||
|
The special notation `[user]` is used to read Prolog text from
|
||||||
|
standard input. For example,
|
||||||
|
|
||||||
```
|
```
|
||||||
?- [user].
|
?- [user].
|
||||||
(type Enter + Ctrl-D to terminate the stream when finished)
|
hello(declarative_world).
|
||||||
member(X, [X|_]).
|
hello(pure_world).
|
||||||
member(X, [_|Xs]) :- member(X, Xs).
|
|
||||||
?- member(X, [a, b, c]).
|
|
||||||
true .
|
|
||||||
X = a ;
|
|
||||||
X = b ;
|
|
||||||
X = c ;
|
|
||||||
false.
|
|
||||||
```
|
|
||||||
and so do conjunctive queries:
|
|
||||||
```
|
|
||||||
?- [user].
|
|
||||||
(type Enter + Ctrl-D to terminate the stream when finished)
|
|
||||||
f(X) :- g(X).
|
|
||||||
g(x). g(y). g(z).
|
|
||||||
h(call(f, X)).
|
|
||||||
?- h(X), X.
|
|
||||||
true .
|
|
||||||
X = call(f, x) ;
|
|
||||||
X = call(f, y) ;
|
|
||||||
X = call(f, z).
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Note that the values of variables belonging to successful queries are
|
Pressing `RETURN` followed by `Ctrl-d` stops reading from
|
||||||
printed out, on one line each. Uninstantiated variables are denoted by
|
standard input and consults the entered Prolog text.
|
||||||
a number preceded by an underscore (`X = _0` in an example above).
|
|
||||||
|
After a program is consulted, you can ask *queries* about the
|
||||||
|
predicates it defines. For example, with the program shown above:
|
||||||
|
|
||||||
|
```
|
||||||
|
?- hello(What).
|
||||||
|
What = declarative_world
|
||||||
|
; What = pure_world.
|
||||||
|
```
|
||||||
|
|
||||||
|
Press `SPACE` to show further answers, if any exist. Press `RETURN` or
|
||||||
|
`.` to abort the search and return to the toplevel prompt.
|
||||||
|
Press `h` to show a help message.
|
||||||
|
|
||||||
|
To quit Scryer Prolog, use the standard predicate `halt/0`:
|
||||||
|
|
||||||
To quit scryer-prolog, type
|
|
||||||
```
|
```
|
||||||
?- halt.
|
?- halt.
|
||||||
```
|
```
|
||||||
@@ -190,46 +219,247 @@ Scryer supports dynamic operators. Using the built-in
|
|||||||
arithmetic operators with the usual precedences,
|
arithmetic operators with the usual precedences,
|
||||||
|
|
||||||
```
|
```
|
||||||
?- write_canonical(-5 + 3 - (2 * 4) // 8).
|
?- write_canonical(-5 + 3 - (2 * 4) // 8), nl.
|
||||||
-(+(-(5), 3), //(*(2, 4), 8))
|
-(+(-5,3),//(*(2,4),8))
|
||||||
true.
|
true.
|
||||||
```
|
```
|
||||||
|
|
||||||
New operators can be defined using the `op` declaration.
|
New operators can be defined using the `op` declaration.
|
||||||
|
|
||||||
### Partial strings
|
### Strings and partial strings
|
||||||
|
|
||||||
Scryer has three specialized non-ISO predicates for handling so-called
|
In Scryer Prolog, the default value of the Prolog flag `double_quotes`
|
||||||
"partial strings." Partial strings imitate difference lists of
|
is `chars`, which is also the recommended setting. This means that
|
||||||
characters, but their characters are packed in UTF-8 format, a much
|
double-quoted strings are interpreted as lists of *characters*, in the
|
||||||
more efficient alternative to how lists of characters are represented
|
tradition of Marseille Prolog.
|
||||||
in many other Prologs.
|
|
||||||
|
|
||||||
To use partial strings, the `non_iso` library must be loaded:
|
For example, the following query succeeds:
|
||||||
|
|
||||||
`?- use_module(library(non_iso)).`
|
```
|
||||||
|
?- "abc" = [a,b,c].
|
||||||
|
true.
|
||||||
|
```
|
||||||
|
|
||||||
If `X` is a free variable, the query
|
Internally, strings are represented very compactly in packed
|
||||||
|
UTF-8 encoding. A naive representation of strings as lists of
|
||||||
|
characters would use one memory cell per character, one
|
||||||
|
memory cell per list constructor, and one memory cell for
|
||||||
|
each tail that occurs in the list. Since one memory cell takes
|
||||||
|
8 bytes on 64-bit machines, the packed representation used by
|
||||||
|
Scryer Prolog yields an up to **24-fold reduction** of
|
||||||
|
memory usage, and corresponding reduction of memory accesses when
|
||||||
|
creating and processing strings.
|
||||||
|
|
||||||
`?- partial_string("abc", X, _), X = [a, b, c | Y], partial_string(X),
|
Scryer Prolog uses the same efficient encoding for *partial* strings,
|
||||||
partial_string_tail(X, Tail), Tail == Y.`
|
which appear to Prolog code as partial lists of characters. The
|
||||||
|
predicate `partial_string/3` from `library(iso_ext)` lets you
|
||||||
|
construct partial strings explicitly. For example:
|
||||||
|
|
||||||
will succeed, posting:
|
```
|
||||||
|
?- partial_string("abc", Ls0, Ls).
|
||||||
|
Ls0 = [a,b,c|Ls].
|
||||||
|
```
|
||||||
|
|
||||||
`Tail = Y, X = [a,b,c|Y].`
|
In this case, and as the answer illustrates, `Ls0` is
|
||||||
|
indistinguishable from a partial list with tail `Ls`, while
|
||||||
|
the efficient packed representation is used internally.
|
||||||
|
|
||||||
By all appearances, partial strings are plain Prolog lists.
|
An important design goal of Scryer Prolog is to *automatically* use
|
||||||
|
the efficient string representation whenever possible. Therefore, it
|
||||||
|
is only very rarely necessary to use `partial_string/3` explicitly. In
|
||||||
|
the above example, posting <tt>Ls0 = [a,b,c|Ls]</tt> yields
|
||||||
|
the exact same internal representation, and has the advantage that
|
||||||
|
only the standard predicate `(=)/2` is used.
|
||||||
|
|
||||||
|
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)
|
||||||
|
|
||||||
|
One of the foremost attractions of Prolog is that logical consequences
|
||||||
|
of pure programs can be derived by various execution strategies
|
||||||
|
that differ regarding essential properties such as termination,
|
||||||
|
completeness and efficiency.
|
||||||
|
|
||||||
|
The default execution strategy of Prolog is depth-first search with
|
||||||
|
chronological backtracking. This strategy is very efficient. Its main
|
||||||
|
drawback is that it is *incomplete*: It may fail to find any solution
|
||||||
|
even if one exists.
|
||||||
|
|
||||||
|
Scryer Prolog supports an alternative execution strategy which is
|
||||||
|
called *tabling* and also known as tabled execution and
|
||||||
|
SLG resolution. To enable tabled execution for a predicate, use
|
||||||
|
[`library(tabling)`](src/lib/tabling.pl) and add a `(table)/1`
|
||||||
|
directive for the desired predicate indicator. For example, if we
|
||||||
|
write:
|
||||||
|
|
||||||
|
```
|
||||||
|
:- use_module(library(tabling)).
|
||||||
|
:- table a/0.
|
||||||
|
|
||||||
|
a :- a.
|
||||||
|
```
|
||||||
|
|
||||||
|
Then the query `?- a.` *terminates* (and fails), whereas it
|
||||||
|
does not terminate with the default execution strategy.
|
||||||
|
|
||||||
|
Scryer Prolog implements tabling via *delimited continuations* as
|
||||||
|
described in [*Tabling as a Library with Delimited
|
||||||
|
Control*](https://biblio.ugent.be/publication/6880648/file/6885145.pdf)
|
||||||
|
by Desouter et. al.
|
||||||
|
|
||||||
|
### Constraint Logic Programming (CLP)
|
||||||
|
|
||||||
|
Scryer Prolog provides excellent support for Constraint Logic
|
||||||
|
Programming (CLP), which is the amalgamation of
|
||||||
|
Logic Programming (LP) and Constraints.
|
||||||
|
|
||||||
|
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/lib/atts.pl) as in SICStus Prolog,
|
||||||
|
which is one of the most sophisticated and fastest constraint systems
|
||||||
|
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 solvers.
|
||||||
|
|
||||||
|
These features make Scryer Prolog an ideal platform for teaching,
|
||||||
|
learning and developing portable CLP applications.
|
||||||
|
|
||||||
### Modules
|
### Modules
|
||||||
|
|
||||||
Scryer has a simple predicate-based module system. It provides a
|
Scryer has a simple predicate-based module system. It provides a
|
||||||
way to separate units of code into distinct namespaces, for both
|
way to separate units of code into distinct namespaces, for both
|
||||||
predicates and operators. See the files `src/prolog/lib/*.pl` for
|
predicates and operators. See the files
|
||||||
|
[`src/lib/*.pl`](src/lib) for
|
||||||
examples.
|
examples.
|
||||||
|
|
||||||
At the time of this writing, several control and list processing
|
At the time of this writing, many predicates reside in their own
|
||||||
operators and predicates are hidden in their own modules that have not
|
modules that need to be imported before they can be used.
|
||||||
been exported to the toplevel. To export them, write
|
The modules that ship with Scryer Prolog are also called
|
||||||
|
*library* modules or *libraries*, and include:
|
||||||
|
|
||||||
|
* [`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/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/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/lib/reif.pl)
|
||||||
|
providing `if_/3`, `tfilter/3` and related predicates
|
||||||
|
as described in *Indexing dif/2*.
|
||||||
|
* [`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/lib/pairs.pl)
|
||||||
|
By convention, *pairs* are Prolog terms with
|
||||||
|
principal 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/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.
|
||||||
|
They are declarative replacements for logically flawed
|
||||||
|
lower-level type tests. For instance, instead of `integer(X)`,
|
||||||
|
write `integer_si(X)` to ensure soundness of your programs.
|
||||||
|
"si" stands for *sufficiently instantiated*, and also for
|
||||||
|
*sound inference*.
|
||||||
|
* [`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 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 resolution).
|
||||||
|
* [`format`](src/lib/format.pl)
|
||||||
|
The nonterminal `format_//2` is used to describe formatted output,
|
||||||
|
arranging arguments according to a given format string.
|
||||||
|
The predicates `format/[2,3]`, `portray_clause/[1,2]` and `listing/1`
|
||||||
|
provide formatted *impure* output.
|
||||||
|
* [`assoc`](src/lib/assoc.pl)
|
||||||
|
providing `empty_assoc/1`, `get_assoc/3`, `put_assoc/4` etc.
|
||||||
|
to manage elements in AVL trees which ensure
|
||||||
|
*O*(log(*N*)) access.
|
||||||
|
* [`ordsets`](src/lib/ordsets.pl)
|
||||||
|
represents ordered sets as lists.
|
||||||
|
* [`clpb`](src/lib/clpb.pl)
|
||||||
|
CLP(B): Constraint Logic Programming over Boolean variables,
|
||||||
|
a BDD-based SAT solver provided via the predicates
|
||||||
|
`sat/1`, `taut/2`, `labeling/1` etc.
|
||||||
|
* [`arithmetic`](src/lib/arithmetic.pl)
|
||||||
|
Arithmetic predicates such as `lsb/2`, `msb/2` and
|
||||||
|
`number_to_rational/2`.
|
||||||
|
* [`time`](src/lib/time.pl) Predicates for reasoning about
|
||||||
|
time, including `time/1` to measure the CPU 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/lib/random.pl)
|
||||||
|
Probabilistic predicates and random number generators.
|
||||||
|
* [`http/http_open`](src/lib/http/http_open.pl) Open a stream to
|
||||||
|
read answers from web servers. HTTPS is also supported.
|
||||||
|
* [`sgml`](src/lib/sgml.pl)
|
||||||
|
`load_html/3` and `load_xml/3` represent HTML and XML documents
|
||||||
|
as Prolog 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 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.
|
||||||
|
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 variables.
|
||||||
|
* [`iso_ext`](src/lib/iso_ext.pl)
|
||||||
|
Conforming extensions to and candidates for inclusion in the Prolog
|
||||||
|
ISO 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 (HKDF), password-based key derivation (PBKDF2),
|
||||||
|
public key signatures and signature verification with Ed25519,
|
||||||
|
ECDH key exchange over Curve25519 (X25519), authenticated symmetric
|
||||||
|
encryption with ChaCha20-Poly1305, and reasoning about elliptic curves.
|
||||||
|
|
||||||
|
To use predicates provided by the `lists` library, write:
|
||||||
|
|
||||||
```
|
```
|
||||||
?- use_module(library(lists)).
|
?- use_module(library(lists)).
|
||||||
@@ -264,7 +494,6 @@ REPL:
|
|||||||
|
|
||||||
```
|
```
|
||||||
?- [user].
|
?- [user].
|
||||||
(type Enter + Ctrl-D to terminate the stream when finished)
|
|
||||||
:- module(test, [local_member/2]).
|
:- module(test, [local_member/2]).
|
||||||
:- use_module(library(lists)).
|
:- use_module(library(lists)).
|
||||||
|
|
||||||
@@ -273,3 +502,17 @@ local_member(X, Xs) :- member(X, Xs).
|
|||||||
|
|
||||||
The user listing can also be terminated by placing `end_of_file.` at
|
The user listing can also be terminated by placing `end_of_file.` at
|
||||||
the end of the stream.
|
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)).
|
||||||
|
```
|
||||||
|
|||||||
85
build.rs
85
build.rs
@@ -1,56 +1,55 @@
|
|||||||
extern crate indexmap;
|
extern crate indexmap;
|
||||||
|
|
||||||
use indexmap::IndexSet;
|
|
||||||
|
|
||||||
use std::env;
|
use std::env;
|
||||||
use std::fs::{File, copy, read_dir};
|
use std::fs;
|
||||||
|
use std::fs::File;
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
use std::path::Path;
|
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 out_dir = env::var("OUT_DIR").unwrap();
|
||||||
let dest_path = Path::new(&out_dir).join("libraries.rs");
|
let dest_path = Path::new(&out_dir).join("libraries.rs");
|
||||||
|
|
||||||
let mut libraries = File::create(&dest_path).unwrap();
|
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();
|
libraries
|
||||||
|
.write_all(
|
||||||
for item in paths {
|
b"ref_thread_local! {
|
||||||
let item = item.unwrap().path();
|
|
||||||
|
|
||||||
if let Some(file_name) = item.file_name() {
|
|
||||||
if let Some(ext) = item.extension() {
|
|
||||||
if ext == "pl" {
|
|
||||||
let file_stem = item.file_stem().unwrap();
|
|
||||||
let file_str = file_stem.to_string_lossy().to_uppercase();
|
|
||||||
let dest = Path::new(&out_dir).join(file_name);
|
|
||||||
|
|
||||||
match copy(&item, dest) {
|
|
||||||
Ok(_) => {},
|
|
||||||
Err(e) => panic!("die: {:?}", e)
|
|
||||||
};
|
|
||||||
|
|
||||||
let include_line = format!("static {}: &str = include_str!(\"{}.pl\");\n",
|
|
||||||
file_str, file_stem.to_string_lossy());
|
|
||||||
|
|
||||||
libraries.write_all(include_line.as_bytes()).unwrap();
|
|
||||||
library_index.insert(file_stem.to_string_lossy().to_string());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
libraries.write_all(b"\nref_thread_local! {
|
|
||||||
pub static managed LIBRARIES: IndexMap<&'static str, &'static str> = {
|
pub static managed LIBRARIES: IndexMap<&'static str, &'static str> = {
|
||||||
let mut m = IndexMap::new();\n").unwrap();
|
let mut m = IndexMap::new();\n",
|
||||||
|
)
|
||||||
for item in library_index {
|
.unwrap();
|
||||||
let line = format!("\n m.insert(\"{}\", {});", item, item.to_uppercase());
|
find_prolog_files(&mut libraries, "", &lib_path);
|
||||||
libraries.write_all(line.as_bytes()).unwrap();
|
libraries.write_all(b"\n m\n };\n}\n").unwrap();
|
||||||
}
|
|
||||||
|
|
||||||
libraries.write_all(b"\n\n m\n };
|
|
||||||
}").unwrap();
|
|
||||||
}
|
}
|
||||||
|
|||||||
BIN
logo/scryer.png
Normal file
BIN
logo/scryer.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 128 KiB |
896
logo/scryer.svg
Normal file
896
logo/scryer.svg
Normal 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 |
@@ -1,9 +1,9 @@
|
|||||||
use prolog_parser::ast::*;
|
use crate::prolog_parser::ast::*;
|
||||||
|
|
||||||
use crate::prolog::fixtures::*;
|
use crate::fixtures::*;
|
||||||
use crate::prolog::forms::*;
|
use crate::forms::*;
|
||||||
use crate::prolog::machine::machine_indices::*;
|
use crate::machine::machine_indices::*;
|
||||||
use crate::prolog::targets::*;
|
use crate::targets::*;
|
||||||
|
|
||||||
use std::cell::Cell;
|
use std::cell::Cell;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
@@ -1,26 +1,29 @@
|
|||||||
use prolog_parser::ast::*;
|
use crate::prolog_parser::ast::*;
|
||||||
|
|
||||||
use crate::prolog::clause_types::*;
|
use crate::clause_types::*;
|
||||||
use crate::prolog::fixtures::*;
|
use crate::fixtures::*;
|
||||||
use crate::prolog::forms::*;
|
use crate::forms::*;
|
||||||
use crate::prolog::instructions::*;
|
use crate::instructions::*;
|
||||||
use crate::prolog::iterators::*;
|
use crate::iterators::*;
|
||||||
|
|
||||||
use crate::prolog::machine::machine_errors::*;
|
use crate::machine::heap::*;
|
||||||
use crate::prolog::machine::machine_indices::*;
|
use crate::machine::machine_errors::*;
|
||||||
|
use crate::machine::machine_indices::*;
|
||||||
|
|
||||||
use crate::prolog::ordered_float::*;
|
use crate::ordered_float::*;
|
||||||
use crate::prolog::rug::ops::PowAssign;
|
use crate::rug::ops::PowAssign;
|
||||||
use crate::prolog::rug::{Assign, Integer, Rational};
|
use crate::rug::{Assign, Integer, Rational};
|
||||||
|
|
||||||
use std::cell::Cell;
|
use std::cell::Cell;
|
||||||
use std::cmp::{max, min, Ordering};
|
use std::cmp::{max, min, Ordering};
|
||||||
|
use std::convert::TryFrom;
|
||||||
use std::f64;
|
use std::f64;
|
||||||
use std::num::FpCategory;
|
use std::num::FpCategory;
|
||||||
use std::ops::{Add, Div, Mul, Neg, Sub};
|
use std::ops::{Add, Div, Mul, Neg, Sub};
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use std::vec::Vec;
|
use std::vec::Vec;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
pub struct ArithInstructionIterator<'a> {
|
pub struct ArithInstructionIterator<'a> {
|
||||||
state_stack: Vec<TermIterState<'a>>,
|
state_stack: Vec<TermIterState<'a>>,
|
||||||
}
|
}
|
||||||
@@ -66,6 +69,7 @@ impl<'a> ArithInstructionIterator<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
pub enum ArithTermRef<'a> {
|
pub enum ArithTermRef<'a> {
|
||||||
Constant(&'a Constant),
|
Constant(&'a Constant),
|
||||||
Op(ClauseName, usize), // name, arity.
|
Op(ClauseName, usize), // name, arity.
|
||||||
@@ -107,6 +111,7 @@ impl<'a> Iterator for ArithInstructionIterator<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
pub struct ArithmeticEvaluator<'a> {
|
pub struct ArithmeticEvaluator<'a> {
|
||||||
bindings: &'a AllocVarDict,
|
bindings: &'a AllocVarDict,
|
||||||
interm: Vec<ArithmeticTerm>,
|
interm: Vec<ArithmeticTerm>,
|
||||||
@@ -262,6 +267,9 @@ impl<'a> ArithmeticEvaluator<'a> {
|
|||||||
|
|
||||||
fn push_constant(&mut self, c: &Constant) -> Result<(), ArithmeticError> {
|
fn push_constant(&mut self, c: &Constant) -> Result<(), ArithmeticError> {
|
||||||
match c {
|
match c {
|
||||||
|
&Constant::Fixnum(n) => self
|
||||||
|
.interm
|
||||||
|
.push(ArithmeticTerm::Number(Number::Fixnum(n))),
|
||||||
&Constant::Integer(ref n) => self
|
&Constant::Integer(ref n) => self
|
||||||
.interm
|
.interm
|
||||||
.push(ArithmeticTerm::Number(Number::Integer(n.clone()))),
|
.push(ArithmeticTerm::Number(Number::Integer(n.clone()))),
|
||||||
@@ -316,18 +324,25 @@ impl<'a> ArithmeticEvaluator<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// integer division rounding function -- 9.1.3.1.
|
// integer division rounding function -- 9.1.3.1.
|
||||||
pub fn rnd_i<'a>(n: &'a Number) -> RefOrOwned<'a, Integer> {
|
pub fn rnd_i<'a>(n: &'a Number) -> RefOrOwned<'a, Number> {
|
||||||
match n {
|
match n {
|
||||||
&Number::Integer(ref n) => RefOrOwned::Borrowed(n),
|
&Number::Integer(_) => {
|
||||||
|
RefOrOwned::Borrowed(n)
|
||||||
|
}
|
||||||
&Number::Float(OrderedFloat(f)) => {
|
&Number::Float(OrderedFloat(f)) => {
|
||||||
RefOrOwned::Owned(Integer::from_f64(f.floor()).unwrap_or_else(|| Integer::from(0)))
|
RefOrOwned::Owned(Number::from(
|
||||||
|
Integer::from_f64(f.floor()).unwrap_or_else(|| Integer::from(0))
|
||||||
|
))
|
||||||
|
}
|
||||||
|
&Number::Fixnum(n) => {
|
||||||
|
RefOrOwned::Owned(Number::from(n))
|
||||||
}
|
}
|
||||||
&Number::Rational(ref r) => {
|
&Number::Rational(ref r) => {
|
||||||
let r_ref = r.fract_floor_ref();
|
let r_ref = r.fract_floor_ref();
|
||||||
let (mut fract, mut floor) = (Rational::new(), Integer::new());
|
let (mut fract, mut floor) = (Rational::new(), Integer::new());
|
||||||
|
|
||||||
(&mut fract, &mut floor).assign(r_ref);
|
(&mut fract, &mut floor).assign(r_ref);
|
||||||
RefOrOwned::Owned(floor)
|
|
||||||
|
RefOrOwned::Owned(Number::from(floor))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -335,6 +350,7 @@ pub fn rnd_i<'a>(n: &'a Number) -> RefOrOwned<'a, Integer> {
|
|||||||
// floating point rounding function -- 9.1.4.1.
|
// floating point rounding function -- 9.1.4.1.
|
||||||
pub fn rnd_f(n: &Number) -> f64 {
|
pub fn rnd_f(n: &Number) -> f64 {
|
||||||
match n {
|
match n {
|
||||||
|
&Number::Fixnum(n) => n as f64,
|
||||||
&Number::Integer(ref n) => n.to_f64(),
|
&Number::Integer(ref n) => n.to_f64(),
|
||||||
&Number::Float(OrderedFloat(f)) => f,
|
&Number::Float(OrderedFloat(f)) => f,
|
||||||
&Number::Rational(ref r) => r.to_f64(),
|
&Number::Rational(ref r) => r.to_f64(),
|
||||||
@@ -370,22 +386,32 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn float_fn_to_f(n: isize) -> Result<f64, EvalError> {
|
||||||
|
classify_float(n as f64, rnd_f)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
fn float_i_to_f(n: &Integer) -> Result<f64, EvalError> {
|
fn float_i_to_f(n: &Integer) -> Result<f64, EvalError> {
|
||||||
classify_float(n.to_f64(), rnd_f)
|
classify_float(n.to_f64(), rnd_f)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
fn float_r_to_f(r: &Rational) -> Result<f64, EvalError> {
|
fn float_r_to_f(r: &Rational) -> Result<f64, EvalError> {
|
||||||
classify_float(r.to_f64(), rnd_f)
|
classify_float(r.to_f64(), rnd_f)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
fn add_f(f1: f64, f2: f64) -> Result<OrderedFloat<f64>, EvalError> {
|
fn add_f(f1: f64, f2: f64) -> Result<OrderedFloat<f64>, EvalError> {
|
||||||
Ok(OrderedFloat(classify_float(f1 + f2, rnd_f)?))
|
Ok(OrderedFloat(classify_float(f1 + f2, rnd_f)?))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
fn mul_f(f1: f64, f2: f64) -> Result<OrderedFloat<f64>, EvalError> {
|
fn mul_f(f1: f64, f2: f64) -> Result<OrderedFloat<f64>, EvalError> {
|
||||||
Ok(OrderedFloat(classify_float(f1 * f2, rnd_f)?))
|
Ok(OrderedFloat(classify_float(f1 * f2, rnd_f)?))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
fn div_f(f1: f64, f2: f64) -> Result<OrderedFloat<f64>, EvalError> {
|
fn div_f(f1: f64, f2: f64) -> Result<OrderedFloat<f64>, EvalError> {
|
||||||
if FpCategory::Zero == f2.classify() {
|
if FpCategory::Zero == f2.classify() {
|
||||||
Err(EvalError::ZeroDivisor)
|
Err(EvalError::ZeroDivisor)
|
||||||
@@ -399,23 +425,46 @@ impl Add<Number> for Number {
|
|||||||
|
|
||||||
fn add(self, rhs: Number) -> Self::Output {
|
fn add(self, rhs: Number) -> Self::Output {
|
||||||
match (self, rhs) {
|
match (self, rhs) {
|
||||||
(Number::Integer(n1), Number::Integer(n2)) => Ok(Number::Integer(n1 + n2)), // add_i
|
(Number::Fixnum(n1), Number::Fixnum(n2)) => {
|
||||||
|
Ok(if let Some(result) = n1.checked_add(n2) {
|
||||||
|
Number::Fixnum(result)
|
||||||
|
} else {
|
||||||
|
Number::from(Integer::from(n1) + Integer::from(n2))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
(Number::Fixnum(n1), Number::Integer(n2)) |
|
||||||
|
(Number::Integer(n2), Number::Fixnum(n1)) => {
|
||||||
|
Ok(Number::from(Integer::from(n1) + &*n2))
|
||||||
|
}
|
||||||
|
(Number::Fixnum(n1), Number::Rational(n2)) |
|
||||||
|
(Number::Rational(n2), Number::Fixnum(n1)) => {
|
||||||
|
Ok(Number::from(Rational::from(n1) + &*n2))
|
||||||
|
}
|
||||||
|
(Number::Fixnum(n1), Number::Float(OrderedFloat(n2))) |
|
||||||
|
(Number::Float(OrderedFloat(n2)), Number::Fixnum(n1)) => {
|
||||||
|
Ok(Number::Float(add_f(float_fn_to_f(n1)?, n2)?))
|
||||||
|
}
|
||||||
|
(Number::Integer(n1), Number::Integer(n2)) => {
|
||||||
|
Ok(Number::from(Integer::from(&*n1) + &*n2)) // add_i
|
||||||
|
}
|
||||||
(Number::Integer(n1), Number::Float(OrderedFloat(n2)))
|
(Number::Integer(n1), Number::Float(OrderedFloat(n2)))
|
||||||
| (Number::Float(OrderedFloat(n2)), Number::Integer(n1)) => {
|
| (Number::Float(OrderedFloat(n2)), Number::Integer(n1)) => {
|
||||||
Ok(Number::Float(add_f(float_i_to_f(&n1)?, n2)?))
|
Ok(Number::Float(add_f(float_i_to_f(&n1)?, n2)?))
|
||||||
}
|
}
|
||||||
(Number::Integer(n1), Number::Rational(n2))
|
(Number::Integer(n1), Number::Rational(n2))
|
||||||
| (Number::Rational(n2), Number::Integer(n1)) => {
|
| (Number::Rational(n2), Number::Integer(n1)) => {
|
||||||
Ok(Number::Rational(Rational::from(n1) + n2))
|
Ok(Number::from(Rational::from(&*n1) + &*n2))
|
||||||
}
|
}
|
||||||
(Number::Rational(n1), Number::Float(OrderedFloat(n2)))
|
(Number::Rational(n1), Number::Float(OrderedFloat(n2)))
|
||||||
| (Number::Float(OrderedFloat(n2)), Number::Rational(n1)) => {
|
| (Number::Float(OrderedFloat(n2)), Number::Rational(n1)) => {
|
||||||
Ok(Number::Float(add_f(float_r_to_f(&n1)?, n2)?))
|
Ok(Number::Float(add_f(float_r_to_f(&n1)?, n2)?))
|
||||||
}
|
}
|
||||||
(Number::Float(OrderedFloat(f1)), Number::Float(OrderedFloat(f2))) => {
|
(Number::Float(OrderedFloat(f1)), Number::Float(OrderedFloat(f2))) => {
|
||||||
Ok(Number::Float(add_f(f1, f2)?))
|
Ok(Number::Float(add_f(f1, f2)?))
|
||||||
}
|
}
|
||||||
(Number::Rational(r1), Number::Rational(r2)) => Ok(Number::Rational(r1 + r2)),
|
(Number::Rational(r1), Number::Rational(r2)) => {
|
||||||
|
Ok(Number::from(Rational::from(&*r1) + &*r2))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -425,9 +474,15 @@ impl Neg for Number {
|
|||||||
|
|
||||||
fn neg(self) -> Self::Output {
|
fn neg(self) -> Self::Output {
|
||||||
match self {
|
match self {
|
||||||
Number::Integer(n) => Number::Integer(-n),
|
Number::Fixnum(n) =>
|
||||||
|
if let Some(n) = n.checked_neg() {
|
||||||
|
Number::Fixnum(n)
|
||||||
|
} else {
|
||||||
|
Number::from(-Integer::from(n))
|
||||||
|
}
|
||||||
|
Number::Integer(n) => Number::Integer(Rc::new(-Integer::from(&*n))),
|
||||||
Number::Float(OrderedFloat(f)) => Number::Float(OrderedFloat(-f)),
|
Number::Float(OrderedFloat(f)) => Number::Float(OrderedFloat(-f)),
|
||||||
Number::Rational(r) => Number::Rational(-r),
|
Number::Rational(r) => Number::Rational(Rc::new(-Rational::from(&*r))),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -445,14 +500,35 @@ impl Mul<Number> for Number {
|
|||||||
|
|
||||||
fn mul(self, rhs: Number) -> Self::Output {
|
fn mul(self, rhs: Number) -> Self::Output {
|
||||||
match (self, rhs) {
|
match (self, rhs) {
|
||||||
(Number::Integer(n1), Number::Integer(n2)) => Ok(Number::Integer(n1 * n2)), // mul_i
|
(Number::Fixnum(n1), Number::Fixnum(n2)) => {
|
||||||
|
Ok(if let Some(result) = n1.checked_mul(n2) {
|
||||||
|
Number::Fixnum(result)
|
||||||
|
} else {
|
||||||
|
Number::from(Integer::from(n1) * Integer::from(n2))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
(Number::Fixnum(n1), Number::Integer(n2)) |
|
||||||
|
(Number::Integer(n2), Number::Fixnum(n1)) => {
|
||||||
|
Ok(Number::from(Integer::from(n1) * &*n2))
|
||||||
|
}
|
||||||
|
(Number::Fixnum(n1), Number::Rational(n2)) |
|
||||||
|
(Number::Rational(n2), Number::Fixnum(n1)) => {
|
||||||
|
Ok(Number::from(Rational::from(n1) * &*n2))
|
||||||
|
}
|
||||||
|
(Number::Fixnum(n1), Number::Float(OrderedFloat(n2))) |
|
||||||
|
(Number::Float(OrderedFloat(n2)), Number::Fixnum(n1)) => {
|
||||||
|
Ok(Number::Float(mul_f(float_fn_to_f(n1)?, n2)?))
|
||||||
|
}
|
||||||
|
(Number::Integer(n1), Number::Integer(n2)) => {
|
||||||
|
Ok(Number::Integer(Rc::new(Integer::from(&*n1) * &*n2))) // mul_i
|
||||||
|
}
|
||||||
(Number::Integer(n1), Number::Float(OrderedFloat(n2)))
|
(Number::Integer(n1), Number::Float(OrderedFloat(n2)))
|
||||||
| (Number::Float(OrderedFloat(n2)), Number::Integer(n1)) => {
|
| (Number::Float(OrderedFloat(n2)), Number::Integer(n1)) => {
|
||||||
Ok(Number::Float(mul_f(float_i_to_f(&n1)?, n2)?))
|
Ok(Number::Float(mul_f(float_i_to_f(&n1)?, n2)?))
|
||||||
}
|
}
|
||||||
(Number::Integer(n1), Number::Rational(n2))
|
(Number::Integer(n1), Number::Rational(n2))
|
||||||
| (Number::Rational(n2), Number::Integer(n1)) => {
|
| (Number::Rational(n2), Number::Integer(n1)) => {
|
||||||
Ok(Number::Rational(Rational::from(n1) * n2))
|
Ok(Number::Rational(Rc::new(Rational::from(&*n1) * &*n2)))
|
||||||
}
|
}
|
||||||
(Number::Rational(n1), Number::Float(OrderedFloat(n2)))
|
(Number::Rational(n1), Number::Float(OrderedFloat(n2)))
|
||||||
| (Number::Float(OrderedFloat(n2)), Number::Rational(n1)) => {
|
| (Number::Float(OrderedFloat(n2)), Number::Rational(n1)) => {
|
||||||
@@ -461,7 +537,9 @@ impl Mul<Number> for Number {
|
|||||||
(Number::Float(OrderedFloat(f1)), Number::Float(OrderedFloat(f2))) => {
|
(Number::Float(OrderedFloat(f1)), Number::Float(OrderedFloat(f2))) => {
|
||||||
Ok(Number::Float(mul_f(f1, f2)?))
|
Ok(Number::Float(mul_f(f1, f2)?))
|
||||||
}
|
}
|
||||||
(Number::Rational(r1), Number::Rational(r2)) => Ok(Number::Rational(r1 * r2)),
|
(Number::Rational(r1), Number::Rational(r2)) => {
|
||||||
|
Ok(Number::Rational(Rc::new(Rational::from(&*r1) * &*r2)))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -471,24 +549,72 @@ impl Div<Number> for Number {
|
|||||||
|
|
||||||
fn div(self, rhs: Number) -> Self::Output {
|
fn div(self, rhs: Number) -> Self::Output {
|
||||||
match (self, rhs) {
|
match (self, rhs) {
|
||||||
(Number::Integer(n1), Number::Integer(n2)) => Ok(Number::Float(div_f(
|
(Number::Fixnum(n1), Number::Fixnum(n2)) => {
|
||||||
float_i_to_f(&n1)?,
|
Ok(Number::Float(div_f(
|
||||||
float_i_to_f(&n2)?,
|
float_fn_to_f(n1)?,
|
||||||
)?)),
|
float_fn_to_f(n2)?,
|
||||||
|
)?))
|
||||||
|
}
|
||||||
|
(Number::Fixnum(n1), Number::Integer(n2)) => {
|
||||||
|
Ok(Number::Float(div_f(
|
||||||
|
float_fn_to_f(n1)?,
|
||||||
|
float_i_to_f(&n2)?,
|
||||||
|
)?))
|
||||||
|
}
|
||||||
|
(Number::Integer(n1), Number::Fixnum(n2)) => {
|
||||||
|
Ok(Number::Float(div_f(
|
||||||
|
float_i_to_f(&n1)?,
|
||||||
|
float_fn_to_f(n2)?,
|
||||||
|
)?))
|
||||||
|
}
|
||||||
|
(Number::Fixnum(n1), Number::Rational(n2)) => {
|
||||||
|
Ok(Number::Float(div_f(
|
||||||
|
float_fn_to_f(n1)?,
|
||||||
|
float_r_to_f(&n2)?,
|
||||||
|
)?))
|
||||||
|
}
|
||||||
|
(Number::Rational(n1), Number::Fixnum(n2)) => {
|
||||||
|
Ok(Number::Float(div_f(
|
||||||
|
float_r_to_f(&n1)?,
|
||||||
|
float_fn_to_f(n2)?,
|
||||||
|
)?))
|
||||||
|
}
|
||||||
|
(Number::Fixnum(n1), Number::Float(OrderedFloat(n2))) => {
|
||||||
|
Ok(Number::Float(div_f(
|
||||||
|
float_fn_to_f(n1)?,
|
||||||
|
n2,
|
||||||
|
)?))
|
||||||
|
}
|
||||||
|
(Number::Float(OrderedFloat(n1)), Number::Fixnum(n2)) => {
|
||||||
|
Ok(Number::Float(div_f(
|
||||||
|
n1,
|
||||||
|
float_fn_to_f(n2)?,
|
||||||
|
)?))
|
||||||
|
}
|
||||||
|
(Number::Integer(n1), Number::Integer(n2)) => {
|
||||||
|
Ok(Number::Float(div_f(
|
||||||
|
float_i_to_f(&n1)?,
|
||||||
|
float_i_to_f(&n2)?,
|
||||||
|
)?))
|
||||||
|
}
|
||||||
(Number::Integer(n1), Number::Float(OrderedFloat(n2))) => {
|
(Number::Integer(n1), Number::Float(OrderedFloat(n2))) => {
|
||||||
Ok(Number::Float(div_f(float_i_to_f(&n1)?, n2)?))
|
Ok(Number::Float(div_f(float_i_to_f(&n1)?, n2)?))
|
||||||
}
|
}
|
||||||
(Number::Float(OrderedFloat(n2)), Number::Integer(n1)) => {
|
(Number::Float(OrderedFloat(n2)), Number::Integer(n1)) => {
|
||||||
Ok(Number::Float(div_f(n2, float_i_to_f(&n1)?)?))
|
Ok(Number::Float(div_f(n2, float_i_to_f(&n1)?)?))
|
||||||
}
|
}
|
||||||
(Number::Integer(n1), Number::Rational(n2)) => Ok(Number::Float(div_f(
|
(Number::Integer(n1), Number::Rational(n2)) => {
|
||||||
float_i_to_f(&n1)?,
|
Ok(Number::Float(div_f(
|
||||||
float_r_to_f(&n2)?,
|
float_i_to_f(&n1)?,
|
||||||
)?)),
|
float_r_to_f(&n2)?,
|
||||||
(Number::Rational(n2), Number::Integer(n1)) => Ok(Number::Float(div_f(
|
)?))
|
||||||
float_r_to_f(&n2)?,
|
}
|
||||||
float_i_to_f(&n1)?,
|
(Number::Rational(n2), Number::Integer(n1)) => {
|
||||||
)?)),
|
Ok(Number::Float(div_f(
|
||||||
|
float_r_to_f(&n2)?,
|
||||||
|
float_i_to_f(&n1)?,
|
||||||
|
)?))
|
||||||
|
}
|
||||||
(Number::Rational(n1), Number::Float(OrderedFloat(n2))) => {
|
(Number::Rational(n1), Number::Float(OrderedFloat(n2))) => {
|
||||||
Ok(Number::Float(div_f(float_r_to_f(&n1)?, n2)?))
|
Ok(Number::Float(div_f(float_r_to_f(&n1)?, n2)?))
|
||||||
}
|
}
|
||||||
@@ -506,41 +632,172 @@ impl Div<Number> for Number {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl PartialEq for Number {
|
||||||
|
fn eq(&self, rhs: &Self) -> bool {
|
||||||
|
match (self, rhs) {
|
||||||
|
(&Number::Fixnum(n1), &Number::Fixnum(n2)) => n1.eq(&n2),
|
||||||
|
(&Number::Fixnum(n1), &Number::Integer(ref n2)) => n1.eq(&**n2),
|
||||||
|
(&Number::Integer(ref n1), &Number::Fixnum(n2)) => (&**n1).eq(&n2),
|
||||||
|
(&Number::Fixnum(n1), &Number::Rational(ref n2)) => n1.eq(&**n2),
|
||||||
|
(&Number::Rational(ref n1), &Number::Fixnum(n2)) => (&**n1).eq(&n2),
|
||||||
|
(&Number::Fixnum(n1), &Number::Float(n2)) => OrderedFloat(n1 as f64).eq(&n2),
|
||||||
|
(&Number::Float(n1), &Number::Fixnum(n2)) => n1.eq(&OrderedFloat(n2 as f64)),
|
||||||
|
(&Number::Integer(ref n1), &Number::Integer(ref n2)) => n1.eq(n2),
|
||||||
|
(&Number::Integer(ref n1), Number::Float(n2)) => OrderedFloat(n1.to_f64()).eq(&n2),
|
||||||
|
(&Number::Float(n1), &Number::Integer(ref n2)) => n1.eq(&OrderedFloat(n2.to_f64())),
|
||||||
|
(&Number::Integer(ref n1), &Number::Rational(ref n2)) => {
|
||||||
|
#[cfg(feature = "num")]
|
||||||
|
{
|
||||||
|
&Rational::from(&**n1) == &**n2
|
||||||
|
}
|
||||||
|
#[cfg(not(feature = "num"))]
|
||||||
|
{
|
||||||
|
&**n1 == &**n2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(&Number::Rational(ref n1), &Number::Integer(ref n2)) => {
|
||||||
|
#[cfg(feature = "num")]
|
||||||
|
{
|
||||||
|
&**n1 == &Rational::from(&**n2)
|
||||||
|
}
|
||||||
|
#[cfg(not(feature = "num"))]
|
||||||
|
{
|
||||||
|
&**n1 == &**n2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(&Number::Rational(ref n1), &Number::Float(n2)) => OrderedFloat(n1.to_f64()).eq(&n2),
|
||||||
|
(&Number::Float(n1), &Number::Rational(ref n2)) => n1.eq(&OrderedFloat(n2.to_f64())),
|
||||||
|
(&Number::Float(f1), &Number::Float(f2)) => f1.eq(&f2),
|
||||||
|
(&Number::Rational(ref r1), &Number::Rational(ref r2)) => r1.eq(&r2),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Eq for Number {}
|
||||||
|
|
||||||
impl PartialOrd for Number {
|
impl PartialOrd for Number {
|
||||||
fn partial_cmp(&self, rhs: &Number) -> Option<Ordering> {
|
fn partial_cmp(&self, rhs: &Number) -> Option<Ordering> {
|
||||||
match (self, rhs) {
|
Some(self.cmp(rhs))
|
||||||
(&Number::Integer(ref n1), &Number::Integer(ref n2)) => Some(n1.cmp(n2)),
|
|
||||||
(&Number::Integer(_), Number::Float(_)) => Some(Ordering::Greater),
|
|
||||||
(&Number::Float(_), &Number::Integer(_)) => Some(Ordering::Less),
|
|
||||||
(&Number::Integer(_), &Number::Rational(_)) => Some(Ordering::Greater),
|
|
||||||
(&Number::Rational(_), &Number::Integer(_)) => Some(Ordering::Less),
|
|
||||||
(&Number::Rational(_), Number::Float(_)) => Some(Ordering::Greater),
|
|
||||||
(&Number::Float(_), &Number::Rational(_)) => Some(Ordering::Less),
|
|
||||||
(&Number::Float(f1), &Number::Float(f2)) => Some(f1.cmp(&f2)),
|
|
||||||
(&Number::Rational(ref r1), &Number::Rational(ref r2)) => Some(r1.cmp(&r2)),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Ord for Number {
|
impl Ord for Number {
|
||||||
fn cmp(&self, rhs: &Number) -> Ordering {
|
fn cmp(&self, rhs: &Number) -> Ordering {
|
||||||
match (self, rhs) {
|
match (self, rhs) {
|
||||||
|
(&Number::Fixnum(n1), &Number::Fixnum(n2)) => n1.cmp(&n2),
|
||||||
|
(&Number::Fixnum(n1), Number::Integer(n2)) => Integer::from(n1).cmp(&*n2),
|
||||||
|
(Number::Integer(n1), &Number::Fixnum(n2)) => (&**n1).cmp(&Integer::from(n2)),
|
||||||
|
(&Number::Fixnum(n1), Number::Rational(n2)) => Rational::from(n1).cmp(&*n2),
|
||||||
|
(Number::Rational(n1), &Number::Fixnum(n2)) => (&**n1).cmp(&Rational::from(n2)),
|
||||||
|
(&Number::Fixnum(n1), &Number::Float(n2)) => OrderedFloat(n1 as f64).cmp(&n2),
|
||||||
|
(&Number::Float(n1), &Number::Fixnum(n2)) => n1.cmp(&OrderedFloat(n2 as f64)),
|
||||||
(&Number::Integer(ref n1), &Number::Integer(ref n2)) => n1.cmp(n2),
|
(&Number::Integer(ref n1), &Number::Integer(ref n2)) => n1.cmp(n2),
|
||||||
(&Number::Integer(_), Number::Float(_)) => Ordering::Greater,
|
(&Number::Integer(ref n1), Number::Float(n2)) => OrderedFloat(n1.to_f64()).cmp(&n2),
|
||||||
(&Number::Float(_), &Number::Integer(_)) => Ordering::Less,
|
(&Number::Float(n1), &Number::Integer(ref n2)) => n1.cmp(&OrderedFloat(n2.to_f64())),
|
||||||
(&Number::Integer(_), &Number::Rational(_)) => Ordering::Greater,
|
(&Number::Integer(ref n1), &Number::Rational(ref n2)) => {
|
||||||
(&Number::Rational(_), &Number::Integer(_)) => Ordering::Less,
|
#[cfg(feature = "num")]
|
||||||
(&Number::Rational(_), Number::Float(_)) => Ordering::Greater,
|
{
|
||||||
(&Number::Float(_), &Number::Rational(_)) => Ordering::Less,
|
Rational::from(&**n1).cmp(n2)
|
||||||
|
}
|
||||||
|
#[cfg(not(feature = "num"))]
|
||||||
|
{
|
||||||
|
(&**n1).partial_cmp(&**n2).unwrap_or(Ordering::Less)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(&Number::Rational(ref n1), &Number::Integer(ref n2)) => {
|
||||||
|
#[cfg(feature = "num")]
|
||||||
|
{
|
||||||
|
(&**n1).cmp(&Rational::from(&**n2))
|
||||||
|
}
|
||||||
|
#[cfg(not(feature = "num"))]
|
||||||
|
{
|
||||||
|
(&**n1).partial_cmp(&**n2).unwrap_or(Ordering::Less)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(&Number::Rational(ref n1), &Number::Float(n2)) => OrderedFloat(n1.to_f64()).cmp(&n2),
|
||||||
|
(&Number::Float(n1), &Number::Rational(ref n2)) => n1.cmp(&OrderedFloat(n2.to_f64())),
|
||||||
(&Number::Float(f1), &Number::Float(f2)) => f1.cmp(&f2),
|
(&Number::Float(f1), &Number::Float(f2)) => f1.cmp(&f2),
|
||||||
(&Number::Rational(ref r1), &Number::Rational(ref r2)) => r1.cmp(&r2),
|
(&Number::Rational(ref r1), &Number::Rational(ref r2)) => r1.cmp(&r2),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'a> TryFrom<(Addr, &'a Heap)> for Number {
|
||||||
|
type Error = ();
|
||||||
|
|
||||||
|
fn try_from((addr, heap): (Addr, &'a Heap)) -> Result<Number, Self::Error> {
|
||||||
|
match addr {
|
||||||
|
Addr::Fixnum(n) => {
|
||||||
|
Ok(Number::from(n))
|
||||||
|
}
|
||||||
|
Addr::Float(n) => {
|
||||||
|
Ok(Number::Float(n))
|
||||||
|
}
|
||||||
|
Addr::Usize(n) => {
|
||||||
|
if let Ok(n) = isize::try_from(n) {
|
||||||
|
Ok(Number::from(n))
|
||||||
|
} else {
|
||||||
|
Ok(Number::from(Integer::from(n)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Addr::Con(h) => {
|
||||||
|
Number::try_from(&heap[h])
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
Err(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> TryFrom<&'a HeapCellValue> for Number {
|
||||||
|
type Error = ();
|
||||||
|
|
||||||
|
fn try_from(value: &'a HeapCellValue) -> Result<Number, Self::Error> {
|
||||||
|
match value {
|
||||||
|
HeapCellValue::Addr(addr) => {
|
||||||
|
match addr {
|
||||||
|
&Addr::Fixnum(n) => {
|
||||||
|
Ok(Number::from(n))
|
||||||
|
}
|
||||||
|
&Addr::Float(n) => {
|
||||||
|
Ok(Number::Float(n))
|
||||||
|
}
|
||||||
|
&Addr::Usize(n) => {
|
||||||
|
if let Ok(n) = isize::try_from(n) {
|
||||||
|
Ok(Number::from(n))
|
||||||
|
} else {
|
||||||
|
Ok(Number::from(Integer::from(n)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
Err(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
HeapCellValue::Integer(n) => {
|
||||||
|
Ok(Number::Integer(n.clone()))
|
||||||
|
}
|
||||||
|
HeapCellValue::Rational(n) => {
|
||||||
|
Ok(Number::Rational(n.clone()))
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
Err(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> From<&'a Integer> for Number {
|
||||||
|
#[inline]
|
||||||
|
fn from(src: &'a Integer) -> Self {
|
||||||
|
Number::Integer(Rc::new(Integer::from(src)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Computes n ^ power. Ignores the sign of power.
|
// Computes n ^ power. Ignores the sign of power.
|
||||||
pub fn binary_pow(mut n: Integer, power: Integer) -> Integer {
|
pub fn binary_pow(mut n: Integer, power: &Integer) -> Integer {
|
||||||
let mut power = power.abs();
|
let mut power = Integer::from(power.abs_ref());
|
||||||
|
|
||||||
if power == 0 {
|
if power == 0 {
|
||||||
return Integer::from(1);
|
return Integer::from(1);
|
||||||
@@ -1,14 +1,14 @@
|
|||||||
use prolog_parser::ast::*;
|
use crate::prolog_parser::ast::*;
|
||||||
|
|
||||||
use crate::prolog::forms::Number;
|
use crate::forms::Number;
|
||||||
use crate::prolog::machine::machine_indices::*;
|
use crate::machine::machine_indices::*;
|
||||||
use crate::prolog::rug::rand::RandState;
|
use crate::rug::rand::RandState;
|
||||||
|
|
||||||
use ref_thread_local::RefThreadLocal;
|
use crate::ref_thread_local::RefThreadLocal;
|
||||||
|
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
|
|
||||||
#[derive(Clone, Copy, Eq, PartialEq)]
|
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
|
||||||
pub enum CompareNumberQT {
|
pub enum CompareNumberQT {
|
||||||
GreaterThan,
|
GreaterThan,
|
||||||
LessThan,
|
LessThan,
|
||||||
@@ -31,7 +31,7 @@ impl CompareNumberQT {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, PartialEq, Eq)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
pub enum CompareTermQT {
|
pub enum CompareTermQT {
|
||||||
LessThan,
|
LessThan,
|
||||||
LessThanOrEqual,
|
LessThanOrEqual,
|
||||||
@@ -50,7 +50,7 @@ impl CompareTermQT {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
pub enum ArithmeticTerm {
|
pub enum ArithmeticTerm {
|
||||||
Reg(RegType),
|
Reg(RegType),
|
||||||
Interm(usize),
|
Interm(usize),
|
||||||
@@ -67,7 +67,7 @@ impl ArithmeticTerm {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Eq, PartialEq)]
|
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||||
pub enum InlinedClauseType {
|
pub enum InlinedClauseType {
|
||||||
CompareNumber(CompareNumberQT, ArithmeticTerm, ArithmeticTerm),
|
CompareNumber(CompareNumberQT, ArithmeticTerm, ArithmeticTerm),
|
||||||
IsAtom(RegType),
|
IsAtom(RegType),
|
||||||
@@ -75,7 +75,6 @@ pub enum InlinedClauseType {
|
|||||||
IsCompound(RegType),
|
IsCompound(RegType),
|
||||||
IsInteger(RegType),
|
IsInteger(RegType),
|
||||||
IsRational(RegType),
|
IsRational(RegType),
|
||||||
IsString(RegType),
|
|
||||||
IsFloat(RegType),
|
IsFloat(RegType),
|
||||||
IsNonVar(RegType),
|
IsNonVar(RegType),
|
||||||
IsVar(RegType),
|
IsVar(RegType),
|
||||||
@@ -105,7 +104,6 @@ ref_thread_local! {
|
|||||||
m.insert(("compound", 1), ClauseType::Inlined(InlinedClauseType::IsCompound(r1)));
|
m.insert(("compound", 1), ClauseType::Inlined(InlinedClauseType::IsCompound(r1)));
|
||||||
m.insert(("integer", 1), ClauseType::Inlined(InlinedClauseType::IsInteger(r1)));
|
m.insert(("integer", 1), ClauseType::Inlined(InlinedClauseType::IsInteger(r1)));
|
||||||
m.insert(("rational", 1), ClauseType::Inlined(InlinedClauseType::IsRational(r1)));
|
m.insert(("rational", 1), ClauseType::Inlined(InlinedClauseType::IsRational(r1)));
|
||||||
m.insert(("string", 1), ClauseType::Inlined(InlinedClauseType::IsString(r1)));
|
|
||||||
m.insert(("float", 1), ClauseType::Inlined(InlinedClauseType::IsFloat(r1)));
|
m.insert(("float", 1), ClauseType::Inlined(InlinedClauseType::IsFloat(r1)));
|
||||||
m.insert(("nonvar", 1), ClauseType::Inlined(InlinedClauseType::IsNonVar(r1)));
|
m.insert(("nonvar", 1), ClauseType::Inlined(InlinedClauseType::IsNonVar(r1)));
|
||||||
m.insert(("var", 1), ClauseType::Inlined(InlinedClauseType::IsVar(r1)));
|
m.insert(("var", 1), ClauseType::Inlined(InlinedClauseType::IsVar(r1)));
|
||||||
@@ -117,7 +115,6 @@ ref_thread_local! {
|
|||||||
m.insert(("@>=", 2), ClauseType::BuiltIn(BuiltInClauseType::CompareTerm(CompareTermQT::GreaterThanOrEqual)));
|
m.insert(("@>=", 2), ClauseType::BuiltIn(BuiltInClauseType::CompareTerm(CompareTermQT::GreaterThanOrEqual)));
|
||||||
m.insert(("@=<", 2), ClauseType::BuiltIn(BuiltInClauseType::CompareTerm(CompareTermQT::LessThanOrEqual)));
|
m.insert(("@=<", 2), ClauseType::BuiltIn(BuiltInClauseType::CompareTerm(CompareTermQT::LessThanOrEqual)));
|
||||||
m.insert(("copy_term", 2), ClauseType::BuiltIn(BuiltInClauseType::CopyTerm));
|
m.insert(("copy_term", 2), ClauseType::BuiltIn(BuiltInClauseType::CopyTerm));
|
||||||
m.insert(("cyclic_term", 1), ClauseType::BuiltIn(BuiltInClauseType::CyclicTerm));
|
|
||||||
m.insert(("==", 2), ClauseType::BuiltIn(BuiltInClauseType::Eq));
|
m.insert(("==", 2), ClauseType::BuiltIn(BuiltInClauseType::Eq));
|
||||||
m.insert(("functor", 3), ClauseType::BuiltIn(BuiltInClauseType::Functor));
|
m.insert(("functor", 3), ClauseType::BuiltIn(BuiltInClauseType::Functor));
|
||||||
m.insert(("ground", 1), ClauseType::BuiltIn(BuiltInClauseType::Ground));
|
m.insert(("ground", 1), ClauseType::BuiltIn(BuiltInClauseType::Ground));
|
||||||
@@ -141,7 +138,6 @@ impl InlinedClauseType {
|
|||||||
&InlinedClauseType::IsCompound(..) => "compound",
|
&InlinedClauseType::IsCompound(..) => "compound",
|
||||||
&InlinedClauseType::IsInteger(..) => "integer",
|
&InlinedClauseType::IsInteger(..) => "integer",
|
||||||
&InlinedClauseType::IsRational(..) => "rational",
|
&InlinedClauseType::IsRational(..) => "rational",
|
||||||
&InlinedClauseType::IsString(..) => "string",
|
|
||||||
&InlinedClauseType::IsFloat(..) => "float",
|
&InlinedClauseType::IsFloat(..) => "float",
|
||||||
&InlinedClauseType::IsNonVar(..) => "nonvar",
|
&InlinedClauseType::IsNonVar(..) => "nonvar",
|
||||||
&InlinedClauseType::IsVar(..) => "var",
|
&InlinedClauseType::IsVar(..) => "var",
|
||||||
@@ -149,7 +145,7 @@ impl InlinedClauseType {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Eq, PartialEq)]
|
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
|
||||||
pub enum SystemClauseType {
|
pub enum SystemClauseType {
|
||||||
AbolishClause,
|
AbolishClause,
|
||||||
AbolishModuleClause,
|
AbolishModuleClause,
|
||||||
@@ -160,18 +156,31 @@ pub enum SystemClauseType {
|
|||||||
AtomCodes,
|
AtomCodes,
|
||||||
AtomLength,
|
AtomLength,
|
||||||
BindFromRegister,
|
BindFromRegister,
|
||||||
CallAttributeGoals,
|
|
||||||
CallContinuation,
|
CallContinuation,
|
||||||
CharCode,
|
CharCode,
|
||||||
|
CharType,
|
||||||
CharsToNumber,
|
CharsToNumber,
|
||||||
ClearAttrVarBindings,
|
|
||||||
ClearAttributeGoals,
|
ClearAttributeGoals,
|
||||||
CloneAttributeGoals,
|
CloneAttributeGoals,
|
||||||
CodesToNumber,
|
CodesToNumber,
|
||||||
CopyTermWithoutAttrVars,
|
CopyTermWithoutAttrVars,
|
||||||
CheckCutPoint,
|
CheckCutPoint,
|
||||||
|
Close,
|
||||||
CopyToLiftedHeap,
|
CopyToLiftedHeap,
|
||||||
CreatePartialString,
|
CreatePartialString,
|
||||||
|
CurrentHostname,
|
||||||
|
CurrentInput,
|
||||||
|
CurrentOutput,
|
||||||
|
DirectoryFiles,
|
||||||
|
FileSize,
|
||||||
|
FileExists,
|
||||||
|
DirectoryExists,
|
||||||
|
DirectorySeparator,
|
||||||
|
MakeDirectory,
|
||||||
|
DeleteFile,
|
||||||
|
WorkingDirectory,
|
||||||
|
PathCanonical,
|
||||||
|
FileTime,
|
||||||
DeleteAttribute,
|
DeleteAttribute,
|
||||||
DeleteHeadAttribute,
|
DeleteHeadAttribute,
|
||||||
DynamicModuleResolution(usize),
|
DynamicModuleResolution(usize),
|
||||||
@@ -179,10 +188,15 @@ pub enum SystemClauseType {
|
|||||||
EnqueueAttributedVar,
|
EnqueueAttributedVar,
|
||||||
ExpandGoal,
|
ExpandGoal,
|
||||||
ExpandTerm,
|
ExpandTerm,
|
||||||
FetchAttributeGoals,
|
|
||||||
FetchGlobalVar,
|
FetchGlobalVar,
|
||||||
FetchGlobalVarWithOffset,
|
FetchGlobalVarWithOffset,
|
||||||
|
FirstStream,
|
||||||
|
FlushOutput,
|
||||||
|
GetByte,
|
||||||
GetChar,
|
GetChar,
|
||||||
|
GetNChars,
|
||||||
|
GetCode,
|
||||||
|
GetSingleChar,
|
||||||
ResetAttrVarState,
|
ResetAttrVarState,
|
||||||
TruncateIfNoLiftedHeapGrowthDiff,
|
TruncateIfNoLiftedHeapGrowthDiff,
|
||||||
TruncateIfNoLiftedHeapGrowth,
|
TruncateIfNoLiftedHeapGrowth,
|
||||||
@@ -217,8 +231,17 @@ pub enum SystemClauseType {
|
|||||||
NumberToChars,
|
NumberToChars,
|
||||||
NumberToCodes,
|
NumberToCodes,
|
||||||
OpDeclaration,
|
OpDeclaration,
|
||||||
|
Open,
|
||||||
|
NextStream,
|
||||||
PartialStringTail,
|
PartialStringTail,
|
||||||
|
PeekByte,
|
||||||
|
PeekChar,
|
||||||
|
PeekCode,
|
||||||
PointsToContinuationResetMarker,
|
PointsToContinuationResetMarker,
|
||||||
|
PutByte,
|
||||||
|
PutChar,
|
||||||
|
PutChars,
|
||||||
|
PutCode,
|
||||||
REPL(REPLCodePtr),
|
REPL(REPLCodePtr),
|
||||||
ReadQueryTerm,
|
ReadQueryTerm,
|
||||||
ReadTerm,
|
ReadTerm,
|
||||||
@@ -231,8 +254,12 @@ pub enum SystemClauseType {
|
|||||||
RetractClause,
|
RetractClause,
|
||||||
RestoreCutPolicy,
|
RestoreCutPolicy,
|
||||||
SetCutPoint(RegType),
|
SetCutPoint(RegType),
|
||||||
|
SetInput,
|
||||||
|
SetOutput,
|
||||||
StoreGlobalVar,
|
StoreGlobalVar,
|
||||||
StoreGlobalVarWithOffset,
|
StoreGlobalVarWithOffset,
|
||||||
|
StreamProperty,
|
||||||
|
SetStreamPosition,
|
||||||
InferenceLevel,
|
InferenceLevel,
|
||||||
CleanUpBlock,
|
CleanUpBlock,
|
||||||
EraseBall,
|
EraseBall,
|
||||||
@@ -243,7 +270,10 @@ pub enum SystemClauseType {
|
|||||||
GetDoubleQuotes,
|
GetDoubleQuotes,
|
||||||
InstallNewBlock,
|
InstallNewBlock,
|
||||||
Maybe,
|
Maybe,
|
||||||
RawInputReadChar,
|
CpuNow,
|
||||||
|
CurrentTime,
|
||||||
|
QuotedToken,
|
||||||
|
ReadTermFromChars,
|
||||||
ResetBlock,
|
ResetBlock,
|
||||||
ReturnFromVerifyAttr,
|
ReturnFromVerifyAttr,
|
||||||
SetBall,
|
SetBall,
|
||||||
@@ -251,7 +281,13 @@ pub enum SystemClauseType {
|
|||||||
SetDoubleQuotes,
|
SetDoubleQuotes,
|
||||||
SetSeed,
|
SetSeed,
|
||||||
SkipMaxList,
|
SkipMaxList,
|
||||||
|
Sleep,
|
||||||
|
SocketClientOpen,
|
||||||
|
SocketServerOpen,
|
||||||
|
SocketServerAccept,
|
||||||
|
SocketServerClose,
|
||||||
Succeed,
|
Succeed,
|
||||||
|
TermAttributedVariables,
|
||||||
TermVariables,
|
TermVariables,
|
||||||
TruncateLiftedHeapTo,
|
TruncateLiftedHeapTo,
|
||||||
UnifyWithOccursCheck,
|
UnifyWithOccursCheck,
|
||||||
@@ -260,6 +296,26 @@ pub enum SystemClauseType {
|
|||||||
Variant,
|
Variant,
|
||||||
WAMInstructions,
|
WAMInstructions,
|
||||||
WriteTerm,
|
WriteTerm,
|
||||||
|
WriteTermToChars,
|
||||||
|
ScryerPrologVersion,
|
||||||
|
CryptoRandomByte,
|
||||||
|
CryptoDataHash,
|
||||||
|
CryptoDataHKDF,
|
||||||
|
CryptoPasswordHash,
|
||||||
|
CryptoDataEncrypt,
|
||||||
|
CryptoDataDecrypt,
|
||||||
|
CryptoCurveScalarMult,
|
||||||
|
Ed25519Sign,
|
||||||
|
Ed25519Verify,
|
||||||
|
Ed25519NewKeyPair,
|
||||||
|
Ed25519KeyPairPublicKey,
|
||||||
|
Curve25519ScalarMult,
|
||||||
|
LoadHTML,
|
||||||
|
LoadXML,
|
||||||
|
GetEnv,
|
||||||
|
SetEnv,
|
||||||
|
UnsetEnv,
|
||||||
|
CharsBase64,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SystemClauseType {
|
impl SystemClauseType {
|
||||||
@@ -274,9 +330,9 @@ impl SystemClauseType {
|
|||||||
&SystemClauseType::AtomCodes => clause_name!("$atom_codes"),
|
&SystemClauseType::AtomCodes => clause_name!("$atom_codes"),
|
||||||
&SystemClauseType::AtomLength => clause_name!("$atom_length"),
|
&SystemClauseType::AtomLength => clause_name!("$atom_length"),
|
||||||
&SystemClauseType::BindFromRegister => clause_name!("$bind_from_register"),
|
&SystemClauseType::BindFromRegister => clause_name!("$bind_from_register"),
|
||||||
&SystemClauseType::CallAttributeGoals => clause_name!("$call_attribute_goals"),
|
|
||||||
&SystemClauseType::CallContinuation => clause_name!("$call_continuation"),
|
&SystemClauseType::CallContinuation => clause_name!("$call_continuation"),
|
||||||
&SystemClauseType::CharCode => clause_name!("$char_code"),
|
&SystemClauseType::CharCode => clause_name!("$char_code"),
|
||||||
|
&SystemClauseType::CharType => clause_name!("$char_type"),
|
||||||
&SystemClauseType::CharsToNumber => clause_name!("$chars_to_number"),
|
&SystemClauseType::CharsToNumber => clause_name!("$chars_to_number"),
|
||||||
&SystemClauseType::CheckCutPoint => clause_name!("$check_cp"),
|
&SystemClauseType::CheckCutPoint => clause_name!("$check_cp"),
|
||||||
&SystemClauseType::ClearAttributeGoals => clause_name!("$clear_attribute_goals"),
|
&SystemClauseType::ClearAttributeGoals => clause_name!("$clear_attribute_goals"),
|
||||||
@@ -284,18 +340,31 @@ impl SystemClauseType {
|
|||||||
&SystemClauseType::CodesToNumber => clause_name!("$codes_to_number"),
|
&SystemClauseType::CodesToNumber => clause_name!("$codes_to_number"),
|
||||||
&SystemClauseType::CopyTermWithoutAttrVars => clause_name!("$copy_term_without_attr_vars"),
|
&SystemClauseType::CopyTermWithoutAttrVars => clause_name!("$copy_term_without_attr_vars"),
|
||||||
&SystemClauseType::CreatePartialString => clause_name!("$create_partial_string"),
|
&SystemClauseType::CreatePartialString => clause_name!("$create_partial_string"),
|
||||||
|
&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::CompileBatch) => clause_name!("$compile_batch"),
|
||||||
&SystemClauseType::REPL(REPLCodePtr::UseModule) => clause_name!("$use_module"),
|
&SystemClauseType::REPL(REPLCodePtr::UseModule) => clause_name!("$use_module"),
|
||||||
&SystemClauseType::REPL(REPLCodePtr::UseQualifiedModule) => {
|
&SystemClauseType::REPL(REPLCodePtr::UseQualifiedModule) => {
|
||||||
clause_name!("$use_qualified_module")
|
clause_name!("$use_qualified_module")
|
||||||
}
|
}
|
||||||
&SystemClauseType::REPL(REPLCodePtr::UseModuleFromFile) => {
|
&SystemClauseType::REPL(REPLCodePtr::UseModuleFromFile) => {
|
||||||
clause_name!("$use_module_from_file")
|
clause_name!("$use_module_from_file")
|
||||||
}
|
}
|
||||||
&SystemClauseType::REPL(REPLCodePtr::UseQualifiedModuleFromFile) => {
|
&SystemClauseType::REPL(REPLCodePtr::UseQualifiedModuleFromFile) => {
|
||||||
clause_name!("$use_qualified_module_from_file")
|
clause_name!("$use_qualified_module_from_file")
|
||||||
}
|
}
|
||||||
&SystemClauseType::ClearAttrVarBindings => clause_name!("$clear_attr_var_bindings"),
|
&SystemClauseType::Close => clause_name!("$close"),
|
||||||
&SystemClauseType::CopyToLiftedHeap => clause_name!("$copy_to_lh"),
|
&SystemClauseType::CopyToLiftedHeap => clause_name!("$copy_to_lh"),
|
||||||
&SystemClauseType::DeleteAttribute => clause_name!("$del_attr_non_head"),
|
&SystemClauseType::DeleteAttribute => clause_name!("$del_attr_non_head"),
|
||||||
&SystemClauseType::DeleteHeadAttribute => clause_name!("$del_attr_head"),
|
&SystemClauseType::DeleteHeadAttribute => clause_name!("$del_attr_head"),
|
||||||
@@ -304,12 +373,17 @@ impl SystemClauseType {
|
|||||||
&SystemClauseType::EnqueueAttributedVar => clause_name!("$enqueue_attr_var"),
|
&SystemClauseType::EnqueueAttributedVar => clause_name!("$enqueue_attr_var"),
|
||||||
&SystemClauseType::ExpandTerm => clause_name!("$expand_term"),
|
&SystemClauseType::ExpandTerm => clause_name!("$expand_term"),
|
||||||
&SystemClauseType::ExpandGoal => clause_name!("$expand_goal"),
|
&SystemClauseType::ExpandGoal => clause_name!("$expand_goal"),
|
||||||
&SystemClauseType::FetchAttributeGoals => clause_name!("$fetch_attribute_goals"),
|
|
||||||
&SystemClauseType::FetchGlobalVar => clause_name!("$fetch_global_var"),
|
&SystemClauseType::FetchGlobalVar => clause_name!("$fetch_global_var"),
|
||||||
&SystemClauseType::FetchGlobalVarWithOffset => {
|
&SystemClauseType::FetchGlobalVarWithOffset => {
|
||||||
clause_name!("$fetch_global_var_with_offset")
|
clause_name!("$fetch_global_var_with_offset")
|
||||||
}
|
}
|
||||||
|
&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::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"),
|
&SystemClauseType::ResetAttrVarState => clause_name!("$reset_attr_var_state"),
|
||||||
&SystemClauseType::TruncateIfNoLiftedHeapGrowth => {
|
&SystemClauseType::TruncateIfNoLiftedHeapGrowth => {
|
||||||
clause_name!("$truncate_if_no_lh_growth")
|
clause_name!("$truncate_if_no_lh_growth")
|
||||||
@@ -338,15 +412,21 @@ impl SystemClauseType {
|
|||||||
&SystemClauseType::GetSCCCleaner => clause_name!("$get_scc_cleaner"),
|
&SystemClauseType::GetSCCCleaner => clause_name!("$get_scc_cleaner"),
|
||||||
&SystemClauseType::Halt => clause_name!("$halt"),
|
&SystemClauseType::Halt => clause_name!("$halt"),
|
||||||
&SystemClauseType::HeadIsDynamic => clause_name!("$head_is_dynamic"),
|
&SystemClauseType::HeadIsDynamic => clause_name!("$head_is_dynamic"),
|
||||||
&SystemClauseType::OpDeclaration => clause_name!("$op$"),
|
&SystemClauseType::Open => clause_name!("$open"),
|
||||||
|
&SystemClauseType::OpDeclaration => clause_name!("$op"),
|
||||||
&SystemClauseType::InstallSCCCleaner => clause_name!("$install_scc_cleaner"),
|
&SystemClauseType::InstallSCCCleaner => clause_name!("$install_scc_cleaner"),
|
||||||
&SystemClauseType::InstallInferenceCounter => {
|
&SystemClauseType::InstallInferenceCounter => {
|
||||||
clause_name!("$install_inference_counter")
|
clause_name!("$install_inference_counter")
|
||||||
}
|
}
|
||||||
&SystemClauseType::IsPartialString => clause_name!("$is_partial_string"),
|
&SystemClauseType::IsPartialString => clause_name!("$is_partial_string"),
|
||||||
&SystemClauseType::PartialStringTail => clause_name!("$partial_string_tail"),
|
&SystemClauseType::PartialStringTail => clause_name!("$partial_string_tail"),
|
||||||
|
&SystemClauseType::PeekByte => clause_name!("$peek_byte"),
|
||||||
|
&SystemClauseType::PeekChar => clause_name!("$peek_char"),
|
||||||
|
&SystemClauseType::PeekCode => clause_name!("$peek_code"),
|
||||||
&SystemClauseType::LiftedHeapLength => clause_name!("$lh_length"),
|
&SystemClauseType::LiftedHeapLength => clause_name!("$lh_length"),
|
||||||
&SystemClauseType::Maybe => clause_name!("maybe"),
|
&SystemClauseType::Maybe => clause_name!("maybe"),
|
||||||
|
&SystemClauseType::CpuNow => clause_name!("$cpu_now"),
|
||||||
|
&SystemClauseType::CurrentTime => clause_name!("$current_time"),
|
||||||
&SystemClauseType::ModuleAssertDynamicPredicateToFront => {
|
&SystemClauseType::ModuleAssertDynamicPredicateToFront => {
|
||||||
clause_name!("$module_asserta")
|
clause_name!("$module_asserta")
|
||||||
}
|
}
|
||||||
@@ -356,19 +436,38 @@ impl SystemClauseType {
|
|||||||
&SystemClauseType::ModuleHeadIsDynamic => clause_name!("$module_head_is_dynamic"),
|
&SystemClauseType::ModuleHeadIsDynamic => clause_name!("$module_head_is_dynamic"),
|
||||||
&SystemClauseType::ModuleExists => clause_name!("$module_exists"),
|
&SystemClauseType::ModuleExists => clause_name!("$module_exists"),
|
||||||
&SystemClauseType::ModuleOf => clause_name!("$module_of"),
|
&SystemClauseType::ModuleOf => clause_name!("$module_of"),
|
||||||
|
&SystemClauseType::NextStream => clause_name!("$next_stream"),
|
||||||
&SystemClauseType::NoSuchPredicate => clause_name!("$no_such_predicate"),
|
&SystemClauseType::NoSuchPredicate => clause_name!("$no_such_predicate"),
|
||||||
&SystemClauseType::NumberToChars => clause_name!("$number_to_chars"),
|
&SystemClauseType::NumberToChars => clause_name!("$number_to_chars"),
|
||||||
&SystemClauseType::NumberToCodes => clause_name!("$number_to_codes"),
|
&SystemClauseType::NumberToCodes => clause_name!("$number_to_codes"),
|
||||||
&SystemClauseType::PointsToContinuationResetMarker => {
|
&SystemClauseType::PointsToContinuationResetMarker => {
|
||||||
clause_name!("$points_to_cont_reset_marker")
|
clause_name!("$points_to_cont_reset_marker")
|
||||||
}
|
}
|
||||||
&SystemClauseType::RawInputReadChar => clause_name!("$raw_input_read_char"),
|
&SystemClauseType::PutByte => {
|
||||||
|
clause_name!("$put_byte")
|
||||||
|
}
|
||||||
|
&SystemClauseType::PutChar => {
|
||||||
|
clause_name!("$put_char")
|
||||||
|
}
|
||||||
|
&SystemClauseType::PutChars => {
|
||||||
|
clause_name!("$put_chars")
|
||||||
|
}
|
||||||
|
&SystemClauseType::PutCode => {
|
||||||
|
clause_name!("$put_code")
|
||||||
|
}
|
||||||
|
&SystemClauseType::QuotedToken => {
|
||||||
|
clause_name!("$quoted_token")
|
||||||
|
}
|
||||||
&SystemClauseType::RedoAttrVarBinding => clause_name!("$redo_attr_var_binding"),
|
&SystemClauseType::RedoAttrVarBinding => clause_name!("$redo_attr_var_binding"),
|
||||||
&SystemClauseType::RemoveCallPolicyCheck => clause_name!("$remove_call_policy_check"),
|
&SystemClauseType::RemoveCallPolicyCheck => clause_name!("$remove_call_policy_check"),
|
||||||
&SystemClauseType::RemoveInferenceCounter => clause_name!("$remove_inference_counter"),
|
&SystemClauseType::RemoveInferenceCounter => clause_name!("$remove_inference_counter"),
|
||||||
&SystemClauseType::RestoreCutPolicy => clause_name!("$restore_cut_policy"),
|
&SystemClauseType::RestoreCutPolicy => clause_name!("$restore_cut_policy"),
|
||||||
&SystemClauseType::SetCutPoint(_) => clause_name!("$set_cp"),
|
&SystemClauseType::SetCutPoint(_) => clause_name!("$set_cp"),
|
||||||
|
&SystemClauseType::SetInput => clause_name!("$set_input"),
|
||||||
|
&SystemClauseType::SetOutput => clause_name!("$set_output"),
|
||||||
&SystemClauseType::SetSeed => clause_name!("$set_seed"),
|
&SystemClauseType::SetSeed => clause_name!("$set_seed"),
|
||||||
|
&SystemClauseType::StreamProperty => clause_name!("$stream_property"),
|
||||||
|
&SystemClauseType::SetStreamPosition => clause_name!("$set_stream_position"),
|
||||||
&SystemClauseType::StoreGlobalVar => clause_name!("$store_global_var"),
|
&SystemClauseType::StoreGlobalVar => clause_name!("$store_global_var"),
|
||||||
&SystemClauseType::StoreGlobalVarWithOffset => {
|
&SystemClauseType::StoreGlobalVarWithOffset => {
|
||||||
clause_name!("$store_global_var_with_offset")
|
clause_name!("$store_global_var_with_offset")
|
||||||
@@ -385,6 +484,7 @@ impl SystemClauseType {
|
|||||||
&SystemClauseType::NextEP => clause_name!("$nextEP"),
|
&SystemClauseType::NextEP => clause_name!("$nextEP"),
|
||||||
&SystemClauseType::ReadQueryTerm => clause_name!("$read_query_term"),
|
&SystemClauseType::ReadQueryTerm => clause_name!("$read_query_term"),
|
||||||
&SystemClauseType::ReadTerm => clause_name!("$read_term"),
|
&SystemClauseType::ReadTerm => clause_name!("$read_term"),
|
||||||
|
&SystemClauseType::ReadTermFromChars => clause_name!("$read_term_from_chars"),
|
||||||
&SystemClauseType::ResetGlobalVarAtKey => clause_name!("$reset_global_var_at_key"),
|
&SystemClauseType::ResetGlobalVarAtKey => clause_name!("$reset_global_var_at_key"),
|
||||||
&SystemClauseType::ResetGlobalVarAtOffset => clause_name!("$reset_global_var_at_offset"),
|
&SystemClauseType::ResetGlobalVarAtOffset => clause_name!("$reset_global_var_at_offset"),
|
||||||
&SystemClauseType::RetractClause => clause_name!("$retract_clause"),
|
&SystemClauseType::RetractClause => clause_name!("$retract_clause"),
|
||||||
@@ -395,7 +495,13 @@ impl SystemClauseType {
|
|||||||
&SystemClauseType::SetCutPointByDefault(_) => clause_name!("$set_cp_by_default"),
|
&SystemClauseType::SetCutPointByDefault(_) => clause_name!("$set_cp_by_default"),
|
||||||
&SystemClauseType::SetDoubleQuotes => clause_name!("$set_double_quotes"),
|
&SystemClauseType::SetDoubleQuotes => clause_name!("$set_double_quotes"),
|
||||||
&SystemClauseType::SkipMaxList => clause_name!("$skip_max_list"),
|
&SystemClauseType::SkipMaxList => clause_name!("$skip_max_list"),
|
||||||
|
&SystemClauseType::Sleep => clause_name!("$sleep"),
|
||||||
|
&SystemClauseType::SocketClientOpen => clause_name!("$socket_client_open"),
|
||||||
|
&SystemClauseType::SocketServerOpen => clause_name!("$socket_server_open"),
|
||||||
|
&SystemClauseType::SocketServerAccept => clause_name!("$socket_server_accept"),
|
||||||
|
&SystemClauseType::SocketServerClose => clause_name!("$socket_server_close"),
|
||||||
&SystemClauseType::Succeed => clause_name!("$succeed"),
|
&SystemClauseType::Succeed => clause_name!("$succeed"),
|
||||||
|
&SystemClauseType::TermAttributedVariables => clause_name!("$term_attributed_variables"),
|
||||||
&SystemClauseType::TermVariables => clause_name!("$term_variables"),
|
&SystemClauseType::TermVariables => clause_name!("$term_variables"),
|
||||||
&SystemClauseType::TruncateLiftedHeapTo => clause_name!("$truncate_lh_to"),
|
&SystemClauseType::TruncateLiftedHeapTo => clause_name!("$truncate_lh_to"),
|
||||||
&SystemClauseType::UnifyWithOccursCheck => clause_name!("$unify_with_occurs_check"),
|
&SystemClauseType::UnifyWithOccursCheck => clause_name!("$unify_with_occurs_check"),
|
||||||
@@ -404,6 +510,26 @@ impl SystemClauseType {
|
|||||||
&SystemClauseType::Variant => clause_name!("$variant"),
|
&SystemClauseType::Variant => clause_name!("$variant"),
|
||||||
&SystemClauseType::WAMInstructions => clause_name!("$wam_instructions"),
|
&SystemClauseType::WAMInstructions => clause_name!("$wam_instructions"),
|
||||||
&SystemClauseType::WriteTerm => clause_name!("$write_term"),
|
&SystemClauseType::WriteTerm => clause_name!("$write_term"),
|
||||||
|
&SystemClauseType::WriteTermToChars => clause_name!("$write_term_to_chars"),
|
||||||
|
&SystemClauseType::ScryerPrologVersion => clause_name!("$scryer_prolog_version"),
|
||||||
|
&SystemClauseType::CryptoRandomByte => clause_name!("$crypto_random_byte"),
|
||||||
|
&SystemClauseType::CryptoDataHash => clause_name!("$crypto_data_hash"),
|
||||||
|
&SystemClauseType::CryptoDataHKDF => clause_name!("$crypto_data_hkdf"),
|
||||||
|
&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::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"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -420,11 +546,10 @@ impl SystemClauseType {
|
|||||||
("$module_assertz", 5) => Some(SystemClauseType::ModuleAssertDynamicPredicateToBack),
|
("$module_assertz", 5) => Some(SystemClauseType::ModuleAssertDynamicPredicateToBack),
|
||||||
("$asserta", 4) => Some(SystemClauseType::AssertDynamicPredicateToFront),
|
("$asserta", 4) => Some(SystemClauseType::AssertDynamicPredicateToFront),
|
||||||
("$assertz", 4) => Some(SystemClauseType::AssertDynamicPredicateToBack),
|
("$assertz", 4) => Some(SystemClauseType::AssertDynamicPredicateToBack),
|
||||||
("$call_attribute_goals", 2) => Some(SystemClauseType::CallAttributeGoals),
|
|
||||||
("$call_continuation", 1) => Some(SystemClauseType::CallContinuation),
|
("$call_continuation", 1) => Some(SystemClauseType::CallContinuation),
|
||||||
("$char_code", 2) => Some(SystemClauseType::CharCode),
|
("$char_code", 2) => Some(SystemClauseType::CharCode),
|
||||||
|
("$char_type", 2) => Some(SystemClauseType::CharType),
|
||||||
("$chars_to_number", 2) => Some(SystemClauseType::CharsToNumber),
|
("$chars_to_number", 2) => Some(SystemClauseType::CharsToNumber),
|
||||||
("$clear_attr_var_bindings", 0) => Some(SystemClauseType::ClearAttrVarBindings),
|
|
||||||
("$clear_attribute_goals", 0) => Some(SystemClauseType::ClearAttributeGoals),
|
("$clear_attribute_goals", 0) => Some(SystemClauseType::ClearAttributeGoals),
|
||||||
("$clone_attribute_goals", 1) => Some(SystemClauseType::CloneAttributeGoals),
|
("$clone_attribute_goals", 1) => Some(SystemClauseType::CloneAttributeGoals),
|
||||||
("$codes_to_number", 2) => Some(SystemClauseType::CodesToNumber),
|
("$codes_to_number", 2) => Some(SystemClauseType::CodesToNumber),
|
||||||
@@ -433,6 +558,13 @@ impl SystemClauseType {
|
|||||||
("$check_cp", 1) => Some(SystemClauseType::CheckCutPoint),
|
("$check_cp", 1) => Some(SystemClauseType::CheckCutPoint),
|
||||||
("$compile_batch", 0) => Some(SystemClauseType::REPL(REPLCodePtr::CompileBatch)),
|
("$compile_batch", 0) => Some(SystemClauseType::REPL(REPLCodePtr::CompileBatch)),
|
||||||
("$copy_to_lh", 2) => Some(SystemClauseType::CopyToLiftedHeap),
|
("$copy_to_lh", 2) => Some(SystemClauseType::CopyToLiftedHeap),
|
||||||
|
("$close", 2) => Some(SystemClauseType::Close),
|
||||||
|
("$current_hostname", 1) => Some(SystemClauseType::CurrentHostname),
|
||||||
|
("$current_input", 1) => Some(SystemClauseType::CurrentInput),
|
||||||
|
("$current_output", 1) => Some(SystemClauseType::CurrentOutput),
|
||||||
|
("$first_stream", 1) => Some(SystemClauseType::FirstStream),
|
||||||
|
("$next_stream", 2) => Some(SystemClauseType::NextStream),
|
||||||
|
("$flush_output", 1) => Some(SystemClauseType::FlushOutput),
|
||||||
("$del_attr_non_head", 1) => Some(SystemClauseType::DeleteAttribute),
|
("$del_attr_non_head", 1) => Some(SystemClauseType::DeleteAttribute),
|
||||||
("$del_attr_head", 1) => Some(SystemClauseType::DeleteHeadAttribute),
|
("$del_attr_head", 1) => Some(SystemClauseType::DeleteHeadAttribute),
|
||||||
("$get_next_db_ref", 2) => Some(SystemClauseType::GetNextDBRef),
|
("$get_next_db_ref", 2) => Some(SystemClauseType::GetNextDBRef),
|
||||||
@@ -443,16 +575,34 @@ impl SystemClauseType {
|
|||||||
("$enqueue_attribute_goal", 1) => Some(SystemClauseType::EnqueueAttributeGoal),
|
("$enqueue_attribute_goal", 1) => Some(SystemClauseType::EnqueueAttributeGoal),
|
||||||
("$enqueue_attr_var", 1) => Some(SystemClauseType::EnqueueAttributedVar),
|
("$enqueue_attr_var", 1) => Some(SystemClauseType::EnqueueAttributedVar),
|
||||||
("$partial_string_tail", 2) => Some(SystemClauseType::PartialStringTail),
|
("$partial_string_tail", 2) => Some(SystemClauseType::PartialStringTail),
|
||||||
|
("$peek_byte", 2) => Some(SystemClauseType::PeekByte),
|
||||||
|
("$peek_char", 2) => Some(SystemClauseType::PeekChar),
|
||||||
|
("$peek_code", 2) => Some(SystemClauseType::PeekCode),
|
||||||
("$is_partial_string", 1) => Some(SystemClauseType::IsPartialString),
|
("$is_partial_string", 1) => Some(SystemClauseType::IsPartialString),
|
||||||
("$expand_term", 2) => Some(SystemClauseType::ExpandTerm),
|
("$expand_term", 2) => Some(SystemClauseType::ExpandTerm),
|
||||||
("$expand_goal", 2) => Some(SystemClauseType::ExpandGoal),
|
("$expand_goal", 2) => Some(SystemClauseType::ExpandGoal),
|
||||||
("$fetch_attribute_goals", 1) => Some(SystemClauseType::FetchAttributeGoals),
|
|
||||||
("$fetch_global_var", 2) => Some(SystemClauseType::FetchGlobalVar),
|
("$fetch_global_var", 2) => Some(SystemClauseType::FetchGlobalVar),
|
||||||
("$fetch_global_var_with_offset", 3) => Some(SystemClauseType::FetchGlobalVarWithOffset),
|
("$fetch_global_var_with_offset", 3) => Some(SystemClauseType::FetchGlobalVarWithOffset),
|
||||||
("$get_char", 1) => Some(SystemClauseType::GetChar),
|
("$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) => {
|
("$points_to_cont_reset_marker", 1) => {
|
||||||
Some(SystemClauseType::PointsToContinuationResetMarker)
|
Some(SystemClauseType::PointsToContinuationResetMarker)
|
||||||
}
|
}
|
||||||
|
("$put_byte", 2) => {
|
||||||
|
Some(SystemClauseType::PutByte)
|
||||||
|
}
|
||||||
|
("$put_char", 2) => {
|
||||||
|
Some(SystemClauseType::PutChar)
|
||||||
|
}
|
||||||
|
("$put_chars", 2) => {
|
||||||
|
Some(SystemClauseType::PutChars)
|
||||||
|
}
|
||||||
|
("$put_code", 2) => {
|
||||||
|
Some(SystemClauseType::PutCode)
|
||||||
|
}
|
||||||
("$reset_attr_var_state", 0) => Some(SystemClauseType::ResetAttrVarState),
|
("$reset_attr_var_state", 0) => Some(SystemClauseType::ResetAttrVarState),
|
||||||
("$truncate_if_no_lh_growth", 1) => {
|
("$truncate_if_no_lh_growth", 1) => {
|
||||||
Some(SystemClauseType::TruncateIfNoLiftedHeapGrowth)
|
Some(SystemClauseType::TruncateIfNoLiftedHeapGrowth)
|
||||||
@@ -468,12 +618,14 @@ impl SystemClauseType {
|
|||||||
("$get_lh_from_offset_diff", 3) => Some(SystemClauseType::GetLiftedHeapFromOffsetDiff),
|
("$get_lh_from_offset_diff", 3) => Some(SystemClauseType::GetLiftedHeapFromOffsetDiff),
|
||||||
("$get_double_quotes", 1) => Some(SystemClauseType::GetDoubleQuotes),
|
("$get_double_quotes", 1) => Some(SystemClauseType::GetDoubleQuotes),
|
||||||
("$get_scc_cleaner", 1) => Some(SystemClauseType::GetSCCCleaner),
|
("$get_scc_cleaner", 1) => Some(SystemClauseType::GetSCCCleaner),
|
||||||
("$halt", 0) => Some(SystemClauseType::Halt),
|
("$halt", 1) => Some(SystemClauseType::Halt),
|
||||||
("$head_is_dynamic", 1) => Some(SystemClauseType::HeadIsDynamic),
|
("$head_is_dynamic", 1) => Some(SystemClauseType::HeadIsDynamic),
|
||||||
("$install_scc_cleaner", 2) => Some(SystemClauseType::InstallSCCCleaner),
|
("$install_scc_cleaner", 2) => Some(SystemClauseType::InstallSCCCleaner),
|
||||||
("$install_inference_counter", 3) => Some(SystemClauseType::InstallInferenceCounter),
|
("$install_inference_counter", 3) => Some(SystemClauseType::InstallInferenceCounter),
|
||||||
("$lh_length", 1) => Some(SystemClauseType::LiftedHeapLength),
|
("$lh_length", 1) => Some(SystemClauseType::LiftedHeapLength),
|
||||||
("$maybe", 0) => Some(SystemClauseType::Maybe),
|
("$maybe", 0) => Some(SystemClauseType::Maybe),
|
||||||
|
("$cpu_now", 1) => Some(SystemClauseType::CpuNow),
|
||||||
|
("$current_time", 1) => Some(SystemClauseType::CurrentTime),
|
||||||
("$module_exists", 1) => Some(SystemClauseType::ModuleExists),
|
("$module_exists", 1) => Some(SystemClauseType::ModuleExists),
|
||||||
("$module_of", 2) => Some(SystemClauseType::ModuleOf),
|
("$module_of", 2) => Some(SystemClauseType::ModuleOf),
|
||||||
("$module_retract_clause", 5) => Some(SystemClauseType::ModuleRetractClause),
|
("$module_retract_clause", 5) => Some(SystemClauseType::ModuleRetractClause),
|
||||||
@@ -482,11 +634,16 @@ impl SystemClauseType {
|
|||||||
("$number_to_chars", 2) => Some(SystemClauseType::NumberToChars),
|
("$number_to_chars", 2) => Some(SystemClauseType::NumberToChars),
|
||||||
("$number_to_codes", 2) => Some(SystemClauseType::NumberToCodes),
|
("$number_to_codes", 2) => Some(SystemClauseType::NumberToCodes),
|
||||||
("$op", 3) => Some(SystemClauseType::OpDeclaration),
|
("$op", 3) => Some(SystemClauseType::OpDeclaration),
|
||||||
|
("$open", 7) => Some(SystemClauseType::Open),
|
||||||
("$redo_attr_var_binding", 2) => Some(SystemClauseType::RedoAttrVarBinding),
|
("$redo_attr_var_binding", 2) => Some(SystemClauseType::RedoAttrVarBinding),
|
||||||
("$remove_call_policy_check", 1) => Some(SystemClauseType::RemoveCallPolicyCheck),
|
("$remove_call_policy_check", 1) => Some(SystemClauseType::RemoveCallPolicyCheck),
|
||||||
("$remove_inference_counter", 2) => Some(SystemClauseType::RemoveInferenceCounter),
|
("$remove_inference_counter", 2) => Some(SystemClauseType::RemoveInferenceCounter),
|
||||||
("$restore_cut_policy", 0) => Some(SystemClauseType::RestoreCutPolicy),
|
("$restore_cut_policy", 0) => Some(SystemClauseType::RestoreCutPolicy),
|
||||||
("$set_cp", 1) => Some(SystemClauseType::SetCutPoint(temp_v!(1))),
|
("$set_cp", 1) => Some(SystemClauseType::SetCutPoint(temp_v!(1))),
|
||||||
|
("$set_input", 1) => Some(SystemClauseType::SetInput),
|
||||||
|
("$set_output", 1) => Some(SystemClauseType::SetOutput),
|
||||||
|
("$stream_property", 3) => Some(SystemClauseType::StreamProperty),
|
||||||
|
("$set_stream_position", 2) => Some(SystemClauseType::SetStreamPosition),
|
||||||
("$inference_level", 2) => Some(SystemClauseType::InferenceLevel),
|
("$inference_level", 2) => Some(SystemClauseType::InferenceLevel),
|
||||||
("$clean_up_block", 1) => Some(SystemClauseType::CleanUpBlock),
|
("$clean_up_block", 1) => Some(SystemClauseType::CleanUpBlock),
|
||||||
("$erase_ball", 0) => Some(SystemClauseType::EraseBall),
|
("$erase_ball", 0) => Some(SystemClauseType::EraseBall),
|
||||||
@@ -498,10 +655,11 @@ impl SystemClauseType {
|
|||||||
("$get_current_block", 1) => Some(SystemClauseType::GetCurrentBlock),
|
("$get_current_block", 1) => Some(SystemClauseType::GetCurrentBlock),
|
||||||
("$get_cp", 1) => Some(SystemClauseType::GetCutPoint),
|
("$get_cp", 1) => Some(SystemClauseType::GetCutPoint),
|
||||||
("$install_new_block", 1) => Some(SystemClauseType::InstallNewBlock),
|
("$install_new_block", 1) => Some(SystemClauseType::InstallNewBlock),
|
||||||
("$raw_input_read_char", 1) => Some(SystemClauseType::RawInputReadChar),
|
("$quoted_token", 1) => Some(SystemClauseType::QuotedToken),
|
||||||
("$nextEP", 3) => Some(SystemClauseType::NextEP),
|
("$nextEP", 3) => Some(SystemClauseType::NextEP),
|
||||||
("$read_query_term", 2) => Some(SystemClauseType::ReadQueryTerm),
|
("$read_query_term", 5) => Some(SystemClauseType::ReadQueryTerm),
|
||||||
("$read_term", 2) => Some(SystemClauseType::ReadTerm),
|
("$read_term", 5) => Some(SystemClauseType::ReadTerm),
|
||||||
|
("$read_term_from_chars", 2) => Some(SystemClauseType::ReadTermFromChars),
|
||||||
("$reset_block", 1) => Some(SystemClauseType::ResetBlock),
|
("$reset_block", 1) => Some(SystemClauseType::ResetBlock),
|
||||||
("$reset_cont_marker", 0) => Some(SystemClauseType::ResetContinuationMarker),
|
("$reset_cont_marker", 0) => Some(SystemClauseType::ResetContinuationMarker),
|
||||||
("$reset_global_var_at_key", 1) => Some(SystemClauseType::ResetGlobalVarAtKey),
|
("$reset_global_var_at_key", 1) => Some(SystemClauseType::ResetGlobalVarAtKey),
|
||||||
@@ -513,35 +671,70 @@ impl SystemClauseType {
|
|||||||
("$set_double_quotes", 1) => Some(SystemClauseType::SetDoubleQuotes),
|
("$set_double_quotes", 1) => Some(SystemClauseType::SetDoubleQuotes),
|
||||||
("$set_seed", 1) => Some(SystemClauseType::SetSeed),
|
("$set_seed", 1) => Some(SystemClauseType::SetSeed),
|
||||||
("$skip_max_list", 4) => Some(SystemClauseType::SkipMaxList),
|
("$skip_max_list", 4) => Some(SystemClauseType::SkipMaxList),
|
||||||
|
("$sleep", 1) => Some(SystemClauseType::Sleep),
|
||||||
|
("$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),
|
||||||
("$store_global_var", 2) => Some(SystemClauseType::StoreGlobalVar),
|
("$store_global_var", 2) => Some(SystemClauseType::StoreGlobalVar),
|
||||||
("$store_global_var_with_offset", 2) => Some(SystemClauseType::StoreGlobalVarWithOffset),
|
("$store_global_var_with_offset", 2) => Some(SystemClauseType::StoreGlobalVarWithOffset),
|
||||||
|
("$term_attributed_variables", 2) => Some(SystemClauseType::TermAttributedVariables),
|
||||||
("$term_variables", 2) => Some(SystemClauseType::TermVariables),
|
("$term_variables", 2) => Some(SystemClauseType::TermVariables),
|
||||||
("$truncate_lh_to", 1) => Some(SystemClauseType::TruncateLiftedHeapTo),
|
("$truncate_lh_to", 1) => Some(SystemClauseType::TruncateLiftedHeapTo),
|
||||||
("$unwind_environments", 0) => Some(SystemClauseType::UnwindEnvironments),
|
("$unwind_environments", 0) => Some(SystemClauseType::UnwindEnvironments),
|
||||||
("$unwind_stack", 0) => Some(SystemClauseType::UnwindStack),
|
("$unwind_stack", 0) => Some(SystemClauseType::UnwindStack),
|
||||||
("$unify_with_occurs_check", 2) => Some(SystemClauseType::UnifyWithOccursCheck),
|
("$unify_with_occurs_check", 2) => Some(SystemClauseType::UnifyWithOccursCheck),
|
||||||
("$use_module", 1) => Some(SystemClauseType::REPL(REPLCodePtr::UseModule)),
|
("$directory_files", 2) => Some(SystemClauseType::DirectoryFiles),
|
||||||
("$use_module_from_file", 1) =>
|
("$file_size", 2) => Some(SystemClauseType::FileSize),
|
||||||
Some(SystemClauseType::REPL(REPLCodePtr::UseModuleFromFile)),
|
("$file_exists", 1) => Some(SystemClauseType::FileExists),
|
||||||
("$use_qualified_module", 2) =>
|
("$directory_exists", 1) => Some(SystemClauseType::DirectoryExists),
|
||||||
Some(SystemClauseType::REPL(REPLCodePtr::UseQualifiedModule)),
|
("$directory_separator", 1) => Some(SystemClauseType::DirectorySeparator),
|
||||||
("$use_qualified_module_from_file", 2) =>
|
("$make_directory", 1) => Some(SystemClauseType::MakeDirectory),
|
||||||
Some(SystemClauseType::REPL(REPLCodePtr::UseQualifiedModuleFromFile)),
|
("$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)),
|
||||||
|
("$use_qualified_module", 2) =>
|
||||||
|
Some(SystemClauseType::REPL(REPLCodePtr::UseQualifiedModule)),
|
||||||
|
("$use_qualified_module_from_file", 2) =>
|
||||||
|
Some(SystemClauseType::REPL(REPLCodePtr::UseQualifiedModuleFromFile)),
|
||||||
("$variant", 2) => Some(SystemClauseType::Variant),
|
("$variant", 2) => Some(SystemClauseType::Variant),
|
||||||
("$write_term", 5) => Some(SystemClauseType::WriteTerm),
|
|
||||||
("$wam_instructions", 3) => Some(SystemClauseType::WAMInstructions),
|
("$wam_instructions", 3) => Some(SystemClauseType::WAMInstructions),
|
||||||
|
("$write_term", 7) => Some(SystemClauseType::WriteTerm),
|
||||||
|
("$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", 4) => Some(SystemClauseType::CryptoDataHash),
|
||||||
|
("$crypto_data_hkdf", 7) => Some(SystemClauseType::CryptoDataHKDF),
|
||||||
|
("$crypto_password_hash", 4) => Some(SystemClauseType::CryptoPasswordHash),
|
||||||
|
("$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", 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,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Eq, PartialEq)]
|
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||||
pub enum BuiltInClauseType {
|
pub enum BuiltInClauseType {
|
||||||
AcyclicTerm,
|
AcyclicTerm,
|
||||||
Arg,
|
Arg,
|
||||||
Compare,
|
Compare,
|
||||||
CompareTerm(CompareTermQT),
|
CompareTerm(CompareTermQT),
|
||||||
CyclicTerm,
|
|
||||||
CopyTerm,
|
CopyTerm,
|
||||||
Eq,
|
Eq,
|
||||||
Functor,
|
Functor,
|
||||||
@@ -554,7 +747,7 @@ pub enum BuiltInClauseType {
|
|||||||
Sort,
|
Sort,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
pub enum ClauseType {
|
pub enum ClauseType {
|
||||||
BuiltIn(BuiltInClauseType),
|
BuiltIn(BuiltInClauseType),
|
||||||
CallN,
|
CallN,
|
||||||
@@ -572,7 +765,6 @@ impl BuiltInClauseType {
|
|||||||
&BuiltInClauseType::Arg => clause_name!("arg"),
|
&BuiltInClauseType::Arg => clause_name!("arg"),
|
||||||
&BuiltInClauseType::Compare => clause_name!("compare"),
|
&BuiltInClauseType::Compare => clause_name!("compare"),
|
||||||
&BuiltInClauseType::CompareTerm(qt) => clause_name!(qt.name()),
|
&BuiltInClauseType::CompareTerm(qt) => clause_name!(qt.name()),
|
||||||
&BuiltInClauseType::CyclicTerm => clause_name!("cyclic_term"),
|
|
||||||
&BuiltInClauseType::CopyTerm => clause_name!("copy_term"),
|
&BuiltInClauseType::CopyTerm => clause_name!("copy_term"),
|
||||||
&BuiltInClauseType::Eq => clause_name!("=="),
|
&BuiltInClauseType::Eq => clause_name!("=="),
|
||||||
&BuiltInClauseType::Functor => clause_name!("functor"),
|
&BuiltInClauseType::Functor => clause_name!("functor"),
|
||||||
@@ -592,7 +784,6 @@ impl BuiltInClauseType {
|
|||||||
&BuiltInClauseType::Arg => 3,
|
&BuiltInClauseType::Arg => 3,
|
||||||
&BuiltInClauseType::Compare => 2,
|
&BuiltInClauseType::Compare => 2,
|
||||||
&BuiltInClauseType::CompareTerm(_) => 2,
|
&BuiltInClauseType::CompareTerm(_) => 2,
|
||||||
&BuiltInClauseType::CyclicTerm => 1,
|
|
||||||
&BuiltInClauseType::CopyTerm => 2,
|
&BuiltInClauseType::CopyTerm => 2,
|
||||||
&BuiltInClauseType::Eq => 2,
|
&BuiltInClauseType::Eq => 2,
|
||||||
&BuiltInClauseType::Functor => 3,
|
&BuiltInClauseType::Functor => 3,
|
||||||
@@ -1,28 +1,30 @@
|
|||||||
use prolog_parser::ast::*;
|
use crate::prolog_parser::ast::*;
|
||||||
|
|
||||||
use crate::prolog::allocator::*;
|
use crate::allocator::*;
|
||||||
use crate::prolog::arithmetic::*;
|
use crate::arithmetic::*;
|
||||||
use crate::prolog::clause_types::*;
|
use crate::clause_types::*;
|
||||||
use crate::prolog::fixtures::*;
|
use crate::fixtures::*;
|
||||||
use crate::prolog::forms::*;
|
use crate::forms::*;
|
||||||
use crate::prolog::indexing::*;
|
use crate::indexing::*;
|
||||||
use crate::prolog::instructions::*;
|
use crate::instructions::*;
|
||||||
use crate::prolog::iterators::*;
|
use crate::iterators::*;
|
||||||
use crate::prolog::machine::machine_indices::*;
|
use crate::machine::machine_indices::*;
|
||||||
use crate::prolog::targets::*;
|
use crate::targets::*;
|
||||||
|
|
||||||
use indexmap::IndexMap;
|
use crate::indexmap::{IndexMap, IndexSet};
|
||||||
|
|
||||||
use std::cell::Cell;
|
use std::cell::Cell;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use std::vec::Vec;
|
use std::vec::Vec;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
pub struct CodeGenerator<TermMarker> {
|
pub struct CodeGenerator<TermMarker> {
|
||||||
marker: TermMarker,
|
marker: TermMarker,
|
||||||
pub var_count: IndexMap<Rc<Var>, usize>,
|
pub var_count: IndexMap<Rc<Var>, usize>,
|
||||||
non_counted_bt: bool,
|
non_counted_bt: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
pub struct ConjunctInfo<'a> {
|
pub struct ConjunctInfo<'a> {
|
||||||
pub perm_vs: VariableFixtures<'a>,
|
pub perm_vs: VariableFixtures<'a>,
|
||||||
pub num_of_chunks: usize,
|
pub num_of_chunks: usize,
|
||||||
@@ -50,56 +52,45 @@ impl<'a> ConjunctInfo<'a> {
|
|||||||
self.has_deep_cut as usize
|
self.has_deep_cut as usize
|
||||||
}
|
}
|
||||||
|
|
||||||
fn mark_unsafe_vars<Alloc: Allocator<'a>>(
|
fn mark_unsafe_vars(
|
||||||
&self,
|
&self,
|
||||||
mut unsafe_var_marker: UnsafeVarMarker,
|
mut unsafe_var_marker: UnsafeVarMarker,
|
||||||
marker: &Alloc,
|
code: &mut Code,
|
||||||
code: &mut Code
|
|
||||||
) {
|
) {
|
||||||
// target the last goal of the rule for handling unsafe variables.
|
if code.is_empty() {
|
||||||
// we use this weird logic to find the last goal.
|
return;
|
||||||
let right_index = if let Some(Line::Control(_)) = code.last() {
|
}
|
||||||
if code.len() >= 2 {
|
|
||||||
code.len() - 2
|
|
||||||
} else {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if code.len() >= 1 {
|
|
||||||
code.len() - 1
|
|
||||||
} else {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut index = right_index;
|
let mut code_index = 0;
|
||||||
|
|
||||||
if let Line::Query(_) = &code[right_index] {
|
for phase in 0 .. {
|
||||||
while let Line::Query(_) = &code[index] {
|
while let Line::Query(ref query_instr) = &code[code_index] {
|
||||||
if index == 0 {
|
if !unsafe_var_marker.mark_safe_vars(query_instr) {
|
||||||
break;
|
unsafe_var_marker.mark_phase(query_instr, phase);
|
||||||
} else {
|
|
||||||
index -= 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
code_index += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Line::Query(_) = &code[index] {
|
if code_index + 1 < code.len() {
|
||||||
|
code_index += 1;
|
||||||
} else {
|
} else {
|
||||||
index += 1;
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
code_index = 0;
|
||||||
|
|
||||||
|
for phase in 0 .. {
|
||||||
|
while let Line::Query(ref mut query_instr) = &mut code[code_index] {
|
||||||
|
unsafe_var_marker.mark_unsafe_vars(query_instr, phase);
|
||||||
|
code_index += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe_var_marker.record_unsafe_vars(&self.perm_vs, marker);
|
if code_index + 1 < code.len() {
|
||||||
|
code_index += 1;
|
||||||
for line in code.iter() {
|
} else {
|
||||||
if let Line::Query(ref query_instr) = line {
|
break;
|
||||||
unsafe_var_marker.mark_safe_vars(query_instr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for index in index..right_index + 1 {
|
|
||||||
if let &mut Line::Query(ref mut query_instr) = &mut code[index] {
|
|
||||||
unsafe_var_marker.mark_unsafe_vars(query_instr);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -131,31 +122,45 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
|
|||||||
*self.var_count.get(var).unwrap()
|
*self.var_count.get(var).unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn mark_var_in_non_callable(
|
||||||
|
&mut self,
|
||||||
|
name: Rc<Var>,
|
||||||
|
term_loc: GenContext,
|
||||||
|
vr: &'a Cell<VarReg>,
|
||||||
|
code: &mut Code,
|
||||||
|
) -> RegType {
|
||||||
|
let mut target = Vec::new();
|
||||||
|
self.marker.mark_var(name, Level::Shallow, vr, term_loc, &mut target);
|
||||||
|
|
||||||
|
if !target.is_empty() {
|
||||||
|
code.extend(target.into_iter().map(Line::Query));
|
||||||
|
}
|
||||||
|
|
||||||
|
vr.get().norm()
|
||||||
|
}
|
||||||
|
|
||||||
fn mark_non_callable(
|
fn mark_non_callable(
|
||||||
&mut self,
|
&mut self,
|
||||||
name: Rc<Var>,
|
name: Rc<Var>,
|
||||||
arity: usize,
|
arg: usize,
|
||||||
term_loc: GenContext,
|
term_loc: GenContext,
|
||||||
vr: &'a Cell<VarReg>,
|
vr: &'a Cell<VarReg>,
|
||||||
code: &mut Code,
|
code: &mut Code,
|
||||||
) -> RegType {
|
) -> RegType {
|
||||||
match self.marker.bindings().get(&name) {
|
match self.marker.bindings().get(&name) {
|
||||||
Some(&VarData::Temp(_, t, _)) if t != 0 => RegType::Temp(t),
|
Some(&VarData::Temp(_, t, _)) if t != 0 => {
|
||||||
Some(&VarData::Perm(p)) if p != 0 => RegType::Perm(p),
|
RegType::Temp(t)
|
||||||
_ => {
|
}
|
||||||
let mut target = Vec::new();
|
Some(&VarData::Perm(p)) if p != 0 => {
|
||||||
|
if let GenContext::Last(_) = term_loc {
|
||||||
self.marker.reset_arg(arity);
|
self.mark_var_in_non_callable(name.clone(), term_loc, vr, code);
|
||||||
self.marker
|
temp_v!(arg)
|
||||||
.mark_var(name, Level::Shallow, vr, term_loc, &mut target);
|
} else {
|
||||||
|
RegType::Perm(p)
|
||||||
if !target.is_empty() {
|
|
||||||
for query_instr in target {
|
|
||||||
code.push(Line::Query(query_instr));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
vr.get().norm()
|
_ => {
|
||||||
|
self.mark_var_in_non_callable(name, term_loc, vr, code)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -174,40 +179,49 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
|
|||||||
target.push(Target::to_void(1));
|
target.push(Target::to_void(1));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn subterm_to_instr<Target>(
|
fn deep_var_instr<Target: CompilationTarget<'a>>(
|
||||||
|
&mut self,
|
||||||
|
cell: &'a Cell<VarReg>,
|
||||||
|
var: &'a Rc<Var>,
|
||||||
|
term_loc: GenContext,
|
||||||
|
is_exposed: bool,
|
||||||
|
target: &mut Vec<Target>,
|
||||||
|
) {
|
||||||
|
if is_exposed || self.get_var_count(var.as_ref()) > 1 {
|
||||||
|
self.marker.mark_var(var.clone(), Level::Deep, cell, term_loc, target);
|
||||||
|
} else {
|
||||||
|
Self::add_or_increment_void_instr(target);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn subterm_to_instr<Target: CompilationTarget<'a>>(
|
||||||
&mut self,
|
&mut self,
|
||||||
subterm: &'a Term,
|
subterm: &'a Term,
|
||||||
term_loc: GenContext,
|
term_loc: GenContext,
|
||||||
is_exposed: bool,
|
is_exposed: bool,
|
||||||
target: &mut Vec<Target>,
|
target: &mut Vec<Target>,
|
||||||
) where
|
) {
|
||||||
Target: CompilationTarget<'a>,
|
|
||||||
{
|
|
||||||
match subterm {
|
match subterm {
|
||||||
&Term::AnonVar if is_exposed => {
|
&Term::AnonVar if is_exposed => {
|
||||||
self.marker.mark_anon_var(Level::Deep, term_loc, target)
|
self.marker.mark_anon_var(Level::Deep, term_loc, target);
|
||||||
|
}
|
||||||
|
&Term::AnonVar => {
|
||||||
|
Self::add_or_increment_void_instr(target);
|
||||||
}
|
}
|
||||||
&Term::AnonVar => Self::add_or_increment_void_instr(target),
|
|
||||||
&Term::Cons(ref cell, _, _) | &Term::Clause(ref cell, _, _, _) => {
|
&Term::Cons(ref cell, _, _) | &Term::Clause(ref cell, _, _, _) => {
|
||||||
self.marker
|
self.marker.mark_non_var(Level::Deep, term_loc, cell, target);
|
||||||
.mark_non_var(Level::Deep, term_loc, cell, target);
|
|
||||||
target.push(Target::clause_arg_to_instr(cell.get()));
|
target.push(Target::clause_arg_to_instr(cell.get()));
|
||||||
}
|
}
|
||||||
&Term::Constant(_, ref constant) => {
|
&Term::Constant(_, ref constant) => {
|
||||||
target.push(Target::constant_subterm(constant.clone()))
|
target.push(Target::constant_subterm(constant.clone()));
|
||||||
}
|
}
|
||||||
&Term::Var(ref cell, ref var) => {
|
&Term::Var(ref cell, ref var) => {
|
||||||
if is_exposed || self.get_var_count(var) > 1 {
|
self.deep_var_instr(cell, var, term_loc, is_exposed, target);
|
||||||
self.marker
|
|
||||||
.mark_var(var.clone(), Level::Deep, cell, term_loc, target);
|
|
||||||
} else {
|
|
||||||
Self::add_or_increment_void_instr(target);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
fn compile_target<Target, Iter>(
|
fn compile_target<Target, Iter>(
|
||||||
&mut self,
|
&mut self,
|
||||||
iter: Iter,
|
iter: Iter,
|
||||||
term_loc: GenContext,
|
term_loc: GenContext,
|
||||||
@@ -221,6 +235,13 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
|
|||||||
|
|
||||||
for term in iter {
|
for term in iter {
|
||||||
match term {
|
match term {
|
||||||
|
TermRef::AnonVar(lvl @ Level::Shallow) => {
|
||||||
|
if let GenContext::Head = term_loc {
|
||||||
|
self.marker.advance_arg();
|
||||||
|
} else {
|
||||||
|
self.marker.mark_anon_var(lvl, term_loc, &mut target);
|
||||||
|
}
|
||||||
|
}
|
||||||
TermRef::Clause(lvl, cell, ct, terms) => {
|
TermRef::Clause(lvl, cell, ct, terms) => {
|
||||||
self.marker.mark_non_var(lvl, term_loc, cell, &mut target);
|
self.marker.mark_non_var(lvl, term_loc, cell, &mut target);
|
||||||
target.push(Target::to_structure(ct, terms.len(), cell.get()));
|
target.push(Target::to_structure(ct, terms.len(), cell.get()));
|
||||||
@@ -236,15 +257,22 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
|
|||||||
self.subterm_to_instr(head, term_loc, is_exposed, &mut target);
|
self.subterm_to_instr(head, term_loc, is_exposed, &mut target);
|
||||||
self.subterm_to_instr(tail, term_loc, is_exposed, &mut target);
|
self.subterm_to_instr(tail, term_loc, is_exposed, &mut target);
|
||||||
}
|
}
|
||||||
|
TermRef::Constant(lvl @ Level::Shallow, cell, Constant::String(ref string)) => {
|
||||||
|
self.marker.mark_non_var(lvl, term_loc, cell, &mut target);
|
||||||
|
target.push(Target::to_pstr(lvl, string.to_string(), cell.get(), false));
|
||||||
|
}
|
||||||
TermRef::Constant(lvl @ Level::Shallow, cell, constant) => {
|
TermRef::Constant(lvl @ Level::Shallow, cell, constant) => {
|
||||||
self.marker.mark_non_var(lvl, term_loc, cell, &mut target);
|
self.marker.mark_non_var(lvl, term_loc, cell, &mut target);
|
||||||
target.push(Target::to_constant(lvl, constant.clone(), cell.get()));
|
target.push(Target::to_constant(lvl, constant.clone(), cell.get()));
|
||||||
}
|
}
|
||||||
TermRef::AnonVar(lvl @ Level::Shallow) => {
|
TermRef::PartialString(lvl, cell, string, tail) => {
|
||||||
if let GenContext::Head = term_loc {
|
self.marker.mark_non_var(lvl, term_loc, cell, &mut target);
|
||||||
self.marker.advance_arg();
|
|
||||||
|
if let Some(tail) = tail {
|
||||||
|
target.push(Target::to_pstr(lvl, string, cell.get(), true));
|
||||||
|
self.subterm_to_instr(tail, term_loc, is_exposed, &mut target);
|
||||||
} else {
|
} else {
|
||||||
self.marker.mark_anon_var(lvl, term_loc, &mut target);
|
target.push(Target::to_pstr(lvl, string, cell.get(), false));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
TermRef::Var(lvl @ Level::Shallow, cell, ref var) if var.as_str() == "!" => {
|
TermRef::Var(lvl @ Level::Shallow, cell, ref var) if var.as_str() == "!" => {
|
||||||
@@ -263,14 +291,13 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
self.marker
|
self.marker.mark_var(var.clone(), lvl, cell, term_loc, &mut target);
|
||||||
.mark_var(var.clone(), lvl, cell, term_loc, &mut target);
|
|
||||||
}
|
}
|
||||||
TermRef::Var(lvl @ Level::Shallow, cell, var) => {
|
TermRef::Var(lvl @ Level::Shallow, cell, var) => {
|
||||||
self.marker
|
self.marker.mark_var(var.clone(), lvl, cell, term_loc, &mut target);
|
||||||
.mark_var(var.clone(), lvl, cell, term_loc, &mut target)
|
}
|
||||||
|
_ => {
|
||||||
}
|
}
|
||||||
_ => {}
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -330,7 +357,9 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
|
|||||||
&mut ControlInstruction::CallClause(_, _, _, ref mut last_call, _) => {
|
&mut ControlInstruction::CallClause(_, _, _, ref mut last_call, _) => {
|
||||||
*last_call = true
|
*last_call = true
|
||||||
}
|
}
|
||||||
&mut ControlInstruction::JmpBy(_, _, _, ref mut last_call) => *last_call = true,
|
&mut ControlInstruction::JmpBy(_, _, _, ref mut last_call) => {
|
||||||
|
*last_call = true
|
||||||
|
}
|
||||||
&mut ControlInstruction::Proceed => {}
|
&mut ControlInstruction::Proceed => {}
|
||||||
_ => dealloc_index += 1,
|
_ => dealloc_index += 1,
|
||||||
},
|
},
|
||||||
@@ -350,33 +379,42 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
|
|||||||
) -> Result<(), ParserError> {
|
) -> Result<(), ParserError> {
|
||||||
match ct {
|
match ct {
|
||||||
&InlinedClauseType::CompareNumber(cmp, ..) => {
|
&InlinedClauseType::CompareNumber(cmp, ..) => {
|
||||||
if let &Term::Var(ref vr, ref name) = terms[0].as_ref() {
|
self.marker.reset_arg(2);
|
||||||
self.mark_non_callable(name.clone(), 2, term_loc, vr, code);
|
|
||||||
}
|
|
||||||
|
|
||||||
if let &Term::Var(ref vr, ref name) = terms[1].as_ref() {
|
|
||||||
self.mark_non_callable(name.clone(), 2, term_loc, vr, code);
|
|
||||||
}
|
|
||||||
|
|
||||||
let (mut lcode, at_1) = self.call_arith_eval(terms[0].as_ref(), 1)?;
|
let (mut lcode, at_1) = self.call_arith_eval(terms[0].as_ref(), 1)?;
|
||||||
let (mut rcode, at_2) = self.call_arith_eval(terms[1].as_ref(), 2)?;
|
let (mut rcode, at_2) = self.call_arith_eval(terms[1].as_ref(), 2)?;
|
||||||
|
|
||||||
|
let at_1 =
|
||||||
|
if let &Term::Var(ref vr, ref name) = terms[0].as_ref() {
|
||||||
|
ArithmeticTerm::Reg(
|
||||||
|
self.mark_non_callable(name.clone(), 1, term_loc, vr, code)
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
at_1.unwrap_or(interm!(1))
|
||||||
|
};
|
||||||
|
|
||||||
|
let at_2 =
|
||||||
|
if let &Term::Var(ref vr, ref name) = terms[1].as_ref() {
|
||||||
|
ArithmeticTerm::Reg(
|
||||||
|
self.mark_non_callable(name.clone(), 2, term_loc, vr, code)
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
at_2.unwrap_or(interm!(2))
|
||||||
|
};
|
||||||
|
|
||||||
code.append(&mut lcode);
|
code.append(&mut lcode);
|
||||||
code.append(&mut rcode);
|
code.append(&mut rcode);
|
||||||
|
|
||||||
code.push(compare_number_instr!(
|
code.push(compare_number_instr!(cmp, at_1, at_2));
|
||||||
cmp,
|
|
||||||
at_1.unwrap_or(interm!(1)),
|
|
||||||
at_2.unwrap_or(interm!(2))
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
&InlinedClauseType::IsAtom(..) => match terms[0].as_ref() {
|
&InlinedClauseType::IsAtom(..) => match terms[0].as_ref() {
|
||||||
&Term::Constant(_, Constant::Char(_))
|
&Term::Constant(_, Constant::Char(_)) |
|
||||||
| &Term::Constant(_, Constant::EmptyList)
|
&Term::Constant(_, Constant::EmptyList) |
|
||||||
| &Term::Constant(_, Constant::Atom(..)) => {
|
&Term::Constant(_, Constant::Atom(..)) => {
|
||||||
code.push(succeed!());
|
code.push(succeed!());
|
||||||
}
|
}
|
||||||
&Term::Var(ref vr, ref name) => {
|
&Term::Var(ref vr, ref name) => {
|
||||||
|
self.marker.reset_arg(1);
|
||||||
let r = self.mark_non_callable(name.clone(), 1, term_loc, vr, code);
|
let r = self.mark_non_callable(name.clone(), 1, term_loc, vr, code);
|
||||||
code.push(is_atom!(r));
|
code.push(is_atom!(r));
|
||||||
}
|
}
|
||||||
@@ -392,6 +430,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
|
|||||||
code.push(succeed!());
|
code.push(succeed!());
|
||||||
}
|
}
|
||||||
&Term::Var(ref vr, ref name) => {
|
&Term::Var(ref vr, ref name) => {
|
||||||
|
self.marker.reset_arg(1);
|
||||||
let r = self.mark_non_callable(name.clone(), 1, term_loc, vr, code);
|
let r = self.mark_non_callable(name.clone(), 1, term_loc, vr, code);
|
||||||
code.push(is_atomic!(r));
|
code.push(is_atomic!(r));
|
||||||
}
|
}
|
||||||
@@ -401,6 +440,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
|
|||||||
code.push(succeed!());
|
code.push(succeed!());
|
||||||
}
|
}
|
||||||
&Term::Var(ref vr, ref name) => {
|
&Term::Var(ref vr, ref name) => {
|
||||||
|
self.marker.reset_arg(1);
|
||||||
let r = self.mark_non_callable(name.clone(), 1, term_loc, vr, code);
|
let r = self.mark_non_callable(name.clone(), 1, term_loc, vr, code);
|
||||||
code.push(is_compound!(r));
|
code.push(is_compound!(r));
|
||||||
}
|
}
|
||||||
@@ -413,6 +453,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
|
|||||||
code.push(succeed!());
|
code.push(succeed!());
|
||||||
}
|
}
|
||||||
&Term::Var(ref vr, ref name) => {
|
&Term::Var(ref vr, ref name) => {
|
||||||
|
self.marker.reset_arg(1);
|
||||||
let r = self.mark_non_callable(name.clone(), 1, term_loc, vr, code);
|
let r = self.mark_non_callable(name.clone(), 1, term_loc, vr, code);
|
||||||
code.push(is_rational!(r));
|
code.push(is_rational!(r));
|
||||||
}
|
}
|
||||||
@@ -425,6 +466,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
|
|||||||
code.push(succeed!());
|
code.push(succeed!());
|
||||||
}
|
}
|
||||||
&Term::Var(ref vr, ref name) => {
|
&Term::Var(ref vr, ref name) => {
|
||||||
|
self.marker.reset_arg(1);
|
||||||
let r = self.mark_non_callable(name.clone(), 1, term_loc, vr, code);
|
let r = self.mark_non_callable(name.clone(), 1, term_loc, vr, code);
|
||||||
code.push(is_float!(r));
|
code.push(is_float!(r));
|
||||||
}
|
}
|
||||||
@@ -432,23 +474,12 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
|
|||||||
code.push(fail!());
|
code.push(fail!());
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
&InlinedClauseType::IsString(..) => match terms[0].as_ref() {
|
|
||||||
&Term::Constant(_, Constant::String(..)) => {
|
|
||||||
code.push(succeed!());
|
|
||||||
}
|
|
||||||
&Term::Var(ref vr, ref name) => {
|
|
||||||
let r = self.mark_non_callable(name.clone(), 1, term_loc, vr, code);
|
|
||||||
code.push(is_string!(r));
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
code.push(fail!());
|
|
||||||
}
|
|
||||||
},
|
|
||||||
&InlinedClauseType::IsNonVar(..) => match terms[0].as_ref() {
|
&InlinedClauseType::IsNonVar(..) => match terms[0].as_ref() {
|
||||||
&Term::AnonVar => {
|
&Term::AnonVar => {
|
||||||
code.push(fail!());
|
code.push(fail!());
|
||||||
}
|
}
|
||||||
&Term::Var(ref vr, ref name) => {
|
&Term::Var(ref vr, ref name) => {
|
||||||
|
self.marker.reset_arg(1);
|
||||||
let r = self.mark_non_callable(name.clone(), 1, term_loc, vr, code);
|
let r = self.mark_non_callable(name.clone(), 1, term_loc, vr, code);
|
||||||
code.push(is_nonvar!(r));
|
code.push(is_nonvar!(r));
|
||||||
}
|
}
|
||||||
@@ -457,10 +488,12 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
&InlinedClauseType::IsInteger(..) => match terms[0].as_ref() {
|
&InlinedClauseType::IsInteger(..) => match terms[0].as_ref() {
|
||||||
&Term::Constant(_, Constant::Integer(_)) => {
|
&Term::Constant(_, Constant::Integer(_)) |
|
||||||
|
&Term::Constant(_, Constant::Fixnum(_)) => {
|
||||||
code.push(succeed!());
|
code.push(succeed!());
|
||||||
}
|
}
|
||||||
&Term::Var(ref vr, ref name) => {
|
&Term::Var(ref vr, ref name) => {
|
||||||
|
self.marker.reset_arg(1);
|
||||||
let r = self.mark_non_callable(name.clone(), 1, term_loc, vr, code);
|
let r = self.mark_non_callable(name.clone(), 1, term_loc, vr, code);
|
||||||
code.push(is_integer!(r));
|
code.push(is_integer!(r));
|
||||||
}
|
}
|
||||||
@@ -476,6 +509,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
|
|||||||
code.push(succeed!());
|
code.push(succeed!());
|
||||||
}
|
}
|
||||||
&Term::Var(ref vr, ref name) => {
|
&Term::Var(ref vr, ref name) => {
|
||||||
|
self.marker.reset_arg(1);
|
||||||
let r = self.mark_non_callable(name.clone(), 1, term_loc, vr, code);
|
let r = self.mark_non_callable(name.clone(), 1, term_loc, vr, code);
|
||||||
code.push(is_var!(r));
|
code.push(is_var!(r));
|
||||||
}
|
}
|
||||||
@@ -490,7 +524,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
|
|||||||
term: &'a Term,
|
term: &'a Term,
|
||||||
target_int: usize,
|
target_int: usize,
|
||||||
) -> Result<ArithCont, ArithmeticError> {
|
) -> Result<ArithCont, ArithmeticError> {
|
||||||
let mut evaluator = ArithmeticEvaluator::new(self.marker.bindings(), target_int);
|
let mut evaluator = ArithmeticEvaluator::new(&self.marker.bindings(), target_int);
|
||||||
evaluator.eval(term)
|
evaluator.eval(term)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -504,36 +538,27 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
|
|||||||
let (mut acode, at) = self.call_arith_eval(terms[1].as_ref(), 1)?;
|
let (mut acode, at) = self.call_arith_eval(terms[1].as_ref(), 1)?;
|
||||||
code.append(&mut acode);
|
code.append(&mut acode);
|
||||||
|
|
||||||
Ok(match terms[0].as_ref() {
|
self.marker.reset_arg(2);
|
||||||
|
|
||||||
|
match terms[0].as_ref() {
|
||||||
&Term::Var(ref vr, ref name) => {
|
&Term::Var(ref vr, ref name) => {
|
||||||
let mut target = vec![];
|
let mut target = vec![];
|
||||||
|
|
||||||
self.marker.reset_arg(2);
|
self.marker.mark_var(name.clone(), Level::Shallow, vr, term_loc, &mut target);
|
||||||
self.marker
|
|
||||||
.mark_var(name.clone(), Level::Shallow, vr, term_loc, &mut target);
|
|
||||||
|
|
||||||
if !target.is_empty() {
|
if !target.is_empty() {
|
||||||
code.extend(target.into_iter().map(Line::Query));
|
code.extend(target.into_iter().map(Line::Query));
|
||||||
}
|
}
|
||||||
|
|
||||||
if use_default_call_policy {
|
|
||||||
code.push(is_call_by_default!(temp_v!(1), at.unwrap_or(interm!(1))))
|
|
||||||
} else {
|
|
||||||
code.push(is_call!(temp_v!(1), at.unwrap_or(interm!(1))))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
&Term::Constant(_, ref c @ Constant::Integer(_)) => {
|
&Term::Constant(_, ref c @ Constant::Integer(_)) |
|
||||||
|
&Term::Constant(_, ref c @ Constant::Fixnum(_)) => {
|
||||||
code.push(Line::Query(put_constant!(
|
code.push(Line::Query(put_constant!(
|
||||||
Level::Shallow,
|
Level::Shallow,
|
||||||
c.clone(),
|
c.clone(),
|
||||||
temp_v!(1)
|
temp_v!(1)
|
||||||
)));
|
)));
|
||||||
|
|
||||||
if use_default_call_policy {
|
self.marker.advance_arg();
|
||||||
code.push(is_call_by_default!(temp_v!(1), at.unwrap_or(interm!(1))))
|
|
||||||
} else {
|
|
||||||
code.push(is_call!(temp_v!(1), at.unwrap_or(interm!(1))))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
&Term::Constant(_, ref c @ Constant::Float(_)) => {
|
&Term::Constant(_, ref c @ Constant::Float(_)) => {
|
||||||
code.push(Line::Query(put_constant!(
|
code.push(Line::Query(put_constant!(
|
||||||
@@ -542,11 +567,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
|
|||||||
temp_v!(1)
|
temp_v!(1)
|
||||||
)));
|
)));
|
||||||
|
|
||||||
if use_default_call_policy {
|
self.marker.advance_arg();
|
||||||
code.push(is_call_by_default!(temp_v!(1), at.unwrap_or(interm!(1))))
|
|
||||||
} else {
|
|
||||||
code.push(is_call!(temp_v!(1), at.unwrap_or(interm!(1))))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
&Term::Constant(_, ref c @ Constant::Rational(_)) => {
|
&Term::Constant(_, ref c @ Constant::Rational(_)) => {
|
||||||
code.push(Line::Query(put_constant!(
|
code.push(Line::Query(put_constant!(
|
||||||
@@ -555,13 +576,27 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
|
|||||||
temp_v!(1)
|
temp_v!(1)
|
||||||
)));
|
)));
|
||||||
|
|
||||||
if use_default_call_policy {
|
self.marker.advance_arg();
|
||||||
code.push(is_call_by_default!(temp_v!(1), at.unwrap_or(interm!(1))))
|
|
||||||
} else {
|
|
||||||
code.push(is_call!(temp_v!(1), at.unwrap_or(interm!(1))))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
_ => code.push(fail!()),
|
_ => {
|
||||||
|
code.push(fail!());
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let at =
|
||||||
|
if let &Term::Var(ref vr, ref name) = terms[1].as_ref() {
|
||||||
|
ArithmeticTerm::Reg(
|
||||||
|
self.mark_non_callable(name.clone(), 2, term_loc, vr, code)
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
at.unwrap_or(interm!(1))
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(if use_default_call_policy {
|
||||||
|
code.push(is_call_by_default!(temp_v!(1), at));
|
||||||
|
} else {
|
||||||
|
code.push(is_call!(temp_v!(1), at));
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -684,6 +719,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
|
|||||||
head: (_, ref args, ref p1),
|
head: (_, ref args, ref p1),
|
||||||
ref clauses,
|
ref clauses,
|
||||||
} = rule;
|
} = rule;
|
||||||
|
|
||||||
let mut code = Vec::new();
|
let mut code = Vec::new();
|
||||||
|
|
||||||
self.marker.reset_at_head(args);
|
self.marker.reset_at_head(args);
|
||||||
@@ -705,39 +741,31 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
|
|||||||
let iter = ChunkedIterator::from_rule_body(p1, clauses);
|
let iter = ChunkedIterator::from_rule_body(p1, clauses);
|
||||||
self.compile_seq(iter, &conjunct_info, &mut code, false)?;
|
self.compile_seq(iter, &conjunct_info, &mut code, false)?;
|
||||||
|
|
||||||
conjunct_info.mark_unsafe_vars(unsafe_var_marker, &self.marker, &mut code);
|
conjunct_info.mark_unsafe_vars(unsafe_var_marker, &mut code);
|
||||||
|
|
||||||
Self::compile_cleanup(&mut code, &conjunct_info, clauses.last().unwrap_or(p1));
|
Self::compile_cleanup(&mut code, &conjunct_info, clauses.last().unwrap_or(p1));
|
||||||
Ok(code)
|
Ok(code)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn mark_unsafe_fact_vars(&self, fact: &mut CompiledFact) -> UnsafeVarMarker {
|
fn mark_unsafe_fact_vars(&self, fact: &mut CompiledFact) -> UnsafeVarMarker {
|
||||||
let mut unsafe_vars = IndexMap::new();
|
let mut safe_vars = IndexSet::new();
|
||||||
|
|
||||||
for var_status in self.marker.bindings().values() {
|
|
||||||
unsafe_vars.insert(var_status.as_reg_type(), false);
|
|
||||||
}
|
|
||||||
|
|
||||||
for fact_instr in fact.iter_mut() {
|
for fact_instr in fact.iter_mut() {
|
||||||
match fact_instr {
|
match fact_instr {
|
||||||
&mut FactInstruction::UnifyValue(reg) => {
|
&mut FactInstruction::UnifyValue(r) => {
|
||||||
if let Some(found) = unsafe_vars.get_mut(®) {
|
if !safe_vars.contains(&r) {
|
||||||
if !*found {
|
*fact_instr = FactInstruction::UnifyLocalValue(r);
|
||||||
*found = true;
|
safe_vars.insert(r);
|
||||||
*fact_instr = FactInstruction::UnifyLocalValue(reg);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
&mut FactInstruction::UnifyVariable(reg) => {
|
&mut FactInstruction::UnifyVariable(r) => {
|
||||||
if let Some(found) = unsafe_vars.get_mut(®) {
|
safe_vars.insert(r);
|
||||||
*found = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
UnsafeVarMarker { unsafe_vars }
|
UnsafeVarMarker::from_safe_vars(safe_vars)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn compile_fact<'b: 'a>(&mut self, term: &'b Term) -> Code {
|
pub fn compile_fact<'b: 'a>(&mut self, term: &'b Term) -> Code {
|
||||||
@@ -802,7 +830,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
|
|||||||
let iter = ChunkedIterator::from_term_sequence(query);
|
let iter = ChunkedIterator::from_term_sequence(query);
|
||||||
self.compile_seq(iter, &conjunct_info, &mut code, true)?;
|
self.compile_seq(iter, &conjunct_info, &mut code, true)?;
|
||||||
|
|
||||||
conjunct_info.mark_unsafe_vars(UnsafeVarMarker::new(), &self.marker, &mut code);
|
conjunct_info.mark_unsafe_vars(UnsafeVarMarker::new(), &mut code);
|
||||||
|
|
||||||
if let Some(query_term) = query.last() {
|
if let Some(query_term) = query.last() {
|
||||||
Self::compile_cleanup(&mut code, &conjunct_info, query_term);
|
Self::compile_cleanup(&mut code, &conjunct_info, query_term);
|
||||||
@@ -1,17 +1,18 @@
|
|||||||
use indexmap::IndexMap;
|
use crate::indexmap::IndexMap;
|
||||||
|
|
||||||
use prolog_parser::ast::*;
|
use crate::prolog_parser::ast::*;
|
||||||
|
|
||||||
use crate::prolog::allocator::*;
|
use crate::allocator::*;
|
||||||
use crate::prolog::fixtures::*;
|
use crate::fixtures::*;
|
||||||
use crate::prolog::forms::*;
|
use crate::forms::*;
|
||||||
use crate::prolog::machine::machine_indices::*;
|
use crate::machine::machine_indices::*;
|
||||||
use crate::prolog::targets::*;
|
use crate::targets::*;
|
||||||
|
|
||||||
use std::cell::Cell;
|
use std::cell::Cell;
|
||||||
use std::collections::BTreeSet;
|
use std::collections::BTreeSet;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
pub struct DebrayAllocator {
|
pub struct DebrayAllocator {
|
||||||
bindings: IndexMap<Rc<Var>, VarData>,
|
bindings: IndexMap<Rc<Var>, VarData>,
|
||||||
arg_c: usize,
|
arg_c: usize,
|
||||||
@@ -292,7 +293,9 @@ impl<'a> Allocator<'a> for DebrayAllocator {
|
|||||||
|
|
||||||
(pr, true)
|
(pr, true)
|
||||||
}
|
}
|
||||||
r => (r, false),
|
r => {
|
||||||
|
(r, false)
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
self.mark_reserved_var(var, lvl, cell, term_loc, target, r, is_new_var);
|
self.mark_reserved_var(var, lvl, cell, term_loc, target, r, is_new_var);
|
||||||
219
src/examples/bimetatrans/README.md
Normal file
219
src/examples/bimetatrans/README.md
Normal 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)))].
|
||||||
|
```
|
||||||
1183
src/examples/bimetatrans/bimetatrans.pl
Normal file
1183
src/examples/bimetatrans/bimetatrans.pl
Normal file
File diff suppressed because it is too large
Load Diff
4061
src/examples/bimetatrans/bimetatrans_tests.pl
Normal file
4061
src/examples/bimetatrans/bimetatrans_tests.pl
Normal file
File diff suppressed because it is too large
Load Diff
@@ -22,7 +22,6 @@ verify_attributes(Var, Other, Goals) :-
|
|||||||
( Els = [] -> % exactly one element
|
( Els = [] -> % exactly one element
|
||||||
Goals = [Other=El] % implied binding
|
Goals = [Other=El] % implied binding
|
||||||
; Goals = [],
|
; Goals = [],
|
||||||
put_atts(Other, -dom(_)),
|
|
||||||
put_atts(Other, dom(Dc))% rescue intersection
|
put_atts(Other, dom(Dc))% rescue intersection
|
||||||
)
|
)
|
||||||
; Goals = [],
|
; Goals = [],
|
||||||
31
src/examples/echo_server.pl
Normal file
31
src/examples/echo_server.pl
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
:- module(echo_server, [echo_server/0,
|
||||||
|
echo_server/1]).
|
||||||
|
|
||||||
|
:- use_module(library(format)).
|
||||||
|
:- use_module(library(sockets)).
|
||||||
|
|
||||||
|
|
||||||
|
echo_server :-
|
||||||
|
echo_server('127.0.0.1').
|
||||||
|
|
||||||
|
|
||||||
|
echo_server(Addr) :-
|
||||||
|
socket_server_open(Addr:Port, ServerSocket),
|
||||||
|
format("echo_server: connection opened at ~w:~d~n", [Addr, Port]),
|
||||||
|
socket_server_accept(ServerSocket, Client, Stream, [eof_action(eof_code)]),
|
||||||
|
format("echo_server: connection accepted from ~a~n", [Client]),
|
||||||
|
!,
|
||||||
|
echo_loop(Stream),
|
||||||
|
socket_server_close(ServerSocket).
|
||||||
|
|
||||||
|
|
||||||
|
echo_loop(Stream) :-
|
||||||
|
read_term(Stream, Term, []),
|
||||||
|
( Term == end_of_file ->
|
||||||
|
true
|
||||||
|
;
|
||||||
|
format("received: ~w~n", [Term]),
|
||||||
|
!,
|
||||||
|
echo_loop(Stream)
|
||||||
|
).
|
||||||
|
|
||||||
57
src/examples/least_time.pl
Normal file
57
src/examples/least_time.pl
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
/* least_time.pl
|
||||||
|
*
|
||||||
|
* By Mark Thom, 2020
|
||||||
|
*
|
||||||
|
* find_min_time/2 solves a problem sometimes posed in the first round
|
||||||
|
* of Google interviews: given a time of day in 24 H format, what is the
|
||||||
|
* lexicographically least permutation of the time that is itself a
|
||||||
|
* valid time in 24 H format?
|
||||||
|
*
|
||||||
|
* Full generality is achieved using the reif library.
|
||||||
|
*/
|
||||||
|
|
||||||
|
:- module(least_time, [find_min_time/2,
|
||||||
|
write_time_nl/1]).
|
||||||
|
|
||||||
|
|
||||||
|
:- use_module(library(dcgs)).
|
||||||
|
:- use_module(library(format)).
|
||||||
|
:- use_module(library(lists)).
|
||||||
|
:- use_module(library(reif)).
|
||||||
|
|
||||||
|
|
||||||
|
permutation([], []).
|
||||||
|
permutation([X|Xs], Ys) :-
|
||||||
|
permutation(Xs, Yss),
|
||||||
|
select(X, Ys, Yss).
|
||||||
|
|
||||||
|
|
||||||
|
valid_time([H1,H2,M1,M2], T) :-
|
||||||
|
memberd_t(H1, [0,1,2], TH1),
|
||||||
|
memberd_t(H2, [0,1,2,3,4,5,6,7,8,9], TH2),
|
||||||
|
memberd_t(M1, [0,1,2,3,4,5], TM1),
|
||||||
|
memberd_t(M2, [0,1,2,3,4,5,6,7,8,9], TM2),
|
||||||
|
( maplist(=(true), [TH1, TH2, TM1, TM2]) ->
|
||||||
|
( H1 =:= 2 ->
|
||||||
|
( H2 =< 3 ->
|
||||||
|
T = true
|
||||||
|
; T = false
|
||||||
|
)
|
||||||
|
; T = true
|
||||||
|
)
|
||||||
|
; T = false
|
||||||
|
).
|
||||||
|
|
||||||
|
|
||||||
|
permuted_times(Time, PermutedTimes) :-
|
||||||
|
setof(P, permutation(Time, P), PermutedTimes0),
|
||||||
|
tfilter(valid_time, PermutedTimes0, PermutedTimes).
|
||||||
|
|
||||||
|
|
||||||
|
find_min_time(Time, Min) :-
|
||||||
|
valid_time(Time, true),
|
||||||
|
permuted_times(Time, [Min|_]).
|
||||||
|
|
||||||
|
|
||||||
|
write_time_nl(Time) :-
|
||||||
|
format("\"~w~w:~w~w\"~n", Time).
|
||||||
@@ -31,6 +31,7 @@
|
|||||||
|
|
||||||
:- use_module(library(dcgs)).
|
:- use_module(library(dcgs)).
|
||||||
:- use_module(library(dif)).
|
:- use_module(library(dif)).
|
||||||
|
:- use_module(library(format)).
|
||||||
:- use_module(library(lists)).
|
:- use_module(library(lists)).
|
||||||
|
|
||||||
pl_resolution(Clauses0, Chain) :-
|
pl_resolution(Clauses0, Chain) :-
|
||||||
31
src/examples/utf8.pl
Normal file
31
src/examples/utf8.pl
Normal 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).
|
||||||
@@ -1,11 +1,10 @@
|
|||||||
use prolog_parser::ast::*;
|
use crate::prolog_parser::ast::*;
|
||||||
|
|
||||||
use crate::prolog::allocator::*;
|
use crate::forms::*;
|
||||||
use crate::prolog::forms::*;
|
use crate::instructions::*;
|
||||||
use crate::prolog::instructions::*;
|
use crate::iterators::*;
|
||||||
use crate::prolog::iterators::*;
|
|
||||||
|
|
||||||
use indexmap::{IndexMap, IndexSet};
|
use crate::indexmap::{IndexMap, IndexSet};
|
||||||
|
|
||||||
use std::cell::Cell;
|
use std::cell::Cell;
|
||||||
use std::collections::BTreeSet;
|
use std::collections::BTreeSet;
|
||||||
@@ -14,6 +13,7 @@ use std::rc::Rc;
|
|||||||
use std::vec::Vec;
|
use std::vec::Vec;
|
||||||
|
|
||||||
// labeled with chunk numbers.
|
// labeled with chunk numbers.
|
||||||
|
#[derive(Debug)]
|
||||||
pub enum VarStatus {
|
pub enum VarStatus {
|
||||||
Perm(usize),
|
Perm(usize),
|
||||||
Temp(usize, TempVarData), // Perm(chunk_num) | Temp(chunk_num, _)
|
Temp(usize, TempVarData), // Perm(chunk_num) | Temp(chunk_num, _)
|
||||||
@@ -23,6 +23,7 @@ pub type OccurrenceSet = BTreeSet<(GenContext, usize)>;
|
|||||||
|
|
||||||
// Perm: 0 initially, a stack register once processed.
|
// Perm: 0 initially, a stack register once processed.
|
||||||
// Temp: labeled with chunk_num and temp offset (unassigned if 0).
|
// Temp: labeled with chunk_num and temp offset (unassigned if 0).
|
||||||
|
#[derive(Debug)]
|
||||||
pub enum VarData {
|
pub enum VarData {
|
||||||
Perm(usize),
|
Perm(usize),
|
||||||
Temp(usize, usize, TempVarData),
|
Temp(usize, usize, TempVarData),
|
||||||
@@ -37,6 +38,7 @@ impl VarData {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
pub struct TempVarData {
|
pub struct TempVarData {
|
||||||
pub last_term_arity: usize,
|
pub last_term_arity: usize,
|
||||||
pub use_set: OccurrenceSet,
|
pub use_set: OccurrenceSet,
|
||||||
@@ -80,6 +82,7 @@ impl TempVarData {
|
|||||||
|
|
||||||
type VariableFixture<'a> = (VarStatus, Vec<&'a Cell<VarReg>>);
|
type VariableFixture<'a> = (VarStatus, Vec<&'a Cell<VarReg>>);
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
pub struct VariableFixtures<'a>{
|
pub struct VariableFixtures<'a>{
|
||||||
perm_vars: IndexMap<Rc<Var>, VariableFixture<'a>>,
|
perm_vars: IndexMap<Rc<Var>, VariableFixture<'a>>,
|
||||||
last_chunk_temp_vars: IndexSet<Rc<Var>>
|
last_chunk_temp_vars: IndexSet<Rc<Var>>
|
||||||
@@ -249,68 +252,69 @@ impl<'a> VariableFixtures<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
pub struct UnsafeVarMarker {
|
pub struct UnsafeVarMarker {
|
||||||
pub unsafe_vars: IndexMap<RegType, bool>,
|
pub unsafe_vars: IndexMap<RegType, usize>,
|
||||||
|
pub safe_vars: IndexSet<RegType>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl UnsafeVarMarker {
|
impl UnsafeVarMarker {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
UnsafeVarMarker {
|
UnsafeVarMarker {
|
||||||
unsafe_vars: IndexMap::new(),
|
unsafe_vars: IndexMap::new(),
|
||||||
|
safe_vars: IndexSet::new()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn record_unsafe_vars<'a, Alloc: Allocator<'a>>(
|
pub fn from_safe_vars(safe_vars: IndexSet<RegType>) -> Self {
|
||||||
&mut self,
|
UnsafeVarMarker {
|
||||||
fixtures: &VariableFixtures,
|
unsafe_vars: IndexMap::new(),
|
||||||
marker: &Alloc
|
safe_vars
|
||||||
) {
|
|
||||||
for &(_, ref cb) in fixtures.values() {
|
|
||||||
if let Some(index) = cb.first() {
|
|
||||||
if !self.unsafe_vars.contains_key(&index.get().norm()) {
|
|
||||||
self.unsafe_vars.insert(index.get().norm(), false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for var in fixtures.last_chunk_temp_vars.iter().cloned() {
|
|
||||||
let r = marker.get(var);
|
|
||||||
self.unsafe_vars.insert(r, false);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn mark_safe_vars(&mut self, query_instr: &QueryInstruction) {
|
pub fn mark_safe_vars(&mut self, query_instr: &QueryInstruction) -> bool {
|
||||||
match query_instr {
|
match query_instr {
|
||||||
QueryInstruction::PutVariable(RegType::Temp(r), _) => {
|
&QueryInstruction::PutVariable(r @ RegType::Temp(_), _)
|
||||||
if let Some(found) = self.unsafe_vars.get_mut(&RegType::Temp(*r)) {
|
| &QueryInstruction::SetVariable(r) => {
|
||||||
*found = true;
|
self.safe_vars.insert(r);
|
||||||
}
|
true
|
||||||
}
|
}
|
||||||
QueryInstruction::SetVariable(reg) => {
|
_ => {
|
||||||
if let Some(found) = self.unsafe_vars.get_mut(reg) {
|
false
|
||||||
*found = true;
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn mark_phase(&mut self, query_instr: &QueryInstruction, phase: usize) {
|
||||||
|
match query_instr {
|
||||||
|
&QueryInstruction::PutValue(r @ RegType::Perm(_), _)
|
||||||
|
| &QueryInstruction::SetValue(r) => {
|
||||||
|
let p = self.unsafe_vars.entry(r).or_insert(0);
|
||||||
|
*p = phase;
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn mark_unsafe_vars(&mut self, query_instr: &mut QueryInstruction) {
|
pub fn mark_unsafe_vars(&mut self, query_instr: &mut QueryInstruction, phase: usize) {
|
||||||
match query_instr {
|
match query_instr {
|
||||||
&mut QueryInstruction::PutValue(RegType::Perm(i), arg) => {
|
&mut QueryInstruction::PutValue(RegType::Perm(i), arg) => {
|
||||||
if let Some(found) = self.unsafe_vars.get_mut(&RegType::Perm(i)) {
|
if let Some(p) = self.unsafe_vars.swap_remove(&RegType::Perm(i)) {
|
||||||
if !*found {
|
if p == phase {
|
||||||
*found = true;
|
|
||||||
*query_instr = QueryInstruction::PutUnsafeValue(i, arg);
|
*query_instr = QueryInstruction::PutUnsafeValue(i, arg);
|
||||||
|
self.safe_vars.insert(RegType::Perm(i));
|
||||||
|
} else {
|
||||||
|
self.unsafe_vars.insert(RegType::Perm(i), p);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
&mut QueryInstruction::SetValue(reg) => {
|
&mut QueryInstruction::SetValue(r) => {
|
||||||
if let Some(found) = self.unsafe_vars.get_mut(®) {
|
if !self.safe_vars.contains(&r) {
|
||||||
if !*found {
|
*query_instr = QueryInstruction::SetLocalValue(r);
|
||||||
*found = true;
|
|
||||||
*query_instr = QueryInstruction::SetLocalValue(reg);
|
self.safe_vars.insert(r);
|
||||||
}
|
self.unsafe_vars.remove(&r);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
@@ -1,14 +1,14 @@
|
|||||||
use prolog_parser::ast::*;
|
use crate::prolog_parser::ast::*;
|
||||||
use prolog_parser::parser::OpDesc;
|
use crate::prolog_parser::parser::OpDesc;
|
||||||
use prolog_parser::tabled_rc::*;
|
use crate::prolog_parser::tabled_rc::*;
|
||||||
|
|
||||||
use crate::prolog::clause_types::*;
|
use crate::clause_types::*;
|
||||||
use crate::prolog::machine::machine_errors::*;
|
use crate::machine::machine_errors::*;
|
||||||
use crate::prolog::machine::machine_indices::*;
|
use crate::machine::machine_indices::*;
|
||||||
use crate::prolog::ordered_float::OrderedFloat;
|
use crate::ordered_float::OrderedFloat;
|
||||||
use crate::prolog::rug::{Integer, Rational};
|
use crate::rug::{Integer, Rational};
|
||||||
|
|
||||||
use indexmap::IndexMap;
|
use crate::indexmap::IndexMap;
|
||||||
|
|
||||||
use std::cell::Cell;
|
use std::cell::Cell;
|
||||||
use std::collections::VecDeque;
|
use std::collections::VecDeque;
|
||||||
@@ -21,7 +21,7 @@ pub type PredicateKey = (ClauseName, usize); // name, arity.
|
|||||||
// of vars (we get their adjoining cells this way).
|
// of vars (we get their adjoining cells this way).
|
||||||
pub type JumpStub = Vec<Term>;
|
pub type JumpStub = Vec<Term>;
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum TopLevel {
|
pub enum TopLevel {
|
||||||
Declaration(Declaration),
|
Declaration(Declaration),
|
||||||
Fact(Term, usize, usize), // Term, line_num, col_num
|
Fact(Term, usize, usize), // Term, line_num, col_num
|
||||||
@@ -41,7 +41,7 @@ impl TopLevel {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub enum Level {
|
pub enum Level {
|
||||||
Deep,
|
Deep,
|
||||||
Root,
|
Root,
|
||||||
@@ -57,7 +57,7 @@ impl Level {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum QueryTerm {
|
pub enum QueryTerm {
|
||||||
// register, clause type, subterms, use default call policy.
|
// register, clause type, subterms, use default call policy.
|
||||||
Clause(Cell<RegType>, ClauseType, Vec<Box<Term>>, bool),
|
Clause(Cell<RegType>, ClauseType, Vec<Box<Term>>, bool),
|
||||||
@@ -85,13 +85,13 @@ impl QueryTerm {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct Rule {
|
pub struct Rule {
|
||||||
pub head: (ClauseName, Vec<Box<Term>>, QueryTerm),
|
pub head: (ClauseName, Vec<Box<Term>>, QueryTerm),
|
||||||
pub clauses: Vec<QueryTerm>,
|
pub clauses: Vec<QueryTerm>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct Predicate(pub Vec<PredicateClause>);
|
pub struct Predicate(pub Vec<PredicateClause>);
|
||||||
|
|
||||||
impl Predicate {
|
impl Predicate {
|
||||||
@@ -113,7 +113,7 @@ impl Predicate {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum ListingSource {
|
pub enum ListingSource {
|
||||||
File(ClauseName, PathBuf), // filename, path
|
File(ClauseName, PathBuf), // filename, path
|
||||||
User,
|
User,
|
||||||
@@ -325,7 +325,7 @@ impl ClauseConsistency for Predicate {
|
|||||||
|
|
||||||
pub type CompiledResult = (Predicate, VecDeque<TopLevel>);
|
pub type CompiledResult = (Predicate, VecDeque<TopLevel>);
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum PredicateClause {
|
pub enum PredicateClause {
|
||||||
Fact(Term, usize, usize), // Term, line number, column number.
|
Fact(Term, usize, usize), // Term, line number, column number.
|
||||||
Rule(Rule, usize, usize), // Term, line number, column number.
|
Rule(Rule, usize, usize), // Term, line number, column number.
|
||||||
@@ -370,21 +370,34 @@ impl PredicateClause {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum ModuleSource {
|
pub enum ModuleSource {
|
||||||
Library(ClauseName),
|
Library(ClauseName),
|
||||||
File(ClauseName),
|
File(ClauseName),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl ModuleSource {
|
||||||
|
pub fn as_functor_stub(&self) -> MachineStub {
|
||||||
|
match self {
|
||||||
|
ModuleSource::Library(ref name) => {
|
||||||
|
functor!("library", [clause_name(name.clone())])
|
||||||
|
}
|
||||||
|
ModuleSource::File(ref name) => {
|
||||||
|
functor!(clause_name(name.clone()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub type ScopedPredicateKey = (ClauseName, PredicateKey); // module name, predicate indicator.
|
pub type ScopedPredicateKey = (ClauseName, PredicateKey); // module name, predicate indicator.
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum MultiFileIndicator {
|
pub enum MultiFileIndicator {
|
||||||
LocalScoped(ClauseName, usize), // name, arity
|
LocalScoped(ClauseName, usize), // name, arity
|
||||||
ModuleScoped(ScopedPredicateKey),
|
ModuleScoped(ScopedPredicateKey),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum Declaration {
|
pub enum Declaration {
|
||||||
Dynamic(ClauseName, usize), // name, arity
|
Dynamic(ClauseName, usize), // name, arity
|
||||||
EndOfFile,
|
EndOfFile,
|
||||||
@@ -394,6 +407,7 @@ pub enum Declaration {
|
|||||||
MultiFile(MultiFileIndicator),
|
MultiFile(MultiFileIndicator),
|
||||||
NonCountedBacktracking(ClauseName, usize), // name, arity
|
NonCountedBacktracking(ClauseName, usize), // name, arity
|
||||||
Op(OpDecl),
|
Op(OpDecl),
|
||||||
|
SetPrologFlag(DoubleQuotes),
|
||||||
UseModule(ModuleSource),
|
UseModule(ModuleSource),
|
||||||
UseQualifiedModule(ModuleSource, Vec<ModuleExport>),
|
UseQualifiedModule(ModuleSource, Vec<ModuleExport>),
|
||||||
}
|
}
|
||||||
@@ -418,7 +432,7 @@ impl Declaration {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord)]
|
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
pub struct OpDecl(pub usize, pub Specifier, pub ClauseName);
|
pub struct OpDecl(pub usize, pub Specifier, pub ClauseName);
|
||||||
|
|
||||||
impl OpDecl {
|
impl OpDecl {
|
||||||
@@ -491,11 +505,11 @@ pub fn fetch_atom_op_spec(
|
|||||||
spec: Option<SharedOpDesc>,
|
spec: Option<SharedOpDesc>,
|
||||||
op_dir: &OpDir,
|
op_dir: &OpDir,
|
||||||
) -> Option<SharedOpDesc> {
|
) -> Option<SharedOpDesc> {
|
||||||
fetch_op_spec(name.clone(), 1, spec.clone(), op_dir)
|
fetch_op_spec_from_existing(name.clone(), 1, spec.clone(), op_dir)
|
||||||
.or_else(|| fetch_op_spec(name, 2, spec, 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,
|
name: ClauseName,
|
||||||
arity: usize,
|
arity: usize,
|
||||||
spec: Option<SharedOpDesc>,
|
spec: Option<SharedOpDesc>,
|
||||||
@@ -510,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
|
2 => op_dir
|
||||||
.get(&(name, Fixity::In))
|
.get(&(name, Fixity::In))
|
||||||
.and_then(|OpDirValue(spec, _)| {
|
.and_then(|OpDirValue(spec, _)| {
|
||||||
@@ -528,7 +550,7 @@ pub fn fetch_op_spec(
|
|||||||
}
|
}
|
||||||
|
|
||||||
op_dir
|
op_dir
|
||||||
.get(&(name.clone(), Fixity::Post))
|
.get(&(name, Fixity::Post))
|
||||||
.and_then(|OpDirValue(spec, _)| {
|
.and_then(|OpDirValue(spec, _)| {
|
||||||
if spec.prec() > 0 {
|
if spec.prec() > 0 {
|
||||||
Some(spec.clone())
|
Some(spec.clone())
|
||||||
@@ -537,24 +559,27 @@ pub fn fetch_op_spec(
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
_ => None,
|
_ => {
|
||||||
})
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type ModuleDir = IndexMap<ClauseName, Module>;
|
pub type ModuleDir = IndexMap<ClauseName, Module>;
|
||||||
|
|
||||||
#[derive(Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
pub enum ModuleExport {
|
pub enum ModuleExport {
|
||||||
OpDecl(OpDecl),
|
OpDecl(OpDecl),
|
||||||
PredicateKey(PredicateKey),
|
PredicateKey(PredicateKey),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct ModuleDecl {
|
pub struct ModuleDecl {
|
||||||
pub name: ClauseName,
|
pub name: ClauseName,
|
||||||
pub exports: Vec<ModuleExport>,
|
pub exports: Vec<ModuleExport>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
pub struct Module {
|
pub struct Module {
|
||||||
pub atom_tbl: TabledData<Atom>,
|
pub atom_tbl: TabledData<Atom>,
|
||||||
pub module_decl: ModuleDecl,
|
pub module_decl: ModuleDecl,
|
||||||
@@ -572,11 +597,33 @@ pub struct Module {
|
|||||||
pub listing_src: ListingSource,
|
pub listing_src: ListingSource,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum Number {
|
pub enum Number {
|
||||||
Float(OrderedFloat<f64>),
|
Float(OrderedFloat<f64>),
|
||||||
Integer(Integer),
|
Integer(Rc<Integer>),
|
||||||
Rational(Rational),
|
Rational(Rc<Rational>),
|
||||||
|
Fixnum(isize),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Integer> for Number {
|
||||||
|
#[inline]
|
||||||
|
fn from(n: Integer) -> Self {
|
||||||
|
Number::Integer(Rc::new(n))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Rational> for Number {
|
||||||
|
#[inline]
|
||||||
|
fn from(n: Rational) -> Self {
|
||||||
|
Number::Rational(Rc::new(n))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<isize> for Number {
|
||||||
|
#[inline]
|
||||||
|
fn from(n: isize) -> Self {
|
||||||
|
Number::Fixnum(n)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Number {
|
impl Default for Number {
|
||||||
@@ -585,48 +632,74 @@ impl Default for Number {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Number {
|
impl Into<Constant> for Number {
|
||||||
pub fn to_constant(self) -> Constant {
|
#[inline]
|
||||||
|
fn into(self) -> Constant {
|
||||||
match self {
|
match self {
|
||||||
|
Number::Fixnum(n) => Constant::Fixnum(n),
|
||||||
Number::Integer(n) => Constant::Integer(n),
|
Number::Integer(n) => Constant::Integer(n),
|
||||||
Number::Float(f) => Constant::Float(f),
|
Number::Float(f) => Constant::Float(f),
|
||||||
Number::Rational(r) => Constant::Rational(r),
|
Number::Rational(r) => Constant::Rational(r),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Into<HeapCellValue> for Number {
|
||||||
|
#[inline]
|
||||||
|
fn into(self) -> HeapCellValue {
|
||||||
|
match self {
|
||||||
|
Number::Fixnum(n) => HeapCellValue::Addr(Addr::Fixnum(n)),
|
||||||
|
Number::Integer(n) => HeapCellValue::Integer(n),
|
||||||
|
Number::Float(f) => HeapCellValue::Addr(Addr::Float(f)),
|
||||||
|
Number::Rational(r) => HeapCellValue::Rational(r),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
impl Number {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn is_positive(&self) -> bool {
|
pub fn is_positive(&self) -> bool {
|
||||||
match self {
|
match self {
|
||||||
&Number::Integer(ref n) => n > &0,
|
&Number::Fixnum(n) => n > 0,
|
||||||
|
&Number::Integer(ref n) => &**n > &0,
|
||||||
&Number::Float(OrderedFloat(f)) => f.is_sign_positive(),
|
&Number::Float(OrderedFloat(f)) => f.is_sign_positive(),
|
||||||
&Number::Rational(ref r) => r > &0,
|
&Number::Rational(ref r) => &**r > &0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn is_negative(&self) -> bool {
|
pub fn is_negative(&self) -> bool {
|
||||||
match self {
|
match self {
|
||||||
&Number::Integer(ref n) => n < &0,
|
&Number::Fixnum(n) => n < 0,
|
||||||
|
&Number::Integer(ref n) => &**n < &0,
|
||||||
&Number::Float(OrderedFloat(f)) => f.is_sign_negative(),
|
&Number::Float(OrderedFloat(f)) => f.is_sign_negative(),
|
||||||
&Number::Rational(ref r) => r < &0,
|
&Number::Rational(ref r) => &**r < &0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn is_zero(&self) -> bool {
|
pub fn is_zero(&self) -> bool {
|
||||||
match self {
|
match self {
|
||||||
&Number::Integer(ref n) => n == &0,
|
&Number::Fixnum(n) => n == 0,
|
||||||
|
&Number::Integer(ref n) => &**n == &0,
|
||||||
&Number::Float(f) => f == OrderedFloat(0f64),
|
&Number::Float(f) => f == OrderedFloat(0f64),
|
||||||
&Number::Rational(ref r) => r == &0,
|
&Number::Rational(ref r) => &**r == &0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn abs(self) -> Self {
|
pub fn abs(self) -> Self {
|
||||||
match self {
|
match self {
|
||||||
Number::Integer(n) => Number::Integer(n.abs()),
|
Number::Fixnum(n) =>
|
||||||
|
if let Some(n) = n.checked_abs() {
|
||||||
|
Number::from(n)
|
||||||
|
} else {
|
||||||
|
Number::from(Integer::from(n).abs())
|
||||||
|
}
|
||||||
|
Number::Integer(n) => Number::from(Integer::from(n.abs_ref())),
|
||||||
Number::Float(f) => Number::Float(OrderedFloat(f.abs())),
|
Number::Float(f) => Number::Float(OrderedFloat(f.abs())),
|
||||||
Number::Rational(r) => Number::Rational(r.abs()),
|
Number::Rational(r) => Number::from(Rational::from(r.abs_ref())),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
342
src/heap_iter.rs
Normal file
342
src/heap_iter.rs
Normal file
@@ -0,0 +1,342 @@
|
|||||||
|
use crate::machine::machine_indices::*;
|
||||||
|
use crate::machine::machine_state::*;
|
||||||
|
|
||||||
|
use crate::indexmap::IndexSet;
|
||||||
|
|
||||||
|
use std::cmp::Ordering;
|
||||||
|
use std::ops::Deref;
|
||||||
|
use std::vec::Vec;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct HCPreOrderIterator<'a> {
|
||||||
|
pub machine_st: &'a MachineState,
|
||||||
|
pub state_stack: Vec<Addr>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> HCPreOrderIterator<'a> {
|
||||||
|
pub fn new(machine_st: &'a MachineState, a: Addr) -> Self {
|
||||||
|
HCPreOrderIterator {
|
||||||
|
machine_st,
|
||||||
|
state_stack: vec![a],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn machine_st(&self) -> &MachineState {
|
||||||
|
&self.machine_st
|
||||||
|
}
|
||||||
|
|
||||||
|
fn follow_heap(&mut self, h: usize) -> Addr {
|
||||||
|
match &self.machine_st.heap[h] {
|
||||||
|
&HeapCellValue::NamedStr(arity, _, _) => {
|
||||||
|
for idx in (1 .. arity + 1).rev() {
|
||||||
|
self.state_stack.push(Addr::HeapCell(h + idx));
|
||||||
|
}
|
||||||
|
|
||||||
|
Addr::Str(h)
|
||||||
|
}
|
||||||
|
&HeapCellValue::Addr(a) => {
|
||||||
|
self.follow(a)
|
||||||
|
}
|
||||||
|
HeapCellValue::PartialString(..) => {
|
||||||
|
self.follow(Addr::PStrLocation(h, 0))
|
||||||
|
}
|
||||||
|
HeapCellValue::Atom(..) | HeapCellValue::DBRef(_)
|
||||||
|
| HeapCellValue::Integer(_) | HeapCellValue::Rational(_) => {
|
||||||
|
Addr::Con(h)
|
||||||
|
}
|
||||||
|
HeapCellValue::Stream(_) => {
|
||||||
|
Addr::Stream(h)
|
||||||
|
}
|
||||||
|
&HeapCellValue::TcpListener(_) => {
|
||||||
|
Addr::TcpListener(h)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// called under the assumption that the location at r is about to
|
||||||
|
// be visited, and so any follow up states need to be added to
|
||||||
|
// state_stack. returns the dereferenced Addr from Ref.
|
||||||
|
fn follow(&mut self, addr: Addr) -> Addr {
|
||||||
|
let da = self.machine_st.store(self.machine_st.deref(addr));
|
||||||
|
|
||||||
|
match da {
|
||||||
|
Addr::Lis(a) => {
|
||||||
|
self.state_stack.push(Addr::HeapCell(a + 1));
|
||||||
|
self.state_stack.push(Addr::HeapCell(a));
|
||||||
|
|
||||||
|
da
|
||||||
|
}
|
||||||
|
Addr::PStrLocation(h, n) => {
|
||||||
|
if let &HeapCellValue::PartialString(ref pstr, has_tail) = &self.machine_st.heap[h] {
|
||||||
|
if let Some(c) = pstr.range_from(n ..).next() {
|
||||||
|
if !pstr.at_end(n + c.len_utf8()) {
|
||||||
|
self.state_stack.push(Addr::PStrLocation(h, n + c.len_utf8()));
|
||||||
|
} else if has_tail {
|
||||||
|
self.state_stack.push(Addr::HeapCell(h + 1));
|
||||||
|
} else {
|
||||||
|
self.state_stack.push(Addr::EmptyList);
|
||||||
|
}
|
||||||
|
|
||||||
|
self.state_stack.push(Addr::Char(c));
|
||||||
|
} else if has_tail {
|
||||||
|
return self.follow(Addr::HeapCell(h + 1));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
|
|
||||||
|
Addr::PStrLocation(h, n)
|
||||||
|
}
|
||||||
|
Addr::Str(s) => {
|
||||||
|
self.follow_heap(s) // record terms of structure.
|
||||||
|
}
|
||||||
|
Addr::Con(h) => {
|
||||||
|
if let &HeapCellValue::PartialString(ref pstr, has_tail) = &self.machine_st.heap[h] {
|
||||||
|
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
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Addr::Con(h)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
da => {
|
||||||
|
da
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Iterator for HCPreOrderIterator<'a> {
|
||||||
|
type Item = Addr;
|
||||||
|
|
||||||
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
|
self.state_stack.pop().map(|a| self.follow(a))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait MutStackHCIterator<'b> where Self: Iterator
|
||||||
|
{
|
||||||
|
type MutStack;
|
||||||
|
|
||||||
|
fn stack(&'b mut self) -> Self::MutStack;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct HCPostOrderIterator<'a> {
|
||||||
|
base_iter: HCPreOrderIterator<'a>,
|
||||||
|
parent_stack: Vec<(usize, Addr)>, // number of children, parent node.
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Deref for HCPostOrderIterator<'a> {
|
||||||
|
type Target = HCPreOrderIterator<'a>;
|
||||||
|
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
&self.base_iter
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> HCPostOrderIterator<'a> {
|
||||||
|
pub fn new(base_iter: HCPreOrderIterator<'a>) -> Self {
|
||||||
|
HCPostOrderIterator {
|
||||||
|
base_iter,
|
||||||
|
parent_stack: vec![],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Iterator for HCPostOrderIterator<'a> {
|
||||||
|
type Item = Addr;
|
||||||
|
|
||||||
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
|
loop {
|
||||||
|
if let Some((child_count, node)) = self.parent_stack.pop() {
|
||||||
|
if child_count == 0 {
|
||||||
|
return Some(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
self.parent_stack.push((child_count - 1, node));
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(item) = self.base_iter.next() {
|
||||||
|
match self.base_iter.machine_st.heap.index_addr(&item).as_ref() {
|
||||||
|
&HeapCellValue::NamedStr(arity, ..) => {
|
||||||
|
self.parent_stack.push((arity, item));
|
||||||
|
}
|
||||||
|
&HeapCellValue::Addr(Addr::Lis(a)) => {
|
||||||
|
self.parent_stack.push((2, Addr::Lis(a)));
|
||||||
|
}
|
||||||
|
&HeapCellValue::Addr(Addr::PStrLocation(h, n)) => {
|
||||||
|
match &self.machine_st.heap[h] {
|
||||||
|
&HeapCellValue::PartialString(ref pstr, _) => {
|
||||||
|
let c = pstr.range_from(n ..).next().unwrap();
|
||||||
|
let next_n = n + c.len_utf8();
|
||||||
|
|
||||||
|
if !pstr.at_end(next_n) {
|
||||||
|
self.parent_stack.push((2, Addr::PStrLocation(h, next_n)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
return Some(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MachineState {
|
||||||
|
pub fn pre_order_iter<'a>(&'a self, a: Addr) -> HCPreOrderIterator<'a> {
|
||||||
|
HCPreOrderIterator::new(self, a)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn post_order_iter<'a>(&'a self, a: Addr) -> HCPostOrderIterator<'a> {
|
||||||
|
HCPostOrderIterator::new(HCPreOrderIterator::new(self, a))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn acyclic_pre_order_iter<'a>(&'a self, a: Addr,) -> HCAcyclicIterator<'a> {
|
||||||
|
HCAcyclicIterator::new(HCPreOrderIterator::new(self, a))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn zipped_acyclic_pre_order_iter<'a>(
|
||||||
|
&'a self,
|
||||||
|
a1: Addr,
|
||||||
|
a2: Addr,
|
||||||
|
) -> HCZippedAcyclicIterator<'a> {
|
||||||
|
HCZippedAcyclicIterator::new(
|
||||||
|
HCPreOrderIterator::new(self, a1),
|
||||||
|
HCPreOrderIterator::new(self, a2),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'b, 'a: 'b> MutStackHCIterator<'b> for HCPreOrderIterator<'a> {
|
||||||
|
type MutStack = &'b mut Vec<Addr>;
|
||||||
|
|
||||||
|
fn stack(&'b mut self) -> Self::MutStack {
|
||||||
|
&mut self.state_stack
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct HCAcyclicIterator<'a> {
|
||||||
|
iter: HCPreOrderIterator<'a>,
|
||||||
|
seen: IndexSet<Addr>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> HCAcyclicIterator<'a> {
|
||||||
|
pub fn new(iter: HCPreOrderIterator<'a>) -> Self {
|
||||||
|
HCAcyclicIterator {
|
||||||
|
iter,
|
||||||
|
seen: IndexSet::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Deref for HCAcyclicIterator<'a> {
|
||||||
|
type Target = HCPreOrderIterator<'a>;
|
||||||
|
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
&self.iter
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'b, 'a: 'b> MutStackHCIterator<'b> for HCAcyclicIterator<'a> {
|
||||||
|
type MutStack = &'b mut Vec<Addr>;
|
||||||
|
|
||||||
|
fn stack(&'b mut self) -> Self::MutStack {
|
||||||
|
self.iter.stack()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Iterator for HCAcyclicIterator<'a>
|
||||||
|
{
|
||||||
|
type Item = Addr;
|
||||||
|
|
||||||
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
|
while let Some(addr) = self.iter.stack().pop() {
|
||||||
|
if !self.seen.contains(&addr) {
|
||||||
|
self.iter.stack().push(addr.clone());
|
||||||
|
self.seen.insert(addr);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.iter.next()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct HCZippedAcyclicIterator<'a> {
|
||||||
|
i1: HCPreOrderIterator<'a>,
|
||||||
|
i2: HCPreOrderIterator<'a>,
|
||||||
|
seen: IndexSet<(Addr, Addr)>,
|
||||||
|
pub first_to_expire: Ordering,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'b, 'a: 'b> MutStackHCIterator<'b> for HCZippedAcyclicIterator<'a> {
|
||||||
|
type MutStack = (&'b mut Vec<Addr>, &'b mut Vec<Addr>);
|
||||||
|
|
||||||
|
fn stack(&'b mut self) -> Self::MutStack {
|
||||||
|
(self.i1.stack(), self.i2.stack())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> HCZippedAcyclicIterator<'a> {
|
||||||
|
pub fn new(i1: HCPreOrderIterator<'a>, i2: HCPreOrderIterator<'a>) -> Self {
|
||||||
|
HCZippedAcyclicIterator {
|
||||||
|
i1,
|
||||||
|
i2,
|
||||||
|
seen: IndexSet::new(),
|
||||||
|
first_to_expire: Ordering::Equal,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Iterator for HCZippedAcyclicIterator<'a>
|
||||||
|
{
|
||||||
|
type Item = (Addr, Addr);
|
||||||
|
|
||||||
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
|
while let (Some(a1), Some(a2)) = (self.i1.stack().pop(), self.i2.stack().pop()) {
|
||||||
|
if !self.seen.contains(&(a1.clone(), a2.clone())) {
|
||||||
|
self.i1.stack().push(a1.clone());
|
||||||
|
self.i2.stack().push(a2.clone());
|
||||||
|
|
||||||
|
self.seen.insert((a1, a2));
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
match (self.i1.next(), self.i2.next()) {
|
||||||
|
(Some(v1), Some(v2)) => Some((v1, v2)),
|
||||||
|
(Some(_), None) => {
|
||||||
|
self.first_to_expire = Ordering::Greater;
|
||||||
|
None
|
||||||
|
}
|
||||||
|
(None, Some(_)) => {
|
||||||
|
self.first_to_expire = Ordering::Less;
|
||||||
|
None
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
1577
src/heap_print.rs
Normal file
1577
src/heap_print.rs
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,20 +1,26 @@
|
|||||||
use prolog_parser::ast::*;
|
use crate::prolog_parser::ast::*;
|
||||||
|
use crate::prolog_parser::tabled_rc::*;
|
||||||
|
|
||||||
use crate::prolog::instructions::*;
|
use crate::instructions::*;
|
||||||
|
use crate::rug::Integer;
|
||||||
|
|
||||||
use indexmap::IndexMap;
|
use crate::indexmap::IndexMap;
|
||||||
|
|
||||||
use std::collections::VecDeque;
|
use std::collections::VecDeque;
|
||||||
|
use std::convert::TryFrom;
|
||||||
use std::hash::Hash;
|
use std::hash::Hash;
|
||||||
|
use std::rc::Rc;
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
enum IntIndex {
|
enum IntIndex {
|
||||||
External(usize),
|
External(usize),
|
||||||
Fail,
|
Fail,
|
||||||
Internal(usize),
|
Internal(usize),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
pub struct CodeOffsets {
|
pub struct CodeOffsets {
|
||||||
|
atom_tbl: TabledData<Atom>,
|
||||||
pub constants: IndexMap<Constant, ThirdLevelIndex>,
|
pub constants: IndexMap<Constant, ThirdLevelIndex>,
|
||||||
pub lists: ThirdLevelIndex,
|
pub lists: ThirdLevelIndex,
|
||||||
pub structures: IndexMap<(ClauseName, usize), ThirdLevelIndex>,
|
pub structures: IndexMap<(ClauseName, usize), ThirdLevelIndex>,
|
||||||
@@ -23,6 +29,7 @@ pub struct CodeOffsets {
|
|||||||
impl CodeOffsets {
|
impl CodeOffsets {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
CodeOffsets {
|
CodeOffsets {
|
||||||
|
atom_tbl: TabledData::new(Rc::new("_index".to_string())),
|
||||||
constants: IndexMap::new(),
|
constants: IndexMap::new(),
|
||||||
lists: Vec::new(),
|
lists: Vec::new(),
|
||||||
structures: IndexMap::new(),
|
structures: IndexMap::new(),
|
||||||
@@ -48,6 +55,94 @@ impl CodeOffsets {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn intercept_overlapping_constant(&mut self, constant: &Constant, index: usize) {
|
||||||
|
match constant {
|
||||||
|
&Constant::Atom(ref name, ref op) if name.is_char() => {
|
||||||
|
let c = name.as_str().chars().next().unwrap();
|
||||||
|
let code = self.constants
|
||||||
|
.entry(Constant::Char(c))
|
||||||
|
.or_insert(vec![]);
|
||||||
|
|
||||||
|
code.push(Self::add_index(code.is_empty(), index));
|
||||||
|
|
||||||
|
if op.is_some() {
|
||||||
|
let code = self.constants
|
||||||
|
.entry(Constant::Atom(name.clone(), None))
|
||||||
|
.or_insert(vec![]);
|
||||||
|
|
||||||
|
code.push(Self::add_index(false, index));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&Constant::Atom(ref name, Some(_)) => {
|
||||||
|
let code = self.constants
|
||||||
|
.entry(Constant::Atom(name.clone(), None))
|
||||||
|
.or_insert(vec![]);
|
||||||
|
|
||||||
|
code.push(Self::add_index(code.is_empty(), index));
|
||||||
|
}
|
||||||
|
&Constant::Char(c) => {
|
||||||
|
let atom = clause_name!(c.to_string(), self.atom_tbl.clone());
|
||||||
|
|
||||||
|
let code = self.constants
|
||||||
|
.entry(Constant::Atom(atom, None))
|
||||||
|
.or_insert(vec![]);
|
||||||
|
|
||||||
|
code.push(Self::add_index(code.is_empty(), index));
|
||||||
|
}
|
||||||
|
&Constant::Fixnum(n) => {
|
||||||
|
let code = self.constants
|
||||||
|
.entry(Constant::Integer(Rc::new(Integer::from(n))))
|
||||||
|
.or_insert(vec![]);
|
||||||
|
|
||||||
|
code.push(Self::add_index(code.is_empty(), index));
|
||||||
|
|
||||||
|
if n >= 0 {
|
||||||
|
if let Ok(n) = usize::try_from(n) {
|
||||||
|
let code = self.constants
|
||||||
|
.entry(Constant::Usize(n))
|
||||||
|
.or_insert(vec![]);
|
||||||
|
|
||||||
|
code.push(Self::add_index(code.is_empty(), index));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&Constant::Integer(ref n) => {
|
||||||
|
if let Some(n) = n.to_isize() {
|
||||||
|
let code = self.constants
|
||||||
|
.entry(Constant::Fixnum(n))
|
||||||
|
.or_insert(vec![]);
|
||||||
|
|
||||||
|
code.push(Self::add_index(code.is_empty(), index));
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(n) = n.to_usize() {
|
||||||
|
let code = self.constants
|
||||||
|
.entry(Constant::Usize(n))
|
||||||
|
.or_insert(vec![]);
|
||||||
|
|
||||||
|
code.push(Self::add_index(code.is_empty(), index));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&Constant::Usize(n) => {
|
||||||
|
let code = self.constants
|
||||||
|
.entry(Constant::Integer(Rc::new(Integer::from(n))))
|
||||||
|
.or_insert(vec![]);
|
||||||
|
|
||||||
|
code.push(Self::add_index(code.is_empty(), index));
|
||||||
|
|
||||||
|
if let Ok(n) = isize::try_from(n) {
|
||||||
|
let code = self.constants
|
||||||
|
.entry(Constant::Fixnum(n))
|
||||||
|
.or_insert(vec![]);
|
||||||
|
|
||||||
|
code.push(Self::add_index(code.is_empty(), index));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn index_term(&mut self, first_arg: &Term, index: usize) {
|
pub fn index_term(&mut self, first_arg: &Term, index: usize) {
|
||||||
match first_arg {
|
match first_arg {
|
||||||
&Term::Clause(_, ref name, ref terms, _) => {
|
&Term::Clause(_, ref name, ref terms, _) => {
|
||||||
@@ -59,27 +154,22 @@ impl CodeOffsets {
|
|||||||
let is_initial_index = code.is_empty();
|
let is_initial_index = code.is_empty();
|
||||||
code.push(Self::add_index(is_initial_index, index));
|
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();
|
let is_initial_index = self.lists.is_empty();
|
||||||
self.lists.push(Self::add_index(is_initial_index, index));
|
self.lists.push(Self::add_index(is_initial_index, index));
|
||||||
}
|
}
|
||||||
&Term::Constant(_, Constant::String(n, ref s)) => {
|
|
||||||
let is_initial_index = self.lists.is_empty();
|
|
||||||
self.lists.push(Self::add_index(is_initial_index, index));
|
|
||||||
|
|
||||||
let constant = Constant::String(n, s.clone());
|
|
||||||
let code = self.constants.entry(constant).or_insert(Vec::new());
|
|
||||||
|
|
||||||
let is_initial_index = code.is_empty();
|
|
||||||
code.push(Self::add_index(is_initial_index, index));
|
|
||||||
}
|
|
||||||
&Term::Constant(_, ref constant) => {
|
&Term::Constant(_, ref constant) => {
|
||||||
let code = self.constants.entry(constant.clone()).or_insert(Vec::new());
|
self.intercept_overlapping_constant(constant, index);
|
||||||
|
|
||||||
|
let code = self.constants
|
||||||
|
.entry(constant.clone())
|
||||||
|
.or_insert(vec![]);
|
||||||
|
|
||||||
let is_initial_index = code.is_empty();
|
let is_initial_index = code.is_empty();
|
||||||
code.push(Self::add_index(is_initial_index, index));
|
code.push(Self::add_index(is_initial_index, index));
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -227,12 +317,11 @@ impl CodeOffsets {
|
|||||||
fn switch_on_lst_offset_from(
|
fn switch_on_lst_offset_from(
|
||||||
lst_loc: IntIndex,
|
lst_loc: IntIndex,
|
||||||
prelude_len: usize,
|
prelude_len: usize,
|
||||||
lst_offset: usize,
|
|
||||||
) -> usize {
|
) -> usize {
|
||||||
match lst_loc {
|
match lst_loc {
|
||||||
IntIndex::External(o) => o + prelude_len + 1,
|
IntIndex::External(o) => o + prelude_len + 1,
|
||||||
IntIndex::Fail => 0,
|
IntIndex::Fail => 0,
|
||||||
IntIndex::Internal(_) => prelude_len - lst_offset + 1,
|
IntIndex::Internal(_) => 1, // this internal is always 0.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -245,8 +334,6 @@ impl CodeOffsets {
|
|||||||
let mut prelude = VecDeque::new();
|
let mut prelude = VecDeque::new();
|
||||||
|
|
||||||
let lst_loc = Self::switch_on_list(self.lists, &mut prelude);
|
let lst_loc = Self::switch_on_list(self.lists, &mut prelude);
|
||||||
let lst_offset = prelude.len();
|
|
||||||
|
|
||||||
let str_loc = Self::switch_on_structure(self.structures, &mut prelude);
|
let str_loc = Self::switch_on_structure(self.structures, &mut prelude);
|
||||||
let con_loc = Self::switch_on_constant(self.constants, &mut prelude);
|
let con_loc = Self::switch_on_constant(self.constants, &mut prelude);
|
||||||
|
|
||||||
@@ -254,18 +341,19 @@ impl CodeOffsets {
|
|||||||
|
|
||||||
for (index, line) in prelude.iter_mut().enumerate() {
|
for (index, line) in prelude.iter_mut().enumerate() {
|
||||||
match line {
|
match line {
|
||||||
&mut Line::IndexedChoice(IndexedChoiceInstruction::Try(ref mut i))
|
&mut Line::IndexedChoice(IndexedChoiceInstruction::Try(ref mut i)) |
|
||||||
| &mut Line::IndexedChoice(IndexedChoiceInstruction::Retry(ref mut i))
|
&mut Line::IndexedChoice(IndexedChoiceInstruction::Retry(ref mut i)) |
|
||||||
| &mut Line::IndexedChoice(IndexedChoiceInstruction::Trust(ref mut i)) => {
|
&mut Line::IndexedChoice(IndexedChoiceInstruction::Trust(ref mut i)) => {
|
||||||
*i += prelude_length - index
|
*i += prelude_length - index;
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
}
|
}
|
||||||
_ => {}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let str_loc = Self::switch_on_str_offset_from(str_loc, prelude.len(), con_loc);
|
let str_loc = Self::switch_on_str_offset_from(str_loc, prelude.len(), con_loc);
|
||||||
let con_loc = Self::switch_on_con_offset_from(con_loc, prelude.len());
|
let con_loc = Self::switch_on_con_offset_from(con_loc, prelude.len());
|
||||||
let lst_loc = Self::switch_on_lst_offset_from(lst_loc, prelude.len(), lst_offset);
|
let lst_loc = Self::switch_on_lst_offset_from(lst_loc, prelude.len());
|
||||||
|
|
||||||
let switch_instr =
|
let switch_instr =
|
||||||
IndexingInstruction::SwitchOnTerm(prelude.len() + 1, con_loc, lst_loc, str_loc);
|
IndexingInstruction::SwitchOnTerm(prelude.len() + 1, con_loc, lst_loc, str_loc);
|
||||||
@@ -1,29 +1,30 @@
|
|||||||
use prolog_parser::ast::*;
|
use crate::prolog_parser::ast::*;
|
||||||
|
|
||||||
use crate::prolog::clause_types::*;
|
use crate::clause_types::*;
|
||||||
use crate::prolog::forms::*;
|
use crate::forms::*;
|
||||||
use crate::prolog::machine::machine_errors::MachineStub;
|
use crate::machine::heap::*;
|
||||||
use crate::prolog::machine::machine_indices::*;
|
use crate::machine::machine_errors::MachineStub;
|
||||||
|
use crate::machine::machine_indices::*;
|
||||||
|
use crate::rug::Integer;
|
||||||
|
|
||||||
use crate::prolog::rug::Integer;
|
use crate::indexmap::IndexMap;
|
||||||
|
|
||||||
use indexmap::IndexMap;
|
|
||||||
|
|
||||||
use std::collections::VecDeque;
|
use std::collections::VecDeque;
|
||||||
|
use std::rc::Rc;
|
||||||
|
|
||||||
fn reg_type_into_functor(r: RegType) -> MachineStub {
|
fn reg_type_into_functor(r: RegType) -> MachineStub {
|
||||||
match r {
|
match r {
|
||||||
RegType::Temp(r) => functor!("x", 1, [heap_integer!(Integer::from(r))]),
|
RegType::Temp(r) => functor!("x", [integer(r)]),
|
||||||
RegType::Perm(r) => functor!("y", 1, [heap_integer!(Integer::from(r))]),
|
RegType::Perm(r) => functor!("y", [integer(r)]),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Level {
|
impl Level {
|
||||||
fn into_functor(self) -> MachineStub {
|
fn into_functor(self) -> MachineStub {
|
||||||
match self {
|
match self {
|
||||||
Level::Root => functor!("level", 1, [heap_atom!("root")]),
|
Level::Root => functor!("level", [atom("root")]),
|
||||||
Level::Shallow => functor!("level", 1, [heap_atom!("shallow")]),
|
Level::Shallow => functor!("level", [atom("shallow")]),
|
||||||
Level::Deep => functor!("level", 1, [heap_atom!("deep")]),
|
Level::Deep => functor!("level", [atom("deep")]),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -31,15 +32,20 @@ impl Level {
|
|||||||
impl ArithmeticTerm {
|
impl ArithmeticTerm {
|
||||||
fn into_functor(&self) -> MachineStub {
|
fn into_functor(&self) -> MachineStub {
|
||||||
match self {
|
match self {
|
||||||
&ArithmeticTerm::Reg(r) => reg_type_into_functor(r),
|
&ArithmeticTerm::Reg(r) => {
|
||||||
&ArithmeticTerm::Interm(i) => {
|
reg_type_into_functor(r)
|
||||||
functor!("intermediate", 1, [heap_integer!(Integer::from(i))])
|
}
|
||||||
|
&ArithmeticTerm::Interm(i) => {
|
||||||
|
functor!("intermediate", [integer(i)])
|
||||||
|
}
|
||||||
|
&ArithmeticTerm::Number(ref n) => {
|
||||||
|
vec![n.clone().into()]
|
||||||
}
|
}
|
||||||
&ArithmeticTerm::Number(ref n) => vec![heap_con!(n.clone().to_constant())],
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
pub enum ChoiceInstruction {
|
pub enum ChoiceInstruction {
|
||||||
DefaultRetryMeElse(usize),
|
DefaultRetryMeElse(usize),
|
||||||
DefaultTrustMe,
|
DefaultTrustMe,
|
||||||
@@ -52,22 +58,25 @@ impl ChoiceInstruction {
|
|||||||
pub fn to_functor(&self) -> MachineStub {
|
pub fn to_functor(&self) -> MachineStub {
|
||||||
match self {
|
match self {
|
||||||
&ChoiceInstruction::TryMeElse(offset) => {
|
&ChoiceInstruction::TryMeElse(offset) => {
|
||||||
functor!("try_me_else", 1, [heap_integer!(Integer::from(offset))])
|
functor!("try_me_else", [integer(offset)])
|
||||||
}
|
}
|
||||||
&ChoiceInstruction::RetryMeElse(offset) => {
|
&ChoiceInstruction::RetryMeElse(offset) => {
|
||||||
functor!("retry_me_else", 1, [heap_integer!(Integer::from(offset))])
|
functor!("retry_me_else", [integer(offset)])
|
||||||
|
}
|
||||||
|
&ChoiceInstruction::TrustMe => {
|
||||||
|
functor!("trust_me")
|
||||||
|
}
|
||||||
|
&ChoiceInstruction::DefaultRetryMeElse(offset) => {
|
||||||
|
functor!("default_retry_me_else", [integer(offset)])
|
||||||
|
}
|
||||||
|
&ChoiceInstruction::DefaultTrustMe => {
|
||||||
|
functor!("default_trust_me")
|
||||||
}
|
}
|
||||||
&ChoiceInstruction::TrustMe => vec![heap_atom!("trust_me")],
|
|
||||||
&ChoiceInstruction::DefaultRetryMeElse(offset) => functor!(
|
|
||||||
"default_retry_me_else",
|
|
||||||
1,
|
|
||||||
[heap_integer!(Integer::from(offset))]
|
|
||||||
),
|
|
||||||
&ChoiceInstruction::DefaultTrustMe => vec![heap_atom!("default_trust_me")],
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
pub enum CutInstruction {
|
pub enum CutInstruction {
|
||||||
Cut(RegType),
|
Cut(RegType),
|
||||||
GetLevel(RegType),
|
GetLevel(RegType),
|
||||||
@@ -79,25 +88,25 @@ impl CutInstruction {
|
|||||||
pub fn to_functor(&self, h: usize) -> MachineStub {
|
pub fn to_functor(&self, h: usize) -> MachineStub {
|
||||||
match self {
|
match self {
|
||||||
&CutInstruction::Cut(r) => {
|
&CutInstruction::Cut(r) => {
|
||||||
let mut stub = functor!("cut", 1, [heap_str!(h + 2)]);
|
let rt_stub = reg_type_into_functor(r);
|
||||||
stub.append(&mut reg_type_into_functor(r));
|
functor!("cut", [aux(h, 0)], [rt_stub])
|
||||||
stub
|
|
||||||
}
|
}
|
||||||
&CutInstruction::GetLevel(r) => {
|
&CutInstruction::GetLevel(r) => {
|
||||||
let mut stub = functor!("get_level", 1, [heap_str!(h + 2)]);
|
let rt_stub = reg_type_into_functor(r);
|
||||||
stub.append(&mut reg_type_into_functor(r));
|
functor!("get_level", [aux(h, 0)], [rt_stub])
|
||||||
stub
|
|
||||||
}
|
}
|
||||||
&CutInstruction::GetLevelAndUnify(r) => {
|
&CutInstruction::GetLevelAndUnify(r) => {
|
||||||
let mut stub = functor!("get_level_and_unify", 1, [heap_str!(h + 2)]);
|
let rt_stub = reg_type_into_functor(r);
|
||||||
stub.append(&mut reg_type_into_functor(r));
|
functor!("get_level_and_unify", [aux(h, 0)], [rt_stub])
|
||||||
stub
|
}
|
||||||
|
&CutInstruction::NeckCut => {
|
||||||
|
functor!("neck_cut")
|
||||||
}
|
}
|
||||||
&CutInstruction::NeckCut => vec![heap_atom!("neck_cut")],
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
pub enum IndexedChoiceInstruction {
|
pub enum IndexedChoiceInstruction {
|
||||||
Retry(usize),
|
Retry(usize),
|
||||||
Trust(usize),
|
Trust(usize),
|
||||||
@@ -122,18 +131,19 @@ impl IndexedChoiceInstruction {
|
|||||||
pub fn to_functor(&self) -> MachineStub {
|
pub fn to_functor(&self) -> MachineStub {
|
||||||
match self {
|
match self {
|
||||||
&IndexedChoiceInstruction::Try(offset) => {
|
&IndexedChoiceInstruction::Try(offset) => {
|
||||||
functor!("try", 1, [heap_integer!(Integer::from(offset))])
|
functor!("try", [integer(offset)])
|
||||||
}
|
}
|
||||||
&IndexedChoiceInstruction::Trust(offset) => {
|
&IndexedChoiceInstruction::Trust(offset) => {
|
||||||
functor!("trust", 1, [heap_integer!(Integer::from(offset))])
|
functor!("trust", [integer(offset)])
|
||||||
}
|
}
|
||||||
&IndexedChoiceInstruction::Retry(offset) => {
|
&IndexedChoiceInstruction::Retry(offset) => {
|
||||||
functor!("retry", 1, [heap_integer!(Integer::from(offset))])
|
functor!("retry", [integer(offset)])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
pub enum Line {
|
pub enum Line {
|
||||||
Arithmetic(ArithmeticInstruction),
|
Arithmetic(ArithmeticInstruction),
|
||||||
Choice(ChoiceInstruction),
|
Choice(ChoiceInstruction),
|
||||||
@@ -169,7 +179,7 @@ impl Line {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum ArithmeticInstruction {
|
pub enum ArithmeticInstruction {
|
||||||
Add(ArithmeticTerm, ArithmeticTerm, usize),
|
Add(ArithmeticTerm, ArithmeticTerm, usize),
|
||||||
Sub(ArithmeticTerm, ArithmeticTerm, usize),
|
Sub(ArithmeticTerm, ArithmeticTerm, usize),
|
||||||
@@ -220,14 +230,11 @@ fn arith_instr_unary_functor(
|
|||||||
) -> MachineStub {
|
) -> MachineStub {
|
||||||
let at_stub = at.into_functor();
|
let at_stub = at.into_functor();
|
||||||
|
|
||||||
let mut stub = functor!(
|
functor!(
|
||||||
name,
|
name,
|
||||||
2,
|
[aux(h, 0), integer(t)],
|
||||||
[heap_cell!(h + 4), heap_integer!(Integer::from(t))]
|
[at_stub]
|
||||||
);
|
)
|
||||||
|
|
||||||
stub.extend(at_stub.into_iter());
|
|
||||||
stub
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn arith_instr_bin_functor(
|
fn arith_instr_bin_functor(
|
||||||
@@ -240,20 +247,11 @@ fn arith_instr_bin_functor(
|
|||||||
let at_1_stub = at_1.into_functor();
|
let at_1_stub = at_1.into_functor();
|
||||||
let at_2_stub = at_2.into_functor();
|
let at_2_stub = at_2.into_functor();
|
||||||
|
|
||||||
let mut stub = functor!(
|
functor!(
|
||||||
name,
|
name,
|
||||||
3,
|
[aux(h, 0), aux(h, 1), integer(t)],
|
||||||
[
|
[at_1_stub, at_2_stub]
|
||||||
heap_cell!(h + 4),
|
)
|
||||||
heap_cell!(h + 4 + at_1_stub.len()),
|
|
||||||
heap_integer!(Integer::from(t))
|
|
||||||
]
|
|
||||||
);
|
|
||||||
|
|
||||||
stub.extend(at_1_stub.into_iter());
|
|
||||||
stub.extend(at_2_stub.into_iter());
|
|
||||||
|
|
||||||
stub
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ArithmeticInstruction {
|
impl ArithmeticInstruction {
|
||||||
@@ -319,17 +317,39 @@ impl ArithmeticInstruction {
|
|||||||
&ArithmeticInstruction::Gcd(ref at_1, ref at_2, t) => {
|
&ArithmeticInstruction::Gcd(ref at_1, ref at_2, t) => {
|
||||||
arith_instr_bin_functor(h, "gcd", at_1, at_2, t)
|
arith_instr_bin_functor(h, "gcd", at_1, at_2, t)
|
||||||
}
|
}
|
||||||
&ArithmeticInstruction::Sign(ref at, t) => arith_instr_unary_functor(h, "sign", at, t),
|
&ArithmeticInstruction::Sign(ref at, t) => {
|
||||||
&ArithmeticInstruction::Cos(ref at, t) => arith_instr_unary_functor(h, "cos", at, t),
|
arith_instr_unary_functor(h, "sign", at, t)
|
||||||
&ArithmeticInstruction::Sin(ref at, t) => arith_instr_unary_functor(h, "sin", at, t),
|
}
|
||||||
&ArithmeticInstruction::Tan(ref at, t) => arith_instr_unary_functor(h, "tan", at, t),
|
&ArithmeticInstruction::Cos(ref at, t) => {
|
||||||
&ArithmeticInstruction::Log(ref at, t) => arith_instr_unary_functor(h, "log", at, t),
|
arith_instr_unary_functor(h, "cos", at, t)
|
||||||
&ArithmeticInstruction::Exp(ref at, t) => arith_instr_unary_functor(h, "exp", at, t),
|
}
|
||||||
&ArithmeticInstruction::ACos(ref at, t) => arith_instr_unary_functor(h, "acos", at, t),
|
&ArithmeticInstruction::Sin(ref at, t) => {
|
||||||
&ArithmeticInstruction::ASin(ref at, t) => arith_instr_unary_functor(h, "asin", at, t),
|
arith_instr_unary_functor(h, "sin", at, t)
|
||||||
&ArithmeticInstruction::ATan(ref at, t) => arith_instr_unary_functor(h, "atan", at, t),
|
}
|
||||||
&ArithmeticInstruction::Sqrt(ref at, t) => arith_instr_unary_functor(h, "sqrt", at, t),
|
&ArithmeticInstruction::Tan(ref at, t) => {
|
||||||
&ArithmeticInstruction::Abs(ref at, t) => arith_instr_unary_functor(h, "abs", at, t),
|
arith_instr_unary_functor(h, "tan", at, t)
|
||||||
|
}
|
||||||
|
&ArithmeticInstruction::Log(ref at, t) => {
|
||||||
|
arith_instr_unary_functor(h, "log", at, t)
|
||||||
|
}
|
||||||
|
&ArithmeticInstruction::Exp(ref at, t) => {
|
||||||
|
arith_instr_unary_functor(h, "exp", at, t)
|
||||||
|
}
|
||||||
|
&ArithmeticInstruction::ACos(ref at, t) => {
|
||||||
|
arith_instr_unary_functor(h, "acos", at, t)
|
||||||
|
}
|
||||||
|
&ArithmeticInstruction::ASin(ref at, t) => {
|
||||||
|
arith_instr_unary_functor(h, "asin", at, t)
|
||||||
|
}
|
||||||
|
&ArithmeticInstruction::ATan(ref at, t) => {
|
||||||
|
arith_instr_unary_functor(h, "atan", at, t)
|
||||||
|
}
|
||||||
|
&ArithmeticInstruction::Sqrt(ref at, t) => {
|
||||||
|
arith_instr_unary_functor(h, "sqrt", at, t)
|
||||||
|
}
|
||||||
|
&ArithmeticInstruction::Abs(ref at, t) => {
|
||||||
|
arith_instr_unary_functor(h, "abs", at, t)
|
||||||
|
}
|
||||||
&ArithmeticInstruction::Float(ref at, t) => {
|
&ArithmeticInstruction::Float(ref at, t) => {
|
||||||
arith_instr_unary_functor(h, "float", at, t)
|
arith_instr_unary_functor(h, "float", at, t)
|
||||||
}
|
}
|
||||||
@@ -345,8 +365,12 @@ impl ArithmeticInstruction {
|
|||||||
&ArithmeticInstruction::Floor(ref at, t) => {
|
&ArithmeticInstruction::Floor(ref at, t) => {
|
||||||
arith_instr_unary_functor(h, "floor", at, t)
|
arith_instr_unary_functor(h, "floor", at, t)
|
||||||
}
|
}
|
||||||
&ArithmeticInstruction::Neg(ref at, t) => arith_instr_unary_functor(h, "-", at, t),
|
&ArithmeticInstruction::Neg(ref at, t) => {
|
||||||
&ArithmeticInstruction::Plus(ref at, t) => arith_instr_unary_functor(h, "+", at, t),
|
arith_instr_unary_functor(h, "-", at, t)
|
||||||
|
}
|
||||||
|
&ArithmeticInstruction::Plus(ref at, t) => {
|
||||||
|
arith_instr_unary_functor(h, "+", at, t)
|
||||||
|
}
|
||||||
&ArithmeticInstruction::BitwiseComplement(ref at, t) => {
|
&ArithmeticInstruction::BitwiseComplement(ref at, t) => {
|
||||||
arith_instr_unary_functor(h, "\\", at, t)
|
arith_instr_unary_functor(h, "\\", at, t)
|
||||||
}
|
}
|
||||||
@@ -354,6 +378,7 @@ impl ArithmeticInstruction {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
pub enum ControlInstruction {
|
pub enum ControlInstruction {
|
||||||
Allocate(usize), // num_frames.
|
Allocate(usize), // num_frames.
|
||||||
// name, arity, perm_vars after threshold, last call, use default call policy.
|
// name, arity, perm_vars after threshold, last call, use default call policy.
|
||||||
@@ -378,33 +403,28 @@ impl ControlInstruction {
|
|||||||
pub fn to_functor(&self) -> MachineStub {
|
pub fn to_functor(&self) -> MachineStub {
|
||||||
match self {
|
match self {
|
||||||
&ControlInstruction::Allocate(num_frames) => {
|
&ControlInstruction::Allocate(num_frames) => {
|
||||||
functor!("allocate", 1, [heap_integer!(Integer::from(num_frames))])
|
functor!("allocate", [integer(num_frames)])
|
||||||
|
}
|
||||||
|
&ControlInstruction::CallClause(ref ct, arity, _, false, _) => {
|
||||||
|
functor!("call", [clause_name(ct.name()), integer(arity)])
|
||||||
|
}
|
||||||
|
&ControlInstruction::CallClause(ref ct, arity, _, true, _) => {
|
||||||
|
functor!("execute", [clause_name(ct.name()), integer(arity)])
|
||||||
|
}
|
||||||
|
&ControlInstruction::Deallocate => {
|
||||||
|
functor!("deallocate")
|
||||||
}
|
}
|
||||||
&ControlInstruction::CallClause(ref ct, arity, _, false, _) => functor!(
|
|
||||||
"call",
|
|
||||||
2,
|
|
||||||
[
|
|
||||||
heap_con!(Constant::Atom(ct.name(), None)),
|
|
||||||
heap_integer!(Integer::from(arity))
|
|
||||||
]
|
|
||||||
),
|
|
||||||
&ControlInstruction::CallClause(ref ct, arity, _, true, _) => functor!(
|
|
||||||
"execute",
|
|
||||||
2,
|
|
||||||
[
|
|
||||||
heap_con!(Constant::Atom(ct.name(), None)),
|
|
||||||
heap_integer!(Integer::from(arity))
|
|
||||||
]
|
|
||||||
),
|
|
||||||
&ControlInstruction::Deallocate => vec![heap_atom!("deallocate")],
|
|
||||||
&ControlInstruction::JmpBy(_, offset, ..) => {
|
&ControlInstruction::JmpBy(_, offset, ..) => {
|
||||||
functor!("jmp_by", 1, [heap_integer!(Integer::from(offset))])
|
functor!("jmp_by", [integer(offset)])
|
||||||
|
}
|
||||||
|
&ControlInstruction::Proceed => {
|
||||||
|
functor!("proceed")
|
||||||
}
|
}
|
||||||
&ControlInstruction::Proceed => vec![heap_atom!("proceed")],
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
pub enum IndexingInstruction {
|
pub enum IndexingInstruction {
|
||||||
SwitchOnTerm(usize, usize, usize, usize),
|
SwitchOnTerm(usize, usize, usize, usize),
|
||||||
SwitchOnConstant(usize, IndexMap<Constant, usize>),
|
SwitchOnConstant(usize, IndexMap<Constant, usize>),
|
||||||
@@ -420,34 +440,36 @@ impl From<IndexingInstruction> for Line {
|
|||||||
impl IndexingInstruction {
|
impl IndexingInstruction {
|
||||||
pub fn to_functor(&self) -> MachineStub {
|
pub fn to_functor(&self) -> MachineStub {
|
||||||
match self {
|
match self {
|
||||||
&IndexingInstruction::SwitchOnTerm(vars, constants, lists, structures) => functor!(
|
&IndexingInstruction::SwitchOnTerm(vars, constants, lists, structures) => {
|
||||||
"switch_on_term",
|
functor!(
|
||||||
4,
|
"switch_on_term",
|
||||||
[
|
[integer(vars),
|
||||||
heap_integer!(Integer::from(vars)),
|
integer(constants),
|
||||||
heap_integer!(Integer::from(constants)),
|
integer(lists),
|
||||||
heap_integer!(Integer::from(lists)),
|
integer(structures)]
|
||||||
heap_integer!(Integer::from(structures))
|
)
|
||||||
]
|
}
|
||||||
),
|
&IndexingInstruction::SwitchOnConstant(constants, _) => {
|
||||||
&IndexingInstruction::SwitchOnConstant(constants, _) => functor!(
|
functor!(
|
||||||
"switch_on_constant",
|
"switch_on_constant",
|
||||||
1,
|
[integer(constants)]
|
||||||
[heap_integer!(Integer::from(constants))]
|
)
|
||||||
),
|
}
|
||||||
&IndexingInstruction::SwitchOnStructure(structures, _) => functor!(
|
&IndexingInstruction::SwitchOnStructure(structures, _) => {
|
||||||
"switch_on_structure",
|
functor!(
|
||||||
1,
|
"switch_on_structure",
|
||||||
[heap_integer!(Integer::from(structures))]
|
[integer(structures)]
|
||||||
),
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum FactInstruction {
|
pub enum FactInstruction {
|
||||||
GetConstant(Level, Constant, RegType),
|
GetConstant(Level, Constant, RegType),
|
||||||
GetList(Level, RegType),
|
GetList(Level, RegType),
|
||||||
|
GetPartialString(Level, String, RegType, bool),
|
||||||
GetStructure(ClauseType, usize, RegType),
|
GetStructure(ClauseType, usize, RegType),
|
||||||
GetValue(RegType, usize),
|
GetValue(RegType, usize),
|
||||||
GetVariable(RegType, usize),
|
GetVariable(RegType, usize),
|
||||||
@@ -461,96 +483,106 @@ pub enum FactInstruction {
|
|||||||
impl FactInstruction {
|
impl FactInstruction {
|
||||||
pub fn to_functor(&self, h: usize) -> MachineStub {
|
pub fn to_functor(&self, h: usize) -> MachineStub {
|
||||||
match self {
|
match self {
|
||||||
&FactInstruction::GetConstant(lvl, ref constant, r) => {
|
&FactInstruction::GetConstant(lvl, ref c, r) => {
|
||||||
let mut stub = functor!(
|
let lvl_stub = lvl.into_functor();
|
||||||
|
let rt_stub = reg_type_into_functor(r);
|
||||||
|
|
||||||
|
functor!(
|
||||||
"get_constant",
|
"get_constant",
|
||||||
3,
|
[aux(h, 0), constant(h, c), aux(h, 1)],
|
||||||
[
|
[lvl_stub, rt_stub]
|
||||||
heap_str!(h + 4),
|
)
|
||||||
heap_con!(constant.clone()),
|
|
||||||
heap_str!(h + 6)
|
|
||||||
]
|
|
||||||
);
|
|
||||||
|
|
||||||
stub.append(&mut lvl.into_functor());
|
|
||||||
stub.append(&mut reg_type_into_functor(r));
|
|
||||||
|
|
||||||
stub
|
|
||||||
}
|
}
|
||||||
&FactInstruction::GetList(lvl, r) => {
|
&FactInstruction::GetList(lvl, r) => {
|
||||||
let mut stub = functor!("get_list", 2, [heap_str!(h + 3), heap_str!(h + 5)]);
|
let lvl_stub = lvl.into_functor();
|
||||||
stub.append(&mut lvl.into_functor());
|
let rt_stub = reg_type_into_functor(r);
|
||||||
stub.append(&mut reg_type_into_functor(r));
|
|
||||||
|
|
||||||
stub
|
functor!(
|
||||||
|
"get_list",
|
||||||
|
[aux(h, 0), aux(h, 1)],
|
||||||
|
[lvl_stub, rt_stub]
|
||||||
|
)
|
||||||
|
}
|
||||||
|
&FactInstruction::GetPartialString(lvl, ref s, r, has_tail) => {
|
||||||
|
let lvl_stub = lvl.into_functor();
|
||||||
|
let rt_stub = reg_type_into_functor(r);
|
||||||
|
|
||||||
|
functor!(
|
||||||
|
"get_partial_string",
|
||||||
|
[aux(h, 0), string(h, s), aux(h, 1), boolean(has_tail)],
|
||||||
|
[lvl_stub, rt_stub]
|
||||||
|
)
|
||||||
}
|
}
|
||||||
&FactInstruction::GetStructure(ref ct, arity, r) => {
|
&FactInstruction::GetStructure(ref ct, arity, r) => {
|
||||||
let mut stub = functor!(
|
let rt_stub = reg_type_into_functor(r);
|
||||||
"get_structure",
|
|
||||||
3,
|
|
||||||
[
|
|
||||||
heap_con!(Constant::Atom(ct.name(), None)),
|
|
||||||
heap_integer!(Integer::from(arity)),
|
|
||||||
heap_str!(h + 4)
|
|
||||||
]
|
|
||||||
);
|
|
||||||
stub.append(&mut reg_type_into_functor(r));
|
|
||||||
|
|
||||||
stub
|
functor!(
|
||||||
|
"get_structure",
|
||||||
|
[clause_name(ct.name()), integer(arity), aux(h, 0)],
|
||||||
|
[rt_stub]
|
||||||
|
)
|
||||||
}
|
}
|
||||||
&FactInstruction::GetValue(r, arg) => {
|
&FactInstruction::GetValue(r, arg) => {
|
||||||
let mut stub = functor!(
|
let rt_stub = reg_type_into_functor(r);
|
||||||
"get_value",
|
|
||||||
2,
|
|
||||||
[heap_str!(h + 3), heap_integer!(Integer::from(arg))]
|
|
||||||
);
|
|
||||||
stub.append(&mut reg_type_into_functor(r));
|
|
||||||
|
|
||||||
stub
|
functor!(
|
||||||
|
"get_value",
|
||||||
|
[aux(h, 0), integer(arg)],
|
||||||
|
[rt_stub]
|
||||||
|
)
|
||||||
}
|
}
|
||||||
&FactInstruction::GetVariable(r, arg) => {
|
&FactInstruction::GetVariable(r, arg) => {
|
||||||
let mut stub = functor!(
|
let rt_stub = reg_type_into_functor(r);
|
||||||
"get_variable",
|
|
||||||
2,
|
|
||||||
[heap_str!(h + 3), heap_integer!(Integer::from(arg))]
|
|
||||||
);
|
|
||||||
stub.append(&mut reg_type_into_functor(r));
|
|
||||||
|
|
||||||
stub
|
functor!(
|
||||||
|
"get_variable",
|
||||||
|
[aux(h, 0), integer(arg)],
|
||||||
|
[rt_stub]
|
||||||
|
)
|
||||||
}
|
}
|
||||||
&FactInstruction::UnifyConstant(ref constant) => {
|
&FactInstruction::UnifyConstant(ref c) => {
|
||||||
functor!("unify_constant", 1, [heap_con!(constant.clone())])
|
functor!("unify_constant", [constant(h, c)], [])
|
||||||
}
|
}
|
||||||
&FactInstruction::UnifyLocalValue(r) => {
|
&FactInstruction::UnifyLocalValue(r) => {
|
||||||
let mut stub = functor!("unify_local_value", 1, [heap_str!(h + 2)]);
|
let rt_stub = reg_type_into_functor(r);
|
||||||
stub.append(&mut reg_type_into_functor(r));
|
|
||||||
|
|
||||||
stub
|
functor!(
|
||||||
|
"unify_local_value",
|
||||||
|
[aux(h, 0)],
|
||||||
|
[rt_stub]
|
||||||
|
)
|
||||||
}
|
}
|
||||||
&FactInstruction::UnifyVariable(r) => {
|
&FactInstruction::UnifyVariable(r) => {
|
||||||
let mut stub = functor!("unify_variable", 1, [heap_str!(h + 2)]);
|
let rt_stub = reg_type_into_functor(r);
|
||||||
stub.append(&mut reg_type_into_functor(r));
|
|
||||||
|
|
||||||
stub
|
functor!(
|
||||||
|
"unify_variable",
|
||||||
|
[aux(h, 0)],
|
||||||
|
[rt_stub]
|
||||||
|
)
|
||||||
}
|
}
|
||||||
&FactInstruction::UnifyValue(r) => {
|
&FactInstruction::UnifyValue(r) => {
|
||||||
let mut stub = functor!("unify_value", 1, [heap_str!(h + 2)]);
|
let rt_stub = reg_type_into_functor(r);
|
||||||
stub.append(&mut reg_type_into_functor(r));
|
|
||||||
|
|
||||||
stub
|
functor!(
|
||||||
|
"unify_value",
|
||||||
|
[aux(h, 0)],
|
||||||
|
[rt_stub]
|
||||||
|
)
|
||||||
}
|
}
|
||||||
&FactInstruction::UnifyVoid(vars) => {
|
&FactInstruction::UnifyVoid(vars) => {
|
||||||
functor!("unify_void", 1, [heap_integer!(Integer::from(vars))])
|
functor!("unify_void", [integer(vars)])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum QueryInstruction {
|
pub enum QueryInstruction {
|
||||||
GetVariable(RegType, usize),
|
GetVariable(RegType, usize),
|
||||||
PutConstant(Level, Constant, RegType),
|
PutConstant(Level, Constant, RegType),
|
||||||
PutList(Level, RegType),
|
PutList(Level, RegType),
|
||||||
|
PutPartialString(Level, String, RegType, bool),
|
||||||
PutStructure(ClauseType, usize, RegType),
|
PutStructure(ClauseType, usize, RegType),
|
||||||
PutUnsafeValue(usize, usize),
|
PutUnsafeValue(usize, usize),
|
||||||
PutValue(RegType, usize),
|
PutValue(RegType, usize),
|
||||||
@@ -567,103 +599,106 @@ impl QueryInstruction {
|
|||||||
match self {
|
match self {
|
||||||
&QueryInstruction::PutUnsafeValue(norm, arg) => functor!(
|
&QueryInstruction::PutUnsafeValue(norm, arg) => functor!(
|
||||||
"put_unsafe_value",
|
"put_unsafe_value",
|
||||||
2,
|
[integer(norm), integer(arg)]
|
||||||
[
|
|
||||||
heap_integer!(Integer::from(norm)),
|
|
||||||
heap_integer!(Integer::from(arg))
|
|
||||||
]
|
|
||||||
),
|
),
|
||||||
&QueryInstruction::PutConstant(lvl, ref constant, r) => {
|
&QueryInstruction::PutConstant(lvl, ref c, r) => {
|
||||||
let mut stub = functor!(
|
let lvl_stub = lvl.into_functor();
|
||||||
|
let rt_stub = reg_type_into_functor(r);
|
||||||
|
|
||||||
|
functor!(
|
||||||
"put_constant",
|
"put_constant",
|
||||||
3,
|
[aux(h, 0), constant(h, c), aux(h, 1)],
|
||||||
[
|
[lvl_stub, rt_stub]
|
||||||
heap_str!(h + 4),
|
)
|
||||||
heap_con!(constant.clone()),
|
|
||||||
heap_str!(h + 6)
|
|
||||||
]
|
|
||||||
);
|
|
||||||
|
|
||||||
stub.append(&mut lvl.into_functor());
|
|
||||||
stub.append(&mut reg_type_into_functor(r));
|
|
||||||
|
|
||||||
stub
|
|
||||||
}
|
}
|
||||||
&QueryInstruction::PutList(lvl, r) => {
|
&QueryInstruction::PutList(lvl, r) => {
|
||||||
let mut stub = functor!("put_list", 2, [heap_str!(h + 3), heap_str!(h + 5)]);
|
let lvl_stub = lvl.into_functor();
|
||||||
|
let rt_stub = reg_type_into_functor(r);
|
||||||
|
|
||||||
stub.append(&mut lvl.into_functor());
|
functor!(
|
||||||
stub.append(&mut reg_type_into_functor(r));
|
"put_list",
|
||||||
|
[aux(h, 0), aux(h, 1)],
|
||||||
|
[lvl_stub, rt_stub]
|
||||||
|
)
|
||||||
|
}
|
||||||
|
&QueryInstruction::PutPartialString(lvl, ref s, r, has_tail) => {
|
||||||
|
let lvl_stub = lvl.into_functor();
|
||||||
|
let rt_stub = reg_type_into_functor(r);
|
||||||
|
|
||||||
stub
|
functor!(
|
||||||
|
"put_partial_string",
|
||||||
|
[aux(h, 0), string(h, s), aux(h, 1), boolean(has_tail)],
|
||||||
|
[lvl_stub, rt_stub]
|
||||||
|
)
|
||||||
}
|
}
|
||||||
&QueryInstruction::PutStructure(ref ct, arity, r) => {
|
&QueryInstruction::PutStructure(ref ct, arity, r) => {
|
||||||
let mut stub = functor!(
|
let rt_stub = reg_type_into_functor(r);
|
||||||
"put_structure",
|
|
||||||
3,
|
|
||||||
[
|
|
||||||
heap_con!(Constant::Atom(ct.name(), None)),
|
|
||||||
heap_integer!(Integer::from(arity)),
|
|
||||||
heap_str!(h + 4)
|
|
||||||
]
|
|
||||||
);
|
|
||||||
|
|
||||||
stub.append(&mut reg_type_into_functor(r));
|
functor!(
|
||||||
stub
|
"put_structure",
|
||||||
|
[clause_name(ct.name()), integer(arity), aux(h, 0)],
|
||||||
|
[rt_stub]
|
||||||
|
)
|
||||||
}
|
}
|
||||||
&QueryInstruction::PutValue(r, arg) => {
|
&QueryInstruction::PutValue(r, arg) => {
|
||||||
let mut stub = functor!(
|
let rt_stub = reg_type_into_functor(r);
|
||||||
"put_value",
|
|
||||||
2,
|
|
||||||
[heap_str!(h + 3), heap_integer!(Integer::from(arg))]
|
|
||||||
);
|
|
||||||
|
|
||||||
stub.append(&mut reg_type_into_functor(r));
|
functor!(
|
||||||
stub
|
"put_value",
|
||||||
|
[aux(h, 0), integer(arg)],
|
||||||
|
[rt_stub]
|
||||||
|
)
|
||||||
}
|
}
|
||||||
&QueryInstruction::GetVariable(r, arg) => {
|
&QueryInstruction::GetVariable(r, arg) => {
|
||||||
let mut stub = functor!(
|
let rt_stub = reg_type_into_functor(r);
|
||||||
"get_variable",
|
|
||||||
2,
|
|
||||||
[heap_str!(h + 3), heap_integer!(Integer::from(arg))]
|
|
||||||
);
|
|
||||||
|
|
||||||
stub.append(&mut reg_type_into_functor(r));
|
functor!(
|
||||||
stub
|
"get_variable",
|
||||||
|
[aux(h, 0), integer(arg)],
|
||||||
|
[rt_stub]
|
||||||
|
)
|
||||||
}
|
}
|
||||||
&QueryInstruction::PutVariable(r, arg) => {
|
&QueryInstruction::PutVariable(r, arg) => {
|
||||||
let mut stub = functor!(
|
let rt_stub = reg_type_into_functor(r);
|
||||||
"put_variable",
|
|
||||||
2,
|
|
||||||
[heap_str!(h + 3), heap_integer!(Integer::from(arg))]
|
|
||||||
);
|
|
||||||
|
|
||||||
stub.append(&mut reg_type_into_functor(r));
|
functor!(
|
||||||
stub
|
"put_variable",
|
||||||
|
[aux(h, 0), integer(arg)],
|
||||||
|
[rt_stub]
|
||||||
|
)
|
||||||
}
|
}
|
||||||
&QueryInstruction::SetConstant(ref constant) => {
|
&QueryInstruction::SetConstant(ref c) => {
|
||||||
functor!("set_constant", 1, [heap_con!(constant.clone())])
|
functor!("set_constant", [constant(h, c)], [])
|
||||||
}
|
}
|
||||||
&QueryInstruction::SetLocalValue(r) => {
|
&QueryInstruction::SetLocalValue(r) => {
|
||||||
let mut stub = functor!("set_local_value", 1, [heap_str!(h + 2)]);
|
let rt_stub = reg_type_into_functor(r);
|
||||||
|
|
||||||
stub.append(&mut reg_type_into_functor(r));
|
functor!(
|
||||||
stub
|
"set_local_value",
|
||||||
|
[aux(h, 0)],
|
||||||
|
[rt_stub]
|
||||||
|
)
|
||||||
}
|
}
|
||||||
&QueryInstruction::SetVariable(r) => {
|
&QueryInstruction::SetVariable(r) => {
|
||||||
let mut stub = functor!("set_variable", 1, [heap_str!(h + 2)]);
|
let rt_stub = reg_type_into_functor(r);
|
||||||
|
|
||||||
stub.append(&mut reg_type_into_functor(r));
|
functor!(
|
||||||
stub
|
"set_variable",
|
||||||
|
[aux(h, 0)],
|
||||||
|
[rt_stub]
|
||||||
|
)
|
||||||
}
|
}
|
||||||
&QueryInstruction::SetValue(r) => {
|
&QueryInstruction::SetValue(r) => {
|
||||||
let mut stub = functor!("set_value", 1, [heap_str!(h + 2)]);
|
let rt_stub = reg_type_into_functor(r);
|
||||||
|
|
||||||
stub.append(&mut reg_type_into_functor(r));
|
functor!(
|
||||||
stub
|
"set_value",
|
||||||
|
[aux(h, 0)],
|
||||||
|
[rt_stub]
|
||||||
|
)
|
||||||
}
|
}
|
||||||
&QueryInstruction::SetVoid(vars) => {
|
&QueryInstruction::SetVoid(vars) => {
|
||||||
functor!("set_void", 1, [heap_integer!(Integer::from(vars))])
|
functor!("set_void", [integer(vars)])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,21 +1,23 @@
|
|||||||
use prolog_parser::ast::*;
|
use crate::prolog_parser::ast::*;
|
||||||
|
|
||||||
use crate::prolog::clause_types::*;
|
use crate::clause_types::*;
|
||||||
use crate::prolog::forms::*;
|
use crate::forms::*;
|
||||||
use crate::prolog::machine::machine_indices::*;
|
use crate::machine::machine_indices::*;
|
||||||
|
|
||||||
use std::cell::Cell;
|
use std::cell::Cell;
|
||||||
use std::collections::VecDeque;
|
use std::collections::VecDeque;
|
||||||
|
use std::fmt;
|
||||||
use std::iter::*;
|
use std::iter::*;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use std::vec::Vec;
|
use std::vec::Vec;
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum TermRef<'a> {
|
pub enum TermRef<'a> {
|
||||||
AnonVar(Level),
|
AnonVar(Level),
|
||||||
Cons(Level, &'a Cell<RegType>, &'a Term, &'a Term),
|
Cons(Level, &'a Cell<RegType>, &'a Term, &'a Term),
|
||||||
Constant(Level, &'a Cell<RegType>, &'a Constant),
|
Constant(Level, &'a Cell<RegType>, &'a Constant),
|
||||||
Clause(Level, &'a Cell<RegType>, ClauseType, &'a Vec<Box<Term>>),
|
Clause(Level, &'a Cell<RegType>, ClauseType, &'a Vec<Box<Term>>),
|
||||||
|
PartialString(Level, &'a Cell<RegType>, String, Option<&'a Term>),
|
||||||
Var(Level, &'a Cell<VarReg>, Rc<Var>),
|
Var(Level, &'a Cell<VarReg>, Rc<Var>),
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -27,10 +29,12 @@ impl<'a> TermRef<'a> {
|
|||||||
| TermRef::Constant(lvl, ..)
|
| TermRef::Constant(lvl, ..)
|
||||||
| TermRef::Var(lvl, ..)
|
| TermRef::Var(lvl, ..)
|
||||||
| TermRef::Clause(lvl, ..) => lvl,
|
| TermRef::Clause(lvl, ..) => lvl,
|
||||||
|
| TermRef::PartialString(lvl, ..) => lvl,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
pub enum TermIterState<'a> {
|
pub enum TermIterState<'a> {
|
||||||
AnonVar(Level),
|
AnonVar(Level),
|
||||||
Constant(Level, &'a Cell<RegType>, &'a Constant),
|
Constant(Level, &'a Cell<RegType>, &'a Constant),
|
||||||
@@ -43,13 +47,67 @@ pub enum TermIterState<'a> {
|
|||||||
),
|
),
|
||||||
InitialCons(Level, &'a Cell<RegType>, &'a Term, &'a Term),
|
InitialCons(Level, &'a Cell<RegType>, &'a Term, &'a Term),
|
||||||
FinalCons(Level, &'a Cell<RegType>, &'a Term, &'a Term),
|
FinalCons(Level, &'a Cell<RegType>, &'a Term, &'a Term),
|
||||||
|
PartialString(Level, &'a Cell<RegType>, String, Option<&'a Term>),
|
||||||
Var(Level, &'a Cell<VarReg>, Rc<Var>),
|
Var(Level, &'a Cell<VarReg>, Rc<Var>),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn is_partial_string<'a>(
|
||||||
|
head: &'a Term,
|
||||||
|
mut tail: &'a Term,
|
||||||
|
) -> Option<(String, Option<&'a Term>)>
|
||||||
|
{
|
||||||
|
let mut string =
|
||||||
|
match head {
|
||||||
|
&Term::Constant(_, Constant::Atom(ref atom, _)) if atom.is_char() => {
|
||||||
|
atom.as_str().chars().next().unwrap().to_string()
|
||||||
|
}
|
||||||
|
&Term::Constant(_, Constant::Char(c)) => {
|
||||||
|
c.to_string()
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
while let Term::Cons(_, ref head, ref succ) = tail {
|
||||||
|
match head.as_ref() {
|
||||||
|
&Term::Constant(_, Constant::Atom(ref atom, _)) if atom.is_char() => {
|
||||||
|
string.push(atom.as_str().chars().next().unwrap());
|
||||||
|
}
|
||||||
|
&Term::Constant(_, Constant::Char(c)) => {
|
||||||
|
string.push(c);
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
tail = succ.as_ref();
|
||||||
|
}
|
||||||
|
|
||||||
|
match tail {
|
||||||
|
Term::AnonVar | Term::Var(..) => {
|
||||||
|
return Some((string, Some(tail)));
|
||||||
|
}
|
||||||
|
Term::Constant(_, Constant::EmptyList) => {
|
||||||
|
return Some((string, None));
|
||||||
|
}
|
||||||
|
Term::Constant(_, Constant::String(tail)) => {
|
||||||
|
string += &tail;
|
||||||
|
return Some((string, None));
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<'a> TermIterState<'a> {
|
impl<'a> TermIterState<'a> {
|
||||||
pub fn subterm_to_state(lvl: Level, term: &'a Term) -> TermIterState<'a> {
|
pub fn subterm_to_state(lvl: Level, term: &'a Term) -> TermIterState<'a> {
|
||||||
match term {
|
match term {
|
||||||
&Term::AnonVar => TermIterState::AnonVar(lvl),
|
&Term::AnonVar => {
|
||||||
|
TermIterState::AnonVar(lvl)
|
||||||
|
}
|
||||||
&Term::Clause(ref cell, ref name, ref subterms, ref spec) => {
|
&Term::Clause(ref cell, ref name, ref subterms, ref spec) => {
|
||||||
let ct = if let Some(spec) = spec {
|
let ct = if let Some(spec) = spec {
|
||||||
ClauseType::Op(name.clone(), spec.clone(), CodeIndex::default())
|
ClauseType::Op(name.clone(), spec.clone(), CodeIndex::default())
|
||||||
@@ -62,12 +120,17 @@ impl<'a> TermIterState<'a> {
|
|||||||
&Term::Cons(ref cell, ref head, ref tail) => {
|
&Term::Cons(ref cell, ref head, ref tail) => {
|
||||||
TermIterState::InitialCons(lvl, cell, head.as_ref(), tail.as_ref())
|
TermIterState::InitialCons(lvl, cell, head.as_ref(), tail.as_ref())
|
||||||
}
|
}
|
||||||
&Term::Constant(ref cell, ref constant) => TermIterState::Constant(lvl, cell, constant),
|
&Term::Constant(ref cell, ref constant) => {
|
||||||
&Term::Var(ref cell, ref var) => TermIterState::Var(lvl, cell, var.clone()),
|
TermIterState::Constant(lvl, cell, constant)
|
||||||
|
}
|
||||||
|
&Term::Var(ref cell, ref var) => {
|
||||||
|
TermIterState::Var(lvl, cell, var.clone())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
pub struct QueryIterator<'a> {
|
pub struct QueryIterator<'a> {
|
||||||
state_stack: Vec<TermIterState<'a>>,
|
state_stack: Vec<TermIterState<'a>>,
|
||||||
}
|
}
|
||||||
@@ -169,7 +232,9 @@ impl<'a> Iterator for QueryIterator<'a> {
|
|||||||
fn next(&mut self) -> Option<Self::Item> {
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
while let Some(iter_state) = self.state_stack.pop() {
|
while let Some(iter_state) = self.state_stack.pop() {
|
||||||
match iter_state {
|
match iter_state {
|
||||||
TermIterState::AnonVar(lvl) => return Some(TermRef::AnonVar(lvl)),
|
TermIterState::AnonVar(lvl) => {
|
||||||
|
return Some(TermRef::AnonVar(lvl));
|
||||||
|
}
|
||||||
TermIterState::Clause(lvl, child_num, cell, ct, child_terms) => {
|
TermIterState::Clause(lvl, child_num, cell, ct, child_terms) => {
|
||||||
if child_num == child_terms.len() {
|
if child_num == child_terms.len() {
|
||||||
match ct {
|
match ct {
|
||||||
@@ -182,7 +247,9 @@ impl<'a> Iterator for QueryIterator<'a> {
|
|||||||
lvl => Some(TermRef::Clause(lvl, cell, ct, child_terms)),
|
lvl => Some(TermRef::Clause(lvl, cell, ct, child_terms)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => return None,
|
_ => {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
self.state_stack.push(TermIterState::Clause(
|
self.state_stack.push(TermIterState::Clause(
|
||||||
@@ -192,23 +259,41 @@ impl<'a> Iterator for QueryIterator<'a> {
|
|||||||
ct,
|
ct,
|
||||||
child_terms,
|
child_terms,
|
||||||
));
|
));
|
||||||
|
|
||||||
self.push_subterm(lvl.child_level(), child_terms[child_num].as_ref());
|
self.push_subterm(lvl.child_level(), child_terms[child_num].as_ref());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
TermIterState::InitialCons(lvl, cell, head, tail) => {
|
TermIterState::InitialCons(lvl, cell, head, tail) => {
|
||||||
self.state_stack
|
if let Some((string, tail)) = is_partial_string(head, tail) {
|
||||||
.push(TermIterState::FinalCons(lvl, cell, head, tail));
|
self.state_stack.push(TermIterState::PartialString(
|
||||||
|
lvl,
|
||||||
|
cell,
|
||||||
|
string,
|
||||||
|
tail,
|
||||||
|
));
|
||||||
|
|
||||||
self.push_subterm(lvl.child_level(), tail);
|
if let Some(tail) = tail {
|
||||||
self.push_subterm(lvl.child_level(), head);
|
self.push_subterm(lvl.child_level(), tail);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
self.state_stack.push(TermIterState::FinalCons(lvl, cell, head, tail));
|
||||||
|
|
||||||
|
self.push_subterm(lvl.child_level(), tail);
|
||||||
|
self.push_subterm(lvl.child_level(), head);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
TermIterState::PartialString(lvl, cell, string, tail) => {
|
||||||
|
return Some(TermRef::PartialString(lvl, cell, string, tail));
|
||||||
}
|
}
|
||||||
TermIterState::FinalCons(lvl, cell, head, tail) => {
|
TermIterState::FinalCons(lvl, cell, head, tail) => {
|
||||||
return Some(TermRef::Cons(lvl, cell, head, tail))
|
return Some(TermRef::Cons(lvl, cell, head, tail));
|
||||||
}
|
}
|
||||||
TermIterState::Constant(lvl, cell, constant) => {
|
TermIterState::Constant(lvl, cell, constant) => {
|
||||||
return Some(TermRef::Constant(lvl, cell, constant))
|
return Some(TermRef::Constant(lvl, cell, constant));
|
||||||
|
}
|
||||||
|
TermIterState::Var(lvl, cell, var) => {
|
||||||
|
return Some(TermRef::Var(lvl, cell, var));
|
||||||
}
|
}
|
||||||
TermIterState::Var(lvl, cell, var) => return Some(TermRef::Var(lvl, cell, var)),
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -216,6 +301,7 @@ impl<'a> Iterator for QueryIterator<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
pub struct FactIterator<'a> {
|
pub struct FactIterator<'a> {
|
||||||
state_queue: VecDeque<TermIterState<'a>>,
|
state_queue: VecDeque<TermIterState<'a>>,
|
||||||
iterable_root: bool,
|
iterable_root: bool,
|
||||||
@@ -223,8 +309,7 @@ pub struct FactIterator<'a> {
|
|||||||
|
|
||||||
impl<'a> FactIterator<'a> {
|
impl<'a> FactIterator<'a> {
|
||||||
fn push_subterm(&mut self, lvl: Level, term: &'a Term) {
|
fn push_subterm(&mut self, lvl: Level, term: &'a Term) {
|
||||||
self.state_queue
|
self.state_queue.push_back(TermIterState::subterm_to_state(lvl, term));
|
||||||
.push_back(TermIterState::subterm_to_state(lvl, term));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_rule_head_clause(terms: &'a Vec<Box<Term>>) -> Self {
|
pub fn from_rule_head_clause(terms: &'a Vec<Box<Term>>) -> Self {
|
||||||
@@ -241,7 +326,9 @@ impl<'a> FactIterator<'a> {
|
|||||||
|
|
||||||
fn new(term: &'a Term, iterable_root: bool) -> Self {
|
fn new(term: &'a Term, iterable_root: bool) -> Self {
|
||||||
let states = match term {
|
let states = match term {
|
||||||
&Term::AnonVar => vec![TermIterState::AnonVar(Level::Root)],
|
&Term::AnonVar => {
|
||||||
|
vec![TermIterState::AnonVar(Level::Root)]
|
||||||
|
}
|
||||||
&Term::Clause(ref cell, ref name, ref terms, ref fixity) => {
|
&Term::Clause(ref cell, ref name, ref terms, ref fixity) => {
|
||||||
let ct = ClauseType::from(name.clone(), terms.len(), fixity.clone());
|
let ct = ClauseType::from(name.clone(), terms.len(), fixity.clone());
|
||||||
vec![TermIterState::Clause(Level::Root, 0, cell, ct, terms)]
|
vec![TermIterState::Clause(Level::Root, 0, cell, ct, terms)]
|
||||||
@@ -273,7 +360,9 @@ impl<'a> Iterator for FactIterator<'a> {
|
|||||||
fn next(&mut self) -> Option<Self::Item> {
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
while let Some(state) = self.state_queue.pop_front() {
|
while let Some(state) = self.state_queue.pop_front() {
|
||||||
match state {
|
match state {
|
||||||
TermIterState::AnonVar(lvl) => return Some(TermRef::AnonVar(lvl)),
|
TermIterState::AnonVar(lvl) => {
|
||||||
|
return Some(TermRef::AnonVar(lvl));
|
||||||
|
}
|
||||||
TermIterState::Clause(lvl, _, cell, ct, child_terms) => {
|
TermIterState::Clause(lvl, _, cell, ct, child_terms) => {
|
||||||
for child_term in child_terms {
|
for child_term in child_terms {
|
||||||
self.push_subterm(lvl.child_level(), child_term);
|
self.push_subterm(lvl.child_level(), child_term);
|
||||||
@@ -285,16 +374,27 @@ impl<'a> Iterator for FactIterator<'a> {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
TermIterState::InitialCons(lvl, cell, head, tail) => {
|
TermIterState::InitialCons(lvl, cell, head, tail) => {
|
||||||
self.push_subterm(Level::Deep, head);
|
if let Some((string, tail)) = is_partial_string(head, tail) {
|
||||||
self.push_subterm(Level::Deep, tail);
|
if let Some(tail) = tail {
|
||||||
|
self.push_subterm(Level::Deep, tail);
|
||||||
|
}
|
||||||
|
|
||||||
return Some(TermRef::Cons(lvl, cell, head, tail));
|
return Some(TermRef::PartialString(lvl, cell, string, tail));
|
||||||
|
} else {
|
||||||
|
self.push_subterm(Level::Deep, head);
|
||||||
|
self.push_subterm(Level::Deep, tail);
|
||||||
|
|
||||||
|
return Some(TermRef::Cons(lvl, cell, head, tail));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
TermIterState::Constant(lvl, cell, constant) => {
|
TermIterState::Constant(lvl, cell, constant) => {
|
||||||
return Some(TermRef::Constant(lvl, cell, constant))
|
return Some(TermRef::Constant(lvl, cell, constant))
|
||||||
}
|
}
|
||||||
TermIterState::Var(lvl, cell, var) => return Some(TermRef::Var(lvl, cell, var)),
|
TermIterState::Var(lvl, cell, var) => {
|
||||||
_ => {}
|
return Some(TermRef::Var(lvl, cell, var));
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -310,6 +410,7 @@ pub fn breadth_first_iter(term: &Term, iterable_root: bool) -> FactIterator {
|
|||||||
FactIterator::new(term, iterable_root)
|
FactIterator::new(term, iterable_root)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
pub enum ChunkedTerm<'a> {
|
pub enum ChunkedTerm<'a> {
|
||||||
HeadClause(ClauseName, &'a Vec<Box<Term>>),
|
HeadClause(ClauseName, &'a Vec<Box<Term>>),
|
||||||
BodyTerm(&'a QueryTerm),
|
BodyTerm(&'a QueryTerm),
|
||||||
@@ -347,6 +448,18 @@ pub struct ChunkedIterator<'a> {
|
|||||||
cut_var_in_head: bool,
|
cut_var_in_head: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'a> fmt::Debug for ChunkedIterator<'a> {
|
||||||
|
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
fmt.debug_struct("ChunkedIterator")
|
||||||
|
.field("chunk_num", &self.chunk_num)
|
||||||
|
// Hacky solution.
|
||||||
|
.field("iter", &"Box<dyn Iterator<Item = ChunkedTerm<'a>> + 'a>")
|
||||||
|
.field("deep_cut_encountered", &self.deep_cut_encountered)
|
||||||
|
.field("cut_var_in_head", &self.cut_var_in_head)
|
||||||
|
.finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
type ChunkedIteratorItem<'a> = (usize, usize, Vec<ChunkedTerm<'a>>);
|
type ChunkedIteratorItem<'a> = (usize, usize, Vec<ChunkedTerm<'a>>);
|
||||||
type RuleBodyIteratorItem<'a> = (usize, usize, Vec<&'a QueryTerm>);
|
type RuleBodyIteratorItem<'a> = (usize, usize, Vec<&'a QueryTerm>);
|
||||||
|
|
||||||
123
src/lib/arithmetic.pl
Normal file
123
src/lib/arithmetic.pl
Normal file
@@ -0,0 +1,123 @@
|
|||||||
|
:- module(arithmetic, [expmod/4, lsb/2, msb/2, number_to_rational/2,
|
||||||
|
number_to_rational/3,
|
||||||
|
rational_numerator_denominator/3]).
|
||||||
|
|
||||||
|
:- use_module(library(charsio), [write_term_to_chars/3]).
|
||||||
|
:- use_module(library(error)).
|
||||||
|
:- use_module(library(lists), [append/3, member/2]).
|
||||||
|
|
||||||
|
expmod(Base, Expo, Mod, R) :-
|
||||||
|
( member(N, [Base, Expo, Mod]), var(N) -> instantiation_error(expmod/4)
|
||||||
|
; member(N, [Base, Expo, Mod]), \+ integer(N) ->
|
||||||
|
type_error(integer, N, expmod/4)
|
||||||
|
; Expo < 0 -> domain_error(not_less_than_zero, Expo, expmod/4)
|
||||||
|
; expmod_(Base, Expo, Mod, 1, R)
|
||||||
|
).
|
||||||
|
|
||||||
|
expmod_(_, _, 1, _, 0) :- !.
|
||||||
|
expmod_(_, 0, _, R, R) :- !.
|
||||||
|
expmod_(Base0, Expo0, Mod, C0, R) :-
|
||||||
|
Expo0 /\ 1 =:= 1,
|
||||||
|
C is (C0 * Base0) mod Mod,
|
||||||
|
!,
|
||||||
|
Expo is Expo0 >> 1,
|
||||||
|
Base is (Base0 * Base0) mod Mod,
|
||||||
|
expmod_(Base, Expo, Mod, C, R).
|
||||||
|
expmod_(Base0, Expo0, Mod, C, R) :-
|
||||||
|
Expo is Expo0 >> 1,
|
||||||
|
Base is (Base0 * Base0) mod Mod,
|
||||||
|
expmod_(Base, Expo, Mod, C, R).
|
||||||
|
|
||||||
|
lsb(X, N) :-
|
||||||
|
builtins:must_be_number(X, lsb/2),
|
||||||
|
( \+ integer(X) -> type_error(integer, X, lsb/2)
|
||||||
|
; X < 1 -> domain_error(not_less_than_one, X, lsb/2)
|
||||||
|
; builtins:can_be_number(N, lsb/2),
|
||||||
|
X1 is X /\ (-X),
|
||||||
|
msb_(X1, -1, N)
|
||||||
|
).
|
||||||
|
|
||||||
|
msb(X, N) :-
|
||||||
|
builtins:must_be_number(X, msb/2),
|
||||||
|
( \+ integer(X) -> type_error(integer, X, msb/2)
|
||||||
|
; X < 1 -> domain_error(not_less_than_one, X, msb/2)
|
||||||
|
; builtins:can_be_number(N, msb/2),
|
||||||
|
X1 is X >> 1,
|
||||||
|
msb_(X1, 0, N)
|
||||||
|
).
|
||||||
|
|
||||||
|
msb_(0, N, N) :- !.
|
||||||
|
msb_(X, M, N) :-
|
||||||
|
X1 is X >> 1,
|
||||||
|
M1 is M + 1,
|
||||||
|
msb_(X1, M1, N).
|
||||||
|
|
||||||
|
number_to_rational(Real, Fraction) :-
|
||||||
|
( var(Real) -> instantiation_error(number_to_rational/2)
|
||||||
|
; integer(Real) -> Fraction is Real rdiv 1
|
||||||
|
; (rational(Real) ; float(Real)) ->
|
||||||
|
number_to_rational(1.0e-6, Real, Fraction)
|
||||||
|
; type_error(number, Real, number_to_rational/2)
|
||||||
|
).
|
||||||
|
|
||||||
|
% If 0 <= Eps0 <= 1e-16 then the search is for "infinite" precision.
|
||||||
|
number_to_rational(Eps0, Real0, Fraction) :-
|
||||||
|
( var(Eps0) -> instantiation_error(number_to_rational/3)
|
||||||
|
; \+ number(Eps0) -> type_error(number, Eps0, number_to_rational/3)
|
||||||
|
; Eps0 < 0 -> domain_error(not_less_than_zero, Eps0, number_to_rational/3)
|
||||||
|
; Eps_ is Eps0 rdiv 1,
|
||||||
|
rational_numerator_denominator(Eps_, EpsN, EpsD),
|
||||||
|
Eps = EpsN/EpsD
|
||||||
|
),
|
||||||
|
( var(Real0) -> instantiation_error(number_to_rational/3)
|
||||||
|
; \+ number(Real0) -> type_error(number, Eps0, number_to_rational/3)
|
||||||
|
; Real_ is Real0 rdiv 1,
|
||||||
|
rational_numerator_denominator(Real_, RealN, RealD),
|
||||||
|
Real = RealN/RealD
|
||||||
|
),
|
||||||
|
E0/E1 = Eps,
|
||||||
|
P0/Q0 = Real,
|
||||||
|
( P0 < 0 -> I1 is -1 + P0 // Q0
|
||||||
|
; I1 is P0 // Q0
|
||||||
|
),
|
||||||
|
P1 is P0 mod Q0,
|
||||||
|
Q1 = Q0,
|
||||||
|
( P1 =:= 0 -> Fraction is I1 + 0 rdiv 1
|
||||||
|
; Qn1n is max(P1 * E1 - Q1 * E0, 0),
|
||||||
|
Qn1d is Q1 * E1,
|
||||||
|
Qn1 = Qn1n/Qn1d,
|
||||||
|
Qp1n is P1 * E1 + Q1 * E0,
|
||||||
|
Qp1d = Qn1d,
|
||||||
|
Qp1 = Qp1n/Qp1d,
|
||||||
|
stern_brocot_(Qn1, Qp1, 0/1, 1/0, P2/Q2),
|
||||||
|
Fraction is I1 + P2 rdiv Q2
|
||||||
|
),
|
||||||
|
!.
|
||||||
|
|
||||||
|
number(X) :-
|
||||||
|
( integer(X)
|
||||||
|
; float(X)
|
||||||
|
; rational(X)
|
||||||
|
).
|
||||||
|
|
||||||
|
stern_brocot_(Qnn/Qnd, Qpn/Qpd, A/B, C/D, Fraction) :-
|
||||||
|
Fn1 is A + C,
|
||||||
|
Fd1 is B + D,
|
||||||
|
simplify_fraction(Fn1/Fd1, Fn/Fd),
|
||||||
|
S1 is sign(Fn * Qnd - Fd * Qnn),
|
||||||
|
S2 is sign(Fn * Qpd - Fd * Qpn),
|
||||||
|
( S1 < 0 -> stern_brocot_(Qnn/Qnd, Qpn/Qpd, Fn/Fd, C/D, Fraction)
|
||||||
|
; S2 > 0 -> stern_brocot_(Qnn/Qnd, Qpn/Qpd, A/B, Fn/Fd, Fraction)
|
||||||
|
; Fraction = Fn/Fd
|
||||||
|
).
|
||||||
|
|
||||||
|
simplify_fraction(A0/B0, A/B) :-
|
||||||
|
G is gcd(A0, B0),
|
||||||
|
A is A0 // G,
|
||||||
|
B is B0 // G.
|
||||||
|
|
||||||
|
rational_numerator_denominator(R, N, D) :-
|
||||||
|
write_term_to_chars(R, [], Cs),
|
||||||
|
append(Ns, [' ', r, d, i, v, ' '|Ds], Cs),
|
||||||
|
number_chars(N, Ns),
|
||||||
|
number_chars(D, Ds).
|
||||||
@@ -1,9 +1,10 @@
|
|||||||
:- module(atts, [op(1199, fx, attribute), call_residue_vars/2,
|
:- module(atts, [op(1199, fx, attribute), call_residue_vars/2,
|
||||||
'$absent_attr'/2, '$copy_attr_list'/2, '$get_attr'/2,
|
term_attributed_variables/2,
|
||||||
'$put_attr'/2, '$absent_from_list'/2,
|
'$absent_attr'/2, '$copy_attr_list'/2, '$get_attr'/2,
|
||||||
'$get_from_list'/3, '$add_to_list'/3, '$del_attr'/3,
|
'$put_attr'/2, '$absent_from_list'/2,
|
||||||
'$del_attr_step'/3, '$del_attr_buried'/4,
|
'$get_from_list'/3, '$add_to_list'/3, '$del_attr'/3,
|
||||||
'$default_attr_list'/4]).
|
'$del_attr_step'/3, '$del_attr_buried'/4,
|
||||||
|
'$default_attr_list'/4]).
|
||||||
|
|
||||||
:- use_module(library(dcgs)).
|
:- use_module(library(dcgs)).
|
||||||
:- use_module(library(terms)).
|
:- use_module(library(terms)).
|
||||||
@@ -56,7 +57,8 @@
|
|||||||
'$del_attr'(Ls0, V, Attr) :-
|
'$del_attr'(Ls0, V, Attr) :-
|
||||||
Ls0 = [Att | Ls1],
|
Ls0 = [Att | Ls1],
|
||||||
nonvar(Att),
|
nonvar(Att),
|
||||||
( Att \= Attr -> '$del_attr_buried'(Ls0, Ls1, V, Attr)
|
( Att \= Attr ->
|
||||||
|
'$del_attr_buried'(Ls0, Ls1, V, Attr)
|
||||||
; '$enqueue_attr_var'(V),
|
; '$enqueue_attr_var'(V),
|
||||||
'$del_attr_head'(V),
|
'$del_attr_head'(V),
|
||||||
'$del_attr'(Ls1, V, Attr)
|
'$del_attr'(Ls1, V, Attr)
|
||||||
@@ -159,3 +161,5 @@ call_residue_vars(Goal, Vars) :-
|
|||||||
call(Goal),
|
call(Goal),
|
||||||
'$get_attr_var_queue_beyond'(B, Vars).
|
'$get_attr_var_queue_beyond'(B, Vars).
|
||||||
|
|
||||||
|
term_attributed_variables(Term, Vars) :-
|
||||||
|
'$term_attributed_variables'(Term, Vars).
|
||||||
@@ -6,14 +6,13 @@
|
|||||||
:- use_module(library(error)).
|
:- use_module(library(error)).
|
||||||
|
|
||||||
between(Lower, Upper, X) :-
|
between(Lower, Upper, X) :-
|
||||||
( Upper == inf ->
|
must_be(integer, Lower),
|
||||||
must_be(integer, Lower),
|
must_be(integer, Upper),
|
||||||
can_be(integer, X),
|
can_be(integer, X),
|
||||||
enumerate_nats(Lower, X)
|
( nonvar(X) ->
|
||||||
; must_be(integer, Lower),
|
Lower =< X,
|
||||||
must_be(integer, Upper),
|
X =< Upper
|
||||||
can_be(integer, X),
|
; between_(Lower, Upper, X)
|
||||||
between_(Lower, Upper, X)
|
|
||||||
).
|
).
|
||||||
|
|
||||||
between_(Lower, Upper, Lower) :-
|
between_(Lower, Upper, Lower) :-
|
||||||
@@ -24,6 +24,8 @@ user:term_expansion((:- op(Pred, Spec, [Op | OtherOps])), OpResults) :-
|
|||||||
:- op(400, yfx, [div, //, rdiv, <<, >>, mod, rem]).
|
:- op(400, yfx, [div, //, rdiv, <<, >>, mod, rem]).
|
||||||
:- op(200, fy, [+, -, \]).
|
:- op(200, fy, [+, -, \]).
|
||||||
|
|
||||||
|
:- op(1200, xfx, -->).
|
||||||
|
|
||||||
% arithmetic comparison operators.
|
% arithmetic comparison operators.
|
||||||
:- op(700, xfx, [>, <, =\=, =:=, >=, =<]).
|
:- op(700, xfx, [>, <, =\=, =:=, >=, =<]).
|
||||||
|
|
||||||
@@ -41,24 +43,35 @@ user:term_expansion((:- op(Pred, Spec, [Op | OtherOps])), OpResults) :-
|
|||||||
:- module(builtins, [(=)/2, (\=)/2, (\+)/1, (',')/2, (->)/2, (;)/2,
|
:- module(builtins, [(=)/2, (\=)/2, (\+)/1, (',')/2, (->)/2, (;)/2,
|
||||||
(=..)/2, (:)/2, (:)/3, (:)/4, (:)/5, (:)/6,
|
(=..)/2, (:)/2, (:)/3, (:)/4, (:)/5, (:)/6,
|
||||||
(:)/7, (:)/8, (:)/9, (:)/10, (:)/11, (:)/12,
|
(:)/7, (:)/8, (:)/9, (:)/10, (:)/11, (:)/12,
|
||||||
abolish/1, asserta/1, assertz/1, atom_chars/2,
|
abolish/1, asserta/1, assertz/1,
|
||||||
atom_codes/2, atom_concat/3, atom_length/2,
|
at_end_of_stream/0, at_end_of_stream/1,
|
||||||
bagof/3, catch/3, char_code/2, clause/2,
|
atom_chars/2, atom_codes/2, atom_concat/3,
|
||||||
current_op/3, current_predicate/1,
|
atom_length/2, bagof/3, catch/3, char_code/2,
|
||||||
current_prolog_flag/2, expand_goal/2,
|
clause/2, close/1, close/2, current_input/1,
|
||||||
expand_term/2, fail/0, false/0, findall/3,
|
current_output/1, current_op/3,
|
||||||
findall/4, get_char/1, halt/0, max_arity/1,
|
current_predicate/1, current_prolog_flag/2,
|
||||||
number_chars/2, number_codes/2, once/1, op/3,
|
expand_goal/2, expand_term/2, fail/0, false/0,
|
||||||
read_term/2, repeat/0, retract/1,
|
findall/3, findall/4, flush_output/0,
|
||||||
set_prolog_flag/2, setof/3, sub_atom/5,
|
flush_output/1, get_byte/1, get_byte/2,
|
||||||
|
get_char/1, get_char/2, get_code/1, get_code/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,
|
||||||
|
put_byte/1, put_byte/2, put_code/1, put_code/2,
|
||||||
|
put_char/1, put_char/2, read_term/2, read_term/3,
|
||||||
|
repeat/0, retract/1, set_prolog_flag/2,
|
||||||
|
set_input/1, set_stream_position/2, set_output/1,
|
||||||
|
setof/3, stream_property/2, sub_atom/5,
|
||||||
subsumes_term/2, term_variables/2, throw/1,
|
subsumes_term/2, term_variables/2, throw/1,
|
||||||
true/0, unify_with_occurs_check/2, write/1,
|
true/0, unify_with_occurs_check/2, write/1,
|
||||||
write_canonical/1, write_term/2, writeq/1]).
|
write_canonical/1, write_term/2, write_term/3,
|
||||||
|
writeq/1]).
|
||||||
|
|
||||||
|
|
||||||
% the maximum arity flag. needs to be replaced with
|
% the maximum arity flag. needs to be replaced with
|
||||||
% current_prolog_flag(max_arity, MAX_ARITY).
|
% current_prolog_flag(max_arity, MAX_ARITY).
|
||||||
max_arity(255).
|
max_arity(1023).
|
||||||
|
|
||||||
% unify.
|
% unify.
|
||||||
X = X.
|
X = X.
|
||||||
@@ -212,18 +225,41 @@ comma_errors(G1, G2, B) :- '$call_with_default_policy'(','(G1, G2, B)).
|
|||||||
|
|
||||||
;(G1, G2) :- '$get_b_value'(B), ;(G1, G2, B).
|
;(G1, G2) :- '$get_b_value'(B), ;(G1, G2, B).
|
||||||
|
|
||||||
|
:- non_counted_backtracking semicolon_compound_selector/3.
|
||||||
|
semicolon_compound_selector(->(G2, G3), G4, B) :-
|
||||||
|
( call(G2) ->
|
||||||
|
call(G3)
|
||||||
|
; '$set_cp'(B),
|
||||||
|
call(G4)
|
||||||
|
).
|
||||||
|
semicolon_compound_selector(','(G2, G3), G4, B) :-
|
||||||
|
( ','(G2, G3, B)
|
||||||
|
; '$set_cp'(B),
|
||||||
|
call(G4)
|
||||||
|
).
|
||||||
|
semicolon_compound_selector(';'(G2, G3), G4, B) :-
|
||||||
|
( ';'(G2, G3, B)
|
||||||
|
; '$set_cp'(B),
|
||||||
|
call(G4)
|
||||||
|
).
|
||||||
|
|
||||||
:- non_counted_backtracking (;)/3.
|
:- non_counted_backtracking (;)/3.
|
||||||
;(G1, G4, B) :- compound(G1),
|
;(G1, G4, B) :-
|
||||||
'$call_with_default_policy'(G1 = ->(G2, G3)),
|
( ( G1 = (_ -> _)
|
||||||
!,
|
; G1 = (_ , _)
|
||||||
( call(G2) -> call(G3)
|
; G1 = (_ ; _)
|
||||||
; '$set_cp'(B),
|
) ->
|
||||||
call(G4)
|
!,
|
||||||
).
|
semicolon_compound_selector(G1, G4, B)
|
||||||
;(G1, G2, B) :- G1 == !, '$set_cp'(B), call(G2).
|
).
|
||||||
;(G1, G2, B) :- G2 == !, call(G1), '$set_cp'(B).
|
;(G1, G2, B) :-
|
||||||
;(G, _, _) :- call(G).
|
G1 == !, !, '$set_cp'(B), call(G2).
|
||||||
;(_, G, _) :- call(G).
|
;(G1, G2, B) :-
|
||||||
|
G2 == !, !, call(G1), '$set_cp'(B).
|
||||||
|
;(G, _, _) :-
|
||||||
|
call(G).
|
||||||
|
;(_, G, _) :-
|
||||||
|
call(G).
|
||||||
|
|
||||||
G1 -> G2 :- '$get_b_value'(B), '$call_with_default_policy'(->(G1, G2, B)).
|
G1 -> G2 :- '$get_b_value'(B), '$call_with_default_policy'(->(G1, G2, B)).
|
||||||
|
|
||||||
@@ -261,8 +297,11 @@ univ_errors(Term, List, N) :-
|
|||||||
Term =.. List :- '$call_with_default_policy'(univ_errors(Term, List, N)),
|
Term =.. List :- '$call_with_default_policy'(univ_errors(Term, List, N)),
|
||||||
'$call_with_default_policy'(univ_worker(Term, List, N)).
|
'$call_with_default_policy'(univ_worker(Term, List, N)).
|
||||||
|
|
||||||
|
|
||||||
:- non_counted_backtracking univ_worker/3.
|
:- non_counted_backtracking univ_worker/3.
|
||||||
univ_worker(Term, List, _) :- atomic(Term), !, '$call_with_default_policy'(List = [Term]).
|
|
||||||
|
univ_worker(Term, List, _) :-
|
||||||
|
atomic(Term), !, '$call_with_default_policy'(List = [Term]).
|
||||||
univ_worker(Term, [Name|Args], N) :-
|
univ_worker(Term, [Name|Args], N) :-
|
||||||
var(Term), !,
|
var(Term), !,
|
||||||
'$call_with_default_policy'(Arity is N-1),
|
'$call_with_default_policy'(Arity is N-1),
|
||||||
@@ -273,7 +312,9 @@ univ_worker(Term, List, _) :-
|
|||||||
'$call_with_default_policy'(get_args(Args, Term, 1, Arity)),
|
'$call_with_default_policy'(get_args(Args, Term, 1, Arity)),
|
||||||
'$call_with_default_policy'(List = [Name|Args]).
|
'$call_with_default_policy'(List = [Name|Args]).
|
||||||
|
|
||||||
|
|
||||||
:- non_counted_backtracking get_args/4.
|
:- non_counted_backtracking get_args/4.
|
||||||
|
|
||||||
get_args(Args, _, _, 0) :-
|
get_args(Args, _, _, 0) :-
|
||||||
!, '$call_with_default_policy'(Args = []).
|
!, '$call_with_default_policy'(Args = []).
|
||||||
get_args([Arg], Func, N, N) :-
|
get_args([Arg], Func, N, N) :-
|
||||||
@@ -283,34 +324,39 @@ get_args([Arg|Args], Func, I0, N) :-
|
|||||||
'$call_with_default_policy'(I1 is I0 + 1),
|
'$call_with_default_policy'(I1 is I0 + 1),
|
||||||
'$call_with_default_policy'(get_args(Args, Func, I1, N)).
|
'$call_with_default_policy'(get_args(Args, Func, I1, N)).
|
||||||
|
|
||||||
% write, write_canonical, writeq, write_term.
|
parse_write_options(Options, OptionValues, Stub) :-
|
||||||
is_write_option(Functor) :-
|
DefaultOptions = [ignore_ops-false, max_depth-0, numbervars-false,
|
||||||
Functor =.. [Name, Arg],
|
quoted-false, variable_names-[]],
|
||||||
( Arg == true -> true
|
parse_options_list(Options, parse_write_options_, DefaultOptions, OptionValues, Stub).
|
||||||
; Arg == false -> true
|
|
||||||
; Name == variable_names -> must_be_var_names_list(Arg)
|
|
||||||
; var(Arg) -> throw(error(instantiation_error, write_term/2))
|
|
||||||
; throw(error(domain_error(write_option, Functor), write_term/2))
|
|
||||||
), % 8.14.2.3 e)
|
|
||||||
( Name == ignore_ops -> true
|
|
||||||
; Name == quoted -> true
|
|
||||||
; Name == numbervars -> true
|
|
||||||
; Name == variable_names -> true
|
|
||||||
; throw(error(domain_error(write_option, Functor), write_term/2))
|
|
||||||
). % 8.14.2.3 e)
|
|
||||||
|
|
||||||
inst_member_or([X|Xs], Y, Z) :-
|
parse_write_options_(ignore_ops(IgnoreOps), ignore_ops-IgnoreOps) :-
|
||||||
( var(X) -> throw(error(instantiation_error, write_term/2))
|
( nonvar(IgnoreOps), lists:member(IgnoreOps, [true, false])
|
||||||
; is_write_option(X) -> ( Y = X, ! ; inst_member_or(Xs, Y, Z) )
|
;
|
||||||
; throw(error(domain_error(write_option, X), write_term/2))
|
throw(error(domain_error(write_option, ignore_ops(IgnoreOps)), _))
|
||||||
|
).
|
||||||
|
parse_write_options_(quoted(Quoted), quoted-Quoted) :-
|
||||||
|
( nonvar(Quoted), lists:member(Quoted, [true, false])
|
||||||
|
;
|
||||||
|
throw(error(domain_error(write_option, quoted(Quoted)), _))
|
||||||
|
).
|
||||||
|
parse_write_options_(numbervars(NumberVars), numbervars-NumberVars) :-
|
||||||
|
( nonvar(NumberVars), lists:member(NumberVars, [true, false])
|
||||||
|
;
|
||||||
|
throw(error(domain_error(write_option, numbervars(NumberVars)), _))
|
||||||
|
).
|
||||||
|
parse_write_options_(variable_names(VNNames), variable_names-VNNames) :-
|
||||||
|
must_be_var_names_list(VNNames).
|
||||||
|
parse_write_options_(max_depth(MaxDepth), max_depth-MaxDepth) :-
|
||||||
|
( integer(MaxDepth), MaxDepth >= 0
|
||||||
|
;
|
||||||
|
throw(error(domain_error(write_option, max_depth(MaxDepth)), _))
|
||||||
).
|
).
|
||||||
inst_member_or([], Y, Y).
|
|
||||||
|
|
||||||
must_be_var_names_list(VarNames) :-
|
must_be_var_names_list(VarNames) :-
|
||||||
'$skip_max_list'(_, -1, VarNames, Tail),
|
'$skip_max_list'(_, -1, VarNames, Tail),
|
||||||
( Tail == [] -> must_be_var_names_list_(VarNames, VarNames)
|
( Tail == [] -> must_be_var_names_list_(VarNames, VarNames)
|
||||||
; var(Tail) -> throw(error(instantiation_error, write_term/2))
|
; var(Tail) -> throw(error(instantiation_error, write_term/2))
|
||||||
; throw(error(domain_error(write_options, variable_names(VarNames)), write_term/2))
|
; throw(error(domain_error(write_option, variable_names(VarNames)), write_term/2))
|
||||||
).
|
).
|
||||||
|
|
||||||
must_be_var_names_list_([], List).
|
must_be_var_names_list_([], List).
|
||||||
@@ -319,44 +365,90 @@ must_be_var_names_list_([VarName | VarNames], List) :-
|
|||||||
( VarName = (Atom = _) ->
|
( VarName = (Atom = _) ->
|
||||||
( atom(Atom) -> must_be_var_names_list_(VarNames, List)
|
( atom(Atom) -> must_be_var_names_list_(VarNames, List)
|
||||||
; var(Atom) -> throw(error(instantiation_error, write_term/2))
|
; var(Atom) -> throw(error(instantiation_error, write_term/2))
|
||||||
; throw(error(domain_error(write_options, variable_names(List)), write_term/2))
|
; throw(error(domain_error(write_option, variable_names(List)), write_term/2))
|
||||||
)
|
)
|
||||||
; throw(error(domain_error(write_options, variable_names(List)), write_term/2))
|
; throw(error(domain_error(write_option, variable_names(List)), write_term/2))
|
||||||
)
|
)
|
||||||
; throw(error(instantiation_error, write_term/2)) % throw(error(domain_error(write_options, variable_names(List)), write_term/2))
|
; throw(error(instantiation_error, write_term/2))
|
||||||
).
|
).
|
||||||
|
|
||||||
write_term(_, Options) :-
|
|
||||||
var(Options), throw(error(instantiation_error, write_term/2)).
|
|
||||||
write_term(Term, Options) :-
|
write_term(Term, Options) :-
|
||||||
'$skip_max_list'(_, -1, Options, Options0),
|
current_output(Stream),
|
||||||
( var(Options0) -> throw(error(instantiation_error, write_term/2))
|
write_term(Stream, Term, Options).
|
||||||
; Options0 == [] -> true
|
|
||||||
; throw(error(type_error(list, Options), write_term/2))
|
|
||||||
), % 8.14.2.3 c)
|
|
||||||
inst_member_or(Options, ignore_ops(IgnoreOps), ignore_ops(false)),
|
|
||||||
inst_member_or(Options, numbervars(NumberVars), numbervars(false)),
|
|
||||||
inst_member_or(Options, quoted(Quoted), quoted(false)),
|
|
||||||
inst_member_or(Options, variable_names(VarNames), variable_names([])),
|
|
||||||
'$write_term'(Term, IgnoreOps, NumberVars, Quoted, VarNames).
|
|
||||||
|
|
||||||
write(Term) :- write_term(Term, [numbervars(true)]).
|
write_term(Stream, Term, Options) :-
|
||||||
|
parse_write_options(Options, [IgnoreOps, MaxDepth, NumberVars, Quoted, VNNames], write_term/3),
|
||||||
|
'$write_term'(Stream, Term, IgnoreOps, NumberVars, Quoted, VNNames, MaxDepth).
|
||||||
|
|
||||||
write_canonical(Term) :- write_term(Term, [ignore_ops(true), quoted(true)]).
|
|
||||||
|
|
||||||
writeq(Term) :- write_term(Term, [quoted(true), numbervars(true)]).
|
write(Term) :-
|
||||||
|
current_output(Stream),
|
||||||
|
'$write_term'(Stream, Term, false, true, false, [], 0).
|
||||||
|
|
||||||
%% TODO: complete the predicate! Most read options are missing.
|
write_canonical(Term) :-
|
||||||
read_term(Term, Options) :-
|
current_output(Stream),
|
||||||
'$skip_max_list'(_, -1, Options, Options0),
|
'$write_term'(Stream, Term, true, false, true, [], 0).
|
||||||
( Options0 == [] -> true
|
|
||||||
; var(Options0) -> throw(error(instantiation_error, read_term/2)) % 8.14.1.3 b)
|
writeq(Term) :-
|
||||||
; throw(error(type_error(list, Options), read_term/2)) % 8.14.1.3 d)
|
current_output(Stream),
|
||||||
),
|
'$write_term'(Stream, Term, false, true, true, [], 0).
|
||||||
( Options = [variable_names(VarList)] -> '$read_term'(Term, VarList)
|
|
||||||
; Options = [] -> read(Term)
|
|
||||||
; false
|
|
||||||
|
select_rightmost_options([Option-Value | OptionPairs], OptionValues) :-
|
||||||
|
( pairs:same_key(Option, OptionPairs, OtherValues, _),
|
||||||
|
OtherValues == [] ->
|
||||||
|
OptionValues = [Value | OptionValues0],
|
||||||
|
select_rightmost_options(OptionPairs, OptionValues0)
|
||||||
|
;
|
||||||
|
select_rightmost_options(OptionPairs, OptionValues)
|
||||||
).
|
).
|
||||||
|
select_rightmost_options([], []).
|
||||||
|
|
||||||
|
|
||||||
|
parse_options_list(Options, Selector, DefaultPairs, OptionValues, Stub) :-
|
||||||
|
'$skip_max_list'(_, -1, Options, Tail),
|
||||||
|
( Tail == [] ->
|
||||||
|
true
|
||||||
|
; var(Tail) ->
|
||||||
|
throw(error(instantiation_error, Stub)) % 8.11.5.3c)
|
||||||
|
; Tail \== [] ->
|
||||||
|
throw(error(type_error(list, Options), Stub)) % 8.11.5.3e)
|
||||||
|
),
|
||||||
|
( lists:maplist(nonvar, Options),
|
||||||
|
catch(lists:maplist(Selector, Options, OptionPairs0),
|
||||||
|
error(E, _),
|
||||||
|
throw(error(E, Stub))) ->
|
||||||
|
lists:append(DefaultPairs, OptionPairs0, OptionPairs1),
|
||||||
|
keysort(OptionPairs1, OptionPairs),
|
||||||
|
select_rightmost_options(OptionPairs, OptionValues)
|
||||||
|
;
|
||||||
|
throw(error(instantiation_error, Stub)) % 8.11.5.3c)
|
||||||
|
).
|
||||||
|
|
||||||
|
|
||||||
|
parse_read_term_options(Options, OptionValues, Stub) :-
|
||||||
|
DefaultOptions = [singletons-_, variables-_, variable_names-_],
|
||||||
|
parse_options_list(Options, parse_read_term_options_, DefaultOptions, OptionValues, Stub).
|
||||||
|
|
||||||
|
|
||||||
|
parse_read_term_options_(singletons(Vars), singletons-Vars).
|
||||||
|
parse_read_term_options_(variables(Vars), variables-Vars).
|
||||||
|
parse_read_term_options_(variable_names(Vars), variable_names-Vars).
|
||||||
|
parse_read_term_options_(E,_) :-
|
||||||
|
throw(error(domain_error(read_option, E), _)).
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
read_term(Stream, Term, Options) :-
|
||||||
|
parse_read_term_options(Options, [Singletons, VariableNames, Variables], read_term/3),
|
||||||
|
'$read_term'(Stream, Term, Singletons, Variables, VariableNames).
|
||||||
|
|
||||||
|
read_term(Term, Options) :-
|
||||||
|
current_input(Stream),
|
||||||
|
read_term(Stream, Term, Options).
|
||||||
|
|
||||||
|
|
||||||
% expand_goal.
|
% expand_goal.
|
||||||
|
|
||||||
@@ -448,7 +540,7 @@ set_difference([], _, []) :- !.
|
|||||||
set_difference(Xs, [], Xs).
|
set_difference(Xs, [], Xs).
|
||||||
|
|
||||||
group_by_variant([V2-S2 | Pairs], V1-S1, [S2 | Solutions], Pairs0) :-
|
group_by_variant([V2-S2 | Pairs], V1-S1, [S2 | Solutions], Pairs0) :-
|
||||||
non_iso:variant(V1, V2), !, V1 = V2, group_by_variant(Pairs, V2-S2, Solutions, Pairs0).
|
iso_ext:variant(V1, V2), !, V1 = V2, group_by_variant(Pairs, V2-S2, Solutions, Pairs0).
|
||||||
group_by_variant(Pairs, _, [], Pairs).
|
group_by_variant(Pairs, _, [], Pairs).
|
||||||
|
|
||||||
group_by_variants([V-S|Pairs], [V-Solution|Solutions]) :-
|
group_by_variants([V-S|Pairs], [V-Solution|Solutions]) :-
|
||||||
@@ -456,7 +548,10 @@ group_by_variants([V-S|Pairs], [V-Solution|Solutions]) :-
|
|||||||
group_by_variants(Pairs0, Solutions).
|
group_by_variants(Pairs0, Solutions).
|
||||||
group_by_variants([], []).
|
group_by_variants([], []).
|
||||||
|
|
||||||
iterate_variants([V-Solution|GroupSolutions], V, Solution).
|
iterate_variants([V-Solution|GroupSolutions], V, Solution) :-
|
||||||
|
( GroupSolutions == [] -> !
|
||||||
|
; true
|
||||||
|
).
|
||||||
iterate_variants([_|GroupSolutions], Ws, Solution) :-
|
iterate_variants([_|GroupSolutions], Ws, Solution) :-
|
||||||
iterate_variants(GroupSolutions, Ws, Solution).
|
iterate_variants(GroupSolutions, Ws, Solution).
|
||||||
|
|
||||||
@@ -472,7 +567,9 @@ findall_with_existential(Template, Goal, PairedSolutions, Witnesses0, Witnesses)
|
|||||||
( nonvar(Goal), Goal = _ ^ _ ->
|
( nonvar(Goal), Goal = _ ^ _ ->
|
||||||
rightmost_power(Goal, Goal1, ExistentialVars0),
|
rightmost_power(Goal, Goal1, ExistentialVars0),
|
||||||
term_variables(ExistentialVars0, ExistentialVars),
|
term_variables(ExistentialVars0, ExistentialVars),
|
||||||
set_difference(Witnesses0, ExistentialVars, Witnesses),
|
sort(Witnesses0, Witnesses1),
|
||||||
|
sort(ExistentialVars, ExistentialVars1),
|
||||||
|
set_difference(Witnesses1, ExistentialVars1, Witnesses),
|
||||||
findall(Witnesses-Template, Goal1, PairedSolutions)
|
findall(Witnesses-Template, Goal1, PairedSolutions)
|
||||||
; Witnesses = Witnesses0,
|
; Witnesses = Witnesses0,
|
||||||
findall(Witnesses-Template, Goal, PairedSolutions)
|
findall(Witnesses-Template, Goal, PairedSolutions)
|
||||||
@@ -491,7 +588,10 @@ bagof(Template, Goal, Solution) :-
|
|||||||
iterate_variants(GroupedSolutions, Witnesses, Solution).
|
iterate_variants(GroupedSolutions, Witnesses, Solution).
|
||||||
|
|
||||||
iterate_variants_and_sort([V-Solution0|GroupSolutions], V, Solution) :-
|
iterate_variants_and_sort([V-Solution0|GroupSolutions], V, Solution) :-
|
||||||
sort(Solution0, Solution).
|
sort(Solution0, Solution),
|
||||||
|
( GroupSolutions == [] -> !
|
||||||
|
; true
|
||||||
|
).
|
||||||
iterate_variants_and_sort([_|GroupSolutions], Ws, Solution) :-
|
iterate_variants_and_sort([_|GroupSolutions], Ws, Solution) :-
|
||||||
iterate_variants_and_sort(GroupSolutions, Ws, Solution).
|
iterate_variants_and_sort(GroupSolutions, Ws, Solution).
|
||||||
|
|
||||||
@@ -531,18 +631,19 @@ setof(Template, Goal, Solution) :-
|
|||||||
|
|
||||||
clause(H, B) :-
|
clause(H, B) :-
|
||||||
( var(H) -> throw(error(instantiation_error, clause/2))
|
( var(H) -> throw(error(instantiation_error, clause/2))
|
||||||
; functor(H, Name, Arity) -> ( Name == '.' -> throw(error(type_error(callable, H), clause/2))
|
; functor(H, Name, Arity) ->
|
||||||
; Name == (:), Arity =:= 2 ->
|
( Name == '.' -> throw(error(type_error(callable, H), clause/2))
|
||||||
arg(1, H, Module),
|
; Name == (:), Arity =:= 2 ->
|
||||||
arg(2, H, F),
|
arg(1, H, Module),
|
||||||
'$module_clause'(F, B, Module)
|
arg(2, H, F),
|
||||||
%% '$no_such_predicate' fails if H is not callable.
|
'$module_clause'(F, B, Module)
|
||||||
; '$no_such_predicate'(H) -> '$fail'
|
%% '$no_such_predicate' fails if H is not callable.
|
||||||
; '$head_is_dynamic'(H) -> '$clause_body_is_valid'(B),
|
; '$no_such_predicate'(H) -> '$fail'
|
||||||
'$get_clause'(H, B)
|
; '$head_is_dynamic'(H) -> '$clause_body_is_valid'(B),
|
||||||
; throw(error(permission_error(access, private_procedure, Name/Arity),
|
'$get_clause'(H, B)
|
||||||
clause/2))
|
; throw(error(permission_error(access, private_procedure, Name/Arity),
|
||||||
)
|
clause/2))
|
||||||
|
)
|
||||||
; throw(error(type_error(callable, H), clause/2))
|
; throw(error(type_error(callable, H), clause/2))
|
||||||
).
|
).
|
||||||
|
|
||||||
@@ -813,7 +914,14 @@ op(Priority, OpSpec, Op) :-
|
|||||||
; throw(error(type_error(list, Op), op/3)) % 8.14.3.3 f)
|
; 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) :-
|
atom_length(Atom, Length) :-
|
||||||
( var(Atom) -> throw(error(instantiation_error, atom_length/2)) % 8.16.1.3 a)
|
( var(Atom) -> throw(error(instantiation_error, atom_length/2)) % 8.16.1.3 a)
|
||||||
@@ -833,10 +941,10 @@ atom_chars(Atom, List) :-
|
|||||||
),
|
),
|
||||||
( var(Atom) ->
|
( var(Atom) ->
|
||||||
( var(Tail) -> throw(error(instantiation_error, atom_chars/2))
|
( var(Tail) -> throw(error(instantiation_error, atom_chars/2))
|
||||||
; ground(List), Tail == [] -> '$atom_chars'(Atom, List)
|
; ground(List) -> '$atom_chars'(Atom, List)
|
||||||
; throw(error(instantiation_error, atom_chars/2))
|
; throw(error(instantiation_error, atom_chars/2))
|
||||||
)
|
)
|
||||||
; atom(Atom) -> can_be_chars_or_vars(List, atom_chars/2), '$atom_chars'(Atom, List)
|
; atom(Atom) -> '$atom_chars'(Atom, List)
|
||||||
; throw(error(type_error(atom, Atom), atom_chars/2))
|
; throw(error(type_error(atom, Atom), atom_chars/2))
|
||||||
).
|
).
|
||||||
|
|
||||||
@@ -850,7 +958,7 @@ atom_codes(Atom, List) :-
|
|||||||
; ground(List), Tail == [] -> '$atom_codes'(Atom, List)
|
; ground(List), Tail == [] -> '$atom_codes'(Atom, List)
|
||||||
; throw(error(instantiation_error, atom_codes/2))
|
; throw(error(instantiation_error, atom_codes/2))
|
||||||
)
|
)
|
||||||
; atom(Atom) -> can_be_codes_or_vars(List, atom_codes/2), '$atom_codes'(Atom, List)
|
; atom(Atom) -> '$atom_codes'(Atom, List)
|
||||||
; throw(error(type_error(atom, Atom), atom_codes/2))
|
; throw(error(type_error(atom, Atom), atom_codes/2))
|
||||||
).
|
).
|
||||||
|
|
||||||
@@ -907,11 +1015,11 @@ char_code(Char, Code) :-
|
|||||||
).
|
).
|
||||||
|
|
||||||
get_char(C) :-
|
get_char(C) :-
|
||||||
( var(C) -> '$get_char'(C)
|
current_input(S),
|
||||||
; C == end_of_file -> '$get_char'(C)
|
'$get_char'(S, C).
|
||||||
; atom_length(C, 1) -> '$get_char'(C)
|
|
||||||
; throw(error(type_error(in_character, C), get_char/1))
|
get_char(S, C) :-
|
||||||
).
|
'$get_char'(S, C).
|
||||||
|
|
||||||
can_be_number(N, PI) :-
|
can_be_number(N, PI) :-
|
||||||
( var(N) -> true
|
( var(N) -> true
|
||||||
@@ -928,45 +1036,6 @@ must_be_number(N, PI) :-
|
|||||||
; throw(error(instantiation_error, PI))
|
; throw(error(instantiation_error, PI))
|
||||||
).
|
).
|
||||||
|
|
||||||
can_be_chars_or_vars(Cs, _) :- var(Cs), !.
|
|
||||||
can_be_chars_or_vars(Cs, PI) :-
|
|
||||||
( string(Cs) ->
|
|
||||||
current_prolog_flag(double_quotes, chars)
|
|
||||||
; chars_or_vars(Cs, PI)
|
|
||||||
).
|
|
||||||
|
|
||||||
chars_or_vars([], _).
|
|
||||||
chars_or_vars([C|Cs], PI) :-
|
|
||||||
( nonvar(C) ->
|
|
||||||
( catch(atom_length(C, 1), _, false) ->
|
|
||||||
( nonvar(Cs) -> chars_or_vars(Cs, PI)
|
|
||||||
; false
|
|
||||||
)
|
|
||||||
; throw(error(type_error(character, C), PI))
|
|
||||||
)
|
|
||||||
; chars_or_vars(Cs, PI)
|
|
||||||
).
|
|
||||||
|
|
||||||
can_be_codes_or_vars(Cs, _) :- var(Cs), !.
|
|
||||||
can_be_codes_or_vars(Cs, PI) :-
|
|
||||||
( string(Cs) ->
|
|
||||||
current_prolog_flag(double_quotes, codes)
|
|
||||||
; codes_or_vars(Cs, PI)
|
|
||||||
).
|
|
||||||
|
|
||||||
codes_or_vars([], _).
|
|
||||||
codes_or_vars([C|Cs], PI) :-
|
|
||||||
( nonvar(C) ->
|
|
||||||
( catch(char_code(_, C), _, false) ->
|
|
||||||
( nonvar(Cs) -> codes_or_vars(Cs, PI)
|
|
||||||
; false
|
|
||||||
)
|
|
||||||
; integer(C) -> throw(error(representation_error(character_code), PI))
|
|
||||||
; throw(error(type_error(integer, C), PI))
|
|
||||||
)
|
|
||||||
; codes_or_vars(Cs, PI)
|
|
||||||
).
|
|
||||||
|
|
||||||
number_chars(N, Chs) :-
|
number_chars(N, Chs) :-
|
||||||
( ground(Chs)
|
( ground(Chs)
|
||||||
-> can_be_number(N, number_chars/2),
|
-> can_be_number(N, number_chars/2),
|
||||||
@@ -1006,3 +1075,226 @@ subsumes_term(General, Specific) :-
|
|||||||
).
|
).
|
||||||
|
|
||||||
unify_with_occurs_check(X, Y) :- '$unify_with_occurs_check'(X, Y).
|
unify_with_occurs_check(X, Y) :- '$unify_with_occurs_check'(X, Y).
|
||||||
|
|
||||||
|
current_input(S) :- '$current_input'(S).
|
||||||
|
|
||||||
|
current_output(S) :- '$current_output'(S).
|
||||||
|
|
||||||
|
set_input(S) :-
|
||||||
|
( var(S) ->
|
||||||
|
throw(error(instantiation_error, set_input/1))
|
||||||
|
; '$set_input'(S)
|
||||||
|
).
|
||||||
|
|
||||||
|
set_output(S) :-
|
||||||
|
( var(S) ->
|
||||||
|
throw(error(instantiation_error, set_output/1))
|
||||||
|
; '$set_output'(S)
|
||||||
|
).
|
||||||
|
|
||||||
|
|
||||||
|
parse_stream_options(Options, OptionValues, Stub) :-
|
||||||
|
DefaultOptions = [alias-[], eof_action-eof_code, reposition-false, type-text],
|
||||||
|
parse_options_list(Options, parse_stream_options_, DefaultOptions, OptionValues, Stub).
|
||||||
|
|
||||||
|
|
||||||
|
parse_stream_options_(type(Type), type-Type) :-
|
||||||
|
( nonvar(Type), lists:member(Type, [text, binary]), !, true
|
||||||
|
;
|
||||||
|
throw(error(domain_error(stream_option, type(Type)), _))
|
||||||
|
).
|
||||||
|
parse_stream_options_(reposition(Bool), reposition-Bool) :-
|
||||||
|
( nonvar(Bool), lists:member(Bool, [true, false]), !, true
|
||||||
|
;
|
||||||
|
throw(error(domain_error(stream_option, reposition(Bool)), _))
|
||||||
|
).
|
||||||
|
parse_stream_options_(alias(A), alias-A) :-
|
||||||
|
( atom(A), A \== [], !, true
|
||||||
|
;
|
||||||
|
throw(error(domain_error(stream_option, alias(A)), _))
|
||||||
|
).
|
||||||
|
parse_stream_options_(eof_action(Action), eof_action-Action) :-
|
||||||
|
( nonvar(Action), lists:member(Action, [eof_code, error, reset]), !, true
|
||||||
|
;
|
||||||
|
throw(error(domain_error(stream_option, eof_action(Action)), _))
|
||||||
|
).
|
||||||
|
parse_stream_options_(E, _) :-
|
||||||
|
throw(error(domain_error(stream_option, E), _)). % 8.11.5.3i)
|
||||||
|
|
||||||
|
|
||||||
|
open(SourceSink, Mode, Stream) :-
|
||||||
|
open(SourceSink, Mode, Stream, []).
|
||||||
|
|
||||||
|
open(SourceSink, Mode, Stream, StreamOptions) :-
|
||||||
|
( var(SourceSink) ->
|
||||||
|
throw(error(instantiation_error, open/4)) % 8.11.5.3a)
|
||||||
|
; var(Mode) ->
|
||||||
|
throw(error(instantiation_error, open/4)) % 8.11.5.3b)
|
||||||
|
; \+ atom(Mode) ->
|
||||||
|
throw(error(type_error(atom, Mode), open/4)) % 8.11.5.3d)
|
||||||
|
; nonvar(Stream) ->
|
||||||
|
throw(error(type_error(variable, Stream), open/4)) % 8.11.5.3f)
|
||||||
|
;
|
||||||
|
parse_stream_options(StreamOptions, [Alias, EOFAction, Reposition, Type], open/4),
|
||||||
|
'$open'(SourceSink, Mode, Stream, Alias, EOFAction, Reposition, Type)
|
||||||
|
).
|
||||||
|
|
||||||
|
|
||||||
|
parse_close_options(Options, OptionValues, Stub) :-
|
||||||
|
DefaultOptions = [force-false],
|
||||||
|
parse_options_list(Options, parse_close_options_, DefaultOptions, OptionValues, Stub).
|
||||||
|
|
||||||
|
parse_close_options_(force(Force), force-Force) :-
|
||||||
|
( nonvar(Force), lists:member(Force, [true, false]), !
|
||||||
|
;
|
||||||
|
throw(error(domain_error(close_option, force(Force)), _))
|
||||||
|
).
|
||||||
|
parse_close_options_(E, _) :-
|
||||||
|
throw(error(domain_error(close_option, E), _)).
|
||||||
|
|
||||||
|
|
||||||
|
close(Stream, CloseOptions) :-
|
||||||
|
parse_close_options(CloseOptions, [Force], close/2),
|
||||||
|
'$close'(Stream, CloseOptions).
|
||||||
|
|
||||||
|
close(Stream) :-
|
||||||
|
'$close'(Stream, []).
|
||||||
|
|
||||||
|
|
||||||
|
flush_output(S) :-
|
||||||
|
'$flush_output'(S).
|
||||||
|
|
||||||
|
flush_output :-
|
||||||
|
current_output(S),
|
||||||
|
'$flush_output'(S).
|
||||||
|
|
||||||
|
|
||||||
|
get_byte(S, B) :-
|
||||||
|
'$get_byte'(S, B).
|
||||||
|
|
||||||
|
get_byte(B) :-
|
||||||
|
current_input(S),
|
||||||
|
'$get_byte'(S, B).
|
||||||
|
|
||||||
|
|
||||||
|
put_char(C) :-
|
||||||
|
current_output(S),
|
||||||
|
'$put_char'(S, C).
|
||||||
|
|
||||||
|
put_char(S, C) :-
|
||||||
|
'$put_char'(S, C).
|
||||||
|
|
||||||
|
|
||||||
|
put_byte(C) :-
|
||||||
|
current_output(S),
|
||||||
|
'$put_byte'(S, C).
|
||||||
|
|
||||||
|
put_byte(S, C) :-
|
||||||
|
'$put_byte'(S, C).
|
||||||
|
|
||||||
|
|
||||||
|
put_code(C) :-
|
||||||
|
current_output(S),
|
||||||
|
'$put_code'(S, C).
|
||||||
|
|
||||||
|
put_code(S, C) :-
|
||||||
|
'$put_code'(S, C).
|
||||||
|
|
||||||
|
|
||||||
|
get_code(C) :-
|
||||||
|
current_input(S),
|
||||||
|
'$get_code'(S, C).
|
||||||
|
|
||||||
|
get_code(S, C) :-
|
||||||
|
'$get_code'(S, C).
|
||||||
|
|
||||||
|
|
||||||
|
peek_byte(S, B) :-
|
||||||
|
'$peek_byte'(S, B).
|
||||||
|
|
||||||
|
peek_byte(B) :-
|
||||||
|
current_input(S),
|
||||||
|
'$peek_byte'(S, B).
|
||||||
|
|
||||||
|
|
||||||
|
peek_code(C) :-
|
||||||
|
current_input(S),
|
||||||
|
'$peek_code'(S, C).
|
||||||
|
|
||||||
|
peek_code(S, C) :-
|
||||||
|
'$peek_code'(S, C).
|
||||||
|
|
||||||
|
|
||||||
|
peek_char(C) :-
|
||||||
|
current_input(S),
|
||||||
|
'$peek_char'(S, C).
|
||||||
|
|
||||||
|
peek_char(S, C) :-
|
||||||
|
'$peek_char'(S, C).
|
||||||
|
|
||||||
|
|
||||||
|
check_stream_property(file_name(F), file_name, F) :-
|
||||||
|
( var(F) -> true ; atom(F) ).
|
||||||
|
check_stream_property(mode(M), mode, M) :-
|
||||||
|
( var(M) -> true ; lists:member(M, [read, write, append]) ).
|
||||||
|
check_stream_property(D, direction, D) :-
|
||||||
|
( var(D) -> true ; lists:member(D, [input, output, input_output]), ! ).
|
||||||
|
check_stream_property(alias(A), alias, A) :-
|
||||||
|
( var(A) -> true ; atom(A) ).
|
||||||
|
check_stream_property(position(P), position, P) :-
|
||||||
|
( var(P) -> true ; integer(P), P >= 0 ).
|
||||||
|
check_stream_property(end_of_stream(E), end_of_stream, E) :-
|
||||||
|
( var(E) -> true ; lists:member(E, [not, at, past]) ).
|
||||||
|
check_stream_property(eof_action(A), eof_action, A) :-
|
||||||
|
( var(A) -> true ; lists:member(A, [error, eof_code, reset]) ).
|
||||||
|
check_stream_property(reposition(B), reposition, B) :-
|
||||||
|
( var(B) -> true ; lists:member(B, [true, false]) ).
|
||||||
|
check_stream_property(type(T), type, T) :-
|
||||||
|
( var(T) -> true ; lists:member(T, [text, binary]) ).
|
||||||
|
|
||||||
|
|
||||||
|
stream_iter_(S, S).
|
||||||
|
stream_iter_(S, S1) :-
|
||||||
|
'$next_stream'(S, S0),
|
||||||
|
stream_iter_(S0, S1).
|
||||||
|
|
||||||
|
stream_iter(S) :-
|
||||||
|
( nonvar(S) ->
|
||||||
|
true
|
||||||
|
; '$first_stream'(S0),
|
||||||
|
stream_iter_(S0, S)
|
||||||
|
).
|
||||||
|
|
||||||
|
|
||||||
|
stream_property(S, P) :-
|
||||||
|
( nonvar(P), \+ check_stream_property(P, _, _) ->
|
||||||
|
throw(error(domain_error(stream_property, P), stream_property/2))
|
||||||
|
; stream_iter(S),
|
||||||
|
check_stream_property(P, PropertyName, PropertyValue),
|
||||||
|
'$stream_property'(S, PropertyName, PropertyValue)
|
||||||
|
).
|
||||||
|
|
||||||
|
|
||||||
|
at_end_of_stream(S_or_a) :-
|
||||||
|
( atom(S_or_a) ->
|
||||||
|
stream_property(S, alias(S_or_a))
|
||||||
|
; S = S_or_a
|
||||||
|
),
|
||||||
|
stream_property(S, end_of_stream(E)),
|
||||||
|
( E = at -> true ; E = past ).
|
||||||
|
|
||||||
|
at_end_of_stream :-
|
||||||
|
current_input(S),
|
||||||
|
stream_property(S, end_of_stream(E)),
|
||||||
|
!,
|
||||||
|
( E = at ; E = past ).
|
||||||
|
|
||||||
|
|
||||||
|
set_stream_position(S_or_a, Position) :-
|
||||||
|
( var(Position) ->
|
||||||
|
throw(error(instantiation_error, set_stream_position/2))
|
||||||
|
; integer(Position), Position >= 0 ->
|
||||||
|
true
|
||||||
|
; throw(error(domain_error(stream_position, Position)))
|
||||||
|
),
|
||||||
|
'$set_stream_position'(S_or_a, Position).
|
||||||
242
src/lib/charsio.pl
Normal file
242
src/lib/charsio.pl
Normal file
@@ -0,0 +1,242 @@
|
|||||||
|
:- 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,
|
||||||
|
chars_base64/3]).
|
||||||
|
|
||||||
|
:- use_module(library(dcgs)).
|
||||||
|
:- use_module(library(iso_ext)).
|
||||||
|
:- use_module(library(error)).
|
||||||
|
:- use_module(library(lists)).
|
||||||
|
|
||||||
|
fabricate_var_name(VarType, VarName, N) :-
|
||||||
|
char_code('A', AC),
|
||||||
|
LN is N mod 26 + AC,
|
||||||
|
char_code(LC, LN),
|
||||||
|
NN is N // 26,
|
||||||
|
( NN =:= 0 ->
|
||||||
|
( VarType == fabricated ->
|
||||||
|
atom_chars(VarName, ['_', LC])
|
||||||
|
; VarType == numbervars ->
|
||||||
|
atom_chars(VarName, [LC])
|
||||||
|
)
|
||||||
|
; number_chars(NN, NNChars),
|
||||||
|
( VarType == fabricated ->
|
||||||
|
atom_chars(VarName, ['_', LC | NNChars])
|
||||||
|
; VarType == numbervars ->
|
||||||
|
atom_chars(VarName, [LC | NNChars])
|
||||||
|
)
|
||||||
|
).
|
||||||
|
|
||||||
|
var_list_contains_name([VarName = _ | VarList], VarName0) :-
|
||||||
|
( VarName == VarName0 -> true
|
||||||
|
; var_list_contains_name(VarList, VarName0)
|
||||||
|
).
|
||||||
|
|
||||||
|
var_list_contains_variable([_ = Var | VarList], Var0) :-
|
||||||
|
( Var == Var0 -> true
|
||||||
|
; var_list_contains_variable(VarList, Var0)
|
||||||
|
).
|
||||||
|
|
||||||
|
make_new_var_name(VarType, V, VarName, N, N1, VarList) :-
|
||||||
|
fabricate_var_name(VarType, VarName0, N),
|
||||||
|
( var_list_contains_name(VarList, VarName0) ->
|
||||||
|
N0 is N + 1,
|
||||||
|
make_new_var_name(VarType, V, VarName, N0, N1, VarList)
|
||||||
|
; VarName = VarName0,
|
||||||
|
N1 is N + 1
|
||||||
|
).
|
||||||
|
|
||||||
|
extend_var_list(Vars, VarList, NewVarList, VarType) :-
|
||||||
|
extend_var_list_(Vars, 0, VarList, NewVarList0, VarType),
|
||||||
|
append(VarList, NewVarList0, NewVarList).
|
||||||
|
|
||||||
|
extend_var_list_([], _, VarList, [], _).
|
||||||
|
extend_var_list_([V|Vs], N, VarList, NewVarList, VarType) :-
|
||||||
|
( var_list_contains_variable(VarList, V) ->
|
||||||
|
extend_var_list_(Vs, N, VarList, NewVarList, VarType)
|
||||||
|
; make_new_var_name(VarType, V, VarName, N, N1, VarList),
|
||||||
|
NewVarList = [VarName = V | NewVarList0],
|
||||||
|
extend_var_list_(Vs, N1, VarList, NewVarList0, VarType)
|
||||||
|
).
|
||||||
|
|
||||||
|
|
||||||
|
char_type(Char, Type) :-
|
||||||
|
( var(Char) -> instantiation_error(char_type/2)
|
||||||
|
; atom_length(Char, 1) ->
|
||||||
|
( ground(Type) ->
|
||||||
|
( ctype(Type) ->
|
||||||
|
'$char_type'(Char, Type)
|
||||||
|
; domain_error(char_type, Type, char_type/2)
|
||||||
|
)
|
||||||
|
; ctype(Type),
|
||||||
|
'$char_type'(Char, Type)
|
||||||
|
)
|
||||||
|
; type_error(in_character, Char, char_type/2)
|
||||||
|
).
|
||||||
|
|
||||||
|
|
||||||
|
ctype(alnum).
|
||||||
|
ctype(alpha).
|
||||||
|
ctype(alphabetic).
|
||||||
|
ctype(ascii).
|
||||||
|
ctype(ascii_graphic).
|
||||||
|
ctype(ascii_punctuation).
|
||||||
|
ctype(binary_digit).
|
||||||
|
ctype(control).
|
||||||
|
ctype(decimal_digit).
|
||||||
|
ctype(exponent).
|
||||||
|
ctype(graphic).
|
||||||
|
ctype(hexadecimal_digit).
|
||||||
|
ctype(layout).
|
||||||
|
ctype(lower).
|
||||||
|
ctype(meta).
|
||||||
|
ctype(numeric).
|
||||||
|
ctype(octal_digit).
|
||||||
|
ctype(prolog).
|
||||||
|
ctype(sign).
|
||||||
|
ctype(solo).
|
||||||
|
ctype(symbolic_control).
|
||||||
|
ctype(symbolic_hexadecimal).
|
||||||
|
ctype(upper).
|
||||||
|
ctype(whitespace).
|
||||||
|
|
||||||
|
|
||||||
|
get_single_char(C) :-
|
||||||
|
( var(C) -> '$get_single_char'(C)
|
||||||
|
; atom_length(C, 1) -> '$get_single_char'(C)
|
||||||
|
; type_error(in_character, C, get_single_char/1)
|
||||||
|
).
|
||||||
|
|
||||||
|
|
||||||
|
read_term_from_chars(Chars, Term) :-
|
||||||
|
( var(Chars) ->
|
||||||
|
instantiation_error(read_term_from_chars/2)
|
||||||
|
; nonvar(Term) ->
|
||||||
|
throw(error(uninstantiation_error(Term), read_term_from_chars/2))
|
||||||
|
; '$skip_max_list'(_, -1, Chars, Chars0),
|
||||||
|
Chars0 == [],
|
||||||
|
partial_string(Chars) ->
|
||||||
|
true
|
||||||
|
;
|
||||||
|
type_error(complete_string, Chars, read_term_from_chars/2)
|
||||||
|
),
|
||||||
|
'$read_term_from_chars'(Chars, Term).
|
||||||
|
|
||||||
|
|
||||||
|
write_term_to_chars(_, Options, _) :-
|
||||||
|
var(Options), instantiation_error(write_term_to_chars/3).
|
||||||
|
write_term_to_chars(Term, Options, Chars) :-
|
||||||
|
builtins:parse_write_options(Options,
|
||||||
|
[IgnoreOps, MaxDepth, NumberVars, Quoted, VNNames],
|
||||||
|
write_term_to_chars/3),
|
||||||
|
( nonvar(Chars) ->
|
||||||
|
throw(error(uninstantiation_error(Chars), write_term_to_chars/3))
|
||||||
|
;
|
||||||
|
true
|
||||||
|
),
|
||||||
|
term_variables(Term, Vars),
|
||||||
|
extend_var_list(Vars, VNNames, NewVarNames, numbervars),
|
||||||
|
'$write_term_to_chars'(Chars, Term, IgnoreOps, NumberVars, Quoted, NewVarNames, MaxDepth).
|
||||||
|
|
||||||
|
% Encodes Ch character to list of Bytes.
|
||||||
|
char_utf8bytes(Ch, Bytes) :-
|
||||||
|
char_code(Ch, Code),
|
||||||
|
phrase(code_to_utf8(Code), Bytes).
|
||||||
|
|
||||||
|
code_to_utf8(Code) --> {Code @< 0x80}, [Code], !.
|
||||||
|
code_to_utf8(Code) --> {Code @< 0x800}, encode(Code, 0xC0, 2), !.
|
||||||
|
code_to_utf8(Code) --> {Code @< 0x10000}, encode(Code, 0xE0, 3), !.
|
||||||
|
code_to_utf8(Code) --> {Code @< 0x110000}, encode(Code, 0xF0, 4), !.
|
||||||
|
|
||||||
|
encode(_, _, 0) --> !.
|
||||||
|
encode(Code, Prefix, Nb) -->
|
||||||
|
{ Nb1 is Nb - 1, Byte is Prefix \/ ((Code >> (6 * Nb1)) /\ 0x3F) },
|
||||||
|
[Byte], encode(Code, 0x80, Nb1).
|
||||||
|
|
||||||
|
% 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) :-
|
||||||
|
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)
|
||||||
|
).
|
||||||
@@ -30,9 +30,11 @@
|
|||||||
:- use_module(library(between)).
|
:- use_module(library(between)).
|
||||||
:- use_module(library(atts)).
|
:- use_module(library(atts)).
|
||||||
:- use_module(library(lists)).
|
:- use_module(library(lists)).
|
||||||
:- use_module(library(non_iso)).
|
:- use_module(library(iso_ext)).
|
||||||
|
:- use_module(library(random)).
|
||||||
|
:- use_module(library(pairs)).
|
||||||
:- use_module(library(dcgs)).
|
:- use_module(library(dcgs)).
|
||||||
:- use_module(library(error), []).
|
:- use_module(library(error), [domain_error/3, type_error/3]).
|
||||||
|
|
||||||
:- attribute
|
:- attribute
|
||||||
clpb/1,
|
clpb/1,
|
||||||
@@ -96,75 +98,14 @@ instantiation_error(_, Goal-Arg) :-
|
|||||||
domain_error(Expectation, Term) :-
|
domain_error(Expectation, Term) :-
|
||||||
domain_error(Expectation, Term, unknown(Term)-1).
|
domain_error(Expectation, Term, unknown(Term)-1).
|
||||||
|
|
||||||
domain_error(Expectation, Term, Goal-Arg) :-
|
|
||||||
throw(error(domain_error(Expectation, Term), domain_error(Goal, Arg, Expectation, Term))).
|
|
||||||
|
|
||||||
|
|
||||||
type_error(Expectation, Term) :-
|
type_error(Expectation, Term) :-
|
||||||
type_error(Expectation, Term, unknown(Term)-1).
|
type_error(Expectation, Term, unknown(Term)-1).
|
||||||
|
|
||||||
type_error(Expectation, Term, Goal-Arg) :-
|
|
||||||
throw(error(type_error(Expectation, Term), type_error(Goal, Arg, Expectation, Term))).
|
|
||||||
|
|
||||||
|
|
||||||
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
||||||
foldl/4
|
|
||||||
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
|
||||||
|
|
||||||
foldl(Goal_3, Ls, A0, A) :-
|
|
||||||
foldl_(Ls, Goal_3, A0, A).
|
|
||||||
|
|
||||||
foldl_([], _, A, A).
|
|
||||||
foldl_([L|Ls], G_3, A0, A) :-
|
|
||||||
call(G_3, L, A0, A1),
|
|
||||||
foldl_(Ls, G_3, A1, A).
|
|
||||||
|
|
||||||
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
||||||
foldl/5
|
|
||||||
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
|
||||||
|
|
||||||
foldl(Goal_4, Xs, Ys, A0, A) :-
|
|
||||||
foldl_(Xs, Ys, Goal_4, A0, A).
|
|
||||||
|
|
||||||
foldl_([], [], _, A, A).
|
|
||||||
foldl_([X|Xs], [Y|Ys], G_4, A0, A) :-
|
|
||||||
call(G_4, X, Y, A0, A1),
|
|
||||||
foldl_(Xs, Ys, G_4, A1, A).
|
|
||||||
|
|
||||||
|
|
||||||
partition(Pred, Ls0, As, Bs) :-
|
partition(Pred, Ls0, As, Bs) :-
|
||||||
include(Pred, Ls0, As),
|
include(Pred, Ls0, As),
|
||||||
exclude(Pred, Ls0, Bs).
|
exclude(Pred, Ls0, Bs).
|
||||||
|
|
||||||
sum_list(Ls, S) :-
|
|
||||||
foldl(sum_, Ls, 0, S).
|
|
||||||
|
|
||||||
sum_(L, S0, S) :- S is S0 + L.
|
|
||||||
|
|
||||||
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
||||||
Pairs.
|
|
||||||
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
|
||||||
|
|
||||||
pairs_keys_values([], [], []).
|
|
||||||
pairs_keys_values([A-B|ABs], [A|As], [B|Bs]) :-
|
|
||||||
pairs_keys_values(ABs, As, Bs).
|
|
||||||
|
|
||||||
pairs_keys(Ps, Ks) :- pairs_keys_values(Ps, Ks, _).
|
|
||||||
|
|
||||||
pairs_values(Ps, Vs) :- pairs_keys_values(Ps, _, Vs).
|
|
||||||
|
|
||||||
map_list_to_pairs(Pred, Ls, Ps) :-
|
|
||||||
map_list_to_pairs2(Ls, Pred, Ps).
|
|
||||||
|
|
||||||
map_list_to_pairs2([], _, []).
|
|
||||||
map_list_to_pairs2([H|T0], Pred, [K-H|T]) :-
|
|
||||||
call(Pred, H, K),
|
|
||||||
map_list_to_pairs2(T0, Pred, T).
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
goal_expansion(get_attr(Var, Module, Value), (var(Var),get_atts(Var, Access))) :-
|
goal_expansion(get_attr(Var, Module, Value), (var(Var),get_atts(Var, Access))) :-
|
||||||
Access =.. [Module,Value].
|
Access =.. [Module,Value].
|
||||||
|
|
||||||
@@ -728,10 +669,6 @@ existential(V, BDD, Node) :-
|
|||||||
Counter network for card(Is,Fs).
|
Counter network for card(Is,Fs).
|
||||||
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||||
|
|
||||||
same_length([], []).
|
|
||||||
same_length([_|As], [_|Bs]) :-
|
|
||||||
same_length(As, Bs).
|
|
||||||
|
|
||||||
counter_network(Cs, Fs, Node) :-
|
counter_network(Cs, Fs, Node) :-
|
||||||
same_length([_|Fs], Indicators),
|
same_length([_|Fs], Indicators),
|
||||||
fill_indicators(Indicators, 0, Cs),
|
fill_indicators(Indicators, 0, Cs),
|
||||||
7622
src/lib/clpz.pl
Normal file
7622
src/lib/clpz.pl
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
:- module(cont, [reset/3, shift/1]).
|
:- module(cont, [reset/3, shift/1]).
|
||||||
|
|
||||||
reset(Goal, Ball, Cont) :-
|
reset(Goal, Ball, Cont) :-
|
||||||
@@ -7,14 +6,14 @@ reset(Goal, Ball, Cont) :-
|
|||||||
'$bind_from_register'(Cont, 3),
|
'$bind_from_register'(Cont, 3),
|
||||||
'$bind_from_register'(Ball, 4).
|
'$bind_from_register'(Ball, 4).
|
||||||
|
|
||||||
shift(Term) :-
|
shift(Ball) :-
|
||||||
'$nextEP'(first, E, P),
|
'$nextEP'(first, E, P),
|
||||||
get_chunks(E, P, L),
|
get_chunks(E, P, L),
|
||||||
( L == [] ->
|
( L == [] ->
|
||||||
Cont = none
|
Cont = cont(true)
|
||||||
; Cont = cont(call_continuation(L))
|
; Cont = cont(call_continuation(L))
|
||||||
),
|
),
|
||||||
'$write_cont_and_term'(_, _, Cont, Term),
|
'$write_cont_and_term'(_, _, Cont, Ball),
|
||||||
'$unwind_environments'.
|
'$unwind_environments'.
|
||||||
|
|
||||||
get_chunks(E, P, L) :-
|
get_chunks(E, P, L) :-
|
||||||
826
src/lib/crypto.pl
Normal file
826
src/lib/crypto.pl
Normal file
@@ -0,0 +1,826 @@
|
|||||||
|
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
Written May 2020 by Markus Triska (triska@metalevel.at)
|
||||||
|
Part of Scryer Prolog.
|
||||||
|
|
||||||
|
Predicates for cryptographic applications.
|
||||||
|
|
||||||
|
This library assumes that the Prolog flag double_quotes is set to chars.
|
||||||
|
In Scryer Prolog, lists of characters are very efficiently represented,
|
||||||
|
and strings have the advantage that the atom table remains unmodified.
|
||||||
|
|
||||||
|
Especially for cryptographic applications, it as an advantage that
|
||||||
|
using strings leaves little trace of what was processed in the system.
|
||||||
|
|
||||||
|
For predicates that accept an encoding/1 option to specify the encoding
|
||||||
|
of the input data, if encoding(octet) is used, then the input can also
|
||||||
|
be specified as a list of bytes, i.e., integers between 0 and 255.
|
||||||
|
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||||
|
|
||||||
|
:- module(crypto,
|
||||||
|
[hex_bytes/2, % ?Hex, ?Bytes
|
||||||
|
crypto_n_random_bytes/2, % +N, -Bytes
|
||||||
|
crypto_data_hash/3, % +Data, -Hash, +Options
|
||||||
|
crypto_data_hkdf/4, % +Data, +Length, -Bytes, +Options
|
||||||
|
crypto_password_hash/2, % +Password, ?Hash
|
||||||
|
crypto_password_hash/3, % +Password, -Hash, +Options
|
||||||
|
crypto_data_encrypt/6, % +PlainText, +Algorithm, +Key, +IV, -CipherText, +Options
|
||||||
|
crypto_data_decrypt/6, % +CipherText, +Algorithm, +Key, +IV, -PlainText, +Options
|
||||||
|
ed25519_new_keypair/1, % -KeyPair
|
||||||
|
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
|
||||||
|
crypto_curve_scalar_mult/4 % +Curve, +Scalar, +Point, -Result
|
||||||
|
]).
|
||||||
|
|
||||||
|
:- use_module(library(error)).
|
||||||
|
:- use_module(library(lists)).
|
||||||
|
:- use_module(library(between)).
|
||||||
|
:- use_module(library(dcgs)).
|
||||||
|
:- use_module(library(clpz)).
|
||||||
|
:- use_module(library(arithmetic)).
|
||||||
|
:- use_module(library(format)).
|
||||||
|
:- use_module(library(charsio)).
|
||||||
|
:- use_module(library(si)).
|
||||||
|
|
||||||
|
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
hex_bytes(?Hex, ?Bytes) is det.
|
||||||
|
|
||||||
|
Relation between a hexadecimal sequence and a list of bytes. Hex
|
||||||
|
is a string of hexadecimal numbers. Bytes is a list of *integers*
|
||||||
|
between 0 and 255 that represent the sequence as a list of bytes.
|
||||||
|
At least one of the arguments must be instantiated.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
?- hex_bytes("501ACE", Bs).
|
||||||
|
Bs = [80,26,206]
|
||||||
|
; false.
|
||||||
|
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||||
|
|
||||||
|
|
||||||
|
hex_bytes(Hs, Bytes) :-
|
||||||
|
( ground(Hs) ->
|
||||||
|
must_be(list, Hs),
|
||||||
|
maplist(must_be(atom), Hs),
|
||||||
|
( phrase(hex_bytes(Hs), Bytes) ->
|
||||||
|
true
|
||||||
|
; domain_error(hex_encoding, Hs, hex_bytes/2)
|
||||||
|
)
|
||||||
|
; must_be_bytes(Bytes, hex_bytes/2),
|
||||||
|
phrase(bytes_hex(Bytes), Hs)
|
||||||
|
).
|
||||||
|
|
||||||
|
hex_bytes([]) --> [].
|
||||||
|
hex_bytes([H1,H2|Hs]) --> [Byte],
|
||||||
|
{ char_hexval(H1, High),
|
||||||
|
char_hexval(H2, Low),
|
||||||
|
Byte #= High*16 + Low },
|
||||||
|
hex_bytes(Hs).
|
||||||
|
|
||||||
|
bytes_hex([]) --> [].
|
||||||
|
bytes_hex([B|Bs]) --> [C0,C1],
|
||||||
|
{ High #= B>>4,
|
||||||
|
Low #= B /\ 0xf,
|
||||||
|
char_hexval(C0, High),
|
||||||
|
char_hexval(C1, Low)
|
||||||
|
},
|
||||||
|
bytes_hex(Bs).
|
||||||
|
|
||||||
|
char_hexval(C, H) :- nth0(H, "0123456789abcdef", C), !.
|
||||||
|
char_hexval(C, H) :- nth0(H, "0123456789ABCDEF", C), !.
|
||||||
|
|
||||||
|
|
||||||
|
must_be_bytes(Bytes, Context) :-
|
||||||
|
must_be(list, Bytes),
|
||||||
|
maplist(must_be(integer), Bytes),
|
||||||
|
( member(B, Bytes), \+ between(0, 255, B) ->
|
||||||
|
type_error(byte, B, Context)
|
||||||
|
; true
|
||||||
|
).
|
||||||
|
|
||||||
|
|
||||||
|
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
|
||||||
|
=======================================
|
||||||
|
|
||||||
|
crypto_n_random_bytes(+N, -Bytes) is det
|
||||||
|
|
||||||
|
Bytes is unified with a list of N cryptographically secure
|
||||||
|
pseudo-random bytes. Each byte is an integer between 0 and 255. If
|
||||||
|
the internal pseudo-random number generator (PRNG) has not been
|
||||||
|
seeded with enough entropy to ensure an unpredictable byte
|
||||||
|
sequence, an exception is thrown.
|
||||||
|
|
||||||
|
One way to relate such a list of bytes to an _integer_ is to use
|
||||||
|
CLP(ℤ) constraints as follows:
|
||||||
|
|
||||||
|
:- use_module(library(clpz)).
|
||||||
|
:- use_module(library(lists)).
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
With this definition, we can generate a random 256-bit integer
|
||||||
|
_from_ a list of 32 random _bytes_:
|
||||||
|
|
||||||
|
?- crypto_n_random_bytes(32, Bs),
|
||||||
|
bytes_integer(Bs, I).
|
||||||
|
Bs = [146,166,162,210,242,7,25,132,64,94|...],
|
||||||
|
I = 337420085690608915485...(56 digits omitted)
|
||||||
|
|
||||||
|
The above relation also works in the other direction, letting you
|
||||||
|
translate an integer _to_ a list of bytes. In addition, you can
|
||||||
|
use hex_bytes/2 to convert bytes to _tokens_ that can be easily
|
||||||
|
exchanged in your applications.
|
||||||
|
|
||||||
|
?- crypto_n_random_bytes(12, Bs),
|
||||||
|
hex_bytes(Hex, Bs).
|
||||||
|
Bs = [34,25,50,72,58,63,50,172,32,46|...], Hex = "221932483a3f32ac202 ..."
|
||||||
|
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||||
|
|
||||||
|
|
||||||
|
crypto_n_random_bytes(N, Bs) :-
|
||||||
|
must_be(integer, N),
|
||||||
|
length(Bs, N),
|
||||||
|
maplist(crypto_random_byte, Bs).
|
||||||
|
|
||||||
|
crypto_random_byte(B) :- '$crypto_random_byte'(B).
|
||||||
|
|
||||||
|
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
Hashing
|
||||||
|
=======
|
||||||
|
|
||||||
|
crypto_data_hash(+Data, -Hash, +Options)
|
||||||
|
|
||||||
|
Where Data is a list of characters, and Hash is the computed hash
|
||||||
|
as a list of hexadecimal characters.
|
||||||
|
|
||||||
|
Options is a list of:
|
||||||
|
|
||||||
|
- algorithm(+A)
|
||||||
|
where A is one of ripemd160, sha256, sha384, sha512, sha512_256,
|
||||||
|
sha3_224, sha3_256, sha3_384, sha3_512, blake2s256, blake2b512,
|
||||||
|
or a variable. If A is a variable, then it is unified with the
|
||||||
|
default algorithm, which is an algorithm that is considered
|
||||||
|
cryptographically secure at the time of this writing.
|
||||||
|
- encoding(+Encoding)
|
||||||
|
The default encoding is utf8. The alternative is octet,
|
||||||
|
to treat the input as a list of raw bytes.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
?- crypto_data_hash("abc", Hs, [algorithm(sha256)]).
|
||||||
|
Hs = "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad"
|
||||||
|
; false.
|
||||||
|
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||||
|
|
||||||
|
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
SHA256 is the current default for several hash-related predicates.
|
||||||
|
It is deemed sufficiently secure for the foreseeable future. Yet,
|
||||||
|
application programmers must be aware that the default may change in
|
||||||
|
future versions. The hash predicates all yield the algorithm they
|
||||||
|
used if a Prolog variable is used for the pertaining option.
|
||||||
|
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||||
|
|
||||||
|
crypto_data_hash(Data0, Hash, Options0) :-
|
||||||
|
must_be(list, Options0),
|
||||||
|
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, Encoding, HashBytes, A),
|
||||||
|
hex_bytes(Hash, HashBytes).
|
||||||
|
|
||||||
|
options_data_chars(Options, Data, Chars, Encoding) :-
|
||||||
|
option(encoding(Encoding), Options, utf8),
|
||||||
|
must_be(atom, Encoding),
|
||||||
|
encoding_chars(Encoding, Data, Chars).
|
||||||
|
|
||||||
|
default_hash(sha256).
|
||||||
|
|
||||||
|
functor_hash_options(F, Hash, Options0, [Option|Options]) :-
|
||||||
|
Option =.. [F,Hash],
|
||||||
|
( select(Option, Options0, Options) ->
|
||||||
|
( var(Hash) ->
|
||||||
|
default_hash(Hash)
|
||||||
|
; must_be(atom, Hash)
|
||||||
|
)
|
||||||
|
; Options = Options0,
|
||||||
|
default_hash(Hash)
|
||||||
|
).
|
||||||
|
|
||||||
|
hash_algorithm(ripemd160).
|
||||||
|
hash_algorithm(sha256).
|
||||||
|
hash_algorithm(sha512).
|
||||||
|
hash_algorithm(sha384).
|
||||||
|
hash_algorithm(sha512_256).
|
||||||
|
hash_algorithm(sha3_224).
|
||||||
|
hash_algorithm(sha3_256).
|
||||||
|
hash_algorithm(sha3_384).
|
||||||
|
hash_algorithm(sha3_512).
|
||||||
|
hash_algorithm(blake2s256).
|
||||||
|
hash_algorithm(blake2b512).
|
||||||
|
|
||||||
|
|
||||||
|
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
crypto_data_hkdf(+Data, +Length, -Bytes, +Options) is det.
|
||||||
|
|
||||||
|
Concentrate possibly dispersed entropy of Data and then expand it
|
||||||
|
to the desired length. Data is a list of characters.
|
||||||
|
|
||||||
|
Bytes is unified with a list of bytes of length Length, and is
|
||||||
|
suitable as input keying material and initialization vectors to
|
||||||
|
symmetric encryption algorithms.
|
||||||
|
|
||||||
|
Admissible options are:
|
||||||
|
|
||||||
|
- algorithm(+Algorithm)
|
||||||
|
One of sha256, sha384 or sha512. If you specify a variable,
|
||||||
|
then it is unified with the algorithm that was used, which is a
|
||||||
|
cryptographically secure algorithm by default.
|
||||||
|
- info(+Info)
|
||||||
|
Optional context and application specific information,
|
||||||
|
specified as a list of characters. The default is [].
|
||||||
|
- salt(+List)
|
||||||
|
Optionally, a list of bytes that are used as salt. The
|
||||||
|
default is all zeroes.
|
||||||
|
- encoding(+Encoding)
|
||||||
|
The default encoding is utf8. The alternative is octet,
|
||||||
|
to treat the input as a list of raw bytes.
|
||||||
|
|
||||||
|
The `info/1` option can be used to generate multiple keys from a
|
||||||
|
single master key, using for example values such as "key" and
|
||||||
|
"iv", or the name of a file that is to be encrypted.
|
||||||
|
|
||||||
|
See crypto_n_random_bytes/2 to obtain a suitable salt.
|
||||||
|
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||||
|
|
||||||
|
crypto_data_hkdf(Data0, L, Bytes, Options0) :-
|
||||||
|
functor_hash_options(algorithm, Algorithm, Options0, Options),
|
||||||
|
( hkdf_algorithm(Algorithm) -> true
|
||||||
|
; domain_error(hkdf_algorithm, Algorithm, crypto_data_hkdf/4)
|
||||||
|
),
|
||||||
|
must_be(integer, L),
|
||||||
|
L >= 0,
|
||||||
|
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, Encoding, SaltBytes, Info, Algorithm, L, Bytes).
|
||||||
|
|
||||||
|
hkdf_algorithm(sha256).
|
||||||
|
hkdf_algorithm(sha384).
|
||||||
|
hkdf_algorithm(sha512).
|
||||||
|
|
||||||
|
option(What, Options, Default) :-
|
||||||
|
( member(V, Options), var(V) ->
|
||||||
|
instantiation_error(option/3)
|
||||||
|
; true
|
||||||
|
),
|
||||||
|
( member(What, Options) -> true
|
||||||
|
; What =.. [_,Default]
|
||||||
|
).
|
||||||
|
|
||||||
|
chars_bytes_(Cs, Bytes, Context) :-
|
||||||
|
must_be(list, Cs),
|
||||||
|
( maplist(integer, Cs) -> Bytes = Cs
|
||||||
|
; chars_utf8bytes(Cs, Bytes)
|
||||||
|
),
|
||||||
|
must_be_bytes(Bytes, Context).
|
||||||
|
|
||||||
|
|
||||||
|
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
The so-called modular crypt format (MCF) is a standard for encoding
|
||||||
|
password hash strings. However, there's no official specification
|
||||||
|
document describing it. Nor is there a central registry of
|
||||||
|
identifiers or rules. This page describes what is known about it:
|
||||||
|
|
||||||
|
https://pythonhosted.org/passlib/modular_crypt_format.html
|
||||||
|
|
||||||
|
As of 2016, the MCF is deprecated in favor of the PHC String Format:
|
||||||
|
|
||||||
|
https://github.com/P-H-C/phc-string-format/blob/master/phc-sf-spec.md
|
||||||
|
|
||||||
|
This is what we are using below. For the time being, it is best to
|
||||||
|
treat these hashes as opaque terms in applications. Please let me
|
||||||
|
know if you need to rely on any specifics of this format.
|
||||||
|
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||||
|
|
||||||
|
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
crypto_password_hash(+Password, ?Hash) is semidet.
|
||||||
|
|
||||||
|
If Hash is instantiated, the predicate succeeds _iff_ the hash
|
||||||
|
matches the given password. Otherwise, the call is equivalent to
|
||||||
|
crypto_password_hash(Password, Hash, []) and computes a
|
||||||
|
password-based hash using the default options.
|
||||||
|
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||||
|
|
||||||
|
crypto_password_hash(Password0, Hash) :-
|
||||||
|
( nonvar(Hash) ->
|
||||||
|
chars_bytes_(Password0, Password, crypto_password_hash/2),
|
||||||
|
must_be(list, Hash),
|
||||||
|
dollar_segments(Hash, [[],"pbkdf2-sha512",[t,=|CsIterations],SaltB64,HashB64]),
|
||||||
|
number_chars(Iterations, CsIterations),
|
||||||
|
bytes_base64(SaltBytes, SaltB64),
|
||||||
|
bytes_base64(HashBytes, HashB64),
|
||||||
|
'$crypto_password_hash'(Password, SaltBytes, Iterations, HashBytes)
|
||||||
|
; crypto_password_hash(Password0, Hash, [])
|
||||||
|
).
|
||||||
|
|
||||||
|
|
||||||
|
dollar_segments(Ls, Segments) :-
|
||||||
|
( append(Front, [$|Ds], Ls) ->
|
||||||
|
Segments = [Front|Rest],
|
||||||
|
dollar_segments(Ds, Rest)
|
||||||
|
; Segments = [Ls]
|
||||||
|
).
|
||||||
|
|
||||||
|
|
||||||
|
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
crypto_password_hash(+Password, -Hash, +Options) is det.
|
||||||
|
|
||||||
|
Derive Hash based on Password. This predicate is similar to
|
||||||
|
crypto_data_hash/3 in that it derives a hash from given data.
|
||||||
|
However, it is tailored for the specific use case of _passwords_.
|
||||||
|
One essential distinction is that for this use case, the derivation
|
||||||
|
of a hash should be _as slow as possible_ to counteract brute-force
|
||||||
|
attacks over possible passwords.
|
||||||
|
|
||||||
|
Another important distinction is that equal passwords must yield,
|
||||||
|
with very high probability, _different_ hashes. For this reason,
|
||||||
|
cryptographically strong random numbers are automatically added to
|
||||||
|
the password before a hash is derived.
|
||||||
|
|
||||||
|
Hash is unified with a string that contains the computed hash and
|
||||||
|
all parameters that were used, except for the password. Instead of
|
||||||
|
storing passwords, store these hashes. Later, you can verify the
|
||||||
|
validity of a password with crypto_password_hash/2, comparing the
|
||||||
|
then entered password to the stored hash. If you need to export this
|
||||||
|
atom, you should treat it as opaque ASCII data with up to 255 bytes
|
||||||
|
of length. The maximal length may increase in the future.
|
||||||
|
|
||||||
|
Admissible options are:
|
||||||
|
|
||||||
|
- algorithm(+Algorithm)
|
||||||
|
The algorithm to use. Currently, the only available algorithm
|
||||||
|
is 'pbkdf2-sha512', which is therefore also the default.
|
||||||
|
- cost(+C)
|
||||||
|
C is an integer, denoting the binary logarithm of the number
|
||||||
|
of _iterations_ used for the derivation of the hash. This
|
||||||
|
means that the number of iterations is set to 2^C. Currently,
|
||||||
|
the default is 17, and thus more than one hundred _thousand_
|
||||||
|
iterations. You should set this option as high as your server
|
||||||
|
and users can tolerate. The default is subject to change and
|
||||||
|
will likely increase in the future or adapt to new algorithms.
|
||||||
|
- salt(+Salt)
|
||||||
|
Use the given list of bytes as salt. By default,
|
||||||
|
cryptographically secure random numbers are generated for this
|
||||||
|
purpose. The default is intended to be secure, and constitutes
|
||||||
|
the typical use case of this predicate.
|
||||||
|
|
||||||
|
Currently, PBKDF2 with SHA-512 is used as the hash derivation
|
||||||
|
function, using 128 bits of salt. All default parameters, including
|
||||||
|
the algorithm, are subject to change, and other algorithms will also
|
||||||
|
become available in the future. Since computed hashes store all
|
||||||
|
parameters that were used during their derivation, such changes will
|
||||||
|
not affect the operation of existing deployments. Note though that
|
||||||
|
new hashes will then be computed with the new default parameters.
|
||||||
|
|
||||||
|
See crypto_data_hkdf/4 for generating keys from Hash.
|
||||||
|
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||||
|
|
||||||
|
crypto_password_hash(Password0, Hash, Options) :-
|
||||||
|
chars_bytes_(Password0, Password, crypto_password_hash/3),
|
||||||
|
must_be(list, Options),
|
||||||
|
option(cost(C), Options, 17),
|
||||||
|
Iterations is 2^C,
|
||||||
|
Algorithm = 'pbkdf2-sha512', % current default and only option
|
||||||
|
option(algorithm(Algorithm), Options, Algorithm),
|
||||||
|
( member(salt(SaltBytes), Options) ->
|
||||||
|
must_be_bytes(SaltBytes, crypto_password_hash/2)
|
||||||
|
; crypto_n_random_bytes(16, SaltBytes)
|
||||||
|
),
|
||||||
|
'$crypto_password_hash'(Password, SaltBytes, Iterations, HashBytes),
|
||||||
|
bytes_base64(HashBytes, HashB64),
|
||||||
|
bytes_base64(SaltBytes, SaltB64),
|
||||||
|
phrase(format_("$pbkdf2-sha512$t=~d$~s$~s", [Iterations,SaltB64,HashB64]), Hash).
|
||||||
|
|
||||||
|
|
||||||
|
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
Bidirectional Bytes <-> Base64 conversion *without padding*.
|
||||||
|
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||||
|
|
||||||
|
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)])
|
||||||
|
).
|
||||||
|
|
||||||
|
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
crypto_data_encrypt(+PlainText,
|
||||||
|
+Algorithm,
|
||||||
|
+Key,
|
||||||
|
+IV,
|
||||||
|
-CipherText,
|
||||||
|
+Options).
|
||||||
|
|
||||||
|
Encrypt the given PlainText, using the symmetric algorithm
|
||||||
|
Algorithm, key Key, and initialization vector (or nonce) IV, to
|
||||||
|
give CipherText.
|
||||||
|
|
||||||
|
PlainText must be a list of characters, Key and IV must be lists of
|
||||||
|
bytes, and CipherText is created as a list of characters.
|
||||||
|
|
||||||
|
Keys and IVs can be chosen at random (using for example
|
||||||
|
crypto_n_random_bytes/2) or derived from input keying material (IKM)
|
||||||
|
using for example crypto_data_hkdf/4. This input is often a shared
|
||||||
|
secret, such as a negotiated point on an elliptic curve, or the hash
|
||||||
|
that was computed from a password via crypto_password_hash/3 with a
|
||||||
|
freshly generated and specified _salt_.
|
||||||
|
|
||||||
|
Reusing the same combination of Key and IV typically leaks at least
|
||||||
|
_some_ information about the plaintext. For example, identical
|
||||||
|
plaintexts will then correspond to identical ciphertexts. For some
|
||||||
|
algorithms, reusing an IV with the same Key has disastrous results
|
||||||
|
and can cause the loss of all properties that are otherwise
|
||||||
|
guaranteed. Especially in such cases, an IV is also called a
|
||||||
|
_nonce_ (number used once).
|
||||||
|
|
||||||
|
It is safe to store and transfer the used initialization vector (or
|
||||||
|
nonce) in plain text, but the key _must be kept secret_.
|
||||||
|
|
||||||
|
Currently, the only supported algorithm is 'chacha20-poly1305', a
|
||||||
|
powerful and efficient _authenticated_ encryption scheme, providing
|
||||||
|
secrecy and at the same time reliable protection against undetected
|
||||||
|
_modifications_ of the encrypted data. This is a very good choice
|
||||||
|
for virtually all use cases. It is a stream cipher and can encrypt
|
||||||
|
data of any length up to 256 GB. Further, the encrypted data has
|
||||||
|
exactly the same length as the original, and no padding is used.
|
||||||
|
|
||||||
|
Options:
|
||||||
|
|
||||||
|
- encoding(+Encoding)
|
||||||
|
Encoding to use for PlainText. Default is utf8. The alternative
|
||||||
|
is octet to treat PlainText as raw bytes.
|
||||||
|
|
||||||
|
- tag(-List)
|
||||||
|
For authenticated encryption schemes, List is unified with a
|
||||||
|
list of _bytes_ holding the tag. This tag must be provided for
|
||||||
|
decryption.
|
||||||
|
|
||||||
|
Here is an example encryption and decryption, using the ChaCha20
|
||||||
|
stream cipher with the Poly1305 authenticator. This cipher uses a
|
||||||
|
256-bit key and a 96-bit nonce, i.e., 32 and 12 _bytes_,
|
||||||
|
respectively:
|
||||||
|
|
||||||
|
?- Algorithm = 'chacha20-poly1305',
|
||||||
|
crypto_n_random_bytes(32, Key),
|
||||||
|
crypto_n_random_bytes(12, IV),
|
||||||
|
crypto_data_encrypt("this text is to be encrypted", Algorithm,
|
||||||
|
Key, IV, CipherText, [tag(Tag)]),
|
||||||
|
crypto_data_decrypt(CipherText, Algorithm,
|
||||||
|
Key, IV, RecoveredText, [tag(Tag)]).
|
||||||
|
|
||||||
|
Yielding:
|
||||||
|
|
||||||
|
Algorithm = 'chacha20-poly1305',
|
||||||
|
Key = [113,247,153,134,177,220,13,193,50,150|...],
|
||||||
|
IV = [135,20,149,153,63,35,68,114,247,171|...],
|
||||||
|
CipherText = "\x94\0Ej\x94\®Â\x95\óÑÆXÃn¾ð©b\x1c\ ...",
|
||||||
|
RecoveredText = "this text is to be ...",
|
||||||
|
Tag = [152,117,152,17,162,75,150,206,144,40|...]
|
||||||
|
|
||||||
|
In this example, we use crypto_n_random_bytes/2 to generate a key
|
||||||
|
and nonce from cryptographically secure random numbers. For
|
||||||
|
repeated applications, you must ensure that a nonce is only used
|
||||||
|
_once_ together with the same key. Note that for _authenticated_
|
||||||
|
encryption schemes, the _tag_ that was computed during encryption
|
||||||
|
is necessary for decryption. It is safe to store and transfer the
|
||||||
|
tag in plain text.
|
||||||
|
|
||||||
|
See also crypto_data_decrypt/6, and hex_bytes/2 for conversion
|
||||||
|
between bytes and hex encoding.
|
||||||
|
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||||
|
|
||||||
|
crypto_data_encrypt(PlainText0, Algorithm, Key, IV, CipherText, Options) :-
|
||||||
|
options_data_chars(Options, PlainText0, PlainText, Encoding),
|
||||||
|
option(tag(Tag), Options, _),
|
||||||
|
( nonvar(Tag) ->
|
||||||
|
must_be_bytes(Tag, crypto_data_encrypt/6)
|
||||||
|
; true
|
||||||
|
),
|
||||||
|
must_be_bytes(Key, crypto_data_encrypt/6),
|
||||||
|
must_be_bytes(IV, crypto_data_encrypt/6),
|
||||||
|
must_be(atom, Algorithm),
|
||||||
|
( Algorithm = 'chacha20-poly1305' -> true
|
||||||
|
; domain_error('chacha20-poly1305', Algorithm, crypto_data_encrypt/6)
|
||||||
|
),
|
||||||
|
'$crypto_data_encrypt'(PlainText, Encoding, Key, IV, Tag, CipherText).
|
||||||
|
|
||||||
|
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
crypto_data_decrypt(+CipherText,
|
||||||
|
+Algorithm,
|
||||||
|
+Key,
|
||||||
|
+IV,
|
||||||
|
-PlainText,
|
||||||
|
+Options).
|
||||||
|
|
||||||
|
Decrypt the given CipherText, using the symmetric algorithm
|
||||||
|
Algorithm, key Key, and initialization vector IV, to give
|
||||||
|
PlainText. CipherText must be a list of characters, and Key and IV
|
||||||
|
must be lists of bytes. PlainText is created as a list of
|
||||||
|
characters.
|
||||||
|
|
||||||
|
Currently, the only supported algorithm is 'chacha20-poly1305',
|
||||||
|
a very secure, fast and versatile authenticated encryption method.
|
||||||
|
|
||||||
|
Options is a list of:
|
||||||
|
|
||||||
|
- encoding(+Encoding)
|
||||||
|
Encoding to use for PlainText. The default is utf8. The
|
||||||
|
alternative is octet, which is used if the data are raw bytes.
|
||||||
|
|
||||||
|
- tag(+Tag)
|
||||||
|
For authenticated encryption schemes, the tag must be specified as
|
||||||
|
a list of bytes exactly as they were generated upon encryption.
|
||||||
|
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||||
|
|
||||||
|
crypto_data_decrypt(CipherText0, Algorithm, Key, IV, PlainText, Options) :-
|
||||||
|
option(tag(Tag), Options, []),
|
||||||
|
must_be_bytes(Tag, crypto_data_decrypt/6),
|
||||||
|
must_be_bytes(Key, crypto_data_decrypt/6),
|
||||||
|
must_be_bytes(IV, crypto_data_decrypt/6),
|
||||||
|
must_be(atom, Algorithm),
|
||||||
|
option(encoding(Encoding), Options, utf8),
|
||||||
|
must_be(atom, Encoding),
|
||||||
|
member(Encoding, [utf8,octet]),
|
||||||
|
must_be(list, CipherText0),
|
||||||
|
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, octet, Key, IV, Encoding, PlainText).
|
||||||
|
|
||||||
|
|
||||||
|
encoding_chars(octet, Bs, Cs) :-
|
||||||
|
must_be(list, Bs),
|
||||||
|
( maplist(integer, Bs) ->
|
||||||
|
maplist(char_code, Cs, Bs)
|
||||||
|
; Bs = Cs
|
||||||
|
),
|
||||||
|
must_be_byte_chars(Cs, crypto_encoding).
|
||||||
|
encoding_chars(utf8, Cs, Cs) :-
|
||||||
|
must_be(list, Cs),
|
||||||
|
maplist(must_be(character), Cs).
|
||||||
|
|
||||||
|
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
Digital signatures with Ed25519
|
||||||
|
===============================
|
||||||
|
|
||||||
|
- ed25519_new_keypair(-Pair)
|
||||||
|
Yields a new Ed25519 key pair Pair, a list of characters. The
|
||||||
|
pair contains the private key and must be kept absolutely secret.
|
||||||
|
Pair can be used for signing. Its public key can be obtained
|
||||||
|
with ed25519_keypair_public_key/2.
|
||||||
|
|
||||||
|
- ed25519_keypair_public_key(+Pair, -PublicKey)
|
||||||
|
PublicKey is the public key of the given key pair. The public key
|
||||||
|
can be used for signature verification, and can be shared freely.
|
||||||
|
The public key is represented as a list of characters.
|
||||||
|
|
||||||
|
- ed25519_sign(+Key, +Data, -Signature, +Options)
|
||||||
|
Key and Data must be lists of characters. Key is a key pair in
|
||||||
|
PKCS#8 v2 format as generated by ed25519_new_keypair/1. Sign Data
|
||||||
|
with Key, yielding Signature as a list of hexadecimal characters.
|
||||||
|
|
||||||
|
- ed25519_verify(+Key, +Data, +Signature, +Options)
|
||||||
|
Key and Data must be lists of characters. Key is a public key.
|
||||||
|
Succeeds if Data was signed with the private key corresponding to
|
||||||
|
Key, where Signature is a list of hexadecimal characters as
|
||||||
|
generated by ed25519_sign/4. Fails otherwise.
|
||||||
|
|
||||||
|
Currently, the only option for signing and verifying is:
|
||||||
|
|
||||||
|
- encoding(+Encoding)
|
||||||
|
The default encoding of Data is utf8. The alternative is octet,
|
||||||
|
which treats Data as a list of raw bytes.
|
||||||
|
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||||
|
|
||||||
|
ed25519_new_keypair(Pair) :-
|
||||||
|
'$ed25519_new_keypair'(Pair).
|
||||||
|
|
||||||
|
ed25519_keypair_public_key(Pair, PublicKey) :-
|
||||||
|
must_be_byte_chars(Pair, ed25519_keypair_public_key),
|
||||||
|
'$ed25519_keypair_public_key'(Pair, octet, PublicKey).
|
||||||
|
|
||||||
|
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(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, octet, Data, Encoding, Signature).
|
||||||
|
|
||||||
|
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
X25519: ECDH key exchange over Curve25519
|
||||||
|
=========================================
|
||||||
|
|
||||||
|
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.
|
||||||
|
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||||
|
|
||||||
|
curve25519_generator(Gs) :-
|
||||||
|
length(Gs0, 32),
|
||||||
|
Gs0 = [9|Zs],
|
||||||
|
maplist(=(0), Zs),
|
||||||
|
maplist(char_code, Gs, Gs0).
|
||||||
|
|
||||||
|
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).
|
||||||
|
|
||||||
|
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
|
||||||
|
=============================
|
||||||
|
|
||||||
|
Sample use: Establishing a shared secret S, using ECDH key exchange.
|
||||||
|
|
||||||
|
?- crypto_name_curve(secp256k1, C),
|
||||||
|
crypto_curve_generator(C, Generator),
|
||||||
|
PrivateKey = 10,
|
||||||
|
crypto_curve_scalar_mult(C, PrivateKey, Generator, PublicKey),
|
||||||
|
Random = 12,
|
||||||
|
crypto_curve_scalar_mult(C, Random, Generator, R),
|
||||||
|
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(Name,P,A,B,point(X,Y),Order,FieldLength,Cofactor).
|
||||||
|
|
||||||
|
First, we define suitable accessors.
|
||||||
|
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||||
|
|
||||||
|
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_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).
|
||||||
|
|
||||||
|
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
?- crypto_name_curve(secp256k1, Curve),
|
||||||
|
crypto_curve_generator(Curve, G),
|
||||||
|
crypto_curve_scalar_mult(Curve, 2, G, R).
|
||||||
|
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||||
|
|
||||||
|
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
Validation.
|
||||||
|
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||||
|
|
||||||
|
curve_contains_point(Curve, point(QX,QY)) :-
|
||||||
|
curve_a(Curve, A),
|
||||||
|
curve_b(Curve, B),
|
||||||
|
curve_p(Curve, P),
|
||||||
|
QY^2 mod P #= (QX^3 + A*QX + B) mod P.
|
||||||
|
|
||||||
|
must_be_on_curve(Curve, P) :-
|
||||||
|
\+ curve_contains_point(Curve, P),
|
||||||
|
domain_error(point_on_curve, P, crypto_elliptic_curves).
|
||||||
|
must_be_on_curve(Curve, P) :- curve_contains_point(Curve, P).
|
||||||
|
|
||||||
|
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
Predefined curves
|
||||||
|
=================
|
||||||
|
|
||||||
|
List available curves:
|
||||||
|
|
||||||
|
$ openssl ecparam -list_curves
|
||||||
|
|
||||||
|
Show curve parameters for secp256k1:
|
||||||
|
|
||||||
|
$ openssl ecparam -param_enc explicit -conv_form uncompressed \
|
||||||
|
-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(secp112r1,
|
||||||
|
0x00db7c2abf62e35e668076bead208b,
|
||||||
|
0x00db7c2abf62e35e668076bead2088,
|
||||||
|
0x659ef8ba043916eede8911702b22,
|
||||||
|
point(0x09487239995a5ee76b55f9c2f098,
|
||||||
|
0xa89ce5af8724c0a23e0e0ff77500),
|
||||||
|
0x00db7c2abf62e35e7628dfac6561c5,
|
||||||
|
14,
|
||||||
|
1)).
|
||||||
|
crypto_name_curve(secp256k1,
|
||||||
|
curve(secp256k1,
|
||||||
|
0x00fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f,
|
||||||
|
0x0,
|
||||||
|
0x7,
|
||||||
|
point(0x79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798,
|
||||||
|
0x483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8),
|
||||||
|
0x00fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141,
|
||||||
|
32,
|
||||||
|
1)).
|
||||||
238
src/lib/csv.pl
Normal file
238
src/lib/csv.pl
Normal 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, []).
|
||||||
@@ -1,14 +1,11 @@
|
|||||||
% :- op(1105, xfy, ('|')).
|
:- module(dcgs,
|
||||||
|
[op(1105, xfy, '|'),
|
||||||
:- module(dcgs, [op(1200, xfx, -->), phrase/2, phrase/3]).
|
phrase/2,
|
||||||
|
phrase/3]).
|
||||||
|
|
||||||
|
:- use_module(library(error)).
|
||||||
:- use_module(library(lists), [append/3]).
|
:- use_module(library(lists), [append/3]).
|
||||||
|
|
||||||
user:term_expansion(Term0, Term) :-
|
|
||||||
nonvar(Term0),
|
|
||||||
dcg_rule(Term0, (Head :- Body)),
|
|
||||||
Term = (Head :- Body).
|
|
||||||
|
|
||||||
phrase(GRBody, S0) :-
|
phrase(GRBody, S0) :-
|
||||||
phrase(GRBody, S0, []).
|
phrase(GRBody, S0, []).
|
||||||
|
|
||||||
@@ -31,8 +28,8 @@ phrase_((A -> B ; C), S0, S) :-
|
|||||||
).
|
).
|
||||||
phrase_((A ; B), S0, S) :-
|
phrase_((A ; B), S0, S) :-
|
||||||
( phrase(A, S0, S) ; phrase(B, S0, S) ).
|
( phrase(A, S0, S) ; phrase(B, S0, S) ).
|
||||||
%% phrase_((A | B), S0, S) :-
|
phrase_((A | B), S0, S) :-
|
||||||
%% ( phrase(A, S0, S) ; phrase(B, S0, S) ).
|
( phrase(A, S0, S) ; phrase(B, S0, S) ).
|
||||||
phrase_({G}, S0, S) :-
|
phrase_({G}, S0, S) :-
|
||||||
( call(G), S0 = S ).
|
( call(G), S0 = S ).
|
||||||
phrase_(call(G), S0, S) :-
|
phrase_(call(G), S0, S) :-
|
||||||
@@ -95,7 +92,7 @@ dcg_constr([]). % 7.14.1
|
|||||||
dcg_constr([_|_]). % 7.14.2 - terminal sequence
|
dcg_constr([_|_]). % 7.14.2 - terminal sequence
|
||||||
dcg_constr(( _, _ )). % 7.14.3 - concatenation
|
dcg_constr(( _, _ )). % 7.14.3 - concatenation
|
||||||
dcg_constr(( _ ; _ )). % 7.14.4 - alternative
|
dcg_constr(( _ ; _ )). % 7.14.4 - alternative
|
||||||
%% dcg_constr(( _'|'_ )). % 7.14.6 - alternative
|
dcg_constr(( _'|'_ )). % 7.14.6 - alternative
|
||||||
dcg_constr({_}). % 7.14.7
|
dcg_constr({_}). % 7.14.7
|
||||||
dcg_constr(call(_)). % 7.14.8
|
dcg_constr(call(_)). % 7.14.8
|
||||||
dcg_constr(phrase(_)). % 7.14.9
|
dcg_constr(phrase(_)). % 7.14.9
|
||||||
@@ -107,6 +104,7 @@ dcg_constr((_->_)). % 7.14.12 - if-then (existence implementation dep.)
|
|||||||
% the construct to be expanded.
|
% the construct to be expanded.
|
||||||
dcg_cbody([], S0, S, S0 = S).
|
dcg_cbody([], S0, S, S0 = S).
|
||||||
dcg_cbody([T|Ts], S0, S, Goal) :-
|
dcg_cbody([T|Ts], S0, S, Goal) :-
|
||||||
|
must_be(list, [T|Ts]),
|
||||||
dcg_terminals([T|Ts], S0, S, Goal).
|
dcg_terminals([T|Ts], S0, S, Goal).
|
||||||
dcg_cbody(( GRFirst, GRSecond ), S0, S, ( First, Second )) :-
|
dcg_cbody(( GRFirst, GRSecond ), S0, S, ( First, Second )) :-
|
||||||
dcg_body(GRFirst, S0, S1, First),
|
dcg_body(GRFirst, S0, S1, First),
|
||||||
@@ -119,9 +117,9 @@ dcg_cbody(( GRCond ; GRElse ), S0, S, ( Cond ; Else )) :-
|
|||||||
subsumes_term(( _GRIf -> _GRThen ), GRCond),
|
subsumes_term(( _GRIf -> _GRThen ), GRCond),
|
||||||
dcg_cbody(GRCond, S0, S, Cond),
|
dcg_cbody(GRCond, S0, S, Cond),
|
||||||
dcg_body(GRElse, S0, S, Else).
|
dcg_body(GRElse, S0, S, Else).
|
||||||
%% dcg_cbody(( GREither '|' GROr ), S0, S, ( Either ; Or )) :-
|
dcg_cbody(( GREither '|' GROr ), S0, S, ( Either ; Or )) :-
|
||||||
%% dcg_body(GREither, S0, S, Either),
|
dcg_body(GREither, S0, S, Either),
|
||||||
%% dcg_body(GROr, S0, S, Or).
|
dcg_body(GROr, S0, S, Or).
|
||||||
dcg_cbody({Goal}, S0, S, ( Goal, S0 = S )).
|
dcg_cbody({Goal}, S0, S, ( Goal, S0 = S )).
|
||||||
dcg_cbody(call(Cont), S0, S, call(Cont, S0, S)).
|
dcg_cbody(call(Cont), S0, S, call(Cont, S0, S)).
|
||||||
dcg_cbody(phrase(Body), S0, S, phrase(Body, S0, S)).
|
dcg_cbody(phrase(Body), S0, S, phrase(Body, S0, S)).
|
||||||
@@ -130,3 +128,8 @@ dcg_cbody(\+ GRBody, S0, S, ( \+ phrase(GRBody,S0,_), S0 = S )).
|
|||||||
dcg_cbody(( GRIf -> GRThen ), S0, S, ( If -> Then )) :-
|
dcg_cbody(( GRIf -> GRThen ), S0, S, ( If -> Then )) :-
|
||||||
dcg_body(GRIf, S0, S1, If),
|
dcg_body(GRIf, S0, S1, If),
|
||||||
dcg_body(GRThen, S1, S, Then).
|
dcg_body(GRThen, S1, S, Then).
|
||||||
|
|
||||||
|
user:term_expansion(Term0, Term) :-
|
||||||
|
nonvar(Term0),
|
||||||
|
dcg_rule(Term0, (Head :- Body)),
|
||||||
|
Term = (Head :- Body).
|
||||||
22
src/lib/debug.pl
Normal file
22
src/lib/debug.pl
Normal 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).
|
||||||
|
|
||||||
|
*(_).
|
||||||
@@ -1,5 +1,9 @@
|
|||||||
:- module(error, [must_be/2,
|
:- module(error, [must_be/2,
|
||||||
can_be/2]).
|
can_be/2,
|
||||||
|
instantiation_error/1,
|
||||||
|
domain_error/3,
|
||||||
|
type_error/3
|
||||||
|
]).
|
||||||
|
|
||||||
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
Written September 2018 by Markus Triska (triska@metalevel.at)
|
Written September 2018 by Markus Triska (triska@metalevel.at)
|
||||||
@@ -23,7 +27,8 @@
|
|||||||
|
|
||||||
- integer
|
- integer
|
||||||
- atom
|
- atom
|
||||||
- list.
|
- list
|
||||||
|
- boolean
|
||||||
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||||
|
|
||||||
must_be(Type, Term) :-
|
must_be(Type, Term) :-
|
||||||
@@ -32,31 +37,41 @@ must_be(Type, Term) :-
|
|||||||
|
|
||||||
must_be_(Type, _) :-
|
must_be_(Type, _) :-
|
||||||
var(Type),
|
var(Type),
|
||||||
instantiation_error(Type).
|
instantiation_error(must_be/2).
|
||||||
must_be_(var, Term) :-
|
must_be_(var, Term) :-
|
||||||
( var(Term) -> true
|
( var(Term) -> true
|
||||||
; throw(error(uninstantiation_error, _))
|
; throw(error(uninstantiation_error, must_be/2))
|
||||||
).
|
).
|
||||||
must_be_(integer, Term) :- check_(integer, integer, Term).
|
must_be_(integer, Term) :- check_(integer, integer, Term).
|
||||||
must_be_(atom, Term) :- check_(atom, atom, 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_(list, Term) :- check_(ilist, list, Term).
|
||||||
must_be_(type, Term) :- check_(type, type, Term).
|
must_be_(type, Term) :- check_(type, type, Term).
|
||||||
|
must_be_(boolean, Term) :- check_(boolean, boolean, Term).
|
||||||
|
|
||||||
check_(Pred, Type, Term) :-
|
check_(Pred, Type, Term) :-
|
||||||
( var(Term) -> instantiation_error(Term)
|
( var(Term) -> instantiation_error(must_be/2)
|
||||||
; call(Pred, Term) -> true
|
; call(Pred, Term) -> true
|
||||||
; type_error(Type, Term)
|
; type_error(Type, Term, must_be/2)
|
||||||
).
|
).
|
||||||
|
|
||||||
ilist(V) :- var(V), instantiation_error(V).
|
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([]).
|
||||||
ilist([_|Ls]) :- ilist(Ls).
|
ilist([_|Ls]) :- ilist(Ls).
|
||||||
|
|
||||||
type(type).
|
type(type).
|
||||||
type(integer).
|
type(integer).
|
||||||
type(atom).
|
type(atom).
|
||||||
|
type(character).
|
||||||
type(list).
|
type(list).
|
||||||
type(var).
|
type(var).
|
||||||
|
type(boolean).
|
||||||
|
|
||||||
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
can_be(Type, Term)
|
can_be(Type, Term)
|
||||||
@@ -76,12 +91,14 @@ can_be(Type, Term) :-
|
|||||||
must_be(type, Type),
|
must_be(type, Type),
|
||||||
( var(Term) -> true
|
( var(Term) -> true
|
||||||
; can_(Type, Term) -> true
|
; can_(Type, Term) -> true
|
||||||
; type_error(Type, Term)
|
; type_error(Type, Term, can_be/2)
|
||||||
).
|
).
|
||||||
|
|
||||||
can_(integer, Term) :- integer(Term).
|
can_(integer, Term) :- integer(Term).
|
||||||
can_(atom, Term) :- atom(Term).
|
can_(atom, Term) :- atom(Term).
|
||||||
|
can_(character, T) :- character(T).
|
||||||
can_(list, Term) :- list_or_partial_list(Term).
|
can_(list, Term) :- list_or_partial_list(Term).
|
||||||
|
can_(boolean, Term) :- boolean(Term).
|
||||||
|
|
||||||
list_or_partial_list(Var) :- var(Var).
|
list_or_partial_list(Var) :- var(Var).
|
||||||
list_or_partial_list([]).
|
list_or_partial_list([]).
|
||||||
@@ -92,11 +109,11 @@ list_or_partial_list([_|Ls]) :-
|
|||||||
Shorthands for throwing ISO errors.
|
Shorthands for throwing ISO errors.
|
||||||
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||||
|
|
||||||
instantiation_error(_Term) :-
|
instantiation_error(Context) :-
|
||||||
throw(error(instantiation_error, _)).
|
throw(error(instantiation_error, Context)).
|
||||||
|
|
||||||
domain_error(Type, Term) :-
|
domain_error(Type, Term, Context) :-
|
||||||
throw(error(domain_error(Type, Term), _)).
|
throw(error(domain_error(Type, Term), Context)).
|
||||||
|
|
||||||
type_error(Type, Term) :-
|
type_error(Type, Term, Context) :-
|
||||||
throw(error(type_error(Type, Term), _)).
|
throw(error(type_error(Type, Term), Context)).
|
||||||
200
src/lib/files.pl
Normal file
200
src/lib/files.pl
Normal 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]
|
||||||
|
).
|
||||||
580
src/lib/format.pl
Normal file
580
src/lib/format.pl
Normal file
@@ -0,0 +1,580 @@
|
|||||||
|
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
Written March 2020 by Markus Triska (triska@metalevel.at)
|
||||||
|
Part of Scryer Prolog.
|
||||||
|
|
||||||
|
This library provides the nonterminal format_//2 to describe
|
||||||
|
formatted strings. format/[2,3] are provided for impure output.
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
======
|
||||||
|
|
||||||
|
phrase(format_(FormatString, Arguments), Ls)
|
||||||
|
|
||||||
|
format_//2 describes a list of characters Ls that are formatted
|
||||||
|
according to FormatString. FormatString is a string (i.e.,
|
||||||
|
a list of characters) that specifies the layout of Ls.
|
||||||
|
The characters in FormatString are used literally, except
|
||||||
|
for the following tokens with special meaning:
|
||||||
|
|
||||||
|
~w use the next available argument from Arguments here
|
||||||
|
~q use the next argument here, formatted as by writeq/1
|
||||||
|
~a use the next argument here, which must be an atom
|
||||||
|
~s use the next argument here, which must be a string
|
||||||
|
~d use the next argument here, which must be an integer
|
||||||
|
~f use the next argument here, a floating point number
|
||||||
|
~Nf where N is an integer: format the float argument
|
||||||
|
using N digits after the decimal point
|
||||||
|
~Nd like ~d, placing the last N digits after a decimal point;
|
||||||
|
if N is 0 or omitted, no decimal point is used.
|
||||||
|
~ND like ~Nd, separating digits to the left of the decimal point
|
||||||
|
in groups of three, using the character "," (comma)
|
||||||
|
~Nr where N is an integer between 2 and 36: format the
|
||||||
|
next argument, which must be an integer, in radix N.
|
||||||
|
The characters "a" to "z" are used for radices 10 to 36.
|
||||||
|
~NR like ~Nr, except that "A" to "Z" are used for radices > 9
|
||||||
|
~| place a tab stop at this position
|
||||||
|
~N| where N is an integer: place a tab stop at text column N
|
||||||
|
~N+ where N is an integer: place a tab stop N characters
|
||||||
|
after the previous tab stop (or start of line)
|
||||||
|
~t distribute spaces evenly between the two closest tab stops
|
||||||
|
~`Ct like ~t, use character C instead of spaces to fill the space
|
||||||
|
~n newline
|
||||||
|
~Nn N newlines
|
||||||
|
~i ignore the next argument
|
||||||
|
~~ the literal ~
|
||||||
|
|
||||||
|
Instead of ~N, you can write ~* to use the next argument from Arguments
|
||||||
|
as the numeric argument.
|
||||||
|
|
||||||
|
The predicate format/2 is like format_//2, except that it outputs
|
||||||
|
the text on the terminal instead of describing it declaratively.
|
||||||
|
|
||||||
|
format/3, used as format(Stream, FormatString, Arguments), outputs
|
||||||
|
the described string to the given Stream. If Stream is a binary
|
||||||
|
stream, then the code of each emitted character must be in 0..255.
|
||||||
|
|
||||||
|
If at all possible, format_//2 should be used, to stress pure parts
|
||||||
|
that enable easy testing etc. If necessary, you can emit the list Ls
|
||||||
|
with maplist(write, Ls).
|
||||||
|
|
||||||
|
The entire library only works if the Prolog flag double_quotes
|
||||||
|
is set to chars, the default value in Scryer Prolog. This should
|
||||||
|
also stay that way, to encourage a sensible environment.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
?- phrase(format_("~s~n~`.t~w!~12|", ["hello",there]), Cs).
|
||||||
|
%@ Cs = "hello\n......there!"
|
||||||
|
%@ ; false.
|
||||||
|
|
||||||
|
I place this code in the public domain. Use it in any way you want.
|
||||||
|
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||||
|
|
||||||
|
:- module(format, [format_//2,
|
||||||
|
format/2,
|
||||||
|
format/3,
|
||||||
|
portray_clause/1,
|
||||||
|
portray_clause/2,
|
||||||
|
listing/1
|
||||||
|
]).
|
||||||
|
|
||||||
|
:- use_module(library(dcgs)).
|
||||||
|
:- use_module(library(lists)).
|
||||||
|
:- use_module(library(error)).
|
||||||
|
:- use_module(library(charsio)).
|
||||||
|
:- use_module(library(between)).
|
||||||
|
|
||||||
|
format_(Fs, Args) -->
|
||||||
|
{ must_be(list, Fs),
|
||||||
|
must_be(list, Args),
|
||||||
|
phrase(cells(Fs,Args,0,[]), Cells) },
|
||||||
|
format_cells(Cells).
|
||||||
|
|
||||||
|
format_cells([]) --> [].
|
||||||
|
format_cells([Cell|Cells]) -->
|
||||||
|
format_cell(Cell),
|
||||||
|
format_cells(Cells).
|
||||||
|
|
||||||
|
format_cell(newline) --> "\n".
|
||||||
|
format_cell(cell(From,To,Es)) -->
|
||||||
|
% distribute the space between the glue elements
|
||||||
|
{ phrase(elements_gluevars(Es, 0, Length), Vs),
|
||||||
|
( Vs = [] -> true
|
||||||
|
; Space is To - From - Length,
|
||||||
|
( Space =< 0 -> maplist(=(0), Vs)
|
||||||
|
; length(Vs, NumGlue),
|
||||||
|
Distr is Space // NumGlue,
|
||||||
|
Delta is Space - Distr*NumGlue,
|
||||||
|
( Delta =:= 0 ->
|
||||||
|
maplist(=(Distr), Vs)
|
||||||
|
; BigGlue is Distr + Delta,
|
||||||
|
reverse(Vs, [BigGlue|Rest]),
|
||||||
|
maplist(=(Distr), Rest)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
) },
|
||||||
|
format_elements(Es).
|
||||||
|
|
||||||
|
format_elements([]) --> [].
|
||||||
|
format_elements([E|Es]) -->
|
||||||
|
format_element(E),
|
||||||
|
format_elements(Es).
|
||||||
|
|
||||||
|
format_element(chars(Cs)) --> list(Cs).
|
||||||
|
format_element(glue(Fill,Num)) -->
|
||||||
|
{ length(Ls, Num),
|
||||||
|
maplist(=(Fill), Ls) },
|
||||||
|
list(Ls).
|
||||||
|
|
||||||
|
list([]) --> [].
|
||||||
|
list([L|Ls]) --> [L], list(Ls).
|
||||||
|
|
||||||
|
elements_gluevars([], N, N) --> [].
|
||||||
|
elements_gluevars([E|Es], N0, N) -->
|
||||||
|
element_gluevar(E, N0, N1),
|
||||||
|
elements_gluevars(Es, N1, N).
|
||||||
|
|
||||||
|
element_gluevar(chars(Cs), N0, N) -->
|
||||||
|
{ length(Cs, L),
|
||||||
|
N is N0 + L }.
|
||||||
|
element_gluevar(glue(_,V), N, N) --> [V].
|
||||||
|
|
||||||
|
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
Our key datastructure is a list of cells and newlines.
|
||||||
|
A cell has the shape from_to(From,To,Elements), where
|
||||||
|
From and To denote the positions of surrounding tab stops.
|
||||||
|
|
||||||
|
Elements is a list of elements that occur in a cell,
|
||||||
|
namely terms of the form chars(Cs) and glue(Char, Var).
|
||||||
|
"glue" elements (TeX terminology) are evenly stretched
|
||||||
|
to fill the remaining whitespace in the cell. For each
|
||||||
|
glue element, the character Char is used for filling,
|
||||||
|
and Var is a free variable that is used when the
|
||||||
|
available space is distributed.
|
||||||
|
|
||||||
|
newline is used if ~n occurs in a format string.
|
||||||
|
It is is used because a newline character does not
|
||||||
|
consume whitespace in the sense of format strings.
|
||||||
|
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||||
|
|
||||||
|
cells([], Args, Tab, Es) -->
|
||||||
|
( { Args == [] } -> cell(Tab, Tab, Es)
|
||||||
|
; { domain_error(empty_list, Args, format_//2) }
|
||||||
|
).
|
||||||
|
cells([~,~|Fs], Args, Tab, Es) --> !,
|
||||||
|
cells(Fs, Args, Tab, [chars("~")|Es]).
|
||||||
|
cells([~,w|Fs], [Arg|Args], Tab, Es) --> !,
|
||||||
|
{ write_term_to_chars(Arg, [], Chars) },
|
||||||
|
cells(Fs, Args, Tab, [chars(Chars)|Es]).
|
||||||
|
cells([~,q|Fs], [Arg|Args], Tab, Es) --> !,
|
||||||
|
{ write_term_to_chars(Arg, [quoted(true)], Chars) },
|
||||||
|
cells(Fs, Args, Tab, [chars(Chars)|Es]).
|
||||||
|
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, [Arg0|Args]) },
|
||||||
|
!,
|
||||||
|
{ Arg is Arg0, % evaluate compound expression
|
||||||
|
must_be(integer, Arg),
|
||||||
|
number_chars(Arg, Cs0) },
|
||||||
|
( { Num =:= 0 } -> { Cs = Cs0 }
|
||||||
|
; { length(Cs0, L),
|
||||||
|
( L =< Num ->
|
||||||
|
Delta is Num - L,
|
||||||
|
length(Zs, Delta),
|
||||||
|
maplist(=('0'), Zs),
|
||||||
|
phrase(("0.",list(Zs),list(Cs0)), Cs)
|
||||||
|
; BeforeComma is L - Num,
|
||||||
|
length(Bs, BeforeComma),
|
||||||
|
append(Bs, Ds, Cs0),
|
||||||
|
phrase((list(Bs),".",list(Ds)), Cs)
|
||||||
|
) }
|
||||||
|
),
|
||||||
|
cells(Fs, Args, Tab, [chars(Cs)|Es]).
|
||||||
|
cells([~|Fs0], Args0, Tab, Es) -->
|
||||||
|
{ numeric_argument(Fs0, Num, ['D'|Fs], Args0, [Arg|Args]) },
|
||||||
|
!,
|
||||||
|
{ number_chars(Num, NCs),
|
||||||
|
phrase(("~",list(NCs),"d"), FStr),
|
||||||
|
phrase(format_(FStr, [Arg]), Cs0),
|
||||||
|
phrase(upto_what(Bs0, .), Cs0, Ds),
|
||||||
|
reverse(Bs0, Bs1),
|
||||||
|
phrase(groups_of_three(Bs1), Bs2),
|
||||||
|
reverse(Bs2, Bs),
|
||||||
|
append(Bs, Ds, Cs) },
|
||||||
|
cells(Fs, Args, Tab, [chars(Cs)|Es]).
|
||||||
|
cells([~,i|Fs], [_|Args], Tab, Es) --> !,
|
||||||
|
cells(Fs, Args, Tab, Es).
|
||||||
|
cells([~,n|Fs], Args, Tab, Es) --> !,
|
||||||
|
cell(Tab, Tab, Es),
|
||||||
|
n_newlines(1),
|
||||||
|
cells(Fs, Args, 0, []).
|
||||||
|
cells([~|Fs0], Args0, Tab, Es) -->
|
||||||
|
{ numeric_argument(Fs0, Num, [n|Fs], Args0, Args) },
|
||||||
|
!,
|
||||||
|
cell(Tab, Tab, Es),
|
||||||
|
n_newlines(Num),
|
||||||
|
cells(Fs, Args, 0, []).
|
||||||
|
cells([~,s|Fs], [Arg|Args], Tab, Es) --> !,
|
||||||
|
cells(Fs, Args, Tab, [chars(Arg)|Es]).
|
||||||
|
cells([~,f|Fs], [Arg|Args], Tab, Es) --> !,
|
||||||
|
{ 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]) },
|
||||||
|
!,
|
||||||
|
{ format_number_chars(Arg, Cs0),
|
||||||
|
phrase(upto_what(Bs, .), Cs0, Cs),
|
||||||
|
( Num =:= 0 -> Chars = Bs
|
||||||
|
; ( Cs = ['.'|Rest] ->
|
||||||
|
length(Rest, L),
|
||||||
|
( Num < L ->
|
||||||
|
length(Ds, Num),
|
||||||
|
append(Ds, _, Rest)
|
||||||
|
; Num =:= L ->
|
||||||
|
Ds = Rest
|
||||||
|
; Num > L,
|
||||||
|
Delta is Num - L,
|
||||||
|
% we should look into the float with
|
||||||
|
% greater accuracy here, and use the
|
||||||
|
% actual digits instead of 0.
|
||||||
|
length(Zs, Delta),
|
||||||
|
maplist(=('0'), Zs),
|
||||||
|
append(Rest, Zs, Ds)
|
||||||
|
)
|
||||||
|
; length(Ds, Num),
|
||||||
|
maplist(=('0'), Ds)
|
||||||
|
),
|
||||||
|
append(Bs, ['.'|Ds], Chars)
|
||||||
|
) },
|
||||||
|
cells(Fs, Args, Tab, [chars(Chars)|Es]).
|
||||||
|
cells([~|Fs0], Args0, Tab, Es) -->
|
||||||
|
{ numeric_argument(Fs0, Num, [r|Fs], Args0, [Arg|Args]) },
|
||||||
|
!,
|
||||||
|
{ integer_to_radix(Arg, Num, lowercase, Cs) },
|
||||||
|
cells(Fs, Args, Tab, [chars(Cs)|Es]).
|
||||||
|
cells([~|Fs0], Args0, Tab, Es) -->
|
||||||
|
{ numeric_argument(Fs0, Num, ['R'|Fs], Args0, [Arg|Args]) },
|
||||||
|
!,
|
||||||
|
{ integer_to_radix(Arg, Num, uppercase, Cs) },
|
||||||
|
cells(Fs, Args, Tab, [chars(Cs)|Es]).
|
||||||
|
cells([~,'`',Char,t|Fs], Args, Tab, Es) --> !,
|
||||||
|
cells(Fs, Args, Tab, [glue(Char,_)|Es]).
|
||||||
|
cells([~,t|Fs], Args, Tab, Es) --> !,
|
||||||
|
cells(Fs, Args, Tab, [glue(' ',_)|Es]).
|
||||||
|
cells([~|Fs0], Args0, Tab, Es) -->
|
||||||
|
{ numeric_argument(Fs0, Num, ['|'|Fs], Args0, Args) },
|
||||||
|
!,
|
||||||
|
cell(Tab, Num, Es),
|
||||||
|
cells(Fs, Args, Num, []).
|
||||||
|
cells([~|Fs0], Args0, Tab0, Es) -->
|
||||||
|
{ numeric_argument(Fs0, Num, [+|Fs], Args0, Args) },
|
||||||
|
!,
|
||||||
|
{ Tab is Tab0 + Num },
|
||||||
|
cell(Tab0, Tab, Es),
|
||||||
|
cells(Fs, Args, Tab, []).
|
||||||
|
cells([~,C|_], _, _, _) -->
|
||||||
|
{ atom_chars(A, [~,C]),
|
||||||
|
domain_error(format_string, A, format_//2) }.
|
||||||
|
cells(Fs0, Args, Tab, Es) -->
|
||||||
|
{ phrase(upto_what(Fs1, ~), Fs0, Fs),
|
||||||
|
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).
|
||||||
|
|
||||||
|
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
?- phrase(upto_what(Cs, ~), "abc~test", Rest).
|
||||||
|
Cs = [a,b,c], Rest = [~,t,e,s,t].
|
||||||
|
?- phrase(upto_what(Cs, ~), "abc", Rest).
|
||||||
|
Cs = [a,b,c], Rest = [].
|
||||||
|
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||||
|
|
||||||
|
upto_what([], W), [W] --> [W], !.
|
||||||
|
upto_what([C|Cs], W) --> [C], !, upto_what(Cs, W).
|
||||||
|
upto_what([], _) --> [].
|
||||||
|
|
||||||
|
groups_of_three([A,B,C,D|Rs]) --> !, [A,B,C], ",", groups_of_three([D|Rs]).
|
||||||
|
groups_of_three(Ls) --> list(Ls).
|
||||||
|
|
||||||
|
cell(From, To, Es0) -->
|
||||||
|
( { Es0 == [] } -> []
|
||||||
|
; { reverse(Es0, Es) },
|
||||||
|
[cell(From,To,Es)]
|
||||||
|
).
|
||||||
|
|
||||||
|
%?- numeric_argument("2f", Num, ['f'|Fs], Args0, Args).
|
||||||
|
|
||||||
|
%?- numeric_argument("100b", Num, Rs, Args0, Args).
|
||||||
|
|
||||||
|
numeric_argument(Ds, Num, Rest, Args0, Args) :-
|
||||||
|
( Ds = [*|Rest] ->
|
||||||
|
Args0 = [Num|Args]
|
||||||
|
; numeric_argument_(Ds, [], Ns, Rest),
|
||||||
|
foldl(pow10, Ns, 0-0, Num-_),
|
||||||
|
Args0 = Args
|
||||||
|
).
|
||||||
|
|
||||||
|
numeric_argument_([D|Ds], Ns0, Ns, Rest) :-
|
||||||
|
( member(D, "0123456789") ->
|
||||||
|
number_chars(N, [D]),
|
||||||
|
numeric_argument_(Ds, [N|Ns0], Ns, Rest)
|
||||||
|
; Ns = Ns0,
|
||||||
|
Rest = [D|Ds]
|
||||||
|
).
|
||||||
|
|
||||||
|
|
||||||
|
pow10(D, N0-Pow0, N-Pow) :-
|
||||||
|
N is N0 + D*10^Pow0,
|
||||||
|
Pow is Pow0 + 1.
|
||||||
|
|
||||||
|
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) ->
|
||||||
|
domain_error(radix, R, format_//2)
|
||||||
|
; true
|
||||||
|
),
|
||||||
|
digits(Which, Ds),
|
||||||
|
( I < 0 ->
|
||||||
|
Pos is abs(I),
|
||||||
|
phrase(integer_to_radix_(Pos, R, Ds), Cs0, "-")
|
||||||
|
; I =:= 0 -> Cs0 = "0"
|
||||||
|
; phrase(integer_to_radix_(I, R, Ds), Cs0)
|
||||||
|
),
|
||||||
|
reverse(Cs0, Cs).
|
||||||
|
|
||||||
|
integer_to_radix_(0, _, _) --> !.
|
||||||
|
integer_to_radix_(I0, R, Ds) -->
|
||||||
|
{ M is I0 mod R,
|
||||||
|
nth0(M, Ds, D),
|
||||||
|
I is I0 // R
|
||||||
|
},
|
||||||
|
[D],
|
||||||
|
integer_to_radix_(I, R, Ds).
|
||||||
|
|
||||||
|
digits(lowercase, "0123456789abcdefghijklmnopqrstuvwxyz").
|
||||||
|
digits(uppercase, "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ").
|
||||||
|
|
||||||
|
|
||||||
|
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
Impure I/O, implemented as a small wrapper over format_//2.
|
||||||
|
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||||
|
|
||||||
|
format(Fs, Args) :-
|
||||||
|
current_output(Stream),
|
||||||
|
format(Stream, Fs, Args).
|
||||||
|
|
||||||
|
format(Stream, Fs, Args) :-
|
||||||
|
phrase(format_(Fs, Args), 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).
|
||||||
|
|
||||||
|
?- phrase(cells("hello~10|", [], 0, []), Cs).
|
||||||
|
?- phrase(cells("~ta~t~10|", [], 0, []), Cs).
|
||||||
|
|
||||||
|
?- phrase(format_("~`at~50|", []), Ls).
|
||||||
|
|
||||||
|
?- phrase(cells("~`at~50|", [], 0, []), Cs),
|
||||||
|
phrase(format_cells(Cs), Ls).
|
||||||
|
?- phrase(cells("~ta~t~tb~tc~21|", [], 0, []), Cs).
|
||||||
|
Cs = [cell(0,21,[glue(' ',_38),chars([a]),glue(' ',_62),glue(' ',_67),chars([b]),glue(' ',_91),chars([c])])].
|
||||||
|
?- phrase(cells("~ta~t~4|", [], 0, []), Cs).
|
||||||
|
Cs = [cell(0,4,[glue(' ',_38),chars([a]),glue(' ',_62)])].
|
||||||
|
|
||||||
|
?- phrase(format_cell(cell(0,1,[glue(a,_94)])), Ls).
|
||||||
|
|
||||||
|
?- phrase(format_cell(cell(0,50,[chars("hello")])), Ls).
|
||||||
|
|
||||||
|
?- phrase(format_("~`at~50|~n", []), Ls).
|
||||||
|
?- phrase(format_("hello~n~tthere~6|", []), Ls).
|
||||||
|
|
||||||
|
?- format("~ta~t~4|", []).
|
||||||
|
a true
|
||||||
|
; false.
|
||||||
|
|
||||||
|
?- format("~ta~tb~tc~10|", []).
|
||||||
|
a b c true
|
||||||
|
; false.
|
||||||
|
|
||||||
|
?- format("~tabc~3|", []).
|
||||||
|
|
||||||
|
?- format("~ta~t~4|", []).
|
||||||
|
|
||||||
|
?- format("~ta~t~tb~tc~20|", []).
|
||||||
|
a b c true
|
||||||
|
; false.
|
||||||
|
|
||||||
|
?- format("~2f~n", [3]).
|
||||||
|
3.00
|
||||||
|
true
|
||||||
|
|
||||||
|
?- format("~20f", [0.1]).
|
||||||
|
0.10000000000000000000 true % this should use higher accuracy!
|
||||||
|
; false.
|
||||||
|
|
||||||
|
?- X is atan(2), format("~7f~n", [X]).
|
||||||
|
1.1071487
|
||||||
|
X = 1.1071487177940906
|
||||||
|
|
||||||
|
?- format("~`at~50|~n", []).
|
||||||
|
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
||||||
|
true
|
||||||
|
|
||||||
|
?- format("~t~N", []).
|
||||||
|
|
||||||
|
?- format("~q", [.]).
|
||||||
|
'.' true
|
||||||
|
|
||||||
|
?- format("~12r", [300]).
|
||||||
|
210 true
|
||||||
|
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||||
|
|
||||||
|
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
We also provide rudimentary versions of portray_clause/1 and listing/1.
|
||||||
|
|
||||||
|
In the eventual library organization, portray_clause/1 and
|
||||||
|
related predicates may be placed in their own dedicated library.
|
||||||
|
|
||||||
|
portray_clause/1 is useful for printing solutions in such a way
|
||||||
|
that they can be read back with read/1.
|
||||||
|
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||||
|
|
||||||
|
portray_clause(Term) :-
|
||||||
|
current_output(Out),
|
||||||
|
portray_clause(Out, Term).
|
||||||
|
|
||||||
|
portray_clause(Stream, Term) :-
|
||||||
|
phrase(portray_clause_(Term), Ls),
|
||||||
|
format(Stream, "~s", [Ls]).
|
||||||
|
|
||||||
|
portray_clause_(Term) -->
|
||||||
|
{ term_variables(Term, Vs),
|
||||||
|
foldl(var_name, Vs, VNs, 0, _) },
|
||||||
|
portray_(Term, VNs), ".\n".
|
||||||
|
|
||||||
|
var_name(V, Name=V, Num0, Num) :-
|
||||||
|
charsio:fabricate_var_name(numbervars, Name, Num0),
|
||||||
|
Num is Num0 + 1.
|
||||||
|
|
||||||
|
literal(Lit, VNs) -->
|
||||||
|
{ write_term_to_chars(Lit, [quoted(true),variable_names(VNs)], Ls) },
|
||||||
|
list(Ls).
|
||||||
|
|
||||||
|
portray_(Var, VNs) --> { var(Var) }, !, literal(Var, VNs).
|
||||||
|
portray_((Head :- Body), VNs) --> !,
|
||||||
|
literal(Head, VNs), " :-\n",
|
||||||
|
body_(Body, 0, 3, VNs).
|
||||||
|
portray_((Head --> Body), VNs) --> !,
|
||||||
|
literal(Head, VNs), " -->\n",
|
||||||
|
body_(Body, 0, 3, VNs).
|
||||||
|
portray_(Any, VNs) --> literal(Any, VNs).
|
||||||
|
|
||||||
|
|
||||||
|
body_(Var, C, I, VNs) --> { var(Var) }, !,
|
||||||
|
indent_to(C, I),
|
||||||
|
literal(Var, VNs).
|
||||||
|
body_((A,B), C, I, VNs) --> !,
|
||||||
|
body_(A, C, I, VNs), ",\n",
|
||||||
|
body_(B, 0, I, VNs).
|
||||||
|
body_((A ; Else), C, I, VNs) --> % ( If -> Then ; Else )
|
||||||
|
{ nonvar(A), A = (If -> Then) },
|
||||||
|
!,
|
||||||
|
indent_to(C, I),
|
||||||
|
"( ",
|
||||||
|
{ C1 is I + 3 },
|
||||||
|
body_(If, C1, C1, VNs), " ->\n",
|
||||||
|
body_(Then, 0, C1, VNs), "\n",
|
||||||
|
else_branch(Else, C1, I, VNs).
|
||||||
|
body_((A;B), C, I, VNs) --> !,
|
||||||
|
indent_to(C, I),
|
||||||
|
"( ",
|
||||||
|
{ C1 is I + 3 },
|
||||||
|
body_(A, C1, C1, VNs), "\n",
|
||||||
|
else_branch(B, C1, I, VNs).
|
||||||
|
body_(Goal, C, I, VNs) -->
|
||||||
|
indent_to(C, I), literal(Goal, VNs).
|
||||||
|
|
||||||
|
|
||||||
|
else_branch(Else, C, I, VNs) -->
|
||||||
|
indent_to(0, I),
|
||||||
|
"; ",
|
||||||
|
body_(Else, C, C, VNs), "\n",
|
||||||
|
indent_to(0, I),
|
||||||
|
")".
|
||||||
|
|
||||||
|
indent_to(CurrentColumn, Indent) -->
|
||||||
|
{ Delta is Indent - CurrentColumn },
|
||||||
|
format_("~t~*|", [Delta]).
|
||||||
|
|
||||||
|
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
?- portray_clause(a).
|
||||||
|
a.
|
||||||
|
|
||||||
|
?- portray_clause((a :- b)).
|
||||||
|
a :-
|
||||||
|
b.
|
||||||
|
|
||||||
|
?- portray_clause((a :- b, c, d)).
|
||||||
|
a :-
|
||||||
|
b,
|
||||||
|
c,
|
||||||
|
d.
|
||||||
|
true
|
||||||
|
|
||||||
|
|
||||||
|
?- portray_clause([a,b,c,d]).
|
||||||
|
"abcd".
|
||||||
|
|
||||||
|
?- portray_clause(X).
|
||||||
|
?- portray_clause((f(X) :- X)).
|
||||||
|
|
||||||
|
?- portray_clause((h :- ( a -> b; c))).
|
||||||
|
|
||||||
|
?- portray_clause((h :- ( (a -> x ; y) -> b; c))).
|
||||||
|
|
||||||
|
?- portray_clause((h(X) :- ( (a(X) ; y(A,B)) -> b; c))).
|
||||||
|
|
||||||
|
?- portray_clause((h :- (a,d;b,c) ; (b,e;d))).
|
||||||
|
|
||||||
|
?- portray_clause((a :- b ; c ; d)).
|
||||||
|
|
||||||
|
?- portray_clause((h :- L = '.')).
|
||||||
|
|
||||||
|
?- portray_clause(-->(a, (b, {t}, d))).
|
||||||
|
|
||||||
|
?- portray_clause((A :- B)).
|
||||||
|
|
||||||
|
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||||
|
|
||||||
|
listing(PI) :-
|
||||||
|
nonvar(PI),
|
||||||
|
( PI = Name/Arity0 ->
|
||||||
|
Arity = Arity0
|
||||||
|
; PI = Name//Arity0 ->
|
||||||
|
Arity is Arity0 + 2
|
||||||
|
; type_error(predicate_indicator, PI, listing/1)
|
||||||
|
),
|
||||||
|
functor(Head, Name, Arity),
|
||||||
|
\+ \+ clause(Head, _), % only true if there is at least one clause
|
||||||
|
( clause(Head, Body),
|
||||||
|
( Body == true ->
|
||||||
|
portray_clause(Head)
|
||||||
|
; portray_clause((Head :- Body))
|
||||||
|
),
|
||||||
|
false
|
||||||
|
; true
|
||||||
|
).
|
||||||
@@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
:- use_module(library(error)).
|
:- use_module(library(error)).
|
||||||
:- use_module(library(lists)).
|
:- use_module(library(lists)).
|
||||||
:- use_module(library(non_iso)).
|
:- use_module(library(iso_ext)).
|
||||||
:- use_module(library(si)).
|
:- use_module(library(si)).
|
||||||
|
|
||||||
gensym_key(Base, BaseKey) :-
|
gensym_key(Base, BaseKey) :-
|
||||||
84
src/lib/http/http_open.pl
Normal file
84
src/lib/http/http_open.pl
Normal 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, []).
|
||||||
|
|
||||||
@@ -1,13 +1,13 @@
|
|||||||
%% for builtins that are not part of the ISO standard.
|
%% for builtins that are not part of the ISO standard.
|
||||||
%% must be loaded at the REPL with
|
%% must be loaded at the REPL with
|
||||||
|
|
||||||
%% ?- use_module(library(non_iso)).
|
%% ?- use_module(library(iso_ext)).
|
||||||
|
|
||||||
:- module(non_iso, [bb_b_put/2, bb_get/2, bb_put/2, call_cleanup/2,
|
:- module(iso_ext, [bb_b_put/2, bb_get/2, bb_put/2, call_cleanup/2,
|
||||||
call_with_inference_limit/3, forall/2, maybe/0,
|
call_with_inference_limit/3, forall/2,
|
||||||
partial_string/1, partial_string/3,
|
partial_string/1, partial_string/3,
|
||||||
partial_string_tail/2, set_random/1,
|
partial_string_tail/2, setup_call_cleanup/3,
|
||||||
setup_call_cleanup/3, variant/2]).
|
variant/2]).
|
||||||
|
|
||||||
forall(Generate, Test) :-
|
forall(Generate, Test) :-
|
||||||
\+ (Generate, \+ Test).
|
\+ (Generate, \+ Test).
|
||||||
@@ -22,9 +22,9 @@ bb_put(Key, _) :- throw(error(type_error(atom, Key), bb_put/2)).
|
|||||||
bb_b_put(Key, NewValue) :-
|
bb_b_put(Key, NewValue) :-
|
||||||
( '$bb_get_with_offset'(Key, OldValue, OldOffset) ->
|
( '$bb_get_with_offset'(Key, OldValue, OldOffset) ->
|
||||||
call_cleanup((store_global_var_with_offset(Key, NewValue) ; false),
|
call_cleanup((store_global_var_with_offset(Key, NewValue) ; false),
|
||||||
reset_global_var_at_offset(Key, OldValue, OldOffset))
|
reset_global_var_at_offset(Key, OldValue, OldOffset))
|
||||||
; call_cleanup((store_global_var_with_offset(Key, NewValue) ; false),
|
; call_cleanup((store_global_var_with_offset(Key, NewValue) ; false),
|
||||||
reset_global_var_at_key(Key))
|
reset_global_var_at_key(Key))
|
||||||
).
|
).
|
||||||
|
|
||||||
store_global_var_with_offset(Key, Value) :- '$store_global_var_with_offset'(Key, Value).
|
store_global_var_with_offset(Key, Value) :- '$store_global_var_with_offset'(Key, Value).
|
||||||
@@ -68,7 +68,8 @@ scc_helper(C, G, Bb) :-
|
|||||||
; '$reset_block'(NBb),
|
; '$reset_block'(NBb),
|
||||||
'$fail').
|
'$fail').
|
||||||
scc_helper(_, _, Bb) :-
|
scc_helper(_, _, Bb) :-
|
||||||
'$reset_block'(Bb), '$get_ball'(Ball),
|
'$reset_block'(Bb),
|
||||||
|
'$get_ball'(Ball),
|
||||||
'$call_with_default_policy'(run_cleaners_with_handling),
|
'$call_with_default_policy'(run_cleaners_with_handling),
|
||||||
'$erase_ball',
|
'$erase_ball',
|
||||||
'$call_with_default_policy'(throw(Ball)).
|
'$call_with_default_policy'(throw(Ball)).
|
||||||
@@ -143,27 +144,14 @@ call_with_inference_limit(_, _, R, Bb, B) :-
|
|||||||
|
|
||||||
variant(X, Y) :- '$variant'(X, Y).
|
variant(X, Y) :- '$variant'(X, Y).
|
||||||
|
|
||||||
% succeeds with probability 0.5.
|
|
||||||
maybe :- '$maybe'.
|
|
||||||
|
|
||||||
set_random(Seed) :-
|
|
||||||
( nonvar(Seed) ->
|
|
||||||
( Seed = seed(S) ->
|
|
||||||
( var(S) -> throw(error(instantiation_error, set_random/1))
|
|
||||||
; integer(S) -> '$set_seed'(S)
|
|
||||||
; throw(error(type_error(integer(S), set_random/1)))
|
|
||||||
)
|
|
||||||
)
|
|
||||||
; throw(error(instantiation_error, set_random/1))
|
|
||||||
).
|
|
||||||
|
|
||||||
partial_string(String, L, L0) :-
|
partial_string(String, L, L0) :-
|
||||||
( String == [] -> throw(error(type_error(list, []), partial_string/3))
|
( String == [] ->
|
||||||
|
L = L0
|
||||||
; catch(atom_chars(Atom, String),
|
; catch(atom_chars(Atom, String),
|
||||||
error(E, _),
|
error(E, _),
|
||||||
throw(error(E, partial_string/3)))
|
throw(error(E, partial_string/3))),
|
||||||
),
|
'$create_partial_string'(Atom, L, L0)
|
||||||
'$create_partial_string'(Atom, L, L0).
|
).
|
||||||
|
|
||||||
partial_string(String) :-
|
partial_string(String) :-
|
||||||
'$is_partial_string'(String).
|
'$is_partial_string'(String).
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
:- module(lists, [member/2, select/3, append/3, foldl/4, foldl/5,
|
:- module(lists, [member/2, select/3, append/2, append/3, foldl/4, foldl/5,
|
||||||
memberchk/2, reverse/2, length/2, maplist/2,
|
memberchk/2, reverse/2, length/2, maplist/2,
|
||||||
maplist/3, maplist/4, maplist/5, maplist/6,
|
maplist/3, maplist/4, maplist/5, maplist/6,
|
||||||
maplist/7, maplist/8, maplist/9, same_length/2,
|
maplist/7, maplist/8, maplist/9, same_length/2, nth0/3,
|
||||||
sumlist/2]).
|
sum_list/2, transpose/2, list_to_set/2]).
|
||||||
|
|
||||||
|
|
||||||
:- use_module(library(error)).
|
:- use_module(library(error)).
|
||||||
@@ -21,9 +21,9 @@ length(Xs, N) :-
|
|||||||
; var(Xs0) -> R is N-M, length_rundown(Xs0, R)).
|
; var(Xs0) -> R is N-M, length_rundown(Xs0, R)).
|
||||||
length(_, N) :-
|
length(_, N) :-
|
||||||
integer(N), !,
|
integer(N), !,
|
||||||
throw(error(domain_error(not_less_than_zero, N), length/2)).
|
domain_error(not_less_than_zero, N, length/2).
|
||||||
length(_, N) :-
|
length(_, N) :-
|
||||||
throw(error(type_error(integer, N), length/2)).
|
type_error(integer, N, length/2).
|
||||||
|
|
||||||
length_addendum([], N, N).
|
length_addendum([], N, N).
|
||||||
length_addendum([_|Xs], N, M) :-
|
length_addendum([_|Xs], N, M) :-
|
||||||
@@ -44,6 +44,12 @@ select(X, [X|Xs], Xs).
|
|||||||
select(X, [Y|Xs], [Y|Ys]) :- select(X, Xs, Ys).
|
select(X, [Y|Xs], [Y|Ys]) :- select(X, Xs, Ys).
|
||||||
|
|
||||||
|
|
||||||
|
append([], []).
|
||||||
|
append([L0|Ls0], Ls) :-
|
||||||
|
append(L0, Rest, Ls),
|
||||||
|
append(Ls0, Rest).
|
||||||
|
|
||||||
|
|
||||||
append([], R, R).
|
append([], R, R).
|
||||||
append([X|L], R, [X|S]) :- append(L, R, S).
|
append([X|L], R, [X|S]) :- append(L, R, S).
|
||||||
|
|
||||||
@@ -57,7 +63,7 @@ reverse(Xs, Ys) :-
|
|||||||
).
|
).
|
||||||
|
|
||||||
reverse([], [], YsRev, YsRev).
|
reverse([], [], YsRev, YsRev).
|
||||||
reverse([X1|Xs], [Y1|Ys], YsPreludeRev, Xss) :-
|
reverse([_|Xs], [Y1|Ys], YsPreludeRev, Xss) :-
|
||||||
reverse(Xs, Ys, [Y1|YsPreludeRev], Xss).
|
reverse(Xs, Ys, [Y1|YsPreludeRev], Xss).
|
||||||
|
|
||||||
|
|
||||||
@@ -98,18 +104,14 @@ maplist(Cont, [E1|E1s], [E2|E2s], [E3|E3s], [E4|E4s], [E5|E5s], [E6|E6s], [E7|E7
|
|||||||
|
|
||||||
maplist(_, [], [], [], [], [], [], [], []).
|
maplist(_, [], [], [], [], [], [], [], []).
|
||||||
maplist(Cont, [E1|E1s], [E2|E2s], [E3|E3s], [E4|E4s], [E5|E5s], [E6|E6s], [E7|E7s], [E8|E8s]) :-
|
maplist(Cont, [E1|E1s], [E2|E2s], [E3|E3s], [E4|E4s], [E5|E5s], [E6|E6s], [E7|E7s], [E8|E8s]) :-
|
||||||
call(Cont, E1, E2, E3, E4, E5, E6, E7),
|
call(Cont, E1, E2, E3, E4, E5, E6, E7, E8),
|
||||||
maplist(Cont, E1s, E2s, E3s, E4s, E5s, E6s, E7s, E8s).
|
maplist(Cont, E1s, E2s, E3s, E4s, E5s, E6s, E7s, E8s).
|
||||||
|
|
||||||
|
|
||||||
sumlist_([], S, S).
|
sum_list(Ls, S) :-
|
||||||
sumlist_([N|Ns], S, S0) :-
|
foldl(sum_, Ls, 0, S).
|
||||||
S1 is S0 + N,
|
|
||||||
sumlist_(Ns, S, S1).
|
|
||||||
|
|
||||||
sumlist(Ns, S) :-
|
sum_(L, S0, S) :- S is S0 + L.
|
||||||
must_be(list, Ns),
|
|
||||||
sumlist_(Ns, S, 0).
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -134,3 +136,67 @@ foldl_([], [], _, A, A).
|
|||||||
foldl_([X|Xs], [Y|Ys], G_4, A0, A) :-
|
foldl_([X|Xs], [Y|Ys], G_4, A0, A) :-
|
||||||
call(G_4, X, Y, A0, A1),
|
call(G_4, X, Y, A0, A1),
|
||||||
foldl_(Xs, Ys, G_4, A1, A).
|
foldl_(Xs, Ys, G_4, A1, A).
|
||||||
|
|
||||||
|
transpose(Ls, Ts) :-
|
||||||
|
lists_transpose(Ls, Ts).
|
||||||
|
|
||||||
|
lists_transpose([], []).
|
||||||
|
lists_transpose([L|Ls], Ts) :-
|
||||||
|
maplist(same_length(L), Ls),
|
||||||
|
foldl(transpose_, L, Ts, [L|Ls], _).
|
||||||
|
|
||||||
|
transpose_(_, Fs, Lists0, Lists) :-
|
||||||
|
maplist(list_first_rest, Lists0, Fs, Lists).
|
||||||
|
|
||||||
|
list_first_rest([L|Ls], L, Ls).
|
||||||
|
|
||||||
|
|
||||||
|
list_to_set(Ls0, Ls) :-
|
||||||
|
maplist(with_var, Ls0, LVs0),
|
||||||
|
keysort(LVs0, LVs),
|
||||||
|
same_elements(LVs),
|
||||||
|
pick_firsts(LVs0, Ls).
|
||||||
|
|
||||||
|
pick_firsts([], []).
|
||||||
|
pick_firsts([E-V|EVs], Fs0) :-
|
||||||
|
( V == visited ->
|
||||||
|
Fs0 = Fs
|
||||||
|
; V = visited,
|
||||||
|
Fs0 = [E|Fs]
|
||||||
|
),
|
||||||
|
pick_firsts(EVs, Fs).
|
||||||
|
|
||||||
|
with_var(E, E-_).
|
||||||
|
|
||||||
|
same_elements([]).
|
||||||
|
same_elements([EV|EVs]) :-
|
||||||
|
foldl(unify_same, EVs, EV, _).
|
||||||
|
|
||||||
|
unify_same(E-V, Prev-Var, E-V) :-
|
||||||
|
( Prev == E ->
|
||||||
|
Var = V
|
||||||
|
; true
|
||||||
|
).
|
||||||
|
|
||||||
|
|
||||||
|
nth0(N, Es, E) :-
|
||||||
|
can_be(integer, N),
|
||||||
|
can_be(list, Es),
|
||||||
|
( integer(N) ->
|
||||||
|
nth0_index(N, Es, E)
|
||||||
|
; nth0_search(N, Es, E)
|
||||||
|
).
|
||||||
|
|
||||||
|
nth0_index(0, [E|_], E) :- !.
|
||||||
|
nth0_index(N, [_|Es], E) :-
|
||||||
|
N > 0,
|
||||||
|
N1 is N - 1,
|
||||||
|
nth0_index(N1, Es, E).
|
||||||
|
|
||||||
|
nth0_search(N, Es, E) :-
|
||||||
|
nth0_search(0, N, Es, E).
|
||||||
|
|
||||||
|
nth0_search(N, N, [E|_], E).
|
||||||
|
nth0_search(N0, N, [_|Es], E) :-
|
||||||
|
N1 is N0 + 1,
|
||||||
|
nth0_search(N1, N, Es, E).
|
||||||
58
src/lib/os.pl
Normal file
58
src/lib/os.pl
Normal 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).
|
||||||
33
src/lib/pairs.pl
Normal file
33
src/lib/pairs.pl
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
:- module(pairs, [pairs_keys_values/3,
|
||||||
|
pairs_keys/2,
|
||||||
|
pairs_values/2,
|
||||||
|
group_pairs_by_key/2,
|
||||||
|
map_list_to_pairs/3]).
|
||||||
|
|
||||||
|
|
||||||
|
pairs_keys_values([], [], []).
|
||||||
|
pairs_keys_values([A-B|ABs], [A|As], [B|Bs]) :-
|
||||||
|
pairs_keys_values(ABs, As, Bs).
|
||||||
|
|
||||||
|
pairs_keys(Ps, Ks) :- pairs_keys_values(Ps, Ks, _).
|
||||||
|
|
||||||
|
pairs_values(Ps, Vs) :- pairs_keys_values(Ps, _, Vs).
|
||||||
|
|
||||||
|
map_list_to_pairs(Pred, Ls, Ps) :-
|
||||||
|
map_list_to_pairs2(Ls, Pred, Ps).
|
||||||
|
|
||||||
|
map_list_to_pairs2([], _, []).
|
||||||
|
map_list_to_pairs2([H|T0], Pred, [K-H|T]) :-
|
||||||
|
call(Pred, H, K),
|
||||||
|
map_list_to_pairs2(T0, Pred, T).
|
||||||
|
|
||||||
|
|
||||||
|
group_pairs_by_key([], []).
|
||||||
|
group_pairs_by_key([K-V|KVs0], [K-[V|Vs]|KVs]) :-
|
||||||
|
same_key(K, KVs0, Vs, KVs1),
|
||||||
|
group_pairs_by_key(KVs1, KVs).
|
||||||
|
|
||||||
|
same_key(K0, [K1-V|KVs0], [V|Vs], KVs) :-
|
||||||
|
K0 == K1, !,
|
||||||
|
same_key(K0, KVs0, Vs, KVs).
|
||||||
|
same_key(_, KVs, [], KVs).
|
||||||
42
src/lib/pio.pl
Normal file
42
src/lib/pio.pl
Normal 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)
|
||||||
|
).
|
||||||
59
src/lib/random.pl
Normal file
59
src/lib/random.pl
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
:- module(random, [maybe/0, random/1, random_integer/3, set_random/1]).
|
||||||
|
|
||||||
|
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
To retain desirable declarative properties, predicates that internally
|
||||||
|
use random numbers should be equipped with an argument that specifies
|
||||||
|
the random seed. This makes everything completely reproducible.
|
||||||
|
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||||
|
|
||||||
|
:- use_module(library(error)).
|
||||||
|
|
||||||
|
% succeeds with probability 0.5.
|
||||||
|
maybe :- '$maybe'.
|
||||||
|
|
||||||
|
% The higher the precision, the slower it gets.
|
||||||
|
random_number_precision(64).
|
||||||
|
|
||||||
|
random(R) :-
|
||||||
|
var(R),
|
||||||
|
random_number_precision(N),
|
||||||
|
rnd(N, R).
|
||||||
|
|
||||||
|
random_integer(Lower, Upper, R) :-
|
||||||
|
var(R),
|
||||||
|
( (var(Lower) ; var(Upper)) ->
|
||||||
|
instantiation_error(random_integer/3)
|
||||||
|
; \+ integer(Lower) ->
|
||||||
|
domain_error(integer, Lower, random_integer/3)
|
||||||
|
; \+ integer(Upper) ->
|
||||||
|
domain_error(integer, Upper, random_integer/3)
|
||||||
|
; Upper > Lower,
|
||||||
|
random(R0),
|
||||||
|
R is floor((Upper - Lower) * R0 + Lower)
|
||||||
|
).
|
||||||
|
|
||||||
|
rnd(N, R) :-
|
||||||
|
rnd_(N, 0, R).
|
||||||
|
|
||||||
|
rnd_(0, R, R) :- !.
|
||||||
|
rnd_(N, R0, R) :-
|
||||||
|
maybe,
|
||||||
|
!,
|
||||||
|
N1 is N - 1,
|
||||||
|
rnd_(N1, R0, R).
|
||||||
|
rnd_(N, R0, R) :-
|
||||||
|
N1 is N - 1,
|
||||||
|
R1 is R0 + 1.0 / 2.0 ^ N,
|
||||||
|
rnd_(N1, R1, R).
|
||||||
|
|
||||||
|
set_random(Seed) :-
|
||||||
|
( nonvar(Seed) ->
|
||||||
|
( Seed = seed(S) ->
|
||||||
|
( var(S) -> instantiation_error(set_random/1)
|
||||||
|
; integer(S) -> '$set_seed'(S)
|
||||||
|
; type_error(integer, S, set_random/1)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
; instantiation_error(set_random/1)
|
||||||
|
).
|
||||||
|
|
||||||
92
src/lib/sgml.pl
Normal file
92
src/lib/sgml.pl
Normal 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)
|
||||||
|
).
|
||||||
67
src/lib/sockets.pl
Normal file
67
src/lib/sockets.pl
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
|
||||||
|
:- module(sockets, [socket_client_open/3,
|
||||||
|
socket_server_open/2,
|
||||||
|
socket_server_accept/4,
|
||||||
|
socket_server_close/1,
|
||||||
|
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) ->
|
||||||
|
throw(error(instantiation_error, socket_client_open/3))
|
||||||
|
;
|
||||||
|
true
|
||||||
|
),
|
||||||
|
must_be(var, Stream),
|
||||||
|
must_be(list, Options),
|
||||||
|
( Addr = Address:Port,
|
||||||
|
atom(Address),
|
||||||
|
( atom(Port) ; integer(Port) ) ->
|
||||||
|
true
|
||||||
|
;
|
||||||
|
throw(error(type_error(socket_address, Addr), socket_client_open/3))
|
||||||
|
),
|
||||||
|
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) :-
|
||||||
|
must_be(var, ServerSocket),
|
||||||
|
( ( integer(Addr) ; var(Addr) ) ->
|
||||||
|
'$socket_server_open'([], Addr, ServerSocket)
|
||||||
|
;
|
||||||
|
Addr = Address:Port,
|
||||||
|
must_be(atom, Address),
|
||||||
|
can_be(integer, Port),
|
||||||
|
'$socket_server_open'(Address, Port, ServerSocket)
|
||||||
|
).
|
||||||
|
|
||||||
|
|
||||||
|
socket_server_accept(ServerSocket, Client, Stream, Options) :-
|
||||||
|
must_be(var, Client),
|
||||||
|
must_be(var, Stream),
|
||||||
|
builtins:parse_stream_options(Options,
|
||||||
|
[Alias, EOFAction, Reposition, Type],
|
||||||
|
socket_server_accept/4),
|
||||||
|
'$socket_server_accept'(ServerSocket, Client, Stream, Alias, EOFAction, Reposition, Type).
|
||||||
|
|
||||||
|
|
||||||
|
socket_server_close(ServerSocket) :-
|
||||||
|
'$socket_server_close'(ServerSocket).
|
||||||
|
|
||||||
|
|
||||||
|
current_hostname(HostName) :-
|
||||||
|
'$current_hostname'(HostName).
|
||||||
@@ -8,17 +8,17 @@
|
|||||||
op(1150, fx, table)
|
op(1150, fx, table)
|
||||||
]).
|
]).
|
||||||
|
|
||||||
:- use_module('tabling/double_linked_list').
|
:- use_module(library(tabling/double_linked_list)).
|
||||||
:- use_module('tabling/table_data_structure').
|
:- use_module(library(tabling/table_data_structure)).
|
||||||
:- use_module('tabling/batched_worklist').
|
:- use_module(library(tabling/batched_worklist)).
|
||||||
:- use_module('tabling/wrapper').
|
:- use_module(library(tabling/wrapper)).
|
||||||
:- use_module('tabling/global_worklist').
|
:- use_module(library(tabling/global_worklist)).
|
||||||
:- use_module('tabling/table_link_manager').
|
:- use_module(library(tabling/table_link_manager)).
|
||||||
|
|
||||||
:- use_module(library(cont)).
|
:- use_module(library(cont)).
|
||||||
:- use_module(library(lists)).
|
:- use_module(library(lists)).
|
||||||
%:- use_module(library(debug)).
|
%:- use_module(library(debug)).
|
||||||
:- use_module(library(non_iso)).
|
:- use_module(library(iso_ext)).
|
||||||
|
|
||||||
%% :- meta_predicate
|
%% :- meta_predicate
|
||||||
%% start_tabling(+, 0).
|
%% start_tabling(+, 0).
|
||||||
@@ -135,19 +135,15 @@ activate(Wrapper,Worker,T) :-
|
|||||||
|
|
||||||
delim(Wrapper,Worker,Table) :-
|
delim(Wrapper,Worker,Table) :-
|
||||||
% debug(tabling, 'ACT: ~p on ~p', [Wrapper, Table]),
|
% debug(tabling, 'ACT: ~p on ~p', [Wrapper, Table]),
|
||||||
reset(Worker,SourceCall,Continuation),
|
reset(Worker,SourceCall,Continuation),
|
||||||
( Continuation == none, var(SourceCall) ->
|
( Continuation = none ->
|
||||||
( add_answer(Table,Wrapper)
|
( add_answer(Table,Wrapper)
|
||||||
-> true %debug(tabling, 'ADD: ~p', [Wrapper])
|
-> true %debug(tabling, 'ADD: ~p', [Wrapper])
|
||||||
; %debug(tabling, 'DUP: ~p', [Wrapper]),
|
; %debug(tabling, 'DUP: ~p', [Wrapper]),
|
||||||
fail
|
fail
|
||||||
)
|
)
|
||||||
;
|
;
|
||||||
( Continuation = cont(Cont) ->
|
Continuation = cont(Cont),
|
||||||
true
|
|
||||||
; Continuation = none ->
|
|
||||||
Cont = true
|
|
||||||
),
|
|
||||||
SourceCall = call_info(_,SourceTable),
|
SourceCall = call_info(_,SourceTable),
|
||||||
TargetCall = call_info(Wrapper,Table),
|
TargetCall = call_info(Wrapper,Table),
|
||||||
Dependency = dependency(SourceCall,Cont,TargetCall),
|
Dependency = dependency(SourceCall,Cont,TargetCall),
|
||||||
@@ -45,8 +45,8 @@
|
|||||||
wkl_worklist_work_done/1 % +WorkList
|
wkl_worklist_work_done/1 % +WorkList
|
||||||
]).
|
]).
|
||||||
|
|
||||||
:- use_module(global_worklist).
|
:- use_module(library(tabling/global_worklist)).
|
||||||
:- use_module(double_linked_list).
|
:- use_module(library(tabling/double_linked_list)).
|
||||||
|
|
||||||
:- use_module(library(atts)).
|
:- use_module(library(atts)).
|
||||||
:- use_module(library(lists)).
|
:- use_module(library(lists)).
|
||||||
@@ -208,4 +208,3 @@ dll_get_reverse_contents_(List, Contents) :-
|
|||||||
dll_get_pointer_to_previous(List, Prev),
|
dll_get_pointer_to_previous(List, Prev),
|
||||||
dll_get_reverse_contents_(Prev, Rest)
|
dll_get_reverse_contents_(Prev, Rest)
|
||||||
).
|
).
|
||||||
|
|
||||||
@@ -9,7 +9,7 @@
|
|||||||
]).
|
]).
|
||||||
|
|
||||||
:- use_module(library(atts)).
|
:- use_module(library(atts)).
|
||||||
:- use_module(library(non_iso)).
|
:- use_module(library(iso_ext)).
|
||||||
|
|
||||||
:- attribute table_global_worklist/1.
|
:- attribute table_global_worklist/1.
|
||||||
|
|
||||||
@@ -15,8 +15,8 @@
|
|||||||
get_nb_identifiers/3 % +Table, -NbWorklistID, -NbAnswerTreeID
|
get_nb_identifiers/3 % +Table, -NbWorklistID, -NbAnswerTreeID
|
||||||
]).
|
]).
|
||||||
|
|
||||||
:- use_module(table_link_manager).
|
:- use_module(library(tabling/table_link_manager)).
|
||||||
:- use_module(trie).
|
:- use_module(library(tabling/trie)).
|
||||||
|
|
||||||
/* Part of SWI-Prolog
|
/* Part of SWI-Prolog
|
||||||
|
|
||||||
@@ -53,11 +53,11 @@
|
|||||||
POSSIBILITY OF SUCH DAMAGE.
|
POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
:- use_module(batched_worklist).
|
:- use_module(library(tabling/batched_worklist)).
|
||||||
|
|
||||||
:- use_module(library(atts)).
|
:- use_module(library(atts)).
|
||||||
:- use_module(library(gensym)).
|
:- use_module(library(gensym)).
|
||||||
:- use_module(library(non_iso)).
|
:- use_module(library(iso_ext)).
|
||||||
|
|
||||||
:- attribute table_status/1, newly_created_table_identifiers/1.
|
:- attribute table_status/1, newly_created_table_identifiers/1.
|
||||||
|
|
||||||
@@ -44,10 +44,10 @@
|
|||||||
|
|
||||||
:- use_module(library(atts)).
|
:- use_module(library(atts)).
|
||||||
:- use_module(library(lists)).
|
:- use_module(library(lists)).
|
||||||
:- use_module(library(non_iso)).
|
:- use_module(library(iso_ext)).
|
||||||
:- use_module(library(terms)).
|
:- use_module(library(terms)).
|
||||||
|
|
||||||
:- use_module(trie).
|
:- use_module(library(tabling/trie)).
|
||||||
|
|
||||||
:- attribute trie_table_link/1.
|
:- attribute trie_table_link/1.
|
||||||
|
|
||||||
@@ -66,7 +66,7 @@
|
|||||||
% p_trie_arity_univ(+Term,-FunctorData,-ArgumentsList).
|
% p_trie_arity_univ(+Term,-FunctorData,-ArgumentsList).
|
||||||
p_trie_arity_univ(Term,functor_data(Name,Arity),Arguments) :-
|
p_trie_arity_univ(Term,functor_data(Name,Arity),Arguments) :-
|
||||||
( var(Term) ->
|
( var(Term) ->
|
||||||
Name = var,
|
Name = Term,
|
||||||
Arity = 0,
|
Arity = 0,
|
||||||
Arguments = []
|
Arguments = []
|
||||||
; Term =.. [Name|Arguments],
|
; Term =.. [Name|Arguments],
|
||||||
129
src/lib/time.pl
Normal file
129
src/lib/time.pl
Normal 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
642
src/lib/xpath.pl
Normal 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.
|
||||||
1209
src/machine/arithmetic_ops.rs
Normal file
1209
src/machine/arithmetic_ops.rs
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,7 @@
|
|||||||
|
:- module('$atts', []).
|
||||||
|
|
||||||
driver(Vars, Values) :-
|
driver(Vars, Values) :-
|
||||||
iterate(Vars, Values, ListOfListsOfGoalLists),
|
iterate(Vars, Values, ListOfListsOfGoalLists),
|
||||||
'$clear_attr_var_bindings',
|
|
||||||
!,
|
!,
|
||||||
call_goals(ListOfListsOfGoalLists),
|
call_goals(ListOfListsOfGoalLists),
|
||||||
'$return_from_verify_attr'.
|
'$return_from_verify_attr'.
|
||||||
@@ -17,13 +18,6 @@ gather_modules([Attr|Attrs], [Module|Modules]) :-
|
|||||||
'$module_of'(Module, Attr), % write the owning module of Attr to Module.
|
'$module_of'(Module, Attr), % write the owning module of Attr to Module.
|
||||||
gather_modules(Attrs, Modules).
|
gather_modules(Attrs, Modules).
|
||||||
|
|
||||||
verify_attrs([Module|Modules], Var, Value, [Goals|ListOfGoalLists]) :-
|
|
||||||
catch(Module:verify_attributes(Var, Value, Goals),
|
|
||||||
error(evaluation_error((Module:verify_attributes)/3), verify_attributes/3),
|
|
||||||
Goals = []),
|
|
||||||
verify_attrs(Modules, Var, Value, ListOfGoalLists).
|
|
||||||
verify_attrs([], _, _, []).
|
|
||||||
|
|
||||||
call_verify_attributes(Attrs, _, _, []) :-
|
call_verify_attributes(Attrs, _, _, []) :-
|
||||||
var(Attrs), !.
|
var(Attrs), !.
|
||||||
call_verify_attributes([], _, _, []).
|
call_verify_attributes([], _, _, []).
|
||||||
@@ -32,6 +26,13 @@ call_verify_attributes([Attr|Attrs], Var, Value, ListOfGoalLists) :-
|
|||||||
sort(Modules0, Modules),
|
sort(Modules0, Modules),
|
||||||
verify_attrs(Modules, Var, Value, ListOfGoalLists).
|
verify_attrs(Modules, Var, Value, ListOfGoalLists).
|
||||||
|
|
||||||
|
verify_attrs([Module|Modules], Var, Value, [Goals|ListOfGoalLists]) :-
|
||||||
|
catch(Module:verify_attributes(Var, Value, Goals),
|
||||||
|
error(evaluation_error((Module:verify_attributes)/3), verify_attributes/3),
|
||||||
|
Goals = []),
|
||||||
|
verify_attrs(Modules, Var, Value, ListOfGoalLists).
|
||||||
|
verify_attrs([], _, _, []).
|
||||||
|
|
||||||
call_goals([ListOfGoalLists | ListsCubed]) :-
|
call_goals([ListOfGoalLists | ListsCubed]) :-
|
||||||
call_goals_0(ListOfGoalLists),
|
call_goals_0(ListOfGoalLists),
|
||||||
call_goals(ListsCubed).
|
call_goals(ListsCubed).
|
||||||
@@ -1,5 +1,9 @@
|
|||||||
use crate::prolog::machine::*;
|
use crate::heap_iter::*;
|
||||||
|
use crate::machine::*;
|
||||||
|
|
||||||
|
use crate::indexmap::IndexSet;
|
||||||
|
|
||||||
|
use std::cmp::Ordering;
|
||||||
use std::vec::IntoIter;
|
use std::vec::IntoIter;
|
||||||
|
|
||||||
pub static VERIFY_ATTRS: &str = include_str!("attributed_variables.pl");
|
pub static VERIFY_ATTRS: &str = include_str!("attributed_variables.pl");
|
||||||
@@ -7,6 +11,7 @@ pub static PROJECT_ATTRS: &str = include_str!("project_attributes.pl");
|
|||||||
|
|
||||||
pub(super) type Bindings = Vec<(usize, Addr)>;
|
pub(super) type Bindings = Vec<(usize, Addr)>;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
pub(super) struct AttrVarInitializer {
|
pub(super) struct AttrVarInitializer {
|
||||||
pub(super) attribute_goals: Vec<Addr>,
|
pub(super) attribute_goals: Vec<Addr>,
|
||||||
pub(super) attr_var_queue: Vec<usize>,
|
pub(super) attr_var_queue: Vec<usize>,
|
||||||
@@ -18,7 +23,8 @@ pub(super) struct AttrVarInitializer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl AttrVarInitializer {
|
impl AttrVarInitializer {
|
||||||
pub(super) fn new(verify_attrs_loc: usize, project_attrs_loc: usize) -> Self {
|
pub(super)
|
||||||
|
fn new(verify_attrs_loc: usize, project_attrs_loc: usize) -> Self {
|
||||||
AttrVarInitializer {
|
AttrVarInitializer {
|
||||||
attribute_goals: vec![],
|
attribute_goals: vec![],
|
||||||
attr_var_queue: vec![],
|
attr_var_queue: vec![],
|
||||||
@@ -31,21 +37,24 @@ impl AttrVarInitializer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub(super) fn reset(&mut self) {
|
pub(super)
|
||||||
self.attribute_goals.clear();
|
fn reset(&mut self) {
|
||||||
|
self.attribute_goals.clear();
|
||||||
self.attr_var_queue.clear();
|
self.attr_var_queue.clear();
|
||||||
self.bindings.clear();
|
self.bindings.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub(super) fn backtrack(&mut self, queue_b: usize, bindings_b: usize) {
|
pub(super)
|
||||||
|
fn backtrack(&mut self, queue_b: usize, bindings_b: usize) {
|
||||||
self.attr_var_queue.truncate(queue_b);
|
self.attr_var_queue.truncate(queue_b);
|
||||||
self.bindings.truncate(bindings_b);
|
self.bindings.truncate(bindings_b);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MachineState {
|
impl MachineState {
|
||||||
pub(super) fn push_attr_var_binding(&mut self, h: usize, addr: Addr) {
|
pub(super)
|
||||||
|
fn push_attr_var_binding(&mut self, h: usize, addr: Addr) {
|
||||||
if self.attr_var_init.bindings.is_empty() {
|
if self.attr_var_init.bindings.is_empty() {
|
||||||
self.attr_var_init.instigating_p = self.p.local();
|
self.attr_var_init.instigating_p = self.p.local();
|
||||||
|
|
||||||
@@ -66,18 +75,17 @@ impl MachineState {
|
|||||||
.attr_var_init
|
.attr_var_init
|
||||||
.bindings
|
.bindings
|
||||||
.iter()
|
.iter()
|
||||||
.map(|(ref h, _)| Addr::AttrVar(*h));
|
.map(|(ref h, _)| HeapCellValue::Addr(Addr::AttrVar(*h)));
|
||||||
|
|
||||||
let var_list_addr = Addr::HeapCell(self.heap.to_list(iter));
|
let var_list_addr = Addr::HeapCell(self.heap.to_list(iter));
|
||||||
|
|
||||||
let iter = self
|
let iter = self
|
||||||
.attr_var_init
|
.attr_var_init
|
||||||
.bindings
|
.bindings
|
||||||
.iter()
|
.drain(0 ..)
|
||||||
.map(|(_, ref addr)| addr.clone());
|
.map(|(_, addr)| HeapCellValue::Addr(addr));
|
||||||
|
|
||||||
let value_list_addr = Addr::HeapCell(self.heap.to_list(iter));
|
let value_list_addr = Addr::HeapCell(self.heap.to_list(iter));
|
||||||
|
|
||||||
(var_list_addr, value_list_addr)
|
(var_list_addr, value_list_addr)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -92,7 +100,8 @@ impl MachineState {
|
|||||||
self[temp_v!(2)] = value_list_addr;
|
self[temp_v!(2)] = value_list_addr;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn gather_attr_vars_created_since(&self, b: usize) -> IntoIter<Addr> {
|
pub(super)
|
||||||
|
fn gather_attr_vars_created_since(&self, b: usize) -> IntoIter<Addr> {
|
||||||
let mut attr_vars: Vec<_> = self.attr_var_init.attr_var_queue[b..]
|
let mut attr_vars: Vec<_> = self.attr_var_init.attr_var_queue[b..]
|
||||||
.iter()
|
.iter()
|
||||||
.filter_map(|h| match self.store(self.deref(Addr::HeapCell(*h))) {
|
.filter_map(|h| match self.store(self.deref(Addr::HeapCell(*h))) {
|
||||||
@@ -101,13 +110,16 @@ impl MachineState {
|
|||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
attr_vars.sort_unstable_by(|a1, a2| self.compare_term_test(a1, a2));
|
attr_vars.sort_unstable_by(|a1, a2| {
|
||||||
|
self.compare_term_test(a1, a2).unwrap_or(Ordering::Less)
|
||||||
|
});
|
||||||
|
|
||||||
self.term_dedup(&mut attr_vars);
|
self.term_dedup(&mut attr_vars);
|
||||||
attr_vars.into_iter()
|
attr_vars.into_iter()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn verify_attr_interrupt(&mut self, p: usize) {
|
pub(super)
|
||||||
|
fn verify_attr_interrupt(&mut self, p: usize) {
|
||||||
self.allocate(self.num_of_args + 2);
|
self.allocate(self.num_of_args + 2);
|
||||||
|
|
||||||
let e = self.e;
|
let e = self.e;
|
||||||
@@ -118,9 +130,9 @@ impl MachineState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
self.stack.index_and_frame_mut(e)[self.num_of_args + 1] =
|
self.stack.index_and_frame_mut(e)[self.num_of_args + 1] =
|
||||||
Addr::Con(Constant::CutPoint(self.b0));
|
Addr::CutPoint(self.b0);
|
||||||
self.stack.index_and_frame_mut(e)[self.num_of_args + 2] =
|
self.stack.index_and_frame_mut(e)[self.num_of_args + 2] =
|
||||||
Addr::Con(Constant::Usize(self.num_of_args));
|
Addr::Usize(self.num_of_args);
|
||||||
|
|
||||||
self.verify_attributes();
|
self.verify_attributes();
|
||||||
|
|
||||||
@@ -128,4 +140,37 @@ impl MachineState {
|
|||||||
self.b0 = self.b;
|
self.b0 = self.b;
|
||||||
self.p = CodePtr::Local(LocalCodePtr::DirEntry(p));
|
self.p = CodePtr::Local(LocalCodePtr::DirEntry(p));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(super)
|
||||||
|
fn attr_vars_of_term(&self, addr: Addr) -> Vec<Addr> {
|
||||||
|
let mut seen_set = IndexSet::new();
|
||||||
|
let mut seen_vars = vec![];
|
||||||
|
|
||||||
|
let mut iter = self.acyclic_pre_order_iter(addr);
|
||||||
|
|
||||||
|
while let Some(addr) = iter.next() {
|
||||||
|
if let HeapCellValue::Addr(Addr::AttrVar(h)) = self.heap.index_addr(&addr).as_ref() {
|
||||||
|
if seen_set.contains(h) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
seen_vars.push(addr);
|
||||||
|
seen_set.insert(*h);
|
||||||
|
|
||||||
|
let mut l = h + 1;
|
||||||
|
let mut list_elements = vec![];
|
||||||
|
|
||||||
|
while let Addr::Lis(elem) = self.store(self.deref(Addr::HeapCell(l))) {
|
||||||
|
list_elements.push(self.heap[elem].as_addr(elem));
|
||||||
|
l = elem + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for element in list_elements.into_iter().rev() {
|
||||||
|
iter.stack().push(element);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
seen_vars
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,17 +1,18 @@
|
|||||||
use crate::prolog::clause_types::*;
|
use crate::clause_types::*;
|
||||||
use crate::prolog::codegen::*;
|
use crate::codegen::*;
|
||||||
use crate::prolog::debray_allocator::*;
|
use crate::debray_allocator::*;
|
||||||
use crate::prolog::forms::*;
|
use crate::forms::*;
|
||||||
use crate::prolog::instructions::*;
|
use crate::instructions::*;
|
||||||
use crate::prolog::machine::compile::*;
|
use crate::machine::compile::*;
|
||||||
use crate::prolog::machine::machine_errors::*;
|
use crate::machine::machine_errors::*;
|
||||||
use crate::prolog::machine::machine_indices::*;
|
use crate::machine::machine_indices::*;
|
||||||
|
|
||||||
use indexmap::IndexSet;
|
use crate::indexmap::IndexSet;
|
||||||
|
|
||||||
use std::collections::VecDeque;
|
use std::collections::VecDeque;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
pub struct CodeRepo {
|
pub struct CodeRepo {
|
||||||
pub(super) cached_query: Code,
|
pub(super) cached_query: Code,
|
||||||
pub(super) goal_expanders: Code,
|
pub(super) goal_expanders: Code,
|
||||||
@@ -52,15 +53,27 @@ impl CodeRepo {
|
|||||||
self.term_dir
|
self.term_dir
|
||||||
.get_mut(&key)
|
.get_mut(&key)
|
||||||
.map(|entry| {
|
.map(|entry| {
|
||||||
(
|
let terms =
|
||||||
Predicate((entry.0).0.drain(len..).collect()),
|
if len < (entry.0).0.len() {
|
||||||
entry.1.drain(queue_len..).collect(),
|
(entry.0).0.drain(len ..).collect()
|
||||||
)
|
} else {
|
||||||
|
vec![]
|
||||||
|
};
|
||||||
|
|
||||||
|
let queue =
|
||||||
|
if queue_len < entry.1.len() {
|
||||||
|
entry.1.drain(queue_len ..).collect()
|
||||||
|
} else {
|
||||||
|
VecDeque::new()
|
||||||
|
};
|
||||||
|
|
||||||
|
(Predicate(terms), queue)
|
||||||
})
|
})
|
||||||
.unwrap_or((Predicate::new(), VecDeque::from(vec![])))
|
.unwrap_or((Predicate::new(), VecDeque::new()))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn add_in_situ_result(
|
pub(crate)
|
||||||
|
fn add_in_situ_result(
|
||||||
&mut self,
|
&mut self,
|
||||||
result: &CompiledResult,
|
result: &CompiledResult,
|
||||||
in_situ_code_dir: &mut InSituCodeDir,
|
in_situ_code_dir: &mut InSituCodeDir,
|
||||||
@@ -100,16 +113,19 @@ impl CodeRepo {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub(super) fn size_of_cached_query(&self) -> usize {
|
pub(super)
|
||||||
|
fn size_of_cached_query(&self) -> usize {
|
||||||
self.cached_query.len()
|
self.cached_query.len()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub(super) fn take_in_situ_code(&mut self) -> Code {
|
pub(super)
|
||||||
|
fn take_in_situ_code(&mut self) -> Code {
|
||||||
mem::replace(&mut self.in_situ_code, Code::new())
|
mem::replace(&mut self.in_situ_code, Code::new())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn lookup_instr<'a>(
|
pub(super)
|
||||||
|
fn lookup_instr<'a>(
|
||||||
&'a self,
|
&'a self,
|
||||||
last_call: bool,
|
last_call: bool,
|
||||||
p: &CodePtr,
|
p: &CodePtr,
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
use crate::prolog::instructions::*;
|
use crate::instructions::*;
|
||||||
|
|
||||||
use std::collections::VecDeque;
|
use std::collections::VecDeque;
|
||||||
|
|
||||||
@@ -1,27 +1,26 @@
|
|||||||
use prolog_parser::ast::*;
|
use crate::prolog_parser::ast::*;
|
||||||
use prolog_parser::parser::get_desc;
|
use crate::prolog_parser::parser::get_desc;
|
||||||
use prolog_parser::tabled_rc::TabledData;
|
use crate::prolog_parser::tabled_rc::TabledData;
|
||||||
|
|
||||||
use crate::prolog::codegen::*;
|
use crate::codegen::*;
|
||||||
use crate::prolog::debray_allocator::*;
|
use crate::debray_allocator::*;
|
||||||
use crate::prolog::forms::*;
|
use crate::forms::*;
|
||||||
use crate::prolog::instructions::*;
|
use crate::instructions::*;
|
||||||
use crate::prolog::iterators::*;
|
use crate::iterators::*;
|
||||||
use crate::prolog::machine::code_walker::*;
|
use crate::machine::code_walker::*;
|
||||||
use crate::prolog::machine::machine_errors::*;
|
use crate::machine::machine_errors::*;
|
||||||
use crate::prolog::machine::machine_indices::*;
|
use crate::machine::machine_indices::*;
|
||||||
use crate::prolog::machine::term_expansion::ExpansionAdditionResult;
|
use crate::machine::term_expansion::ExpansionAdditionResult;
|
||||||
use crate::prolog::machine::toplevel::*;
|
use crate::machine::toplevel::*;
|
||||||
use crate::prolog::machine::*;
|
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::cell::Cell;
|
||||||
use std::collections::VecDeque;
|
use std::collections::VecDeque;
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io::Read;
|
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
@@ -60,9 +59,9 @@ fn fix_filename(
|
|||||||
Ok(path)
|
Ok(path)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn load_module<R: Read>(
|
fn load_module(
|
||||||
wam: &mut Machine,
|
wam: &mut Machine,
|
||||||
stream: ParsingStream<R>,
|
stream: Stream,
|
||||||
suppress_warnings: bool,
|
suppress_warnings: bool,
|
||||||
listing_src: &ListingSource,
|
listing_src: &ListingSource,
|
||||||
) -> Result<ClauseName, SessionError> {
|
) -> Result<ClauseName, SessionError> {
|
||||||
@@ -78,7 +77,13 @@ fn load_module<R: Read>(
|
|||||||
listing_src.clone(),
|
listing_src.clone(),
|
||||||
);
|
);
|
||||||
|
|
||||||
let results = compiler.gather_items(wam, stream, &mut indices);
|
let mut stream = parsing_stream(stream)?;
|
||||||
|
|
||||||
|
let results = compiler.gather_items(
|
||||||
|
wam,
|
||||||
|
&mut stream,
|
||||||
|
&mut indices,
|
||||||
|
);
|
||||||
|
|
||||||
let module_name = if let Some(ref module) = &compiler.module {
|
let module_name = if let Some(ref module) = &compiler.module {
|
||||||
module.module_decl.name.clone()
|
module.module_decl.name.clone()
|
||||||
@@ -114,14 +119,14 @@ fn load_module_from_file(
|
|||||||
let mut path_buf = fix_filename(wam.indices.atom_tbl.clone(), path_buf)?;
|
let mut path_buf = fix_filename(wam.indices.atom_tbl.clone(), path_buf)?;
|
||||||
let filename = clause_name!(path_buf.to_string_lossy().to_string(), wam.indices.atom_tbl);
|
let filename = clause_name!(path_buf.to_string_lossy().to_string(), wam.indices.atom_tbl);
|
||||||
|
|
||||||
let file_handle = File::open(&path_buf).or_else(|_| {
|
let file_handle = Stream::from_file_as_input(filename.clone(), File::open(&path_buf).or_else(|_| {
|
||||||
Err(SessionError::InvalidFileName(filename.clone()))
|
Err(SessionError::InvalidFileName(filename.clone()))
|
||||||
})?;
|
})?);
|
||||||
|
|
||||||
path_buf.pop();
|
path_buf.pop();
|
||||||
|
|
||||||
let listing_src = ListingSource::from_file_and_path(filename, path_buf);
|
let listing_src = ListingSource::from_file_and_path(filename, path_buf);
|
||||||
load_module(wam, parsing_stream(file_handle), suppress_warnings, &listing_src)
|
load_module(wam, file_handle, suppress_warnings, &listing_src)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type PredicateCompileQueue = (Predicate, VecDeque<TopLevel>);
|
pub type PredicateCompileQueue = (Predicate, VecDeque<TopLevel>);
|
||||||
@@ -185,6 +190,8 @@ fn set_first_index(code: &mut Code) {
|
|||||||
if *offset == 0 =>
|
if *offset == 0 =>
|
||||||
{
|
{
|
||||||
*offset = code_len - idx;
|
*offset = code_len - idx;
|
||||||
|
debug_assert!(*offset > 0);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
@@ -320,10 +327,11 @@ fn setup_module_expansions(wam: &mut Machine, module: &Module) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn compile_into_module<R: Read>(
|
pub(super)
|
||||||
|
fn compile_into_module(
|
||||||
wam: &mut Machine,
|
wam: &mut Machine,
|
||||||
module_name: ClauseName,
|
module_name: ClauseName,
|
||||||
src: ParsingStream<R>,
|
src: Stream,
|
||||||
name: ClauseName,
|
name: ClauseName,
|
||||||
) -> EvalSession {
|
) -> EvalSession {
|
||||||
let mut indices = default_index_store!(wam.atom_tbl_of(&name));
|
let mut indices = default_index_store!(wam.atom_tbl_of(&name));
|
||||||
@@ -333,37 +341,45 @@ pub(super) fn compile_into_module<R: Read>(
|
|||||||
indices.op_dir = module.op_dir.clone();
|
indices.op_dir = module.op_dir.clone();
|
||||||
indices.atom_tbl = module.atom_tbl.clone();
|
indices.atom_tbl = module.atom_tbl.clone();
|
||||||
|
|
||||||
let mut compiler = ListingCompiler::new(&wam.code_repo, true, module.listing_src.clone());
|
let mut compiler = ListingCompiler::new(
|
||||||
|
&wam.code_repo,
|
||||||
|
true,
|
||||||
|
module.listing_src.clone(),
|
||||||
|
);
|
||||||
|
|
||||||
match compile_into_module_impl(wam, &mut compiler, module, src, indices) {
|
match compile_into_module_impl(wam, &mut compiler, module, src, indices) {
|
||||||
Ok(()) => EvalSession::EntrySuccess,
|
Ok(()) => {
|
||||||
|
EvalSession::EntrySuccess
|
||||||
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
if let Some(module) = compiler.module.take() {
|
|
||||||
wam.indices.insert_module(module);
|
|
||||||
}
|
|
||||||
|
|
||||||
compiler.drop_expansions(&mut wam.code_repo);
|
compiler.drop_expansions(&mut wam.code_repo);
|
||||||
EvalSession::from(e)
|
EvalSession::from(e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn compile_into_module_impl<R: Read>(
|
fn compile_into_module_impl(
|
||||||
wam: &mut Machine,
|
wam: &mut Machine,
|
||||||
compiler: &mut ListingCompiler,
|
compiler: &mut ListingCompiler,
|
||||||
module: Module,
|
module: Module,
|
||||||
src: ParsingStream<R>,
|
src: Stream,
|
||||||
mut indices: IndexStore,
|
mut indices: IndexStore,
|
||||||
) -> Result<(), SessionError> {
|
) -> Result<(), SessionError> {
|
||||||
setup_module_expansions(wam, &module);
|
setup_module_expansions(wam, &module);
|
||||||
|
|
||||||
let module_name = module.module_decl.name.clone();
|
let module_name = module.module_decl.name.clone();
|
||||||
compiler.module = Some(module);
|
// compiler.module = Some(module); This trips the goal expansion up. Should be possible to 'merge' modules.
|
||||||
|
// A much better strategy!
|
||||||
|
wam.indices.insert_module(module);
|
||||||
|
|
||||||
wam.code_repo.compile_hook(CompileTimeHook::TermExpansion)?;
|
wam.code_repo.compile_hook(CompileTimeHook::TermExpansion)?;
|
||||||
wam.code_repo.compile_hook(CompileTimeHook::GoalExpansion)?;
|
wam.code_repo.compile_hook(CompileTimeHook::GoalExpansion)?;
|
||||||
|
|
||||||
let mut results = compiler.gather_items(wam, src, &mut indices)?;
|
let mut results = compiler.gather_items(
|
||||||
|
wam,
|
||||||
|
&mut parsing_stream(src)?,
|
||||||
|
&mut indices,
|
||||||
|
)?;
|
||||||
|
|
||||||
compiler.adapt_in_situ_code(
|
compiler.adapt_in_situ_code(
|
||||||
results.worker_results,
|
results.worker_results,
|
||||||
@@ -383,21 +399,22 @@ fn compile_into_module_impl<R: Read>(
|
|||||||
clause_code_generator.generate_clause_code(&results.dynamic_clause_map, wam)?;
|
clause_code_generator.generate_clause_code(&results.dynamic_clause_map, wam)?;
|
||||||
|
|
||||||
let top_level_term_dir = results.top_level_term_dirs.consolidate();
|
let top_level_term_dir = results.top_level_term_dirs.consolidate();
|
||||||
|
let module = wam.indices.take_module(module_name).unwrap();
|
||||||
|
|
||||||
add_module(
|
add_module(
|
||||||
wam,
|
wam,
|
||||||
compiler.module.take().unwrap(),
|
module,
|
||||||
indices,
|
indices,
|
||||||
top_level_term_dir,
|
top_level_term_dir,
|
||||||
);
|
);
|
||||||
|
|
||||||
wam.code_repo.code.extend(results.in_situ_code.into_iter());
|
wam.code_repo.code.extend(results.in_situ_code.into_iter());
|
||||||
|
|
||||||
clause_code_generator.add_clause_code(wam, results.dynamic_clause_map);
|
clause_code_generator.add_clause_code(wam, results.dynamic_clause_map);
|
||||||
|
|
||||||
Ok(compiler.drop_expansions(&mut wam.code_repo))
|
Ok(compiler.drop_expansions(&mut wam.code_repo))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
pub struct GatherResult {
|
pub struct GatherResult {
|
||||||
dynamic_clause_map: DynamicClauseMap,
|
dynamic_clause_map: DynamicClauseMap,
|
||||||
pub(crate) worker_results: Vec<PredicateCompileQueue>,
|
pub(crate) worker_results: Vec<PredicateCompileQueue>,
|
||||||
@@ -412,6 +429,7 @@ pub struct GatherResult {
|
|||||||
in_situ_module_dir: ModuleStubDir,
|
in_situ_module_dir: ModuleStubDir,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
pub struct ClauseCodeGenerator {
|
pub struct ClauseCodeGenerator {
|
||||||
len_offset: usize,
|
len_offset: usize,
|
||||||
code: Code,
|
code: Code,
|
||||||
@@ -451,6 +469,7 @@ impl ClauseCodeGenerator {
|
|||||||
vec![Box::new(head.clone()), Box::new(tail.clone())],
|
vec![Box::new(head.clone()), Box::new(tail.clone())],
|
||||||
None,
|
None,
|
||||||
);
|
);
|
||||||
|
|
||||||
PredicateClause::Fact(clause, 0, 0)
|
PredicateClause::Fact(clause, 0, 0)
|
||||||
})
|
})
|
||||||
.collect(),
|
.collect(),
|
||||||
@@ -518,6 +537,7 @@ fn insert_or_refresh_term_dir_quantum(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
pub struct ListingCompiler {
|
pub struct ListingCompiler {
|
||||||
module: Option<Module>,
|
module: Option<Module>,
|
||||||
user_term_dir: TermDir,
|
user_term_dir: TermDir,
|
||||||
@@ -548,8 +568,8 @@ fn add_module(
|
|||||||
term_dir: TermDir,
|
term_dir: TermDir,
|
||||||
) {
|
) {
|
||||||
module.code_dir.extend(indices.code_dir);
|
module.code_dir.extend(indices.code_dir);
|
||||||
module.op_dir.extend(indices.op_dir.into_iter());
|
module.op_dir.extend(indices.op_dir);
|
||||||
module.term_dir.extend(term_dir.into_iter());
|
module.term_dir.extend(term_dir);
|
||||||
|
|
||||||
wam.add_in_situ_module_dir(indices.module_dir);
|
wam.add_in_situ_module_dir(indices.module_dir);
|
||||||
wam.add_module(module);
|
wam.add_module(module);
|
||||||
@@ -568,7 +588,7 @@ fn add_non_module_code(
|
|||||||
clause_code_generator.generate_clause_code(&dynamic_clause_map, wam)?;
|
clause_code_generator.generate_clause_code(&dynamic_clause_map, wam)?;
|
||||||
|
|
||||||
add_toplevel(wam, indices, term_dir);
|
add_toplevel(wam, indices, term_dir);
|
||||||
wam.code_repo.code.extend(code.into_iter());
|
wam.code_repo.code.extend(code);
|
||||||
clause_code_generator.add_clause_code(wam, dynamic_clause_map);
|
clause_code_generator.add_clause_code(wam, dynamic_clause_map);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -582,21 +602,22 @@ fn load_library(
|
|||||||
) -> Result<ClauseName, SessionError> {
|
) -> Result<ClauseName, SessionError> {
|
||||||
match LIBRARIES.borrow().get(name.as_str()) {
|
match LIBRARIES.borrow().get(name.as_str()) {
|
||||||
Some(code) => {
|
Some(code) => {
|
||||||
let mut lib_path = current_dir();
|
let listing_src = ListingSource::User;
|
||||||
|
|
||||||
lib_path.pop();
|
|
||||||
lib_path.push("lib");
|
|
||||||
|
|
||||||
let listing_src = ListingSource::from_file_and_path(name, lib_path);
|
|
||||||
|
|
||||||
load_module(
|
load_module(
|
||||||
wam,
|
wam,
|
||||||
parsing_stream(code.as_bytes()),
|
Stream::from(*code),
|
||||||
suppress_warnings,
|
suppress_warnings,
|
||||||
&listing_src,
|
&listing_src,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
None => Err(SessionError::ModuleNotFound)
|
None => {
|
||||||
|
let err = ExistenceError::ModuleSource(ModuleSource::Library(
|
||||||
|
name.clone()
|
||||||
|
));
|
||||||
|
|
||||||
|
Err(SessionError::ExistenceError(err))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -614,7 +635,7 @@ impl ListingCompiler {
|
|||||||
.term_dir_entry_len((clause_name!("term_expansion"), 2)),
|
.term_dir_entry_len((clause_name!("term_expansion"), 2)),
|
||||||
orig_goal_expansion_lens: code_repo
|
orig_goal_expansion_lens: code_repo
|
||||||
.term_dir_entry_len((clause_name!("goal_expansion"), 2)),
|
.term_dir_entry_len((clause_name!("goal_expansion"), 2)),
|
||||||
initialization_goals: (vec![], VecDeque::from(vec![])),
|
initialization_goals: (vec![], VecDeque::from(vec![])),
|
||||||
suppress_warnings,
|
suppress_warnings,
|
||||||
listing_src
|
listing_src
|
||||||
}
|
}
|
||||||
@@ -682,7 +703,11 @@ impl ListingCompiler {
|
|||||||
|
|
||||||
Ok(wam_indices.insert_module(submodule))
|
Ok(wam_indices.insert_module(submodule))
|
||||||
} else {
|
} else {
|
||||||
Err(SessionError::ModuleNotFound)
|
let err = ExistenceError::ModuleSource(ModuleSource::File(
|
||||||
|
module_name,
|
||||||
|
));
|
||||||
|
|
||||||
|
Err(SessionError::ExistenceError(err))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -716,7 +741,11 @@ impl ListingCompiler {
|
|||||||
|
|
||||||
Ok(wam_indices.insert_module(submodule))
|
Ok(wam_indices.insert_module(submodule))
|
||||||
} else {
|
} else {
|
||||||
Err(SessionError::ModuleNotFound)
|
let err = ExistenceError::ModuleSource(ModuleSource::File(
|
||||||
|
module_name
|
||||||
|
));
|
||||||
|
|
||||||
|
Err(SessionError::ExistenceError(err))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -729,14 +758,14 @@ impl ListingCompiler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn generate_init_goal_code(
|
fn generate_init_goal_code(
|
||||||
&mut self,
|
&mut self,
|
||||||
) -> Result<Code, SessionError> {
|
) -> Result<Code, SessionError> {
|
||||||
let query_terms = mem::replace(&mut self.initialization_goals.0, vec![]);
|
let query_terms = mem::replace(&mut self.initialization_goals.0, vec![]);
|
||||||
let queue = mem::replace(&mut self.initialization_goals.1, VecDeque::new());
|
let queue = mem::replace(&mut self.initialization_goals.1, VecDeque::new());
|
||||||
|
|
||||||
compile_query(query_terms, queue)
|
compile_query(query_terms, queue)
|
||||||
.map(|(code, _)| code)
|
.map(|(code, _)| code)
|
||||||
.map_err(SessionError::from)
|
.map_err(SessionError::from)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_code_index(
|
fn set_code_index(
|
||||||
@@ -875,7 +904,7 @@ impl ListingCompiler {
|
|||||||
.or_insert((Predicate::new(), VecDeque::from(vec![])));
|
.or_insert((Predicate::new(), VecDeque::from(vec![])));
|
||||||
|
|
||||||
len += 1;
|
len += 1;
|
||||||
queue_len += queue_len;
|
queue_len += queue.len();
|
||||||
|
|
||||||
(preds.0).0.push(clause);
|
(preds.0).0.push(clause);
|
||||||
preds.1.extend(queue.into_iter());
|
preds.1.extend(queue.into_iter());
|
||||||
@@ -952,12 +981,12 @@ impl ListingCompiler {
|
|||||||
Err(SessionError::from(ParserError::InvalidModuleDecl))
|
Err(SessionError::from(ParserError::InvalidModuleDecl))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Declaration::ModuleInitialization(query_terms, queue) => {
|
Declaration::ModuleInitialization(query_terms, queue) => {
|
||||||
self.initialization_goals.0.extend(query_terms.into_iter());
|
self.initialization_goals.0.extend(query_terms.into_iter());
|
||||||
self.initialization_goals.1.extend(queue.into_iter());
|
self.initialization_goals.1.extend(queue.into_iter());
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
Declaration::MultiFile(..) => {
|
Declaration::MultiFile(..) => {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -968,6 +997,10 @@ impl ListingCompiler {
|
|||||||
Declaration::Op(op_decl) => {
|
Declaration::Op(op_decl) => {
|
||||||
self.submit_op(wam, indices, &op_decl)
|
self.submit_op(wam, indices, &op_decl)
|
||||||
}
|
}
|
||||||
|
Declaration::SetPrologFlag(dbl_quotes) => {
|
||||||
|
wam.machine_st.flags.double_quotes = dbl_quotes;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
Declaration::UseModule(ModuleSource::Library(name)) => {
|
Declaration::UseModule(ModuleSource::Library(name)) => {
|
||||||
let name = if !wam.indices.modules.contains_key(&name) {
|
let name = if !wam.indices.modules.contains_key(&name) {
|
||||||
load_library(wam, name, true)?
|
load_library(wam, name, true)?
|
||||||
@@ -1018,10 +1051,10 @@ impl ListingCompiler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn setup_multifile_decl<R: Read>(
|
fn setup_multifile_decl(
|
||||||
&self,
|
&self,
|
||||||
indicator: MultiFileIndicator,
|
indicator: MultiFileIndicator,
|
||||||
worker: &mut TopLevelBatchWorker<R>,
|
worker: &mut TopLevelBatchWorker,
|
||||||
) -> Result<(), SessionError> {
|
) -> Result<(), SessionError> {
|
||||||
match indicator {
|
match indicator {
|
||||||
MultiFileIndicator::LocalScoped(name, arity) => {
|
MultiFileIndicator::LocalScoped(name, arity) => {
|
||||||
@@ -1042,7 +1075,11 @@ impl ListingCompiler {
|
|||||||
insert_or_refresh_term_dir_quantum(term_dir, key, term_dirs);
|
insert_or_refresh_term_dir_quantum(term_dir, key, term_dirs);
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
return Err(SessionError::ModuleNotFound);
|
let err = ExistenceError::ModuleSource(ModuleSource::File(
|
||||||
|
module_name,
|
||||||
|
));
|
||||||
|
|
||||||
|
return Err(SessionError::ExistenceError(err));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1051,10 +1088,10 @@ impl ListingCompiler {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn process_and_commit_decl<R: Read>(
|
fn process_and_commit_decl(
|
||||||
&mut self,
|
&mut self,
|
||||||
decl: Declaration,
|
decl: Declaration,
|
||||||
worker: &mut TopLevelBatchWorker<R>,
|
worker: &mut TopLevelBatchWorker,
|
||||||
indices: &mut IndexStore,
|
indices: &mut IndexStore,
|
||||||
flags: MachineFlags,
|
flags: MachineFlags,
|
||||||
) -> Result<(), SessionError> {
|
) -> Result<(), SessionError> {
|
||||||
@@ -1067,9 +1104,9 @@ impl ListingCompiler {
|
|||||||
.entry((name.clone(), arity))
|
.entry((name.clone(), arity))
|
||||||
.or_insert(vec![]);
|
.or_insert(vec![]);
|
||||||
|
|
||||||
indices.code_dir
|
indices.code_dir
|
||||||
.entry((name.clone(), arity))
|
.entry((name.clone(), arity))
|
||||||
.or_insert(CodeIndex::dynamic_undefined(self.get_module_name()));
|
.or_insert(CodeIndex::dynamic_undefined(self.get_module_name()));
|
||||||
}
|
}
|
||||||
&Declaration::Hook(hook, _, ref queue) if self.module.is_none() => worker
|
&Declaration::Hook(hook, _, ref queue) if self.module.is_none() => worker
|
||||||
.term_stream
|
.term_stream
|
||||||
@@ -1101,15 +1138,16 @@ impl ListingCompiler {
|
|||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn gather_items<R: Read>(
|
pub(crate)
|
||||||
|
fn gather_items(
|
||||||
&mut self,
|
&mut self,
|
||||||
wam: &mut Machine,
|
wam: &mut Machine,
|
||||||
mut src: ParsingStream<R>,
|
src: &mut ParsingStream<Stream>,
|
||||||
indices: &mut IndexStore,
|
indices: &mut IndexStore,
|
||||||
) -> Result<GatherResult, SessionError> {
|
) -> Result<GatherResult, SessionError> {
|
||||||
let flags = wam.machine_flags();
|
let flags = wam.machine_flags();
|
||||||
let atom_tbl = indices.atom_tbl.clone();
|
let atom_tbl = indices.atom_tbl.clone();
|
||||||
let mut worker = TopLevelBatchWorker::new(&mut src, atom_tbl.clone(), flags, wam);
|
let mut worker = TopLevelBatchWorker::new(src, atom_tbl.clone(), flags, wam);
|
||||||
|
|
||||||
let mut toplevel_results = vec![];
|
let mut toplevel_results = vec![];
|
||||||
let mut toplevel_indices = default_index_store!(atom_tbl.clone());
|
let mut toplevel_indices = default_index_store!(atom_tbl.clone());
|
||||||
@@ -1246,6 +1284,17 @@ fn compile_work_impl(
|
|||||||
.filter(|(name, _)| name.owning_module().as_str() != "builtins")
|
.filter(|(name, _)| name.owning_module().as_str() != "builtins")
|
||||||
.map(ModuleExport::PredicateKey)
|
.map(ModuleExport::PredicateKey)
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
|
module.module_decl.exports.extend(
|
||||||
|
indices.op_dir.iter()
|
||||||
|
.map(|((name, _), OpDirValue (shared_op_desc, _))|
|
||||||
|
ModuleExport::OpDecl(OpDecl(
|
||||||
|
shared_op_desc.prec(),
|
||||||
|
shared_op_desc.assoc(),
|
||||||
|
name.clone(),
|
||||||
|
))
|
||||||
|
)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut clause_code_generator =
|
let mut clause_code_generator =
|
||||||
@@ -1286,7 +1335,7 @@ fn compile_work_impl(
|
|||||||
let init_goal_code = compiler.generate_init_goal_code()?;
|
let init_goal_code = compiler.generate_init_goal_code()?;
|
||||||
|
|
||||||
if init_goal_code.len() > 0 {
|
if init_goal_code.len() > 0 {
|
||||||
if !wam.run_init_code(init_goal_code) {
|
if !wam.run_init_code(init_goal_code) {
|
||||||
println!("Warning: initialization goal for {} failed",
|
println!("Warning: initialization goal for {} failed",
|
||||||
compiler.listing_src.name());
|
compiler.listing_src.name());
|
||||||
}
|
}
|
||||||
@@ -1302,30 +1351,35 @@ fn compile_work_impl(
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn compile_work<R: Read>(
|
fn compile_work(
|
||||||
compiler: &mut ListingCompiler,
|
compiler: &mut ListingCompiler,
|
||||||
wam: &mut Machine,
|
wam: &mut Machine,
|
||||||
src: ParsingStream<R>,
|
src: Stream,
|
||||||
mut indices: IndexStore,
|
mut indices: IndexStore,
|
||||||
) -> EvalSession {
|
) -> EvalSession {
|
||||||
|
let mut stream = try_eval_session!(parsing_stream(src));
|
||||||
|
let src = &mut stream;
|
||||||
let results = try_eval_session!(compiler.gather_items(wam, src, &mut indices));
|
let results = try_eval_session!(compiler.gather_items(wam, src, &mut indices));
|
||||||
|
|
||||||
try_eval_session!(compile_work_impl(compiler, wam, indices, results));
|
try_eval_session!(compile_work_impl(compiler, wam, indices, results));
|
||||||
|
|
||||||
EvalSession::EntrySuccess
|
EvalSession::EntrySuccess
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This is a truncated version of compile_user_module, used for
|
/* This is a truncated version of compile_user_module, used for
|
||||||
compiling code composing special forms, ie. the code that calls
|
compiling code composing special forms, ie. the code that calls
|
||||||
M:verify_attributes on attributed variables. */
|
M:verify_attributes on attributed variables. */
|
||||||
pub fn compile_special_form<R: Read>(
|
pub fn compile_special_form(
|
||||||
wam: &mut Machine,
|
wam: &mut Machine,
|
||||||
src: ParsingStream<R>,
|
src: Stream,
|
||||||
listing_src: ListingSource,
|
listing_src: ListingSource,
|
||||||
) -> Result<usize, SessionError> {
|
) -> Result<usize, SessionError> {
|
||||||
let mut indices = default_index_store!(wam.indices.atom_tbl.clone());
|
let mut indices = default_index_store!(wam.indices.atom_tbl.clone());
|
||||||
setup_indices(wam, clause_name!("builtins"), &mut indices)?;
|
setup_indices(wam, clause_name!("builtins"), &mut indices)?;
|
||||||
|
|
||||||
|
let mut src = parsing_stream(src)?;
|
||||||
let mut compiler = ListingCompiler::new(&wam.code_repo, true, listing_src);
|
let mut compiler = ListingCompiler::new(&wam.code_repo, true, listing_src);
|
||||||
let mut results = compiler.gather_items(wam, src, &mut indices)?;
|
let mut results = compiler.gather_items(wam, &mut src, &mut indices)?;
|
||||||
|
|
||||||
compiler.adapt_in_situ_code(
|
compiler.adapt_in_situ_code(
|
||||||
results.worker_results,
|
results.worker_results,
|
||||||
@@ -1348,9 +1402,9 @@ pub fn compile_special_form<R: Read>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn compile_listing<R: Read>(
|
pub fn compile_listing(
|
||||||
wam: &mut Machine,
|
wam: &mut Machine,
|
||||||
src: ParsingStream<R>,
|
src: Stream,
|
||||||
indices: IndexStore,
|
indices: IndexStore,
|
||||||
suppress_warnings: bool,
|
suppress_warnings: bool,
|
||||||
listing_src: ListingSource,
|
listing_src: ListingSource,
|
||||||
@@ -1373,20 +1427,24 @@ pub(super) fn setup_indices(
|
|||||||
module: ClauseName,
|
module: ClauseName,
|
||||||
indices: &mut IndexStore,
|
indices: &mut IndexStore,
|
||||||
) -> Result<(), SessionError> {
|
) -> Result<(), SessionError> {
|
||||||
if let Some(module) = wam.indices.take_module(module) {
|
if let Some(module) = wam.indices.take_module(module.clone()) {
|
||||||
let flags = wam.machine_flags();
|
let flags = wam.machine_flags();
|
||||||
let result = indices.use_module(&mut wam.code_repo, flags, &module);
|
let result = indices.use_module(&mut wam.code_repo, flags, &module);
|
||||||
|
|
||||||
wam.indices.insert_module(module);
|
wam.indices.insert_module(module);
|
||||||
result
|
result
|
||||||
} else {
|
} else {
|
||||||
Err(SessionError::ModuleNotFound)
|
let err = ExistenceError::ModuleSource(ModuleSource::Library(
|
||||||
|
module
|
||||||
|
));
|
||||||
|
|
||||||
|
Err(SessionError::ExistenceError(err))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn compile_user_module<R: Read>(
|
pub fn compile_user_module(
|
||||||
wam: &mut Machine,
|
wam: &mut Machine,
|
||||||
src: ParsingStream<R>,
|
src: Stream,
|
||||||
suppress_warnings: bool,
|
suppress_warnings: bool,
|
||||||
listing_src: ListingSource,
|
listing_src: ListingSource,
|
||||||
) -> EvalSession {
|
) -> EvalSession {
|
||||||
314
src/machine/copier.rs
Normal file
314
src/machine/copier.rs
Normal file
@@ -0,0 +1,314 @@
|
|||||||
|
use crate::machine::machine_indices::*;
|
||||||
|
use crate::machine::stack::*;
|
||||||
|
|
||||||
|
use std::mem;
|
||||||
|
use std::ops::IndexMut;
|
||||||
|
|
||||||
|
type Trail = Vec<(Ref, HeapCellValue)>;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
pub enum AttrVarPolicy {
|
||||||
|
DeepCopy,
|
||||||
|
StripAttributes
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate)
|
||||||
|
trait CopierTarget: IndexMut<usize, Output = HeapCellValue> {
|
||||||
|
fn deref(&self, val: Addr) -> Addr;
|
||||||
|
fn push(&mut self, val: HeapCellValue);
|
||||||
|
fn stack(&mut self) -> &mut Stack;
|
||||||
|
fn store(&self, val: Addr) -> Addr;
|
||||||
|
fn threshold(&self) -> usize;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate)
|
||||||
|
fn copy_term<T: CopierTarget>(target: T, addr: Addr, attr_var_policy: AttrVarPolicy) {
|
||||||
|
let mut copy_term_state = CopyTermState::new(target, attr_var_policy);
|
||||||
|
copy_term_state.copy_term_impl(addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct CopyTermState<T: CopierTarget> {
|
||||||
|
trail: Trail,
|
||||||
|
scan: usize,
|
||||||
|
old_h: usize,
|
||||||
|
target: T,
|
||||||
|
attr_var_policy: AttrVarPolicy,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: CopierTarget> CopyTermState<T> {
|
||||||
|
fn new(target: T, attr_var_policy: AttrVarPolicy) -> Self {
|
||||||
|
CopyTermState {
|
||||||
|
trail: Trail::new(),
|
||||||
|
scan: 0,
|
||||||
|
old_h: target.threshold(),
|
||||||
|
target,
|
||||||
|
attr_var_policy
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn value_at_scan(&mut self) -> &mut HeapCellValue {
|
||||||
|
let scan = self.scan;
|
||||||
|
&mut self.target[scan]
|
||||||
|
}
|
||||||
|
|
||||||
|
fn trail_list_cell(&mut self, addr: usize, threshold: usize) {
|
||||||
|
let trail_item = mem::replace(
|
||||||
|
&mut self.target[addr],
|
||||||
|
HeapCellValue::Addr(Addr::Lis(threshold)),
|
||||||
|
);
|
||||||
|
|
||||||
|
self.trail.push((
|
||||||
|
Ref::HeapCell(addr),
|
||||||
|
trail_item,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn copy_list(&mut self, addr: usize) {
|
||||||
|
for offset in 0 .. 2 {
|
||||||
|
if let Addr::Lis(h) = self.target[addr + offset].as_addr(addr + offset) {
|
||||||
|
if h >= self.old_h {
|
||||||
|
*self.value_at_scan() = HeapCellValue::Addr(Addr::Lis(h));
|
||||||
|
self.scan += 1;
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let threshold = self.target.threshold();
|
||||||
|
|
||||||
|
*self.value_at_scan() = HeapCellValue::Addr(Addr::Lis(threshold));
|
||||||
|
|
||||||
|
for i in 0 .. 2 {
|
||||||
|
let hcv = self.target[addr + i].context_free_clone();
|
||||||
|
self.target.push(hcv);
|
||||||
|
}
|
||||||
|
|
||||||
|
let cdr = self.target.store(self.target.deref(Addr::HeapCell(addr + 1)));
|
||||||
|
|
||||||
|
if !cdr.is_ref() {
|
||||||
|
self.trail_list_cell(addr + 1, threshold);
|
||||||
|
} else {
|
||||||
|
let car = self.target.store(self.target.deref(Addr::HeapCell(addr)));
|
||||||
|
|
||||||
|
if !car.is_ref() {
|
||||||
|
self.trail_list_cell(addr, threshold);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.scan += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
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, n));
|
||||||
|
self.scan += 1;
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let threshold = self.target.threshold();
|
||||||
|
|
||||||
|
*self.value_at_scan() =
|
||||||
|
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(0), has_tail)
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
self.target.push(HeapCellValue::PartialString(pstr, has_tail));
|
||||||
|
|
||||||
|
let replacement = HeapCellValue::Addr(Addr::PStrLocation(threshold, n));
|
||||||
|
|
||||||
|
let trail_item = mem::replace(
|
||||||
|
&mut self.target[addr],
|
||||||
|
replacement,
|
||||||
|
);
|
||||||
|
|
||||||
|
self.trail.push((
|
||||||
|
Ref::HeapCell(addr),
|
||||||
|
trail_item,
|
||||||
|
));
|
||||||
|
|
||||||
|
if has_tail {
|
||||||
|
let tail_addr = self.target[addr + 1].as_addr(addr + 1);
|
||||||
|
self.target.push(HeapCellValue::Addr(tail_addr));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn reinstantiate_var(&mut self, addr: Addr, frontier: usize) {
|
||||||
|
match addr {
|
||||||
|
Addr::HeapCell(h) => {
|
||||||
|
self.target[frontier] = HeapCellValue::Addr(Addr::HeapCell(frontier));
|
||||||
|
self.target[h] = HeapCellValue::Addr(Addr::HeapCell(frontier));
|
||||||
|
|
||||||
|
self.trail.push((
|
||||||
|
Ref::HeapCell(h),
|
||||||
|
HeapCellValue::Addr(Addr::HeapCell(h)),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
Addr::StackCell(fr, sc) => {
|
||||||
|
self.target[frontier] = HeapCellValue::Addr(Addr::HeapCell(frontier));
|
||||||
|
self.target.stack().index_and_frame_mut(fr)[sc] = Addr::HeapCell(frontier);
|
||||||
|
|
||||||
|
self.trail.push((
|
||||||
|
Ref::StackCell(fr, sc),
|
||||||
|
HeapCellValue::Addr(Addr::StackCell(fr, sc)),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
Addr::AttrVar(h) => {
|
||||||
|
let threshold = if let AttrVarPolicy::DeepCopy = self.attr_var_policy {
|
||||||
|
self.target.threshold()
|
||||||
|
} else {
|
||||||
|
frontier
|
||||||
|
};
|
||||||
|
|
||||||
|
self.target[frontier] = HeapCellValue::Addr(Addr::HeapCell(threshold));
|
||||||
|
self.target[h] = HeapCellValue::Addr(Addr::HeapCell(threshold));
|
||||||
|
|
||||||
|
self.trail.push((
|
||||||
|
Ref::AttrVar(h),
|
||||||
|
HeapCellValue::Addr(Addr::AttrVar(h)),
|
||||||
|
));
|
||||||
|
|
||||||
|
if let AttrVarPolicy::DeepCopy = self.attr_var_policy {
|
||||||
|
self.target.push(HeapCellValue::Addr(Addr::AttrVar(threshold)));
|
||||||
|
|
||||||
|
let list_val = self.target[h + 1].context_free_clone();
|
||||||
|
self.target.push(list_val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn copy_var(&mut self, addr: Addr) {
|
||||||
|
let rd = self.target.store(self.target.deref(addr));
|
||||||
|
|
||||||
|
match rd {
|
||||||
|
Addr::AttrVar(h) | Addr::HeapCell(h) if h >= self.old_h => {
|
||||||
|
*self.value_at_scan() = HeapCellValue::Addr(rd);
|
||||||
|
self.scan += 1;
|
||||||
|
}
|
||||||
|
_ if addr == rd => {
|
||||||
|
self.reinstantiate_var(addr, self.scan);
|
||||||
|
self.scan += 1;
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
*self.value_at_scan() = HeapCellValue::Addr(rd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn copy_structure(&mut self, addr: usize) {
|
||||||
|
match self.target[addr].context_free_clone() {
|
||||||
|
HeapCellValue::NamedStr(arity, name, fixity) => {
|
||||||
|
let threshold = self.target.threshold();
|
||||||
|
|
||||||
|
*self.value_at_scan() = HeapCellValue::Addr(Addr::Str(threshold));
|
||||||
|
|
||||||
|
let trail_item = mem::replace(
|
||||||
|
&mut self.target[addr],
|
||||||
|
HeapCellValue::Addr(Addr::Str(threshold)),
|
||||||
|
);
|
||||||
|
|
||||||
|
self.trail.push((
|
||||||
|
Ref::HeapCell(addr),
|
||||||
|
trail_item,
|
||||||
|
));
|
||||||
|
|
||||||
|
self.target.push(HeapCellValue::NamedStr(arity, name, fixity));
|
||||||
|
|
||||||
|
for i in 0..arity {
|
||||||
|
let hcv = self.target[addr + 1 + i].context_free_clone();
|
||||||
|
self.target.push(hcv);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
HeapCellValue::Addr(Addr::Str(addr)) => {
|
||||||
|
*self.value_at_scan() = HeapCellValue::Addr(Addr::Str(addr))
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.scan += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn copy_term_impl(&mut self, addr: Addr) {
|
||||||
|
self.scan = self.target.threshold();
|
||||||
|
self.target.push(HeapCellValue::Addr(addr));
|
||||||
|
|
||||||
|
while self.scan < self.target.threshold() {
|
||||||
|
match self.value_at_scan() {
|
||||||
|
&mut HeapCellValue::Addr(addr) => {
|
||||||
|
match addr {
|
||||||
|
Addr::Con(h) => {
|
||||||
|
let addr = self.target[h].as_addr(h);
|
||||||
|
|
||||||
|
if addr == Addr::Con(h) {
|
||||||
|
*self.value_at_scan() = self.target[h].context_free_clone();
|
||||||
|
} else {
|
||||||
|
*self.value_at_scan() = HeapCellValue::Addr(addr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Addr::Lis(h) => {
|
||||||
|
if h >= self.old_h {
|
||||||
|
self.scan += 1;
|
||||||
|
} else {
|
||||||
|
self.copy_list(h);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
addr @ Addr::AttrVar(_) |
|
||||||
|
addr @ Addr::HeapCell(_) |
|
||||||
|
addr @ Addr::StackCell(..) => {
|
||||||
|
self.copy_var(addr);
|
||||||
|
}
|
||||||
|
Addr::Str(addr) => {
|
||||||
|
self.copy_structure(addr);
|
||||||
|
}
|
||||||
|
Addr::PStrLocation(addr, n) => {
|
||||||
|
self.copy_partial_string(addr, n);
|
||||||
|
}
|
||||||
|
Addr::Stream(h) => {
|
||||||
|
*self.value_at_scan() = self.target[h].context_free_clone();
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
self.scan += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
self.scan += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.unwind_trail();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn unwind_trail(&mut self) {
|
||||||
|
for (r, value) in self.trail.drain(0..) {
|
||||||
|
match r {
|
||||||
|
Ref::AttrVar(h) | Ref::HeapCell(h) =>
|
||||||
|
self.target[h] = value,
|
||||||
|
Ref::StackCell(fr, sc) =>
|
||||||
|
self.target.stack().index_and_frame_mut(fr)[sc] = value.as_addr(0),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,11 +1,12 @@
|
|||||||
use prolog_parser::ast::*;
|
use crate::prolog_parser::ast::*;
|
||||||
|
|
||||||
use crate::prolog::heap_print::*;
|
use crate::heap_print::*;
|
||||||
use crate::prolog::machine::compile::*;
|
use crate::machine::*;
|
||||||
use crate::prolog::machine::machine_errors::*;
|
use crate::machine::compile::*;
|
||||||
use crate::prolog::machine::*;
|
use crate::machine::machine_errors::*;
|
||||||
|
use crate::machine::streams::*;
|
||||||
|
|
||||||
use std::io::Read;
|
use std::convert::TryFrom;
|
||||||
|
|
||||||
impl Machine {
|
impl Machine {
|
||||||
pub(super) fn atom_tbl_of(&self, name: &ClauseName) -> TabledData<Atom> {
|
pub(super) fn atom_tbl_of(&self, name: &ClauseName) -> TabledData<Atom> {
|
||||||
@@ -15,9 +16,9 @@ impl Machine {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn compile_into_machine<R: Read>(
|
fn compile_into_machine(
|
||||||
&mut self,
|
&mut self,
|
||||||
src: ParsingStream<R>,
|
src: Stream,
|
||||||
name: ClauseName,
|
name: ClauseName,
|
||||||
arity: usize,
|
arity: usize,
|
||||||
) -> EvalSession {
|
) -> EvalSession {
|
||||||
@@ -42,13 +43,38 @@ impl Machine {
|
|||||||
let arity = self.machine_st[arity].clone();
|
let arity = self.machine_st[arity].clone();
|
||||||
|
|
||||||
let name = match self.machine_st.store(self.machine_st.deref(name)) {
|
let name = match self.machine_st.store(self.machine_st.deref(name)) {
|
||||||
Addr::Con(Constant::Atom(name, _)) => name,
|
Addr::Con(h) =>
|
||||||
|
if let HeapCellValue::Atom(ref name, _) = &self.machine_st.heap[h] {
|
||||||
|
name.clone()
|
||||||
|
} else {
|
||||||
|
unreachable!()
|
||||||
|
},
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let arity = match self.machine_st.store(self.machine_st.deref(arity)) {
|
let arity = match self.machine_st.store(self.machine_st.deref(arity)) {
|
||||||
Addr::Con(Constant::Integer(arity)) => arity.to_usize().unwrap(),
|
Addr::Con(h) => {
|
||||||
_ => unreachable!(),
|
match &self.machine_st.heap[h] {
|
||||||
|
HeapCellValue::Integer(ref arity) => {
|
||||||
|
arity.to_usize().unwrap()
|
||||||
|
}
|
||||||
|
HeapCellValue::Addr(Addr::Fixnum(arity)) => {
|
||||||
|
usize::try_from(*arity).unwrap()
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Addr::Fixnum(arity) => {
|
||||||
|
usize::try_from(arity).unwrap()
|
||||||
|
}
|
||||||
|
Addr::Usize(n) => {
|
||||||
|
n
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
(name, arity)
|
(name, arity)
|
||||||
@@ -75,6 +101,18 @@ impl Machine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn make_undefined(&mut self, name: ClauseName, arity: usize) {
|
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)) {
|
if let Some(idx) = self.indices.code_dir.get(&(name, arity)) {
|
||||||
set_code_index!(idx, IndexPtr::DynamicUndefined, clause_name!("user"));
|
set_code_index!(idx, IndexPtr::DynamicUndefined, clause_name!("user"));
|
||||||
}
|
}
|
||||||
@@ -102,16 +140,21 @@ impl Machine {
|
|||||||
let module_addr = self.machine_st[module].clone();
|
let module_addr = self.machine_st[module].clone();
|
||||||
|
|
||||||
let module_name = match self.machine_st.store(self.machine_st.deref(module_addr)) {
|
let module_name = match self.machine_st.store(self.machine_st.deref(module_addr)) {
|
||||||
Addr::Con(Constant::Atom(module, _)) => match self.indices.modules.get_mut(&module) {
|
Addr::Con(h) =>
|
||||||
Some(ref mut module) => {
|
if let HeapCellValue::Atom(ref module, _) = &self.machine_st.heap[h] {
|
||||||
module.code_dir.remove(&(name.clone(), arity));
|
match self.indices.modules.get_mut(module) {
|
||||||
module.module_decl.name.clone()
|
Some(ref mut module) => {
|
||||||
}
|
module.code_dir.remove(&(name.clone(), arity));
|
||||||
_ => {
|
module.module_decl.name.clone()
|
||||||
self.machine_st.fail = true;
|
}
|
||||||
return;
|
_ => {
|
||||||
}
|
self.machine_st.fail = true;
|
||||||
},
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
unreachable!()
|
||||||
|
},
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -130,7 +173,12 @@ impl Machine {
|
|||||||
) {
|
) {
|
||||||
let machine_st = mem::replace(&mut self.machine_st, MachineState::new());
|
let machine_st = mem::replace(&mut self.machine_st, MachineState::new());
|
||||||
|
|
||||||
let result = self.compile_into_machine(parsing_stream(pred_str.as_bytes()), name, arity);
|
let result = self.compile_into_machine(
|
||||||
|
Stream::from(pred_str),
|
||||||
|
name,
|
||||||
|
arity,
|
||||||
|
);
|
||||||
|
|
||||||
self.machine_st = machine_st;
|
self.machine_st = machine_st;
|
||||||
|
|
||||||
if let EvalSession::Error(err) = result {
|
if let EvalSession::Error(err) = result {
|
||||||
@@ -158,21 +206,34 @@ impl Machine {
|
|||||||
place.push_to_queue(&mut addrs, added_clause);
|
place.push_to_queue(&mut addrs, added_clause);
|
||||||
self.print_new_dynamic_clause(addrs, name.clone(), arity)
|
self.print_new_dynamic_clause(addrs, name.clone(), arity)
|
||||||
}
|
}
|
||||||
Err(err) => return self.machine_st.throw_exception(err),
|
Err(err) => {
|
||||||
|
return self.machine_st.throw_exception(err);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
self.handle_eval_result_from_dynamic_compile(pred_str, name, arity, place.predicate_name());
|
self.handle_eval_result_from_dynamic_compile(
|
||||||
|
pred_str,
|
||||||
|
name,
|
||||||
|
arity,
|
||||||
|
place.predicate_name(),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_module_atom_tbl(&mut self, module_addr: Addr, name: &mut ClauseName) -> bool {
|
fn set_module_atom_tbl(&mut self, module_addr: Addr, name: &mut ClauseName) -> bool {
|
||||||
let atom_tbl = match self.machine_st.store(self.machine_st.deref(module_addr)) {
|
let atom_tbl = match self.machine_st.store(self.machine_st.deref(module_addr)) {
|
||||||
Addr::Con(Constant::Atom(module, _)) => match self.indices.modules.get(&module) {
|
Addr::Con(h) =>
|
||||||
Some(ref module) => module.atom_tbl.clone(),
|
if let HeapCellValue::Atom(ref module, _) = &self.machine_st.heap[h] {
|
||||||
None => {
|
match self.indices.modules.get(module) {
|
||||||
|
Some(ref module) => module.atom_tbl.clone(),
|
||||||
|
None => {
|
||||||
|
self.machine_st.fail = true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
self.machine_st.fail = true;
|
self.machine_st.fail = true;
|
||||||
return false;
|
return false;
|
||||||
}
|
},
|
||||||
},
|
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -200,8 +261,24 @@ impl Machine {
|
|||||||
fn retract_from_dynamic_predicate_in_module(&mut self) {
|
fn retract_from_dynamic_predicate_in_module(&mut self) {
|
||||||
let index = self.machine_st[temp_v!(3)].clone();
|
let index = self.machine_st[temp_v!(3)].clone();
|
||||||
let index = match self.machine_st.store(self.machine_st.deref(index)) {
|
let index = match self.machine_st.store(self.machine_st.deref(index)) {
|
||||||
Addr::Con(Constant::Integer(n)) => n.to_usize().unwrap(),
|
Addr::Con(h) =>
|
||||||
_ => unreachable!(),
|
match &self.machine_st.heap[h] {
|
||||||
|
HeapCellValue::Integer(ref arity) => {
|
||||||
|
arity.to_usize().unwrap()
|
||||||
|
}
|
||||||
|
HeapCellValue::Addr(Addr::Fixnum(arity)) => {
|
||||||
|
usize::try_from(*arity).unwrap()
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Addr::Fixnum(arity) => {
|
||||||
|
usize::try_from(arity).unwrap()
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let (mut name, arity) = self.get_predicate_key(temp_v!(1), temp_v!(2));
|
let (mut name, arity) = self.get_predicate_key(temp_v!(1), temp_v!(2));
|
||||||
@@ -220,7 +297,9 @@ impl Machine {
|
|||||||
|
|
||||||
self.print_new_dynamic_clause(addrs, name.clone(), arity)
|
self.print_new_dynamic_clause(addrs, name.clone(), arity)
|
||||||
}
|
}
|
||||||
Err(err) => return self.machine_st.throw_exception(err),
|
Err(err) => {
|
||||||
|
return self.machine_st.throw_exception(err);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
self.handle_eval_result_from_dynamic_compile(
|
self.handle_eval_result_from_dynamic_compile(
|
||||||
@@ -235,8 +314,28 @@ impl Machine {
|
|||||||
fn retract_from_dynamic_predicate(&mut self) {
|
fn retract_from_dynamic_predicate(&mut self) {
|
||||||
let index = self.machine_st[temp_v!(3)].clone();
|
let index = self.machine_st[temp_v!(3)].clone();
|
||||||
let index = match self.machine_st.store(self.machine_st.deref(index)) {
|
let index = match self.machine_st.store(self.machine_st.deref(index)) {
|
||||||
Addr::Con(Constant::Integer(n)) => n.to_usize().unwrap(),
|
Addr::Con(h) => {
|
||||||
_ => unreachable!(),
|
match &self.machine_st.heap[h] {
|
||||||
|
HeapCellValue::Integer(ref arity) => {
|
||||||
|
arity.to_usize().unwrap()
|
||||||
|
}
|
||||||
|
HeapCellValue::Addr(Addr::Fixnum(arity)) => {
|
||||||
|
usize::try_from(*arity).unwrap()
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Addr::Usize(n) => {
|
||||||
|
n
|
||||||
|
}
|
||||||
|
Addr::Fixnum(n) => {
|
||||||
|
usize::try_from(n).unwrap()
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let (name, arity) = self.get_predicate_key(temp_v!(1), temp_v!(2));
|
let (name, arity) = self.get_predicate_key(temp_v!(1), temp_v!(2));
|
||||||
@@ -253,7 +352,9 @@ impl Machine {
|
|||||||
|
|
||||||
self.print_new_dynamic_clause(addrs, name.clone(), arity)
|
self.print_new_dynamic_clause(addrs, name.clone(), arity)
|
||||||
}
|
}
|
||||||
Err(err) => return self.machine_st.throw_exception(err),
|
Err(err) => {
|
||||||
|
return self.machine_st.throw_exception(err);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
self.handle_eval_result_from_dynamic_compile(
|
self.handle_eval_result_from_dynamic_compile(
|
||||||
@@ -1,15 +1,17 @@
|
|||||||
use core::marker::PhantomData;
|
use core::marker::PhantomData;
|
||||||
|
|
||||||
use crate::prolog_parser::ast::*;
|
use crate::prolog_parser::ast::Constant;
|
||||||
|
|
||||||
use crate::prolog::machine::machine_indices::*;
|
use crate::machine::machine_indices::*;
|
||||||
use crate::prolog::machine::partial_string::*;
|
use crate::machine::partial_string::*;
|
||||||
use crate::prolog::machine::raw_block::*;
|
use crate::machine::raw_block::*;
|
||||||
|
|
||||||
|
use std::convert::TryFrom;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use std::ops::{Index, IndexMut};
|
use std::ops::{Index, IndexMut};
|
||||||
use std::ptr;
|
use std::ptr;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
pub(crate) struct StandardHeapTraits {}
|
pub(crate) struct StandardHeapTraits {}
|
||||||
|
|
||||||
impl RawBlockTraits for StandardHeapTraits {
|
impl RawBlockTraits for StandardHeapTraits {
|
||||||
@@ -24,6 +26,7 @@ impl RawBlockTraits for StandardHeapTraits {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
pub(crate) struct HeapTemplate<T: RawBlockTraits> {
|
pub(crate) struct HeapTemplate<T: RawBlockTraits> {
|
||||||
buf: RawBlock<T>,
|
buf: RawBlock<T>,
|
||||||
_marker: PhantomData<HeapCellValue>,
|
_marker: PhantomData<HeapCellValue>,
|
||||||
@@ -38,13 +41,14 @@ impl<T: RawBlockTraits> Drop for HeapTemplate<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
pub(crate)
|
pub(crate)
|
||||||
struct HeapIntoIterator<T: RawBlockTraits> {
|
struct HeapIntoIter<T: RawBlockTraits> {
|
||||||
offset: usize,
|
offset: usize,
|
||||||
buf: RawBlock<T>,
|
buf: RawBlock<T>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: RawBlockTraits> Drop for HeapIntoIterator<T> {
|
impl<T: RawBlockTraits> Drop for HeapIntoIter<T> {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
let mut heap =
|
let mut heap =
|
||||||
HeapTemplate { buf: self.buf.take(), _marker: PhantomData };
|
HeapTemplate { buf: self.buf.take(), _marker: PhantomData };
|
||||||
@@ -54,7 +58,7 @@ impl<T: RawBlockTraits> Drop for HeapIntoIterator<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: RawBlockTraits> Iterator for HeapIntoIterator<T> {
|
impl<T: RawBlockTraits> Iterator for HeapIntoIter<T> {
|
||||||
type Item = HeapCellValue;
|
type Item = HeapCellValue;
|
||||||
|
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
@@ -71,20 +75,21 @@ impl<T: RawBlockTraits> Iterator for HeapIntoIterator<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
pub(crate)
|
pub(crate)
|
||||||
struct HeapIterator<'a, T: RawBlockTraits> {
|
struct HeapIter<'a, T: RawBlockTraits> {
|
||||||
offset: usize,
|
offset: usize,
|
||||||
buf: &'a RawBlock<T>,
|
buf: &'a RawBlock<T>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, T: RawBlockTraits> HeapIterator<'a, T> {
|
impl<'a, T: RawBlockTraits> HeapIter<'a, T> {
|
||||||
pub(crate)
|
pub(crate)
|
||||||
fn new(buf: &'a RawBlock<T>, offset: usize) -> Self {
|
fn new(buf: &'a RawBlock<T>, offset: usize) -> Self {
|
||||||
HeapIterator { buf, offset }
|
HeapIter { buf, offset }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, T: RawBlockTraits> Iterator for HeapIterator<'a, T> {
|
impl<'a, T: RawBlockTraits> Iterator for HeapIter<'a, T> {
|
||||||
type Item = &'a HeapCellValue;
|
type Item = &'a HeapCellValue;
|
||||||
|
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
@@ -101,20 +106,29 @@ impl<'a, T: RawBlockTraits> Iterator for HeapIterator<'a, T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
pub(crate)
|
pub(crate)
|
||||||
struct HeapIteratorMut<'a, T: RawBlockTraits> {
|
fn print_heap_terms<'a, I: Iterator<Item = &'a HeapCellValue>>(heap: I, h: usize) {
|
||||||
|
for (index, term) in heap.enumerate() {
|
||||||
|
println!("{} : {}", h + index, term);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub(crate)
|
||||||
|
struct HeapIterMut<'a, T: RawBlockTraits> {
|
||||||
offset: usize,
|
offset: usize,
|
||||||
buf: &'a mut RawBlock<T>,
|
buf: &'a mut RawBlock<T>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, T: RawBlockTraits> HeapIteratorMut<'a, T> {
|
impl<'a, T: RawBlockTraits> HeapIterMut<'a, T> {
|
||||||
pub(crate)
|
pub(crate)
|
||||||
fn new(buf: &'a mut RawBlock<T>, offset: usize) -> Self {
|
fn new(buf: &'a mut RawBlock<T>, offset: usize) -> Self {
|
||||||
HeapIteratorMut { buf, offset }
|
HeapIterMut { buf, offset }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, T: RawBlockTraits> Iterator for HeapIteratorMut<'a, T> {
|
impl<'a, T: RawBlockTraits> Iterator for HeapIterMut<'a, T> {
|
||||||
type Item = &'a mut HeapCellValue;
|
type Item = &'a mut HeapCellValue;
|
||||||
|
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
@@ -140,17 +154,177 @@ impl<T: RawBlockTraits> HeapTemplate<T> {
|
|||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub(crate)
|
pub(crate)
|
||||||
fn push(&mut self, val: HeapCellValue) {
|
fn clone(&self, h: usize) -> HeapCellValue {
|
||||||
unsafe {
|
match &self[h] {
|
||||||
let new_top = self.buf.new_block(mem::size_of::<HeapCellValue>());
|
&HeapCellValue::Addr(addr) => {
|
||||||
ptr::write(self.buf.top as *mut _, val);
|
HeapCellValue::Addr(addr)
|
||||||
self.buf.top = new_top;
|
}
|
||||||
|
&HeapCellValue::Atom(ref name, ref op) => {
|
||||||
|
HeapCellValue::Atom(name.clone(), op.clone())
|
||||||
|
}
|
||||||
|
&HeapCellValue::DBRef(ref db_ref) => {
|
||||||
|
HeapCellValue::DBRef(db_ref.clone())
|
||||||
|
}
|
||||||
|
&HeapCellValue::Integer(ref n) => {
|
||||||
|
HeapCellValue::Integer(n.clone())
|
||||||
|
}
|
||||||
|
&HeapCellValue::NamedStr(arity, ref name, ref op) => {
|
||||||
|
HeapCellValue::NamedStr(arity, name.clone(), op.clone())
|
||||||
|
}
|
||||||
|
&HeapCellValue::PartialString(..) => {
|
||||||
|
HeapCellValue::Addr(Addr::PStrLocation(h, 0))
|
||||||
|
}
|
||||||
|
&HeapCellValue::Rational(ref r) => {
|
||||||
|
HeapCellValue::Rational(r.clone())
|
||||||
|
}
|
||||||
|
&HeapCellValue::Stream(_) => {
|
||||||
|
HeapCellValue::Addr(Addr::Stream(h))
|
||||||
|
}
|
||||||
|
&HeapCellValue::TcpListener(_) => {
|
||||||
|
HeapCellValue::Addr(Addr::TcpListener(h))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub(crate)
|
pub(crate)
|
||||||
fn allocate_pstr(&mut self, mut src: &str) -> Option<Addr> {
|
fn put_complete_string(&mut self, s: &str) -> Addr {
|
||||||
|
if s.is_empty() {
|
||||||
|
return Addr::EmptyList;
|
||||||
|
}
|
||||||
|
|
||||||
|
let addr = self.allocate_pstr(s);
|
||||||
|
self.pop();
|
||||||
|
|
||||||
|
let h = self.h();
|
||||||
|
|
||||||
|
match &mut self[h - 1] {
|
||||||
|
&mut HeapCellValue::PartialString(_, ref mut has_tail) => {
|
||||||
|
*has_tail = false;
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
addr
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub(crate)
|
||||||
|
fn put_constant(&mut self, c: Constant) -> Addr {
|
||||||
|
match c {
|
||||||
|
Constant::Atom(name, op) => {
|
||||||
|
Addr::Con(self.push(HeapCellValue::Atom(name, op)))
|
||||||
|
}
|
||||||
|
Constant::Char(c) => {
|
||||||
|
Addr::Char(c)
|
||||||
|
}
|
||||||
|
Constant::EmptyList => {
|
||||||
|
Addr::EmptyList
|
||||||
|
}
|
||||||
|
Constant::Fixnum(n) => {
|
||||||
|
Addr::Fixnum(n)
|
||||||
|
}
|
||||||
|
Constant::Integer(n) => {
|
||||||
|
Addr::Con(self.push(HeapCellValue::Integer(n)))
|
||||||
|
}
|
||||||
|
Constant::Rational(r) => {
|
||||||
|
Addr::Con(self.push(HeapCellValue::Rational(r)))
|
||||||
|
}
|
||||||
|
Constant::Float(f) => {
|
||||||
|
Addr::Float(f)
|
||||||
|
}
|
||||||
|
Constant::String(s) => {
|
||||||
|
if s.is_empty() {
|
||||||
|
Addr::EmptyList
|
||||||
|
} else {
|
||||||
|
self.put_complete_string(&s)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Constant::Usize(n) => {
|
||||||
|
Addr::Usize(n)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub(crate)
|
||||||
|
fn pop(&mut self) {
|
||||||
|
let h = self.h();
|
||||||
|
|
||||||
|
if h > 0 {
|
||||||
|
self.truncate(h - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub(crate)
|
||||||
|
fn push(&mut self, val: HeapCellValue) -> usize {
|
||||||
|
let h = self.h();
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
let new_top = self.buf.new_block(mem::size_of::<HeapCellValue>());
|
||||||
|
ptr::write(self.buf.top as *mut _, val);
|
||||||
|
self.buf.top = new_top;
|
||||||
|
}
|
||||||
|
|
||||||
|
h
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub(crate)
|
||||||
|
fn atom_at(&self, h: usize) -> bool {
|
||||||
|
if let HeapCellValue::Atom(..) = &self[h] {
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub(crate)
|
||||||
|
fn to_unifiable(&mut self, non_heap_value: HeapCellValue) -> Addr {
|
||||||
|
match non_heap_value {
|
||||||
|
HeapCellValue::Addr(addr) => {
|
||||||
|
addr
|
||||||
|
}
|
||||||
|
val @ HeapCellValue::Atom(..) |
|
||||||
|
val @ HeapCellValue::Integer(_) |
|
||||||
|
val @ HeapCellValue::DBRef(_) |
|
||||||
|
val @ HeapCellValue::Rational(_) => {
|
||||||
|
Addr::Con(self.push(val))
|
||||||
|
}
|
||||||
|
val @ HeapCellValue::NamedStr(..) => {
|
||||||
|
Addr::Str(self.push(val))
|
||||||
|
}
|
||||||
|
HeapCellValue::PartialString(pstr, has_tail) => {
|
||||||
|
let h = self.push(HeapCellValue::PartialString(pstr, has_tail));
|
||||||
|
|
||||||
|
if has_tail {
|
||||||
|
self.push(HeapCellValue::Addr(Addr::EmptyList));
|
||||||
|
}
|
||||||
|
|
||||||
|
Addr::Con(h)
|
||||||
|
}
|
||||||
|
val @ HeapCellValue::Stream(..) => {
|
||||||
|
Addr::Stream(self.push(val))
|
||||||
|
}
|
||||||
|
val @ HeapCellValue::TcpListener(..) => {
|
||||||
|
Addr::TcpListener(self.push(val))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub(crate)
|
||||||
|
fn allocate_pstr(&mut self, src: &str) -> Addr {
|
||||||
|
self.write_pstr(src)
|
||||||
|
.unwrap_or_else(|| Addr::EmptyList)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn write_pstr(&mut self, mut src: &str) -> Option<Addr> {
|
||||||
let orig_h = self.h();
|
let orig_h = self.h();
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
@@ -158,17 +332,8 @@ impl<T: RawBlockTraits> HeapTemplate<T> {
|
|||||||
return if orig_h == self.h() {
|
return if orig_h == self.h() {
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
let prev_h = self.h() - 1;
|
let tail_h = self.h() - 1;
|
||||||
|
self[tail_h] = HeapCellValue::Addr(Addr::HeapCell(tail_h));
|
||||||
match &mut self[prev_h] {
|
|
||||||
HeapCellValue::PartialString(ref mut pstr) => {
|
|
||||||
let s = pstr.block_as_str();
|
|
||||||
pstr.tail = Addr::PStrTail(prev_h, s.len());
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
unreachable!()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Some(Addr::PStrLocation(orig_h, 0))
|
Some(Addr::PStrLocation(orig_h, 0))
|
||||||
};
|
};
|
||||||
@@ -176,8 +341,8 @@ impl<T: RawBlockTraits> HeapTemplate<T> {
|
|||||||
|
|
||||||
let h = self.h();
|
let h = self.h();
|
||||||
|
|
||||||
let (mut pstr, rest_src) =
|
let (pstr, rest_src) =
|
||||||
match PartialString::new(src, h) {
|
match PartialString::new(src) {
|
||||||
Some(tuple) => {
|
Some(tuple) => {
|
||||||
tuple
|
tuple
|
||||||
}
|
}
|
||||||
@@ -188,44 +353,19 @@ impl<T: RawBlockTraits> HeapTemplate<T> {
|
|||||||
} else if orig_h == h {
|
} else if orig_h == h {
|
||||||
return None;
|
return None;
|
||||||
} else {
|
} else {
|
||||||
let prev_h = h - 1;
|
self[h - 1] = HeapCellValue::Addr(Addr::HeapCell(h - 1));
|
||||||
|
|
||||||
match &mut self[prev_h] {
|
|
||||||
HeapCellValue::PartialString(ref mut pstr) => {
|
|
||||||
let s = pstr.block_as_str();
|
|
||||||
pstr.tail = Addr::PStrTail(prev_h, s.len());
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
unreachable!()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return Some(Addr::PStrLocation(orig_h, 0));
|
return Some(Addr::PStrLocation(orig_h, 0));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let new_top = unsafe {
|
self.push(HeapCellValue::PartialString(pstr, true));
|
||||||
self.buf.new_block(mem::size_of::<HeapCellValue>())
|
|
||||||
};
|
|
||||||
|
|
||||||
if rest_src != "" {
|
if rest_src != "" {
|
||||||
pstr.tail = Addr::PStrLocation(h+1, 0);
|
self.push(HeapCellValue::Addr(Addr::PStrLocation(h + 2, 0)));
|
||||||
src = rest_src;
|
src = rest_src;
|
||||||
} else {
|
} else {
|
||||||
pstr.tail = Addr::PStrTail(h, src.len());
|
self.push(HeapCellValue::Addr(Addr::HeapCell(h + 1)));
|
||||||
}
|
|
||||||
|
|
||||||
unsafe{
|
|
||||||
ptr::write(
|
|
||||||
self.buf.top as *mut _,
|
|
||||||
HeapCellValue::PartialString(pstr),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
self.buf.top = new_top;
|
|
||||||
|
|
||||||
if rest_src == "" {
|
|
||||||
return Some(Addr::PStrLocation(orig_h, 0));
|
return Some(Addr::PStrLocation(orig_h, 0));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -279,35 +419,39 @@ impl<T: RawBlockTraits> HeapTemplate<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub(crate)
|
pub(crate)
|
||||||
fn to_list<Iter: Iterator<Item = Addr>>(&mut self, values: Iter) -> usize {
|
fn to_list<Iter, SrcT>(&mut self, values: Iter) -> usize
|
||||||
|
where Iter: Iterator<Item = SrcT>,
|
||||||
|
SrcT: Into<HeapCellValue>
|
||||||
|
{
|
||||||
let head_addr = self.h();
|
let head_addr = self.h();
|
||||||
|
let mut h = head_addr;
|
||||||
|
|
||||||
for value in values {
|
for value in values.map(|v| v.into()) {
|
||||||
let h = self.h();
|
|
||||||
|
|
||||||
self.push(HeapCellValue::Addr(Addr::Lis(h + 1)));
|
self.push(HeapCellValue::Addr(Addr::Lis(h + 1)));
|
||||||
self.push(HeapCellValue::Addr(value));
|
self.push(value);
|
||||||
|
|
||||||
|
h += 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.push(HeapCellValue::Addr(Addr::Con(Constant::EmptyList)));
|
self.push(HeapCellValue::Addr(Addr::EmptyList));
|
||||||
|
|
||||||
head_addr
|
head_addr
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Create an iterator starting from the passed offset. */
|
/* Create an iterator starting from the passed offset. */
|
||||||
pub(crate)
|
pub(crate)
|
||||||
fn iter_from<'a>(&'a self, offset: usize) -> HeapIterator<'a, T> {
|
fn iter_from<'a>(&'a self, offset: usize) -> HeapIter<'a, T> {
|
||||||
HeapIterator::new(&self.buf, offset * mem::size_of::<HeapCellValue>())
|
HeapIter::new(&self.buf, offset * mem::size_of::<HeapCellValue>())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate)
|
pub(crate)
|
||||||
fn iter_mut_from<'a>(&'a mut self, offset: usize) -> HeapIteratorMut<'a, T> {
|
fn iter_mut_from<'a>(&'a mut self, offset: usize) -> HeapIterMut<'a, T> {
|
||||||
HeapIteratorMut::new(&mut self.buf, offset * mem::size_of::<HeapCellValue>())
|
HeapIterMut::new(&mut self.buf, offset * mem::size_of::<HeapCellValue>())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate)
|
pub(crate)
|
||||||
fn into_iter(mut self) -> HeapIntoIterator<T> {
|
fn into_iter(mut self) -> HeapIntoIter<T> {
|
||||||
HeapIntoIterator { buf: self.buf.take(), offset: 0 }
|
HeapIntoIter { buf: self.buf.take(), offset: 0 }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate)
|
pub(crate)
|
||||||
@@ -320,8 +464,9 @@ impl<T: RawBlockTraits> HeapTemplate<T> {
|
|||||||
pub(crate)
|
pub(crate)
|
||||||
fn to_local_code_ptr(&self, addr: &Addr) -> Option<LocalCodePtr> {
|
fn to_local_code_ptr(&self, addr: &Addr) -> Option<LocalCodePtr> {
|
||||||
let extract_integer = |s: usize| -> Option<usize> {
|
let extract_integer = |s: usize| -> Option<usize> {
|
||||||
match self[s].as_addr(s) {
|
match &self[s] {
|
||||||
Addr::Con(Constant::Integer(n)) => n.to_usize(),
|
&HeapCellValue::Addr(Addr::Fixnum(n)) => usize::try_from(n).ok(),
|
||||||
|
&HeapCellValue::Integer(ref n) => n.to_usize(),
|
||||||
_ => None
|
_ => None
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -361,6 +506,19 @@ impl<T: RawBlockTraits> HeapTemplate<T> {
|
|||||||
_ => None
|
_ => None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub
|
||||||
|
fn index_addr<'a>(&'a self, addr: &Addr) -> RefOrOwned<'a, HeapCellValue> {
|
||||||
|
match addr {
|
||||||
|
&Addr::Con(h) | &Addr::Str(h) | &Addr::Stream(h) | &Addr::TcpListener(h) => {
|
||||||
|
RefOrOwned::Borrowed(&self[h])
|
||||||
|
}
|
||||||
|
addr => {
|
||||||
|
RefOrOwned::Owned(HeapCellValue::Addr(*addr))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: RawBlockTraits> Index<usize> for HeapTemplate<T> {
|
impl<T: RawBlockTraits> Index<usize> for HeapTemplate<T> {
|
||||||
843
src/machine/machine_errors.rs
Normal file
843
src/machine/machine_errors.rs
Normal file
@@ -0,0 +1,843 @@
|
|||||||
|
use crate::prolog_parser::ast::*;
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
pub(crate) type MachineStub = Vec<HeapCellValue>;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
enum ErrorProvenance {
|
||||||
|
Constructed, // if constructed, offset the addresses.
|
||||||
|
Received, // otherwise, preserve the addresses.
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub(crate) struct MachineError {
|
||||||
|
stub: MachineStub,
|
||||||
|
location: Option<(usize, usize)>, // line_num, col_num
|
||||||
|
from: ErrorProvenance,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate)
|
||||||
|
trait TypeError {
|
||||||
|
fn type_error(self, h: usize, valid_type: ValidType) -> MachineError;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TypeError for Addr {
|
||||||
|
fn type_error(self, _: usize, valid_type: ValidType) -> MachineError {
|
||||||
|
let stub = functor!(
|
||||||
|
"type_error",
|
||||||
|
[atom(valid_type.as_str()), addr(self)]
|
||||||
|
);
|
||||||
|
|
||||||
|
MachineError {
|
||||||
|
stub,
|
||||||
|
location: None,
|
||||||
|
from: ErrorProvenance::Received
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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!(
|
||||||
|
"type_error",
|
||||||
|
[atom(valid_type.as_str()), aux(h, 0)],
|
||||||
|
[self]
|
||||||
|
);
|
||||||
|
|
||||||
|
MachineError {
|
||||||
|
stub,
|
||||||
|
location: None,
|
||||||
|
from: ErrorProvenance::Constructed
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TypeError for Number {
|
||||||
|
fn type_error(self, _h: usize, valid_type: ValidType) -> MachineError {
|
||||||
|
let stub = functor!(
|
||||||
|
"type_error",
|
||||||
|
[atom(valid_type.as_str()), number(self)]
|
||||||
|
);
|
||||||
|
|
||||||
|
MachineError {
|
||||||
|
stub,
|
||||||
|
location: None,
|
||||||
|
from: ErrorProvenance::Received
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate)
|
||||||
|
trait PermissionError {
|
||||||
|
fn permission_error(self, h: usize, index_str: &'static str, perm: Permission) -> MachineError;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PermissionError for Addr {
|
||||||
|
fn permission_error(self, _: usize, index_str: &'static str, perm: Permission) -> MachineError {
|
||||||
|
let stub = functor!(
|
||||||
|
"permission_error",
|
||||||
|
[atom(perm.as_str()), atom(index_str), addr(self)]
|
||||||
|
);
|
||||||
|
|
||||||
|
MachineError {
|
||||||
|
stub,
|
||||||
|
location: None,
|
||||||
|
from: ErrorProvenance::Received
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PermissionError for MachineStub {
|
||||||
|
fn permission_error(self, h: usize, index_str: &'static str, perm: Permission) -> MachineError {
|
||||||
|
let stub = functor!(
|
||||||
|
"permission_error",
|
||||||
|
[atom(perm.as_str()), atom(index_str), aux(h, 0)],
|
||||||
|
[self]
|
||||||
|
);
|
||||||
|
|
||||||
|
MachineError {
|
||||||
|
stub,
|
||||||
|
location: None,
|
||||||
|
from: ErrorProvenance::Constructed
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super)
|
||||||
|
trait DomainError {
|
||||||
|
fn domain_error(self, error: DomainErrorType) -> MachineError;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DomainError for Addr {
|
||||||
|
fn domain_error(self, error: DomainErrorType) -> MachineError {
|
||||||
|
let stub = functor!(
|
||||||
|
"domain_error",
|
||||||
|
[atom(error.as_str()), addr(self)]
|
||||||
|
);
|
||||||
|
|
||||||
|
MachineError {
|
||||||
|
stub,
|
||||||
|
location: None,
|
||||||
|
from: ErrorProvenance::Received,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DomainError for Number {
|
||||||
|
fn domain_error(self, error: DomainErrorType) -> MachineError {
|
||||||
|
let stub = functor!(
|
||||||
|
"domain_error",
|
||||||
|
[atom(error.as_str()), number(self)]
|
||||||
|
);
|
||||||
|
|
||||||
|
MachineError {
|
||||||
|
stub,
|
||||||
|
location: None,
|
||||||
|
from: ErrorProvenance::Received,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MachineError {
|
||||||
|
pub(super)
|
||||||
|
fn functor_stub(name: ClauseName, arity: usize) -> MachineStub {
|
||||||
|
functor!(
|
||||||
|
"/",
|
||||||
|
SharedOpDesc::new(400, YFX),
|
||||||
|
[clause_name(name), integer(arity)]
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub(super)
|
||||||
|
fn interrupt_error() -> Self {
|
||||||
|
let stub = functor!("$interrupt_thrown");
|
||||||
|
|
||||||
|
MachineError {
|
||||||
|
stub,
|
||||||
|
location: None,
|
||||||
|
from: ErrorProvenance::Received,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super)
|
||||||
|
fn evaluation_error(eval_error: EvalError) -> Self {
|
||||||
|
let stub = functor!("evaluation_error", [atom(eval_error.as_str())]);
|
||||||
|
|
||||||
|
MachineError {
|
||||||
|
stub,
|
||||||
|
location: None,
|
||||||
|
from: ErrorProvenance::Received,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super)
|
||||||
|
fn type_error<T: TypeError>(h: usize, valid_type: ValidType, culprit: T) -> Self {
|
||||||
|
culprit.type_error(h, valid_type)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super)
|
||||||
|
fn module_resolution_error(
|
||||||
|
h: usize,
|
||||||
|
mod_name: ClauseName,
|
||||||
|
name: ClauseName,
|
||||||
|
arity: usize,
|
||||||
|
) -> Self {
|
||||||
|
let res_stub = functor!(
|
||||||
|
":",
|
||||||
|
SharedOpDesc::new(600, XFY),
|
||||||
|
[clause_name(mod_name), clause_name(name)]
|
||||||
|
);
|
||||||
|
|
||||||
|
let ind_stub = functor!(
|
||||||
|
"/",
|
||||||
|
SharedOpDesc::new(400, YFX),
|
||||||
|
[aux(h + 2, 0), integer(arity)],
|
||||||
|
[res_stub]
|
||||||
|
);
|
||||||
|
|
||||||
|
let stub = functor!(
|
||||||
|
"evaluation_error",
|
||||||
|
[aux(h, 0)],
|
||||||
|
[ind_stub]
|
||||||
|
);
|
||||||
|
|
||||||
|
MachineError {
|
||||||
|
stub,
|
||||||
|
location: None,
|
||||||
|
from: ErrorProvenance::Constructed,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super)
|
||||||
|
fn existence_error(h: usize, err: ExistenceError) -> Self {
|
||||||
|
match err {
|
||||||
|
ExistenceError::Module(name) => {
|
||||||
|
let stub = functor!(
|
||||||
|
"existence_error",
|
||||||
|
[atom("source_sink"), clause_name(name)]
|
||||||
|
);
|
||||||
|
|
||||||
|
MachineError {
|
||||||
|
stub,
|
||||||
|
location: None,
|
||||||
|
from: ErrorProvenance::Received,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ExistenceError::Procedure(name, arity) => {
|
||||||
|
let culprit = functor!(
|
||||||
|
"/",
|
||||||
|
SharedOpDesc::new(400, YFX),
|
||||||
|
[clause_name(name), integer(arity)]
|
||||||
|
);
|
||||||
|
|
||||||
|
let stub = functor!(
|
||||||
|
"existence_error",
|
||||||
|
[atom("procedure"), aux(h, 0)],
|
||||||
|
[culprit]
|
||||||
|
);
|
||||||
|
|
||||||
|
MachineError {
|
||||||
|
stub,
|
||||||
|
location: None,
|
||||||
|
from: ErrorProvenance::Constructed,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ExistenceError::ModuleSource(source) => {
|
||||||
|
let source_stub = source.as_functor_stub();
|
||||||
|
|
||||||
|
let stub = functor!(
|
||||||
|
"existence_error",
|
||||||
|
[atom("source_sink"), aux(h, 0)],
|
||||||
|
[source_stub]
|
||||||
|
);
|
||||||
|
|
||||||
|
MachineError {
|
||||||
|
stub,
|
||||||
|
location: None,
|
||||||
|
from: ErrorProvenance::Constructed,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ExistenceError::SourceSink(culprit) => {
|
||||||
|
let stub = functor!(
|
||||||
|
"existence_error",
|
||||||
|
[atom("source_sink"), addr(culprit)]
|
||||||
|
);
|
||||||
|
|
||||||
|
MachineError {
|
||||||
|
stub,
|
||||||
|
location: None,
|
||||||
|
from: ErrorProvenance::Received,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ExistenceError::Stream(culprit) => {
|
||||||
|
let stub = functor!(
|
||||||
|
"existence_error",
|
||||||
|
[atom("stream"), addr(culprit)]
|
||||||
|
);
|
||||||
|
|
||||||
|
MachineError {
|
||||||
|
stub,
|
||||||
|
location: None,
|
||||||
|
from: ErrorProvenance::Received,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super)
|
||||||
|
fn permission_error<T: PermissionError>(
|
||||||
|
h: usize,
|
||||||
|
err: Permission,
|
||||||
|
index_str: &'static str,
|
||||||
|
culprit: T,
|
||||||
|
) -> Self {
|
||||||
|
culprit.permission_error(
|
||||||
|
h,
|
||||||
|
index_str,
|
||||||
|
err,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn arithmetic_error(h: usize, err: ArithmeticError) -> Self {
|
||||||
|
match err {
|
||||||
|
ArithmeticError::UninstantiatedVar => {
|
||||||
|
Self::instantiation_error()
|
||||||
|
}
|
||||||
|
ArithmeticError::NonEvaluableFunctor(name, arity) => {
|
||||||
|
let culprit = functor!(
|
||||||
|
"/",
|
||||||
|
SharedOpDesc::new(400, YFX),
|
||||||
|
[constant(h, &name), integer(arity)]
|
||||||
|
);
|
||||||
|
|
||||||
|
Self::type_error(h, ValidType::Evaluable, culprit)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub(super)
|
||||||
|
fn domain_error<T: DomainError>(error: DomainErrorType, culprit: T) -> Self {
|
||||||
|
culprit.domain_error(error)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super)
|
||||||
|
fn instantiation_error() -> Self {
|
||||||
|
let stub = functor!("instantiation_error");
|
||||||
|
|
||||||
|
MachineError {
|
||||||
|
stub,
|
||||||
|
location: None,
|
||||||
|
from: ErrorProvenance::Received,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super)
|
||||||
|
fn uninstantiation_error(culprit: Addr) -> Self {
|
||||||
|
let stub = functor!(
|
||||||
|
"uninstantiation_error",
|
||||||
|
[addr(culprit)]
|
||||||
|
);
|
||||||
|
|
||||||
|
MachineError {
|
||||||
|
stub,
|
||||||
|
location: None,
|
||||||
|
from: ErrorProvenance::Received,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super)
|
||||||
|
fn session_error(h: usize, err: SessionError) -> Self {
|
||||||
|
match err {
|
||||||
|
SessionError::CannotOverwriteBuiltIn(pred_str) |
|
||||||
|
SessionError::CannotOverwriteImport(pred_str) => {
|
||||||
|
Self::permission_error(
|
||||||
|
h,
|
||||||
|
Permission::Modify,
|
||||||
|
"private_procedure",
|
||||||
|
functor!(clause_name(pred_str)),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
SessionError::ExistenceError(err) => {
|
||||||
|
Self::existence_error(h, err)
|
||||||
|
}
|
||||||
|
SessionError::InvalidFileName(filename) => {
|
||||||
|
Self::existence_error(h, ExistenceError::Module(filename))
|
||||||
|
}
|
||||||
|
SessionError::ModuleDoesNotContainExport(..) => {
|
||||||
|
Self::permission_error(
|
||||||
|
h,
|
||||||
|
Permission::Access,
|
||||||
|
"private_procedure",
|
||||||
|
functor!("module_does_not_contain_claimed_export"),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
SessionError::NamelessEntry => {
|
||||||
|
Self::permission_error(
|
||||||
|
h,
|
||||||
|
Permission::Create,
|
||||||
|
"static_procedure",
|
||||||
|
functor!("nameless_procedure")
|
||||||
|
)
|
||||||
|
}
|
||||||
|
SessionError::OpIsInfixAndPostFix(op) => {
|
||||||
|
Self::permission_error(
|
||||||
|
h,
|
||||||
|
Permission::Create,
|
||||||
|
"operator",
|
||||||
|
functor!(clause_name(op)),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
SessionError::ParserError(err) => {
|
||||||
|
Self::syntax_error(h, err)
|
||||||
|
}
|
||||||
|
SessionError::QueryCannotBeDefinedAsFact => {
|
||||||
|
Self::permission_error(
|
||||||
|
h,
|
||||||
|
Permission::Create,
|
||||||
|
"static_procedure",
|
||||||
|
functor!("query_cannot_be_defined_as_fact")
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super)
|
||||||
|
fn syntax_error(h: usize, err: ParserError) -> Self {
|
||||||
|
if let ParserError::Arithmetic(err) = err {
|
||||||
|
return Self::arithmetic_error(h, err);
|
||||||
|
}
|
||||||
|
|
||||||
|
let location = err.line_and_col_num();
|
||||||
|
let stub = functor!(err.as_str());
|
||||||
|
|
||||||
|
let stub = functor!(
|
||||||
|
"syntax_error",
|
||||||
|
[aux(h, 0)],
|
||||||
|
[stub]
|
||||||
|
);
|
||||||
|
|
||||||
|
MachineError {
|
||||||
|
stub,
|
||||||
|
location,
|
||||||
|
from: ErrorProvenance::Constructed,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super)
|
||||||
|
fn representation_error(flag: RepFlag) -> Self {
|
||||||
|
let stub = functor!("representation_error", [atom(flag.as_str())]);
|
||||||
|
|
||||||
|
MachineError {
|
||||||
|
stub,
|
||||||
|
location: None,
|
||||||
|
from: ErrorProvenance::Received,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn into_iter(self, offset: usize) -> Box<dyn Iterator<Item = HeapCellValue>> {
|
||||||
|
match self.from {
|
||||||
|
ErrorProvenance::Constructed => {
|
||||||
|
Box::new(self.stub.into_iter().map(move |hcv| match hcv {
|
||||||
|
HeapCellValue::Addr(addr) => HeapCellValue::Addr(addr + offset),
|
||||||
|
hcv => hcv,
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
ErrorProvenance::Received => Box::new(self.stub.into_iter()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn len(&self) -> usize {
|
||||||
|
self.stub.len()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
pub enum Permission {
|
||||||
|
Access,
|
||||||
|
Create,
|
||||||
|
InputStream,
|
||||||
|
Modify,
|
||||||
|
Open,
|
||||||
|
OutputStream,
|
||||||
|
Reposition,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Permission {
|
||||||
|
#[inline]
|
||||||
|
pub fn as_str(self) -> &'static str {
|
||||||
|
match self {
|
||||||
|
Permission::Access => "access",
|
||||||
|
Permission::Create => "create",
|
||||||
|
Permission::InputStream => "input",
|
||||||
|
Permission::Modify => "modify",
|
||||||
|
Permission::Open => "open",
|
||||||
|
Permission::OutputStream => "output",
|
||||||
|
Permission::Reposition => "reposition",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// from 7.12.2 b) of 13211-1:1995
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
pub enum ValidType {
|
||||||
|
Atom,
|
||||||
|
Atomic,
|
||||||
|
// Boolean,
|
||||||
|
Byte,
|
||||||
|
Callable,
|
||||||
|
Character,
|
||||||
|
Compound,
|
||||||
|
Evaluable,
|
||||||
|
Float,
|
||||||
|
InByte,
|
||||||
|
InCharacter,
|
||||||
|
Integer,
|
||||||
|
List,
|
||||||
|
Number,
|
||||||
|
Pair,
|
||||||
|
// PredicateIndicator,
|
||||||
|
// Variable
|
||||||
|
TcpListener,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ValidType {
|
||||||
|
pub fn as_str(self) -> &'static str {
|
||||||
|
match self {
|
||||||
|
ValidType::Atom => "atom",
|
||||||
|
ValidType::Atomic => "atomic",
|
||||||
|
// ValidType::Boolean => "boolean",
|
||||||
|
ValidType::Byte => "byte",
|
||||||
|
ValidType::Callable => "callable",
|
||||||
|
ValidType::Character => "character",
|
||||||
|
ValidType::Compound => "compound",
|
||||||
|
ValidType::Evaluable => "evaluable",
|
||||||
|
ValidType::Float => "float",
|
||||||
|
ValidType::InByte => "in_byte",
|
||||||
|
ValidType::InCharacter => "in_character",
|
||||||
|
ValidType::Integer => "integer",
|
||||||
|
ValidType::List => "list",
|
||||||
|
ValidType::Number => "number",
|
||||||
|
ValidType::Pair => "pair",
|
||||||
|
// ValidType::PredicateIndicator => "predicate_indicator",
|
||||||
|
// ValidType::Variable => "variable"
|
||||||
|
ValidType::TcpListener => "tcp_listener",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
pub enum DomainErrorType {
|
||||||
|
IOMode,
|
||||||
|
NotLessThanZero,
|
||||||
|
Order,
|
||||||
|
SourceSink,
|
||||||
|
Stream,
|
||||||
|
StreamOrAlias,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DomainErrorType {
|
||||||
|
pub fn as_str(self) -> &'static str {
|
||||||
|
match self {
|
||||||
|
DomainErrorType::IOMode => "io_mode",
|
||||||
|
DomainErrorType::NotLessThanZero => "not_less_than_zero",
|
||||||
|
DomainErrorType::Order => "order",
|
||||||
|
DomainErrorType::SourceSink => "source_sink",
|
||||||
|
DomainErrorType::Stream => "stream",
|
||||||
|
DomainErrorType::StreamOrAlias => "stream_or_alias",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// from 7.12.2 f) of 13211-1:1995
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
pub enum RepFlag {
|
||||||
|
Character,
|
||||||
|
CharacterCode,
|
||||||
|
InCharacterCode,
|
||||||
|
MaxArity,
|
||||||
|
// MaxInteger,
|
||||||
|
// MinInteger
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RepFlag {
|
||||||
|
pub fn as_str(self) -> &'static str {
|
||||||
|
match self {
|
||||||
|
RepFlag::Character => "character",
|
||||||
|
RepFlag::CharacterCode => "character_code",
|
||||||
|
RepFlag::InCharacterCode => "in_character_code",
|
||||||
|
RepFlag::MaxArity => "max_arity",
|
||||||
|
// RepFlag::MaxInteger => "max_integer",
|
||||||
|
// RepFlag::MinInteger => "min_integer"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// from 7.12.2 g) of 13211-1:1995
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
pub enum EvalError {
|
||||||
|
FloatOverflow,
|
||||||
|
Undefined,
|
||||||
|
// Underflow,
|
||||||
|
ZeroDivisor,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl EvalError {
|
||||||
|
pub fn as_str(self) -> &'static str {
|
||||||
|
match self {
|
||||||
|
EvalError::FloatOverflow => "float_overflow",
|
||||||
|
EvalError::Undefined => "undefined",
|
||||||
|
// EvalError::FloatUnderflow => "underflow",
|
||||||
|
EvalError::ZeroDivisor => "zero_divisor",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// used by '$skip_max_list'.
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
pub(super) enum CycleSearchResult {
|
||||||
|
EmptyList,
|
||||||
|
NotList,
|
||||||
|
PartialList(usize, Ref), // the list length (up to max), and an offset into the heap.
|
||||||
|
ProperList(usize), // the list length.
|
||||||
|
PStrLocation(usize, usize, usize), // the list length (up to max), the heap offset, byte offset into the string.
|
||||||
|
UntouchedList(usize), // the address of an uniterated Addr::Lis(address).
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MachineState {
|
||||||
|
// see 8.4.3 of Draft Technical Corrigendum 2.
|
||||||
|
pub(super)
|
||||||
|
fn check_sort_errors(&self) -> CallResult {
|
||||||
|
let stub = MachineError::functor_stub(clause_name!("sort"), 2);
|
||||||
|
let list = self.store(self.deref(self[temp_v!(1)].clone()));
|
||||||
|
let sorted = self.store(self.deref(self[temp_v!(2)].clone()));
|
||||||
|
|
||||||
|
match self.detect_cycles(list.clone()) {
|
||||||
|
CycleSearchResult::PartialList(..) => {
|
||||||
|
return Err(self.error_form(MachineError::instantiation_error(), stub))
|
||||||
|
}
|
||||||
|
CycleSearchResult::NotList => {
|
||||||
|
return Err(self.error_form(MachineError::type_error(0, ValidType::List, list), stub))
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
};
|
||||||
|
|
||||||
|
match self.detect_cycles(sorted.clone()) {
|
||||||
|
CycleSearchResult::NotList if !sorted.is_ref() => {
|
||||||
|
Err(self.error_form(MachineError::type_error(0, ValidType::List, sorted), stub))
|
||||||
|
}
|
||||||
|
_ => Ok(()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn check_for_list_pairs(&self, list: Addr) -> CallResult {
|
||||||
|
let stub = MachineError::functor_stub(clause_name!("keysort"), 2);
|
||||||
|
|
||||||
|
match self.detect_cycles(list.clone()) {
|
||||||
|
CycleSearchResult::NotList if !list.is_ref() => {
|
||||||
|
Err(self.error_form(MachineError::type_error(0, ValidType::List, list), stub))
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
let mut addr = list;
|
||||||
|
|
||||||
|
while let Addr::Lis(l) = self.store(self.deref(addr)) {
|
||||||
|
let mut new_l = l;
|
||||||
|
|
||||||
|
loop {
|
||||||
|
match self.heap.clone(new_l) {
|
||||||
|
HeapCellValue::Addr(Addr::Str(l)) => {
|
||||||
|
new_l = l;
|
||||||
|
}
|
||||||
|
HeapCellValue::NamedStr(2, ref name, Some(_))
|
||||||
|
if name.as_str() == "-" => {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
HeapCellValue::Addr(Addr::HeapCell(_)) => {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
HeapCellValue::Addr(Addr::StackCell(..)) => {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
return Err(self.error_form(
|
||||||
|
MachineError::type_error(0, ValidType::Pair, Addr::HeapCell(l)),
|
||||||
|
stub,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
addr = Addr::HeapCell(l + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// see 8.4.4 of Draft Technical Corrigendum 2.
|
||||||
|
pub(super)
|
||||||
|
fn check_keysort_errors(&self) -> CallResult {
|
||||||
|
let stub = MachineError::functor_stub(clause_name!("keysort"), 2);
|
||||||
|
|
||||||
|
let pairs = self.store(self.deref(self[temp_v!(1)].clone()));
|
||||||
|
let sorted = self.store(self.deref(self[temp_v!(2)].clone()));
|
||||||
|
|
||||||
|
match self.detect_cycles(pairs.clone()) {
|
||||||
|
CycleSearchResult::PartialList(..) => {
|
||||||
|
Err(self.error_form(MachineError::instantiation_error(), stub))
|
||||||
|
}
|
||||||
|
CycleSearchResult::NotList => {
|
||||||
|
Err(self.error_form(MachineError::type_error(0, ValidType::List, pairs), stub))
|
||||||
|
}
|
||||||
|
_ => Ok(()),
|
||||||
|
}?;
|
||||||
|
|
||||||
|
self.check_for_list_pairs(sorted)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub(crate)
|
||||||
|
fn type_error<T: TypeError>(
|
||||||
|
&self,
|
||||||
|
valid_type: ValidType,
|
||||||
|
culprit: T,
|
||||||
|
caller: ClauseName,
|
||||||
|
arity: usize,
|
||||||
|
) -> MachineStub {
|
||||||
|
let stub = MachineError::functor_stub(caller, arity);
|
||||||
|
let err = MachineError::type_error(
|
||||||
|
self.heap.h(),
|
||||||
|
valid_type,
|
||||||
|
culprit,
|
||||||
|
);
|
||||||
|
|
||||||
|
return self.error_form(err, stub);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub(crate)
|
||||||
|
fn representation_error(
|
||||||
|
&self,
|
||||||
|
rep_flag: RepFlag,
|
||||||
|
caller: ClauseName,
|
||||||
|
arity: usize,
|
||||||
|
) -> MachineStub {
|
||||||
|
let stub = MachineError::functor_stub(caller, arity);
|
||||||
|
let err = MachineError::representation_error(
|
||||||
|
rep_flag,
|
||||||
|
);
|
||||||
|
|
||||||
|
return self.error_form(err, stub);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super)
|
||||||
|
fn error_form(&self, err: MachineError, src: MachineStub) -> MachineStub {
|
||||||
|
let location = err.location;
|
||||||
|
let err_len = err.len();
|
||||||
|
|
||||||
|
let h = self.heap.h();
|
||||||
|
let mut stub = vec![
|
||||||
|
HeapCellValue::NamedStr(2, clause_name!("error"), None),
|
||||||
|
HeapCellValue::Addr(Addr::HeapCell(h + 3)),
|
||||||
|
HeapCellValue::Addr(Addr::HeapCell(h + 3 + err_len)),
|
||||||
|
];
|
||||||
|
|
||||||
|
stub.extend(err.into_iter(3));
|
||||||
|
|
||||||
|
if let Some((line_num, _)) = location {
|
||||||
|
let colon_op_desc = Some(SharedOpDesc::new(600, XFY));
|
||||||
|
|
||||||
|
stub.push(HeapCellValue::NamedStr(2, clause_name!(":"), colon_op_desc));
|
||||||
|
stub.push(HeapCellValue::Addr(Addr::HeapCell(h + 6 + err_len)));
|
||||||
|
stub.push(HeapCellValue::Integer(Rc::new(Integer::from(line_num))));
|
||||||
|
}
|
||||||
|
|
||||||
|
stub.extend(src.into_iter());
|
||||||
|
stub
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super)
|
||||||
|
fn throw_exception(&mut self, err: MachineStub) {
|
||||||
|
let h = self.heap.h();
|
||||||
|
|
||||||
|
self.ball.boundary = 0;
|
||||||
|
self.ball.stub.truncate(0);
|
||||||
|
|
||||||
|
self.heap.append(err);
|
||||||
|
|
||||||
|
self.registers[1] = Addr::HeapCell(h);
|
||||||
|
|
||||||
|
self.set_ball();
|
||||||
|
self.unwind_stack();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum ExistenceError {
|
||||||
|
Module(ClauseName),
|
||||||
|
ModuleSource(ModuleSource),
|
||||||
|
Procedure(ClauseName, usize),
|
||||||
|
SourceSink(Addr),
|
||||||
|
Stream(Addr),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum SessionError {
|
||||||
|
CannotOverwriteBuiltIn(ClauseName),
|
||||||
|
CannotOverwriteImport(ClauseName),
|
||||||
|
ExistenceError(ExistenceError),
|
||||||
|
InvalidFileName(ClauseName),
|
||||||
|
ModuleDoesNotContainExport(ClauseName, PredicateKey),
|
||||||
|
NamelessEntry,
|
||||||
|
OpIsInfixAndPostFix(ClauseName),
|
||||||
|
QueryCannotBeDefinedAsFact,
|
||||||
|
ParserError(ParserError),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum EvalSession {
|
||||||
|
EntrySuccess,
|
||||||
|
Error(SessionError),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<SessionError> for EvalSession {
|
||||||
|
fn from(err: SessionError) -> Self {
|
||||||
|
EvalSession::Error(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<ParserError> for SessionError {
|
||||||
|
fn from(err: ParserError) -> Self {
|
||||||
|
SessionError::ParserError(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<ParserError> for EvalSession {
|
||||||
|
fn from(err: ParserError) -> Self {
|
||||||
|
EvalSession::from(SessionError::ParserError(err))
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,32 +1,38 @@
|
|||||||
use prolog_parser::ast::*;
|
use crate::prolog_parser::ast::*;
|
||||||
use prolog_parser::tabled_rc::*;
|
use crate::prolog_parser::tabled_rc::*;
|
||||||
|
|
||||||
use crate::prolog::clause_types::*;
|
use crate::clause_types::*;
|
||||||
use crate::prolog::fixtures::*;
|
use crate::fixtures::*;
|
||||||
use crate::prolog::forms::*;
|
use crate::forms::*;
|
||||||
use crate::prolog::machine::code_repo::CodeRepo;
|
use crate::machine::code_repo::CodeRepo;
|
||||||
use crate::prolog::machine::Ball;
|
use crate::machine::Ball;
|
||||||
use crate::prolog::machine::heap::*;
|
use crate::machine::heap::*;
|
||||||
use crate::prolog::machine::partial_string::*;
|
use crate::machine::machine_state::*;
|
||||||
use crate::prolog::machine::raw_block::RawBlockTraits;
|
use crate::machine::partial_string::*;
|
||||||
use crate::prolog::instructions::*;
|
use crate::machine::raw_block::RawBlockTraits;
|
||||||
use crate::prolog::rug::Integer;
|
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::cell::RefCell;
|
||||||
use std::cmp::Ordering;
|
use std::cmp::Ordering;
|
||||||
use std::collections::{BTreeMap, VecDeque};
|
use std::collections::{BTreeMap, BTreeSet, VecDeque};
|
||||||
|
use std::convert::TryFrom;
|
||||||
|
use std::fmt;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
|
use std::net::TcpListener;
|
||||||
use std::ops::{Add, AddAssign, Sub, SubAssign};
|
use std::ops::{Add, AddAssign, Sub, SubAssign};
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||||
pub struct OrderedOpDirKey(pub ClauseName, pub Fixity);
|
pub struct OrderedOpDirKey(pub ClauseName, pub Fixity);
|
||||||
|
|
||||||
pub type OssifiedOpDir = BTreeMap<OrderedOpDirKey, (usize, Specifier)>;
|
pub type OssifiedOpDir = BTreeMap<OrderedOpDirKey, (usize, Specifier)>;
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Eq, Hash)]
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
pub enum DBRef {
|
pub enum DBRef {
|
||||||
NamedPred(ClauseName, usize, Option<SharedOpDesc>),
|
NamedPred(ClauseName, usize, Option<SharedOpDesc>),
|
||||||
Op(
|
Op(
|
||||||
@@ -38,25 +44,40 @@ pub enum DBRef {
|
|||||||
),
|
),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Eq, Hash)]
|
// 7.2
|
||||||
pub enum Addr {
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
AttrVar(usize),
|
pub enum TermOrderCategory {
|
||||||
Con(Constant),
|
Variable,
|
||||||
DBRef(DBRef),
|
FloatingPoint,
|
||||||
Lis(usize),
|
Integer,
|
||||||
HeapCell(usize),
|
Atom,
|
||||||
StackCell(usize, usize),
|
Compound,
|
||||||
Str(usize),
|
|
||||||
PStrLocation(usize, usize), // location of pstr in heap, offset into string in bytes.
|
|
||||||
PStrTail(usize, usize), // location of pstr in heap, offset into string in bytes.
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Hash, Eq, PartialEq)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||||
|
pub enum Addr {
|
||||||
|
AttrVar(usize),
|
||||||
|
Char(char),
|
||||||
|
Con(usize),
|
||||||
|
CutPoint(usize),
|
||||||
|
EmptyList,
|
||||||
|
Fixnum(isize),
|
||||||
|
Float(OrderedFloat<f64>),
|
||||||
|
Lis(usize),
|
||||||
|
HeapCell(usize),
|
||||||
|
PStrLocation(usize, usize), // location of pstr in heap, offset into string in bytes.
|
||||||
|
StackCell(usize, usize),
|
||||||
|
Str(usize),
|
||||||
|
Stream(usize),
|
||||||
|
TcpListener(usize),
|
||||||
|
Usize(usize),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq, PartialOrd)]
|
||||||
pub enum Ref {
|
pub enum Ref {
|
||||||
AttrVar(usize),
|
AttrVar(usize),
|
||||||
HeapCell(usize),
|
HeapCell(usize),
|
||||||
StackCell(usize, usize),
|
StackCell(usize, usize),
|
||||||
PStrTail(usize, usize),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Ref {
|
impl Ref {
|
||||||
@@ -65,7 +86,28 @@ impl Ref {
|
|||||||
Ref::AttrVar(h) => Addr::AttrVar(h),
|
Ref::AttrVar(h) => Addr::AttrVar(h),
|
||||||
Ref::HeapCell(h) => Addr::HeapCell(h),
|
Ref::HeapCell(h) => Addr::HeapCell(h),
|
||||||
Ref::StackCell(fr, sc) => Addr::StackCell(fr, sc),
|
Ref::StackCell(fr, sc) => Addr::StackCell(fr, sc),
|
||||||
Ref::PStrTail(h, n) => Addr::PStrTail(h, n),
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Ord for Ref {
|
||||||
|
fn cmp(&self, other: &Ref) -> Ordering {
|
||||||
|
match (self, other) {
|
||||||
|
(Ref::AttrVar(h1), Ref::AttrVar(h2))
|
||||||
|
| (Ref::HeapCell(h1), Ref::HeapCell(h2))
|
||||||
|
| (Ref::HeapCell(h1), Ref::AttrVar(h2))
|
||||||
|
| (Ref::AttrVar(h1), Ref::HeapCell(h2)) => {
|
||||||
|
h1.cmp(&h2)
|
||||||
|
}
|
||||||
|
(Ref::StackCell(fr1, sc1), Ref::StackCell(fr2, sc2)) => {
|
||||||
|
fr1.cmp(&fr2).then_with(|| sc1.cmp(&sc2))
|
||||||
|
}
|
||||||
|
(Ref::StackCell(..), _) => {
|
||||||
|
Ordering::Greater
|
||||||
|
}
|
||||||
|
(_, Ref::StackCell(..)) => {
|
||||||
|
Ordering::Less
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -76,13 +118,13 @@ impl PartialEq<Ref> for Addr {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// for use in MachineState::bind.
|
// for use crate::in MachineState::bind.
|
||||||
impl PartialOrd<Ref> for Addr {
|
impl PartialOrd<Ref> for Addr {
|
||||||
fn partial_cmp(&self, r: &Ref) -> Option<Ordering> {
|
fn partial_cmp(&self, r: &Ref) -> Option<Ordering> {
|
||||||
match self {
|
match self {
|
||||||
&Addr::StackCell(fr, sc) => {
|
&Addr::StackCell(fr, sc) => {
|
||||||
match *r {
|
match *r {
|
||||||
Ref::AttrVar(_) | Ref::HeapCell(_) | Ref::PStrTail(..) => {
|
Ref::AttrVar(_) | Ref::HeapCell(_) => {
|
||||||
Some(Ordering::Greater)
|
Some(Ordering::Greater)
|
||||||
}
|
}
|
||||||
Ref::StackCell(fr1, sc1) => {
|
Ref::StackCell(fr1, sc1) => {
|
||||||
@@ -104,22 +146,6 @@ impl PartialOrd<Ref> for Addr {
|
|||||||
Ref::AttrVar(h1) | Ref::HeapCell(h1) => {
|
Ref::AttrVar(h1) | Ref::HeapCell(h1) => {
|
||||||
h.partial_cmp(h1)
|
h.partial_cmp(h1)
|
||||||
}
|
}
|
||||||
Ref::PStrTail(h1, _) => {
|
|
||||||
h.partial_cmp(h1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
&Addr::PStrTail(h, n) => {
|
|
||||||
match r {
|
|
||||||
Ref::StackCell(..) => {
|
|
||||||
Some(Ordering::Less)
|
|
||||||
}
|
|
||||||
Ref::AttrVar(h1) | Ref::HeapCell(h1) => {
|
|
||||||
h.partial_cmp(h1)
|
|
||||||
}
|
|
||||||
Ref::PStrTail(h1, n1) => {
|
|
||||||
Some(h.cmp(h1).then_with(|| n.cmp(n1)))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
@@ -130,9 +156,24 @@ impl PartialOrd<Ref> for Addr {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Addr {
|
impl Addr {
|
||||||
|
#[inline]
|
||||||
|
pub fn is_heap_bound(&self) -> bool {
|
||||||
|
match self {
|
||||||
|
Addr::Char(_) | Addr::EmptyList |
|
||||||
|
Addr::CutPoint(_) | Addr::Usize(_) | Addr::Fixnum(_) |
|
||||||
|
Addr::Float(_) => {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
pub fn is_ref(&self) -> bool {
|
pub fn is_ref(&self) -> bool {
|
||||||
match self {
|
match self {
|
||||||
Addr::HeapCell(_) | Addr::StackCell(_, _) | Addr::AttrVar(_) | Addr::PStrTail(..) => {
|
Addr::HeapCell(_) | Addr::StackCell(_, _) | Addr::AttrVar(_) => {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
@@ -141,16 +182,105 @@ impl Addr {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
pub fn as_var(&self) -> Option<Ref> {
|
pub fn as_var(&self) -> Option<Ref> {
|
||||||
match self {
|
match self {
|
||||||
&Addr::AttrVar(h) => Some(Ref::AttrVar(h)),
|
&Addr::AttrVar(h) => Some(Ref::AttrVar(h)),
|
||||||
&Addr::HeapCell(h) => Some(Ref::HeapCell(h)),
|
&Addr::HeapCell(h) => Some(Ref::HeapCell(h)),
|
||||||
&Addr::StackCell(fr, sc) => Some(Ref::StackCell(fr, sc)),
|
&Addr::StackCell(fr, sc) => Some(Ref::StackCell(fr, sc)),
|
||||||
&Addr::PStrTail(h, n) => Some(Ref::PStrTail(h, n)),
|
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(super)
|
||||||
|
fn order_category(&self, heap: &Heap) -> Option<TermOrderCategory> {
|
||||||
|
match Number::try_from((*self, heap)) {
|
||||||
|
Ok(Number::Integer(_)) | Ok(Number::Fixnum(_)) | Ok(Number::Rational(_)) => {
|
||||||
|
Some(TermOrderCategory::Integer)
|
||||||
|
}
|
||||||
|
Ok(Number::Float(_)) => {
|
||||||
|
Some(TermOrderCategory::FloatingPoint)
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
match self {
|
||||||
|
Addr::HeapCell(_) | Addr::AttrVar(_) | Addr::StackCell(..) => {
|
||||||
|
Some(TermOrderCategory::Variable)
|
||||||
|
}
|
||||||
|
Addr::Float(_) => {
|
||||||
|
Some(TermOrderCategory::FloatingPoint)
|
||||||
|
}
|
||||||
|
&Addr::Con(h) => {
|
||||||
|
match &heap[h] {
|
||||||
|
HeapCellValue::Atom(..) => {
|
||||||
|
Some(TermOrderCategory::Atom)
|
||||||
|
}
|
||||||
|
HeapCellValue::DBRef(_) => {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Addr::Char(_) | Addr::EmptyList => {
|
||||||
|
Some(TermOrderCategory::Atom)
|
||||||
|
}
|
||||||
|
Addr::Fixnum(_) | Addr::Usize(_) => {
|
||||||
|
Some(TermOrderCategory::Integer)
|
||||||
|
}
|
||||||
|
Addr::Lis(_) | Addr::PStrLocation(..) | Addr::Str(_) => {
|
||||||
|
Some(TermOrderCategory::Compound)
|
||||||
|
}
|
||||||
|
Addr::CutPoint(_) | Addr::Stream(_) | Addr::TcpListener(_) => {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn as_constant_index(&self, machine_st: &MachineState) -> Option<Constant> {
|
||||||
|
match self {
|
||||||
|
&Addr::Char(c) => {
|
||||||
|
Some(Constant::Char(c))
|
||||||
|
}
|
||||||
|
&Addr::Con(h) => {
|
||||||
|
match &machine_st.heap[h] {
|
||||||
|
&HeapCellValue::Atom(ref name, _) if name.is_char() => {
|
||||||
|
Some(Constant::Char(name.as_str().chars().next().unwrap()))
|
||||||
|
}
|
||||||
|
&HeapCellValue::Atom(ref name, _) => {
|
||||||
|
Some(Constant::Atom(name.clone(), None))
|
||||||
|
}
|
||||||
|
&HeapCellValue::Integer(ref n) => {
|
||||||
|
Some(Constant::Integer(n.clone()))
|
||||||
|
}
|
||||||
|
&HeapCellValue::Rational(ref n) => {
|
||||||
|
Some(Constant::Rational(n.clone()))
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&Addr::EmptyList => {
|
||||||
|
Some(Constant::EmptyList)
|
||||||
|
}
|
||||||
|
&Addr::Fixnum(n) => {
|
||||||
|
Some(Constant::Fixnum(n))
|
||||||
|
}
|
||||||
|
&Addr::Float(f) => {
|
||||||
|
Some(Constant::Float(f))
|
||||||
|
}
|
||||||
|
&Addr::Usize(n) => {
|
||||||
|
Some(Constant::Usize(n))
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn is_protected(&self, e: usize) -> bool {
|
pub fn is_protected(&self, e: usize) -> bool {
|
||||||
match self {
|
match self {
|
||||||
&Addr::StackCell(addr, _) if addr >= e => false,
|
&Addr::StackCell(addr, _) if addr >= e => false,
|
||||||
@@ -164,12 +294,13 @@ impl Add<usize> for Addr {
|
|||||||
|
|
||||||
fn add(self, rhs: usize) -> Self::Output {
|
fn add(self, rhs: usize) -> Self::Output {
|
||||||
match self {
|
match self {
|
||||||
|
Addr::Stream(h) => Addr::Stream(h + rhs),
|
||||||
|
Addr::Con(h) => Addr::Con(h + rhs),
|
||||||
Addr::Lis(a) => Addr::Lis(a + rhs),
|
Addr::Lis(a) => Addr::Lis(a + rhs),
|
||||||
Addr::AttrVar(h) => Addr::AttrVar(h + rhs),
|
Addr::AttrVar(h) => Addr::AttrVar(h + rhs),
|
||||||
Addr::HeapCell(h) => Addr::HeapCell(h + rhs),
|
Addr::HeapCell(h) => Addr::HeapCell(h + rhs),
|
||||||
Addr::Str(s) => Addr::Str(s + rhs),
|
Addr::Str(s) => Addr::Str(s + rhs),
|
||||||
Addr::PStrLocation(h, n) => Addr::PStrLocation(h + rhs, n),
|
Addr::PStrLocation(h, n) => Addr::PStrLocation(h + rhs, n),
|
||||||
Addr::PStrTail(h, n) => Addr::PStrTail(h + rhs, n),
|
|
||||||
_ => self,
|
_ => self,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -181,11 +312,12 @@ impl Sub<i64> for Addr {
|
|||||||
fn sub(self, rhs: i64) -> Self::Output {
|
fn sub(self, rhs: i64) -> Self::Output {
|
||||||
if rhs < 0 {
|
if rhs < 0 {
|
||||||
match self {
|
match self {
|
||||||
|
Addr::Stream(h) => Addr::Stream(h + rhs.abs() as usize),
|
||||||
|
Addr::Con(h) => Addr::Con(h + rhs.abs() as usize),
|
||||||
Addr::Lis(a) => Addr::Lis(a + rhs.abs() as usize),
|
Addr::Lis(a) => Addr::Lis(a + rhs.abs() as usize),
|
||||||
Addr::AttrVar(h) => Addr::AttrVar(h + rhs.abs() as usize),
|
Addr::AttrVar(h) => Addr::AttrVar(h + rhs.abs() as usize),
|
||||||
Addr::HeapCell(h) => Addr::HeapCell(h + rhs.abs() as usize),
|
Addr::HeapCell(h) => Addr::HeapCell(h + rhs.abs() as usize),
|
||||||
Addr::Str(s) => Addr::Str(s + rhs.abs() as usize),
|
Addr::Str(s) => Addr::Str(s + rhs.abs() as usize),
|
||||||
Addr::PStrTail(h, n) => Addr::PStrTail(h + rhs.abs() as usize, n),
|
|
||||||
Addr::PStrLocation(h, n) => Addr::PStrLocation(h + rhs.abs() as usize, n),
|
Addr::PStrLocation(h, n) => Addr::PStrLocation(h + rhs.abs() as usize, n),
|
||||||
_ => self,
|
_ => self,
|
||||||
}
|
}
|
||||||
@@ -200,11 +332,12 @@ impl Sub<usize> for Addr {
|
|||||||
|
|
||||||
fn sub(self, rhs: usize) -> Self::Output {
|
fn sub(self, rhs: usize) -> Self::Output {
|
||||||
match self {
|
match self {
|
||||||
|
Addr::Stream(h) => Addr::Stream(h - rhs),
|
||||||
|
Addr::Con(h) => Addr::Con(h - rhs),
|
||||||
Addr::Lis(a) => Addr::Lis(a - rhs),
|
Addr::Lis(a) => Addr::Lis(a - rhs),
|
||||||
Addr::AttrVar(h) => Addr::AttrVar(h - rhs),
|
Addr::AttrVar(h) => Addr::AttrVar(h - rhs),
|
||||||
Addr::HeapCell(h) => Addr::HeapCell(h - rhs),
|
Addr::HeapCell(h) => Addr::HeapCell(h - rhs),
|
||||||
Addr::Str(s) => Addr::Str(s - rhs),
|
Addr::Str(s) => Addr::Str(s - rhs),
|
||||||
Addr::PStrTail(h, n) => Addr::PStrTail(h - rhs, n),
|
|
||||||
Addr::PStrLocation(h, n) => Addr::PStrLocation(h - rhs, n),
|
Addr::PStrLocation(h, n) => Addr::PStrLocation(h - rhs, n),
|
||||||
_ => self,
|
_ => self,
|
||||||
}
|
}
|
||||||
@@ -217,7 +350,7 @@ impl SubAssign<usize> for Addr {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub enum TrailRef {
|
pub enum TrailRef {
|
||||||
Ref(Ref),
|
Ref(Ref),
|
||||||
AttrVarHeapLink(usize),
|
AttrVarHeapLink(usize),
|
||||||
@@ -230,30 +363,87 @@ impl From<Ref> for TrailRef {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, PartialEq)]
|
#[derive(Debug)]
|
||||||
pub enum HeapCellValue {
|
pub enum HeapCellValue {
|
||||||
Addr(Addr),
|
Addr(Addr),
|
||||||
|
Atom(ClauseName, Option<SharedOpDesc>),
|
||||||
|
DBRef(DBRef),
|
||||||
|
Integer(Rc<Integer>),
|
||||||
NamedStr(usize, ClauseName, Option<SharedOpDesc>), // arity, name, precedence/Specifier if it has one.
|
NamedStr(usize, ClauseName, Option<SharedOpDesc>), // arity, name, precedence/Specifier if it has one.
|
||||||
PartialString(PartialString),
|
Rational(Rc<Rational>),
|
||||||
|
PartialString(PartialString, bool), // the partial string, a bool indicating whether it came from a Constant.
|
||||||
|
Stream(Stream),
|
||||||
|
TcpListener(TcpListener),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl HeapCellValue {
|
impl HeapCellValue {
|
||||||
|
#[inline]
|
||||||
pub fn as_addr(&self, focus: usize) -> Addr {
|
pub fn as_addr(&self, focus: usize) -> Addr {
|
||||||
match self {
|
match self {
|
||||||
HeapCellValue::Addr(ref a) => {
|
HeapCellValue::Addr(ref a) => {
|
||||||
a.clone()
|
*a
|
||||||
|
}
|
||||||
|
HeapCellValue::Atom(..) | HeapCellValue::DBRef(..) | HeapCellValue::Integer(..) |
|
||||||
|
HeapCellValue::Rational(..) => {
|
||||||
|
Addr::Con(focus)
|
||||||
}
|
}
|
||||||
HeapCellValue::NamedStr(_, _, _) => {
|
HeapCellValue::NamedStr(_, _, _) => {
|
||||||
Addr::Str(focus)
|
Addr::Str(focus)
|
||||||
}
|
}
|
||||||
HeapCellValue::PartialString(_) => {
|
HeapCellValue::PartialString(..) => {
|
||||||
Addr::PStrLocation(focus, 0)
|
Addr::PStrLocation(focus, 0)
|
||||||
}
|
}
|
||||||
|
HeapCellValue::Stream(_) => {
|
||||||
|
Addr::Stream(focus)
|
||||||
|
}
|
||||||
|
HeapCellValue::TcpListener(_) => {
|
||||||
|
Addr::TcpListener(focus)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn context_free_clone(&self) -> HeapCellValue {
|
||||||
|
match self {
|
||||||
|
&HeapCellValue::Addr(addr) => {
|
||||||
|
HeapCellValue::Addr(addr)
|
||||||
|
}
|
||||||
|
&HeapCellValue::Atom(ref name, ref op) => {
|
||||||
|
HeapCellValue::Atom(name.clone(), op.clone())
|
||||||
|
}
|
||||||
|
&HeapCellValue::DBRef(ref db_ref) => {
|
||||||
|
HeapCellValue::DBRef(db_ref.clone())
|
||||||
|
}
|
||||||
|
&HeapCellValue::Integer(ref n) => {
|
||||||
|
HeapCellValue::Integer(n.clone())
|
||||||
|
}
|
||||||
|
&HeapCellValue::NamedStr(arity, ref name, ref op) => {
|
||||||
|
HeapCellValue::NamedStr(arity, name.clone(), op.clone())
|
||||||
|
}
|
||||||
|
&HeapCellValue::Rational(ref r) => {
|
||||||
|
HeapCellValue::Rational(r.clone())
|
||||||
|
}
|
||||||
|
&HeapCellValue::PartialString(ref pstr, has_tail) => {
|
||||||
|
HeapCellValue::PartialString(pstr.clone(), has_tail)
|
||||||
|
}
|
||||||
|
&HeapCellValue::Stream(ref stream) => {
|
||||||
|
HeapCellValue::Stream(stream.clone())
|
||||||
|
}
|
||||||
|
&HeapCellValue::TcpListener(_) => {
|
||||||
|
HeapCellValue::Atom(clause_name!("$tcp_listener"), None)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Eq, PartialEq, Ord, PartialOrd)]
|
impl From<Addr> for HeapCellValue {
|
||||||
|
#[inline]
|
||||||
|
fn from(value: Addr) -> HeapCellValue {
|
||||||
|
HeapCellValue::Addr(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd)]
|
||||||
pub enum IndexPtr {
|
pub enum IndexPtr {
|
||||||
DynamicUndefined, // a predicate, declared as dynamic, whose location in code is as yet undefined.
|
DynamicUndefined, // a predicate, declared as dynamic, whose location in code is as yet undefined.
|
||||||
Undefined,
|
Undefined,
|
||||||
@@ -263,7 +453,7 @@ pub enum IndexPtr {
|
|||||||
UserTermExpansion
|
UserTermExpansion
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Ord, PartialOrd, Eq, PartialEq)]
|
#[derive(Debug, Clone, Ord, PartialOrd, Eq, PartialEq)]
|
||||||
pub struct CodeIndex(pub Rc<RefCell<(IndexPtr, ClauseName)>>);
|
pub struct CodeIndex(pub Rc<RefCell<(IndexPtr, ClauseName)>>);
|
||||||
|
|
||||||
impl CodeIndex {
|
impl CodeIndex {
|
||||||
@@ -318,7 +508,7 @@ impl From<(usize, ClauseName)> for CodeIndex {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, PartialEq)]
|
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||||
pub enum DynamicAssertPlace {
|
pub enum DynamicAssertPlace {
|
||||||
Back,
|
Back,
|
||||||
Front,
|
Front,
|
||||||
@@ -342,7 +532,7 @@ impl DynamicAssertPlace {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, PartialEq)]
|
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||||
pub enum DynamicTransactionType {
|
pub enum DynamicTransactionType {
|
||||||
Abolish,
|
Abolish,
|
||||||
Assert(DynamicAssertPlace),
|
Assert(DynamicAssertPlace),
|
||||||
@@ -352,7 +542,7 @@ pub enum DynamicTransactionType {
|
|||||||
Retract, // dynamic index of the clause to remove.
|
Retract, // dynamic index of the clause to remove.
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, PartialOrd, Ord, PartialEq, Eq)]
|
#[derive(Debug, Clone, Copy, PartialOrd, Ord, PartialEq, Eq)]
|
||||||
pub enum REPLCodePtr {
|
pub enum REPLCodePtr {
|
||||||
CompileBatch,
|
CompileBatch,
|
||||||
UseModule,
|
UseModule,
|
||||||
@@ -361,7 +551,7 @@ pub enum REPLCodePtr {
|
|||||||
UseQualifiedModuleFromFile
|
UseQualifiedModuleFromFile
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
pub enum CodePtr {
|
pub enum CodePtr {
|
||||||
BuiltInClause(BuiltInClauseType, LocalCodePtr), // local is the successor call.
|
BuiltInClause(BuiltInClauseType, LocalCodePtr), // local is the successor call.
|
||||||
CallN(usize, LocalCodePtr, bool), // arity, local, last call.
|
CallN(usize, LocalCodePtr, bool), // arity, local, last call.
|
||||||
@@ -428,37 +618,31 @@ impl LocalCodePtr {
|
|||||||
LocalCodePtr::DirEntry(p) => {
|
LocalCodePtr::DirEntry(p) => {
|
||||||
heap.append(functor!(
|
heap.append(functor!(
|
||||||
"dir_entry",
|
"dir_entry",
|
||||||
1,
|
[integer(*p)]
|
||||||
[heap_integer!(Integer::from(*p))]
|
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
LocalCodePtr::InSituDirEntry(p) => {
|
LocalCodePtr::InSituDirEntry(p) => {
|
||||||
heap.append(functor!(
|
heap.append(functor!(
|
||||||
"in_situ_dir_entry",
|
"in_situ_dir_entry",
|
||||||
1,
|
[integer(*p)]
|
||||||
[heap_integer!(Integer::from(*p))]
|
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
LocalCodePtr::TopLevel(chunk_num, offset) => {
|
LocalCodePtr::TopLevel(chunk_num, offset) => {
|
||||||
heap.append(functor!(
|
heap.append(functor!(
|
||||||
"top_level",
|
"top_level",
|
||||||
2,
|
[integer(*chunk_num), integer(*offset)]
|
||||||
[heap_integer!(Integer::from(*chunk_num)),
|
|
||||||
heap_integer!(Integer::from(*offset))]
|
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
LocalCodePtr::UserGoalExpansion(p) => {
|
LocalCodePtr::UserGoalExpansion(p) => {
|
||||||
heap.append(functor!(
|
heap.append(functor!(
|
||||||
"user_goal_expansion",
|
"user_goal_expansion",
|
||||||
1,
|
[integer(*p)]
|
||||||
[heap_integer!(Integer::from(*p))]
|
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
LocalCodePtr::UserTermExpansion(p) => {
|
LocalCodePtr::UserTermExpansion(p) => {
|
||||||
heap.append(functor!(
|
heap.append(functor!(
|
||||||
"user_term_expansion",
|
"user_term_expansion",
|
||||||
1,
|
[integer(*p)]
|
||||||
[heap_integer!(Integer::from(*p))]
|
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -470,8 +654,12 @@ impl LocalCodePtr {
|
|||||||
impl PartialOrd<CodePtr> for CodePtr {
|
impl PartialOrd<CodePtr> for CodePtr {
|
||||||
fn partial_cmp(&self, other: &CodePtr) -> Option<Ordering> {
|
fn partial_cmp(&self, other: &CodePtr) -> Option<Ordering> {
|
||||||
match (self, other) {
|
match (self, other) {
|
||||||
(&CodePtr::Local(ref l1), &CodePtr::Local(ref l2)) => l1.partial_cmp(l2),
|
(&CodePtr::Local(ref l1), &CodePtr::Local(ref l2)) => {
|
||||||
_ => Some(Ordering::Greater),
|
l1.partial_cmp(l2)
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
Some(Ordering::Greater)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -486,8 +674,12 @@ impl PartialOrd<LocalCodePtr> for LocalCodePtr {
|
|||||||
| (&LocalCodePtr::TopLevel(_, p1), &LocalCodePtr::TopLevel(_, ref p2)) => {
|
| (&LocalCodePtr::TopLevel(_, p1), &LocalCodePtr::TopLevel(_, ref p2)) => {
|
||||||
p1.partial_cmp(p2)
|
p1.partial_cmp(p2)
|
||||||
}
|
}
|
||||||
(_, &LocalCodePtr::TopLevel(_, _)) => Some(Ordering::Less),
|
(_, &LocalCodePtr::TopLevel(_, _)) => {
|
||||||
_ => Some(Ordering::Greater),
|
Some(Ordering::Less)
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
Some(Ordering::Greater)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -578,7 +770,7 @@ impl AddAssign<usize> for CodePtr {
|
|||||||
pub type HeapVarDict = IndexMap<Rc<Var>, Addr>;
|
pub type HeapVarDict = IndexMap<Rc<Var>, Addr>;
|
||||||
pub type AllocVarDict = IndexMap<Rc<Var>, VarData>;
|
pub type AllocVarDict = IndexMap<Rc<Var>, VarData>;
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct DynamicPredicateInfo {
|
pub struct DynamicPredicateInfo {
|
||||||
pub(super) clauses_subsection_p: usize, // a LocalCodePtr::DirEntry value.
|
pub(super) clauses_subsection_p: usize, // a LocalCodePtr::DirEntry value.
|
||||||
}
|
}
|
||||||
@@ -598,6 +790,7 @@ pub type DynamicCodeDir = IndexMap<(ClauseName, ClauseName, usize), DynamicPredi
|
|||||||
|
|
||||||
pub type GlobalVarDir = IndexMap<ClauseName, (Ball, Option<usize>)>;
|
pub type GlobalVarDir = IndexMap<ClauseName, (Ball, Option<usize>)>;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
pub(crate) struct ModuleStub {
|
pub(crate) struct ModuleStub {
|
||||||
pub(crate) atom_tbl: TabledData<Atom>,
|
pub(crate) atom_tbl: TabledData<Atom>,
|
||||||
pub(crate) in_situ_code_dir: InSituCodeDir,
|
pub(crate) in_situ_code_dir: InSituCodeDir,
|
||||||
@@ -613,17 +806,22 @@ impl ModuleStub {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) type ModuleStubDir = IndexMap<ClauseName, ModuleStub>;
|
pub(crate) type ModuleStubDir = IndexMap<ClauseName, ModuleStub>;
|
||||||
|
pub(crate) type StreamAliasDir = IndexMap<ClauseName, Stream>;
|
||||||
|
pub(crate) type StreamDir = BTreeSet<Stream>;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
pub struct IndexStore {
|
pub struct IndexStore {
|
||||||
pub(super) atom_tbl: TabledData<Atom>,
|
pub(super) atom_tbl: TabledData<Atom>,
|
||||||
pub(super) code_dir: CodeDir,
|
pub(super) code_dir: CodeDir,
|
||||||
pub(super) module_dir: ModuleDir,
|
|
||||||
pub(super) dynamic_code_dir: DynamicCodeDir,
|
pub(super) dynamic_code_dir: DynamicCodeDir,
|
||||||
pub(super) global_variables: GlobalVarDir,
|
pub(super) global_variables: GlobalVarDir,
|
||||||
pub(super) in_situ_code_dir: InSituCodeDir,
|
pub(super) in_situ_code_dir: InSituCodeDir,
|
||||||
pub(super) in_situ_module_dir: ModuleStubDir,
|
pub(super) in_situ_module_dir: ModuleStubDir,
|
||||||
|
pub(super) module_dir: ModuleDir,
|
||||||
pub(super) modules: ModuleDir,
|
pub(super) modules: ModuleDir,
|
||||||
pub(super) op_dir: OpDir,
|
pub(super) op_dir: OpDir,
|
||||||
|
pub(super) streams: StreamDir,
|
||||||
|
pub(super) stream_aliases: StreamAliasDir,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl IndexStore {
|
impl IndexStore {
|
||||||
@@ -710,6 +908,8 @@ impl IndexStore {
|
|||||||
in_situ_module_dir: ModuleStubDir::new(),
|
in_situ_module_dir: ModuleStubDir::new(),
|
||||||
op_dir: default_op_dir(),
|
op_dir: default_op_dir(),
|
||||||
modules: ModuleDir::new(),
|
modules: ModuleDir::new(),
|
||||||
|
stream_aliases: StreamAliasDir::new(),
|
||||||
|
streams: StreamDir::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -740,13 +940,13 @@ impl IndexStore {
|
|||||||
let r_w_h = clause_name!("run_cleaners_with_handling");
|
let r_w_h = clause_name!("run_cleaners_with_handling");
|
||||||
let r_wo_h = clause_name!("run_cleaners_without_handling");
|
let r_wo_h = clause_name!("run_cleaners_without_handling");
|
||||||
|
|
||||||
let non_iso = clause_name!("non_iso");
|
let iso_ext = clause_name!("iso_ext");
|
||||||
|
|
||||||
let r_w_h = self
|
let r_w_h = self
|
||||||
.get_internal(r_w_h, 0, non_iso.clone())
|
.get_internal(r_w_h, 0, iso_ext.clone())
|
||||||
.and_then(|item| item.local());
|
.and_then(|item| item.local());
|
||||||
let r_wo_h = self
|
let r_wo_h = self
|
||||||
.get_internal(r_wo_h, 1, non_iso)
|
.get_internal(r_wo_h, 1, iso_ext)
|
||||||
.and_then(|item| item.local());
|
.and_then(|item| item.local());
|
||||||
|
|
||||||
if let Some(r_w_h) = r_w_h {
|
if let Some(r_w_h) = r_w_h {
|
||||||
@@ -762,6 +962,7 @@ impl IndexStore {
|
|||||||
pub type CodeDir = BTreeMap<PredicateKey, CodeIndex>;
|
pub type CodeDir = BTreeMap<PredicateKey, CodeIndex>;
|
||||||
pub type TermDir = IndexMap<PredicateKey, (Predicate, VecDeque<TopLevel>)>;
|
pub type TermDir = IndexMap<PredicateKey, (Predicate, VecDeque<TopLevel>)>;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
pub struct TermDirQuantumEntry {
|
pub struct TermDirQuantumEntry {
|
||||||
pub old_terms: (Predicate, VecDeque<TopLevel>),
|
pub old_terms: (Predicate, VecDeque<TopLevel>),
|
||||||
pub new_terms: (Predicate, VecDeque<TopLevel>),
|
pub new_terms: (Predicate, VecDeque<TopLevel>),
|
||||||
@@ -790,6 +991,7 @@ impl TermDirQuantumEntry {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
pub struct TermDirQuantum(IndexMap<PredicateKey, TermDirQuantumEntry>);
|
pub struct TermDirQuantum(IndexMap<PredicateKey, TermDirQuantumEntry>);
|
||||||
|
|
||||||
impl TermDirQuantum {
|
impl TermDirQuantum {
|
||||||
@@ -833,7 +1035,7 @@ impl TermDirQuantum {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, PartialEq, Eq, Ord, PartialOrd)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Ord, PartialOrd)]
|
||||||
pub enum CompileTimeHook {
|
pub enum CompileTimeHook {
|
||||||
GoalExpansion,
|
GoalExpansion,
|
||||||
TermExpansion,
|
TermExpansion,
|
||||||
@@ -887,6 +1089,16 @@ pub enum RefOrOwned<'a, T: 'a> {
|
|||||||
Owned(T),
|
Owned(T),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'a, T: 'a + fmt::Debug> fmt::Debug for RefOrOwned<'a, T> {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
match self {
|
||||||
|
&RefOrOwned::Borrowed(ref borrowed) =>
|
||||||
|
write!(f, "Borrowed({:?})", borrowed),
|
||||||
|
&RefOrOwned::Owned(ref owned) => write!(f, "Owned({:?})", owned),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<'a, T> RefOrOwned<'a, T> {
|
impl<'a, T> RefOrOwned<'a, T> {
|
||||||
pub fn as_ref(&'a self) -> &'a T {
|
pub fn as_ref(&'a self) -> &'a T {
|
||||||
match self {
|
match self {
|
||||||
File diff suppressed because it is too large
Load Diff
3375
src/machine/machine_state_impl.rs
Normal file
3375
src/machine/machine_state_impl.rs
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,12 +1,12 @@
|
|||||||
use prolog_parser::ast::*;
|
use crate::prolog_parser::ast::*;
|
||||||
use prolog_parser::tabled_rc::*;
|
use crate::prolog_parser::tabled_rc::*;
|
||||||
|
|
||||||
use crate::prolog::clause_types::*;
|
use crate::clause_types::*;
|
||||||
use crate::prolog::forms::*;
|
use crate::forms::*;
|
||||||
use crate::prolog::heap_print::*;
|
use crate::heap_print::*;
|
||||||
use crate::prolog::instructions::*;
|
use crate::instructions::*;
|
||||||
use crate::prolog::machine::heap::*;
|
use crate::machine::heap::*;
|
||||||
use crate::prolog::read::*;
|
use crate::read::*;
|
||||||
|
|
||||||
mod attributed_variables;
|
mod attributed_variables;
|
||||||
pub(super) mod code_repo;
|
pub(super) mod code_repo;
|
||||||
@@ -19,37 +19,41 @@ pub mod machine_errors;
|
|||||||
pub mod machine_indices;
|
pub mod machine_indices;
|
||||||
pub(super) mod machine_state;
|
pub(super) mod machine_state;
|
||||||
pub mod modules;
|
pub mod modules;
|
||||||
mod partial_string;
|
pub mod partial_string;
|
||||||
mod raw_block;
|
mod raw_block;
|
||||||
mod stack;
|
mod stack;
|
||||||
|
pub(crate) mod streams;
|
||||||
pub(super) mod term_expansion;
|
pub(super) mod term_expansion;
|
||||||
pub mod toplevel;
|
pub mod toplevel;
|
||||||
|
|
||||||
|
#[macro_use]
|
||||||
|
mod arithmetic_ops;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
mod machine_state_impl;
|
mod machine_state_impl;
|
||||||
mod system_calls;
|
mod system_calls;
|
||||||
|
|
||||||
use crate::prolog::machine::attributed_variables::*;
|
use crate::machine::attributed_variables::*;
|
||||||
use crate::prolog::machine::code_repo::*;
|
use crate::machine::code_repo::*;
|
||||||
use crate::prolog::machine::compile::*;
|
use crate::machine::compile::*;
|
||||||
use crate::prolog::machine::machine_errors::*;
|
use crate::machine::machine_errors::*;
|
||||||
use crate::prolog::machine::machine_indices::*;
|
use crate::machine::machine_indices::*;
|
||||||
use crate::prolog::machine::machine_state::*;
|
use crate::machine::machine_state::*;
|
||||||
use crate::prolog::machine::modules::*;
|
use crate::machine::modules::*;
|
||||||
use crate::prolog::machine::toplevel::*;
|
use crate::machine::streams::*;
|
||||||
use crate::prolog::read::PrologStream;
|
use crate::machine::toplevel::*;
|
||||||
|
|
||||||
use indexmap::IndexMap;
|
use crate::indexmap::IndexMap;
|
||||||
|
|
||||||
use std::collections::VecDeque;
|
use std::collections::VecDeque;
|
||||||
|
use std::convert::TryFrom;
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io::Read;
|
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use std::ops::Index;
|
use std::ops::Index;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use std::sync::atomic::AtomicBool;
|
use std::sync::atomic::AtomicBool;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
pub struct MachinePolicies {
|
pub struct MachinePolicies {
|
||||||
call_policy: Box<dyn CallPolicy>,
|
call_policy: Box<dyn CallPolicy>,
|
||||||
cut_policy: Box<dyn CutPolicy>,
|
cut_policy: Box<dyn CutPolicy>,
|
||||||
@@ -69,6 +73,14 @@ impl MachinePolicies {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Default for MachinePolicies {
|
||||||
|
#[inline]
|
||||||
|
fn default() -> Self {
|
||||||
|
MachinePolicies::new()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
pub struct Machine {
|
pub struct Machine {
|
||||||
pub(super) machine_st: MachineState,
|
pub(super) machine_st: MachineState,
|
||||||
pub(super) inner_heap: Heap,
|
pub(super) inner_heap: Heap,
|
||||||
@@ -76,7 +88,8 @@ pub struct Machine {
|
|||||||
pub(super) indices: IndexStore,
|
pub(super) indices: IndexStore,
|
||||||
pub(super) code_repo: CodeRepo,
|
pub(super) code_repo: CodeRepo,
|
||||||
pub(super) toplevel_idx: usize,
|
pub(super) toplevel_idx: usize,
|
||||||
pub(super) prolog_stream: ParsingStream<Box<dyn Read>>,
|
pub(super) current_input_stream: Stream,
|
||||||
|
pub(super) current_output_stream: Stream,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Index<LocalCodePtr> for CodeRepo {
|
impl Index<LocalCodePtr> for CodeRepo {
|
||||||
@@ -149,7 +162,15 @@ impl SubModuleUser for IndexStore {
|
|||||||
fn insert_dir_entry(&mut self, name: ClauseName, arity: usize, idx: CodeIndex) {
|
fn insert_dir_entry(&mut self, name: ClauseName, arity: usize, idx: CodeIndex) {
|
||||||
if let Some(ref code_idx) = self.code_dir.get(&(name.clone(), arity)) {
|
if let Some(ref code_idx) = self.code_dir.get(&(name.clone(), arity)) {
|
||||||
if !code_idx.is_undefined() {
|
if !code_idx.is_undefined() {
|
||||||
println!("Warning: overwriting {}/{}", &name, arity);
|
match (name.as_str(), arity) {
|
||||||
|
("term_expansion", 2) => {
|
||||||
|
}
|
||||||
|
("goal_expansion", 2) => {
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
println!("Warning: overwriting {}/{}", &name, arity);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let (p, module_name) = idx.0.borrow().clone();
|
let (p, module_name) = idx.0.borrow().clone();
|
||||||
@@ -191,13 +212,6 @@ impl SubModuleUser for IndexStore {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn current_dir() -> std::path::PathBuf {
|
|
||||||
let mut path_buf = std::path::PathBuf::from(file!());
|
|
||||||
path_buf.pop();
|
|
||||||
path_buf
|
|
||||||
}
|
|
||||||
|
|
||||||
include!(concat!(env!("OUT_DIR"), "/libraries.rs"));
|
include!(concat!(env!("OUT_DIR"), "/libraries.rs"));
|
||||||
|
|
||||||
static TOPLEVEL: &str = include_str!("../toplevel.pl");
|
static TOPLEVEL: &str = include_str!("../toplevel.pl");
|
||||||
@@ -205,14 +219,13 @@ static TOPLEVEL: &str = include_str!("../toplevel.pl");
|
|||||||
impl Machine {
|
impl Machine {
|
||||||
fn compile_special_forms(&mut self)
|
fn compile_special_forms(&mut self)
|
||||||
{
|
{
|
||||||
let current_dir = current_dir();
|
let verify_attrs_src = ListingSource::User;
|
||||||
|
|
||||||
let verify_attrs_src = ListingSource::from_file_and_path(
|
match compile_special_form(
|
||||||
clause_name!("attributed_variables.pl"),
|
self,
|
||||||
current_dir.clone(),
|
Stream::from(VERIFY_ATTRS),
|
||||||
);
|
verify_attrs_src,
|
||||||
|
)
|
||||||
match compile_special_form(self, parsing_stream(VERIFY_ATTRS.as_bytes()), verify_attrs_src)
|
|
||||||
{
|
{
|
||||||
Ok(p) => {
|
Ok(p) => {
|
||||||
self.machine_st.attr_var_init.verify_attrs_loc = p;
|
self.machine_st.attr_var_init.verify_attrs_loc = p;
|
||||||
@@ -221,12 +234,13 @@ impl Machine {
|
|||||||
panic!("Machine::compile_special_forms() failed at VERIFY_ATTRS"),
|
panic!("Machine::compile_special_forms() failed at VERIFY_ATTRS"),
|
||||||
}
|
}
|
||||||
|
|
||||||
let project_attrs_src = ListingSource::from_file_and_path(
|
let project_attrs_src = ListingSource::User;
|
||||||
clause_name!("project_attributes.pl"),
|
|
||||||
current_dir,
|
|
||||||
);
|
|
||||||
|
|
||||||
match compile_special_form(self, parsing_stream(PROJECT_ATTRS.as_bytes()), project_attrs_src)
|
match compile_special_form(
|
||||||
|
self,
|
||||||
|
Stream::from(PROJECT_ATTRS),
|
||||||
|
project_attrs_src,
|
||||||
|
)
|
||||||
{
|
{
|
||||||
Ok(p) => {
|
Ok(p) => {
|
||||||
self.machine_st.attr_var_init.project_attrs_loc = p;
|
self.machine_st.attr_var_init.project_attrs_loc = p;
|
||||||
@@ -240,17 +254,11 @@ impl Machine {
|
|||||||
{
|
{
|
||||||
self.toplevel_idx = self.code_repo.code.len();
|
self.toplevel_idx = self.code_repo.code.len();
|
||||||
|
|
||||||
let mut current_dir = current_dir();
|
let top_lvl_src = ListingSource::User;
|
||||||
current_dir.pop();
|
|
||||||
|
|
||||||
let top_lvl_src = ListingSource::from_file_and_path(
|
|
||||||
clause_name!("toplevel.pl"),
|
|
||||||
current_dir,
|
|
||||||
);
|
|
||||||
|
|
||||||
compile_user_module(
|
compile_user_module(
|
||||||
self,
|
self,
|
||||||
parsing_stream(TOPLEVEL.as_bytes()),
|
Stream::from(TOPLEVEL),
|
||||||
true,
|
true,
|
||||||
top_lvl_src,
|
top_lvl_src,
|
||||||
);
|
);
|
||||||
@@ -264,7 +272,11 @@ impl Machine {
|
|||||||
|
|
||||||
Ok(self.indices.insert_module(module))
|
Ok(self.indices.insert_module(module))
|
||||||
} else {
|
} else {
|
||||||
Err(SessionError::ModuleNotFound)
|
let err = ExistenceError::ModuleSource(ModuleSource::File(
|
||||||
|
clause_name!("$toplevel"),
|
||||||
|
));
|
||||||
|
|
||||||
|
Err(SessionError::ExistenceError(err))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -278,7 +290,10 @@ impl Machine {
|
|||||||
|
|
||||||
if path.is_file() {
|
if path.is_file() {
|
||||||
let file_src = match File::open(&path) {
|
let file_src = match File::open(&path) {
|
||||||
Ok(file_handle) => parsing_stream(file_handle),
|
Ok(file_handle) => Stream::from_file_as_input(
|
||||||
|
clause_name!(".scryerrc"),
|
||||||
|
file_handle,
|
||||||
|
),
|
||||||
Err(_) => return,
|
Err(_) => return,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -293,47 +308,46 @@ impl Machine {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
pub fn reset(&mut self) {
|
pub fn reset(&mut self) {
|
||||||
self.prolog_stream = readline::input_stream();
|
self.current_input_stream = readline::input_stream();
|
||||||
self.policies.cut_policy = Box::new(DefaultCutPolicy {});
|
self.policies.cut_policy = Box::new(DefaultCutPolicy {});
|
||||||
self.machine_st.reset();
|
self.machine_st.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_init_code(&mut self, code: Code) -> bool {
|
pub fn run_init_code(&mut self, code: Code) -> bool {
|
||||||
let old_machine_st = self.sink_to_snapshot();
|
let old_machine_st = self.sink_to_snapshot();
|
||||||
self.machine_st.reset();
|
self.machine_st.reset();
|
||||||
|
|
||||||
self.code_repo.cached_query = code;
|
self.code_repo.cached_query = code;
|
||||||
self.run_query();
|
self.run_query();
|
||||||
|
|
||||||
let result = self.machine_st.fail;
|
let result = self.machine_st.fail;
|
||||||
self.absorb_snapshot(old_machine_st);
|
self.absorb_snapshot(old_machine_st);
|
||||||
|
|
||||||
!result
|
!result
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_top_level(&mut self) {
|
pub fn run_top_level(&mut self) {
|
||||||
use std::env;
|
use std::env;
|
||||||
|
|
||||||
let mut filename_atoms = vec![];
|
let mut arg_pstrs = vec![];
|
||||||
|
|
||||||
// the first of these is the path to the scryer-prolog executable, so skip
|
for arg in env::args() {
|
||||||
// it.
|
arg_pstrs.push(self.machine_st.heap.put_complete_string(&arg));
|
||||||
for filename in env::args().skip(1) {
|
}
|
||||||
let atom = atom!(filename, self.indices.atom_tbl);
|
|
||||||
filename_atoms.push(Addr::Con(atom));
|
|
||||||
}
|
|
||||||
|
|
||||||
let list_addr =
|
let list_addr = Addr::HeapCell(self.machine_st.heap.to_list(arg_pstrs.into_iter()));
|
||||||
Addr::HeapCell(self.machine_st.heap.to_list(filename_atoms.into_iter()));
|
self.machine_st[temp_v!(1)] = list_addr;
|
||||||
|
|
||||||
self.machine_st[temp_v!(1)] = list_addr;
|
loop {
|
||||||
self.machine_st.p = CodePtr::Local(LocalCodePtr::DirEntry(self.toplevel_idx));
|
self.machine_st.p = CodePtr::Local(LocalCodePtr::DirEntry(self.toplevel_idx));
|
||||||
|
self.run_query();
|
||||||
self.run_query();
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new(prolog_stream: PrologStream) -> Self
|
pub fn new(current_input_stream: Stream, current_output_stream: Stream) -> Self
|
||||||
{
|
{
|
||||||
|
use crate::ref_thread_local::RefThreadLocal;
|
||||||
|
|
||||||
let mut wam = Machine {
|
let mut wam = Machine {
|
||||||
machine_st: MachineState::new(),
|
machine_st: MachineState::new(),
|
||||||
inner_heap: Heap::new(),
|
inner_heap: Heap::new(),
|
||||||
@@ -341,53 +355,64 @@ impl Machine {
|
|||||||
indices: IndexStore::new(),
|
indices: IndexStore::new(),
|
||||||
code_repo: CodeRepo::new(),
|
code_repo: CodeRepo::new(),
|
||||||
toplevel_idx: 0,
|
toplevel_idx: 0,
|
||||||
prolog_stream,
|
current_input_stream,
|
||||||
|
current_output_stream,
|
||||||
};
|
};
|
||||||
|
|
||||||
let atom_tbl = wam.indices.atom_tbl.clone();
|
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();
|
wam.indices.add_term_and_goal_expansion_indices();
|
||||||
|
|
||||||
compile_listing(
|
compile_listing(
|
||||||
&mut wam,
|
&mut wam,
|
||||||
parsing_stream(BUILTINS.as_bytes()),
|
Stream::from(LIBRARIES.borrow()["builtins"]),
|
||||||
default_index_store!(atom_tbl.clone()),
|
default_index_store!(atom_tbl.clone()),
|
||||||
true,
|
true,
|
||||||
ListingSource::from_file_and_path(
|
ListingSource::User,
|
||||||
clause_name!("builtins.pl"),
|
|
||||||
lib_path.clone(),
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
|
|
||||||
wam.compile_special_forms();
|
wam.compile_special_forms();
|
||||||
|
|
||||||
compile_user_module(&mut wam, parsing_stream(ERROR.as_bytes()), true,
|
compile_user_module(
|
||||||
ListingSource::from_file_and_path(
|
&mut wam,
|
||||||
clause_name!("error"),
|
Stream::from(LIBRARIES.borrow()["error"]),
|
||||||
lib_path.clone(),
|
true,
|
||||||
)
|
ListingSource::User,
|
||||||
);
|
);
|
||||||
compile_user_module(&mut wam, parsing_stream(LISTS.as_bytes()), true,
|
|
||||||
ListingSource::from_file_and_path(
|
compile_user_module(
|
||||||
clause_name!("lists"),
|
&mut wam,
|
||||||
lib_path.clone(),
|
Stream::from(LIBRARIES.borrow()["pairs"]),
|
||||||
),
|
true,
|
||||||
|
ListingSource::User,
|
||||||
);
|
);
|
||||||
compile_user_module(&mut wam, parsing_stream(NON_ISO.as_bytes()), true,
|
|
||||||
ListingSource::from_file_and_path(
|
compile_user_module(
|
||||||
clause_name!("non_iso"),
|
&mut wam,
|
||||||
lib_path.clone(),
|
Stream::from(LIBRARIES.borrow()["lists"]),
|
||||||
)
|
true,
|
||||||
|
ListingSource::User,
|
||||||
);
|
);
|
||||||
compile_user_module(&mut wam, parsing_stream(SI.as_bytes()), true,
|
|
||||||
ListingSource::from_file_and_path(
|
compile_user_module(
|
||||||
clause_name!("si"),
|
&mut wam,
|
||||||
lib_path.clone(),
|
Stream::from(LIBRARIES.borrow()["iso_ext"]),
|
||||||
)
|
true,
|
||||||
|
ListingSource::User,
|
||||||
|
);
|
||||||
|
|
||||||
|
compile_user_module(
|
||||||
|
&mut wam,
|
||||||
|
Stream::from(LIBRARIES.borrow()["si"]),
|
||||||
|
true,
|
||||||
|
ListingSource::User,
|
||||||
|
);
|
||||||
|
|
||||||
|
compile_user_module(
|
||||||
|
&mut wam,
|
||||||
|
Stream::from(LIBRARIES.borrow()["charsio"]),
|
||||||
|
true,
|
||||||
|
ListingSource::User,
|
||||||
);
|
);
|
||||||
|
|
||||||
if wam.compile_top_level().is_err() {
|
if wam.compile_top_level().is_err() {
|
||||||
@@ -395,10 +420,35 @@ impl Machine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
wam.compile_scryerrc();
|
wam.compile_scryerrc();
|
||||||
|
wam.configure_streams();
|
||||||
|
|
||||||
wam
|
wam
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn configure_streams(&mut self) {
|
||||||
|
self.current_input_stream.options.alias = Some(clause_name!("user_input"));
|
||||||
|
|
||||||
|
self.indices.stream_aliases.insert(
|
||||||
|
clause_name!("user_input"),
|
||||||
|
self.current_input_stream.clone(),
|
||||||
|
);
|
||||||
|
|
||||||
|
self.indices.streams.insert(
|
||||||
|
self.current_input_stream.clone()
|
||||||
|
);
|
||||||
|
|
||||||
|
self.current_output_stream.options.alias = Some(clause_name!("user_output"));
|
||||||
|
|
||||||
|
self.indices.stream_aliases.insert(
|
||||||
|
clause_name!("user_output"),
|
||||||
|
self.current_output_stream.clone(),
|
||||||
|
);
|
||||||
|
|
||||||
|
self.indices.streams.insert(
|
||||||
|
self.current_output_stream.clone()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn machine_flags(&self) -> MachineFlags {
|
pub fn machine_flags(&self) -> MachineFlags {
|
||||||
self.machine_st.flags
|
self.machine_st.flags
|
||||||
@@ -504,53 +554,57 @@ impl Machine {
|
|||||||
|
|
||||||
fn extract_module_export_list(&mut self) -> Result<Vec<ModuleExport>, ParserError>
|
fn extract_module_export_list(&mut self) -> Result<Vec<ModuleExport>, ParserError>
|
||||||
{
|
{
|
||||||
let mut export_list = self.machine_st[temp_v!(2)].clone();
|
let mut export_list = self.machine_st[temp_v!(2)].clone();
|
||||||
let mut exports = vec![];
|
let mut exports = vec![];
|
||||||
|
|
||||||
while let Addr::Lis(l) = self.machine_st.store(self.machine_st.deref(export_list)) {
|
while let Addr::Lis(l) = self.machine_st.store(self.machine_st.deref(export_list)) {
|
||||||
match &self.machine_st.heap[l] {
|
match &self.machine_st.heap[l] {
|
||||||
&HeapCellValue::Addr(Addr::Str(s)) => {
|
&HeapCellValue::Addr(Addr::Str(s)) => {
|
||||||
match &self.machine_st.heap[s] {
|
match &self.machine_st.heap[s] {
|
||||||
HeapCellValue::NamedStr(arity, ref name, _)
|
HeapCellValue::NamedStr(arity, ref name, _)
|
||||||
if *arity == 2 && name.as_str() == "/" => {
|
if *arity == 2 && name.as_str() == "/" => {
|
||||||
let name = match &self.machine_st.heap[s+1] {
|
let name = match &self.machine_st.heap[s+1] {
|
||||||
&HeapCellValue::Addr(Addr::Con(Constant::Atom(ref name, _))) =>
|
&HeapCellValue::Atom(ref name, _) =>
|
||||||
name.clone(),
|
name.clone(),
|
||||||
_ =>
|
_ =>
|
||||||
unreachable!()
|
unreachable!()
|
||||||
};
|
};
|
||||||
|
|
||||||
let arity = match &self.machine_st.heap[s+2] {
|
let arity = match &self.machine_st.heap[s+2] {
|
||||||
&HeapCellValue::Addr(Addr::Con(Constant::Integer(ref arity))) =>
|
&HeapCellValue::Integer(ref arity) =>
|
||||||
arity.to_usize().unwrap(),
|
arity.to_usize().unwrap(),
|
||||||
_ =>
|
&HeapCellValue::Addr(Addr::Fixnum(n)) =>
|
||||||
unreachable!()
|
usize::try_from(n).unwrap(),
|
||||||
};
|
_ =>
|
||||||
|
unreachable!()
|
||||||
|
};
|
||||||
|
|
||||||
exports.push(ModuleExport::PredicateKey((name, arity)));
|
exports.push(ModuleExport::PredicateKey((name, arity)));
|
||||||
}
|
}
|
||||||
HeapCellValue::NamedStr(arity, ref name, _)
|
HeapCellValue::NamedStr(arity, ref name, _)
|
||||||
if *arity == 3 && name.as_str() == "op" => {
|
if *arity == 3 && name.as_str() == "op" => {
|
||||||
let name = match &self.machine_st.heap[s+3] {
|
let name = match &self.machine_st.heap[s+3] {
|
||||||
&HeapCellValue::Addr(Addr::Con(Constant::Atom(ref name, _))) =>
|
&HeapCellValue::Atom(ref name, _) =>
|
||||||
name.clone(),
|
name.clone(),
|
||||||
_ =>
|
_ =>
|
||||||
unreachable!()
|
unreachable!()
|
||||||
};
|
};
|
||||||
|
|
||||||
let spec = match &self.machine_st.heap[s+2] {
|
let spec = match &self.machine_st.heap[s+2] {
|
||||||
&HeapCellValue::Addr(Addr::Con(Constant::Atom(ref name, _))) =>
|
&HeapCellValue::Atom(ref name, _) =>
|
||||||
name.clone(),
|
name.clone(),
|
||||||
_ =>
|
_ =>
|
||||||
unreachable!()
|
unreachable!()
|
||||||
};
|
};
|
||||||
|
|
||||||
let prec = match &self.machine_st.heap[s+1] {
|
let prec = match &self.machine_st.heap[s+1] {
|
||||||
&HeapCellValue::Addr(Addr::Con(Constant::Integer(ref arity))) =>
|
&HeapCellValue::Integer(ref arity) =>
|
||||||
arity.to_usize().unwrap(),
|
arity.to_usize().unwrap(),
|
||||||
_ =>
|
&HeapCellValue::Addr(Addr::Fixnum(n)) =>
|
||||||
unreachable!()
|
usize::try_from(n).unwrap(),
|
||||||
};
|
_ =>
|
||||||
|
unreachable!()
|
||||||
|
};
|
||||||
|
|
||||||
exports.push(ModuleExport::OpDecl(to_op_decl(
|
exports.push(ModuleExport::OpDecl(to_op_decl(
|
||||||
prec,
|
prec,
|
||||||
@@ -560,43 +614,58 @@ impl Machine {
|
|||||||
}
|
}
|
||||||
_ => unreachable!()
|
_ => unreachable!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => unreachable!()
|
_ => unreachable!()
|
||||||
|
}
|
||||||
|
|
||||||
|
export_list = self.machine_st.heap[l+1].as_addr(l+1);
|
||||||
}
|
}
|
||||||
|
|
||||||
export_list = self.machine_st.heap[l+1].as_addr(l+1);
|
Ok(exports)
|
||||||
}
|
|
||||||
|
|
||||||
Ok(exports)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn use_module<ToSource>(&mut self, to_src: ToSource)
|
fn use_module<ToSource>(&mut self, to_src: ToSource)
|
||||||
where ToSource: Fn(ClauseName) -> ModuleSource
|
where ToSource: Fn(ClauseName) -> ModuleSource
|
||||||
{
|
{
|
||||||
// the term expander will overwrite the cached query, so save it here.
|
// the term expander will overwrite the cached query, so save it here.
|
||||||
let cached_query = mem::replace(&mut self.code_repo.cached_query, vec![]);
|
let cached_query = mem::replace(&mut self.code_repo.cached_query, vec![]);
|
||||||
|
|
||||||
let module_spec = self.machine_st[temp_v!(1)].clone();
|
let module_spec = self.machine_st[temp_v!(1)].clone();
|
||||||
let name = match self.machine_st.store(self.machine_st.deref(module_spec)) {
|
let name = {
|
||||||
Addr::Con(Constant::Atom(name, _)) => name,
|
let addr = self.machine_st.store(self.machine_st.deref(module_spec));
|
||||||
_ => unreachable!()
|
|
||||||
};
|
|
||||||
|
|
||||||
let load_result = match to_src(name) {
|
match self.machine_st.heap.index_addr(&addr).as_ref() {
|
||||||
ModuleSource::Library(name) =>
|
HeapCellValue::Atom(name, _) =>
|
||||||
|
name.clone(),
|
||||||
|
HeapCellValue::Addr(Addr::Char(c)) =>
|
||||||
|
clause_name!(c.to_string(), self.indices.atom_tbl),
|
||||||
|
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!(),
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let load_result = match to_src(name) {
|
||||||
|
ModuleSource::Library(name) =>
|
||||||
if let Some(module) = self.indices.take_module(name.clone()) {
|
if let Some(module) = self.indices.take_module(name.clone()) {
|
||||||
self.indices.remove_module(clause_name!("user"), &module);
|
self.indices.remove_module(clause_name!("user"), &module);
|
||||||
self.indices.modules.insert(name.clone(), module);
|
self.indices.modules.insert(name.clone(), module);
|
||||||
|
|
||||||
Ok(name)
|
Ok(name)
|
||||||
} else {
|
} else {
|
||||||
load_library(self, name, false)
|
load_library(self, name, false)
|
||||||
},
|
},
|
||||||
ModuleSource::File(name) =>
|
ModuleSource::File(name) =>
|
||||||
load_module_from_file(self, PathBuf::from(name.as_str()), false)
|
load_module_from_file(self, PathBuf::from(name.as_str()), false)
|
||||||
};
|
};
|
||||||
|
|
||||||
let result = load_result.and_then(|name| {
|
let result = load_result.and_then(|name| {
|
||||||
let module = self.indices.take_module(name.clone()).unwrap();
|
let module = self.indices.take_module(name.clone()).unwrap();
|
||||||
|
|
||||||
if !module.is_impromptu_module {
|
if !module.is_impromptu_module {
|
||||||
@@ -606,26 +675,34 @@ impl Machine {
|
|||||||
Ok(self.indices.insert_module(module))
|
Ok(self.indices.insert_module(module))
|
||||||
});
|
});
|
||||||
|
|
||||||
self.code_repo.cached_query = cached_query;
|
self.code_repo.cached_query = cached_query;
|
||||||
|
|
||||||
if let Err(e) = result {
|
if let Err(e) = result {
|
||||||
self.throw_session_error(e, (clause_name!("use_module"), 1));
|
self.throw_session_error(e, (clause_name!("use_module"), 1));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn use_qualified_module<ToSource>(&mut self, to_src: ToSource)
|
fn use_qualified_module<ToSource>(&mut self, to_src: ToSource)
|
||||||
where ToSource: Fn(ClauseName) -> ModuleSource
|
where ToSource: Fn(ClauseName) -> ModuleSource
|
||||||
{
|
{
|
||||||
// the term expander will overwrite the cached query, so save it here.
|
// the term expander will overwrite the cached query, so save it here.
|
||||||
let cached_query = mem::replace(&mut self.code_repo.cached_query, vec![]);
|
let cached_query = mem::replace(&mut self.code_repo.cached_query, vec![]);
|
||||||
|
|
||||||
let module_spec = self.machine_st[temp_v!(1)].clone();
|
let module_spec = self.machine_st[temp_v!(1)].clone();
|
||||||
let name = match self.machine_st.store(self.machine_st.deref(module_spec)) {
|
let name = {
|
||||||
Addr::Con(Constant::Atom(name, _)) => name,
|
let addr = self.machine_st.store(self.machine_st.deref(module_spec));
|
||||||
_ => unreachable!()
|
|
||||||
};
|
|
||||||
|
|
||||||
let exports = match self.extract_module_export_list() {
|
match self.machine_st.heap.index_addr(&addr).as_ref() {
|
||||||
|
HeapCellValue::Atom(name, _) =>
|
||||||
|
name.clone(),
|
||||||
|
HeapCellValue::Addr(Addr::Char(c)) =>
|
||||||
|
clause_name!(c.to_string(), self.indices.atom_tbl),
|
||||||
|
_ =>
|
||||||
|
unreachable!(),
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let exports = match self.extract_module_export_list() {
|
||||||
Ok(exports) => exports,
|
Ok(exports) => exports,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
self.throw_session_error(SessionError::from(e), (clause_name!("use_module"), 2));
|
self.throw_session_error(SessionError::from(e), (clause_name!("use_module"), 2));
|
||||||
@@ -633,38 +710,38 @@ impl Machine {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let load_result = match to_src(name) {
|
let load_result = match to_src(name) {
|
||||||
ModuleSource::Library(name) =>
|
ModuleSource::Library(name) =>
|
||||||
if let Some(module) = self.indices.take_module(name.clone()) {
|
if let Some(module) = self.indices.take_module(name.clone()) {
|
||||||
self.indices.remove_module(clause_name!("user"), &module);
|
self.indices.remove_module(clause_name!("user"), &module);
|
||||||
self.indices.modules.insert(name.clone(), module);
|
self.indices.modules.insert(name.clone(), module);
|
||||||
|
|
||||||
Ok(name)
|
Ok(name)
|
||||||
} else {
|
} else {
|
||||||
load_library(self, name, false)
|
load_library(self, name, false)
|
||||||
},
|
},
|
||||||
ModuleSource::File(name) =>
|
ModuleSource::File(name) =>
|
||||||
load_module_from_file(self, PathBuf::from(name.as_str()), false)
|
load_module_from_file(self, PathBuf::from(name.as_str()), false)
|
||||||
};
|
};
|
||||||
|
|
||||||
let result = load_result.and_then(|name| {
|
let result = load_result.and_then(|name| {
|
||||||
let module = self.indices.take_module(name.clone()).unwrap();
|
let module = self.indices.take_module(name.clone()).unwrap();
|
||||||
|
|
||||||
if !module.is_impromptu_module {
|
if !module.is_impromptu_module {
|
||||||
self.indices.use_qualified_module(&mut self.code_repo,
|
self.indices.use_qualified_module(&mut self.code_repo,
|
||||||
self.machine_st.flags,
|
self.machine_st.flags,
|
||||||
&module,
|
&module,
|
||||||
&exports)?;
|
&exports)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(self.indices.insert_module(module))
|
Ok(self.indices.insert_module(module))
|
||||||
});
|
});
|
||||||
|
|
||||||
self.code_repo.cached_query = cached_query;
|
self.code_repo.cached_query = cached_query;
|
||||||
|
|
||||||
if let Err(e) = result {
|
if let Err(e) = result {
|
||||||
self.throw_session_error(e, (clause_name!("use_module"), 2));
|
self.throw_session_error(e, (clause_name!("use_module"), 2));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_toplevel_command(&mut self, code_ptr: REPLCodePtr, p: LocalCodePtr) {
|
fn handle_toplevel_command(&mut self, code_ptr: REPLCodePtr, p: LocalCodePtr) {
|
||||||
@@ -679,14 +756,14 @@ impl Machine {
|
|||||||
self.throw_session_error(e, (clause_name!("repl"), 0));
|
self.throw_session_error(e, (clause_name!("repl"), 0));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
REPLCodePtr::UseModule =>
|
REPLCodePtr::UseModule =>
|
||||||
self.use_module(ModuleSource::Library),
|
self.use_module(ModuleSource::Library),
|
||||||
REPLCodePtr::UseModuleFromFile =>
|
REPLCodePtr::UseModuleFromFile =>
|
||||||
self.use_module(ModuleSource::File),
|
self.use_module(ModuleSource::File),
|
||||||
REPLCodePtr::UseQualifiedModule =>
|
REPLCodePtr::UseQualifiedModule =>
|
||||||
self.use_qualified_module(ModuleSource::Library),
|
self.use_qualified_module(ModuleSource::Library),
|
||||||
REPLCodePtr::UseQualifiedModuleFromFile =>
|
REPLCodePtr::UseQualifiedModuleFromFile =>
|
||||||
self.use_qualified_module(ModuleSource::File)
|
self.use_qualified_module(ModuleSource::File)
|
||||||
}
|
}
|
||||||
|
|
||||||
self.machine_st.p = CodePtr::Local(p);
|
self.machine_st.p = CodePtr::Local(p);
|
||||||
@@ -699,7 +776,7 @@ impl Machine {
|
|||||||
snapshot.e = self.machine_st.e;
|
snapshot.e = self.machine_st.e;
|
||||||
snapshot.b = self.machine_st.b;
|
snapshot.b = self.machine_st.b;
|
||||||
snapshot.b0 = self.machine_st.b0;
|
snapshot.b0 = self.machine_st.b0;
|
||||||
snapshot.s = self.machine_st.s;
|
snapshot.s = self.machine_st.s.clone();
|
||||||
snapshot.tr = self.machine_st.tr;
|
snapshot.tr = self.machine_st.tr;
|
||||||
snapshot.num_of_args = self.machine_st.num_of_args;
|
snapshot.num_of_args = self.machine_st.num_of_args;
|
||||||
|
|
||||||
@@ -743,7 +820,7 @@ impl Machine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn run_query(&mut self) {
|
pub(super) fn run_query(&mut self) {
|
||||||
self.machine_st.cp = LocalCodePtr::TopLevel(0, self.code_repo.size_of_cached_query());
|
self.machine_st.cp = LocalCodePtr::TopLevel(0, self.code_repo.size_of_cached_query());
|
||||||
let end_ptr = CodePtr::Local(self.machine_st.cp);
|
let end_ptr = CodePtr::Local(self.machine_st.cp);
|
||||||
|
|
||||||
while self.machine_st.p < end_ptr {
|
while self.machine_st.p < end_ptr {
|
||||||
@@ -751,12 +828,16 @@ impl Machine {
|
|||||||
&mut self.indices,
|
&mut self.indices,
|
||||||
&mut self.policies,
|
&mut self.policies,
|
||||||
&mut self.code_repo,
|
&mut self.code_repo,
|
||||||
&mut self.prolog_stream,
|
&mut self.current_input_stream,
|
||||||
|
&mut self.current_output_stream,
|
||||||
);
|
);
|
||||||
|
|
||||||
match self.machine_st.p {
|
match self.machine_st.p {
|
||||||
CodePtr::Local(LocalCodePtr::TopLevel(_, p)) if p > 0 => {}
|
CodePtr::Local(LocalCodePtr::TopLevel(_, p)) if p > 0 => {
|
||||||
CodePtr::REPL(code_ptr, p) => self.handle_toplevel_command(code_ptr, p),
|
}
|
||||||
|
CodePtr::REPL(code_ptr, p) => {
|
||||||
|
self.handle_toplevel_command(code_ptr, p)
|
||||||
|
}
|
||||||
CodePtr::DynamicTransaction(trans_type, p) => {
|
CodePtr::DynamicTransaction(trans_type, p) => {
|
||||||
// self.code_repo.cached_query is about to be overwritten by the term expander,
|
// self.code_repo.cached_query is about to be overwritten by the term expander,
|
||||||
// so hold onto it locally and restore it after the compiler has finished.
|
// so hold onto it locally and restore it after the compiler has finished.
|
||||||
@@ -784,29 +865,37 @@ impl MachineState {
|
|||||||
indices: &mut IndexStore,
|
indices: &mut IndexStore,
|
||||||
policies: &mut MachinePolicies,
|
policies: &mut MachinePolicies,
|
||||||
code_repo: &CodeRepo,
|
code_repo: &CodeRepo,
|
||||||
prolog_stream: &mut PrologStream,
|
current_input_stream: &mut Stream,
|
||||||
|
current_output_stream: &mut Stream,
|
||||||
) {
|
) {
|
||||||
match instr {
|
match instr {
|
||||||
&Line::Arithmetic(ref arith_instr) => self.execute_arith_instr(arith_instr),
|
&Line::Arithmetic(ref arith_instr) => {
|
||||||
|
self.execute_arith_instr(arith_instr)
|
||||||
|
}
|
||||||
&Line::Choice(ref choice_instr) => {
|
&Line::Choice(ref choice_instr) => {
|
||||||
self.execute_choice_instr(choice_instr, &mut policies.call_policy)
|
self.execute_choice_instr(choice_instr, &mut policies.call_policy)
|
||||||
}
|
}
|
||||||
&Line::Cut(ref cut_instr) => {
|
&Line::Cut(ref cut_instr) => {
|
||||||
self.execute_cut_instr(cut_instr, &mut policies.cut_policy)
|
self.execute_cut_instr(cut_instr, &mut policies.cut_policy)
|
||||||
}
|
}
|
||||||
&Line::Control(ref control_instr) => self.execute_ctrl_instr(
|
&Line::Control(ref control_instr) => {
|
||||||
indices,
|
self.execute_ctrl_instr(
|
||||||
code_repo,
|
indices,
|
||||||
&mut policies.call_policy,
|
code_repo,
|
||||||
&mut policies.cut_policy,
|
&mut policies.call_policy,
|
||||||
prolog_stream,
|
&mut policies.cut_policy,
|
||||||
control_instr,
|
current_input_stream,
|
||||||
),
|
current_output_stream,
|
||||||
|
control_instr,
|
||||||
|
)
|
||||||
|
}
|
||||||
&Line::Fact(ref fact_instr) => {
|
&Line::Fact(ref fact_instr) => {
|
||||||
self.execute_fact_instr(&fact_instr);
|
self.execute_fact_instr(&fact_instr);
|
||||||
self.p += 1;
|
self.p += 1;
|
||||||
}
|
}
|
||||||
&Line::Indexing(ref indexing_instr) => self.execute_indexing_instr(&indexing_instr),
|
&Line::Indexing(ref indexing_instr) => {
|
||||||
|
self.execute_indexing_instr(&indexing_instr)
|
||||||
|
}
|
||||||
&Line::IndexedChoice(ref choice_instr) => {
|
&Line::IndexedChoice(ref choice_instr) => {
|
||||||
self.execute_indexed_choice_instr(choice_instr, &mut policies.call_policy)
|
self.execute_indexed_choice_instr(choice_instr, &mut policies.call_policy)
|
||||||
}
|
}
|
||||||
@@ -822,14 +911,22 @@ impl MachineState {
|
|||||||
indices: &mut IndexStore,
|
indices: &mut IndexStore,
|
||||||
policies: &mut MachinePolicies,
|
policies: &mut MachinePolicies,
|
||||||
code_repo: &CodeRepo,
|
code_repo: &CodeRepo,
|
||||||
prolog_stream: &mut PrologStream,
|
current_input_stream: &mut Stream,
|
||||||
|
current_output_stream: &mut Stream,
|
||||||
) {
|
) {
|
||||||
let instr = match code_repo.lookup_instr(self.last_call, &self.p) {
|
let instr = match code_repo.lookup_instr(self.last_call, &self.p) {
|
||||||
Some(instr) => instr,
|
Some(instr) => instr,
|
||||||
None => return,
|
None => return,
|
||||||
};
|
};
|
||||||
|
|
||||||
self.dispatch_instr(instr.as_ref(), indices, policies, code_repo, prolog_stream);
|
self.dispatch_instr(
|
||||||
|
instr.as_ref(),
|
||||||
|
indices,
|
||||||
|
policies,
|
||||||
|
code_repo,
|
||||||
|
current_input_stream,
|
||||||
|
current_output_stream,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn backtrack(&mut self) {
|
fn backtrack(&mut self) {
|
||||||
@@ -880,7 +977,8 @@ impl MachineState {
|
|||||||
indices: &mut IndexStore,
|
indices: &mut IndexStore,
|
||||||
policies: &mut MachinePolicies,
|
policies: &mut MachinePolicies,
|
||||||
code_repo: &mut CodeRepo,
|
code_repo: &mut CodeRepo,
|
||||||
prolog_stream: &mut PrologStream,
|
current_input_stream: &mut Stream,
|
||||||
|
current_output_stream: &mut Stream,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
loop {
|
loop {
|
||||||
let instr = match code_repo.lookup_instr(self.last_call, &self.p) {
|
let instr = match code_repo.lookup_instr(self.last_call, &self.p) {
|
||||||
@@ -896,7 +994,14 @@ impl MachineState {
|
|||||||
None => return false,
|
None => return false,
|
||||||
};
|
};
|
||||||
|
|
||||||
self.dispatch_instr(instr.as_ref(), indices, policies, code_repo, prolog_stream);
|
self.dispatch_instr(
|
||||||
|
instr.as_ref(),
|
||||||
|
indices,
|
||||||
|
policies,
|
||||||
|
code_repo,
|
||||||
|
current_input_stream,
|
||||||
|
current_output_stream,
|
||||||
|
);
|
||||||
|
|
||||||
if self.fail {
|
if self.fail {
|
||||||
self.backtrack();
|
self.backtrack();
|
||||||
@@ -920,10 +1025,17 @@ impl MachineState {
|
|||||||
indices: &mut IndexStore,
|
indices: &mut IndexStore,
|
||||||
policies: &mut MachinePolicies,
|
policies: &mut MachinePolicies,
|
||||||
code_repo: &mut CodeRepo,
|
code_repo: &mut CodeRepo,
|
||||||
prolog_stream: &mut PrologStream,
|
current_input_stream: &mut Stream,
|
||||||
|
current_output_stream: &mut Stream,
|
||||||
) {
|
) {
|
||||||
loop {
|
loop {
|
||||||
self.execute_instr(indices, policies, code_repo, prolog_stream);
|
self.execute_instr(
|
||||||
|
indices,
|
||||||
|
policies,
|
||||||
|
code_repo,
|
||||||
|
current_input_stream,
|
||||||
|
current_output_stream,
|
||||||
|
);
|
||||||
|
|
||||||
if self.fail {
|
if self.fail {
|
||||||
self.backtrack();
|
self.backtrack();
|
||||||
@@ -939,7 +1051,13 @@ impl MachineState {
|
|||||||
if !instigating_instr.as_ref().is_head_instr() {
|
if !instigating_instr.as_ref().is_head_instr() {
|
||||||
let cp = self.p.local();
|
let cp = self.p.local();
|
||||||
self.run_verify_attr_interrupt(cp);
|
self.run_verify_attr_interrupt(cp);
|
||||||
} else if !self.verify_attr_stepper(indices, policies, code_repo, prolog_stream) {
|
} else if !self.verify_attr_stepper(
|
||||||
|
indices,
|
||||||
|
policies,
|
||||||
|
code_repo,
|
||||||
|
current_input_stream,
|
||||||
|
current_output_stream,
|
||||||
|
) {
|
||||||
if self.fail {
|
if self.fail {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
use prolog_parser::ast::*;
|
use crate::prolog_parser::ast::*;
|
||||||
use prolog_parser::tabled_rc::*;
|
use crate::prolog_parser::tabled_rc::*;
|
||||||
|
|
||||||
use crate::prolog::forms::*;
|
use crate::forms::*;
|
||||||
use crate::prolog::machine::code_repo::*;
|
use crate::machine::code_repo::*;
|
||||||
use crate::prolog::machine::machine_errors::*;
|
use crate::machine::machine_errors::*;
|
||||||
use crate::prolog::machine::machine_indices::*;
|
use crate::machine::machine_indices::*;
|
||||||
|
|
||||||
use std::collections::VecDeque;
|
use std::collections::VecDeque;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
@@ -48,6 +48,7 @@ impl Module {
|
|||||||
(te.0)
|
(te.0)
|
||||||
.0
|
.0
|
||||||
.extend((self.user_term_expansions.0).0.iter().cloned());
|
.extend((self.user_term_expansions.0).0.iter().cloned());
|
||||||
|
|
||||||
te.1.extend(self.user_term_expansions.1.iter().cloned());
|
te.1.extend(self.user_term_expansions.1.iter().cloned());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -60,6 +61,7 @@ impl Module {
|
|||||||
(ge.0)
|
(ge.0)
|
||||||
.0
|
.0
|
||||||
.extend((self.user_goal_expansions.0).0.iter().cloned());
|
.extend((self.user_goal_expansions.0).0.iter().cloned());
|
||||||
|
|
||||||
ge.1.extend(self.user_goal_expansions.1.iter().cloned());
|
ge.1.extend(self.user_goal_expansions.1.iter().cloned());
|
||||||
}
|
}
|
||||||
|
|
||||||
202
src/machine/partial_string.rs
Normal file
202
src/machine/partial_string.rs
Normal file
@@ -0,0 +1,202 @@
|
|||||||
|
use core::marker::PhantomData;
|
||||||
|
|
||||||
|
use std::alloc;
|
||||||
|
use std::mem;
|
||||||
|
use std::ptr;
|
||||||
|
use std::ops::RangeFrom;
|
||||||
|
use std::slice;
|
||||||
|
use std::str;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct PartialString {
|
||||||
|
buf: *const u8,
|
||||||
|
len: usize,
|
||||||
|
_marker: PhantomData<[u8]>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for PartialString {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
unsafe {
|
||||||
|
let layout = alloc::Layout::from_size_align_unchecked(self.len, mem::align_of::<u8>());
|
||||||
|
alloc::dealloc(self.buf as *mut u8, layout);
|
||||||
|
|
||||||
|
self.buf = ptr::null();
|
||||||
|
self.len = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Clone for PartialString {
|
||||||
|
#[inline]
|
||||||
|
fn clone(&self) -> Self {
|
||||||
|
self.clone_from_offset(0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn scan_for_terminator<Iter: Iterator<Item = char>>(iter: Iter) -> usize {
|
||||||
|
let mut terminator_idx = 0;
|
||||||
|
|
||||||
|
for c in iter {
|
||||||
|
if c == '\u{0}' && terminator_idx != 0 {
|
||||||
|
return terminator_idx;
|
||||||
|
}
|
||||||
|
|
||||||
|
terminator_idx += c.len_utf8();
|
||||||
|
}
|
||||||
|
|
||||||
|
terminator_idx
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct PStrIter {
|
||||||
|
buf: *const u8,
|
||||||
|
len: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PStrIter {
|
||||||
|
#[inline]
|
||||||
|
fn from(buf: *const u8, len: usize, idx: usize) -> Self {
|
||||||
|
PStrIter {
|
||||||
|
buf: (buf as usize + idx) as *const _,
|
||||||
|
len: len - idx,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Iterator for PStrIter {
|
||||||
|
type Item = char;
|
||||||
|
|
||||||
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
|
unsafe {
|
||||||
|
let slice = slice::from_raw_parts(self.buf, self.len);
|
||||||
|
let s = str::from_utf8(slice).unwrap();
|
||||||
|
|
||||||
|
if let Some(c) = s.chars().next() {
|
||||||
|
self.buf = self.buf.offset(c.len_utf8() as isize);
|
||||||
|
self.len -= c.len_utf8();
|
||||||
|
|
||||||
|
Some(c)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PartialString {
|
||||||
|
#[inline]
|
||||||
|
pub(super)
|
||||||
|
fn new(src: &str) -> Option<(Self, &str)> {
|
||||||
|
let pstr = PartialString {
|
||||||
|
buf: ptr::null_mut(),
|
||||||
|
len: 0,
|
||||||
|
_marker: PhantomData,
|
||||||
|
};
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
pstr.append_chars(src)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn append_chars(mut self, src: &str) -> Option<(Self, &str)> {
|
||||||
|
let terminator_idx = scan_for_terminator(src.chars());
|
||||||
|
|
||||||
|
let layout = alloc::Layout::from_size_align_unchecked(
|
||||||
|
terminator_idx + '\u{0}'.len_utf8(),
|
||||||
|
mem::align_of::<u8>(),
|
||||||
|
);
|
||||||
|
|
||||||
|
self.buf = alloc::alloc(layout) as *const _;
|
||||||
|
self.len = terminator_idx + '\u{0}'.len_utf8();
|
||||||
|
|
||||||
|
ptr::copy(
|
||||||
|
src.as_ptr(),
|
||||||
|
self.buf as *mut _,
|
||||||
|
terminator_idx,
|
||||||
|
);
|
||||||
|
|
||||||
|
self.write_terminator_at(terminator_idx);
|
||||||
|
|
||||||
|
Some(if terminator_idx != src.as_bytes().len() {
|
||||||
|
(self, &src[terminator_idx ..])
|
||||||
|
} else {
|
||||||
|
(self, "")
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super)
|
||||||
|
fn clone_from_offset(&self, n: usize) -> Self {
|
||||||
|
let len =
|
||||||
|
if self.len - '\u{0}'.len_utf8() > n {
|
||||||
|
self.len - n - '\u{0}'.len_utf8()
|
||||||
|
} else {
|
||||||
|
0
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut pstr = PartialString {
|
||||||
|
buf: ptr::null_mut(),
|
||||||
|
len: len + '\u{0}'.len_utf8(),
|
||||||
|
_marker: PhantomData,
|
||||||
|
};
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
let layout = alloc::Layout::from_size_align_unchecked(
|
||||||
|
len + '\u{0}'.len_utf8(),
|
||||||
|
mem::align_of::<u8>(),
|
||||||
|
);
|
||||||
|
|
||||||
|
pstr.buf = alloc::alloc(layout);
|
||||||
|
|
||||||
|
if len > 0 {
|
||||||
|
ptr::copy(
|
||||||
|
(self.buf as usize + n) as *const u8,
|
||||||
|
pstr.buf as *mut _,
|
||||||
|
len,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
pstr.write_terminator_at(len);
|
||||||
|
}
|
||||||
|
|
||||||
|
pstr
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub(super)
|
||||||
|
fn write_terminator_at(&mut self, index: usize) {
|
||||||
|
unsafe {
|
||||||
|
ptr::write(
|
||||||
|
(self.buf as usize + index) as *mut u8,
|
||||||
|
0u8,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn range_from(&self, index: RangeFrom<usize>) -> PStrIter {
|
||||||
|
if self.len >= '\u{0}'.len_utf8() {
|
||||||
|
PStrIter::from(self.buf, self.len - '\u{0}'.len_utf8(), index.start)
|
||||||
|
} else {
|
||||||
|
PStrIter::from(self.buf, 0, 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn at_end(&self, end_n: usize) -> bool {
|
||||||
|
end_n + 1 == self.len
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn as_str_from(&self, n: usize) -> &str {
|
||||||
|
unsafe {
|
||||||
|
let slice = slice::from_raw_parts(
|
||||||
|
self.buf,
|
||||||
|
self.len - '\u{0}'.len_utf8(),
|
||||||
|
);
|
||||||
|
|
||||||
|
let s = str::from_utf8(slice).unwrap();
|
||||||
|
|
||||||
|
&s[n ..]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,3 +1,5 @@
|
|||||||
|
:- module('$project_atts', [copy_term/3]).
|
||||||
|
|
||||||
'$attribute_goals_driver'(QueryVars, AttrVars) :-
|
'$attribute_goals_driver'(QueryVars, AttrVars) :-
|
||||||
gather_modules(AttrVars, Modules0, _),
|
gather_modules(AttrVars, Modules0, _),
|
||||||
sort(Modules0, Modules),
|
sort(Modules0, Modules),
|
||||||
@@ -99,7 +101,7 @@ call_attribute_goals_with_module_prefix([Module | Modules], GoalCaller, AttrVars
|
|||||||
call_attribute_goals_with_module_prefix(Modules, GoalCaller, AttrVars, Gs).
|
call_attribute_goals_with_module_prefix(Modules, GoalCaller, AttrVars, Gs).
|
||||||
|
|
||||||
copy_term(Source, Dest, Goals) :-
|
copy_term(Source, Dest, Goals) :-
|
||||||
term_variables(Source, Vars),
|
'$term_attributed_variables'(Source, Vars),
|
||||||
gather_modules(Vars, Modules0, _),
|
gather_modules(Vars, Modules0, _),
|
||||||
sort(Modules0, Modules),
|
sort(Modules0, Modules),
|
||||||
call_attribute_goals_with_module_prefix(Modules, call_query_var_goals, Vars, Goals0),
|
call_attribute_goals_with_module_prefix(Modules, call_query_var_goals, Vars, Goals0),
|
||||||
@@ -14,6 +14,7 @@ pub(crate) trait RawBlockTraits {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
pub(crate) struct RawBlock<T: RawBlockTraits> {
|
pub(crate) struct RawBlock<T: RawBlockTraits> {
|
||||||
pub(crate) size: usize,
|
pub(crate) size: usize,
|
||||||
pub(crate) base: *const u8,
|
pub(crate) base: *const u8,
|
||||||
@@ -36,20 +37,6 @@ impl<T: RawBlockTraits> RawBlock<T> {
|
|||||||
block
|
block
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate)
|
|
||||||
fn with_capacity(cap: usize) -> Self {
|
|
||||||
let mut block = RawBlock { size: 0,
|
|
||||||
base: ptr::null(),
|
|
||||||
top: ptr::null(),
|
|
||||||
_marker: PhantomData };
|
|
||||||
|
|
||||||
unsafe {
|
|
||||||
block.init_at_size(cap);
|
|
||||||
}
|
|
||||||
|
|
||||||
block
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe fn init_at_size(&mut self, cap: usize) {
|
unsafe fn init_at_size(&mut self, cap: usize) {
|
||||||
let layout = alloc::Layout::from_size_align_unchecked(cap, T::align());
|
let layout = alloc::Layout::from_size_align_unchecked(cap, T::align());
|
||||||
|
|
||||||
@@ -86,7 +73,6 @@ impl<T: RawBlockTraits> RawBlock<T> {
|
|||||||
mem::replace(self, Self::empty_block())
|
mem::replace(self, Self::empty_block())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn free_space(&self) -> usize {
|
fn free_space(&self) -> usize {
|
||||||
debug_assert!(self.top >= self.base,
|
debug_assert!(self.top >= self.base,
|
||||||
@@ -1,12 +1,13 @@
|
|||||||
use crate::prolog::machine::machine_indices::*;
|
|
||||||
use crate::prolog::machine::raw_block::*;
|
|
||||||
|
|
||||||
use core::marker::PhantomData;
|
use core::marker::PhantomData;
|
||||||
|
|
||||||
|
use crate::machine::machine_indices::*;
|
||||||
|
use crate::machine::raw_block::*;
|
||||||
|
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use std::ops::{Index, IndexMut};
|
use std::ops::{Index, IndexMut};
|
||||||
use std::ptr;
|
use std::ptr;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
struct StackTraits {}
|
struct StackTraits {}
|
||||||
|
|
||||||
impl RawBlockTraits for StackTraits {
|
impl RawBlockTraits for StackTraits {
|
||||||
@@ -35,6 +36,7 @@ const fn prelude_size<Prelude>() -> usize {
|
|||||||
(size & !(align - 1)) + align
|
(size & !(align - 1)) + align
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
pub struct Stack {
|
pub struct Stack {
|
||||||
buf: RawBlock<StackTraits>,
|
buf: RawBlock<StackTraits>,
|
||||||
_marker: PhantomData<Addr>,
|
_marker: PhantomData<Addr>,
|
||||||
@@ -47,12 +49,12 @@ impl Drop for Stack {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub struct FramePrelude {
|
pub struct FramePrelude {
|
||||||
is_or_frame: u8,
|
|
||||||
pub num_cells: usize,
|
pub num_cells: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
pub struct AndFramePrelude {
|
pub struct AndFramePrelude {
|
||||||
pub univ_prelude: FramePrelude,
|
pub univ_prelude: FramePrelude,
|
||||||
pub e: usize,
|
pub e: usize,
|
||||||
@@ -60,9 +62,9 @@ pub struct AndFramePrelude {
|
|||||||
pub interrupt_cp: LocalCodePtr,
|
pub interrupt_cp: LocalCodePtr,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
pub struct AndFrame {
|
pub struct AndFrame {
|
||||||
pub prelude: AndFramePrelude,
|
pub prelude: AndFramePrelude,
|
||||||
_marker: PhantomData<Addr>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AndFrame {
|
impl AndFrame {
|
||||||
@@ -101,24 +103,7 @@ impl IndexMut<usize> for AndFrame {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Drop for AndFrame {
|
#[derive(Debug)]
|
||||||
fn drop(&mut self) {
|
|
||||||
let prelude_offset = prelude_size::<AndFramePrelude>();
|
|
||||||
|
|
||||||
unsafe {
|
|
||||||
let ptr = mem::transmute::<&mut AndFrame, *const u8>(self);
|
|
||||||
let ptr = ptr as usize + prelude_offset;
|
|
||||||
|
|
||||||
for idx in 0 .. self.prelude.univ_prelude.num_cells {
|
|
||||||
let index_offset = idx * mem::size_of::<Addr>();
|
|
||||||
let ptr = (ptr + index_offset) as *mut Addr;
|
|
||||||
|
|
||||||
ptr::drop_in_place(ptr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct OrFramePrelude {
|
pub struct OrFramePrelude {
|
||||||
pub univ_prelude: FramePrelude,
|
pub univ_prelude: FramePrelude,
|
||||||
pub e: usize,
|
pub e: usize,
|
||||||
@@ -133,9 +118,9 @@ pub struct OrFramePrelude {
|
|||||||
pub attr_var_init_bindings_b: usize,
|
pub attr_var_init_bindings_b: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
pub struct OrFrame {
|
pub struct OrFrame {
|
||||||
pub prelude: OrFramePrelude,
|
pub prelude: OrFramePrelude,
|
||||||
_marker: PhantomData<Addr>
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Index<usize> for OrFrame {
|
impl Index<usize> for OrFrame {
|
||||||
@@ -170,24 +155,6 @@ impl IndexMut<usize> for OrFrame {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Drop for OrFrame {
|
|
||||||
fn drop(&mut self) {
|
|
||||||
let prelude_offset = prelude_size::<OrFramePrelude>();
|
|
||||||
|
|
||||||
unsafe {
|
|
||||||
let ptr = mem::transmute::<&mut OrFrame, *const u8>(self);
|
|
||||||
let ptr = ptr as usize + prelude_offset;
|
|
||||||
|
|
||||||
for idx in 0 .. self.prelude.univ_prelude.num_cells {
|
|
||||||
let index_offset = idx * mem::size_of::<Addr>();
|
|
||||||
let ptr = (ptr + index_offset) as *mut Addr;
|
|
||||||
|
|
||||||
ptr::drop_in_place(ptr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl OrFrame {
|
impl OrFrame {
|
||||||
pub fn size_of(num_cells: usize) -> usize {
|
pub fn size_of(num_cells: usize) -> usize {
|
||||||
prelude_size::<OrFramePrelude>() + num_cells * mem::size_of::<Addr>()
|
prelude_size::<OrFramePrelude>() + num_cells * mem::size_of::<Addr>()
|
||||||
@@ -204,18 +171,19 @@ impl Stack {
|
|||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
let new_top = self.buf.new_block(frame_size);
|
let new_top = self.buf.new_block(frame_size);
|
||||||
|
let e = self.buf.top as usize - self.buf.base as usize;
|
||||||
|
|
||||||
for idx in 0 .. num_cells {
|
for idx in 0 .. num_cells {
|
||||||
let offset = prelude_size::<AndFramePrelude>() + idx * mem::size_of::<Addr>();
|
let offset = prelude_size::<AndFramePrelude>() + idx * mem::size_of::<Addr>();
|
||||||
ptr::write((self.buf.top as usize + offset) as *mut Addr, Addr::StackCell(0,0));
|
ptr::write(
|
||||||
|
(self.buf.top as usize + offset) as *mut Addr,
|
||||||
|
Addr::StackCell(e, idx + 1),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
let and_frame = &mut *(self.buf.top as *mut AndFrame);
|
let and_frame = &mut *(self.buf.top as *mut AndFrame);
|
||||||
|
|
||||||
and_frame.prelude.univ_prelude.is_or_frame = 0;
|
|
||||||
and_frame.prelude.univ_prelude.num_cells = num_cells;
|
and_frame.prelude.univ_prelude.num_cells = num_cells;
|
||||||
|
|
||||||
let e = self.buf.top as usize - self.buf.base as usize;
|
|
||||||
self.buf.top = new_top;
|
self.buf.top = new_top;
|
||||||
|
|
||||||
e
|
e
|
||||||
@@ -227,18 +195,19 @@ impl Stack {
|
|||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
let new_top = self.buf.new_block(frame_size);
|
let new_top = self.buf.new_block(frame_size);
|
||||||
|
let b = self.buf.top as usize - self.buf.base as usize;
|
||||||
|
|
||||||
for idx in 0 .. num_cells {
|
for idx in 0 .. num_cells {
|
||||||
let offset = prelude_size::<OrFramePrelude>() + idx * mem::size_of::<Addr>();
|
let offset = prelude_size::<OrFramePrelude>() + idx * mem::size_of::<Addr>();
|
||||||
ptr::write((self.buf.top as usize + offset) as *mut Addr, Addr::StackCell(0,0));
|
ptr::write(
|
||||||
|
(self.buf.top as usize + offset) as *mut Addr,
|
||||||
|
Addr::StackCell(b, idx),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
let or_frame = &mut *(self.buf.top as *mut OrFrame);
|
let or_frame = &mut *(self.buf.top as *mut OrFrame);
|
||||||
|
|
||||||
or_frame.prelude.univ_prelude.is_or_frame = 1;
|
|
||||||
or_frame.prelude.univ_prelude.num_cells = num_cells;
|
or_frame.prelude.univ_prelude.num_cells = num_cells;
|
||||||
|
|
||||||
let b = self.buf.top as usize - self.buf.base as usize;
|
|
||||||
self.buf.top = new_top;
|
self.buf.top = new_top;
|
||||||
|
|
||||||
b
|
b
|
||||||
@@ -281,6 +250,7 @@ impl Stack {
|
|||||||
Stack { buf: self.buf.take(), _marker: PhantomData }
|
Stack { buf: self.buf.take(), _marker: PhantomData }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
pub fn truncate(&mut self, b: usize) {
|
pub fn truncate(&mut self, b: usize) {
|
||||||
if b == 0 {
|
if b == 0 {
|
||||||
self.inner_truncate(mem::align_of::<Addr>());
|
self.inner_truncate(mem::align_of::<Addr>());
|
||||||
@@ -289,40 +259,12 @@ impl Stack {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
fn inner_truncate(&mut self, b: usize) {
|
fn inner_truncate(&mut self, b: usize) {
|
||||||
let mut b = b + self.buf.base as usize;
|
let base = b + self.buf.base as usize;
|
||||||
let base = b;
|
|
||||||
|
|
||||||
unsafe {
|
if base < self.buf.top as usize {
|
||||||
while b as *const _ < self.buf.top {
|
self.buf.top = base as *const _;
|
||||||
let univ_prelude = ptr::read(b as *const FramePrelude);
|
|
||||||
|
|
||||||
let offset = if univ_prelude.is_or_frame == 0 {
|
|
||||||
let frame_ptr = b as *mut AndFrame;
|
|
||||||
let frame = &mut *frame_ptr;
|
|
||||||
let size_of_frame = AndFrame::size_of(frame.prelude.univ_prelude.num_cells);
|
|
||||||
|
|
||||||
ptr::drop_in_place(frame_ptr);
|
|
||||||
|
|
||||||
b + size_of_frame
|
|
||||||
} else {
|
|
||||||
debug_assert!(univ_prelude.is_or_frame == 1);
|
|
||||||
|
|
||||||
let frame_ptr = b as *mut OrFrame;
|
|
||||||
let frame = &mut *frame_ptr;
|
|
||||||
let size_of_frame = OrFrame::size_of(frame.prelude.univ_prelude.num_cells);
|
|
||||||
|
|
||||||
ptr::drop_in_place(frame_ptr);
|
|
||||||
|
|
||||||
b + size_of_frame
|
|
||||||
};
|
|
||||||
|
|
||||||
b = offset;
|
|
||||||
}
|
|
||||||
|
|
||||||
if base < self.buf.top as usize {
|
|
||||||
self.buf.top = base as *const _;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
1236
src/machine/streams.rs
Normal file
1236
src/machine/streams.rs
Normal file
File diff suppressed because it is too large
Load Diff
6013
src/machine/system_calls.rs
Normal file
6013
src/machine/system_calls.rs
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,42 +1,16 @@
|
|||||||
use prolog_parser::ast::*;
|
use crate::prolog_parser::ast::*;
|
||||||
use prolog_parser::parser::*;
|
use crate::prolog_parser::parser::*;
|
||||||
|
|
||||||
use crate::prolog::machine::machine_indices::HeapCellValue;
|
use crate::machine::machine_indices::HeapCellValue;
|
||||||
use crate::prolog::machine::*;
|
use crate::machine::*;
|
||||||
use crate::prolog::rug::ops::Pow;
|
use crate::rug::ops::Pow;
|
||||||
use crate::prolog::rug::Integer;
|
use crate::rug::Integer;
|
||||||
|
|
||||||
use std::cell::Cell;
|
use std::cell::Cell;
|
||||||
use std::collections::VecDeque;
|
use std::collections::VecDeque;
|
||||||
use std::io::Read;
|
|
||||||
use std::iter::Rev;
|
use std::iter::Rev;
|
||||||
use std::vec::IntoIter;
|
use std::vec::IntoIter;
|
||||||
|
|
||||||
fn unfold_by_str_once(term: &mut Term, s: &str) -> Option<(Term, Term)> {
|
|
||||||
if let &mut Term::Clause(_, ref name, ref mut subterms, _) = term {
|
|
||||||
if name.as_str() == s && subterms.len() == 2 {
|
|
||||||
let snd = *subterms.pop().unwrap();
|
|
||||||
let fst = *subterms.pop().unwrap();
|
|
||||||
|
|
||||||
return Some((fst, snd));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
None
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn unfold_by_str(mut term: Term, s: &str) -> Vec<Term> {
|
|
||||||
let mut terms = vec![];
|
|
||||||
|
|
||||||
while let Some((fst, snd)) = unfold_by_str_once(&mut term, s) {
|
|
||||||
terms.push(fst);
|
|
||||||
term = snd;
|
|
||||||
}
|
|
||||||
|
|
||||||
terms.push(term);
|
|
||||||
terms
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn fold_by_str<I>(terms: I, mut term: Term, sym: ClauseName) -> Term
|
pub fn fold_by_str<I>(terms: I, mut term: Term, sym: ClauseName) -> Term
|
||||||
where
|
where
|
||||||
I: DoubleEndedIterator<Item = Term>,
|
I: DoubleEndedIterator<Item = Term>,
|
||||||
@@ -53,7 +27,11 @@ where
|
|||||||
term
|
term
|
||||||
}
|
}
|
||||||
|
|
||||||
fn extract_from_list(head: Box<Term>, tail: Box<Term>) -> Result<Rev<IntoIter<Term>>, ParserError> {
|
fn extract_from_list(
|
||||||
|
head: Box<Term>,
|
||||||
|
tail: Box<Term>,
|
||||||
|
) -> Result<Rev<IntoIter<Term>>, ParserError>
|
||||||
|
{
|
||||||
let mut terms = vec![*head];
|
let mut terms = vec![*head];
|
||||||
let mut tail = *tail;
|
let mut tail = *tail;
|
||||||
|
|
||||||
@@ -69,16 +47,18 @@ fn extract_from_list(head: Box<Term>, tail: Box<Term>) -> Result<Rev<IntoIter<Te
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct TermStream<'a, R: Read> {
|
#[derive(Debug)]
|
||||||
|
pub struct TermStream<'a> {
|
||||||
stack: Vec<Term>,
|
stack: Vec<Term>,
|
||||||
pub(crate) wam: &'a mut Machine,
|
pub(crate) wam: &'a mut Machine,
|
||||||
parser: Parser<'a, R>,
|
parser: Parser<'a, Stream>,
|
||||||
pub(crate) flags: MachineFlags,
|
pub(crate) flags: MachineFlags,
|
||||||
term_expansion_lens: (usize, usize),
|
term_expansion_lens: (usize, usize),
|
||||||
goal_expansion_lens: (usize, usize),
|
goal_expansion_lens: (usize, usize),
|
||||||
top_level_terms: Vec<(Term, usize, usize)>, // term, line_num, col_num.
|
top_level_terms: Vec<(Term, usize, usize)>, // term, line_num, col_num.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
pub struct ExpansionAdditionResult {
|
pub struct ExpansionAdditionResult {
|
||||||
term_expansion_additions: (Predicate, VecDeque<TopLevel>),
|
term_expansion_additions: (Predicate, VecDeque<TopLevel>),
|
||||||
goal_expansion_additions: (Predicate, VecDeque<TopLevel>),
|
goal_expansion_additions: (Predicate, VecDeque<TopLevel>),
|
||||||
@@ -100,7 +80,7 @@ impl ExpansionAdditionResult {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, R: Read> Drop for TermStream<'a, R> {
|
impl<'a> Drop for TermStream<'a> {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
self.wam.indices.in_situ_code_dir.clear();
|
self.wam.indices.in_situ_code_dir.clear();
|
||||||
self.wam.indices.in_situ_module_dir.clear();
|
self.wam.indices.in_situ_module_dir.clear();
|
||||||
@@ -110,9 +90,9 @@ impl<'a, R: Read> Drop for TermStream<'a, R> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, R: Read> TermStream<'a, R> {
|
impl<'a> TermStream<'a> {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
src: &'a mut ParsingStream<R>,
|
src: &'a mut ParsingStream<Stream>,
|
||||||
atom_tbl: TabledData<Atom>,
|
atom_tbl: TabledData<Atom>,
|
||||||
flags: MachineFlags,
|
flags: MachineFlags,
|
||||||
wam: &'a mut Machine,
|
wam: &'a mut Machine,
|
||||||
@@ -185,7 +165,7 @@ impl<'a, R: Read> TermStream<'a, R> {
|
|||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn eof(&mut self) -> Result<bool, ParserError> {
|
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()?)
|
Ok(self.stack.is_empty() && self.parser.eof()?)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -201,6 +181,7 @@ impl<'a, R: Read> TermStream<'a, R> {
|
|||||||
te_len,
|
te_len,
|
||||||
te_queue_len,
|
te_queue_len,
|
||||||
);
|
);
|
||||||
|
|
||||||
let goal_expansion_additions = self.wam.code_repo.truncate_terms(
|
let goal_expansion_additions = self.wam.code_repo.truncate_terms(
|
||||||
(clause_name!("goal_expansion"), 2),
|
(clause_name!("goal_expansion"), 2),
|
||||||
ge_len,
|
ge_len,
|
||||||
@@ -240,7 +221,7 @@ impl<'a, R: Read> TermStream<'a, R> {
|
|||||||
term_string: &str,
|
term_string: &str,
|
||||||
op_dir: &OpDir,
|
op_dir: &OpDir,
|
||||||
) -> Result<Term, ParserError> {
|
) -> Result<Term, ParserError> {
|
||||||
let mut stream = parsing_stream(term_string.trim().as_bytes());
|
let mut stream = parsing_stream(term_string.trim().as_bytes())?;
|
||||||
let mut parser = Parser::new(&mut stream, self.parser.get_atom_tbl(), self.flags);
|
let mut parser = Parser::new(&mut stream, self.parser.get_atom_tbl(), self.flags);
|
||||||
|
|
||||||
parser.read_term(composite_op!(
|
parser.read_term(composite_op!(
|
||||||
@@ -326,7 +307,8 @@ impl<'a, R: Read> TermStream<'a, R> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl MachineState {
|
impl MachineState {
|
||||||
pub(super) fn print_with_locs(&self, addr: Addr, op_dir: &OpDir) -> PrinterOutputter {
|
pub(super)
|
||||||
|
fn print_with_locs(&self, addr: Addr, op_dir: &OpDir) -> PrinterOutputter {
|
||||||
let output = PrinterOutputter::new();
|
let output = PrinterOutputter::new();
|
||||||
let mut printer = HCPrinter::from_heap_locs(&self, op_dir, output);
|
let mut printer = HCPrinter::from_heap_locs(&self, op_dir, output);
|
||||||
let mut max_var_length = 0;
|
let mut max_var_length = 0;
|
||||||
@@ -337,12 +319,16 @@ impl MachineState {
|
|||||||
|
|
||||||
printer.quoted = true;
|
printer.quoted = true;
|
||||||
printer.numbervars = true;
|
printer.numbervars = true;
|
||||||
// the purpose of the offset is to avoid clashes with variable names that might
|
|
||||||
// occur after the addresses in the expanded term are substituted with the variable
|
// the purpose of the offset is to avoid clashes with variable
|
||||||
// names in the pre-expansion term. This formula ensures that all generated "numbervars"-
|
// names that might occur after the addresses in the expanded
|
||||||
// style variable names will be longer than the keys of the var_dict, and therefore
|
// term are substituted with the variable names in the
|
||||||
// not equal to any of them.
|
// pre-expansion term. This formula ensures that all generated
|
||||||
|
// "numbervars"- style variable names will be longer than the
|
||||||
|
// keys of the var_dict, and therefore not equal to any of
|
||||||
|
// them.
|
||||||
printer.numbervars_offset = Integer::from(10).pow(max_var_length as u32) * 26;
|
printer.numbervars_offset = Integer::from(10).pow(max_var_length as u32) * 26;
|
||||||
|
printer.print_strings_as_strs = true;
|
||||||
printer.drop_toplevel_spec();
|
printer.drop_toplevel_spec();
|
||||||
|
|
||||||
printer.see_all_locs();
|
printer.see_all_locs();
|
||||||
@@ -354,8 +340,8 @@ impl MachineState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// reset the machine, but keep the heap contents as they were.
|
// reset the machine, but keep the heap contents as they were.
|
||||||
// this prevents clashes between underscored variable names
|
// this prevents clashes between underscored variable names in the
|
||||||
// in the same query.
|
// same query.
|
||||||
fn reset_with_heap_preservation(&mut self) {
|
fn reset_with_heap_preservation(&mut self) {
|
||||||
let heap = self.heap.take();
|
let heap = self.heap.take();
|
||||||
self.reset();
|
self.reset();
|
||||||
@@ -379,13 +365,16 @@ impl MachineState {
|
|||||||
wam.code_repo.cached_query = code;
|
wam.code_repo.cached_query = code;
|
||||||
|
|
||||||
self.cp = LocalCodePtr::TopLevel(0, 0);
|
self.cp = LocalCodePtr::TopLevel(0, 0);
|
||||||
|
|
||||||
self.at_end_of_expansion = false;
|
self.at_end_of_expansion = false;
|
||||||
|
self.flags.double_quotes = DoubleQuotes::Chars;
|
||||||
|
|
||||||
self.query_stepper(
|
self.query_stepper(
|
||||||
&mut wam.indices,
|
&mut wam.indices,
|
||||||
&mut wam.policies,
|
&mut MachinePolicies::default(),
|
||||||
&mut wam.code_repo,
|
&mut wam.code_repo,
|
||||||
&mut readline::input_stream(),
|
&mut readline::input_stream(),
|
||||||
|
&mut Stream::stdout(),
|
||||||
);
|
);
|
||||||
|
|
||||||
if self.fail || self.at_end_of_expansion {
|
if self.fail || self.at_end_of_expansion {
|
||||||
@@ -398,6 +387,7 @@ impl MachineState {
|
|||||||
let output = self.print_with_locs(Addr::HeapCell(h), &wam.indices.op_dir);
|
let output = self.print_with_locs(Addr::HeapCell(h), &wam.indices.op_dir);
|
||||||
|
|
||||||
self.reset_with_heap_preservation();
|
self.reset_with_heap_preservation();
|
||||||
|
|
||||||
Some(output.result())
|
Some(output.result())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,19 +1,20 @@
|
|||||||
use prolog_parser::ast::*;
|
use crate::prolog_parser::ast::*;
|
||||||
use prolog_parser::tabled_rc::*;
|
use crate::prolog_parser::tabled_rc::*;
|
||||||
|
|
||||||
use crate::prolog::forms::*;
|
use crate::forms::*;
|
||||||
use crate::prolog::iterators::*;
|
use crate::iterators::*;
|
||||||
use crate::prolog::machine::machine_errors::*;
|
use crate::machine::machine_errors::*;
|
||||||
use crate::prolog::machine::machine_indices::*;
|
use crate::machine::machine_indices::*;
|
||||||
use crate::prolog::machine::term_expansion::*;
|
use crate::machine::term_expansion::*;
|
||||||
use crate::prolog::machine::*;
|
use crate::machine::*;
|
||||||
|
|
||||||
use indexmap::{IndexMap, IndexSet};
|
use crate::indexmap::{IndexMap, IndexSet};
|
||||||
|
|
||||||
use std::borrow::BorrowMut;
|
use std::borrow::BorrowMut;
|
||||||
use std::cell::Cell;
|
use std::cell::Cell;
|
||||||
use std::collections::VecDeque;
|
use std::collections::VecDeque;
|
||||||
use std::io::Read;
|
use std::convert::TryFrom;
|
||||||
|
use std::fmt;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use std::ops::DerefMut;
|
use std::ops::DerefMut;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
@@ -23,6 +24,15 @@ enum IndexSource<'a, T> {
|
|||||||
Local(&'a mut T)
|
Local(&'a mut T)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'a, T: fmt::Debug> fmt::Debug for IndexSource<'a, T> {
|
||||||
|
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
match self {
|
||||||
|
IndexSource::TermStream => write!(fmt, "TermStream"),
|
||||||
|
IndexSource::Local(ref local) => write!(fmt, "Local({:?})", local),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn op_dir<'a, 'b: 'a>(from: &'b IndexSource<'a, IndexStore>) -> RefOrOwned<'a, OpDir> {
|
fn op_dir<'a, 'b: 'a>(from: &'b IndexSource<'a, IndexStore>) -> RefOrOwned<'a, OpDir> {
|
||||||
match from {
|
match from {
|
||||||
IndexSource::TermStream => RefOrOwned::Owned(OpDir::new()),
|
IndexSource::TermStream => RefOrOwned::Owned(OpDir::new()),
|
||||||
@@ -30,15 +40,16 @@ fn op_dir<'a, 'b: 'a>(from: &'b IndexSource<'a, IndexStore>) -> RefOrOwned<'a, O
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct CompositeIndices<'a, 'b, 'c, R: Read> {
|
#[derive(Debug)]
|
||||||
term_stream: &'b mut TermStream<'a, R>,
|
struct CompositeIndices<'a, 'b, 'c> {
|
||||||
|
term_stream: &'b mut TermStream<'a>,
|
||||||
index_src: IndexSource<'c, IndexStore>,
|
index_src: IndexSource<'c, IndexStore>,
|
||||||
static_code_dir: Option<IndexSource<'c, CodeDir>>
|
static_code_dir: Option<IndexSource<'c, CodeDir>>
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'b, 'c, R: Read> CompositeIndices<'a, 'b, 'c, R> {
|
impl<'a, 'b, 'c> CompositeIndices<'a, 'b, 'c> {
|
||||||
fn new(
|
fn new(
|
||||||
term_stream: &'b mut TermStream<'a, R>,
|
term_stream: &'b mut TermStream<'a>,
|
||||||
index_src: IndexSource<'c, IndexStore>,
|
index_src: IndexSource<'c, IndexStore>,
|
||||||
static_code_dir: Option<IndexSource<'c, CodeDir>>,
|
static_code_dir: Option<IndexSource<'c, CodeDir>>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
@@ -212,8 +223,8 @@ fn setup_op_decl(
|
|||||||
};
|
};
|
||||||
|
|
||||||
let prec = match *terms.pop().unwrap() {
|
let prec = match *terms.pop().unwrap() {
|
||||||
Term::Constant(_, Constant::Integer(bi)) => match bi.to_usize() {
|
Term::Constant(_, Constant::Fixnum(bi)) => match usize::try_from(bi) {
|
||||||
Some(n) if n <= 1200 => n,
|
Ok(n) if n <= 1200 => n,
|
||||||
_ => return Err(ParserError::InconsistentEntry),
|
_ => return Err(ParserError::InconsistentEntry),
|
||||||
},
|
},
|
||||||
_ => return Err(ParserError::InconsistentEntry),
|
_ => return Err(ParserError::InconsistentEntry),
|
||||||
@@ -225,16 +236,21 @@ fn setup_op_decl(
|
|||||||
fn setup_predicate_indicator(term: &mut Term) -> Result<PredicateKey, ParserError>
|
fn setup_predicate_indicator(term: &mut Term) -> Result<PredicateKey, ParserError>
|
||||||
{
|
{
|
||||||
match term {
|
match term {
|
||||||
Term::Clause(_, ref name, ref mut terms, Some(_))
|
Term::Clause(_, ref slash, ref mut terms, Some(_))
|
||||||
if name.as_str() == "/" && terms.len() == 2 =>
|
if (slash.as_str() == "/" || slash.as_str() == "//") && terms.len() == 2 =>
|
||||||
{
|
{
|
||||||
let arity = *terms.pop().unwrap();
|
let arity = *terms.pop().unwrap();
|
||||||
let name = *terms.pop().unwrap();
|
let name = *terms.pop().unwrap();
|
||||||
|
|
||||||
let arity = arity
|
let arity = arity
|
||||||
.to_constant()
|
.to_constant()
|
||||||
.and_then(|c| c.to_integer())
|
.and_then(|c| {
|
||||||
.and_then(|n| n.to_usize())
|
match c {
|
||||||
|
Constant::Integer(n) => n.to_usize(),
|
||||||
|
Constant::Fixnum(n) => usize::try_from(n).ok(),
|
||||||
|
_ => None
|
||||||
|
}
|
||||||
|
})
|
||||||
.ok_or(ParserError::InvalidModuleExport)?;
|
.ok_or(ParserError::InvalidModuleExport)?;
|
||||||
|
|
||||||
let name = name
|
let name = name
|
||||||
@@ -242,7 +258,11 @@ fn setup_predicate_indicator(term: &mut Term) -> Result<PredicateKey, ParserErro
|
|||||||
.and_then(|c| c.to_atom())
|
.and_then(|c| c.to_atom())
|
||||||
.ok_or(ParserError::InvalidModuleExport)?;
|
.ok_or(ParserError::InvalidModuleExport)?;
|
||||||
|
|
||||||
Ok((name, arity))
|
if slash.as_str() == "/" {
|
||||||
|
Ok((name, arity))
|
||||||
|
} else {
|
||||||
|
Ok((name, arity + 2))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
_ => Err(ParserError::InvalidModuleExport),
|
_ => Err(ParserError::InvalidModuleExport),
|
||||||
}
|
}
|
||||||
@@ -320,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() {
|
match *terms.pop().unwrap() {
|
||||||
Term::Clause(_, ref name, ref mut terms, None)
|
Term::Clause(_, ref name, ref mut terms, None)
|
||||||
if name.as_str() == "library" && terms.len() == 1 =>
|
if name.as_str() == "library" && terms.len() == 1 =>
|
||||||
{
|
{
|
||||||
terms
|
read_library_path(*terms.pop().unwrap(), atom_tbl)
|
||||||
.pop()
|
|
||||||
.unwrap()
|
|
||||||
.to_constant()
|
|
||||||
.and_then(|c| c.to_atom())
|
|
||||||
.map(|c| ModuleSource::Library(c))
|
.map(|c| ModuleSource::Library(c))
|
||||||
.ok_or(ParserError::InvalidUseModuleDecl)
|
.ok_or(ParserError::InvalidUseModuleDecl)
|
||||||
}
|
}
|
||||||
@@ -339,6 +380,32 @@ fn setup_use_module_decl(mut terms: Vec<Box<Term>>) -> Result<ModuleSource, Pars
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn setup_double_quotes(mut terms: Vec<Box<Term>>) -> Result<DoubleQuotes, ParserError> {
|
||||||
|
let dbl_quotes = *terms.pop().unwrap();
|
||||||
|
|
||||||
|
match terms[0].as_ref() {
|
||||||
|
Term::Constant(_, Constant::Atom(ref name, _))
|
||||||
|
if name.as_str() == "double_quotes" => {
|
||||||
|
match dbl_quotes {
|
||||||
|
Term::Constant(_, Constant::Atom(name, _)) => {
|
||||||
|
match name.as_str() {
|
||||||
|
"atom" => Ok(DoubleQuotes::Atom),
|
||||||
|
"chars" => Ok(DoubleQuotes::Chars),
|
||||||
|
"codes" => Ok(DoubleQuotes::Codes),
|
||||||
|
_ => Err(ParserError::InvalidDoubleQuotesDecl),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
Err(ParserError::InvalidDoubleQuotesDecl)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_ => {
|
||||||
|
Err(ParserError::InvalidDoubleQuotesDecl)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
type UseModuleExport = (ModuleSource, Vec<ModuleExport>);
|
type UseModuleExport = (ModuleSource, Vec<ModuleExport>);
|
||||||
|
|
||||||
fn setup_qualified_import(
|
fn setup_qualified_import(
|
||||||
@@ -350,11 +417,7 @@ fn setup_qualified_import(
|
|||||||
Term::Clause(_, ref name, ref mut terms, None)
|
Term::Clause(_, ref name, ref mut terms, None)
|
||||||
if name.as_str() == "library" && terms.len() == 1 =>
|
if name.as_str() == "library" && terms.len() == 1 =>
|
||||||
{
|
{
|
||||||
terms
|
read_library_path(*terms.pop().unwrap(), atom_tbl.clone())
|
||||||
.pop()
|
|
||||||
.unwrap()
|
|
||||||
.to_constant()
|
|
||||||
.and_then(|c| c.to_atom())
|
|
||||||
.map(|c| ModuleSource::Library(c))
|
.map(|c| ModuleSource::Library(c))
|
||||||
.ok_or(ParserError::InvalidUseModuleDecl)
|
.ok_or(ParserError::InvalidUseModuleDecl)
|
||||||
}
|
}
|
||||||
@@ -551,8 +614,8 @@ fn draw_from_term_dir_impl(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn draw_from_term_dir<R: Read>(
|
fn draw_from_term_dir(
|
||||||
indices: &CompositeIndices<R>,
|
indices: &CompositeIndices,
|
||||||
intra_module_term_dirs: &mut IndexMap<ClauseName, TermDirQuantum>,
|
intra_module_term_dirs: &mut IndexMap<ClauseName, TermDirQuantum>,
|
||||||
top_level_term_dirs: &mut TermDirQuantum,
|
top_level_term_dirs: &mut TermDirQuantum,
|
||||||
key: &PredicateKey,
|
key: &PredicateKey,
|
||||||
@@ -589,8 +652,8 @@ fn draw_from_term_dir<R: Read>(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn setup_declaration<'a, 'b, 'c, R: Read>(
|
fn setup_declaration<'a, 'b, 'c>(
|
||||||
indices: &mut CompositeIndices<'a, 'b, 'c, R>,
|
indices: &mut CompositeIndices<'a, 'b, 'c>,
|
||||||
flags: MachineFlags,
|
flags: MachineFlags,
|
||||||
mut terms: Vec<Box<Term>>,
|
mut terms: Vec<Box<Term>>,
|
||||||
line_num: usize,
|
line_num: usize,
|
||||||
@@ -600,54 +663,62 @@ fn setup_declaration<'a, 'b, 'c, R: Read>(
|
|||||||
|
|
||||||
match term {
|
match term {
|
||||||
Term::Clause(_, name, mut terms, _) =>
|
Term::Clause(_, name, mut terms, _) =>
|
||||||
match (name.as_str(), terms.len()) {
|
match (name.as_str(), terms.len()) {
|
||||||
("dynamic", 1) => {
|
("dynamic", 1) => {
|
||||||
let (name, arity) = setup_predicate_indicator(&mut *terms.pop().unwrap())?;
|
let (name, arity) = setup_predicate_indicator(&mut *terms.pop().unwrap())?;
|
||||||
Ok(Declaration::Dynamic(name, arity))
|
Ok(Declaration::Dynamic(name, arity))
|
||||||
}
|
}
|
||||||
("initialization", 1) => {
|
("initialization", 1) => {
|
||||||
let mut rel_worker = RelationWorker::new(flags, line_num, col_num);
|
let mut rel_worker = RelationWorker::new(flags, line_num, col_num);
|
||||||
let query_terms = rel_worker.setup_query(indices, terms, false)?;
|
let (query_terms, _) = rel_worker.setup_query(indices, terms, false, false)?;
|
||||||
let queue = rel_worker.parse_queue(indices)?;
|
let queue = rel_worker.parse_queue(indices)?;
|
||||||
|
|
||||||
Ok(Declaration::ModuleInitialization(query_terms, queue))
|
Ok(Declaration::ModuleInitialization(query_terms, queue))
|
||||||
}
|
}
|
||||||
("module", 2) =>
|
("module", 2) =>
|
||||||
Ok(Declaration::Module(setup_module_decl(terms, indices.atom_tbl())?)),
|
Ok(Declaration::Module(setup_module_decl(terms, indices.atom_tbl())?)),
|
||||||
("op", 3) =>
|
("op", 3) =>
|
||||||
Ok(Declaration::Op(setup_op_decl(terms, indices.atom_tbl())?)),
|
Ok(Declaration::Op(setup_op_decl(terms, indices.atom_tbl())?)),
|
||||||
("non_counted_backtracking", 1) => {
|
("non_counted_backtracking", 1) => {
|
||||||
let (name, arity) = setup_predicate_indicator(&mut *terms.pop().unwrap())?;
|
let (name, arity) = setup_predicate_indicator(&mut *terms.pop().unwrap())?;
|
||||||
Ok(Declaration::NonCountedBacktracking(name, arity))
|
Ok(Declaration::NonCountedBacktracking(name, arity))
|
||||||
}
|
}
|
||||||
|
("set_prolog_flag", 2) => {
|
||||||
|
Ok(Declaration::SetPrologFlag(setup_double_quotes(terms)?))
|
||||||
|
}
|
||||||
("multifile", 1) => {
|
("multifile", 1) => {
|
||||||
let mut term = *terms.pop().unwrap();
|
let mut term = *terms.pop().unwrap();
|
||||||
|
|
||||||
match setup_predicate_indicator(&mut term) {
|
match setup_predicate_indicator(&mut term) {
|
||||||
Ok((name, arity)) =>
|
Ok((name, arity)) => {
|
||||||
Ok(Declaration::MultiFile(MultiFileIndicator::LocalScoped(name, arity))),
|
Ok(Declaration::MultiFile(MultiFileIndicator::LocalScoped(name, arity)))
|
||||||
_ =>
|
}
|
||||||
|
_ => {
|
||||||
setup_scoped_predicate_indicator(&mut term)
|
setup_scoped_predicate_indicator(&mut term)
|
||||||
.map(|key| {
|
.map(|key| {
|
||||||
Declaration::MultiFile(MultiFileIndicator::ModuleScoped(key))
|
Declaration::MultiFile(MultiFileIndicator::ModuleScoped(key))
|
||||||
})
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
("use_module", 1) => {
|
("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) => {
|
("use_module", 2) => {
|
||||||
let (name, exports) = setup_qualified_import(terms, indices.atom_tbl())?;
|
let (name, exports) = setup_qualified_import(terms, indices.atom_tbl())?;
|
||||||
Ok(Declaration::UseQualifiedModule(name, exports))
|
Ok(Declaration::UseQualifiedModule(name, exports))
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
Err(ParserError::InconsistentEntry)
|
Err(ParserError::InconsistentEntry)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
_ => Err(ParserError::InconsistentEntry),
|
_ => {
|
||||||
|
Err(ParserError::InconsistentEntry)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
struct RelationWorker {
|
struct RelationWorker {
|
||||||
flags: MachineFlags,
|
flags: MachineFlags,
|
||||||
dynamic_clauses: Vec<(Term, Term)>, // Head, Body.
|
dynamic_clauses: Vec<(Term, Term)>, // Head, Body.
|
||||||
@@ -767,9 +838,9 @@ impl RelationWorker {
|
|||||||
self.fabricate_rule(fold_by_str(prec_seq.into_iter(), body_term, comma_sym))
|
self.fabricate_rule(fold_by_str(prec_seq.into_iter(), body_term, comma_sym))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn to_query_term<'a, 'b, 'c, R: Read>(
|
fn to_query_term<'a, 'b, 'c>(
|
||||||
&mut self,
|
&mut self,
|
||||||
indices: &mut CompositeIndices<'a, 'b, 'c, R>,
|
indices: &mut CompositeIndices<'a, 'b, 'c>,
|
||||||
term: Term,
|
term: Term,
|
||||||
) -> Result<QueryTerm, ParserError> {
|
) -> Result<QueryTerm, ParserError> {
|
||||||
match term {
|
match term {
|
||||||
@@ -818,6 +889,7 @@ impl RelationWorker {
|
|||||||
let term = Term::Clause(Cell::default(), clause_name!(";"), terms, None);
|
let term = Term::Clause(Cell::default(), clause_name!(";"), terms, None);
|
||||||
let (stub, clauses) = self.fabricate_disjunct(term);
|
let (stub, clauses) = self.fabricate_disjunct(term);
|
||||||
|
|
||||||
|
debug_assert!(clauses.len() > 0);
|
||||||
self.queue.push_back(clauses);
|
self.queue.push_back(clauses);
|
||||||
Ok(QueryTerm::Jump(stub))
|
Ok(QueryTerm::Jump(stub))
|
||||||
}
|
}
|
||||||
@@ -843,9 +915,9 @@ impl RelationWorker {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pre_query_term<'a, 'b, 'c, R: Read>(
|
fn pre_query_term<'a, 'b, 'c>(
|
||||||
&mut self,
|
&mut self,
|
||||||
indices: &mut CompositeIndices<'a, 'b, 'c, R>,
|
indices: &mut CompositeIndices<'a, 'b, 'c>,
|
||||||
term: Term,
|
term: Term,
|
||||||
) -> Result<QueryTerm, ParserError> {
|
) -> Result<QueryTerm, ParserError> {
|
||||||
match term {
|
match term {
|
||||||
@@ -864,16 +936,19 @@ impl RelationWorker {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn setup_query<'a, 'b, 'c, R: Read>(
|
fn setup_query<'a, 'b, 'c>(
|
||||||
&mut self,
|
&mut self,
|
||||||
indices: &mut CompositeIndices<'a, 'b, 'c, R>,
|
indices: &mut CompositeIndices<'a, 'b, 'c>,
|
||||||
terms: Vec<Box<Term>>,
|
terms: Vec<Box<Term>>,
|
||||||
blocks_cuts: bool,
|
blocks_cuts: bool,
|
||||||
) -> Result<Vec<QueryTerm>, ParserError> {
|
assume_dyn: bool,
|
||||||
|
) -> Result<(Vec<QueryTerm>, Term), ParserError> {
|
||||||
let mut query_terms = vec![];
|
let mut query_terms = vec![];
|
||||||
let mut work_queue = VecDeque::from(terms);
|
let mut work_queue = VecDeque::from(terms);
|
||||||
let mut machine_st = MachineState::new();
|
let mut machine_st = MachineState::new();
|
||||||
|
|
||||||
|
let mut dynamic_clause_terms = vec![];
|
||||||
|
|
||||||
while let Some(term) = work_queue.pop_front() {
|
while let Some(term) = work_queue.pop_front() {
|
||||||
let term = *term;
|
let term = *term;
|
||||||
let op_dir = op_dir(&indices.index_src);
|
let op_dir = op_dir(&indices.index_src);
|
||||||
@@ -892,7 +967,7 @@ impl RelationWorker {
|
|||||||
let mut term = *term;
|
let mut term = *term;
|
||||||
|
|
||||||
if let Term::Clause(cell, name, terms, op_spec) = term {
|
if let Term::Clause(cell, name, terms, op_spec) = term {
|
||||||
if name.as_str() == "," {
|
if name.as_str() == "," && terms.len() == 2 {
|
||||||
let term = Term::Clause(cell, name, terms, op_spec);
|
let term = Term::Clause(cell, name, terms, op_spec);
|
||||||
let mut subterms = unfold_by_str(term, ",");
|
let mut subterms = unfold_by_str(term, ",");
|
||||||
|
|
||||||
@@ -910,17 +985,28 @@ impl RelationWorker {
|
|||||||
mark_cut_variable(&mut term);
|
mark_cut_variable(&mut term);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if assume_dyn {
|
||||||
|
dynamic_clause_terms.push(term.clone());
|
||||||
|
}
|
||||||
|
|
||||||
query_terms.push(self.pre_query_term(indices, term)?);
|
query_terms.push(self.pre_query_term(indices, term)?);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(query_terms)
|
let dynamic_clause_body =
|
||||||
|
if let Some(term) = dynamic_clause_terms.pop() {
|
||||||
|
fold_by_str(dynamic_clause_terms.into_iter(), term, clause_name!(","))
|
||||||
|
} else {
|
||||||
|
Term::Constant(Cell::default(), Constant::Atom(clause_name!("true"), None))
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok((query_terms, dynamic_clause_body))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn setup_hook<'a, 'b, 'c, R: Read>(
|
fn setup_hook<'a, 'b, 'c>(
|
||||||
&mut self,
|
&mut self,
|
||||||
hook: CompileTimeHook,
|
hook: CompileTimeHook,
|
||||||
indices: &mut CompositeIndices<'a, 'b, 'c, R>,
|
indices: &mut CompositeIndices<'a, 'b, 'c>,
|
||||||
term: Term,
|
term: Term,
|
||||||
) -> Result<CompileTimeHookCompileInfo, ParserError> {
|
) -> Result<CompileTimeHookCompileInfo, ParserError> {
|
||||||
match flatten_hook(term) {
|
match flatten_hook(term) {
|
||||||
@@ -941,24 +1027,24 @@ impl RelationWorker {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn setup_rule<'a, 'b, 'c, R: Read>(
|
fn setup_rule<'a, 'b, 'c>(
|
||||||
&mut self,
|
&mut self,
|
||||||
indices: &mut CompositeIndices<'a, 'b, 'c, R>,
|
indices: &mut CompositeIndices<'a, 'b, 'c>,
|
||||||
mut terms: Vec<Box<Term>>,
|
mut terms: Vec<Box<Term>>,
|
||||||
blocks_cuts: bool,
|
blocks_cuts: bool,
|
||||||
assume_dyn: bool,
|
assume_dyn: bool,
|
||||||
) -> Result<Rule, ParserError> {
|
) -> Result<Rule, ParserError> {
|
||||||
let head = *terms.first().cloned().unwrap();
|
let dynamic_term_head = *terms.first().cloned().unwrap();
|
||||||
let post_head_terms: Vec<_> = terms.drain(1..).collect();
|
let post_head_terms: Vec<_> = terms.drain(1 ..).collect();
|
||||||
|
|
||||||
let tail = *post_head_terms.first().cloned().unwrap();
|
let (mut query_terms, dynamic_term_body) =
|
||||||
|
self.setup_query(indices, post_head_terms, blocks_cuts, assume_dyn)?;
|
||||||
|
|
||||||
if assume_dyn {
|
if assume_dyn {
|
||||||
self.dynamic_clauses.push((head, tail));
|
self.dynamic_clauses.push((dynamic_term_head, dynamic_term_body));
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut query_terms = self.setup_query(indices, post_head_terms, blocks_cuts)?;
|
let clauses = query_terms.drain(1 ..).collect();
|
||||||
let clauses = query_terms.drain(1..).collect();
|
|
||||||
let qt = query_terms.pop().unwrap();
|
let qt = query_terms.pop().unwrap();
|
||||||
|
|
||||||
match *terms.pop().unwrap() {
|
match *terms.pop().unwrap() {
|
||||||
@@ -974,23 +1060,26 @@ impl RelationWorker {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn try_term_to_query<'a, 'b, 'c, R: Read>(
|
fn try_term_to_query<'a, 'b, 'c>(
|
||||||
&mut self,
|
&mut self,
|
||||||
indices: &mut CompositeIndices<'a, 'b, 'c, R>,
|
indices: &mut CompositeIndices<'a, 'b, 'c>,
|
||||||
terms: Vec<Box<Term>>,
|
terms: Vec<Box<Term>>,
|
||||||
blocks_cuts: bool,
|
blocks_cuts: bool,
|
||||||
) -> Result<TopLevel, ParserError> {
|
) -> Result<TopLevel, ParserError> {
|
||||||
Ok(TopLevel::Query(self.setup_query(
|
let (result, _) = self.setup_query(
|
||||||
indices,
|
indices,
|
||||||
terms,
|
terms,
|
||||||
blocks_cuts,
|
blocks_cuts,
|
||||||
)?))
|
false,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
Ok(TopLevel::Query(result))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn compact_module_scoped_head<'a, 'b, 'c, R: Read>(
|
fn compact_module_scoped_head<'a, 'b, 'c>(
|
||||||
&self,
|
&self,
|
||||||
term: &mut Term,
|
term: &mut Term,
|
||||||
indices: &mut CompositeIndices<'a, 'b, 'c, R>,
|
indices: &mut CompositeIndices<'a, 'b, 'c>,
|
||||||
) {
|
) {
|
||||||
let inner_term = match term {
|
let inner_term = match term {
|
||||||
Term::Clause(_, ref name, ref mut inner_terms, _)
|
Term::Clause(_, ref name, ref mut inner_terms, _)
|
||||||
@@ -1015,9 +1104,9 @@ impl RelationWorker {
|
|||||||
*term = inner_term;
|
*term = inner_term;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn try_term_to_tl<'a, 'b, 'c, R: Read>(
|
fn try_term_to_tl<'a, 'b, 'c>(
|
||||||
&mut self,
|
&mut self,
|
||||||
indices: &mut CompositeIndices<'a, 'b, 'c, R>,
|
indices: &mut CompositeIndices<'a, 'b, 'c>,
|
||||||
term: Term,
|
term: Term,
|
||||||
blocks_cuts: bool,
|
blocks_cuts: bool,
|
||||||
) -> Result<TopLevel, ParserError> {
|
) -> Result<TopLevel, ParserError> {
|
||||||
@@ -1051,19 +1140,20 @@ impl RelationWorker {
|
|||||||
Ok(TopLevel::Fact(self.setup_fact(term, true)?, self.line_num, self.col_num))
|
Ok(TopLevel::Fact(self.setup_fact(term, true)?, self.line_num, self.col_num))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
term =>
|
term => {
|
||||||
Ok(TopLevel::Fact(self.setup_fact(term, true)?, self.line_num, self.col_num)),
|
Ok(TopLevel::Fact(self.setup_fact(term, true)?, self.line_num, self.col_num))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn try_terms_to_tls<'a, 'b, 'c, I, R>(
|
fn try_terms_to_tls<'a, 'b, 'c, I>(
|
||||||
&mut self,
|
&mut self,
|
||||||
indices: &mut CompositeIndices<'a, 'b, 'c, R>,
|
indices: &mut CompositeIndices<'a, 'b, 'c>,
|
||||||
terms: I,
|
terms: I,
|
||||||
blocks_cuts: bool,
|
blocks_cuts: bool,
|
||||||
) -> Result<VecDeque<TopLevel>, ParserError>
|
) -> Result<VecDeque<TopLevel>, ParserError>
|
||||||
where
|
where
|
||||||
I: IntoIterator<Item = Term>, R: Read
|
I: IntoIterator<Item = Term>
|
||||||
{
|
{
|
||||||
let mut results = VecDeque::new();
|
let mut results = VecDeque::new();
|
||||||
|
|
||||||
@@ -1074,9 +1164,9 @@ impl RelationWorker {
|
|||||||
Ok(results)
|
Ok(results)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_queue<'a, 'b, 'c, R: Read>(
|
fn parse_queue<'a, 'b, 'c>(
|
||||||
&mut self,
|
&mut self,
|
||||||
indices: &mut CompositeIndices<'a, 'b, 'c, R>,
|
indices: &mut CompositeIndices<'a, 'b, 'c>,
|
||||||
) -> Result<VecDeque<TopLevel>, ParserError> {
|
) -> Result<VecDeque<TopLevel>, ParserError> {
|
||||||
let mut queue = VecDeque::new();
|
let mut queue = VecDeque::new();
|
||||||
|
|
||||||
@@ -1090,8 +1180,7 @@ impl RelationWorker {
|
|||||||
|
|
||||||
fn absorb(&mut self, other: RelationWorker) {
|
fn absorb(&mut self, other: RelationWorker) {
|
||||||
self.queue.extend(other.queue.into_iter());
|
self.queue.extend(other.queue.into_iter());
|
||||||
self.dynamic_clauses
|
self.dynamic_clauses.extend(other.dynamic_clauses.into_iter());
|
||||||
.extend(other.dynamic_clauses.into_iter());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1099,8 +1188,9 @@ pub type DynamicClause = Vec<(Term, Term)>;
|
|||||||
|
|
||||||
pub type DynamicClauseMap = IndexMap<(ClauseName, usize), DynamicClause>;
|
pub type DynamicClauseMap = IndexMap<(ClauseName, usize), DynamicClause>;
|
||||||
|
|
||||||
pub struct TopLevelBatchWorker<'a, R: Read> {
|
#[derive(Debug)]
|
||||||
pub(crate) term_stream: TermStream<'a, R>,
|
pub struct TopLevelBatchWorker<'a> {
|
||||||
|
pub(crate) term_stream: TermStream<'a>,
|
||||||
rel_worker: RelationWorker,
|
rel_worker: RelationWorker,
|
||||||
pub(crate) results: Vec<(Predicate, VecDeque<TopLevel>)>,
|
pub(crate) results: Vec<(Predicate, VecDeque<TopLevel>)>,
|
||||||
pub(crate) dynamic_clause_map: DynamicClauseMap,
|
pub(crate) dynamic_clause_map: DynamicClauseMap,
|
||||||
@@ -1110,14 +1200,14 @@ pub struct TopLevelBatchWorker<'a, R: Read> {
|
|||||||
pub(crate) non_counted_bt_preds: IndexSet<PredicateKey>,
|
pub(crate) non_counted_bt_preds: IndexSet<PredicateKey>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, R: Read> TopLevelBatchWorker<'a, R> {
|
impl<'a> TopLevelBatchWorker<'a> {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
inner: &'a mut ParsingStream<R>,
|
stream: &'a mut ParsingStream<Stream>,
|
||||||
atom_tbl: TabledData<Atom>,
|
atom_tbl: TabledData<Atom>,
|
||||||
flags: MachineFlags,
|
flags: MachineFlags,
|
||||||
wam: &'a mut Machine,
|
wam: &'a mut Machine,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let term_stream = TermStream::new(inner, atom_tbl, flags, wam);
|
let term_stream = TermStream::new(stream, atom_tbl, flags, wam);
|
||||||
|
|
||||||
let line_num = term_stream.line_num();
|
let line_num = term_stream.line_num();
|
||||||
let col_num = term_stream.col_num();
|
let col_num = term_stream.col_num();
|
||||||
@@ -1201,7 +1291,7 @@ impl<'a, R: Read> TopLevelBatchWorker<'a, R> {
|
|||||||
match self.dynamic_clause_map.get_mut(&(name.clone(), arity)) {
|
match self.dynamic_clause_map.get_mut(&(name.clone(), arity)) {
|
||||||
Some(ref mut entry) => {
|
Some(ref mut entry) => {
|
||||||
entry.clear(); // don't treat dynamic predicates as if they're discontiguous.
|
entry.clear(); // don't treat dynamic predicates as if they're discontiguous.
|
||||||
entry.extend(self.rel_worker.dynamic_clauses.drain(0..));
|
entry.extend(self.rel_worker.dynamic_clauses.drain(0 ..));
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
self.rel_worker.dynamic_clauses.clear();
|
self.rel_worker.dynamic_clauses.clear();
|
||||||
@@ -1248,7 +1338,7 @@ impl<'a, R: Read> TopLevelBatchWorker<'a, R> {
|
|||||||
TopLevel::Declaration(decl) =>
|
TopLevel::Declaration(decl) =>
|
||||||
return Ok(Some(decl)),
|
return Ok(Some(decl)),
|
||||||
TopLevel::Query(_) =>
|
TopLevel::Query(_) =>
|
||||||
return Err(SessionError::NamelessEntry),
|
return Err(SessionError::QueryCannotBeDefinedAsFact),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
431
src/macros.rs
Normal file
431
src/macros.rs
Normal file
@@ -0,0 +1,431 @@
|
|||||||
|
macro_rules! interm {
|
||||||
|
($n: expr) => {
|
||||||
|
ArithmeticTerm::Interm($n)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/* A simple macro to count the arguments in a variadic list
|
||||||
|
* of token trees.
|
||||||
|
*/
|
||||||
|
macro_rules! count_tt {
|
||||||
|
() => { 0 };
|
||||||
|
($odd:tt $($a:tt $b:tt)*) => { (count_tt!($($a)*) << 1) | 1 };
|
||||||
|
($($a:tt $even:tt)*) => { count_tt!($($a)*) << 1 };
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! functor {
|
||||||
|
($name:expr, $fixity:expr, [$($dt:ident($($value:expr),*)),+], [$($aux:ident),*]) => ({
|
||||||
|
{
|
||||||
|
#[allow(unused_variables, unused_mut)]
|
||||||
|
let mut addendum = Heap::new();
|
||||||
|
let arity = count_tt!($($dt) +);
|
||||||
|
let aux_lens = [$($aux.len()),*];
|
||||||
|
|
||||||
|
let mut result =
|
||||||
|
vec![ HeapCellValue::NamedStr(arity, clause_name!($name), Some($fixity)),
|
||||||
|
$(functor_term!( $dt($($value),*), arity, aux_lens, addendum ),)+ ];
|
||||||
|
|
||||||
|
$(
|
||||||
|
result.extend($aux.into_iter());
|
||||||
|
)*
|
||||||
|
|
||||||
|
result.extend(addendum.into_iter());
|
||||||
|
result
|
||||||
|
}
|
||||||
|
});
|
||||||
|
($name:expr, $fixity:expr, [$($dt:ident($($value:expr),*)),+]) => ({
|
||||||
|
{
|
||||||
|
#[allow(unused_variables, unused_mut)]
|
||||||
|
let mut addendum = Heap::new();
|
||||||
|
let arity = count_tt!($($dt) +);
|
||||||
|
|
||||||
|
let mut result =
|
||||||
|
vec![ HeapCellValue::NamedStr(arity, clause_name!($name), Some($fixity)),
|
||||||
|
$(functor_term!( $dt($($value),*), arity, [], addendum ),)+ ];
|
||||||
|
|
||||||
|
result.extend(addendum.into_iter());
|
||||||
|
result
|
||||||
|
}
|
||||||
|
});
|
||||||
|
($name:expr, [$($dt:ident($($value:expr),*)),+], [$($aux:ident),*]) => ({
|
||||||
|
{
|
||||||
|
#[allow(unused_variables, unused_mut)]
|
||||||
|
let mut addendum = Heap::new();
|
||||||
|
let arity = count_tt!($($dt) +);
|
||||||
|
let aux_lens = [$($aux.len()),*];
|
||||||
|
|
||||||
|
let mut result =
|
||||||
|
vec![ HeapCellValue::NamedStr(arity, clause_name!($name), None),
|
||||||
|
$(functor_term!( $dt($($value),*), arity, aux_lens, addendum ),)+ ];
|
||||||
|
|
||||||
|
$(
|
||||||
|
result.extend($aux.into_iter());
|
||||||
|
)*
|
||||||
|
|
||||||
|
result.extend(addendum.into_iter());
|
||||||
|
result
|
||||||
|
}
|
||||||
|
});
|
||||||
|
($name:expr, [$($dt:ident($($value:expr),*)),+]) => ({
|
||||||
|
{
|
||||||
|
let arity = count_tt!($($dt) +);
|
||||||
|
|
||||||
|
vec![ HeapCellValue::NamedStr(arity, clause_name!($name), None),
|
||||||
|
$(functor_term!( $dt($($value),*), arity, [], addendum ),)+ ]
|
||||||
|
}
|
||||||
|
});
|
||||||
|
($name:expr, $fixity:expr) => (
|
||||||
|
vec![ HeapCellValue::Atom(clause_name!($name), Some($fixity)) ]
|
||||||
|
);
|
||||||
|
(clause_name($name:expr)) => (
|
||||||
|
vec![ HeapCellValue::Atom($name, None) ]
|
||||||
|
);
|
||||||
|
($name:expr) => (
|
||||||
|
vec![ HeapCellValue::Atom(clause_name!($name), None) ]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! functor_term {
|
||||||
|
(aux(0), $arity:expr, $aux_lens:expr, $addendum:ident) => ({
|
||||||
|
HeapCellValue::Addr(Addr::HeapCell($arity + 1))
|
||||||
|
});
|
||||||
|
(aux($e:expr), $arity:expr, $aux_lens:expr, $addendum:ident) => ({
|
||||||
|
let len: usize = $aux_lens[0 .. $e].iter().sum();
|
||||||
|
HeapCellValue::Addr(Addr::HeapCell($arity + 1 + len))
|
||||||
|
});
|
||||||
|
(aux($h:expr, 0), $arity:expr, $aux_lens:expr, $addendum:ident) => ({
|
||||||
|
HeapCellValue::Addr(Addr::HeapCell($arity + $h + 1))
|
||||||
|
});
|
||||||
|
(aux($h:expr, $e:expr), $arity:expr, $aux_lens:expr, $addendum:ident) => ({
|
||||||
|
let len: usize = $aux_lens[0 .. $e].iter().sum();
|
||||||
|
HeapCellValue::Addr(Addr::HeapCell($arity + $h + 1 + len))
|
||||||
|
});
|
||||||
|
(addr($e:expr), $arity:expr, $aux_lens:expr, $addendum:ident) => (
|
||||||
|
HeapCellValue::Addr($e)
|
||||||
|
);
|
||||||
|
(constant($h:expr, $e:expr), $arity:expr, $aux_lens:expr, $addendum:ident) => (
|
||||||
|
from_constant!($e, $h, $arity, $aux_lens, $addendum)
|
||||||
|
);
|
||||||
|
(constant($e:expr), $arity:expr, $aux_lens:expr, $addendum:ident) => (
|
||||||
|
from_constant!($e, 0, $arity, $aux_lens, $addendum)
|
||||||
|
);
|
||||||
|
(number($e:expr), $arity:expr, $aux_lens:expr, $addendum:ident) => (
|
||||||
|
$e.into()
|
||||||
|
);
|
||||||
|
(integer($e:expr), $arity:expr, $aux_lens:expr, $addendum: ident) => (
|
||||||
|
HeapCellValue::Integer(Rc::new(Integer::from($e)))
|
||||||
|
);
|
||||||
|
(clause_name($e:expr), $arity:expr, $aux_lens:expr, $addendum: ident) => (
|
||||||
|
HeapCellValue::Atom($e, None)
|
||||||
|
);
|
||||||
|
(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;
|
||||||
|
|
||||||
|
$addendum.put_complete_string(&$e);
|
||||||
|
|
||||||
|
HeapCellValue::Addr(Addr::PStrLocation(h, 0))
|
||||||
|
});
|
||||||
|
(boolean($e:expr), $arity:expr, $aux_lens:expr, $addendum: ident) => ({
|
||||||
|
if $e {
|
||||||
|
functor_term!(atom("true"), $arity, $aux_lens, $addendum)
|
||||||
|
} else {
|
||||||
|
functor_term!(atom("false"), $arity, $aux_lens, $addendum)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
($e:expr, $arity:expr, $aux_lens:expr, $addendum:ident) => (
|
||||||
|
$e
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! from_constant {
|
||||||
|
($e:expr, $over_h:expr, $arity:expr, $aux_lens:expr, $addendum:ident) => ({
|
||||||
|
match $e {
|
||||||
|
&Constant::Atom(ref name, ref op) => {
|
||||||
|
HeapCellValue::Atom(name.clone(), op.clone())
|
||||||
|
}
|
||||||
|
&Constant::Char(c) => {
|
||||||
|
HeapCellValue::Addr(Addr::Char(c))
|
||||||
|
}
|
||||||
|
&Constant::Fixnum(n) => {
|
||||||
|
HeapCellValue::Addr(Addr::Fixnum(n))
|
||||||
|
}
|
||||||
|
&Constant::Integer(ref n) => {
|
||||||
|
HeapCellValue::Integer(n.clone())
|
||||||
|
}
|
||||||
|
&Constant::Rational(ref r) => {
|
||||||
|
HeapCellValue::Rational(r.clone())
|
||||||
|
}
|
||||||
|
&Constant::Float(f) => {
|
||||||
|
HeapCellValue::Addr(Addr::Float(f))
|
||||||
|
}
|
||||||
|
&Constant::String(ref s) => {
|
||||||
|
let len: usize = $aux_lens.iter().sum();
|
||||||
|
let h = len + $arity + 1 + $addendum.h() + $over_h;
|
||||||
|
|
||||||
|
$addendum.put_complete_string(&s);
|
||||||
|
|
||||||
|
HeapCellValue::Addr(Addr::PStrLocation(h, 0))
|
||||||
|
}
|
||||||
|
&Constant::Usize(u) => {
|
||||||
|
HeapCellValue::Addr(Addr::Usize(u))
|
||||||
|
}
|
||||||
|
&Constant::EmptyList => {
|
||||||
|
HeapCellValue::Addr(Addr::EmptyList)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! is_atom {
|
||||||
|
($r:expr) => {
|
||||||
|
call_clause!(ClauseType::Inlined(InlinedClauseType::IsAtom($r)), 1, 0)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! is_atomic {
|
||||||
|
($r:expr) => {
|
||||||
|
call_clause!(ClauseType::Inlined(InlinedClauseType::IsAtomic($r)), 1, 0)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! is_integer {
|
||||||
|
($r:expr) => {
|
||||||
|
call_clause!(ClauseType::Inlined(InlinedClauseType::IsInteger($r)), 1, 0)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! is_compound {
|
||||||
|
($r:expr) => {
|
||||||
|
call_clause!(ClauseType::Inlined(InlinedClauseType::IsCompound($r)), 1, 0)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! is_float {
|
||||||
|
($r:expr) => {
|
||||||
|
call_clause!(ClauseType::Inlined(InlinedClauseType::IsFloat($r)), 1, 0)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! is_rational {
|
||||||
|
($r:expr) => {
|
||||||
|
call_clause!(ClauseType::Inlined(InlinedClauseType::IsRational($r)), 1, 0)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! is_nonvar {
|
||||||
|
($r:expr) => {
|
||||||
|
call_clause!(ClauseType::Inlined(InlinedClauseType::IsNonVar($r)), 1, 0)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! is_var {
|
||||||
|
($r:expr) => {
|
||||||
|
call_clause!(ClauseType::Inlined(InlinedClauseType::IsVar($r)), 1, 0)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! call_clause {
|
||||||
|
($ct:expr, $arity:expr, $pvs:expr) => {
|
||||||
|
Line::Control(ControlInstruction::CallClause(
|
||||||
|
$ct, $arity, $pvs, false, false,
|
||||||
|
))
|
||||||
|
};
|
||||||
|
($ct:expr, $arity:expr, $pvs:expr, $lco:expr) => {
|
||||||
|
Line::Control(ControlInstruction::CallClause(
|
||||||
|
$ct, $arity, $pvs, $lco, false,
|
||||||
|
))
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! call_clause_by_default {
|
||||||
|
($ct:expr, $arity:expr, $pvs:expr) => {
|
||||||
|
Line::Control(ControlInstruction::CallClause(
|
||||||
|
$ct, $arity, $pvs, false, true,
|
||||||
|
))
|
||||||
|
};
|
||||||
|
($ct:expr, $arity:expr, $pvs:expr, $lco:expr) => {
|
||||||
|
Line::Control(ControlInstruction::CallClause(
|
||||||
|
$ct, $arity, $pvs, $lco, true,
|
||||||
|
))
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! proceed {
|
||||||
|
() => {
|
||||||
|
Line::Control(ControlInstruction::Proceed)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! is_call {
|
||||||
|
($r:expr, $at:expr) => {
|
||||||
|
call_clause!(ClauseType::BuiltIn(BuiltInClauseType::Is($r, $at)), 2, 0)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! is_call_by_default {
|
||||||
|
($r:expr, $at:expr) => {
|
||||||
|
call_clause_by_default!(ClauseType::BuiltIn(BuiltInClauseType::Is($r, $at)), 2, 0)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! set_cp {
|
||||||
|
($r:expr) => {
|
||||||
|
call_clause!(ClauseType::System(SystemClauseType::SetCutPoint($r)), 1, 0)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! succeed {
|
||||||
|
() => {
|
||||||
|
call_clause!(ClauseType::System(SystemClauseType::Succeed), 0, 0)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! fail {
|
||||||
|
() => {
|
||||||
|
call_clause!(ClauseType::System(SystemClauseType::Fail), 0, 0)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! compare_number_instr {
|
||||||
|
($cmp: expr, $at_1: expr, $at_2: expr) => {{
|
||||||
|
let ct = ClauseType::Inlined(InlinedClauseType::CompareNumber($cmp, $at_1, $at_2));
|
||||||
|
call_clause!(ct, 2, 0)
|
||||||
|
}};
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! jmp_call {
|
||||||
|
($arity:expr, $offset:expr, $pvs:expr) => {
|
||||||
|
Line::Control(ControlInstruction::JmpBy($arity, $offset, $pvs, false))
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! try_eval_session {
|
||||||
|
($e:expr) => {
|
||||||
|
match $e {
|
||||||
|
Ok(result) => result,
|
||||||
|
Err(e) => return EvalSession::from(e),
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
macro_rules! return_from_clause {
|
||||||
|
($lco:expr, $machine_st:expr) => {{
|
||||||
|
if let CodePtr::VerifyAttrInterrupt(_) = $machine_st.p {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
if $lco {
|
||||||
|
$machine_st.p = CodePtr::Local($machine_st.cp);
|
||||||
|
} else {
|
||||||
|
$machine_st.p += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}};
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! dir_entry {
|
||||||
|
($idx:expr) => {
|
||||||
|
LocalCodePtr::DirEntry($idx)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! set_code_index {
|
||||||
|
($idx:expr, $ip:expr, $mod_name:expr) => {{
|
||||||
|
let mut idx = $idx.0.borrow_mut();
|
||||||
|
|
||||||
|
idx.0 = $ip;
|
||||||
|
idx.1 = $mod_name.clone();
|
||||||
|
}};
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! index_store {
|
||||||
|
($atom_tbl:expr, $code_dir:expr, $op_dir:expr, $modules:expr) => {
|
||||||
|
IndexStore {
|
||||||
|
atom_tbl: $atom_tbl,
|
||||||
|
code_dir: $code_dir,
|
||||||
|
module_dir: ModuleDir::new(),
|
||||||
|
dynamic_code_dir: DynamicCodeDir::new(),
|
||||||
|
global_variables: GlobalVarDir::new(),
|
||||||
|
in_situ_code_dir: InSituCodeDir::new(),
|
||||||
|
in_situ_module_dir: ModuleStubDir::new(),
|
||||||
|
op_dir: $op_dir,
|
||||||
|
modules: $modules,
|
||||||
|
stream_aliases: StreamAliasDir::new(),
|
||||||
|
streams: StreamDir::new(),
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! default_index_store {
|
||||||
|
($atom_tbl:expr) => {
|
||||||
|
index_store!($atom_tbl, CodeDir::new(), default_op_dir(), IndexMap::new())
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! put_constant {
|
||||||
|
($lvl:expr, $cons:expr, $r:expr) => {
|
||||||
|
QueryInstruction::PutConstant($lvl, $cons, $r)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! get_level_and_unify {
|
||||||
|
($r: expr) => {
|
||||||
|
Line::Cut(CutInstruction::GetLevelAndUnify($r))
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! unwind_protect {
|
||||||
|
($e: expr, $protected: expr) => {
|
||||||
|
match $e {
|
||||||
|
Err(e) => {
|
||||||
|
$protected;
|
||||||
|
return Err(e);
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! discard_result {
|
||||||
|
($f: expr) => {
|
||||||
|
match $f {
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! ar_reg {
|
||||||
|
($r: expr) => {
|
||||||
|
ArithmeticTerm::Reg($r)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! atom_from {
|
||||||
|
($self:expr, $indices:expr, $e:expr) => {
|
||||||
|
match $e {
|
||||||
|
Addr::Con(h) if $self.heap.atom_at(h) => {
|
||||||
|
match &$self.heap[h] {
|
||||||
|
HeapCellValue::Atom(ref atom, _) => {
|
||||||
|
atom.clone()
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Addr::Char(c) => {
|
||||||
|
clause_name!(c.to_string(), $indices.atom_tbl.clone())
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
47
src/main.rs
47
src/main.rs
@@ -1,29 +1,62 @@
|
|||||||
|
extern crate blake2;
|
||||||
|
extern crate chrono;
|
||||||
|
extern crate cpu_time;
|
||||||
|
extern crate crossterm;
|
||||||
|
extern crate divrem;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate downcast;
|
extern crate downcast;
|
||||||
|
extern crate git_version;
|
||||||
|
extern crate hostname;
|
||||||
extern crate indexmap;
|
extern crate indexmap;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate lazy_static;
|
extern crate lazy_static;
|
||||||
extern crate libc;
|
extern crate libc;
|
||||||
|
extern crate native_tls;
|
||||||
extern crate nix;
|
extern crate nix;
|
||||||
|
extern crate openssl;
|
||||||
|
extern crate ordered_float;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate prolog_parser;
|
extern crate prolog_parser;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate ref_thread_local;
|
extern crate ref_thread_local;
|
||||||
extern crate termion;
|
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 machine::*;
|
||||||
use crate::prolog::read::*;
|
use machine::streams::*;
|
||||||
|
use read::*;
|
||||||
|
|
||||||
use std::sync::atomic::Ordering;
|
use std::sync::atomic::Ordering;
|
||||||
|
|
||||||
extern fn handle_sigint(signal: libc::c_int) {
|
extern fn handle_sigint(signal: libc::c_int) {
|
||||||
let signal = signal::Signal::from_c_int(signal).unwrap();
|
let signal = signal::Signal::from_c_int(signal).unwrap();
|
||||||
if signal == signal::Signal::SIGINT {
|
if signal == signal::Signal::SIGINT {
|
||||||
INTERRUPT.store(true, Ordering::Relaxed);
|
INTERRUPT.store(true, Ordering::Relaxed);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -31,6 +64,6 @@ fn main() {
|
|||||||
let handler = signal::SigHandler::Handler(handle_sigint);
|
let handler = signal::SigHandler::Handler(handle_sigint);
|
||||||
unsafe { signal::signal(signal::Signal::SIGINT, handler) }.unwrap();
|
unsafe { signal::signal(signal::Signal::SIGINT, handler) }.unwrap();
|
||||||
|
|
||||||
let mut wam = Machine::new(readline::input_stream());
|
let mut wam = Machine::new(readline::input_stream(), Stream::stdout());
|
||||||
wam.run_top_level();
|
wam.run_top_level();
|
||||||
}
|
}
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user