Compare commits
3753 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4e7d9f9010 | ||
|
|
d3edffb7fc | ||
|
|
295a642034 | ||
|
|
ae0999a3bb | ||
|
|
11fd39bbaf | ||
|
|
eb06f19c32 | ||
|
|
ea88ca552d | ||
|
|
eabbf67e86 | ||
|
|
7a636b0394 | ||
|
|
71ea74a077 | ||
|
|
091af28368 | ||
|
|
fbc5345c9a | ||
|
|
9d49415449 | ||
|
|
83218bf0da | ||
|
|
fcd6c3f127 | ||
|
|
efbddeaeee | ||
|
|
daaab1cb37 | ||
|
|
9b73536cdd | ||
|
|
e12d3f14c1 | ||
|
|
ffb77473b2 | ||
|
|
49c0cd3733 | ||
|
|
a236d00d7d | ||
|
|
bb5a59170a | ||
|
|
2b757de73a | ||
|
|
03f796e9ff | ||
|
|
d8be99b6ad | ||
|
|
2a04025419 | ||
|
|
bc14e3aedd | ||
|
|
bcb9dd0860 | ||
|
|
18dd939159 | ||
|
|
1cbc95bd06 | ||
|
|
d1e8ea4dd5 | ||
|
|
068959bd07 | ||
|
|
3a2d57db33 | ||
|
|
3ce16656ee | ||
|
|
732f3ae10a | ||
|
|
a4993284cd | ||
|
|
8aeb326e5c | ||
|
|
304cf424ed | ||
|
|
3cd40419eb | ||
|
|
f8f7b3b7e2 | ||
|
|
39c850b4f4 | ||
|
|
8b6d68a4cd | ||
|
|
149d3932be | ||
|
|
36cbeb3d6c | ||
|
|
875ae5a773 | ||
|
|
70d046499a | ||
|
|
b6db1cde25 | ||
|
|
257209df75 | ||
|
|
d5d514ec96 | ||
|
|
533594b6b6 | ||
|
|
43b6afcdf3 | ||
|
|
2c23f84808 | ||
|
|
ad13aa3801 | ||
|
|
79597b63bf | ||
|
|
bdba7ba0f5 | ||
|
|
6c7d5e8278 | ||
|
|
61ebcdb56e | ||
|
|
f2195c2362 | ||
|
|
6150ca90d3 | ||
|
|
938f588769 | ||
|
|
61d94dceae | ||
|
|
1411417a44 | ||
|
|
609514b4b8 | ||
|
|
1fd9246b16 | ||
|
|
19974e580b | ||
|
|
550efb8416 | ||
|
|
e0c491e9f3 | ||
|
|
f16850e5f8 | ||
|
|
ca0d4e9aac | ||
|
|
6e50268efb | ||
|
|
54b3034905 | ||
|
|
cf9e667b50 | ||
|
|
3f0b471227 | ||
|
|
bfca60aa86 | ||
|
|
6b9a291f4e | ||
|
|
777637001f | ||
|
|
9fcd7776a9 | ||
|
|
4f166f50a8 | ||
|
|
1547839c33 | ||
|
|
5a1423d0f0 | ||
|
|
3faa838ee2 | ||
|
|
e4792429d3 | ||
|
|
d50d425099 | ||
|
|
0df5f7e576 | ||
|
|
b9f1443eb0 | ||
|
|
ac18aed5a7 | ||
|
|
2c60e4183f | ||
|
|
2bbb6487ec | ||
|
|
095fa1227a | ||
|
|
f395d554a5 | ||
|
|
ad614b684c | ||
|
|
898b6b2b25 | ||
|
|
3c5818a040 | ||
|
|
0c313a0849 | ||
|
|
7c9075b4ee | ||
|
|
4c14cbe39a | ||
|
|
afe744aa57 | ||
|
|
89dde3f370 | ||
|
|
f8ddd78776 | ||
|
|
327a677a7c | ||
|
|
48a34aa2cc | ||
|
|
af54fb2aba | ||
|
|
b2dad66270 | ||
|
|
eac7ff680c | ||
|
|
b4db85c8c3 | ||
|
|
6765921666 | ||
|
|
ff293a56e6 | ||
|
|
ab2b652c84 | ||
|
|
83add732e0 | ||
|
|
f8c4679850 | ||
|
|
3da2b8fba2 | ||
|
|
f7dc1d72f6 | ||
|
|
8dffd72db5 | ||
|
|
703a6dddd1 | ||
|
|
5ea262e1d3 | ||
|
|
010b00f349 | ||
|
|
974722bc1c | ||
|
|
695389bda1 | ||
|
|
9cf0d8b484 | ||
|
|
381b4f2857 | ||
|
|
35aa4d9048 | ||
|
|
8e2dcd905b | ||
|
|
081f3c0827 | ||
|
|
8bbb484f94 | ||
|
|
717c3c2db8 | ||
|
|
0aa6abe517 | ||
|
|
4a9f690c16 | ||
|
|
e3d020ea74 | ||
|
|
82378c6338 | ||
|
|
f456c98c5b | ||
|
|
4db325e4b8 | ||
|
|
8f33eaf7d1 | ||
|
|
eba16a2213 | ||
|
|
87f97c7e5c | ||
|
|
2fec440ba6 | ||
|
|
3e2f3ecfdb | ||
|
|
2b6b11e6be | ||
|
|
7da2ba2015 | ||
|
|
bb9c1cf5a2 | ||
|
|
28f8da5ce9 | ||
|
|
c065b52778 | ||
|
|
6a10c6d6a5 | ||
|
|
0623e8e7df | ||
|
|
3c9c7ade8d | ||
|
|
13c85c74db | ||
|
|
5fc21241d6 | ||
|
|
833c3bd77f | ||
|
|
153f04b72a | ||
|
|
8aab887388 | ||
|
|
79a9b950cb | ||
|
|
fba2854f21 | ||
|
|
1c9fd1501a | ||
|
|
b0b89a0aca | ||
|
|
025da8315b | ||
|
|
8002b9a78b | ||
|
|
02f86587b5 | ||
|
|
4d144ea819 | ||
|
|
02c927bb83 | ||
|
|
4a8388a6e9 | ||
|
|
7bf014cdf5 | ||
|
|
b41563e976 | ||
|
|
ead2fccdbb | ||
|
|
817c584993 | ||
|
|
e00112b92f | ||
|
|
4bd0ff0fcb | ||
|
|
ed59aa05b0 | ||
|
|
16ed1040d2 | ||
|
|
fa21ff4813 | ||
|
|
891f7fc892 | ||
|
|
fae9ca1bb9 | ||
|
|
ac71cff338 | ||
|
|
8f39bee463 | ||
|
|
2dc904aa73 | ||
|
|
0ceab41b39 | ||
|
|
2a79d6fc40 | ||
|
|
49e49b425d | ||
|
|
7d0d61d789 | ||
|
|
5ef5a3f30a | ||
|
|
337d9c5583 | ||
|
|
26523139a8 | ||
|
|
65aadb3b88 | ||
|
|
dfad71bc6e | ||
|
|
d8c6fa1fe5 | ||
|
|
18b476af28 | ||
|
|
bd233fedfd | ||
|
|
083546442d | ||
|
|
3343188756 | ||
|
|
ed36aa7313 | ||
|
|
0dc94ecc0b | ||
|
|
453a88f03e | ||
|
|
c79fd74331 | ||
|
|
e446b13376 | ||
|
|
a83f412251 | ||
|
|
1a8c4f9b03 | ||
|
|
c2e1ded852 | ||
|
|
70220687f4 | ||
|
|
69a367d1c9 | ||
|
|
e2bdf59c81 | ||
|
|
6284aa3a3f | ||
|
|
29cd80510b | ||
|
|
9089f9ddb4 | ||
|
|
16dc10ee96 | ||
|
|
4e8f338870 | ||
|
|
b14e363d5e | ||
|
|
87f89545bb | ||
|
|
5064760b1e | ||
|
|
eca4262be6 | ||
|
|
73c26bed2a | ||
|
|
172b6a6f8f | ||
|
|
129cca53ed | ||
|
|
cd1ed106ed | ||
|
|
00aba96185 | ||
|
|
616f071cd9 | ||
|
|
580572aec6 | ||
|
|
47e908bf76 | ||
|
|
11901b5fde | ||
|
|
d63b0a192c | ||
|
|
2fc08dde1e | ||
|
|
193cfabc66 | ||
|
|
7c3ffd0e87 | ||
|
|
797a8f8611 | ||
|
|
f570e566f8 | ||
|
|
96a9dfcc1b | ||
|
|
6fdcd17f32 | ||
|
|
652e824e59 | ||
|
|
f595eaee2e | ||
|
|
9ddeeed683 | ||
|
|
b287f0aedb | ||
|
|
3b019fca1d | ||
|
|
4bd16b8a2e | ||
|
|
f2e044e5b8 | ||
|
|
1cd55d8131 | ||
|
|
14265118f1 | ||
|
|
b66824ffce | ||
|
|
6ec8c9064f | ||
|
|
d4f2f7ba2b | ||
|
|
a05dc79505 | ||
|
|
e90c813528 | ||
|
|
516848e214 | ||
|
|
6063783e9d | ||
|
|
e9e97fe82a | ||
|
|
5686b69013 | ||
|
|
248b05c992 | ||
|
|
a283c8bdc2 | ||
|
|
6b5ec3fab8 | ||
|
|
a0b4162d7a | ||
|
|
119761ad10 | ||
|
|
bf8651db29 | ||
|
|
11d0215963 | ||
|
|
16fd7a8d51 | ||
|
|
5357ecf8e3 | ||
|
|
e7c288f8f0 | ||
|
|
95abc4017e | ||
|
|
b91ce76052 | ||
|
|
617a551a56 | ||
|
|
31247545c3 | ||
|
|
15d112485c | ||
|
|
768f7ce9a7 | ||
|
|
e4d9692535 | ||
|
|
f050e75d81 | ||
|
|
3dcb42af3c | ||
|
|
fdcd92db08 | ||
|
|
c82f1ccde1 | ||
|
|
2b85a307ae | ||
|
|
d7d5dfe059 | ||
|
|
109796122e | ||
|
|
476c1718f9 | ||
|
|
f8b9944f5c | ||
|
|
6e7dbfc75e | ||
|
|
1add5a9a75 | ||
|
|
777e6de9ee | ||
|
|
2443af57d0 | ||
|
|
ed03d5b1b4 | ||
|
|
9376bc6369 | ||
|
|
2f43c3ff40 | ||
|
|
e7ac3ae0f7 | ||
|
|
60595f990f | ||
|
|
042631cb4c | ||
|
|
32b6458deb | ||
|
|
12db664bd9 | ||
|
|
e9ff1348b1 | ||
|
|
fc6e007ad1 | ||
|
|
7637a0f7d4 | ||
|
|
ba7b54e8f8 | ||
|
|
012e3de3a1 | ||
|
|
72cdba82f5 | ||
|
|
24f431e2ca | ||
|
|
8afcc7742b | ||
|
|
e9834ffa3e | ||
|
|
28ec457159 | ||
|
|
1ece558a71 | ||
|
|
be18eda696 | ||
|
|
fdbaf6ac9d | ||
|
|
5c341ce371 | ||
|
|
5f58e1cfd7 | ||
|
|
dc05526c71 | ||
|
|
ffea37d899 | ||
|
|
368c9fd9dd | ||
|
|
c067bfa832 | ||
|
|
aa3d8b8fba | ||
|
|
14ce052bf2 | ||
|
|
252361fc20 | ||
|
|
78c08b87b6 | ||
|
|
eb91b3c1fb | ||
|
|
a140720c6f | ||
|
|
6f3f66c407 | ||
|
|
1f7a60dec9 | ||
|
|
ce9b41815d | ||
|
|
80bf276e09 | ||
|
|
8bc8171ec7 | ||
|
|
3b5b768f4a | ||
|
|
176858ad42 | ||
|
|
eba681786d | ||
|
|
f4297e365f | ||
|
|
cd777294b9 | ||
|
|
3e929511bb | ||
|
|
d1356db7e3 | ||
|
|
7b2bf73ba1 | ||
|
|
edd6d44bd6 | ||
|
|
4b5e4a2745 | ||
|
|
3a4dfc46da | ||
|
|
d8346b1651 | ||
|
|
20d52c093a | ||
|
|
35d34231f2 | ||
|
|
90e6e84312 | ||
|
|
cd501beb0b | ||
|
|
39d02a0caf | ||
|
|
e168b31963 | ||
|
|
eed0a5babb | ||
|
|
ad29f0f180 | ||
|
|
b14bda310f | ||
|
|
39cf60bc05 | ||
|
|
02b8a6010c | ||
|
|
b2cfc8b6f2 | ||
|
|
c5389dbbf2 | ||
|
|
633b86ddc4 | ||
|
|
348c5029b3 | ||
|
|
7ffd93c0d7 | ||
|
|
6338a40eed | ||
|
|
3aa272e44d | ||
|
|
52f3ddd20d | ||
|
|
f61c069c2b | ||
|
|
f1171e2fb2 | ||
|
|
e38ee14580 | ||
|
|
93cc4d4898 | ||
|
|
87f5295bd0 | ||
|
|
97607d2bcd | ||
|
|
216c251c48 | ||
|
|
8af0a19130 | ||
|
|
9485ae2ca5 | ||
|
|
18c451e11c | ||
|
|
a4c071a44b | ||
|
|
c0fb3fd429 | ||
|
|
9fb7d15f0a | ||
|
|
a8fa8993e1 | ||
|
|
af3792f79a | ||
|
|
d83827b21f | ||
|
|
ee39be4361 | ||
|
|
bc4689ca4a | ||
|
|
86dc22a850 | ||
|
|
9cc170f2ad | ||
|
|
61f8bc008c | ||
|
|
948cbd8f40 | ||
|
|
e1a52a4dde | ||
|
|
7b960a7d63 | ||
|
|
c5fd4c1d8a | ||
|
|
7dc6d6e4e0 | ||
|
|
1d643d8385 | ||
|
|
badd6304c7 | ||
|
|
a8da2b6a99 | ||
|
|
a43bac8fd8 | ||
|
|
72d5574ff0 | ||
|
|
a2e19bd483 | ||
|
|
d907f86c8d | ||
|
|
fadd3a0839 | ||
|
|
45041be336 | ||
|
|
b2d639b159 | ||
|
|
3a6b92d227 | ||
|
|
409159d68d | ||
|
|
143f32be23 | ||
|
|
d0a6dc9df2 | ||
|
|
62e43a3ab0 | ||
|
|
eb82d1b6d4 | ||
|
|
70d65bcea8 | ||
|
|
25edde2eb4 | ||
|
|
ab675e071a | ||
|
|
dc08a4ab11 | ||
|
|
1120bcde29 | ||
|
|
dc495f10f8 | ||
|
|
d2ffd4f4bf | ||
|
|
87dbad2294 | ||
|
|
ca52c65902 | ||
|
|
7f233da10c | ||
|
|
ff546a0f9a | ||
|
|
746d4fd106 | ||
|
|
97e2e5d7f0 | ||
|
|
1ee4f7a55f | ||
|
|
43dd1587fb | ||
|
|
8971809c83 | ||
|
|
e321f29b9c | ||
|
|
129c80bf16 | ||
|
|
183761eba4 | ||
|
|
6c7833b9c7 | ||
|
|
82e989f631 | ||
|
|
2b052bf8dd | ||
|
|
003e9d4610 | ||
|
|
d79ece2497 | ||
|
|
ae0baf4893 | ||
|
|
1114700ce6 | ||
|
|
dea43a0244 | ||
|
|
0c2c6124eb | ||
|
|
9cccd509e3 | ||
|
|
36bdab84ba | ||
|
|
cf51338a77 | ||
|
|
f738b42e49 | ||
|
|
f45426e8ab | ||
|
|
3d2439c92b | ||
|
|
6205f2f1f1 | ||
|
|
760e1d2aac | ||
|
|
e1246f0c83 | ||
|
|
bd1f8bb37e | ||
|
|
620459ea1e | ||
|
|
d2502b0520 | ||
|
|
34eab2e73a | ||
|
|
db3f2717bc | ||
|
|
7227e1d97c | ||
|
|
9d8906da30 | ||
|
|
f524062e5b | ||
|
|
eb29390a79 | ||
|
|
f91aedcc2f | ||
|
|
4f04d2dfca | ||
|
|
de89a78cbb | ||
|
|
e7600884fb | ||
|
|
3365cffa96 | ||
|
|
df3f1236f7 | ||
|
|
8766851919 | ||
|
|
014d1b0095 | ||
|
|
c885d1a7e7 | ||
|
|
7593f88d5a | ||
|
|
6885074006 | ||
|
|
73cc872b50 | ||
|
|
fae5e13bd5 | ||
|
|
6d7c217227 | ||
|
|
166ec02973 | ||
|
|
1d26f98688 | ||
|
|
58b9a6ad69 | ||
|
|
a639fec153 | ||
|
|
495bcd73f2 | ||
|
|
ae3019d923 | ||
|
|
72631b3e0b | ||
|
|
8cc74b2af7 | ||
|
|
7199e9a2db | ||
|
|
edf21494d9 | ||
|
|
b364c9073a | ||
|
|
9b293cf1b6 | ||
|
|
65dda019a2 | ||
|
|
4aa2a45736 | ||
|
|
4efceda8c5 | ||
|
|
5dc8983eec | ||
|
|
49b30e9f81 | ||
|
|
b78ccf8f28 | ||
|
|
2dc66d33dd | ||
|
|
e303e5a805 | ||
|
|
762b63e1f4 | ||
|
|
2844b5a958 | ||
|
|
1332611f83 | ||
|
|
725def07cd | ||
|
|
cbdd0fbf15 | ||
|
|
87ca083cfa | ||
|
|
d01557f3c1 | ||
|
|
8b009448f4 | ||
|
|
709dc041eb | ||
|
|
8763a42c98 | ||
|
|
d6b6eda77d | ||
|
|
4e0493474e | ||
|
|
a9847eef65 | ||
|
|
cb9b988905 | ||
|
|
073ec4c1d0 | ||
|
|
d51cbd67e0 | ||
|
|
e9bb41f0d6 | ||
|
|
b12d1ece17 | ||
|
|
706ffe7ad9 | ||
|
|
258244caf2 | ||
|
|
39ea2d5899 | ||
|
|
41b90c6e46 | ||
|
|
6bcbb91e08 | ||
|
|
e1e52338d6 | ||
|
|
995a39419a | ||
|
|
4644ea2404 | ||
|
|
f3cd6326a3 | ||
|
|
bf31d3f9a9 | ||
|
|
4c46f0e54d | ||
|
|
e563fd8e4f | ||
|
|
1297a24469 | ||
|
|
907e64e185 | ||
|
|
46f259bf7d | ||
|
|
634ccf22aa | ||
|
|
16b3bea48e | ||
|
|
e20363b462 | ||
|
|
549a26dd03 | ||
|
|
8981ab72d1 | ||
|
|
98dae9aecc | ||
|
|
22080f3787 | ||
|
|
9e1e99f961 | ||
|
|
eef7b06919 | ||
|
|
2ad870c740 | ||
|
|
3dee07f648 | ||
|
|
9daf016d63 | ||
|
|
fadcfb966e | ||
|
|
57f76169fd | ||
|
|
ae4d12a123 | ||
|
|
3c85ef2724 | ||
|
|
15f1320d05 | ||
|
|
7b357ba84d | ||
|
|
c0cd371056 | ||
|
|
79be0c0625 | ||
|
|
c0f72704ec | ||
|
|
f7bbdfe73a | ||
|
|
1ef681bd21 | ||
|
|
34ac85bb6d | ||
|
|
a69303dc93 | ||
|
|
778068129f | ||
|
|
ce56b5ed6b | ||
|
|
8e01eea440 | ||
|
|
1cf5de8f5c | ||
|
|
686f20db74 | ||
|
|
17377064cf | ||
|
|
f49a0ae79b | ||
|
|
4b480a7eab | ||
|
|
4a6f86591c | ||
|
|
37ac5bb3c1 | ||
|
|
9456517bed | ||
|
|
8f514ce419 | ||
|
|
e40125ff3a | ||
|
|
c790bbfce9 | ||
|
|
b767e4de25 | ||
|
|
ca173873af | ||
|
|
036c59e5fa | ||
|
|
7809edca19 | ||
|
|
a42a88a2c9 | ||
|
|
9dab070c11 | ||
|
|
ec28872a9a | ||
|
|
eb96a0c957 | ||
|
|
90f4716cc3 | ||
|
|
3a6289324e | ||
|
|
f496abbbef | ||
|
|
f1793744bc | ||
|
|
bd4b305649 | ||
|
|
638a765937 | ||
|
|
78fec46517 | ||
|
|
00a44921db | ||
|
|
d79bc199b3 | ||
|
|
4da0f90097 | ||
|
|
d18ef52e67 | ||
|
|
925921e9ab | ||
|
|
b98076b39e | ||
|
|
3090cb0084 | ||
|
|
971521791c | ||
|
|
2c8041250d | ||
|
|
1b22c89211 | ||
|
|
4e207fc34a | ||
|
|
8558bd2214 | ||
|
|
ba9fed3eae | ||
|
|
024c498bee | ||
|
|
8c348a7160 | ||
|
|
1f82dafcb6 | ||
|
|
d2dfb7ccda | ||
|
|
20525e5013 | ||
|
|
14c8fc3e34 | ||
|
|
3d60094330 | ||
|
|
ae27e78d80 | ||
|
|
3826ef38cd | ||
|
|
7b6f4439bb | ||
|
|
464cfd9213 | ||
|
|
9dbf592a58 | ||
|
|
e273b007a2 | ||
|
|
6df4eaf809 | ||
|
|
165d47c7b5 | ||
|
|
a45a1f6197 | ||
|
|
16187390cd | ||
|
|
57bf1ec39b | ||
|
|
7ac84d3565 | ||
|
|
32d91449b5 | ||
|
|
3799974b82 | ||
|
|
9da0a06afa | ||
|
|
b8526e0510 | ||
|
|
2d4fcf9714 | ||
|
|
4f3843742c | ||
|
|
a0e3283d64 | ||
|
|
c9a0f3332e | ||
|
|
aeacccbe4c | ||
|
|
5d468d3e19 | ||
|
|
080a4fed03 | ||
|
|
3b89c1124d | ||
|
|
236ed93c6c | ||
|
|
cea8e6b1c9 | ||
|
|
93e804eeaa | ||
|
|
b32273fc79 | ||
|
|
4fc4152eac | ||
|
|
914318b14e | ||
|
|
3fc5709c50 | ||
|
|
28926486e0 | ||
|
|
ad211d5e05 | ||
|
|
5386c183d2 | ||
|
|
0a2457943e | ||
|
|
baae1dca15 | ||
|
|
4e032c8a28 | ||
|
|
7a6620b52d | ||
|
|
dd6533e76c | ||
|
|
d262159399 | ||
|
|
c77ea48fbd | ||
|
|
35c1880937 | ||
|
|
e5cca9d10a | ||
|
|
f45b0bcfe8 | ||
|
|
8966e175f1 | ||
|
|
2a218f34b9 | ||
|
|
d8213e29c5 | ||
|
|
7f2ce57ba7 | ||
|
|
949d316773 | ||
|
|
0cf46d3ec4 | ||
|
|
e68ac8347f | ||
|
|
d4bf52e82c | ||
|
|
22538a05be | ||
|
|
6d80c843e6 | ||
|
|
b8ccebbf24 | ||
|
|
7108e87e92 | ||
|
|
fdc35f8b40 | ||
|
|
2fe7b55343 | ||
|
|
f509d3d66f | ||
|
|
079a69396a | ||
|
|
c548b14f50 | ||
|
|
590d0daa24 | ||
|
|
7a5a5bb795 | ||
|
|
5a869e8b48 | ||
|
|
28678e708b | ||
|
|
f69c58c6b6 | ||
|
|
0cde8f9a43 | ||
|
|
20735ea34c | ||
|
|
f3a92c6551 | ||
|
|
e2d1a2b6bc | ||
|
|
d3361c16d8 | ||
|
|
9420c7e41e | ||
|
|
a7598184bf | ||
|
|
bc0f614bf9 | ||
|
|
b1e66f686b | ||
|
|
b74c8139d1 | ||
|
|
75d499bf8a | ||
|
|
f1100271e2 | ||
|
|
143430dd9c | ||
|
|
00e6e323f8 | ||
|
|
b76bdd75e4 | ||
|
|
1ed4fe6555 | ||
|
|
894405149b | ||
|
|
eff094cc29 | ||
|
|
6cedbc33c0 | ||
|
|
2856cc4371 | ||
|
|
a683d3e363 | ||
|
|
2257503951 | ||
|
|
531d482ba7 | ||
|
|
28c386422b | ||
|
|
edaba024b2 | ||
|
|
333d6740ae | ||
|
|
56cb27f71c | ||
|
|
d57f871a12 | ||
|
|
afc7b74bbd | ||
|
|
d287095e61 | ||
|
|
a599a11169 | ||
|
|
b7943837a0 | ||
|
|
e01a4cdc85 | ||
|
|
555dff5bad | ||
|
|
75ac3fffae | ||
|
|
8dc80b815f | ||
|
|
6175e334a5 | ||
|
|
7e22c12a8d | ||
|
|
b5030be34f | ||
|
|
c59f54252c | ||
|
|
a9a77779e3 | ||
|
|
5f035ec6ad | ||
|
|
9eef380764 | ||
|
|
ce6a0a1541 | ||
|
|
b919a39b96 | ||
|
|
84fc639f31 | ||
|
|
a15b2789e2 | ||
|
|
2e910de485 | ||
|
|
74e3d32ca9 | ||
|
|
500a6cdaf1 | ||
|
|
17293a5753 | ||
|
|
a75266c3ce | ||
|
|
a92eac919f | ||
|
|
2ff50f06bc | ||
|
|
e219e1c483 | ||
|
|
eef9f74a68 | ||
|
|
eae1f53846 | ||
|
|
48a42ae140 | ||
|
|
44facf07ab | ||
|
|
9265d66f58 | ||
|
|
3d3baeed82 | ||
|
|
e21c772181 | ||
|
|
2f82c78bc0 | ||
|
|
ec6286ffab | ||
|
|
bb5adba4ef | ||
|
|
33d8abfed8 | ||
|
|
d336cbc86a | ||
|
|
79fbd9e90f | ||
|
|
cab61738ad | ||
|
|
e6cc408ff2 | ||
|
|
dc8348b843 | ||
|
|
cb040dafc1 | ||
|
|
c13fc2d1b6 | ||
|
|
1375f448a0 | ||
|
|
0433706db6 | ||
|
|
e74fd11b0d | ||
|
|
4480e7c066 | ||
|
|
71dec62ce2 | ||
|
|
658e39aae6 | ||
|
|
29fc55cb28 | ||
|
|
8e7dc9dba8 | ||
|
|
abe1f37167 | ||
|
|
8cde3f8ce3 | ||
|
|
dba9c9a0a7 | ||
|
|
ea02b54e7f | ||
|
|
0427d9ef11 | ||
|
|
c1571bf063 | ||
|
|
cef45de74a | ||
|
|
d7bf7445f1 | ||
|
|
8e5ddebddb | ||
|
|
ff03432624 | ||
|
|
7fd409140c | ||
|
|
9f6bbe949c | ||
|
|
e78914219e | ||
|
|
620077d8c1 | ||
|
|
556b7c733f | ||
|
|
e577a5430b | ||
|
|
e8ef9bc33a | ||
|
|
7b18b1d47a | ||
|
|
c39ea4818a | ||
|
|
90d418a181 | ||
|
|
9785a04b3a | ||
|
|
6dd0ec0b98 | ||
|
|
e9f03c89a6 | ||
|
|
8f41c1aa7e | ||
|
|
442636c131 | ||
|
|
190929e4ac | ||
|
|
2f47343cb5 | ||
|
|
3bc1885606 | ||
|
|
0552530b41 | ||
|
|
951c88d5f3 | ||
|
|
383eb5bdd9 | ||
|
|
3fa6b69a79 | ||
|
|
0bc3d67298 | ||
|
|
a898d7a667 | ||
|
|
238f1bd639 | ||
|
|
4b0f9558b3 | ||
|
|
c922ed8b0a | ||
|
|
3af24a8067 | ||
|
|
fdd6579230 | ||
|
|
16734ec7e4 | ||
|
|
d32f3ee2f3 | ||
|
|
ada9ba98cc | ||
|
|
a885e87ef7 | ||
|
|
e369c15a27 | ||
|
|
afa7af3de6 | ||
|
|
d3071988b2 | ||
|
|
08aed04dd2 | ||
|
|
7af93f1532 | ||
|
|
2b73107631 | ||
|
|
61c258f49e | ||
|
|
6f0c7f42c6 | ||
|
|
7b09d447d6 | ||
|
|
9f4d31a825 | ||
|
|
806e980cca | ||
|
|
12a61cdff8 | ||
|
|
808ea9fc79 | ||
|
|
e1d830d680 | ||
|
|
6be671d7d9 | ||
|
|
5c39e2a5a1 | ||
|
|
e24396d78a | ||
|
|
264e3e9dd6 | ||
|
|
3f25ee3749 | ||
|
|
c24a51b633 | ||
|
|
8925133f40 | ||
|
|
2faab30af9 | ||
|
|
c1b88cee99 | ||
|
|
8736526b35 | ||
|
|
7afc08af47 | ||
|
|
12aaae5fc0 | ||
|
|
e0ec5e75b4 | ||
|
|
7092e278d7 | ||
|
|
82a7d7efbd | ||
|
|
37a906cf37 | ||
|
|
bacfed8983 | ||
|
|
ed1b25cb30 | ||
|
|
bc262db6d7 | ||
|
|
86a2c5e2ed | ||
|
|
e77c97e0d1 | ||
|
|
48f3a7b87e | ||
|
|
e5aaa9d277 | ||
|
|
938401dbc6 | ||
|
|
620bf385d1 | ||
|
|
cc51b8150d | ||
|
|
775b14c537 | ||
|
|
7cfe8ee55c | ||
|
|
058b9c5e51 | ||
|
|
deed6fb984 | ||
|
|
2d04c0dcf8 | ||
|
|
5a0abd713e | ||
|
|
df33da111e | ||
|
|
17a816eff4 | ||
|
|
880e22d164 | ||
|
|
c16d2d4147 | ||
|
|
59af900aaf | ||
|
|
add03cb4ee | ||
|
|
409f56ea37 | ||
|
|
2814d79b56 | ||
|
|
4009b40029 | ||
|
|
260c52adec | ||
|
|
b1f057b67d | ||
|
|
177bc16255 | ||
|
|
4ce4cd1bc1 | ||
|
|
9e8d8aa19e | ||
|
|
4d3ceb387e | ||
|
|
5038b716eb | ||
|
|
e310f9683e | ||
|
|
c29b76143c | ||
|
|
3ad4b05a97 | ||
|
|
0da313eb84 | ||
|
|
6b50ec328c | ||
|
|
1eb6a883f6 | ||
|
|
e7fd408548 | ||
|
|
eaa95293e4 | ||
|
|
8ac663d703 | ||
|
|
902712695c | ||
|
|
5d03be4b09 | ||
|
|
689632b51c | ||
|
|
1b19ae81d5 | ||
|
|
a0d790445d | ||
|
|
213ee5ca45 | ||
|
|
74720d4d2e | ||
|
|
39bd520542 | ||
|
|
496e4e9f56 | ||
|
|
89c1ea4232 | ||
|
|
a2a50586aa | ||
|
|
0284a2092d | ||
|
|
c414f75329 | ||
|
|
943dce566b | ||
|
|
b32498b37c | ||
|
|
ea041a40f9 | ||
|
|
1d66f91a41 | ||
|
|
fee7ba58b0 | ||
|
|
8e53d12776 | ||
|
|
08a9f7c068 | ||
|
|
33793193cc | ||
|
|
285f11ccdc | ||
|
|
d87400afa0 | ||
|
|
fcb41542c3 | ||
|
|
87b4c9d736 | ||
|
|
6386e70584 | ||
|
|
722975d77e | ||
|
|
8943962704 | ||
|
|
ed57ef3d01 | ||
|
|
9e7d41025a | ||
|
|
d2f236d116 | ||
|
|
1ff995fedb | ||
|
|
1b16c6c73f | ||
|
|
ceac9c9095 | ||
|
|
0005dcaacb | ||
|
|
467a82fe46 | ||
|
|
ce40f8f10c | ||
|
|
d2d451b182 | ||
|
|
52fa51853e | ||
|
|
6575b1b573 | ||
|
|
cba81b4dc7 | ||
|
|
91253917b4 | ||
|
|
821358c062 | ||
|
|
3de0a4e2ad | ||
|
|
b8a3067744 | ||
|
|
7509cc1a07 | ||
|
|
dd2548453b | ||
|
|
a93585080c | ||
|
|
5f30c9599a | ||
|
|
4b3edfd370 | ||
|
|
d6ac03552d | ||
|
|
a72632ae85 | ||
|
|
2d18e0d719 | ||
|
|
45a8a7bb31 | ||
|
|
1a9d10d298 | ||
|
|
80a0cab6ab | ||
|
|
96720457d0 | ||
|
|
f4d2839dc7 | ||
|
|
070f1e8dfa | ||
|
|
42a0d686a5 | ||
|
|
79bc2d9c68 | ||
|
|
f3eea6302d | ||
|
|
bcfa0219e2 | ||
|
|
5e1effc69a | ||
|
|
be23c74b17 | ||
|
|
8fe1c206d3 | ||
|
|
a6157a926d | ||
|
|
9837187183 | ||
|
|
c2657cce37 | ||
|
|
7d6109feca | ||
|
|
cf14b222f2 | ||
|
|
238343f389 | ||
|
|
77e90ca725 | ||
|
|
f734c273ca | ||
|
|
e23e5203de | ||
|
|
a2dd189241 | ||
|
|
0ed4e41000 | ||
|
|
352919862f | ||
|
|
aab6567750 | ||
|
|
ea9e24f214 | ||
|
|
40fc4f9392 | ||
|
|
795a7c690d | ||
|
|
2fdbb94c79 | ||
|
|
767d90d5e7 | ||
|
|
bc04790fd5 | ||
|
|
58f7c94e74 | ||
|
|
8af29c200d | ||
|
|
1db6bff890 | ||
|
|
0292cb73d3 | ||
|
|
7b33eafbb0 | ||
|
|
ee60c463c8 | ||
|
|
e1a6b5eb03 | ||
|
|
4ebdd97ad3 | ||
|
|
6f7f979c05 | ||
|
|
ca8e280b4c | ||
|
|
b26e8b0e34 | ||
|
|
df41eb1870 | ||
|
|
90c602f867 | ||
|
|
6b8a679a51 | ||
|
|
8b16a0e1f6 | ||
|
|
ec251b254c | ||
|
|
e0c8163211 | ||
|
|
01f757c940 | ||
|
|
42f4827854 | ||
|
|
f2d3779fa9 | ||
|
|
b70f121e46 | ||
|
|
641765858f | ||
|
|
ba362e2fe0 | ||
|
|
84d5ce0d1e | ||
|
|
419623d158 | ||
|
|
1dd0c599c6 | ||
|
|
c7934ca246 | ||
|
|
27852eafd7 | ||
|
|
d4bde5008d | ||
|
|
74a525a672 | ||
|
|
e9982dc447 | ||
|
|
7028baaf8f | ||
|
|
7837c76c74 | ||
|
|
e5ad70c093 | ||
|
|
7fce688769 | ||
|
|
90c874777c | ||
|
|
70795134af | ||
|
|
8f2e9c6b94 | ||
|
|
ce34ca8f1f | ||
|
|
7c632cf165 | ||
|
|
b3c5a8db80 | ||
|
|
1d2961e047 | ||
|
|
b43f0979d9 | ||
|
|
539a1aee2c | ||
|
|
8e323b9dfa | ||
|
|
53b7d9eec9 | ||
|
|
89d3451767 | ||
|
|
aa98a7e7d6 | ||
|
|
614850ab1d | ||
|
|
140a15f9cb | ||
|
|
ec4a8745e7 | ||
|
|
673329ddb7 | ||
|
|
6a421dd8b0 | ||
|
|
de6c460a51 | ||
|
|
75a94fd0b3 | ||
|
|
7573c64087 | ||
|
|
cbb422f69d | ||
|
|
06f198bc57 | ||
|
|
6586657658 | ||
|
|
a0e598b97e | ||
|
|
8a6ea29c45 | ||
|
|
e1b0ba466b | ||
|
|
f35d6287ab | ||
|
|
53028a9c2a | ||
|
|
33fc2ed10c | ||
|
|
bc02fb3754 | ||
|
|
48b2379fe5 | ||
|
|
7de693eb23 | ||
|
|
7bb9c00356 | ||
|
|
9aacfff35d | ||
|
|
2e728c7051 | ||
|
|
7e973a6da6 | ||
|
|
cb014095ad | ||
|
|
6fe8f64835 | ||
|
|
6111f72b24 | ||
|
|
43041971b7 | ||
|
|
3505cc3ba0 | ||
|
|
05ba5f4358 | ||
|
|
bc616ca7d8 | ||
|
|
99131131af | ||
|
|
44b945a5f3 | ||
|
|
3bff923331 | ||
|
|
a6ccf95076 | ||
|
|
665f319a0e | ||
|
|
fe31afce6b | ||
|
|
ac07d2dfc8 | ||
|
|
71165c6984 | ||
|
|
eab3bff78b | ||
|
|
81dba11ab1 | ||
|
|
388fa5baa9 | ||
|
|
fe3241c07c | ||
|
|
0559ddca2a | ||
|
|
98a046500f | ||
|
|
58cd0d1669 | ||
|
|
6421fe10f8 | ||
|
|
99c85459a7 | ||
|
|
958bf51648 | ||
|
|
e3aa85e2a2 | ||
|
|
29ced36a79 | ||
|
|
f9a5c2d341 | ||
|
|
dde03718e1 | ||
|
|
60d34bea70 | ||
|
|
6fb3b61441 | ||
|
|
11ca168175 | ||
|
|
f02c0eacd8 | ||
|
|
72a566d2f8 | ||
|
|
b56ae28c45 | ||
|
|
cd89d71e0c | ||
|
|
902cd5c3ea | ||
|
|
f9eadc8e6a | ||
|
|
7b8c8fdda7 | ||
|
|
1f3de74cbd | ||
|
|
770ead9c05 | ||
|
|
fe371ff1d1 | ||
|
|
2f783f0aef | ||
|
|
92b85d4ba6 | ||
|
|
e702fe5c68 | ||
|
|
ed92e1b4f4 | ||
|
|
f2b63d1689 | ||
|
|
d51defed06 | ||
|
|
851ea2c45b | ||
|
|
ec97ee5d41 | ||
|
|
78b83ca1e1 | ||
|
|
ea0130d114 | ||
|
|
e66e7c5034 | ||
|
|
ff010678c3 | ||
|
|
5abc72cc8b | ||
|
|
fac8866fb4 | ||
|
|
d58e91303b | ||
|
|
8bd0317e9c | ||
|
|
76b1167842 | ||
|
|
7537686d8f | ||
|
|
6fc340c4db | ||
|
|
38f25af47d | ||
|
|
91df533834 | ||
|
|
9a05ca0667 | ||
|
|
ccf581d86f | ||
|
|
1dc546ac36 | ||
|
|
372b4bca46 | ||
|
|
5c89029462 | ||
|
|
a475a8a899 | ||
|
|
47b5ae7984 | ||
|
|
f5d9a67f36 | ||
|
|
1f90dbec20 | ||
|
|
d713456e29 | ||
|
|
d9d90d1ae8 | ||
|
|
62b61107e0 | ||
|
|
1e0fa56786 | ||
|
|
97d5bf7e97 | ||
|
|
75302ab716 | ||
|
|
742de9e77c | ||
|
|
921046e886 | ||
|
|
781f4afe25 | ||
|
|
10158f62e0 | ||
|
|
42d6749501 | ||
|
|
2fa46e6b6c | ||
|
|
47ec5eb6c6 | ||
|
|
799035c692 | ||
|
|
6c07256dc5 | ||
|
|
20c6a327ea | ||
|
|
bcfdc812f9 | ||
|
|
373b08a91e | ||
|
|
a7154968d8 | ||
|
|
46e432c4d9 | ||
|
|
44a61fa72c | ||
|
|
299df50066 | ||
|
|
335330690f | ||
|
|
f30cee7655 | ||
|
|
b943afb7c7 | ||
|
|
30f3818c66 | ||
|
|
13624568b5 | ||
|
|
e4f64581ec | ||
|
|
d132227860 | ||
|
|
45abb4703d | ||
|
|
a66b93c96f | ||
|
|
e5ea95db8d | ||
|
|
8938331915 | ||
|
|
749767539a | ||
|
|
399b50b4d7 | ||
|
|
82f3731c97 | ||
|
|
658258c8c3 | ||
|
|
d14cce2374 | ||
|
|
f411fb1eb3 | ||
|
|
6a30ccc907 | ||
|
|
1e1426cab0 | ||
|
|
2e750671ca | ||
|
|
147e47c8eb | ||
|
|
7208916230 | ||
|
|
43556f6df0 | ||
|
|
c0c33392f1 | ||
|
|
77ce5a9586 | ||
|
|
8665722367 | ||
|
|
57b52fbe90 | ||
|
|
b052b62b16 | ||
|
|
4df7e94d56 | ||
|
|
fcf2e2db05 | ||
|
|
1c52de9ab1 | ||
|
|
9cd762d88a | ||
|
|
eddcdaabef | ||
|
|
2c76943d35 | ||
|
|
24e3e1794e | ||
|
|
99055b553a | ||
|
|
576f13df60 | ||
|
|
004201abda | ||
|
|
6899c6b63c | ||
|
|
7f5c56a2a8 | ||
|
|
92e07d2be1 | ||
|
|
aff1fdc6aa | ||
|
|
b0b1efcc49 | ||
|
|
eb575b9882 | ||
|
|
e667abb143 | ||
|
|
347ee0211b | ||
|
|
4f4feba6fc | ||
|
|
8cb4dfef62 | ||
|
|
de452bb2c2 | ||
|
|
e8d8b09e52 | ||
|
|
631674db29 | ||
|
|
bc3ae52c7a | ||
|
|
4c795018b4 | ||
|
|
651b7b2f59 | ||
|
|
5cb207d8b3 | ||
|
|
de5de0cfaf | ||
|
|
b8ef367824 | ||
|
|
f1458b772e | ||
|
|
4181c9fab2 | ||
|
|
1fbc7f9842 | ||
|
|
73ed08a412 | ||
|
|
7cac13aefa | ||
|
|
2e114df4c7 | ||
|
|
36ab590c4e | ||
|
|
20da3427c1 | ||
|
|
2811660fa7 | ||
|
|
ef8eb935d4 | ||
|
|
11832b524b | ||
|
|
503e45eae1 | ||
|
|
041ec06dbc | ||
|
|
3841b29db8 | ||
|
|
1c94624958 | ||
|
|
c6f3700de1 | ||
|
|
186bba9d75 | ||
|
|
a3e83d59be | ||
|
|
54166b91eb | ||
|
|
1e5bb2d3da | ||
|
|
8d9a759a7d | ||
|
|
f32b035287 | ||
|
|
a8e6930d19 | ||
|
|
7fa4cb7ee8 | ||
|
|
df5855dbda | ||
|
|
e7f5ba6ca1 | ||
|
|
bcb68fcc3d | ||
|
|
e5ee918063 | ||
|
|
4be320abc8 | ||
|
|
300f5f817f | ||
|
|
574a4d0758 | ||
|
|
a02bd46094 | ||
|
|
cab80d3fa2 | ||
|
|
98d8b00d7a | ||
|
|
40608dc8d4 | ||
|
|
3b7d4a7b36 | ||
|
|
f704fcb41d | ||
|
|
8570f119c0 | ||
|
|
1656d9d7ad | ||
|
|
50c64b8512 | ||
|
|
83b9c6184c | ||
|
|
0ad479498c | ||
|
|
2dd1f6e880 | ||
|
|
da0018efdf | ||
|
|
16f768197b | ||
|
|
d6fe5b5aad | ||
|
|
dfe4fbfdc5 | ||
|
|
9444e62df9 | ||
|
|
dddffb01a6 | ||
|
|
4520bedf8d | ||
|
|
126d7bba57 | ||
|
|
575245c62f | ||
|
|
59264c0aa5 | ||
|
|
ee1bd9e006 | ||
|
|
dfd9e43405 | ||
|
|
8f06ef965a | ||
|
|
ae7cf15c70 | ||
|
|
469d2bd104 | ||
|
|
682b2ada4c | ||
|
|
f4e5426e97 | ||
|
|
6bae789bd6 | ||
|
|
ff19db0084 | ||
|
|
f10d7c05f9 | ||
|
|
f80dff851b | ||
|
|
63cbeb9a3c | ||
|
|
773d3f81fd | ||
|
|
4ab3e23b1f | ||
|
|
d588b18c39 | ||
|
|
97b899f4a3 | ||
|
|
6a913bc4cc | ||
|
|
bf46c4b5c1 | ||
|
|
69a0725c30 | ||
|
|
0c9740fe52 | ||
|
|
43f0b6c28d | ||
|
|
2776beb842 | ||
|
|
d7fa6c0ade | ||
|
|
025412aac0 | ||
|
|
bfa7d3cf41 | ||
|
|
9990780b82 | ||
|
|
dff2e73842 | ||
|
|
e2000859b6 | ||
|
|
3a6aee72a3 | ||
|
|
3fb2e451a2 | ||
|
|
7875b96956 | ||
|
|
d96c9e00b7 | ||
|
|
379c252b89 | ||
|
|
307cb56ef5 | ||
|
|
62e6ca02f9 | ||
|
|
c6fcbe20e1 | ||
|
|
a1b71f0440 | ||
|
|
dc08c26d9f | ||
|
|
669023914a | ||
|
|
e4a677ceea | ||
|
|
8aadc99f1d | ||
|
|
1ea397a807 | ||
|
|
b348f54c33 | ||
|
|
721cf20cf7 | ||
|
|
6ed9a99832 | ||
|
|
1163d14ea1 | ||
|
|
b83631fb20 | ||
|
|
902b08e657 | ||
|
|
b5fdde08aa | ||
|
|
4962c3df11 | ||
|
|
8de3498e07 | ||
|
|
26fdf83a48 | ||
|
|
32af047925 | ||
|
|
282633c877 | ||
|
|
77de570aa4 | ||
|
|
c9df19ca30 | ||
|
|
7c1cd18a06 | ||
|
|
0ca2356be5 | ||
|
|
8329d222cb | ||
|
|
1c3df1cdd7 | ||
|
|
b149805b9e | ||
|
|
99348ec309 | ||
|
|
c6976c0f92 | ||
|
|
cacc7f3193 | ||
|
|
4b9cf0952e | ||
|
|
6d37684e9c | ||
|
|
743412de33 | ||
|
|
11c1ee4481 | ||
|
|
f34703a279 | ||
|
|
5cce8ddd7d | ||
|
|
ff63eacf2c | ||
|
|
8121dce2a4 | ||
|
|
4d910f6bfe | ||
|
|
51c00fce57 | ||
|
|
1ab14ea519 | ||
|
|
c5c7c1913a | ||
|
|
3fc969b38b | ||
|
|
7ed38d6c6c | ||
|
|
fa68fa211c | ||
|
|
69cf2c36bc | ||
|
|
640c637ca8 | ||
|
|
0ad4427f83 | ||
|
|
1bfdea7527 | ||
|
|
6c36d067d7 | ||
|
|
1e60eeef34 | ||
|
|
005570c90a | ||
|
|
c070fbec62 | ||
|
|
f9d44c93fd | ||
|
|
fab5ca9440 | ||
|
|
7b128a9f00 | ||
|
|
fd14869ddc | ||
|
|
07d7d3b13b | ||
|
|
7c10683e46 | ||
|
|
3ffea2d987 | ||
|
|
770665a7b8 | ||
|
|
93ff049e54 | ||
|
|
f3b848537a | ||
|
|
27b971cbfa | ||
|
|
a1ceeb697a | ||
|
|
4a8aa0acbd | ||
|
|
6fa00b5b55 | ||
|
|
c2218faf47 | ||
|
|
21c61b6e3a | ||
|
|
b065e1cd53 | ||
|
|
7d6ce119f5 | ||
|
|
62c23166fa | ||
|
|
25afc11168 | ||
|
|
9e713406d3 | ||
|
|
f33f641f11 | ||
|
|
ca2ddfeed0 | ||
|
|
11cd42379b | ||
|
|
40d3345cd5 | ||
|
|
035e214ef5 | ||
|
|
f630a8cc1a | ||
|
|
0bfb08e464 | ||
|
|
5f6ae3857b | ||
|
|
750544dd2a | ||
|
|
660860bccf | ||
|
|
841aaa78b4 | ||
|
|
93f46a4142 | ||
|
|
a86db1bde8 | ||
|
|
4163437d5a | ||
|
|
a6535c28ea | ||
|
|
2efe95f2fb | ||
|
|
56992570d8 | ||
|
|
39934208c3 | ||
|
|
193bb313fd | ||
|
|
e8334f9b67 | ||
|
|
280ff8b5d0 | ||
|
|
172bb9e96a | ||
|
|
c04f1dea48 | ||
|
|
9114c982e0 | ||
|
|
f644a76281 | ||
|
|
63bb993c02 | ||
|
|
c50291cec8 | ||
|
|
2fe79b5fc3 | ||
|
|
b4fab5a806 | ||
|
|
35d0042be1 | ||
|
|
75dcc3f276 | ||
|
|
9c43974747 | ||
|
|
4be5fc6d43 | ||
|
|
f03336b3a2 | ||
|
|
a5db117ef6 | ||
|
|
142e0c2c3a | ||
|
|
1c8cd85f6c | ||
|
|
c547f67c54 | ||
|
|
c26e9436b4 | ||
|
|
b3239abea1 | ||
|
|
81edd4592f | ||
|
|
7484433e2b | ||
|
|
cb79e83510 | ||
|
|
cac52c0537 | ||
|
|
f5c23fbb16 | ||
|
|
a64a765f32 | ||
|
|
eecfeb2d03 | ||
|
|
54a0313d72 | ||
|
|
7cf6e77f4d | ||
|
|
4968fa0024 | ||
|
|
5e55625733 | ||
|
|
65f64e428e | ||
|
|
d2f5291412 | ||
|
|
9dc1c339ef | ||
|
|
c86304b18e | ||
|
|
7c83a1fb8e | ||
|
|
f02728aab3 | ||
|
|
48283c4dbc | ||
|
|
6bdd7f3a3f | ||
|
|
6e0dd371a0 | ||
|
|
5b1df8c4b3 | ||
|
|
5fa68e253c | ||
|
|
3e14ef634f | ||
|
|
adb5fcf708 | ||
|
|
136463c92e | ||
|
|
ef56193c44 | ||
|
|
4077040d03 | ||
|
|
de440a8c92 | ||
|
|
c75f74f681 | ||
|
|
46c78ad338 | ||
|
|
2b7a8875c0 | ||
|
|
2ee131c52c | ||
|
|
f3901cd8b8 | ||
|
|
7f0536b51d | ||
|
|
af76659830 | ||
|
|
fb658c4918 | ||
|
|
85cc4a80d0 | ||
|
|
6fe85c5779 | ||
|
|
b38a56e7d3 | ||
|
|
cbf18e5c3a | ||
|
|
96bd0d267c | ||
|
|
ec67752db4 | ||
|
|
ad4c17fbb6 | ||
|
|
672979c515 | ||
|
|
efcc2b81cd | ||
|
|
640f29fe0f | ||
|
|
13a0085408 | ||
|
|
74440d503e | ||
|
|
f4769de5c4 | ||
|
|
b843b76b7a | ||
|
|
182afe3b7d | ||
|
|
920e0c6b56 | ||
|
|
b6ce6b7cdb | ||
|
|
a0b5a24853 | ||
|
|
fa11d6bdd4 | ||
|
|
a9aef2bc84 | ||
|
|
bf2b73706a | ||
|
|
83ebce86b6 | ||
|
|
1967518fa2 | ||
|
|
5928d64d7a | ||
|
|
c7ec5a13a5 | ||
|
|
01aeb7515d | ||
|
|
d54c3369b3 | ||
|
|
d24e6100a7 | ||
|
|
cd0e45b70e | ||
|
|
0f0018abe4 | ||
|
|
a95c5e26e6 | ||
|
|
70b6cc8e55 | ||
|
|
13cbff7eab | ||
|
|
86166dbf25 | ||
|
|
b2130c2a48 | ||
|
|
5585e83fd6 | ||
|
|
7b921fc767 | ||
|
|
cfd67c8337 | ||
|
|
dc498d4de8 | ||
|
|
2c67106f26 | ||
|
|
b105c33b79 | ||
|
|
2ccc238119 | ||
|
|
e693b7d33b | ||
|
|
aca0de06cd | ||
|
|
85f4bdbe0b | ||
|
|
1257ba165f | ||
|
|
1c33d2a2ed | ||
|
|
99bd3d3b1a | ||
|
|
d8aed0ac4f | ||
|
|
5ebd4bb2a4 | ||
|
|
c934e06171 | ||
|
|
8a0685a3e9 | ||
|
|
2b018be392 | ||
|
|
4d19c437e0 | ||
|
|
44c274b9e9 | ||
|
|
66f6399b8a | ||
|
|
53a1be78cc | ||
|
|
78b35dc57d | ||
|
|
c65d1204af | ||
|
|
3bfed50d81 | ||
|
|
4523bb5b81 | ||
|
|
75aec69de1 | ||
|
|
9b96735615 | ||
|
|
f74d74fe6e | ||
|
|
77394ba914 | ||
|
|
d13173942d | ||
|
|
afbadd9ea2 | ||
|
|
c25888288a | ||
|
|
4fd059be5f | ||
|
|
bfb3164a0d | ||
|
|
81712f4c82 | ||
|
|
7e97f16f41 | ||
|
|
98086de77e | ||
|
|
24456e9703 | ||
|
|
7f024f3b8d | ||
|
|
67c1b171c7 | ||
|
|
04fbb0c1ce | ||
|
|
327423ab84 | ||
|
|
20cfffdff5 | ||
|
|
d8e126044f | ||
|
|
61f975ea18 | ||
|
|
25d4950216 | ||
|
|
5aa1521819 | ||
|
|
dd030fa18b | ||
|
|
013df58fea | ||
|
|
745ddc2c87 | ||
|
|
f6d3b2f896 | ||
|
|
7da321ab4f | ||
|
|
92fdc7e380 | ||
|
|
2e811de0f5 | ||
|
|
f02cd0ad3c | ||
|
|
a36df33a67 | ||
|
|
4a6bf5fd5f | ||
|
|
26c0b4fc75 | ||
|
|
ce1c8aac4c | ||
|
|
72ceceb7ae | ||
|
|
cf63b588bc | ||
|
|
4e8f7f0a1b | ||
|
|
579816a04f | ||
|
|
cc04872933 | ||
|
|
fad363e64a | ||
|
|
094cf2ac5d | ||
|
|
cc82727d20 | ||
|
|
924750f826 | ||
|
|
ffbf630b5c | ||
|
|
8073a4ba87 | ||
|
|
48a4835819 | ||
|
|
3cf3c0ea99 | ||
|
|
ac61055d43 | ||
|
|
65eb93793c | ||
|
|
ec450fc567 | ||
|
|
2c05ebbded | ||
|
|
0ddda0a864 | ||
|
|
3ff02da314 | ||
|
|
df048a4f42 | ||
|
|
21c36880f1 | ||
|
|
02328d818c | ||
|
|
0f55ba7218 | ||
|
|
1c089a2bbb | ||
|
|
54a887cdc3 | ||
|
|
ca28c76e52 | ||
|
|
a70157003b | ||
|
|
6aa3c7d5d6 | ||
|
|
4ef8c5c47d | ||
|
|
31d17f135a | ||
|
|
03f7b01109 | ||
|
|
c2658dc6da | ||
|
|
30dac8ea41 | ||
|
|
0d28404aad | ||
|
|
2f99bb025c | ||
|
|
bff48e7c7f | ||
|
|
3b67ffa814 | ||
|
|
49b4e4cbcb | ||
|
|
287c308bc3 | ||
|
|
af44d91568 | ||
|
|
40b6890c54 | ||
|
|
7248425a76 | ||
|
|
1dcc1ca524 | ||
|
|
0e17d6acd7 | ||
|
|
c89217903a | ||
|
|
762e6d3ba4 | ||
|
|
e9ae80e250 | ||
|
|
fd7f24e265 | ||
|
|
24450a8827 | ||
|
|
57e8ed65b0 | ||
|
|
3f819e2dfd | ||
|
|
9a7862c322 | ||
|
|
92c77cdff5 | ||
|
|
554e956ef5 | ||
|
|
9fd6e18d59 | ||
|
|
d8a9475460 | ||
|
|
60d9d01a55 | ||
|
|
cb79552dd0 | ||
|
|
f310ff24a5 | ||
|
|
b1963864d2 | ||
|
|
9e85be11fe | ||
|
|
b4e7000eb2 | ||
|
|
0b833bd2f3 | ||
|
|
7c93450aa7 | ||
|
|
e529e7ba21 | ||
|
|
cae32d6a00 | ||
|
|
836f6c1d5b | ||
|
|
1697cd5c7f | ||
|
|
dcd7360b17 | ||
|
|
4fd247f881 | ||
|
|
85bc544fb9 | ||
|
|
14646074be | ||
|
|
1ba040c24d | ||
|
|
56f6772422 | ||
|
|
db43d461b9 | ||
|
|
42a50474da | ||
|
|
cf367024fd | ||
|
|
644559b7f7 | ||
|
|
bb95ed3ad0 | ||
|
|
3947390877 | ||
|
|
e7f1e32ee3 | ||
|
|
5f8cc3c64b | ||
|
|
67d198ac77 | ||
|
|
a154a34f87 | ||
|
|
86c90d77dd | ||
|
|
4e1a4dae6c | ||
|
|
cf345d8174 | ||
|
|
a18da368a1 | ||
|
|
5d3295c40c | ||
|
|
de10ccfdee | ||
|
|
65a8ce8e22 | ||
|
|
5a7da721cd | ||
|
|
b234ef7ea3 | ||
|
|
617c961f88 | ||
|
|
e95355e56e | ||
|
|
ff5e9a793b | ||
|
|
101d0548db | ||
|
|
b6a81c51ab | ||
|
|
ba2cd43144 | ||
|
|
bd720b49f3 | ||
|
|
9590d5200c | ||
|
|
12f890e4a2 | ||
|
|
a9cb826bf3 | ||
|
|
4163cb038d | ||
|
|
b051f39145 | ||
|
|
cfc49243c8 | ||
|
|
29430ec88b | ||
|
|
d520046a4f | ||
|
|
814ce2d672 | ||
|
|
4fd37335f5 | ||
|
|
1791bd8626 | ||
|
|
3f5dbc1680 | ||
|
|
44052cb373 | ||
|
|
8c33da11ce | ||
|
|
ab80c84714 | ||
|
|
c0dd94c8a3 | ||
|
|
f65675836c | ||
|
|
f324c9591d | ||
|
|
3347f830c7 | ||
|
|
568abef5b8 | ||
|
|
703efdb22d | ||
|
|
bb420e9347 | ||
|
|
2f45f0cfed | ||
|
|
112d398175 | ||
|
|
95b31146b5 | ||
|
|
55a1f8d3da | ||
|
|
fba7790637 | ||
|
|
918dfca409 | ||
|
|
d18f128a3c | ||
|
|
c8b9059289 | ||
|
|
b8a6882a27 | ||
|
|
fb8e3071f2 | ||
|
|
067b5998ee | ||
|
|
2e26f37f5e | ||
|
|
6525c1f543 | ||
|
|
4db0b385f3 | ||
|
|
b7f77d1747 | ||
|
|
811ff65209 | ||
|
|
fd70d8975b | ||
|
|
b746a8f9ab | ||
|
|
483e4568a2 | ||
|
|
9ff1b660f1 | ||
|
|
5ffdd2d91a | ||
|
|
5b81bee941 | ||
|
|
3b9b9e75c4 | ||
|
|
faef45fd68 | ||
|
|
b5b45dde9d | ||
|
|
5ab087bc1e | ||
|
|
7683367c0e | ||
|
|
d2db66b9f7 | ||
|
|
c58d8804a1 | ||
|
|
5d09449c95 | ||
|
|
076a75d138 | ||
|
|
7f69ac3f4a | ||
|
|
7f159a7ed2 | ||
|
|
42274ef3ae | ||
|
|
ab893be418 | ||
|
|
f5e7573bd6 | ||
|
|
9cdad087ef | ||
|
|
e36f96fd47 | ||
|
|
cb25a90250 | ||
|
|
38a9d23174 | ||
|
|
521118265a | ||
|
|
a09306c585 | ||
|
|
8140ff9154 | ||
|
|
3cbe78cb9b | ||
|
|
699afb2c00 | ||
|
|
d079a18459 | ||
|
|
b0566e4150 | ||
|
|
c38a26e6cd | ||
|
|
31030738a4 | ||
|
|
caf84a259e | ||
|
|
1620824d3a | ||
|
|
1d2f5053d6 | ||
|
|
42282c6e6e | ||
|
|
a3f8ddd24a | ||
|
|
bfe808a779 | ||
|
|
28065b0565 | ||
|
|
4953cfd10e | ||
|
|
db972de40c | ||
|
|
330e9ba4ef | ||
|
|
bb09de1805 | ||
|
|
a6a0cef9fc | ||
|
|
c36bd4dc07 | ||
|
|
83f352b95e | ||
|
|
c84a5c3282 | ||
|
|
58af615dd4 | ||
|
|
c4b13a2176 | ||
|
|
039fffb339 | ||
|
|
8613513b9c | ||
|
|
ceb276b249 | ||
|
|
16f281e3d1 | ||
|
|
b593fffc7d | ||
|
|
ce890799bc | ||
|
|
aa65287c3b | ||
|
|
a6522d6317 | ||
|
|
0b45d42912 | ||
|
|
d9829a3606 | ||
|
|
59766e2db4 | ||
|
|
e52a4fbfc0 | ||
|
|
c05afb4705 | ||
|
|
9f209dadd9 | ||
|
|
2ec45b7413 | ||
|
|
bf581879e6 | ||
|
|
9bc3757a9e | ||
|
|
18d0a74f23 | ||
|
|
7a188744da | ||
|
|
7f45ac3f7a | ||
|
|
612861e010 | ||
|
|
fcae0d9fcf | ||
|
|
f446939770 | ||
|
|
92853a6a12 | ||
|
|
4ad113a6f8 | ||
|
|
89ed1aa8de | ||
|
|
d7f5675727 | ||
|
|
4d982d22c1 | ||
|
|
5ed1802f0f | ||
|
|
2716381e7b | ||
|
|
c5c83d724a | ||
|
|
749dedf477 | ||
|
|
911c49c43f | ||
|
|
770a682d8b | ||
|
|
73ca37ecca | ||
|
|
e0f49e8f43 | ||
|
|
dae34b6009 | ||
|
|
5850125d97 | ||
|
|
97bd778745 | ||
|
|
43df2e2649 | ||
|
|
c2f2623471 | ||
|
|
8e4465315f | ||
|
|
86beb222ae | ||
|
|
5e124ccf44 | ||
|
|
47d4e6d2f9 | ||
|
|
33f65210ee | ||
|
|
9ea6cb4cab | ||
|
|
0e583d620a | ||
|
|
b205abe949 | ||
|
|
cb59c3003a | ||
|
|
942095baa7 | ||
|
|
097849385e | ||
|
|
c4783062ff | ||
|
|
063cf0c608 | ||
|
|
a66d666bed | ||
|
|
170818759d | ||
|
|
e41d1b319b | ||
|
|
b9c9de5222 | ||
|
|
d565f5901b | ||
|
|
46317c3a39 | ||
|
|
bcc5bff376 | ||
|
|
5244d71570 | ||
|
|
9fac289d9a | ||
|
|
de665c05d8 | ||
|
|
98b0ab3409 | ||
|
|
3c344b176b | ||
|
|
6093c2858d | ||
|
|
e06ab1ca1c | ||
|
|
5154314786 | ||
|
|
fa07306f09 | ||
|
|
07115ce4f5 | ||
|
|
b656700294 | ||
|
|
7bc7f0ad06 | ||
|
|
495df8846a | ||
|
|
05d48cdcc3 | ||
|
|
dc02be4944 | ||
|
|
462097d956 | ||
|
|
0e374c2e96 | ||
|
|
94a1313916 | ||
|
|
b54a4afad6 | ||
|
|
c71b8e05f0 | ||
|
|
021c01dfd0 | ||
|
|
30f222b837 | ||
|
|
f7d9237bb9 | ||
|
|
49addc7b04 | ||
|
|
2f9996f9ac | ||
|
|
c1218fc986 | ||
|
|
57ef706eb0 | ||
|
|
e4b19dc1dd | ||
|
|
4e60cc46a2 | ||
|
|
d8edf7bfff | ||
|
|
e951db662d | ||
|
|
c5a3ec3ba8 | ||
|
|
f12a90351a | ||
|
|
b162c40007 | ||
|
|
402100fd52 | ||
|
|
2a1b8f37ec | ||
|
|
7d2e59ab64 | ||
|
|
f35298a227 | ||
|
|
198e925430 | ||
|
|
8b7281fad0 | ||
|
|
502574dfc3 | ||
|
|
7a0f4e5787 | ||
|
|
f277f660f3 | ||
|
|
9c037d6028 | ||
|
|
396528189d | ||
|
|
4b882c465c | ||
|
|
8937cac47d | ||
|
|
5a3e2899dd | ||
|
|
3a5ed4723b | ||
|
|
dcf4c44173 | ||
|
|
5763a4b9df | ||
|
|
82200a21eb | ||
|
|
fc7d98d748 | ||
|
|
5dce7d9075 | ||
|
|
f08f539768 | ||
|
|
be45672e22 | ||
|
|
94efb9ffe3 | ||
|
|
fd1e902492 | ||
|
|
8d6e3d7d56 | ||
|
|
a197bb6815 | ||
|
|
9de8456c7f | ||
|
|
ebf8091dba | ||
|
|
47ce84b273 | ||
|
|
449e097f4a | ||
|
|
fe27605497 | ||
|
|
8792ee438c | ||
|
|
7279062d3c | ||
|
|
b87fe1e21f | ||
|
|
d6ac125425 | ||
|
|
b79d8732ea | ||
|
|
3df0806017 | ||
|
|
c7759aa737 | ||
|
|
8ab1155fc5 | ||
|
|
adc77985d7 | ||
|
|
d85fc7c9f8 | ||
|
|
41b083c962 | ||
|
|
4ee6a7bfb8 | ||
|
|
6e53d08d40 | ||
|
|
01285f12c3 | ||
|
|
cd586aab8c | ||
|
|
4da646252b | ||
|
|
cc8bb38abc | ||
|
|
04ba9bc11a | ||
|
|
9b35a316c9 | ||
|
|
3a522f3c98 | ||
|
|
4c44859132 | ||
|
|
ecd77f7512 | ||
|
|
56bd596af3 | ||
|
|
21acb9361a | ||
|
|
c3477d8476 | ||
|
|
cba09d4ea1 | ||
|
|
884b0ca10e | ||
|
|
c9ecfb11d9 | ||
|
|
9288dcabe9 | ||
|
|
73df96244d | ||
|
|
7396630627 | ||
|
|
0ac93751d0 | ||
|
|
400ca21213 | ||
|
|
3286e78cd2 | ||
|
|
24eb9ce483 | ||
|
|
3dc6ed79d2 | ||
|
|
f94294dbd9 | ||
|
|
04ba58067a | ||
|
|
92b262d599 | ||
|
|
7ffb40e0ad | ||
|
|
997161c740 | ||
|
|
84c95c59e9 | ||
|
|
669242a8ce | ||
|
|
2a04d5e799 | ||
|
|
9d52d2a653 | ||
|
|
95f6ebc000 | ||
|
|
6e9cd072c5 | ||
|
|
729f2b1cb9 | ||
|
|
1a01438064 | ||
|
|
34ec6d3167 | ||
|
|
c9295323f6 | ||
|
|
92d543b8a8 | ||
|
|
3f445c76be | ||
|
|
a6e416f13d | ||
|
|
601ff567e3 | ||
|
|
56783b8e4b | ||
|
|
326f18ea75 | ||
|
|
491472a8c5 | ||
|
|
359619e035 | ||
|
|
9454d670c7 | ||
|
|
2fcec4fff9 | ||
|
|
2c2a9fe01e | ||
|
|
165a55dac6 | ||
|
|
196e9c1e47 | ||
|
|
17450520ba | ||
|
|
97702f3071 | ||
|
|
e8408ca93f | ||
|
|
e0dcf88b68 | ||
|
|
cc38cf15a4 | ||
|
|
da4c0a359b | ||
|
|
ce56a7303e | ||
|
|
5667ec8699 | ||
|
|
36b3150225 | ||
|
|
28c338416f | ||
|
|
26a8fc1a37 | ||
|
|
f347baafa3 | ||
|
|
95278c221b | ||
|
|
5a28366158 | ||
|
|
ac0cea8a73 | ||
|
|
814b631543 | ||
|
|
0d8c7f8785 | ||
|
|
5bae8fcaf8 | ||
|
|
4110cfcfcb | ||
|
|
2bdba261ea | ||
|
|
58fb851717 | ||
|
|
1118b37c92 | ||
|
|
39606a2277 | ||
|
|
275d306b69 | ||
|
|
e948413c09 | ||
|
|
f8bb3148d0 | ||
|
|
e7cf70936a | ||
|
|
409287e8f8 | ||
|
|
87d6ef16f7 | ||
|
|
3c08eba559 | ||
|
|
d399b68d01 | ||
|
|
2e9ec653a8 | ||
|
|
7ca782b92d | ||
|
|
996496c3f5 | ||
|
|
90cf713186 | ||
|
|
ca4aaf44de | ||
|
|
b04d845ec0 | ||
|
|
a8ea2b0f97 | ||
|
|
a29227d0d4 | ||
|
|
7f8f137aa0 | ||
|
|
cc7e721611 | ||
|
|
058cbcf19a | ||
|
|
22b815dc5c | ||
|
|
c709853aa7 | ||
|
|
d755bb7e12 | ||
|
|
6d99912b7b | ||
|
|
82dd9e0596 | ||
|
|
6ba3d49034 | ||
|
|
64be8e0fba | ||
|
|
43a297b691 | ||
|
|
df266378c4 | ||
|
|
ec55765cb2 | ||
|
|
de2ff8118f | ||
|
|
c30c9dc98f | ||
|
|
1f872c3f0c | ||
|
|
b6204eb6f1 | ||
|
|
af9f0f81d8 | ||
|
|
1c08b56e05 | ||
|
|
6cb8020f62 | ||
|
|
d742d4cde9 | ||
|
|
b7d06540e6 | ||
|
|
909f2e1058 | ||
|
|
26d39c3617 | ||
|
|
371bc3b231 | ||
|
|
bdeabcdd89 | ||
|
|
7f177c3d03 | ||
|
|
4ed36a12e9 | ||
|
|
a7e93db363 | ||
|
|
789715f31a | ||
|
|
7cc900d437 | ||
|
|
ff0f6f4fc2 | ||
|
|
5698e8f21a | ||
|
|
ddcae2c906 | ||
|
|
468d096ccb | ||
|
|
bca79d12c0 | ||
|
|
03eba9594b | ||
|
|
5e0e3e2754 | ||
|
|
04fd835267 | ||
|
|
f072761150 | ||
|
|
46d1e3bee3 | ||
|
|
f8e6e0252d | ||
|
|
f9e3bdb6b0 | ||
|
|
a80aab48cd | ||
|
|
3a4aa2a541 | ||
|
|
84583da5b8 | ||
|
|
f213956ceb | ||
|
|
c5caa9d311 | ||
|
|
0c4d93f01f | ||
|
|
a4e8bfc1ba | ||
|
|
542b9e1976 | ||
|
|
73a1ee59fa | ||
|
|
2771109427 | ||
|
|
cc420bd31a | ||
|
|
2fe1d2ef53 | ||
|
|
bb624cc971 | ||
|
|
aa7b8e52f3 | ||
|
|
07f358c91b | ||
|
|
8ae0a1a4af | ||
|
|
7647ad14b8 | ||
|
|
21e4347b3e | ||
|
|
f2d041ea23 | ||
|
|
56c1c4e43c | ||
|
|
820011412b | ||
|
|
81afa6942f | ||
|
|
6cb8d7596a | ||
|
|
a2d46af5ac | ||
|
|
6d94b8ab75 | ||
|
|
0166c3bf0f | ||
|
|
6a995fb62b | ||
|
|
d804d8a92e | ||
|
|
cf63e8375d | ||
|
|
1eff758751 | ||
|
|
0a8fc70ba9 | ||
|
|
b4b72a3166 | ||
|
|
a5054c0064 | ||
|
|
705f421d53 | ||
|
|
4dc0114c52 | ||
|
|
5f2c77fa74 | ||
|
|
5f703afed1 | ||
|
|
c6aa2068e2 | ||
|
|
209f7a239a | ||
|
|
0d404ad374 | ||
|
|
d5db0c641c | ||
|
|
21d6220f3f | ||
|
|
e0464d5447 | ||
|
|
309e5b320e | ||
|
|
afa9703eb5 | ||
|
|
56e5da6680 | ||
|
|
a8810d73e4 | ||
|
|
4b31c30cab | ||
|
|
df4b56148f | ||
|
|
f22a48f576 | ||
|
|
d660e4244f | ||
|
|
d383e5eb8b | ||
|
|
e1dc114517 | ||
|
|
73780ebf63 | ||
|
|
a19f7a0b9f | ||
|
|
e07473d155 | ||
|
|
d429b263eb | ||
|
|
b2a0d0c1c7 | ||
|
|
8bafd7adb1 | ||
|
|
76d24fe4e3 | ||
|
|
3bdcc3aba9 | ||
|
|
cb25b27963 | ||
|
|
b3df81c143 | ||
|
|
68b3c480c9 | ||
|
|
9fd1bf5574 | ||
|
|
b491a06c6d | ||
|
|
d16312a314 | ||
|
|
d19a8d6b98 | ||
|
|
c90dd80ece | ||
|
|
eb9d865635 | ||
|
|
694c87cb61 | ||
|
|
c41aba6b90 | ||
|
|
28ea672e36 | ||
|
|
9366a48d6d | ||
|
|
c7e1f5d568 | ||
|
|
d91ee5b77c | ||
|
|
fd97b84916 | ||
|
|
23f59970cb | ||
|
|
8781e03863 | ||
|
|
f2940ddfcf | ||
|
|
140149f051 | ||
|
|
9055370326 | ||
|
|
1af62c8d11 | ||
|
|
ec5430826e | ||
|
|
b2cccab768 | ||
|
|
579aa8acd4 | ||
|
|
9c2cb144b5 | ||
|
|
3d04689660 | ||
|
|
a891cc4edf | ||
|
|
706ab2ae5b | ||
|
|
9c1de8e00b | ||
|
|
1109e05e06 | ||
|
|
ce313b8a6b | ||
|
|
7c96b91663 | ||
|
|
87e966e185 | ||
|
|
1e018681de | ||
|
|
5b324680ba | ||
|
|
abca5fc405 | ||
|
|
6a455d2866 | ||
|
|
70da818101 | ||
|
|
5ec837acb4 | ||
|
|
76e33d051c | ||
|
|
7c5318b784 | ||
|
|
47892bf24a | ||
|
|
8a9cd7779c | ||
|
|
d4c0277065 | ||
|
|
069e132c0e | ||
|
|
4e6c138099 | ||
|
|
0ab355eada | ||
|
|
44825826df | ||
|
|
612f09893c | ||
|
|
e9f507b868 | ||
|
|
78278c804f | ||
|
|
b51460a59a | ||
|
|
181be5be3f | ||
|
|
91d4e91f53 | ||
|
|
ad3ae7991b | ||
|
|
c7caf6b7a9 | ||
|
|
4422ffe39f | ||
|
|
1ff52f70aa | ||
|
|
fce45167a5 | ||
|
|
b8f384045c | ||
|
|
ea95a7900c | ||
|
|
edea1273c8 | ||
|
|
ec9c763211 | ||
|
|
5a08117e75 | ||
|
|
0aec980aa8 | ||
|
|
6b05ee5130 | ||
|
|
1ffbf63d20 | ||
|
|
b905d2758d | ||
|
|
311d985145 | ||
|
|
a9a06b5297 | ||
|
|
6b8e620495 | ||
|
|
577f85099d | ||
|
|
607c84a79b | ||
|
|
2eec6499ff | ||
|
|
cd1150c11d | ||
|
|
987bbdecf5 | ||
|
|
a68394b6f2 | ||
|
|
3d6fbabc86 | ||
|
|
1479b5d38c | ||
|
|
336311ecc8 | ||
|
|
e9bb35c895 | ||
|
|
ab4f93dcee | ||
|
|
140a199805 | ||
|
|
232b66cfc3 | ||
|
|
11ba7e47fd | ||
|
|
c36d4a9c9a | ||
|
|
4b5c22864e | ||
|
|
5e1faeb5d2 | ||
|
|
4b7c2ba6c8 | ||
|
|
b9285f8de1 | ||
|
|
084fc84590 | ||
|
|
7a9b71cc03 | ||
|
|
6b49653754 | ||
|
|
d5fa8cc211 | ||
|
|
10a11c293e | ||
|
|
e486862db8 | ||
|
|
1c8aae0839 | ||
|
|
6feb1f8b82 | ||
|
|
bef8eb538c | ||
|
|
4e3b066555 | ||
|
|
4d23542ef3 | ||
|
|
47a6b498e3 | ||
|
|
b6f77f4e6f | ||
|
|
b96cd06129 | ||
|
|
e8eb6765bd | ||
|
|
8df552e952 | ||
|
|
18c52e076f | ||
|
|
1810dabc14 | ||
|
|
609a3a229f | ||
|
|
dff56643f0 | ||
|
|
77f8d52271 | ||
|
|
1e9821ec0c | ||
|
|
66e047083a | ||
|
|
e6438e79d8 | ||
|
|
a5e72679bc | ||
|
|
15cc916333 | ||
|
|
2f3de51e55 | ||
|
|
cea1353fbb | ||
|
|
bfbafd4168 | ||
|
|
27a15a2464 | ||
|
|
c2a87f898e | ||
|
|
aaa75c3ffc | ||
|
|
2dfa108034 | ||
|
|
4895cb7b22 | ||
|
|
2d3eb8483f | ||
|
|
36ef988514 | ||
|
|
d58dd7cc91 | ||
|
|
7e06abebd5 | ||
|
|
8dd7f51ae3 | ||
|
|
6030fae685 | ||
|
|
0f502fff84 | ||
|
|
789f662ec8 | ||
|
|
72536037ca | ||
|
|
e4eefc92f4 | ||
|
|
23c4e935b4 | ||
|
|
68b4951bc9 | ||
|
|
ed89c43e48 | ||
|
|
16137ace0e | ||
|
|
b4ef7556da | ||
|
|
eea83d9474 | ||
|
|
9d5264c5a3 | ||
|
|
66075bf45b | ||
|
|
35b8f69f92 | ||
|
|
2d5fe21b05 | ||
|
|
b448681872 | ||
|
|
05c14d5780 | ||
|
|
bb9de52a53 | ||
|
|
7595ec16e5 | ||
|
|
d8cf0f320d | ||
|
|
d644a3996e | ||
|
|
525050c407 | ||
|
|
468088fd6b | ||
|
|
95c192a988 | ||
|
|
d6287fae06 | ||
|
|
9e98f75495 | ||
|
|
56681af1b6 | ||
|
|
8bf3d4ea71 | ||
|
|
00eab4d415 | ||
|
|
0876d46880 | ||
|
|
ed803d30cd | ||
|
|
b6504bf377 | ||
|
|
85b4f235ef | ||
|
|
064bfa5e0d | ||
|
|
4a6ffb6b9e | ||
|
|
d952b7ace8 | ||
|
|
3b6138eaaa | ||
|
|
f3167f6b5f | ||
|
|
8c99d748e2 | ||
|
|
0ab928063e | ||
|
|
c9a34bde3f | ||
|
|
7f85c682b8 | ||
|
|
181185bad6 | ||
|
|
01a9fd9e25 | ||
|
|
3be00045cf | ||
|
|
86176dce8d | ||
|
|
1fa8a0a969 | ||
|
|
d5fe2e88d1 | ||
|
|
9177dbce7f | ||
|
|
55a896367d | ||
|
|
f2e49c84cc | ||
|
|
afa0bea1b1 | ||
|
|
f7e31fceac | ||
|
|
c490d818fb | ||
|
|
32bdedde6d | ||
|
|
48960f1beb | ||
|
|
cf65cbe2f1 | ||
|
|
45c35eca3e | ||
|
|
bb2a8c9090 | ||
|
|
6798b22b49 | ||
|
|
3acbe2a418 | ||
|
|
c45cdd6ea0 | ||
|
|
f520c38b60 | ||
|
|
046a2175ab | ||
|
|
83def95383 | ||
|
|
012fefa37e | ||
|
|
4878e42e07 | ||
|
|
1a7992e524 | ||
|
|
94d7c6dc5f | ||
|
|
23bfb4da50 | ||
|
|
1f21a5fe62 | ||
|
|
2173a8e3cb | ||
|
|
067e2633af | ||
|
|
d916da9ba8 | ||
|
|
c2fc33afec | ||
|
|
3d4e400ed2 | ||
|
|
75d719d204 | ||
|
|
172e3e9f34 | ||
|
|
8e32bdd8db | ||
|
|
895b02b641 | ||
|
|
d06b5f7ab5 | ||
|
|
e88ec6736c | ||
|
|
922abf21e7 | ||
|
|
c55bfa2c6e | ||
|
|
5463c1d47f | ||
|
|
3513a9c7ba | ||
|
|
45db236ec7 | ||
|
|
5848ff5735 | ||
|
|
64c9ac4071 | ||
|
|
75fc922898 | ||
|
|
59e2c3fd5e | ||
|
|
5bd73741cf | ||
|
|
fcfa3beaa3 | ||
|
|
dfbdaa9dab | ||
|
|
5f1f07e5a1 | ||
|
|
eace0d9b37 | ||
|
|
d83b32a200 | ||
|
|
9cefb33388 | ||
|
|
bd5d6d0686 | ||
|
|
ecebaf8216 | ||
|
|
8762647b55 | ||
|
|
664c0ee77c | ||
|
|
7a9c3d351d | ||
|
|
69e52d1ed8 | ||
|
|
bd594e0c05 | ||
|
|
3bf42860e2 | ||
|
|
0532f51cc2 | ||
|
|
1808597258 | ||
|
|
2744989cf1 | ||
|
|
0d04abb5c7 | ||
|
|
495168e7bb | ||
|
|
475fbf9561 | ||
|
|
c6264cf098 | ||
|
|
bc9123affb | ||
|
|
7fd12972ad | ||
|
|
2d19243b3b | ||
|
|
8ad4f188f2 | ||
|
|
0c19c56909 | ||
|
|
de35baadf3 | ||
|
|
66c209f9e4 | ||
|
|
d7a3ed2d4a | ||
|
|
0c25ffc26e | ||
|
|
9f864574de | ||
|
|
a38f7c8524 | ||
|
|
bf85cd404c | ||
|
|
102adb3544 | ||
|
|
c2b360d03e | ||
|
|
1bec1b7002 | ||
|
|
1b4b4807a5 | ||
|
|
d4d135f2a9 | ||
|
|
96faad1c01 | ||
|
|
d55d5f15ae | ||
|
|
26e4560429 | ||
|
|
775bd3a08b | ||
|
|
d92d8bce89 | ||
|
|
1b91663244 | ||
|
|
8fb673e93e | ||
|
|
d1372d9b3b | ||
|
|
063f0da565 | ||
|
|
c893247107 | ||
|
|
a5adcfff4c | ||
|
|
d3583276b3 | ||
|
|
55d8de1b23 | ||
|
|
5b829636cb | ||
|
|
68ac92a616 | ||
|
|
db20cda27a | ||
|
|
60dd47c696 | ||
|
|
42da543980 | ||
|
|
e4ea547623 | ||
|
|
33a6c81a07 | ||
|
|
9ba503cd6b | ||
|
|
f3f3dccf8e | ||
|
|
2f0718e885 | ||
|
|
7b8001d060 | ||
|
|
3c022e4332 | ||
|
|
37e34c5209 | ||
|
|
4b71607215 | ||
|
|
e62875ac90 | ||
|
|
835345b89e | ||
|
|
4ddacc707d | ||
|
|
0d653a2ce6 | ||
|
|
3208260ef8 | ||
|
|
2e57789d10 | ||
|
|
b3006f6fd8 | ||
|
|
142ddcd57a | ||
|
|
a562793fce | ||
|
|
e6c4ecfc10 | ||
|
|
5ff579f793 | ||
|
|
8df346f377 | ||
|
|
af76068297 | ||
|
|
5dddf0a460 | ||
|
|
1854338ff4 | ||
|
|
11b96875e0 | ||
|
|
6462c524f4 | ||
|
|
b703303dd4 | ||
|
|
ab77b6b28e | ||
|
|
0da9d1c036 | ||
|
|
88436b8627 | ||
|
|
f6116510a1 | ||
|
|
5a132aaff4 | ||
|
|
59992c8af2 | ||
|
|
ff3ec78df9 | ||
|
|
b980ae1e8c | ||
|
|
97b9d488d4 | ||
|
|
3ebf8d5db9 | ||
|
|
89e33903b2 | ||
|
|
6a610ac57d | ||
|
|
413f797155 | ||
|
|
6c8dc49216 | ||
|
|
9ded1447ec | ||
|
|
516ed1fd5b | ||
|
|
1a4f8f992b | ||
|
|
23adfef281 | ||
|
|
20b6816562 | ||
|
|
c6400550e1 | ||
|
|
f26749ad79 | ||
|
|
177c98fa95 | ||
|
|
7baa187863 | ||
|
|
11d504e8f4 | ||
|
|
83378e4373 | ||
|
|
06abe2302b | ||
|
|
f3e5f7879d | ||
|
|
bc5125b719 | ||
|
|
c6d23f9a0b | ||
|
|
3b8afce7c7 | ||
|
|
39e28f1f2a | ||
|
|
08363b1d73 | ||
|
|
91aa0f200e | ||
|
|
d9e190096c | ||
|
|
4dca86d5cf | ||
|
|
d3b628bb24 | ||
|
|
cfbb05fb1b | ||
|
|
340d428c88 | ||
|
|
d22bbc54c7 | ||
|
|
c5cda99f9d | ||
|
|
67854e0720 | ||
|
|
cfe257495a | ||
|
|
5f4e701461 | ||
|
|
e3622e0860 | ||
|
|
f0e6b8ca47 | ||
|
|
ef0b239e70 | ||
|
|
590d80268e | ||
|
|
a5de329712 | ||
|
|
2889a4438b | ||
|
|
f5952088e3 | ||
|
|
bcacb49c05 | ||
|
|
976b8e426d | ||
|
|
90ecd34cfd | ||
|
|
35670c8654 | ||
|
|
07bc97fb31 | ||
|
|
d01806ee2d | ||
|
|
a54e42961c | ||
|
|
2e46aa33c0 | ||
|
|
d90cf6384c | ||
|
|
af3f676683 | ||
|
|
abf980d603 | ||
|
|
693b6d2547 | ||
|
|
06313cac64 | ||
|
|
cf1e315d72 | ||
|
|
955e1799c8 | ||
|
|
3db86f1e25 | ||
|
|
6f9b6a29c4 | ||
|
|
b056d40eba | ||
|
|
708c3bc3ce | ||
|
|
39efc12dc8 | ||
|
|
4211151fe6 | ||
|
|
3974b6e6cd | ||
|
|
b24df6e195 | ||
|
|
bcd33dc8e3 | ||
|
|
6c66c236fb | ||
|
|
520121b2b2 | ||
|
|
48c1d05151 | ||
|
|
8ba61a1da1 | ||
|
|
cd129e32a7 | ||
|
|
2b3e43f160 | ||
|
|
d7bf04d2c0 | ||
|
|
4cde8cd501 | ||
|
|
fb4e627e62 | ||
|
|
ef3a97cedd | ||
|
|
1a86ad5cec | ||
|
|
529c401eee | ||
|
|
a87236fea2 | ||
|
|
975c1ca62c | ||
|
|
d02b9d848c | ||
|
|
f340f9ac94 | ||
|
|
1b3f290037 | ||
|
|
b551ef315f | ||
|
|
10bb6ab3bb | ||
|
|
4af57b0dd3 | ||
|
|
bc613eeff9 | ||
|
|
7507e88406 | ||
|
|
073f281f1e | ||
|
|
3355b49724 | ||
|
|
0e2db4a23e | ||
|
|
addc817cca | ||
|
|
a0a86d0f62 | ||
|
|
b24e7cce38 | ||
|
|
ffd1b7069f | ||
|
|
0404c3bd94 | ||
|
|
d0b74a95f4 | ||
|
|
0288d5dc19 | ||
|
|
9d06229cba | ||
|
|
c60ada8421 | ||
|
|
74a1d5cf38 | ||
|
|
43532e5322 | ||
|
|
68cd1d6631 | ||
|
|
afc18cc390 | ||
|
|
57d15936cb | ||
|
|
14406dbf76 | ||
|
|
12c561cee0 | ||
|
|
f79b8a1ca5 | ||
|
|
637daa5bda | ||
|
|
2eae6b4be7 | ||
|
|
dc5e935ecd | ||
|
|
538085169a | ||
|
|
7e8a635e7e | ||
|
|
74e76b6f97 | ||
|
|
cb6309d370 | ||
|
|
8065889862 | ||
|
|
e7a8950d09 | ||
|
|
88e9dc2177 | ||
|
|
2c555c969e | ||
|
|
77c04c3a14 | ||
|
|
48cea6efdf | ||
|
|
89a90d9522 | ||
|
|
0026f3fdef | ||
|
|
ee054fd99c | ||
|
|
7abdade7c1 | ||
|
|
79a50de697 | ||
|
|
e47aef5615 | ||
|
|
b96ae1bac0 | ||
|
|
7dafcb0860 | ||
|
|
5a6a686f42 | ||
|
|
b576bb55ef | ||
|
|
fc8205d375 | ||
|
|
7eb0669de5 | ||
|
|
86161ccf2a | ||
|
|
5e55732cb0 | ||
|
|
a87f0481b8 | ||
|
|
c3d61361f8 | ||
|
|
a48934e31c | ||
|
|
ac75f67e2a | ||
|
|
45cfa6c8d8 | ||
|
|
25a06b0bea | ||
|
|
91af72e8b1 | ||
|
|
fd9b354c70 | ||
|
|
1647e67dd4 | ||
|
|
803e120a51 | ||
|
|
6ba374c62b | ||
|
|
ca28f24e42 | ||
|
|
0d4c38138a | ||
|
|
fe291e90f0 | ||
|
|
220e1e8d83 | ||
|
|
2c0fb3adb0 | ||
|
|
b851eefb03 | ||
|
|
eaad2d8b1f | ||
|
|
575d235296 | ||
|
|
faf74519dc | ||
|
|
66becaf91c | ||
|
|
6610ba67c4 | ||
|
|
e05dd5ebb5 | ||
|
|
cf77f29988 | ||
|
|
2be8ed886b | ||
|
|
21e5b0ab52 | ||
|
|
d72cb74ffa | ||
|
|
3c988d555f | ||
|
|
5981a65cc2 | ||
|
|
9900762747 | ||
|
|
0db2ca6659 | ||
|
|
8e68626f14 | ||
|
|
72a88d1f91 | ||
|
|
bd75e9c184 | ||
|
|
23df16ecf9 | ||
|
|
387732d2f9 | ||
|
|
75b01d5021 | ||
|
|
b7fa5db570 | ||
|
|
297f126f66 | ||
|
|
bd6400f17f | ||
|
|
21e55023a4 | ||
|
|
49e024bdd8 | ||
|
|
57877107d8 | ||
|
|
e9b4a99c8f | ||
|
|
7bc4876071 | ||
|
|
e7899ee15e | ||
|
|
7ea20d9ce9 | ||
|
|
3045f327d5 | ||
|
|
2d1f182c49 | ||
|
|
0677f51717 | ||
|
|
a9bfeb0e96 | ||
|
|
c44d27fb7f | ||
|
|
a0a01b8ba7 | ||
|
|
e32215e19a | ||
|
|
893fb0e3cc | ||
|
|
1d2a838717 | ||
|
|
8457a19792 | ||
|
|
0b2638b201 | ||
|
|
4dce57a1b6 | ||
|
|
658b835a70 | ||
|
|
52af955463 | ||
|
|
09e886db0b | ||
|
|
f668640e3d | ||
|
|
afcd44deaa | ||
|
|
8c8c21c63b | ||
|
|
55dabbe16a | ||
|
|
494bd7b79c | ||
|
|
320ee072e6 | ||
|
|
67ef5fe8e6 | ||
|
|
7c5c700bb8 | ||
|
|
dd51908439 | ||
|
|
6a0f638d40 | ||
|
|
2480c6633c | ||
|
|
495025dafb | ||
|
|
ca62e54652 | ||
|
|
44dd9ae9fb | ||
|
|
3f4d62952a | ||
|
|
391cda919f | ||
|
|
44fc61ed86 | ||
|
|
f70685d53c | ||
|
|
807abfef4f | ||
|
|
810d4c51f9 | ||
|
|
1a0684cd20 | ||
|
|
47d811c250 | ||
|
|
4d0998ef72 | ||
|
|
5d2b0377d8 | ||
|
|
f6d69b6051 | ||
|
|
490496f381 | ||
|
|
bc4f719931 | ||
|
|
ded4a75b9c | ||
|
|
9e75eb35a0 | ||
|
|
326fb99849 | ||
|
|
fe1ced9f58 | ||
|
|
00d0502cbd | ||
|
|
c30bd51b91 | ||
|
|
9391dd9d51 | ||
|
|
3cd112b60f | ||
|
|
dce0c43e26 | ||
|
|
80e228f236 | ||
|
|
8ee2545b05 | ||
|
|
9bcc56e337 | ||
|
|
3c5a94452a | ||
|
|
fce7f8aa68 | ||
|
|
9e13f18463 | ||
|
|
2905f6b465 | ||
|
|
9d3f3eb013 | ||
|
|
75b5afa759 | ||
|
|
78c2f19e72 | ||
|
|
9a66a626f7 | ||
|
|
f42b7f4efa | ||
|
|
bf9654e138 | ||
|
|
4decd1d784 | ||
|
|
3e7cd24814 | ||
|
|
3e0bece53a | ||
|
|
c1b89b3b06 | ||
|
|
f5eadb2957 | ||
|
|
ee393c66dd | ||
|
|
72a7765b58 | ||
|
|
176daeec03 | ||
|
|
066f740819 | ||
|
|
04121644a3 | ||
|
|
1e37a0d9e6 | ||
|
|
fc8d33a98a | ||
|
|
2089727c7f | ||
|
|
fbbf705d10 | ||
|
|
e08c302756 | ||
|
|
87ef3519d9 | ||
|
|
9002c33046 | ||
|
|
b9ad6f4fd2 | ||
|
|
57db17853e | ||
|
|
58555d598b | ||
|
|
0eeae24049 | ||
|
|
3def7c66ad | ||
|
|
eeac3bc436 | ||
|
|
bdebc7f32e | ||
|
|
e7d6811948 | ||
|
|
0e263dd753 | ||
|
|
56bbcb1cb3 | ||
|
|
f02648022a | ||
|
|
9bb1f4e6f8 | ||
|
|
d219f0bdc6 | ||
|
|
c8d0f6ff20 | ||
|
|
2813c75292 | ||
|
|
581e055359 | ||
|
|
88a2cfc5e1 | ||
|
|
fb29830521 | ||
|
|
6540fea4da | ||
|
|
4fd33b015e | ||
|
|
d2fcdb3b6c | ||
|
|
c2fe0876c2 | ||
|
|
39aebd7144 | ||
|
|
6a7d0b8c0a | ||
|
|
7b92bee596 | ||
|
|
f7eda362c7 | ||
|
|
0fb8459bc1 | ||
|
|
42d9b57733 | ||
|
|
ebe143d9c9 | ||
|
|
8acbdfbf1d | ||
|
|
6eb36226b1 | ||
|
|
21984f0bbe | ||
|
|
5eac945bc0 | ||
|
|
2736b4198a | ||
|
|
a4f2f7faa6 | ||
|
|
94923175a8 | ||
|
|
f1c629e7bf | ||
|
|
5d0c60bd24 | ||
|
|
59f08cd651 | ||
|
|
63db194140 | ||
|
|
38db8d4e1a | ||
|
|
c2e8cbb846 | ||
|
|
3c567b895f | ||
|
|
673c75fb72 | ||
|
|
7a576ee36e | ||
|
|
73c09e3365 | ||
|
|
07dd2b279e | ||
|
|
c7943d2521 | ||
|
|
9b483d381f | ||
|
|
4e25337779 | ||
|
|
1e5041b8b0 | ||
|
|
3f4bbe9b9e | ||
|
|
56eaf883dc | ||
|
|
d8c0af7ded | ||
|
|
8724a6b6e2 | ||
|
|
b968b2c438 | ||
|
|
533d1ea9ab | ||
|
|
c9e32c449a | ||
|
|
d9e42bfcba | ||
|
|
f552564fc1 | ||
|
|
b21a096516 | ||
|
|
d0b25de554 | ||
|
|
bba836dc31 | ||
|
|
14fc8e2efa | ||
|
|
d8bd4fbea6 | ||
|
|
7cc89da879 | ||
|
|
baed12f45e | ||
|
|
dfbf291725 | ||
|
|
cb07074246 | ||
|
|
0198fe90b6 | ||
|
|
061221b073 | ||
|
|
7e4cfede7d | ||
|
|
48225c3c0a | ||
|
|
02b89362b2 | ||
|
|
e0e812f95c | ||
|
|
2cbc7e4f9a | ||
|
|
7bec37bfd8 | ||
|
|
828550687c | ||
|
|
d3caba4073 | ||
|
|
7e802706fe | ||
|
|
c87e3eac08 | ||
|
|
5b1b12ec9e | ||
|
|
c0c6f13d44 | ||
|
|
20f192daa1 | ||
|
|
0e73b53803 | ||
|
|
e2923c378e | ||
|
|
216d4da85a | ||
|
|
407e775282 | ||
|
|
e71afa63b0 | ||
|
|
30fd99679a | ||
|
|
a9ef15cdfa | ||
|
|
b08442b46f | ||
|
|
f56e2fc48e | ||
|
|
5452b55e38 | ||
|
|
bec8d36961 | ||
|
|
8188e3d0cf | ||
|
|
10e92eec32 | ||
|
|
37f2336eee | ||
|
|
290cb1b517 | ||
|
|
7520fe7000 | ||
|
|
9f861dfe89 | ||
|
|
fffb87d013 | ||
|
|
0cb731c584 | ||
|
|
233faea200 | ||
|
|
1b9015a049 | ||
|
|
111de1462c | ||
|
|
7fb0b4a8df | ||
|
|
627c49c5db | ||
|
|
665b1ad58a | ||
|
|
4623e9d7fc | ||
|
|
a3f0290432 | ||
|
|
69b1798af7 | ||
|
|
10af206024 | ||
|
|
6c23d7aec8 | ||
|
|
7937ccee30 | ||
|
|
b98e8c34eb | ||
|
|
5c2059b4e8 | ||
|
|
f4be0cf4b3 | ||
|
|
5f7abda22d | ||
|
|
51424aed32 | ||
|
|
914fb09ed0 | ||
|
|
7ea7e5c951 | ||
|
|
c69807b416 | ||
|
|
08320119f1 | ||
|
|
49dcd9bb4a | ||
|
|
8f41603101 | ||
|
|
d437609365 | ||
|
|
e1c681fffe | ||
|
|
d4d47182b4 | ||
|
|
bc2d0191ff | ||
|
|
bd222ed2bf | ||
|
|
ceac824e2b | ||
|
|
93b835ae0d | ||
|
|
aa2d57cf37 | ||
|
|
f6d4821a68 | ||
|
|
fa025bcf39 | ||
|
|
842176a595 | ||
|
|
0fb74b56b3 | ||
|
|
87abcd6a52 | ||
|
|
0a71e40030 | ||
|
|
1b9db035ba | ||
|
|
34c3035c2b | ||
|
|
d92951ba5b | ||
|
|
c5749cbbb1 | ||
|
|
a2e5bcc137 | ||
|
|
761d707b69 | ||
|
|
d327a05e12 | ||
|
|
6477d21e24 | ||
|
|
d3612e956e | ||
|
|
5a3ee3a46e | ||
|
|
23cb743ce2 | ||
|
|
40e5a2dc35 | ||
|
|
73eb4079ef | ||
|
|
5b60c8aa7e | ||
|
|
8c5a688566 | ||
|
|
7ea9706c94 | ||
|
|
5976e2d873 | ||
|
|
d32d452583 | ||
|
|
b77bdabca6 | ||
|
|
e8971e0d8b | ||
|
|
498c4660d0 | ||
|
|
54c142fc0d | ||
|
|
6079402dc4 | ||
|
|
3d4a7f97e1 | ||
|
|
d6e04beb95 | ||
|
|
9a225e6244 | ||
|
|
a03f00628b | ||
|
|
360485d830 | ||
|
|
3f1cfd2995 | ||
|
|
08e2b601f1 | ||
|
|
101ed9a633 | ||
|
|
81ecd17b93 | ||
|
|
5a78f02dcb | ||
|
|
0a08464d4f | ||
|
|
a638d42d92 | ||
|
|
90256ea2f5 | ||
|
|
90aefd35f0 | ||
|
|
2f428b7261 | ||
|
|
f935060b2b | ||
|
|
a367812348 | ||
|
|
8e6a89b279 | ||
|
|
0747697d10 | ||
|
|
8c7494885f | ||
|
|
590a0b8077 | ||
|
|
064d261357 | ||
|
|
adb96710bf | ||
|
|
dd64268bc7 | ||
|
|
aecbd0eda3 | ||
|
|
2c1b7e3b14 | ||
|
|
3eb6357892 | ||
|
|
e0c98a5c79 | ||
|
|
dfb60ec2ed | ||
|
|
b85e260b92 | ||
|
|
4d72845c58 | ||
|
|
9067f76bd6 | ||
|
|
6c447da730 | ||
|
|
1a9f6f06df | ||
|
|
5f8bdc564b | ||
|
|
f6498f2a7b | ||
|
|
0ef5f7f9b1 | ||
|
|
a323a4dd8e | ||
|
|
d5581ffd05 | ||
|
|
77968ab33a | ||
|
|
265a5955d7 | ||
|
|
465ab2fa34 | ||
|
|
d60bfef924 | ||
|
|
5225587ff5 | ||
|
|
fec790e108 | ||
|
|
eb5ea28bcd | ||
|
|
a9fe2ab5c4 | ||
|
|
f2db0886dd | ||
|
|
f6926a9642 | ||
|
|
d3442bb08f | ||
|
|
a08f5c3016 | ||
|
|
eff892ccb8 | ||
|
|
b565eaaf5a | ||
|
|
3831a371a4 | ||
|
|
77ec8ebfc3 | ||
|
|
c272e4d1e8 | ||
|
|
d69b7f41f2 | ||
|
|
c8a47d839a | ||
|
|
b3db8913c6 | ||
|
|
e8f8f34a76 | ||
|
|
5bec2c87cb | ||
|
|
d4d283480f | ||
|
|
71a524662d | ||
|
|
172aef7e26 | ||
|
|
395b5faa2d | ||
|
|
f4a765c5ed | ||
|
|
f5ad845d57 | ||
|
|
2a70ca375c | ||
|
|
396c589743 | ||
|
|
7670b81633 | ||
|
|
f9b98f97b6 | ||
|
|
00bf39204d | ||
|
|
e9ba3ad223 | ||
|
|
6b6666be47 | ||
|
|
e2a413df78 | ||
|
|
b24f68eee7 | ||
|
|
72c1a0222c | ||
|
|
bd97083268 | ||
|
|
e7cf5d4f3d | ||
|
|
2429971bcd | ||
|
|
170a71bd02 | ||
|
|
14efbb1356 | ||
|
|
20cd0dd77a | ||
|
|
2db1fac1eb | ||
|
|
ce8490ed41 | ||
|
|
7e208984de | ||
|
|
4d29a3ae3c | ||
|
|
547c63b28e | ||
|
|
9004aae597 | ||
|
|
1bdfc5a1a4 | ||
|
|
195273f01d | ||
|
|
605aea2211 | ||
|
|
d1afcb941f | ||
|
|
cc7e21170f | ||
|
|
30602c0849 | ||
|
|
1dabe95899 | ||
|
|
4995c0ed94 | ||
|
|
df82dbe5f5 | ||
|
|
de9c74e1d9 | ||
|
|
d89eb9ff0e | ||
|
|
5041042925 | ||
|
|
0d983e63a1 | ||
|
|
3f7a60d84b | ||
|
|
1eb9fcf521 | ||
|
|
1571690bbb | ||
|
|
eb2133e648 | ||
|
|
9107b3ddbe | ||
|
|
64433bd8dd | ||
|
|
bc6159c538 | ||
|
|
8e5954f36f | ||
|
|
b53ef148a0 | ||
|
|
3f950490f9 | ||
|
|
49b1c1368e | ||
|
|
bdb5df104a | ||
|
|
700778e574 | ||
|
|
a104b35cea | ||
|
|
bbbf95705b | ||
|
|
927871d73d | ||
|
|
62419e975f | ||
|
|
3fc2c4223b | ||
|
|
84da884211 | ||
|
|
1bc8e9aebf | ||
|
|
a228e46a39 | ||
|
|
81913a5987 | ||
|
|
2d7f31a60d | ||
|
|
804858d736 | ||
|
|
222be9cf6c | ||
|
|
75a52f032b | ||
|
|
a9e0a51059 | ||
|
|
164b993064 | ||
|
|
62b103fa23 | ||
|
|
e17eb01f76 | ||
|
|
2fe55e4715 | ||
|
|
a8a82e45a0 | ||
|
|
fcba140ffe | ||
|
|
b96ff781bc | ||
|
|
94392f248c | ||
|
|
24e6c31c44 | ||
|
|
cab0e4395a | ||
|
|
ae66e299e6 | ||
|
|
88ad2ee103 | ||
|
|
48f3f4ca37 | ||
|
|
f3ab17a3c0 | ||
|
|
5749d43fb6 | ||
|
|
f5d808e68f | ||
|
|
88f1160e2b | ||
|
|
b7218d2279 | ||
|
|
e928a0aaea | ||
|
|
a2447ecaa3 | ||
|
|
09a089d5f1 | ||
|
|
137b0cd837 | ||
|
|
4ffdd9eb15 | ||
|
|
4e29099ed9 | ||
|
|
8900df6f13 | ||
|
|
814c034683 | ||
|
|
e1ec4bee75 | ||
|
|
6ed7767512 | ||
|
|
08b18af8a0 | ||
|
|
75908ab88f | ||
|
|
fcba33997f | ||
|
|
134be307d3 | ||
|
|
092f8e6482 | ||
|
|
cf5960afad | ||
|
|
e5204e55d3 | ||
|
|
61b14d1cd9 | ||
|
|
c2e3b47d29 | ||
|
|
a239007db0 | ||
|
|
c5e5eb8b86 | ||
|
|
a4d15bfb88 | ||
|
|
b33158b92e | ||
|
|
3b30c4d487 | ||
|
|
dfd7ac633a | ||
|
|
213f8a604e | ||
|
|
13499352fd | ||
|
|
70aa4934c5 | ||
|
|
1d538ee70c | ||
|
|
2ed2e6d62f | ||
|
|
aea0570d2b | ||
|
|
def33a77da | ||
|
|
29db677a9e | ||
|
|
d362ca3a6d | ||
|
|
3796792421 | ||
|
|
b8020db029 | ||
|
|
a90030ca2d | ||
|
|
3f8d3afe5c | ||
|
|
155004bdbb | ||
|
|
534c74b67c | ||
|
|
5428935ab1 | ||
|
|
fc14d089b1 | ||
|
|
4e543238e1 | ||
|
|
6579a542b8 | ||
|
|
27e3dcea6c | ||
|
|
01f73b11d8 | ||
|
|
dd07226ab4 | ||
|
|
67d856e4b7 | ||
|
|
6ad1e57123 | ||
|
|
27a52ef56a | ||
|
|
d290596c1d | ||
|
|
342b4a3b52 | ||
|
|
19652e6367 | ||
|
|
1c76c869ef | ||
|
|
706d842102 | ||
|
|
2889631b61 | ||
|
|
5b9f0f45a9 | ||
|
|
ecc059bf8b | ||
|
|
e1f4a50e65 | ||
|
|
ec2c5a9b2c | ||
|
|
4efbc20a4f | ||
|
|
657e4f12bb | ||
|
|
22ffb1f53f | ||
|
|
4854da4805 | ||
|
|
33a0df20c3 | ||
|
|
e4d1e4b7a0 | ||
|
|
dbc193ab2a | ||
|
|
7bde174b40 | ||
|
|
cf8014582b | ||
|
|
e2796dd351 | ||
|
|
0696a18e0b | ||
|
|
0cc9388af0 | ||
|
|
a73529969a | ||
|
|
c55de17ca8 | ||
|
|
41a751e7f5 | ||
|
|
b9a53e441e | ||
|
|
add62c2093 | ||
|
|
de01ac233c | ||
|
|
c9e926f451 | ||
|
|
8d405849be | ||
|
|
5fbdb1af9f | ||
|
|
83350f8866 | ||
|
|
b4ccd889af | ||
|
|
35a3f2dc91 | ||
|
|
ed7a4514de | ||
|
|
2e295e354a | ||
|
|
d71d9cc8ef | ||
|
|
108b62d839 | ||
|
|
46dfaa5b28 | ||
|
|
323e9c3eb3 | ||
|
|
d677d3d2ef | ||
|
|
c39b239d78 | ||
|
|
5f3ab823fd | ||
|
|
03d1da4bf2 | ||
|
|
78656d220b | ||
|
|
7e7aa7992a | ||
|
|
a53b4df8b6 | ||
|
|
3ba2b8ade6 | ||
|
|
79cb4cd6a5 | ||
|
|
d3ab4b5def | ||
|
|
cdeb07520f | ||
|
|
cc77ef680d | ||
|
|
e75ebd9b6e | ||
|
|
62c9b8390b | ||
|
|
0724c044d6 | ||
|
|
bed4afe74f | ||
|
|
d4263cc8b9 | ||
|
|
b4b11465a1 | ||
|
|
daaebc59cb | ||
|
|
79a74038ac | ||
|
|
314baabf1d | ||
|
|
a24fbb8f61 | ||
|
|
32eaab0783 | ||
|
|
e185b626bd | ||
|
|
74dc94f6bc | ||
|
|
099d9aaca6 | ||
|
|
5fa3b9f2fb | ||
|
|
ad8e2ad4f6 | ||
|
|
8203eff47b | ||
|
|
ad333047d9 | ||
|
|
6e5d2d6a36 | ||
|
|
4b610b6293 | ||
|
|
2bd998e82f | ||
|
|
c55cc3c472 | ||
|
|
674483a4c6 | ||
|
|
a16f84560d | ||
|
|
1b4500339e | ||
|
|
3143468751 | ||
|
|
f627b32355 | ||
|
|
10ba6fb773 | ||
|
|
2d3f1e51ec | ||
|
|
1c23336cff | ||
|
|
a622ffddfe | ||
|
|
79cf0c63c4 | ||
|
|
d57a592273 | ||
|
|
4f15802fbc | ||
|
|
357ae7a8aa | ||
|
|
ac00ae4daf | ||
|
|
249f034a38 | ||
|
|
32c612b747 | ||
|
|
386f7cf65d | ||
|
|
8dc07882b6 | ||
|
|
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 | ||
|
|
eb1980d286 | ||
|
|
424af312e5 | ||
|
|
a2a4c78c9a | ||
|
|
0457b38e41 | ||
|
|
617f803355 | ||
|
|
d3da2683cb | ||
|
|
d97c670fcd | ||
|
|
8902bcb5ab | ||
|
|
5f51e264f2 | ||
|
|
1c4e2c0ed6 | ||
|
|
5a6333129b | ||
|
|
969bd8f82c | ||
|
|
a732bc9dc4 | ||
|
|
1b5cf493d6 | ||
|
|
0be8abd38c | ||
|
|
b71e8082d2 | ||
|
|
034af296ff | ||
|
|
554b08a7d2 | ||
|
|
00b38549f5 | ||
|
|
62b41ddb93 | ||
|
|
d83c5cf5f1 | ||
|
|
740bd528c4 | ||
|
|
668c9489c9 | ||
|
|
dcf2eadcf2 | ||
|
|
9c1064c1a3 | ||
|
|
40bf5bc75f | ||
|
|
6be2d8ccf2 | ||
|
|
9958ad6f34 | ||
|
|
728be8c259 | ||
|
|
9a80d398e8 | ||
|
|
242c47bb92 | ||
|
|
85e37a9977 | ||
|
|
dded56af78 | ||
|
|
3bf1cbbe6c | ||
|
|
4ef8ab6e76 | ||
|
|
837ae4cb17 | ||
|
|
a4e352ba0d | ||
|
|
02d8b1441d | ||
|
|
196784bd09 | ||
|
|
b0fa45cd33 | ||
|
|
923c9d4ad8 | ||
|
|
2be7070e1a | ||
|
|
f16c2a6e99 | ||
|
|
d6e75110a5 | ||
|
|
3d2c4f0801 | ||
|
|
5ccd334555 | ||
|
|
90e1c990e5 | ||
|
|
018b076835 | ||
|
|
9ae029b04d | ||
|
|
43b39538ff | ||
|
|
738ea59e23 | ||
|
|
33c60d3434 | ||
|
|
607673ddcb | ||
|
|
fc8e55c582 | ||
|
|
943e5eeb35 | ||
|
|
52488b875a | ||
|
|
c362cc6d34 | ||
|
|
406d3520f1 | ||
|
|
9b71866b54 | ||
|
|
e48f87fcf0 | ||
|
|
77e83a390c | ||
|
|
27b659c401 | ||
|
|
a4cacaeab2 | ||
|
|
0eb20a5d8e | ||
|
|
3e49db1a29 | ||
|
|
2d719ab6b7 | ||
|
|
34745f6242 | ||
|
|
9c9c484ee4 | ||
|
|
335202b9d9 | ||
|
|
f998d6a99f | ||
|
|
5723edd765 | ||
|
|
7eb0de7f52 | ||
|
|
9ae901bd0d | ||
|
|
1dec482e22 | ||
|
|
0a665b79f2 | ||
|
|
c3c53017f9 | ||
|
|
834c57466f | ||
|
|
4e887e3a87 | ||
|
|
7bf6a230f3 | ||
|
|
24ffdc2724 | ||
|
|
6899f051ac | ||
|
|
d9d77b3022 | ||
|
|
b31b23e41c | ||
|
|
16418a47a8 | ||
|
|
1139b3b4c1 | ||
|
|
3277ecd13d | ||
|
|
37ff4a821c | ||
|
|
f82c6f3fed | ||
|
|
d3842bb070 | ||
|
|
2ab745016a | ||
|
|
5aaba8534f | ||
|
|
2b625b1094 | ||
|
|
17f9695ab2 | ||
|
|
c0a49b6a66 | ||
|
|
66bebff01e | ||
|
|
6f9477f0bb | ||
|
|
de88fdc4dc | ||
|
|
c219d9ad5f | ||
|
|
15927d7054 |
6
.dockerignore
Normal file
6
.dockerignore
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
target
|
||||||
|
Dockerfile
|
||||||
|
README.md
|
||||||
|
.git
|
||||||
|
.gitignore
|
||||||
|
.gitmodules
|
||||||
2
.git-blame-ignore-revs
Normal file
2
.git-blame-ignore-revs
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
# Resolved all lints and formatted the codebase
|
||||||
|
9444e62df9820d6bfd96dbd8849e177bc5cecc2e
|
||||||
4
.gitattributes
vendored
Normal file
4
.gitattributes
vendored
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
*.png binary
|
||||||
|
*.pl text eol=lf
|
||||||
|
*.rs text eol=lf diff=rust
|
||||||
|
*.md text eol=lf diff=markdown
|
||||||
63
.github/actions/setup-rust/action.yml
vendored
Normal file
63
.github/actions/setup-rust/action.yml
vendored
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
name: 'Setup Rust'
|
||||||
|
description: |
|
||||||
|
Setup the rust toolchain and environment for the selected toolchain
|
||||||
|
|
||||||
|
inputs:
|
||||||
|
rust-version:
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
targets:
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
components:
|
||||||
|
required: false
|
||||||
|
default:
|
||||||
|
cache-context:
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
|
||||||
|
runs:
|
||||||
|
using: "composite"
|
||||||
|
steps:
|
||||||
|
- uses: dtolnay/rust-toolchain@3c5f7ea28cd621ae0bf5283f0e981fb97b8a7af9 # master
|
||||||
|
id: toolchain
|
||||||
|
with:
|
||||||
|
toolchain: ${{ inputs.rust-version }}
|
||||||
|
targets: ${{ inputs.targets }}
|
||||||
|
components: ${{ inputs.components }}
|
||||||
|
|
||||||
|
- name: Install i686 dependencies
|
||||||
|
if: "contains(inputs.targets,'i686')"
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
sudo dpkg --add-architecture i386
|
||||||
|
sudo apt-get update
|
||||||
|
sudo apt-get install libssl-dev:i386 gcc-multilib clang -y
|
||||||
|
echo "CC=clang" >> $GITHUB_ENV
|
||||||
|
echo "PKG_CONFIG_SYSROOT_DIR=/" >> $GITHUB_ENV
|
||||||
|
|
||||||
|
- name: Install s390x cross-compilation toolchain
|
||||||
|
if: ${{ matrix.target == 's390x-unknown-linux-gnu' }}
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
sudo apt-get update
|
||||||
|
sudo apt-get install -y gcc-s390x-linux-gnu
|
||||||
|
echo "CARGO_TARGET_S390X_UNKNOWN_LINUX_GNU_LINKER=s390x-linux-gnu-gcc" >> $GITHUB_ENV
|
||||||
|
|
||||||
|
- uses: actions/cache@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4
|
||||||
|
with:
|
||||||
|
path: |
|
||||||
|
~/.cargo/bin/
|
||||||
|
~/.cargo/registry/index/
|
||||||
|
~/.cargo/registry/cache/
|
||||||
|
~/.cargo/git/db/
|
||||||
|
target/
|
||||||
|
key: ${{ inputs.cache-context }}_${{ inputs.targets }}_rustc-${{ steps.toolchain.outputs.cachekey }}_cargo-${{ hashFiles('**/Cargo.lock') }}
|
||||||
|
|
||||||
|
# Remove build artifacts for the current crate, since it will be rebuilt every
|
||||||
|
# run anyway, but keep dependency artifacts to cache them.
|
||||||
|
# Must be placed after actions/cache so its post step runs first.
|
||||||
|
- uses: pyTooling/Actions/with-post-step@41aed3e559cbf69bfdb46abb25d7c535900ed5b6 # v7.7.0
|
||||||
|
with:
|
||||||
|
main: bash ./.github/actions/setup-rust/cleanup.sh
|
||||||
|
post: bash ./.github/actions/setup-rust/cleanup.sh
|
||||||
13
.github/actions/setup-rust/cleanup.sh
vendored
Executable file
13
.github/actions/setup-rust/cleanup.sh
vendored
Executable file
@@ -0,0 +1,13 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -e
|
||||||
|
|
||||||
|
echo Cleanup workspace build artifacts and extra target output
|
||||||
|
|
||||||
|
# clean just the direct members of the current workspace, use cargo metadata to generalize to all rust projects
|
||||||
|
cargo clean --workspace
|
||||||
|
|
||||||
|
# remove directories in /target/ that are not named `debug` or `release`
|
||||||
|
before=`du -s target | awk '{print $1}'`
|
||||||
|
find ./target -maxdepth 1 -type d ! -name debug ! -name release ! -name target -exec rm -r {} \;
|
||||||
|
after=`du -s target | awk '{print $1}'`
|
||||||
|
echo Deleted $(($before - $after)) bytes from target directory
|
||||||
52
.github/dependabot.yml
vendored
Normal file
52
.github/dependabot.yml
vendored
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
version: 2
|
||||||
|
|
||||||
|
updates:
|
||||||
|
# Enable version updates for cargo
|
||||||
|
- package-ecosystem: "cargo"
|
||||||
|
# Look for `Cargo.toml` and `Cargo.lock` files in the `root` directory
|
||||||
|
directory: "/"
|
||||||
|
schedule:
|
||||||
|
interval: "monthly"
|
||||||
|
cooldown:
|
||||||
|
default-days: "7"
|
||||||
|
groups:
|
||||||
|
cargo-incompatible:
|
||||||
|
applies-to: version-updates
|
||||||
|
# TODO: use incompatible update-type once available
|
||||||
|
# see issue https://github.com/dependabot/dependabot-core/issues/9681
|
||||||
|
update-types:
|
||||||
|
- "major"
|
||||||
|
- "minor" # pre-1.0 dependencies
|
||||||
|
cargo-compatible:
|
||||||
|
applies-to: version-updates
|
||||||
|
# TODO: use compatible update-type once available
|
||||||
|
# see issue https://github.com/dependabot/dependabot-core/issues/9681
|
||||||
|
update-types:
|
||||||
|
- "patch"
|
||||||
|
ignore:
|
||||||
|
# ignore all cargo updates for now while dependabot does not respect msrv/rust-version
|
||||||
|
# see issue https://github.com/dependabot/dependabot-core/issues/5423
|
||||||
|
- dependency-name: "*"
|
||||||
|
|
||||||
|
# Enable version updates for Docker
|
||||||
|
- package-ecosystem: "docker"
|
||||||
|
# Look for a `Dockerfile` in the `root` directory
|
||||||
|
directory: "/"
|
||||||
|
schedule:
|
||||||
|
interval: "monthly"
|
||||||
|
cooldown:
|
||||||
|
default-days: "7"
|
||||||
|
|
||||||
|
# Enable version updates for GitHub Actions
|
||||||
|
- package-ecosystem: "github-actions"
|
||||||
|
# Workflow files stored in the default location of `.github/workflows`
|
||||||
|
# You don't need to specify `/.github/workflows` for `directory`. You can use `directory: "/"`.
|
||||||
|
directory: "/"
|
||||||
|
schedule:
|
||||||
|
interval: "monthly"
|
||||||
|
cooldown:
|
||||||
|
default-days: "7"
|
||||||
|
ignore:
|
||||||
|
# these actions doesn't have proper version tags
|
||||||
|
- dependency-name: "dtolnay/rust-toolchain"
|
||||||
|
- dependency-name: "logtalk-actions/setup-logtalk"
|
||||||
12
.github/workflows/check_features.sh
vendored
Executable file
12
.github/workflows/check_features.sh
vendored
Executable file
@@ -0,0 +1,12 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -e
|
||||||
|
|
||||||
|
echo "Checking all feature at once"
|
||||||
|
cargo check -q --all-targets --all-features "$@"
|
||||||
|
|
||||||
|
features=$(cargo metadata --no-deps --format-version 1 | jq -r '.packages[] | select(.name = "scryer-prolog") | .features | keys | join(" ")')
|
||||||
|
|
||||||
|
for feature in ${features} ; do
|
||||||
|
echo "Checking feature ${feature} in isolation"
|
||||||
|
cargo check -q --all-targets --no-default-features --features=${feature} "$@"
|
||||||
|
done
|
||||||
248
.github/workflows/ci.yml
vendored
Normal file
248
.github/workflows/ci.yml
vendored
Normal file
@@ -0,0 +1,248 @@
|
|||||||
|
name: CI
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- master
|
||||||
|
- rebis-dev
|
||||||
|
tags:
|
||||||
|
- "v**"
|
||||||
|
pull_request:
|
||||||
|
schedule:
|
||||||
|
- cron: '0 0 * * 3' # At 12:00 AM, only on Wednesday
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
checks: write
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
style:
|
||||||
|
runs-on: ubuntu-22.04
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||||
|
- name: Setup Rust
|
||||||
|
uses: ./.github/actions/setup-rust
|
||||||
|
with:
|
||||||
|
rust-version: stable
|
||||||
|
targets: x86_64-unknown-linux-gnu
|
||||||
|
components: clippy, rustfmt
|
||||||
|
cache-context: style
|
||||||
|
|
||||||
|
- name: Check formatting
|
||||||
|
run: cargo fmt --check
|
||||||
|
- name: Check clippy
|
||||||
|
run: cargo clippy --no-deps --all-targets
|
||||||
|
if: ${{ !cancelled() }}
|
||||||
|
|
||||||
|
read-msrv:
|
||||||
|
runs-on: ubuntu-22.04
|
||||||
|
outputs:
|
||||||
|
msrv: ${{ steps.read-declared-msrv.outputs.msrv }}
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||||
|
- id: read-declared-msrv
|
||||||
|
name: Read msrv from Cargo.toml rust_version field
|
||||||
|
run: echo "msrv=$(cargo metadata --no-deps --format-version 1 | jq -r '.packages[] | select(.name = "scryer-prolog") | ."rust_version"')" >> "$GITHUB_OUTPUT"
|
||||||
|
|
||||||
|
|
||||||
|
build-test:
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
needs: [read-msrv]
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
include:
|
||||||
|
# operating systems
|
||||||
|
- { os: windows-latest, rust-version: stable, target: 'x86_64-pc-windows-msvc', publish: true, check-features: true }
|
||||||
|
- { os: macos-latest, rust-version: stable, target: 'x86_64-apple-darwin', publish: true, check-features: true }
|
||||||
|
# architectures
|
||||||
|
- { os: ubuntu-22.04, rust-version: stable, target: 'x86_64-unknown-linux-gnu', publish: true, check-features: true }
|
||||||
|
- { os: ubuntu-22.04, rust-version: stable, target: 'i686-unknown-linux-gnu', publish: true }
|
||||||
|
# FIXME(issue #2138): run wasm tests, failing to run since https://github.com/mthom/scryer-prolog/pull/2137 removed wasm-pack
|
||||||
|
- { os: ubuntu-22.04, rust-version: nightly, target: 'wasm32-unknown-unknown', publish: true, args: '--no-default-features' , test-args: '--no-run --no-default-features', use_swap: true }
|
||||||
|
# Cargo.toml rust-version
|
||||||
|
- { os: ubuntu-22.04, rust-version: "${{ needs.read-msrv.outputs.msrv }}" , target: 'x86_64-unknown-linux-gnu' }
|
||||||
|
- { os: ubuntu-22.04, rust-version: beta, target: 'x86_64-unknown-linux-gnu' }
|
||||||
|
- { os: ubuntu-22.04, rust-version: nightly, target: 'x86_64-unknown-linux-gnu', miri: true, components: "miri" }
|
||||||
|
# run miri for a big-endian target, with all features that are simple to get cross-compiled
|
||||||
|
- { os: ubuntu-22.04, rust-version: nightly, target: 's390x-unknown-linux-gnu', miri: true, components: "miri", args: '--no-default-features --features=all-simple-cross', test-args: '--no-run --no-default-features --features=all-simple-cross' }
|
||||||
|
defaults:
|
||||||
|
run:
|
||||||
|
shell: bash
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||||
|
|
||||||
|
- uses: actionhippie/swap-space@0cffa893f224708cfb6b011690d8ba819d69c10f # v1.1.0
|
||||||
|
if: matrix.use_swap
|
||||||
|
with:
|
||||||
|
size: 10G
|
||||||
|
|
||||||
|
- name: Setup Rust
|
||||||
|
uses: ./.github/actions/setup-rust
|
||||||
|
with:
|
||||||
|
rust-version: ${{ matrix.rust-version }}
|
||||||
|
targets: ${{ matrix.target }}
|
||||||
|
cache-context: ${{ matrix.os }}
|
||||||
|
components: ${{ matrix.components }}
|
||||||
|
|
||||||
|
# Build and test.
|
||||||
|
- name: Build library
|
||||||
|
run: cargo build --all-targets --target ${{ matrix.target }} ${{ matrix.args }} --verbose
|
||||||
|
|
||||||
|
- name: Test
|
||||||
|
run: cargo test --target ${{ matrix.target }} ${{ matrix.test-args }} --all
|
||||||
|
|
||||||
|
- name: Check features
|
||||||
|
if: matrix.check-features
|
||||||
|
run: bash ./.github/workflows/check_features.sh --target ${{ matrix.target }}
|
||||||
|
|
||||||
|
- name: Check miri
|
||||||
|
if: matrix.miri
|
||||||
|
run: cargo miri test --target ${{ matrix.target }} ${{ matrix.args }}
|
||||||
|
|
||||||
|
# On stable rust builds, build a binary and publish as a github actions
|
||||||
|
# artifact. These binaries could be useful for testing the pipeline but
|
||||||
|
# are only retained by github for 90 days.
|
||||||
|
- name: Build release binary
|
||||||
|
if: matrix.publish
|
||||||
|
run: |
|
||||||
|
cargo rustc --target ${{ matrix.target }} ${{ matrix.args }} --verbose --bin scryer-prolog --release
|
||||||
|
echo "$PWD/target/release" >> $GITHUB_PATH
|
||||||
|
|
||||||
|
- name: Install cargo-deb for creating debian packages
|
||||||
|
if: ${{ matrix.publish && contains(matrix.target, 'linux') }}
|
||||||
|
run: cargo install cargo-deb --force --locked
|
||||||
|
|
||||||
|
- name: Build release debian packages
|
||||||
|
if: ${{ matrix.publish && contains(matrix.target, 'linux') }}
|
||||||
|
run: cargo deb --target ${{ matrix.target }}
|
||||||
|
|
||||||
|
- name: Publish release binary artifact
|
||||||
|
if: matrix.publish
|
||||||
|
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
||||||
|
with:
|
||||||
|
path: |
|
||||||
|
target/${{ matrix.target }}/release/scryer-prolog*
|
||||||
|
target/${{ matrix.target }}/debian/scryer-prolog*.deb
|
||||||
|
name: scryer-prolog_${{ matrix.os }}_${{ matrix.target }}
|
||||||
|
|
||||||
|
logtalk-test:
|
||||||
|
# if: false # uncomment to disable job
|
||||||
|
runs-on: ubuntu-22.04
|
||||||
|
needs: [build-test]
|
||||||
|
steps:
|
||||||
|
# Download prebuilt ubuntu binary from build-test job, setup logtalk
|
||||||
|
- uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c #v8.0.1
|
||||||
|
with:
|
||||||
|
name: scryer-prolog_ubuntu-22.04_x86_64-unknown-linux-gnu
|
||||||
|
- run: |
|
||||||
|
chmod +x release/scryer-prolog
|
||||||
|
echo "$PWD/release" >> "$GITHUB_PATH"
|
||||||
|
- name: Install Logtalk
|
||||||
|
uses: logtalk-actions/setup-logtalk@4ea002fe3037199afcf1c6c91bf1f57de0f995e6 # master
|
||||||
|
with:
|
||||||
|
logtalk-version: "3.70.0"
|
||||||
|
logtalk-tool-dependencies: false
|
||||||
|
|
||||||
|
# Run logtalk tests.
|
||||||
|
- name: Run Logtalk's prolog compliance test suite
|
||||||
|
working-directory: ${{ env.LOGTALKUSER }}/tests/prolog/
|
||||||
|
run: |
|
||||||
|
pwd
|
||||||
|
scryerlgt -g '{ack(tester)},halt.'
|
||||||
|
logtalk_tester -p scryer -g "set_logtalk_flag(clean,off)" -w -t 360 \
|
||||||
|
-f xunit \
|
||||||
|
-s "$LOGTALKUSER/tests/prolog" \
|
||||||
|
|| echo "::warning ::logtalk compliance suite failed"
|
||||||
|
# -u "https://github.com/LogtalkDotOrg/logtalk3/tree/$LOGTALK_GIT_HASH/tests/prolog/" \
|
||||||
|
- name: Publish Logtalk test logs
|
||||||
|
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
||||||
|
with:
|
||||||
|
name: logtalk-test-logs
|
||||||
|
path: '${{ env.LOGTALKUSER }}/tests/prolog/logtalk_tester_logs'
|
||||||
|
- name: Publish Logtalk test results artifact
|
||||||
|
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
||||||
|
with:
|
||||||
|
name: logtalk-test-results
|
||||||
|
path: '${{ env.LOGTALKUSER }}/tests/prolog/**/*.xml'
|
||||||
|
- name: Publish Logtalk test summary
|
||||||
|
uses: EnricoMi/publish-unit-test-result-action/composite@c950f6fb443cb5af20a377fd0dfaa78838901040 # v2.23.0
|
||||||
|
with:
|
||||||
|
check_name: Logtalk test summary
|
||||||
|
files: '${{ env.LOGTALKUSER }}/tests/prolog/**/*.xml'
|
||||||
|
fail_on: nothing
|
||||||
|
comment_mode: off
|
||||||
|
|
||||||
|
report:
|
||||||
|
runs-on: ubuntu-22.04
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||||
|
- name: Setup Rust
|
||||||
|
uses: ./.github/actions/setup-rust
|
||||||
|
with:
|
||||||
|
rust-version: stable
|
||||||
|
targets: x86_64-unknown-linux-gnu
|
||||||
|
cache-context: report
|
||||||
|
- name: Install CLI tools
|
||||||
|
run: |
|
||||||
|
cargo install cargo2junit --force
|
||||||
|
version=`yq -ptoml -oj -r '.package[] | select(.name == "iai-callgrind") | .version' Cargo.lock`
|
||||||
|
echo installing iai-callgrind "$version"
|
||||||
|
cargo install iai-callgrind-runner --force --version "$version"
|
||||||
|
sudo apt-get update -y
|
||||||
|
sudo apt-get install valgrind -y
|
||||||
|
|
||||||
|
- name: Test and report
|
||||||
|
run: |
|
||||||
|
RUSTC_BOOTSTRAP=1 cargo test --all -- -Z unstable-options --format json --report-time | cargo2junit > cargo_test_results.xml
|
||||||
|
- name: Publish cargo test results artifact
|
||||||
|
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
||||||
|
with:
|
||||||
|
name: cargo-test-results
|
||||||
|
path: cargo_test_results.xml
|
||||||
|
- name: Publish cargo test summary
|
||||||
|
uses: EnricoMi/publish-unit-test-result-action/composite@c950f6fb443cb5af20a377fd0dfaa78838901040 # v2.23.0
|
||||||
|
with:
|
||||||
|
check_name: Cargo test summary
|
||||||
|
files: cargo_test_results.xml
|
||||||
|
fail_on: nothing
|
||||||
|
comment_mode: off
|
||||||
|
|
||||||
|
- run: cargo build --all-targets --release
|
||||||
|
- run: cargo test --bench setup --release
|
||||||
|
- run: cargo bench --bench run_iai -- --save-summary=json
|
||||||
|
- run: cargo bench --bench run_criterion
|
||||||
|
- run: cargo bench --bench run_criterion -- --profile-time 60
|
||||||
|
|
||||||
|
- name: Publish benchmark results
|
||||||
|
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
||||||
|
with:
|
||||||
|
name: benchmark-results
|
||||||
|
path: |
|
||||||
|
target/criterion/*
|
||||||
|
target/iai/*
|
||||||
|
target/benchmark_inference_counts.json
|
||||||
|
|
||||||
|
# Publish binaries when building for a tag
|
||||||
|
release:
|
||||||
|
runs-on: ubuntu-22.04
|
||||||
|
needs: [build-test]
|
||||||
|
if: startsWith(github.ref, 'refs/tags/v')
|
||||||
|
steps:
|
||||||
|
- uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c #v8.0.1
|
||||||
|
- name: Zip binaries for release
|
||||||
|
run: |
|
||||||
|
zip scryer-prolog_macos-latest.zip ./scryer-prolog_macos-latest_x86_64-apple-darwin/scryer-prolog
|
||||||
|
zip scryer-prolog_ubuntu-22.04_i686.zip ./scryer-prolog_ubuntu-22.04_i686-unknown-linux-gnu/release/scryer-prolog ./scryer-prolog_ubuntu-22.04_i686-unknown-linux-gnu/debian/scryer-prolog*.deb
|
||||||
|
zip scryer-prolog_ubuntu-22.04_x86_64.zip ./scryer-prolog_ubuntu-22.04_x86_64-unknown-linux-gnu/release/scryer-prolog ./scryer-prolog_ubuntu-22.04_x86_64-unknown-linux-gnu/debian/scryer-prolog*.deb
|
||||||
|
zip scryer-prolog_windows-latest.zip ./scryer-prolog_windows-latest_x86_64-pc-windows-msvc/scryer-prolog.exe
|
||||||
|
zip scryer-prolog_wasm32.zip ./scryer-prolog_ubuntu-22.04_wasm32-unknown-unknown/scryer-prolog.wasm
|
||||||
|
- name: Release
|
||||||
|
uses: softprops/action-gh-release@153bb8e04406b158c6c84fc1615b65b24149a1fe # v2.6.1
|
||||||
|
with:
|
||||||
|
files: |
|
||||||
|
scryer-prolog_macos-latest.zip
|
||||||
|
scryer-prolog_ubuntu-22.04_i686.zip
|
||||||
|
scryer-prolog_ubuntu-22.04_x86_64.zip
|
||||||
|
scryer-prolog_windows-latest.zip
|
||||||
|
scryer-prolog_wasm32.zip
|
||||||
61
.github/workflows/docker-publish.yml
vendored
Normal file
61
.github/workflows/docker-publish.yml
vendored
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
name: Docker Publish
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- 'master'
|
||||||
|
tags:
|
||||||
|
- 'v*.*.*'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||||
|
|
||||||
|
# Workaround: https://github.com/docker/build-push-action/issues/461
|
||||||
|
- name: Setup Docker buildx
|
||||||
|
# https://github.com/docker/setup-buildx-action
|
||||||
|
uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4.0.0
|
||||||
|
|
||||||
|
# Login against Docker registry
|
||||||
|
- name: Log into registry
|
||||||
|
# https://github.com/docker/login-action
|
||||||
|
uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4.1.0
|
||||||
|
with:
|
||||||
|
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||||
|
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||||
|
|
||||||
|
# Extract Docker image tag from git tag. E.g. if git tag is "v0.19.1" then use
|
||||||
|
# Docker image tag "0.19.1". The "latest" tag reflects the most recent build on
|
||||||
|
# master.
|
||||||
|
- name: Extract Docker metadata
|
||||||
|
id: meta
|
||||||
|
# https://github.com/docker/metadata-action
|
||||||
|
uses: docker/metadata-action@030e881283bb7a6894de51c315a6bfe6a94e05cf # v6.0.0
|
||||||
|
with:
|
||||||
|
images: docker.io/${{ secrets.DOCKERHUB_USERNAME }}/scryer-prolog
|
||||||
|
tags: |
|
||||||
|
type=semver,pattern={{version}}
|
||||||
|
type=raw,value=latest,enable={{is_default_branch}}
|
||||||
|
# type=raw,value=latest,enable=${{ github.ref == format('refs/heads/{0}', 'master') }}
|
||||||
|
|
||||||
|
# Build and push Docker image with Buildx
|
||||||
|
- name: Build and push Docker image
|
||||||
|
id: build-and-push
|
||||||
|
# https://github.com/docker/build-push-action
|
||||||
|
uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f # v7.1.0
|
||||||
|
# v4 adds SLSA Provenance attestation which is
|
||||||
|
# - unsupported by AWS Lambda
|
||||||
|
# - limited support by Google Cloud Run
|
||||||
|
# > If deploying a multi-architecture image, the manifest list must include linux/amd64.
|
||||||
|
# see https://github.com/docker/build-push-action/releases/tag/v4.0.0
|
||||||
|
# we might want to disable this if its a problem for someone
|
||||||
|
with:
|
||||||
|
context: .
|
||||||
|
push: true
|
||||||
|
tags: ${{ steps.meta.outputs.tags }}
|
||||||
|
labels: ${{ steps.meta.outputs.labels }}
|
||||||
5
.gitignore
vendored
5
.gitignore
vendored
@@ -1,4 +1,7 @@
|
|||||||
|
src/static_atoms.rs
|
||||||
target/
|
target/
|
||||||
Cargo.lock
|
.direnv/
|
||||||
|
|
||||||
|
|
||||||
|
__pycache__
|
||||||
|
*.pyc
|
||||||
13
.travis.yml
13
.travis.yml
@@ -1,13 +0,0 @@
|
|||||||
language: rust
|
|
||||||
rust:
|
|
||||||
- stable
|
|
||||||
- beta
|
|
||||||
- nightly
|
|
||||||
matrix:
|
|
||||||
allow_failures:
|
|
||||||
- rust: nightly
|
|
||||||
fast_finish: true
|
|
||||||
|
|
||||||
script:
|
|
||||||
- cargo build --verbose --all
|
|
||||||
- cargo test --verbose --all
|
|
||||||
4422
Cargo.lock
generated
Normal file
4422
Cargo.lock
generated
Normal file
File diff suppressed because it is too large
Load Diff
187
Cargo.toml
187
Cargo.toml
@@ -1,28 +1,179 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "scryer-prolog"
|
name = "scryer-prolog"
|
||||||
version = "0.8.116"
|
version = "0.10.0"
|
||||||
authors = ["Mark Thom <markjordanthom@gmail.com>"]
|
authors = ["Mark Thom <markjordanthom@gmail.com>"]
|
||||||
build = "build.rs"
|
edition = "2024"
|
||||||
repository = "https://github.com/mthom/scryer-prolog"
|
|
||||||
description = "A modern Prolog implementation written mostly in Rust."
|
description = "A modern Prolog implementation written mostly in Rust."
|
||||||
|
readme = "README.md"
|
||||||
|
repository = "https://github.com/mthom/scryer-prolog"
|
||||||
license = "BSD-3-Clause"
|
license = "BSD-3-Clause"
|
||||||
edition = "2018"
|
keywords = ["prolog", "prolog-interpreter", "prolog-system"]
|
||||||
|
categories = ["command-line-utilities"]
|
||||||
|
build = "build/main.rs"
|
||||||
|
# Remember to check CI
|
||||||
|
rust-version = "1.93.1"
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
crate-type = ["cdylib", "rlib"]
|
||||||
|
|
||||||
|
[features]
|
||||||
|
default = ["all-simple-cross", "tls", "http"]
|
||||||
|
# activates all features that depend on no non pure-rust dependencies
|
||||||
|
#
|
||||||
|
# currently does not include
|
||||||
|
# ffi due to libffi
|
||||||
|
# tls, http due to openssl
|
||||||
|
# crypto-full due to ring
|
||||||
|
all-pure = ["repl", "hostname"]
|
||||||
|
# enables all features that are simple to get working for cross-compliation
|
||||||
|
# currently all but tls, http as those depend on openssl
|
||||||
|
all-simple-cross = ["all-pure", "ffi", "crypto-full"]
|
||||||
|
ffi = ["dep:libffi"]
|
||||||
|
repl = ["dep:crossterm", "dep:ctrlc", "dep:rustyline"]
|
||||||
|
hostname = ["dep:hostname"]
|
||||||
|
tls = ["dep:native-tls"]
|
||||||
|
http = ["dep:warp", "dep:reqwest"]
|
||||||
|
# crypto function that require non pure-rust dependencies
|
||||||
|
crypto-full = ["dep:ring"]
|
||||||
|
|
||||||
|
[lints.clippy]
|
||||||
|
collapsible_match = "allow"
|
||||||
|
|
||||||
|
[lints.rust]
|
||||||
|
unexpected_cfgs = "deny"
|
||||||
|
function_casts_as_integer = "deny"
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
indexmap = "1.0.2"
|
proc-macro2 = "1.0.86"
|
||||||
|
quote = "1.0.36"
|
||||||
|
strum = "0.26"
|
||||||
|
strum_macros = "0.26"
|
||||||
|
syn = { version = "2.0.72", features = ['full', 'visit', 'extra-traits'] }
|
||||||
|
to-syn-value = "0.1.1"
|
||||||
|
to-syn-value_derive = "0.1.1"
|
||||||
|
walkdir = "2"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
dirs = "2.0.2"
|
arcu = { version = "0.1.2", features = ["thread_local_counter"] }
|
||||||
downcast = "0.10.0"
|
base64 = "0.22.1"
|
||||||
indexmap = "1.0.2"
|
bit-set = "0.8.0"
|
||||||
lazy_static = "1.4.0"
|
bitvec = "1"
|
||||||
libc = "0.2.62"
|
blake2 = "0.10.6"
|
||||||
nix = "0.15.0"
|
bytes = "1"
|
||||||
ordered-float = "0.5.0"
|
chrono = "0.4.38"
|
||||||
prolog_parser = "0.8.34"
|
cpu-time = "1.0.0"
|
||||||
ref_thread_local = "0.0.0"
|
crrl = "0.9.0"
|
||||||
rug = "1.4.0"
|
dashu = { version = "0.4.2", features = ["rand"] }
|
||||||
rustyline = "5.0.3"
|
derive_more = "0.99.18"
|
||||||
|
dirs-next = "2.0.0"
|
||||||
|
divrem = "1.0.0"
|
||||||
|
futures = "0.3"
|
||||||
|
fxhash = "0.2.1"
|
||||||
|
git-version = "0.3.9"
|
||||||
|
indexmap = "2.3.0"
|
||||||
|
lexical = "7.0.4"
|
||||||
|
libc = "0.2.155"
|
||||||
|
libloading = "0.8"
|
||||||
|
modular-bitfield = "0.13.1"
|
||||||
|
num-order = { version = "1.2.0" }
|
||||||
|
ordered-float = "5.0.0"
|
||||||
|
phf = { version = "0.11", features = ["macros"] }
|
||||||
|
puruspe = "0.4.1"
|
||||||
|
rand = "0.8.5"
|
||||||
|
ring = { version = "0.17.8", features = [
|
||||||
|
"wasm32_unknown_unknown_js",
|
||||||
|
], optional = true }
|
||||||
|
ripemd = "0.1.3"
|
||||||
|
roxmltree = "0.20.0"
|
||||||
|
ryu = "1.0.18"
|
||||||
|
sha3 = "0.10.8"
|
||||||
|
smallvec = "1.13.2"
|
||||||
|
static_assertions = "1.1.0"
|
||||||
|
|
||||||
[dependencies.termion]
|
scraper = { version = "0.23.1", default-features = false, features = [
|
||||||
version = "1.4.0"
|
"errors",
|
||||||
|
] }
|
||||||
|
ego-tree = "0.10.0"
|
||||||
|
|
||||||
|
|
||||||
|
serde_json = "1.0.122"
|
||||||
|
serde = "1.0.204"
|
||||||
|
parking_lot = "0.12.4"
|
||||||
|
|
||||||
|
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
|
||||||
|
crossterm = { version = "0.28.1", optional = true }
|
||||||
|
ctrlc = { version = "3.4.4", optional = true }
|
||||||
|
hostname = { version = "0.4.0", optional = true }
|
||||||
|
libffi = { version = "5.1.0", optional = true }
|
||||||
|
native-tls = { version = "0.2.12", optional = true }
|
||||||
|
# the version requirement of reqwest is kept low for compatibility with old deno versions
|
||||||
|
# that pin reqwest to 0.11.20
|
||||||
|
reqwest = { version = "0.11.0", optional = true }
|
||||||
|
rustyline = { version = "18.0.0", optional = true }
|
||||||
|
tokio = { version = "1.39.2", features = ["full"] }
|
||||||
|
warp = { version = "0.3.7", features = ["tls"], optional = true }
|
||||||
|
|
||||||
|
[target.'cfg(target_arch = "wasm32")'.dependencies]
|
||||||
|
getrandom = { version = "0.2.15", features = ["js"] }
|
||||||
|
tokio = { version = "1.39.2", features = [
|
||||||
|
"sync",
|
||||||
|
"macros",
|
||||||
|
"io-util",
|
||||||
|
"rt",
|
||||||
|
"time",
|
||||||
|
] }
|
||||||
|
|
||||||
|
[target.'cfg(all(target_arch = "wasm32", target_os = "unknown"))'.dependencies]
|
||||||
|
console_error_panic_hook = "0.1"
|
||||||
|
wasm-bindgen = "0.2.92"
|
||||||
|
wasm-bindgen-futures = "0.4"
|
||||||
|
serde-wasm-bindgen = "0.6"
|
||||||
|
web-sys = { version = "0.3", features = [
|
||||||
|
"Document",
|
||||||
|
"Window",
|
||||||
|
"Element",
|
||||||
|
"Performance",
|
||||||
|
] }
|
||||||
|
js-sys = "0.3"
|
||||||
|
ouroboros = "0.18"
|
||||||
|
|
||||||
|
[dev-dependencies]
|
||||||
|
current_platform = "0.2.0"
|
||||||
|
maplit = "1.0.2"
|
||||||
|
serial_test = "3.1.1"
|
||||||
|
|
||||||
|
[target.'cfg(not(all(target_arch = "wasm32", target_os = "unknown")))'.dev-dependencies]
|
||||||
|
criterion = "0.5.1"
|
||||||
|
iai-callgrind = "0.12.1"
|
||||||
|
trycmd = "0.15.6"
|
||||||
|
|
||||||
|
[target.'cfg(not(any(target_os = "windows", all(target_arch = "wasm32", target_os = "unknown"))))'.dev-dependencies]
|
||||||
|
pprof = { version = "0.13.0", features = ["criterion", "flamegraph"] }
|
||||||
|
|
||||||
|
[profile.bench]
|
||||||
|
lto = true
|
||||||
|
opt-level = 3
|
||||||
|
|
||||||
|
[profile.release]
|
||||||
|
lto = true
|
||||||
|
opt-level = 3
|
||||||
|
debug = 2
|
||||||
|
|
||||||
|
[profile.wasm-dev]
|
||||||
|
inherits = "dev"
|
||||||
|
opt-level = 1
|
||||||
|
lto = "off"
|
||||||
|
|
||||||
|
[profile.wasm-release]
|
||||||
|
inherits = "release"
|
||||||
|
lto = "off"
|
||||||
|
panic = "abort"
|
||||||
|
codegen-units = 256
|
||||||
|
|
||||||
|
[[bench]]
|
||||||
|
name = "run_criterion"
|
||||||
|
harness = false
|
||||||
|
|
||||||
|
[[bench]]
|
||||||
|
name = "run_iai"
|
||||||
|
harness = false
|
||||||
|
|||||||
34
Dockerfile
Normal file
34
Dockerfile
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
# See https://github.com/LukeMathWalker/cargo-chef
|
||||||
|
ARG DEBIAN_RELEASE=bookworm
|
||||||
|
ARG RUST_VERSION=1-${DEBIAN_RELEASE}
|
||||||
|
FROM rust:${RUST_VERSION} AS planner
|
||||||
|
WORKDIR /scryer-prolog
|
||||||
|
RUN cargo install cargo-chef
|
||||||
|
COPY . .
|
||||||
|
RUN cargo chef prepare --recipe-path recipe.json
|
||||||
|
|
||||||
|
FROM rust:${RUST_VERSION} AS cacher
|
||||||
|
WORKDIR /scryer-prolog
|
||||||
|
RUN cargo install cargo-chef
|
||||||
|
COPY --from=planner /scryer-prolog/recipe.json recipe.json
|
||||||
|
RUN cargo chef cook --release --recipe-path recipe.json
|
||||||
|
|
||||||
|
FROM rust:${RUST_VERSION} AS builder
|
||||||
|
WORKDIR /scryer-prolog
|
||||||
|
COPY . .
|
||||||
|
# Copy over the cached dependencies
|
||||||
|
COPY --from=cacher /scryer-prolog/target target
|
||||||
|
COPY --from=cacher $CARGO_HOME $CARGO_HOME
|
||||||
|
RUN cargo build --release --bin scryer-prolog
|
||||||
|
|
||||||
|
FROM debian:${DEBIAN_RELEASE}-slim
|
||||||
|
RUN apt-get update \
|
||||||
|
&& apt-get install -y --no-install-recommends openssl \
|
||||||
|
&& apt-get clean -y \
|
||||||
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
COPY --from=builder /scryer-prolog/target/release/scryer-prolog /usr/local/bin
|
||||||
|
ENV RUST_BACKTRACE=1
|
||||||
|
# Sanity check the binary: if it can't be executed (e.g. if there are missing libraries)
|
||||||
|
# then fail the build
|
||||||
|
RUN scryer-prolog --version
|
||||||
|
ENTRYPOINT ["/usr/local/bin/scryer-prolog"]
|
||||||
79
INDEX.dj
Normal file
79
INDEX.dj
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
# Scryer Prolog
|
||||||
|
|
||||||
|
```
|
||||||
|
?- append("Hello, ", X, "Hello, Scryer Prolog!").
|
||||||
|
X = "Scryer Prolog!".
|
||||||
|
```
|
||||||
|
|
||||||
|
{width=128 style=float:right;} [Scryer Prolog](https://github.com/mthom/scryer-prolog) is a free software ISO Prolog system intended to be an industrial
|
||||||
|
strength production environment *and* a testbed for bleeding edge research in
|
||||||
|
logic and constraint programming.
|
||||||
|
|
||||||
|
Some of the Scryer Prolog features are:
|
||||||
|
|
||||||
|
* ISO standard compliant
|
||||||
|
* Integrated constraint programming libraries: [clp(B)](/clpb.html), [clp(Z)](/clpz.html).
|
||||||
|
* [Definite Clause Grammars](/dcgs.html)
|
||||||
|
* Coroutining support ([`dif/2`](/dif.html), [`freeze/2`](/freeze.html), ...)
|
||||||
|
* [Tabling and SLG resolution](/tabling.html)
|
||||||
|
* Compact string representation
|
||||||
|
* Network libraries ([TCP sockets](/sockets.html), [HTTP server](/http/http_server.html), [HTTP client](/http/http_open.html), ...)
|
||||||
|
* [Cryptographical predicates](/crypto.html)
|
||||||
|
* [Foreign Function Interface](/ffi.html)
|
||||||
|
* WebAssembly support
|
||||||
|
* Usable as a library
|
||||||
|
* WAM based engine, cross-platform made in Rust
|
||||||
|
* _and more..._
|
||||||
|
|
||||||
|
Try Scryer Prolog without any installation! Use [Scryer Playground](https://play.scryer.pl), which uses the WASM version of Scryer Prolog.
|
||||||
|
|
||||||
|
## What is Prolog?
|
||||||
|
|
||||||
|
Prolog is a logic programming language created by [Alain Colmerauer](https://en.wikipedia.org/wiki/Alain_Colmerauer) and [Robert Kowalski](https://en.wikipedia.org/wiki/Robert_Kowalski) in 1972.
|
||||||
|
The idea behind Prolog is try to express a task in language similar to First Order Logic.
|
||||||
|
Prolog systems include _unification_ and _non-determinism_ as key concepts upon which we build programs.
|
||||||
|
|
||||||
|
A Prolog program is made up of predicates which define a relation between its arguments. A predicate
|
||||||
|
is made from clauses. A clause can be either a fact or a rule. There's also a toplevel, which we
|
||||||
|
can use to ask and reason about our task.
|
||||||
|
|
||||||
|
It's still to this day one of the best examples and one of the most popular languages in the field
|
||||||
|
of logic programming. That's because Prolog allows us to elegantly solve many tasks with short and
|
||||||
|
general programs.
|
||||||
|
|
||||||
|
If you want a more detailed description of Prolog, check [A Tour of Prolog](https://www.youtube.com/watch?v=8XUutFBbUrg).
|
||||||
|
|
||||||
|
If you want to learn more about Prolog history, check the videos [l'Aventure Prolog](https://www.youtube.com/watch?v=74Ig_QKndvE) and [50 years of Prolog and beyond](https://prologyear.logicprogramming.org/videos/PrologDay_Session_1_talk.mp4).
|
||||||
|
|
||||||
|
## Where can I learn Prolog?
|
||||||
|
|
||||||
|
There are a lot of classical Prolog books. Those books can teach you the basics of Prolog. Some
|
||||||
|
examples are: _The Art of Prolog (Shapiro)_, _Programming in Prolog (Clocksin, Mellish)_ and _The Craft
|
||||||
|
of Prolog (O'Keefe)_. However, most of them are not updated to _modern_ Prolog.
|
||||||
|
We recommend _[The Power of Prolog (Markus Triska)](https://www.metalevel.at/prolog)_ for modern Prolog. For reference about
|
||||||
|
the builtin Prolog modules and libraries in Scryer, check the documentation site. It's this!
|
||||||
|
|
||||||
|
## Downloads
|
||||||
|
|
||||||
|
The latest version of Scryer Prolog is *0.10.0*. And it's already useful for lots of tasks.
|
||||||
|
|
||||||
|
| Windows (64 bits) | [Download](https://scryerprologrelease.blob.core.windows.net/release-0100/scryer-prolog_windows-latest_x86_64-pc-windows-msvc.zip) |
|
||||||
|
| macOS (Intel) | [Download](https://scryerprologrelease.blob.core.windows.net/release-0100/scryer-prolog_macos-11_x86_64-apple-darwin.zip) |
|
||||||
|
| macOS (ARM) | [Download](https://scryerprologrelease.blob.core.windows.net/release-0100/scryer-prolog--0.10.0.arm64_tahoe.bottle.tar.gz) |
|
||||||
|
| Linux (Ubuntu 22.04, 64 bits) | [Download](https://scryerprologrelease.blob.core.windows.net/release-0100/scryer-prolog_ubuntu-22.04_x86_64-unknown-linux-gnu.zip) |
|
||||||
|
| Linux (Ubuntu 22.04, 32 bits) | [Download](https://scryerprologrelease.blob.core.windows.net/release-0100/scryer-prolog_ubuntu-22.04_i686-unknown-linux-gnu.zip) |
|
||||||
|
|
||||||
|
Scryer Prolog can also be compiled from source, instructions are on the [GitHub README](https://github.com/mthom/scryer-prolog). It runs on Linux, macOS and Windows. Other operating systems may work but they're not regularly tested.
|
||||||
|
|
||||||
|
If you're in Linux, maybe your distribution already has an Scryer Prolog package.
|
||||||
|
|
||||||
|
There's also a [Docker image](https://github.com/mthom/scryer-prolog#docker-install) available.
|
||||||
|
|
||||||
|
## Support and discussions
|
||||||
|
|
||||||
|
If Scryer Prolog crashes or yields unexpected errors, consider filing
|
||||||
|
an [issue](https://github.com/mthom/scryer-prolog/issues).
|
||||||
|
|
||||||
|
To get in touch with the Scryer Prolog community, participate in
|
||||||
|
[discussions](https://github.com/mthom/scryer-prolog/discussions)
|
||||||
|
or visit our #scryer IRC channel on [Libera](https://libera.chat)!
|
||||||
35
_typos.toml
Normal file
35
_typos.toml
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
# config for https://github.com/crate-ci/typos
|
||||||
|
|
||||||
|
[default]
|
||||||
|
# example from https://github.com/crate-ci/typos/blob/master/docs/reference.md#example-configurations
|
||||||
|
extend-ignore-re = [
|
||||||
|
"(#|//)\\s*spellchecker:ignore-next-line\\n.*"
|
||||||
|
]
|
||||||
|
|
||||||
|
# correct word key to value
|
||||||
|
# can be used to ignore a typo by adding an entry <typo> = "<typo>"
|
||||||
|
[default.extend-words]
|
||||||
|
|
||||||
|
# correct identifier key to value
|
||||||
|
# can be used to ignore a typo by adding an entry <typo> = "<typo>"
|
||||||
|
[default.extend-identifiers]
|
||||||
|
interm = "interm"
|
||||||
|
IntermReg = "IntermReg"
|
||||||
|
|
||||||
|
[type.rust]
|
||||||
|
extend-glob = [ "*.rs" ]
|
||||||
|
[type.rust.extend-identifiers]
|
||||||
|
consts = "consts" # std::{f32,f64}::consts
|
||||||
|
|
||||||
|
|
||||||
|
[type.prolog]
|
||||||
|
extend-glob = ["*.pl"]
|
||||||
|
check-file = false
|
||||||
|
|
||||||
|
[type.stdout]
|
||||||
|
extend-glob = ["*.stdout"]
|
||||||
|
check-file = false
|
||||||
|
|
||||||
|
|
||||||
|
[files]
|
||||||
|
extend-exclude = ["lib_integration_test_commands.txt"]
|
||||||
95
benches/README.md
Normal file
95
benches/README.md
Normal file
@@ -0,0 +1,95 @@
|
|||||||
|
# About benches
|
||||||
|
|
||||||
|
The `benches` directory contains benchmarks that test scryer-prolog performance.
|
||||||
|
|
||||||
|
Benchmarks are run via two harnesses:
|
||||||
|
|
||||||
|
* `criterion` - criterion performs statistical analysis of benchmark runs and is
|
||||||
|
great for benchmarking locally.
|
||||||
|
* `iai-callgrind` - this runs the benchmark with callgrind, which is able to
|
||||||
|
precisely track the number of instructions executed during the run. This is
|
||||||
|
especially helpful in a public CI runner context where neighboring VMs can
|
||||||
|
cause a very high wall time variance. While instructions executed is only
|
||||||
|
correlated with the desired metric (wall time), this is a good tradeoff for CI
|
||||||
|
where that metric is unreliable.
|
||||||
|
|
||||||
|
Run benchmarks with the following commands:
|
||||||
|
|
||||||
|
```
|
||||||
|
cargo bench --bench run_criterion
|
||||||
|
|
||||||
|
# run a particular criterion benchmark
|
||||||
|
cargo bench --bench run_criterion -- <benchmark_name>
|
||||||
|
|
||||||
|
# run in profiling mode which outputs flamegraphs. Set profile time in seconds:
|
||||||
|
cargo bench --bench run_criterion -- --profile-time <time>
|
||||||
|
|
||||||
|
# to run iai, you need valgrind installed and to install iai-callgrind-runner
|
||||||
|
# at the same version as is in Cargo.toml:
|
||||||
|
cargo install iai-callgrind-runner --version 0.7.3
|
||||||
|
|
||||||
|
cargo bench --bench run_iai
|
||||||
|
```
|
||||||
|
|
||||||
|
For consistency, both runners -- `run_iai.rs` and `run_criterion.rs` -- import
|
||||||
|
the same setup code from `setup.rs`.
|
||||||
|
|
||||||
|
## Setup
|
||||||
|
|
||||||
|
`setup.rs` contains the setup code to run benchmarks. `fn prolog_benches()` at
|
||||||
|
the top of the file is where the benchmarks are defined.
|
||||||
|
|
||||||
|
Benchmarks are organized around running queries against a prolog module file.
|
||||||
|
Before a benchmark starts, `benchmark.setup()` is called which reads the module
|
||||||
|
file and initializes a new `scryer_prolog::machine::Machine`.
|
||||||
|
|
||||||
|
Each benchmark measurement is done by running a query against the machine. In
|
||||||
|
the case of criterion each query is run many times, in the case of iai it's run
|
||||||
|
once.
|
||||||
|
|
||||||
|
## Adding benchmarks
|
||||||
|
|
||||||
|
This design is meant to support defining lots of benchmarks.
|
||||||
|
|
||||||
|
To add a new benchmark:
|
||||||
|
|
||||||
|
* Add a new file `benches/[module].pl` that contains setup prolog code. Import
|
||||||
|
libraries, define predicates, etc.
|
||||||
|
* Add a new section in `setup.rs::prolog_benchmarks()` that refers to to the
|
||||||
|
file and write a query to be benchmarked.
|
||||||
|
* If the query mutates the machine, then use `Strategy::Fresh` so the criterion
|
||||||
|
benchmark will recreate a new machine for each benchmark run, otherwise use
|
||||||
|
`Strategy::Reuse` which has lower overhead. (This is not used by the iai
|
||||||
|
benchmark because it only runs once anyway.)
|
||||||
|
|
||||||
|
Some tips:
|
||||||
|
|
||||||
|
* The goal of benchmarking is to know if a library or engine change improved
|
||||||
|
performance or not.
|
||||||
|
* Once a benchmark is defined and named, avoid changing it's definition. If a
|
||||||
|
benchmark needs to change to be more useful, give the new definition a new
|
||||||
|
name instead. This will prevent charts from showing wild changes in
|
||||||
|
performance just because the definition changed (see previous).
|
||||||
|
* Aim for queries to execute in less than 0.5s realtime. Longer runtimes make it
|
||||||
|
easier for humans to see big differences, but benchmarks either run 10x slower
|
||||||
|
(iai) or execute repeatedly to attain statistical significance (criterion) and
|
||||||
|
in both cases benchmarking queries that take longer than about 0.5s are
|
||||||
|
cumbersome to run.
|
||||||
|
* Consider that the library runtime actually parses the text output of the top
|
||||||
|
level. So don't use custom outputs or it will fail to parse. Also keep the
|
||||||
|
output small so it doesn't just benchmark the output parsing code.
|
||||||
|
* DO test the output of the benchmark run, we don't want to count broken
|
||||||
|
benchmarks.
|
||||||
|
|
||||||
|
## CI
|
||||||
|
|
||||||
|
Both benchmark harnesses are run in `.github/workflows/ci.yaml` in the `report`
|
||||||
|
job, and the results are published as build artifacts.
|
||||||
|
|
||||||
|
## Todo
|
||||||
|
|
||||||
|
- [ ] Currently, the execution time to load a module is not benchmarked. It
|
||||||
|
would be nice to have at least one benchmark for loading a module (probably a
|
||||||
|
big one).
|
||||||
|
- [ ] Write a new action that downloads the test and benchmark results
|
||||||
|
artifacts, plots them over time, and publishes a report to github pages.
|
||||||
41
benches/csv.pl
Normal file
41
benches/csv.pl
Normal file
File diff suppressed because one or more lines are too long
130
benches/edges.pl
Normal file
130
benches/edges.pl
Normal file
@@ -0,0 +1,130 @@
|
|||||||
|
:- use_module(library(clpb)).
|
||||||
|
:- use_module(library(assoc)).
|
||||||
|
:- use_module(library(lists)).
|
||||||
|
:- use_module(library(pairs)).
|
||||||
|
|
||||||
|
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
Contiguous United States and DC as they appear in SGB:
|
||||||
|
http://www-cs-faculty.stanford.edu/~uno/sgb.html
|
||||||
|
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||||
|
|
||||||
|
edge(al, fl).
|
||||||
|
edge(al, ga).
|
||||||
|
edge(al, ms).
|
||||||
|
edge(al, tn).
|
||||||
|
edge(ar, la).
|
||||||
|
edge(ar, mo).
|
||||||
|
edge(ar, ms).
|
||||||
|
edge(ar, ok).
|
||||||
|
edge(ar, tn).
|
||||||
|
edge(ar, tx).
|
||||||
|
edge(az, ca).
|
||||||
|
edge(az, nm).
|
||||||
|
edge(az, nv).
|
||||||
|
edge(az, ut).
|
||||||
|
edge(ca, nv).
|
||||||
|
edge(ca, or).
|
||||||
|
edge(co, ks).
|
||||||
|
edge(co, ne).
|
||||||
|
edge(co, nm).
|
||||||
|
edge(co, ok).
|
||||||
|
edge(co, ut).
|
||||||
|
edge(co, wy).
|
||||||
|
edge(ct, ma).
|
||||||
|
edge(ct, ny).
|
||||||
|
edge(ct, ri).
|
||||||
|
edge(dc, md).
|
||||||
|
edge(dc, va).
|
||||||
|
edge(de, md).
|
||||||
|
edge(de, nj).
|
||||||
|
edge(de, pa).
|
||||||
|
edge(fl, ga).
|
||||||
|
edge(ga, nc).
|
||||||
|
edge(ga, sc).
|
||||||
|
edge(ga, tn).
|
||||||
|
edge(ia, il).
|
||||||
|
edge(ia, mn).
|
||||||
|
edge(ia, mo).
|
||||||
|
edge(ia, ne).
|
||||||
|
edge(ia, sd).
|
||||||
|
edge(ia, wi).
|
||||||
|
edge(id, mt).
|
||||||
|
edge(id, nv).
|
||||||
|
edge(id, or).
|
||||||
|
edge(id, ut).
|
||||||
|
edge(id, wa).
|
||||||
|
edge(id, wy).
|
||||||
|
edge(il, in).
|
||||||
|
edge(il, ky).
|
||||||
|
edge(il, mo).
|
||||||
|
edge(il, wi).
|
||||||
|
edge(in, ky).
|
||||||
|
edge(in, mi).
|
||||||
|
edge(in, oh).
|
||||||
|
edge(ks, mo).
|
||||||
|
edge(ks, ne).
|
||||||
|
edge(ks, ok).
|
||||||
|
edge(ky, mo).
|
||||||
|
edge(ky, oh).
|
||||||
|
edge(ky, tn).
|
||||||
|
edge(ky, va).
|
||||||
|
edge(ky, wv).
|
||||||
|
edge(la, ms).
|
||||||
|
edge(la, tx).
|
||||||
|
edge(ma, nh).
|
||||||
|
edge(ma, ny).
|
||||||
|
edge(ma, ri).
|
||||||
|
edge(ma, vt).
|
||||||
|
edge(md, pa).
|
||||||
|
edge(md, va).
|
||||||
|
edge(md, wv).
|
||||||
|
edge(me, nh).
|
||||||
|
edge(mi, oh).
|
||||||
|
edge(mi, wi).
|
||||||
|
edge(mn, nd).
|
||||||
|
edge(mn, sd).
|
||||||
|
edge(mn, wi).
|
||||||
|
edge(mo, ne).
|
||||||
|
edge(mo, ok).
|
||||||
|
edge(mo, tn).
|
||||||
|
edge(ms, tn).
|
||||||
|
edge(mt, nd).
|
||||||
|
edge(mt, sd).
|
||||||
|
edge(mt, wy).
|
||||||
|
edge(nc, sc).
|
||||||
|
edge(nc, tn).
|
||||||
|
edge(nc, va).
|
||||||
|
edge(nd, sd).
|
||||||
|
edge(ne, sd).
|
||||||
|
edge(ne, wy).
|
||||||
|
edge(nh, vt).
|
||||||
|
edge(nj, ny).
|
||||||
|
edge(nj, pa).
|
||||||
|
edge(nm, ok).
|
||||||
|
edge(nm, tx).
|
||||||
|
edge(nv, or).
|
||||||
|
edge(nv, ut).
|
||||||
|
edge(ny, pa).
|
||||||
|
edge(ny, vt).
|
||||||
|
edge(oh, pa).
|
||||||
|
edge(oh, wv).
|
||||||
|
edge(ok, tx).
|
||||||
|
edge(or, wa).
|
||||||
|
edge(pa, wv).
|
||||||
|
edge(sd, wy).
|
||||||
|
edge(tn, va).
|
||||||
|
edge(ut, wy).
|
||||||
|
edge(va, wv).
|
||||||
|
|
||||||
|
independent_set(G, *(NBs)) :-
|
||||||
|
findall(U-V, (edge(U, V),G@<U), Edges),
|
||||||
|
setof(U, V^(member(U-V, Edges);member(V-U, Edges)), Nodes),
|
||||||
|
pairs_keys_values(Pairs, Nodes, _),
|
||||||
|
list_to_assoc(Pairs, Assoc),
|
||||||
|
maplist(not_both(Assoc), Edges, NBs).
|
||||||
|
|
||||||
|
not_both(Assoc, U-V, ~BU + ~BV) :-
|
||||||
|
get_assoc(U, Assoc, BU),
|
||||||
|
get_assoc(V, Assoc, BV).
|
||||||
|
|
||||||
|
independent_set_count(G, Count) :- independent_set(G, Sat), sat_count(Sat, Count).
|
||||||
2
benches/numlist.pl
Normal file
2
benches/numlist.pl
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
:- use_module(library(between)).
|
||||||
|
run_numlist(Upper, Head) :- numlist(1, Upper, L), L = [Head|_].
|
||||||
46
benches/run_criterion.rs
Normal file
46
benches/run_criterion.rs
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
#[cfg(not(all(target_arch = "wasm32", target_os = "unknown")))]
|
||||||
|
use criterion::{BatchSize, Criterion, criterion_group, criterion_main};
|
||||||
|
|
||||||
|
#[cfg(not(all(target_arch = "wasm32", target_os = "unknown")))]
|
||||||
|
#[cfg(not(target_os = "windows"))]
|
||||||
|
use pprof::criterion::{Output, PProfProfiler};
|
||||||
|
|
||||||
|
#[cfg(not(all(target_arch = "wasm32", target_os = "unknown")))]
|
||||||
|
mod setup;
|
||||||
|
|
||||||
|
#[cfg(not(all(target_arch = "wasm32", target_os = "unknown")))]
|
||||||
|
fn bench_criterion(c: &mut Criterion) {
|
||||||
|
for (&name, bench) in setup::prolog_benches().iter() {
|
||||||
|
match bench.strategy {
|
||||||
|
setup::Strategy::Fresh => c.bench_function(name, |b| {
|
||||||
|
b.iter_batched(|| bench.setup(), |mut r| r(), BatchSize::LargeInput)
|
||||||
|
}),
|
||||||
|
setup::Strategy::Reuse => c.bench_function(name, |b| b.iter(bench.setup())),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[cfg(not(all(target_arch = "wasm32", target_os = "unknown")))]
|
||||||
|
#[cfg(not(target_os = "windows"))]
|
||||||
|
fn config() -> Criterion {
|
||||||
|
Criterion::default()
|
||||||
|
.sample_size(20)
|
||||||
|
.with_profiler(PProfProfiler::new(100, Output::Flamegraph(None)))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(target_os = "windows")]
|
||||||
|
fn config() -> Criterion {
|
||||||
|
Criterion::default().sample_size(20)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(all(target_arch = "wasm32", target_os = "unknown")))]
|
||||||
|
criterion_group!(
|
||||||
|
name = benches;
|
||||||
|
config = config();
|
||||||
|
targets = bench_criterion
|
||||||
|
);
|
||||||
|
|
||||||
|
#[cfg(not(all(target_arch = "wasm32", target_os = "unknown")))]
|
||||||
|
criterion_main!(benches);
|
||||||
|
|
||||||
|
#[cfg(all(target_arch = "wasm32", target_os = "unknown"))]
|
||||||
|
fn main() {}
|
||||||
38
benches/run_iai.rs
Normal file
38
benches/run_iai.rs
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
#[cfg(not(all(target_arch = "wasm32", target_os = "unknown")))]
|
||||||
|
mod setup;
|
||||||
|
|
||||||
|
#[cfg(not(all(target_arch = "wasm32", target_os = "unknown")))]
|
||||||
|
mod iai {
|
||||||
|
use iai_callgrind::{library_benchmark, library_benchmark_group, main};
|
||||||
|
|
||||||
|
use scryer_prolog::LeafAnswer;
|
||||||
|
|
||||||
|
use super::setup;
|
||||||
|
|
||||||
|
#[library_benchmark]
|
||||||
|
#[bench::count_edges(setup::prolog_benches()["count_edges"].setup())]
|
||||||
|
#[bench::numlist(setup::prolog_benches()["numlist"].setup())]
|
||||||
|
#[bench::csv_codename(setup::prolog_benches()["csv_codename"].setup())]
|
||||||
|
fn bench(mut run: impl FnMut() -> Vec<LeafAnswer>) -> Vec<LeafAnswer> {
|
||||||
|
run()
|
||||||
|
}
|
||||||
|
|
||||||
|
library_benchmark_group!(
|
||||||
|
name = benches;
|
||||||
|
benchmarks = bench
|
||||||
|
);
|
||||||
|
|
||||||
|
main!(library_benchmark_groups = benches);
|
||||||
|
|
||||||
|
pub fn call_main() {
|
||||||
|
main()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(all(target_arch = "wasm32", target_os = "unknown")))]
|
||||||
|
fn main() {
|
||||||
|
iai::call_main();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(all(target_arch = "wasm32", target_os = "unknown"))]
|
||||||
|
fn main() {}
|
||||||
140
benches/setup.rs
Normal file
140
benches/setup.rs
Normal file
@@ -0,0 +1,140 @@
|
|||||||
|
use std::{collections::BTreeMap, fs, path::Path};
|
||||||
|
|
||||||
|
use maplit::btreemap;
|
||||||
|
use scryer_prolog::{LeafAnswer, Machine, MachineBuilder, Term};
|
||||||
|
|
||||||
|
pub fn prolog_benches() -> BTreeMap<&'static str, PrologBenchmark> {
|
||||||
|
[
|
||||||
|
(
|
||||||
|
"count_edges", // name of the benchmark
|
||||||
|
"benches/edges.pl", // name of the prolog module file to load. use the same file in multiple benchmarks
|
||||||
|
"independent_set_count(ky, Count).", // query to benchmark in the context of the loaded module. consider making the query adjustable to tune the run time to ~0.1s
|
||||||
|
Strategy::Reuse,
|
||||||
|
btreemap! { "Count" => Term::integer(2869176) },
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"numlist",
|
||||||
|
"benches/numlist.pl",
|
||||||
|
"run_numlist(1000000, Head).",
|
||||||
|
Strategy::Reuse,
|
||||||
|
btreemap! { "Head" => Term::integer(1) },
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"csv_codename",
|
||||||
|
"benches/csv.pl",
|
||||||
|
"get_codename(\"0020\",Name).",
|
||||||
|
Strategy::Reuse,
|
||||||
|
btreemap! { "Name" => Term::string("SPACE") },
|
||||||
|
),
|
||||||
|
]
|
||||||
|
.map(|b| {
|
||||||
|
(
|
||||||
|
b.0,
|
||||||
|
PrologBenchmark {
|
||||||
|
name: b.0,
|
||||||
|
filename: b.1,
|
||||||
|
query: b.2,
|
||||||
|
strategy: b.3,
|
||||||
|
bindings: b.4,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.into()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum Strategy {
|
||||||
|
#[allow(dead_code)]
|
||||||
|
Fresh,
|
||||||
|
Reuse,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub struct PrologBenchmark {
|
||||||
|
pub name: &'static str,
|
||||||
|
pub filename: &'static str,
|
||||||
|
pub query: &'static str,
|
||||||
|
pub strategy: Strategy,
|
||||||
|
pub bindings: BTreeMap<&'static str, Term>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PrologBenchmark {
|
||||||
|
pub fn make_machine(&self) -> Machine {
|
||||||
|
let program = fs::read_to_string(self.filename).unwrap();
|
||||||
|
let module_name = Path::new(self.filename)
|
||||||
|
.file_stem()
|
||||||
|
.and_then(|s| s.to_str())
|
||||||
|
.unwrap();
|
||||||
|
let mut machine = MachineBuilder::default().build();
|
||||||
|
machine.load_module_string(module_name, program);
|
||||||
|
machine
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(all(target_arch = "wasm32", target_os = "unknown")))]
|
||||||
|
pub fn setup(&self) -> impl FnMut() -> Vec<LeafAnswer> + use<> {
|
||||||
|
let mut machine = self.make_machine();
|
||||||
|
let query = self.query;
|
||||||
|
move || {
|
||||||
|
use criterion::black_box;
|
||||||
|
black_box(
|
||||||
|
machine
|
||||||
|
.run_query(black_box(query))
|
||||||
|
.collect::<Result<Vec<_>, _>>()
|
||||||
|
.unwrap(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn validate_benchmarks() {
|
||||||
|
use super::prolog_benches;
|
||||||
|
use scryer_prolog::LeafAnswer;
|
||||||
|
use std::{fmt::Write, fs};
|
||||||
|
|
||||||
|
struct BenchResult {
|
||||||
|
pub name: &'static str,
|
||||||
|
pub setup_inference_count: u64,
|
||||||
|
pub query_inference_count: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut results: Vec<BenchResult> = vec![];
|
||||||
|
|
||||||
|
for (_, r) in prolog_benches() {
|
||||||
|
let mut machine = r.make_machine();
|
||||||
|
let setup_inference_count = machine.get_inference_count();
|
||||||
|
|
||||||
|
let result: Vec<_> = machine
|
||||||
|
.run_query(r.query)
|
||||||
|
.collect::<Result<_, _>>()
|
||||||
|
.unwrap();
|
||||||
|
let query_inference_count = machine.get_inference_count() - setup_inference_count;
|
||||||
|
|
||||||
|
let expected = [LeafAnswer::from_bindings(r.bindings.clone())];
|
||||||
|
assert_eq!(result, expected, "validating benchmark {}", r.name);
|
||||||
|
|
||||||
|
results.push(BenchResult {
|
||||||
|
name: r.name,
|
||||||
|
setup_inference_count,
|
||||||
|
query_inference_count,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut json: String = Default::default();
|
||||||
|
json.push('[');
|
||||||
|
for r in results {
|
||||||
|
json.push('\n');
|
||||||
|
write!(
|
||||||
|
json,
|
||||||
|
r#"{{"name":"{}","setup_inference_count":{},"query_inference_count":{}}},"#,
|
||||||
|
r.name, r.setup_inference_count, r.query_inference_count
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
json.pop(); // trailing comma
|
||||||
|
json.push_str("\n]");
|
||||||
|
fs::write("target/benchmark_inference_counts.json", json).expect("Unable to write file");
|
||||||
|
}
|
||||||
|
}
|
||||||
56
build.rs
56
build.rs
@@ -1,56 +0,0 @@
|
|||||||
extern crate indexmap;
|
|
||||||
|
|
||||||
use indexmap::IndexSet;
|
|
||||||
|
|
||||||
use std::env;
|
|
||||||
use std::fs::{File, copy, read_dir};
|
|
||||||
use std::io::Write;
|
|
||||||
use std::path::Path;
|
|
||||||
|
|
||||||
fn main()
|
|
||||||
{
|
|
||||||
let out_dir = env::var("OUT_DIR").unwrap();
|
|
||||||
let dest_path = Path::new(&out_dir).join("libraries.rs");
|
|
||||||
|
|
||||||
let mut libraries = File::create(&dest_path).unwrap();
|
|
||||||
let mut library_index = IndexSet::new();
|
|
||||||
|
|
||||||
let paths = read_dir("./src/prolog/lib").unwrap();
|
|
||||||
|
|
||||||
for item in paths {
|
|
||||||
let item = item.unwrap().path();
|
|
||||||
|
|
||||||
if let Some(file_name) = item.file_name() {
|
|
||||||
if let Some(ext) = item.extension() {
|
|
||||||
if ext == "pl" {
|
|
||||||
let file_stem = item.file_stem().unwrap();
|
|
||||||
let file_str = file_stem.to_string_lossy().to_uppercase();
|
|
||||||
let dest = Path::new(&out_dir).join(file_name);
|
|
||||||
|
|
||||||
match copy(&item, dest) {
|
|
||||||
Ok(_) => {},
|
|
||||||
Err(e) => panic!("die: {:?}", e)
|
|
||||||
};
|
|
||||||
|
|
||||||
let include_line = format!("static {}: &str = include_str!(\"{}.pl\");\n",
|
|
||||||
file_str, file_stem.to_string_lossy());
|
|
||||||
|
|
||||||
libraries.write_all(include_line.as_bytes()).unwrap();
|
|
||||||
library_index.insert(file_stem.to_string_lossy().to_string());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
libraries.write_all(b"\nref_thread_local! {
|
|
||||||
pub static managed LIBRARIES: IndexMap<&'static str, &'static str> = {
|
|
||||||
let mut m = IndexMap::new();\n").unwrap();
|
|
||||||
|
|
||||||
for item in library_index {
|
|
||||||
let line = format!("\n m.insert(\"{}\", {});", item, item.to_uppercase());
|
|
||||||
libraries.write_all(line.as_bytes()).unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
libraries.write_all(b"\n\n m\n };
|
|
||||||
}").unwrap();
|
|
||||||
}
|
|
||||||
2045
build/instructions_template.rs
Normal file
2045
build/instructions_template.rs
Normal file
File diff suppressed because it is too large
Load Diff
121
build/main.rs
Normal file
121
build/main.rs
Normal file
@@ -0,0 +1,121 @@
|
|||||||
|
mod instructions_template;
|
||||||
|
mod static_string_indexing;
|
||||||
|
|
||||||
|
use instructions_template::generate_instructions_rs;
|
||||||
|
use static_string_indexing::index_static_strings;
|
||||||
|
|
||||||
|
use std::collections::BTreeMap;
|
||||||
|
use std::env;
|
||||||
|
use std::fs::File;
|
||||||
|
use std::io::Write;
|
||||||
|
use std::path::MAIN_SEPARATOR_STR;
|
||||||
|
use std::path::Path;
|
||||||
|
use std::path::PathBuf;
|
||||||
|
use std::process::{Command, Stdio};
|
||||||
|
|
||||||
|
fn find_prolog_files(path_prefix: &str, current_dir: &Path) -> Vec<(String, PathBuf)> {
|
||||||
|
// use a BTreeMap to get a stable order independent of fs enumeration order
|
||||||
|
let mut libraries = BTreeMap::new();
|
||||||
|
|
||||||
|
let entries = match current_dir.read_dir() {
|
||||||
|
Ok(entries) => entries,
|
||||||
|
Err(_) => return vec![],
|
||||||
|
};
|
||||||
|
|
||||||
|
for entry in entries.filter_map(Result::ok).map(|e| e.path()) {
|
||||||
|
if entry.is_dir() {
|
||||||
|
if let Some(file_name) = entry.file_name() {
|
||||||
|
let file_name = file_name.to_str().unwrap();
|
||||||
|
let new_path_prefix = format!("{path_prefix}{file_name}/");
|
||||||
|
let new_libs = find_prolog_files(&new_path_prefix, &entry);
|
||||||
|
libraries.extend(new_libs);
|
||||||
|
}
|
||||||
|
} else if entry.is_file() {
|
||||||
|
let ext = std::ffi::OsStr::new("pl");
|
||||||
|
if entry.extension() == Some(ext) {
|
||||||
|
let name = entry.file_stem().unwrap().to_str().unwrap();
|
||||||
|
let lib_name = format!("{path_prefix}{name}");
|
||||||
|
|
||||||
|
libraries.insert(lib_name, entry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
libraries.into_iter().collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let has_rustfmt = Command::new("rustfmt")
|
||||||
|
.arg("--version")
|
||||||
|
.stdin(Stdio::inherit())
|
||||||
|
.status()
|
||||||
|
.is_ok();
|
||||||
|
|
||||||
|
if !has_rustfmt {
|
||||||
|
println!("Failed to run rustfmt, will skip formatting generated files.")
|
||||||
|
}
|
||||||
|
|
||||||
|
let out_dir = env::var("OUT_DIR").unwrap();
|
||||||
|
let dest_path = Path::new(&out_dir).join("libraries.rs");
|
||||||
|
|
||||||
|
let mut libraries = File::create(dest_path).unwrap();
|
||||||
|
let lib_path = Path::new("src").join("lib");
|
||||||
|
|
||||||
|
let constants = find_prolog_files("", &lib_path);
|
||||||
|
|
||||||
|
let out_dir = std::env::var("OUT_DIR").unwrap();
|
||||||
|
|
||||||
|
writeln!(libraries, "{{").unwrap();
|
||||||
|
for (name, lib_path) in constants {
|
||||||
|
let path = format!("{}{}", MAIN_SEPARATOR_STR, lib_path.display());
|
||||||
|
writeln!(
|
||||||
|
libraries,
|
||||||
|
"m.insert(\"{name}\", include_str!(concat!(env!(\"CARGO_MANIFEST_DIR\"), {path:?})));"
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
writeln!(libraries, "}}").unwrap();
|
||||||
|
|
||||||
|
let instructions_path = Path::new(&out_dir).join("instructions.rs");
|
||||||
|
let mut instructions_file = File::create(&instructions_path).unwrap();
|
||||||
|
|
||||||
|
let quoted_output = generate_instructions_rs();
|
||||||
|
|
||||||
|
instructions_file
|
||||||
|
.write_all(quoted_output.to_string().as_bytes())
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
if has_rustfmt {
|
||||||
|
format_generated_file(instructions_path.as_path());
|
||||||
|
}
|
||||||
|
|
||||||
|
let static_atoms_path = Path::new(&out_dir).join("static_atoms.rs");
|
||||||
|
let mut static_atoms_file = File::create(&static_atoms_path).unwrap();
|
||||||
|
|
||||||
|
let quoted_output = index_static_strings(&instructions_path);
|
||||||
|
|
||||||
|
static_atoms_file
|
||||||
|
.write_all(quoted_output.to_string().as_bytes())
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
if has_rustfmt {
|
||||||
|
format_generated_file(static_atoms_path.as_path());
|
||||||
|
}
|
||||||
|
|
||||||
|
println!("cargo:rerun-if-changed=src/");
|
||||||
|
}
|
||||||
|
|
||||||
|
fn format_generated_file(path: &Path) {
|
||||||
|
Command::new("rustfmt")
|
||||||
|
.arg(path.as_os_str())
|
||||||
|
.spawn()
|
||||||
|
.unwrap_or_else(|err| {
|
||||||
|
panic!(
|
||||||
|
"{}: rustfmt was detected as available, but failed to format generated file '{}'",
|
||||||
|
err,
|
||||||
|
path.display()
|
||||||
|
);
|
||||||
|
})
|
||||||
|
.wait()
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
207
build/static_string_indexing.rs
Normal file
207
build/static_string_indexing.rs
Normal file
@@ -0,0 +1,207 @@
|
|||||||
|
use std::collections::BTreeSet;
|
||||||
|
|
||||||
|
use proc_macro2::TokenStream;
|
||||||
|
use syn::parse::*;
|
||||||
|
use syn::visit::*;
|
||||||
|
use syn::*;
|
||||||
|
|
||||||
|
struct StaticStrVisitor {
|
||||||
|
static_strs: BTreeSet<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl StaticStrVisitor {
|
||||||
|
fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
static_strs: BTreeSet::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct MacroFnArgs {
|
||||||
|
args: Vec<Expr>,
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ReadHeapCellExprAndArms {
|
||||||
|
expr: Expr,
|
||||||
|
arms: Vec<Arm>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Parse for ReadHeapCellExprAndArms {
|
||||||
|
fn parse(input: ParseStream) -> Result<Self> {
|
||||||
|
let mut arms = vec![];
|
||||||
|
let expr = input.parse()?;
|
||||||
|
|
||||||
|
input.parse::<Token![,]>()?;
|
||||||
|
arms.push(input.parse()?);
|
||||||
|
|
||||||
|
while !input.is_empty() {
|
||||||
|
let _ = input.parse::<Token![,]>();
|
||||||
|
arms.push(input.parse()?);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(ReadHeapCellExprAndArms { expr, arms })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Parse for MacroFnArgs {
|
||||||
|
fn parse(input: ParseStream) -> Result<Self> {
|
||||||
|
let mut args = vec![];
|
||||||
|
|
||||||
|
if !input.is_empty() {
|
||||||
|
args.push(input.parse()?);
|
||||||
|
}
|
||||||
|
|
||||||
|
while !input.is_empty() {
|
||||||
|
let _ = input.parse::<Token![,]>();
|
||||||
|
args.push(input.parse()?);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(MacroFnArgs { args })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'ast> Visit<'ast> for StaticStrVisitor {
|
||||||
|
fn visit_macro(&mut self, m: &'ast Macro) {
|
||||||
|
let Macro { path, .. } = m;
|
||||||
|
|
||||||
|
if path.is_ident("atom") {
|
||||||
|
if let Ok(Lit::Str(string)) = m.parse_body::<Lit>() {
|
||||||
|
self.static_strs.insert(string.value());
|
||||||
|
}
|
||||||
|
} else if path.is_ident("read_heap_cell") || path.is_ident("match_untyped_arena_ptr") {
|
||||||
|
if let Ok(m) = m.parse_body::<ReadHeapCellExprAndArms>() {
|
||||||
|
self.visit_expr(&m.expr);
|
||||||
|
|
||||||
|
for e in m.arms {
|
||||||
|
self.visit_arm(&e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if let Ok(m) = m.parse_body::<MacroFnArgs>() {
|
||||||
|
for e in m.args {
|
||||||
|
self.visit_expr(&e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const INLINED_ATOM_MAX_LEN: usize = 6;
|
||||||
|
|
||||||
|
fn static_string_index(string: &str, index: usize) -> u64 {
|
||||||
|
if !string.is_empty() && string.len() <= INLINED_ATOM_MAX_LEN && !string.contains('\u{0}') {
|
||||||
|
let mut string_buf: [u8; 8] = [0u8; 8];
|
||||||
|
string_buf[..string.len()].copy_from_slice(string.as_bytes());
|
||||||
|
(u64::from_le_bytes(string_buf) << 1) | 1
|
||||||
|
} else {
|
||||||
|
(index << 1) as u64
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn index_static_strings(instruction_rs_path: &std::path::Path) -> TokenStream {
|
||||||
|
use quote::*;
|
||||||
|
|
||||||
|
use std::ffi::OsStr;
|
||||||
|
use std::fs::File;
|
||||||
|
use std::io::Read;
|
||||||
|
|
||||||
|
use walkdir::WalkDir;
|
||||||
|
|
||||||
|
fn filter_rust_files(e: &walkdir::DirEntry) -> bool {
|
||||||
|
if e.path().is_dir() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
e.path().extension().and_then(OsStr::to_str) == Some("rs")
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut visitor = StaticStrVisitor::new();
|
||||||
|
|
||||||
|
fn process_filepath(path: &std::path::Path) -> std::result::Result<syn::File, ()> {
|
||||||
|
let mut src = String::new();
|
||||||
|
|
||||||
|
let mut file = match File::open(path) {
|
||||||
|
Ok(file) => file,
|
||||||
|
Err(_) => return Err(()),
|
||||||
|
};
|
||||||
|
|
||||||
|
match file.read_to_string(&mut src) {
|
||||||
|
Ok(_) => {}
|
||||||
|
Err(e) => {
|
||||||
|
panic!("error reading file: {e:?}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let syntax = match syn::parse_file(&src) {
|
||||||
|
Ok(s) => s,
|
||||||
|
Err(e) => {
|
||||||
|
println!("cargo::warning=parse error: {e} in file {path:?}");
|
||||||
|
syn::File {
|
||||||
|
shebang: None,
|
||||||
|
attrs: vec![],
|
||||||
|
items: vec![],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
Ok(syntax)
|
||||||
|
}
|
||||||
|
|
||||||
|
for entry in WalkDir::new("src/")
|
||||||
|
.into_iter()
|
||||||
|
.filter_entry(filter_rust_files)
|
||||||
|
{
|
||||||
|
let entry = entry.unwrap();
|
||||||
|
|
||||||
|
if entry.path().is_dir() {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let syntax = match process_filepath(entry.path()) {
|
||||||
|
Ok(syntax) => syntax,
|
||||||
|
Err(_) => continue,
|
||||||
|
};
|
||||||
|
|
||||||
|
visitor.visit_file(&syntax);
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Ok(syntax) = process_filepath(instruction_rs_path) {
|
||||||
|
visitor.visit_file(&syntax)
|
||||||
|
}
|
||||||
|
|
||||||
|
let static_str_keys: Vec<_> = visitor.static_strs.iter().collect();
|
||||||
|
let mut static_strs = Vec::with_capacity(static_str_keys.len());
|
||||||
|
let mut static_str_indices = Vec::with_capacity(static_str_keys.len());
|
||||||
|
|
||||||
|
let indices: Vec<u64> = visitor
|
||||||
|
.static_strs
|
||||||
|
.iter()
|
||||||
|
.map(|string| {
|
||||||
|
let index = static_string_index(string, static_strs.len());
|
||||||
|
|
||||||
|
if index & 1 == 1 {
|
||||||
|
index
|
||||||
|
} else {
|
||||||
|
static_str_indices.push(index);
|
||||||
|
static_strs.push(string);
|
||||||
|
index
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
let static_strs_len = static_strs.len();
|
||||||
|
|
||||||
|
quote! {
|
||||||
|
static STRINGS: [&str; #static_strs_len] = [
|
||||||
|
#(
|
||||||
|
#static_strs,
|
||||||
|
)*
|
||||||
|
];
|
||||||
|
|
||||||
|
macro_rules! atom {
|
||||||
|
#((#static_str_keys) => { Atom { index: #indices } };)*
|
||||||
|
($name:literal) => {compile_error!(concat!("unknown static atom ", $name))};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub static STATIC_ATOMS_MAP: phf::Map<&'static str, Atom> = phf::phf_map! {
|
||||||
|
#(#static_strs => { Atom { index: #static_str_indices } },)*
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
26
clippy.toml
Normal file
26
clippy.toml
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
disallowed-macros = [
|
||||||
|
# https://rust-lang.github.io/rust-clippy/master/#disallowed_macros
|
||||||
|
|
||||||
|
# list of macros that may panic on allocation failure e.g.
|
||||||
|
|
||||||
|
# "std::vec",
|
||||||
|
]
|
||||||
|
|
||||||
|
disallowed-methods = [
|
||||||
|
# https://rust-lang.github.io/rust-clippy/master/#disallowed_method
|
||||||
|
|
||||||
|
# list of methods that may panic on allocation failure
|
||||||
|
# though not including things that can be used correctly by reversing ahead of time (i.e. std::vec::Vec::try_reserve + std::iter::Extend::extend ).
|
||||||
|
|
||||||
|
# "std::iter::Iter::collect",
|
||||||
|
# { path = "std::vec::Vec::with_capacity", replacement = "std::vec::Vec::new + std::vec::Vec::try_reserve" },
|
||||||
|
# { path = "std::string::String::with_capacity", replacement = "std::string::String::new + std::string::String::try_reserve" },
|
||||||
|
]
|
||||||
|
|
||||||
|
disallowed-types = [
|
||||||
|
# https://rust-lang.github.io/rust-clippy/master/#disallowed_types
|
||||||
|
|
||||||
|
# list of types that can't be used without risking a panic due to allocation failure
|
||||||
|
|
||||||
|
# { path = "std::collections::BTreeMap", reason = "unlike Vec and HashMap BTreeMap cannot reserve capacity ahead of time (i.e. try_reserve) making it unusable without risk of oom panic"},
|
||||||
|
]
|
||||||
13
doclog.config.pl
Normal file
13
doclog.config.pl
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
project_name("Scryer Prolog").
|
||||||
|
readme_file("INDEX.dj").
|
||||||
|
source_lib_folder("src/lib").
|
||||||
|
websource("https://github.com/mthom/scryer-prolog/tree/master/src/lib").
|
||||||
|
omit(["ops_and_meta_predicates.pl", "tabling"]).
|
||||||
|
learn_pages_source_folder("learn").
|
||||||
|
learn_pages_categories(["First steps", "Tutorials"]).
|
||||||
|
learn_pages([
|
||||||
|
page("Let's play Brisca", "Tutorials", "lets-play-brisca.dj")
|
||||||
|
]).
|
||||||
|
copy_file("logo/scryer.png", "scryer.png").
|
||||||
|
copy_file("learn/Spanish_deck_Fournier.jpg", "learn/Spanish_deck_Fournier.jpg").
|
||||||
|
copy_file("learn/brisca-interactive.png", "learn/brisca-interactive.png").
|
||||||
82
flake.lock
generated
Normal file
82
flake.lock
generated
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
{
|
||||||
|
"nodes": {
|
||||||
|
"flake-utils": {
|
||||||
|
"inputs": {
|
||||||
|
"systems": "systems"
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1731533236,
|
||||||
|
"narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
|
||||||
|
"owner": "numtide",
|
||||||
|
"repo": "flake-utils",
|
||||||
|
"rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "numtide",
|
||||||
|
"repo": "flake-utils",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nixpkgs": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1744868846,
|
||||||
|
"narHash": "sha256-5RJTdUHDmj12Qsv7XOhuospjAjATNiTMElplWnJE9Hs=",
|
||||||
|
"owner": "NixOS",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"rev": "ebe4301cbd8f81c4f8d3244b3632338bbeb6d49c",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "NixOS",
|
||||||
|
"ref": "nixpkgs-unstable",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"root": {
|
||||||
|
"inputs": {
|
||||||
|
"flake-utils": "flake-utils",
|
||||||
|
"nixpkgs": "nixpkgs",
|
||||||
|
"rust-overlay": "rust-overlay"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"rust-overlay": {
|
||||||
|
"inputs": {
|
||||||
|
"nixpkgs": [
|
||||||
|
"nixpkgs"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1745289264,
|
||||||
|
"narHash": "sha256-7nt+UJ7qaIUe2J7BdnEEph9n2eKEwxUwKS/QIr091uA=",
|
||||||
|
"owner": "oxalica",
|
||||||
|
"repo": "rust-overlay",
|
||||||
|
"rev": "3b7171858c20d5293360042936058fb0c4cb93a9",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "oxalica",
|
||||||
|
"repo": "rust-overlay",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"systems": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1681028828,
|
||||||
|
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
||||||
|
"owner": "nix-systems",
|
||||||
|
"repo": "default",
|
||||||
|
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "nix-systems",
|
||||||
|
"repo": "default",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"root": "root",
|
||||||
|
"version": 7
|
||||||
|
}
|
||||||
85
flake.nix
Normal file
85
flake.nix
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
{
|
||||||
|
description = "A modern Prolog implementation written mostly in Rust";
|
||||||
|
|
||||||
|
inputs = {
|
||||||
|
nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
|
||||||
|
flake-utils.url = "github:numtide/flake-utils";
|
||||||
|
rust-overlay = {
|
||||||
|
url = "github:oxalica/rust-overlay";
|
||||||
|
inputs.nixpkgs.follows = "nixpkgs";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
outputs = { nixpkgs, flake-utils, rust-overlay, ... }:
|
||||||
|
let
|
||||||
|
meta = (builtins.fromTOML (builtins.readFile ./Cargo.toml)).package;
|
||||||
|
inherit (meta) name version;
|
||||||
|
overlays = [
|
||||||
|
(import rust-overlay)
|
||||||
|
(self: super: {
|
||||||
|
rustToolchainDev = super.rust-bin.stable.latest.default.override {
|
||||||
|
extensions = [ "rust-src" "rust-analyzer" ];
|
||||||
|
};
|
||||||
|
rustToolchainDevWasm = super.rust-bin.stable.latest.default.override {
|
||||||
|
extensions = [ "rust-src" "rust-analyzer" ];
|
||||||
|
targets = [ "wasm32-unknown-unknown" ];
|
||||||
|
};
|
||||||
|
rustToolchainNightly = super.rust-bin.selectLatestNightlyWith (toolchain:
|
||||||
|
toolchain.default.override {
|
||||||
|
extensions = [ "rust-src" "rust-analyzer" "miri" ];
|
||||||
|
}
|
||||||
|
);
|
||||||
|
})
|
||||||
|
];
|
||||||
|
in flake-utils.lib.eachDefaultSystem(system:
|
||||||
|
let
|
||||||
|
pkgs = import nixpkgs { inherit system overlays; };
|
||||||
|
nativeBuildInputs = with pkgs; [ pkg-config ];
|
||||||
|
buildInputs = with pkgs; [ openssl ] ++
|
||||||
|
lib.optionals pkgs.stdenv.isDarwin [
|
||||||
|
pkgs.darwin.apple_sdk.frameworks.SystemConfiguration
|
||||||
|
];
|
||||||
|
in
|
||||||
|
{
|
||||||
|
devShells = {
|
||||||
|
default = pkgs.mkShell.override { stdenv = pkgs.clangMultiStdenv; } {
|
||||||
|
nativeBuildInputs = nativeBuildInputs;
|
||||||
|
buildInputs = buildInputs ++ (with pkgs; [
|
||||||
|
rustToolchainDev
|
||||||
|
]);
|
||||||
|
};
|
||||||
|
wasm-js = pkgs.mkShell.override { stdenv = pkgs.clangMultiStdenv; } {
|
||||||
|
nativeBuildInputs = nativeBuildInputs;
|
||||||
|
buildInputs = buildInputs ++ (with pkgs; [
|
||||||
|
wasm-pack
|
||||||
|
rustToolchainDevWasm
|
||||||
|
]);
|
||||||
|
TARGET_CC = "${pkgs.clangMultiStdenv.cc}/bin/clang";
|
||||||
|
hardeningDisable = [ "all" ];
|
||||||
|
};
|
||||||
|
# For use with Miri and stuff like it
|
||||||
|
nightly = pkgs.mkShell {
|
||||||
|
nativeBuildInputs = nativeBuildInputs;
|
||||||
|
buildInputs = buildInputs ++ (with pkgs; [
|
||||||
|
rustToolchainNightly
|
||||||
|
]);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
packages = rec {
|
||||||
|
default = scryer-prolog;
|
||||||
|
scryer-prolog = pkgs.rustPlatform.buildRustPackage {
|
||||||
|
pname = name;
|
||||||
|
inherit version;
|
||||||
|
src = ./.;
|
||||||
|
nativeBuildInputs = nativeBuildInputs;
|
||||||
|
buildInputs = buildInputs;
|
||||||
|
cargoLock = {
|
||||||
|
lockFile = ./Cargo.lock;
|
||||||
|
};
|
||||||
|
release = true;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
BIN
learn/Spanish_deck_Fournier.jpg
Normal file
BIN
learn/Spanish_deck_Fournier.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 629 KiB |
BIN
learn/brisca-interactive.png
Normal file
BIN
learn/brisca-interactive.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 100 KiB |
457
learn/lets-play-brisca.dj
Normal file
457
learn/lets-play-brisca.dj
Normal file
@@ -0,0 +1,457 @@
|
|||||||
|
# Let's play Brisca
|
||||||
|
|
||||||
|
In this article, we'll see how to use modern Prolog to model the game of [Brisca](https://en.wikipedia.org/wiki/Brisca). First things first, what is Brisca?
|
||||||
|
|
||||||
|
## Rules of the game
|
||||||
|
|
||||||
|
Brisca is a traditional card game from Spain, although similar games both in name and in rules are spread across the Mediterranean. It's also similar to Tute. It is played using the traditional Spanish deck, usually with 40 cards in 4 suites (oros, espadas, bastos, copas). Here you have the famous Castillian pattern by Heraclio Fournier, the one I play in my family with my grandparents.
|
||||||
|
|
||||||
|

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

|
||||||
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 |
28
scryer-prolog.wxs
Normal file
28
scryer-prolog.wxs
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
|
||||||
|
<Product Name="Scryer Prolog" Manufacturer="Scryer Prolog contributors" Id="*" UpgradeCode="cfb2dee4-5dd5-4d7d-b426-cd7340810559" Language="1033" Codepage="1252" Version="0.9.0">
|
||||||
|
<Package Description="An open source industrial strength production environment for ISO Prolog that is also a testbed for bleeding edge research in logic and constraint programming, which is itself written in a high-level language." Platform="x64" Keywords="prolog" Id="*" Compressed="yes" InstallScope="perMachine" InstallerVersion="300" Languages="1033" SummaryCodepage="1252" Manufacturer="Scryer Prolog contributors"/>
|
||||||
|
<Property Id="APPHELPLINK" Value="https://github.com/mthom/scryer-prolog"/>
|
||||||
|
<Media Id="1" Cabinet="scryer.cab" EmbedCab="yes" />
|
||||||
|
<Directory Id="TARGETDIR" Name="SourceDir">
|
||||||
|
<Directory Id="ProgramFilesFolder" Name="PFiles">
|
||||||
|
<Directory Id="INSTALLDIR" Name="Scryer Prolog">
|
||||||
|
<Component Id="MainExecutable" Guid="1b41ceda-ba18-47f9-911b-ee41b4f20921">
|
||||||
|
<File Id="ScryerPrologEXE" Name="scryer-prolog.exe" DiskId="1" Source="target/release/scryer-prolog.exe" KeyPath="yes" Checksum="yes"/>
|
||||||
|
</Component>
|
||||||
|
</Directory>
|
||||||
|
</Directory>
|
||||||
|
<Directory Id="ProgramMenuFolder">
|
||||||
|
<Component Id="ApplicationShortcut" Guid="8c9b14a3-e7b1-4d30-a892-61d7371dcae2">
|
||||||
|
<Shortcut Id="ApplicationStarMenuShortcut" Name="Scryer Prolog" Description="Launch Scryer Prolog" Target="[#ScryerPrologEXE]" WorkingDirectory="INSTALLDIR"/>
|
||||||
|
<RemoveFolder Id="ApplicationShortcut" On="uninstall"/>
|
||||||
|
<RegistryValue Root="HKCU" Key="Software\Microsoft\ScryerProlog" Name="installed" Type="integer" Value="1" KeyPath="yes"/>
|
||||||
|
</Component>
|
||||||
|
</Directory>
|
||||||
|
</Directory>
|
||||||
|
<Feature Id="Complete" Level="1" Display="expand" ConfigurableDirectory="INSTALLDIR">
|
||||||
|
<ComponentRef Id="MainExecutable"/>
|
||||||
|
<ComponentRef Id="ApplicationShortcut"/>
|
||||||
|
</Feature>
|
||||||
|
</Product>
|
||||||
|
</Wix>
|
||||||
57
src/allocator.rs
Normal file
57
src/allocator.rs
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
use crate::parser::ast::*;
|
||||||
|
|
||||||
|
use crate::forms::*;
|
||||||
|
use crate::instructions::*;
|
||||||
|
use crate::targets::*;
|
||||||
|
|
||||||
|
use std::cell::Cell;
|
||||||
|
|
||||||
|
pub(crate) trait Allocator {
|
||||||
|
fn new() -> Self;
|
||||||
|
|
||||||
|
fn mark_anon_var<'a, Target: CompilationTarget<'a>>(
|
||||||
|
&mut self,
|
||||||
|
lvl: Level,
|
||||||
|
context: GenContext,
|
||||||
|
code: &mut CodeDeque,
|
||||||
|
) -> RegType;
|
||||||
|
|
||||||
|
fn mark_non_var<'a, Target: CompilationTarget<'a>>(
|
||||||
|
&mut self,
|
||||||
|
lvl: Level,
|
||||||
|
context: GenContext,
|
||||||
|
cell: &'a Cell<RegType>,
|
||||||
|
code: &mut CodeDeque,
|
||||||
|
);
|
||||||
|
|
||||||
|
#[allow(clippy::too_many_arguments)]
|
||||||
|
fn mark_reserved_var<'a, Target: CompilationTarget<'a>>(
|
||||||
|
&mut self,
|
||||||
|
var_num: usize,
|
||||||
|
lvl: Level,
|
||||||
|
cell: &Cell<VarReg>,
|
||||||
|
term_loc: GenContext,
|
||||||
|
code: &mut CodeDeque,
|
||||||
|
r: RegType,
|
||||||
|
is_new_var: bool,
|
||||||
|
);
|
||||||
|
|
||||||
|
fn mark_cut_var(&mut self, var_num: usize, chunk_num: usize) -> RegType;
|
||||||
|
|
||||||
|
fn mark_var<'a, Target: CompilationTarget<'a>>(
|
||||||
|
&mut self,
|
||||||
|
var_num: usize,
|
||||||
|
lvl: Level,
|
||||||
|
cell: &Cell<VarReg>,
|
||||||
|
context: GenContext,
|
||||||
|
code: &mut CodeDeque,
|
||||||
|
);
|
||||||
|
|
||||||
|
fn reset(&mut self);
|
||||||
|
fn reset_arg(&mut self, arg_num: usize);
|
||||||
|
fn reset_at_head(&mut self, args: &[Term]);
|
||||||
|
fn reset_contents(&mut self);
|
||||||
|
|
||||||
|
fn advance_arg(&mut self);
|
||||||
|
fn max_reg_allocated(&self) -> usize;
|
||||||
|
}
|
||||||
897
src/arena.rs
Normal file
897
src/arena.rs
Normal file
@@ -0,0 +1,897 @@
|
|||||||
|
#[cfg(feature = "http")]
|
||||||
|
use crate::http::{HttpListener, HttpResponse};
|
||||||
|
use crate::machine::heap::AllocError;
|
||||||
|
use crate::machine::loader::LiveLoadState;
|
||||||
|
use crate::machine::streams::*;
|
||||||
|
use crate::offset_table::*;
|
||||||
|
use crate::read::*;
|
||||||
|
use crate::types::UntypedArenaPtr;
|
||||||
|
|
||||||
|
use crate::parser::dashu::{Integer, Rational};
|
||||||
|
use ordered_float::OrderedFloat;
|
||||||
|
|
||||||
|
use std::fmt;
|
||||||
|
use std::fmt::Debug;
|
||||||
|
use std::hash::{Hash, Hasher};
|
||||||
|
use std::io::PipeReader;
|
||||||
|
use std::io::PipeWriter;
|
||||||
|
use std::mem;
|
||||||
|
use std::mem::ManuallyDrop;
|
||||||
|
use std::net::TcpListener;
|
||||||
|
use std::ops::{Deref, DerefMut};
|
||||||
|
use std::process::Child;
|
||||||
|
use std::ptr;
|
||||||
|
use std::ptr::NonNull;
|
||||||
|
use std::ptr::addr_of_mut;
|
||||||
|
|
||||||
|
macro_rules! arena_alloc {
|
||||||
|
($e:expr, $arena:expr) => {{
|
||||||
|
let result = $e;
|
||||||
|
$crate::arena::AllocateInArena::arena_allocate(result, $arena)
|
||||||
|
}};
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! float_alloc {
|
||||||
|
($e:expr, $arena:expr) => {{ $arena.f64_tbl.build_with(OrderedFloat($e)) }};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn header_offset_from_payload<T: ?Sized + ArenaAllocated>() -> usize
|
||||||
|
where
|
||||||
|
T::Payload: Sized,
|
||||||
|
{
|
||||||
|
let payload_offset = mem::offset_of!(TypedAllocSlab<T>, payload);
|
||||||
|
let slab_offset = mem::offset_of!(TypedAllocSlab<T>, slab);
|
||||||
|
let header_offset = slab_offset + mem::offset_of!(AllocSlab, header);
|
||||||
|
|
||||||
|
debug_assert!(payload_offset > header_offset);
|
||||||
|
payload_offset - header_offset
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Specifier, Copy, Clone, Debug, PartialEq)]
|
||||||
|
#[bits = 7]
|
||||||
|
pub enum ArenaHeaderTag {
|
||||||
|
Integer = 0b10,
|
||||||
|
Rational = 0b11,
|
||||||
|
LiveLoadState = 0b0001000,
|
||||||
|
InactiveLoadState = 0b1011000,
|
||||||
|
InputFileStream = 0b10000,
|
||||||
|
OutputFileStream = 0b10100,
|
||||||
|
NamedTcpStream = 0b011100,
|
||||||
|
NamedTlsStream = 0b100000,
|
||||||
|
HttpReadStream = 0b100001,
|
||||||
|
HttpWriteStream = 0b100010,
|
||||||
|
ReadlineStream = 0b110000,
|
||||||
|
StaticStringStream = 0b110100,
|
||||||
|
ByteStream = 0b111000,
|
||||||
|
CallbackStream = 0b111001,
|
||||||
|
InputChannelStream = 0b111010,
|
||||||
|
StandardOutputStream = 0b1100,
|
||||||
|
StandardErrorStream = 0b11000,
|
||||||
|
NullStream = 0b111100,
|
||||||
|
TcpListener = 0b1000000,
|
||||||
|
HttpListener = 0b1000001,
|
||||||
|
HttpResponse = 0b1000010,
|
||||||
|
PipeWriter = 0b1000011,
|
||||||
|
Dropped = 0b1000100,
|
||||||
|
PipeReader = 0b1001001,
|
||||||
|
ChildProcess = 0b1001010,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[bitfield]
|
||||||
|
#[repr(align(8))]
|
||||||
|
#[derive(Copy, Clone, Debug)]
|
||||||
|
pub struct ArenaHeader {
|
||||||
|
#[allow(dead_code)]
|
||||||
|
size: B56,
|
||||||
|
m: bool,
|
||||||
|
tag: ArenaHeaderTag,
|
||||||
|
}
|
||||||
|
|
||||||
|
const_assert!(mem::size_of::<ArenaHeader>() == 8);
|
||||||
|
|
||||||
|
impl ArenaHeader {
|
||||||
|
#[inline]
|
||||||
|
pub fn build_with(size: u64, tag: ArenaHeaderTag) -> Self {
|
||||||
|
ArenaHeader::new()
|
||||||
|
.with_size(size)
|
||||||
|
.with_tag(tag)
|
||||||
|
.with_m(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn get_tag(self) -> ArenaHeaderTag {
|
||||||
|
self.tag()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct TypedArenaPtr<T: ?Sized + ArenaAllocated>(ptr::NonNull<T::Payload>);
|
||||||
|
|
||||||
|
impl<T: ?Sized + ArenaAllocated> PartialOrd for TypedArenaPtr<T>
|
||||||
|
where
|
||||||
|
T::Payload: PartialOrd,
|
||||||
|
{
|
||||||
|
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
|
||||||
|
(**self).partial_cmp(&**other)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: ?Sized + ArenaAllocated> PartialEq for TypedArenaPtr<T>
|
||||||
|
where
|
||||||
|
T::Payload: PartialEq,
|
||||||
|
{
|
||||||
|
fn eq(&self, other: &TypedArenaPtr<T>) -> bool {
|
||||||
|
std::ptr::addr_eq(self.0.as_ptr(), other.0.as_ptr()) || **self == **other
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: ?Sized + ArenaAllocated> Eq for TypedArenaPtr<T> where T::Payload: Eq {}
|
||||||
|
|
||||||
|
impl<T: ?Sized + ArenaAllocated> Ord for TypedArenaPtr<T>
|
||||||
|
where
|
||||||
|
T::Payload: Ord,
|
||||||
|
{
|
||||||
|
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
|
||||||
|
(**self).cmp(&**other)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: ?Sized + ArenaAllocated> Hash for TypedArenaPtr<T>
|
||||||
|
where
|
||||||
|
T::Payload: Hash,
|
||||||
|
{
|
||||||
|
#[inline(always)]
|
||||||
|
fn hash<H: Hasher>(&self, hasher: &mut H) {
|
||||||
|
(self as &T::Payload).hash(hasher)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: ?Sized + ArenaAllocated> Clone for TypedArenaPtr<T> {
|
||||||
|
fn clone(&self) -> Self {
|
||||||
|
*self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: ?Sized + ArenaAllocated> Copy for TypedArenaPtr<T> {}
|
||||||
|
|
||||||
|
impl<T: ?Sized + ArenaAllocated> Deref for TypedArenaPtr<T> {
|
||||||
|
type Target = T::Payload;
|
||||||
|
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
unsafe { self.0.as_ref() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: ?Sized + ArenaAllocated> DerefMut for TypedArenaPtr<T> {
|
||||||
|
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||||
|
unsafe { self.0.as_mut() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: ArenaAllocated> fmt::Display for TypedArenaPtr<T>
|
||||||
|
where
|
||||||
|
T::Payload: fmt::Display,
|
||||||
|
{
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
write!(f, "{}", (self as &T::Payload))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: ?Sized + ArenaAllocated> TypedArenaPtr<T> {
|
||||||
|
#[inline]
|
||||||
|
pub fn as_ptr(&self) -> *mut T::Payload {
|
||||||
|
self.0.as_ptr()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<P, T: ?Sized + ArenaAllocated<Payload = ManuallyDrop<P>>> TypedArenaPtr<T> {
|
||||||
|
pub fn drop_payload(&mut self) {
|
||||||
|
if self.get_tag() != ArenaHeaderTag::Dropped {
|
||||||
|
self.set_tag(ArenaHeaderTag::Dropped);
|
||||||
|
unsafe { ManuallyDrop::drop(&mut *self.as_ptr()) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: ?Sized + ArenaAllocated> TypedArenaPtr<T>
|
||||||
|
where
|
||||||
|
T::Payload: Sized,
|
||||||
|
{
|
||||||
|
#[inline]
|
||||||
|
pub fn header_ptr(&self) -> *const ArenaHeader {
|
||||||
|
unsafe { self.as_ptr().byte_sub(T::header_offset_from_payload()) as *const _ }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn header_ptr_mut(&mut self) -> *mut ArenaHeader {
|
||||||
|
unsafe { self.as_ptr().byte_sub(T::header_offset_from_payload()) as *mut _ }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn get_mark_bit(&self) -> bool {
|
||||||
|
unsafe { (*self.header_ptr()).m() }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn set_tag(&mut self, tag: ArenaHeaderTag) {
|
||||||
|
unsafe {
|
||||||
|
(*self.header_ptr_mut()).set_tag(tag);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn get_tag(&self) -> ArenaHeaderTag {
|
||||||
|
unsafe { (*self.header_ptr()).get_tag() }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn mark(&mut self) {
|
||||||
|
unsafe {
|
||||||
|
(*self.header_ptr_mut()).set_m(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn unmark(&mut self) {
|
||||||
|
unsafe {
|
||||||
|
(*self.header_ptr_mut()).set_m(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait AllocateInArena<AllocFor>
|
||||||
|
where
|
||||||
|
AllocFor: ArenaAllocated,
|
||||||
|
{
|
||||||
|
fn arena_allocate(self, arena: &mut Arena) -> TypedArenaPtr<AllocFor>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<P, T: ArenaAllocated<Payload = P>> AllocateInArena<T> for P {
|
||||||
|
fn arena_allocate(self, arena: &mut Arena) -> TypedArenaPtr<T> {
|
||||||
|
T::alloc(arena, self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* this isn't allowed due to https://github.com/rust-lang/rust/issues/20400 I think,
|
||||||
|
though P == ManuallyDrop<P> might also be a problem event though that shouldn't be possible
|
||||||
|
impl<P, T: ArenaAllocated<Payload = ManuallyDrop<P>>> AllocateInArena<T> for P {
|
||||||
|
fn arena_allocate(self, arena: &mut Arena) -> TypedArenaPtr<T> {
|
||||||
|
T::alloc(arena, ManuallyDrop::new(self))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
pub trait ArenaAllocated {
|
||||||
|
type Payload: ?Sized;
|
||||||
|
|
||||||
|
fn tag() -> ArenaHeaderTag;
|
||||||
|
|
||||||
|
fn header_offset_from_payload() -> usize
|
||||||
|
where
|
||||||
|
Self::Payload: Sized,
|
||||||
|
{
|
||||||
|
header_offset_from_payload::<Self>()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// # Safety
|
||||||
|
/// - the caller must guarantee that the pointee type of UntypedArenaPtr is Self
|
||||||
|
/// - the pointer must be non-null
|
||||||
|
unsafe fn typed_ptr(ptr: UntypedArenaPtr) -> TypedArenaPtr<Self>
|
||||||
|
where
|
||||||
|
Self::Payload: Sized,
|
||||||
|
{
|
||||||
|
unsafe {
|
||||||
|
TypedArenaPtr(NonNull::new_unchecked(
|
||||||
|
ptr.get_ptr()
|
||||||
|
.byte_add(Self::header_offset_from_payload())
|
||||||
|
.cast_mut()
|
||||||
|
.cast::<Self::Payload>(),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::missing_safety_doc)]
|
||||||
|
fn alloc(arena: &mut Arena, value: Self::Payload) -> TypedArenaPtr<Self>
|
||||||
|
where
|
||||||
|
Self::Payload: Sized,
|
||||||
|
{
|
||||||
|
let size = mem::size_of::<TypedAllocSlab<Self>>();
|
||||||
|
let slab = Box::new(TypedAllocSlab {
|
||||||
|
slab: AllocSlab {
|
||||||
|
next: arena.base.take(),
|
||||||
|
header: ArenaHeader::build_with(size as u64, Self::tag()),
|
||||||
|
},
|
||||||
|
payload: value,
|
||||||
|
});
|
||||||
|
|
||||||
|
let (allocated_ptr, untyped_slab) = slab.to_untyped();
|
||||||
|
|
||||||
|
arena.base = Some(untyped_slab);
|
||||||
|
|
||||||
|
allocated_ptr
|
||||||
|
}
|
||||||
|
|
||||||
|
/// # Safety
|
||||||
|
/// - ptr points to an allocated slab of the correct kind
|
||||||
|
unsafe fn dealloc(ptr: NonNull<TypedAllocSlab<Self>>) {
|
||||||
|
drop(unsafe { Box::from_raw(ptr.as_ptr()) });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ArenaAllocated for Integer {
|
||||||
|
type Payload = Self;
|
||||||
|
#[inline]
|
||||||
|
fn tag() -> ArenaHeaderTag {
|
||||||
|
ArenaHeaderTag::Integer
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ArenaAllocated for Rational {
|
||||||
|
type Payload = Self;
|
||||||
|
#[inline]
|
||||||
|
fn tag() -> ArenaHeaderTag {
|
||||||
|
ArenaHeaderTag::Rational
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AllocateInArena<LiveLoadState> for LiveLoadState {
|
||||||
|
fn arena_allocate(self, arena: &mut Arena) -> TypedArenaPtr<LiveLoadState> {
|
||||||
|
LiveLoadState::alloc(arena, ManuallyDrop::new(self))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ArenaAllocated for LiveLoadState {
|
||||||
|
type Payload = ManuallyDrop<Self>;
|
||||||
|
#[inline]
|
||||||
|
fn tag() -> ArenaHeaderTag {
|
||||||
|
ArenaHeaderTag::LiveLoadState
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn dealloc(ptr: NonNull<TypedAllocSlab<Self>>) {
|
||||||
|
let mut slab = unsafe { Box::from_raw(ptr.as_ptr()) };
|
||||||
|
|
||||||
|
match slab.tag() {
|
||||||
|
ArenaHeaderTag::LiveLoadState | ArenaHeaderTag::InactiveLoadState => {
|
||||||
|
unsafe { ManuallyDrop::drop(&mut slab.payload) };
|
||||||
|
}
|
||||||
|
ArenaHeaderTag::Dropped => {}
|
||||||
|
_ => {
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
drop(slab);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AllocateInArena<TcpListener> for TcpListener {
|
||||||
|
fn arena_allocate(self, arena: &mut Arena) -> TypedArenaPtr<TcpListener> {
|
||||||
|
TcpListener::alloc(arena, ManuallyDrop::new(self))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ArenaAllocated for TcpListener {
|
||||||
|
type Payload = ManuallyDrop<Self>;
|
||||||
|
#[inline]
|
||||||
|
fn tag() -> ArenaHeaderTag {
|
||||||
|
ArenaHeaderTag::TcpListener
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "http")]
|
||||||
|
impl ArenaAllocated for HttpListener {
|
||||||
|
type Payload = Self;
|
||||||
|
#[inline]
|
||||||
|
fn tag() -> ArenaHeaderTag {
|
||||||
|
ArenaHeaderTag::HttpListener
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "http")]
|
||||||
|
impl ArenaAllocated for HttpResponse {
|
||||||
|
type Payload = Self;
|
||||||
|
#[inline]
|
||||||
|
fn tag() -> ArenaHeaderTag {
|
||||||
|
ArenaHeaderTag::HttpResponse
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ArenaAllocated for Child {
|
||||||
|
type Payload = ManuallyDrop<Self>;
|
||||||
|
#[inline]
|
||||||
|
fn tag() -> ArenaHeaderTag {
|
||||||
|
ArenaHeaderTag::ChildProcess
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl AllocateInArena<Child> for Child {
|
||||||
|
fn arena_allocate(self, arena: &mut Arena) -> TypedArenaPtr<Child> {
|
||||||
|
Child::alloc(arena, ManuallyDrop::new(self))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct AllocSlab {
|
||||||
|
next: Option<UntypedArenaSlab>,
|
||||||
|
header: ArenaHeader,
|
||||||
|
}
|
||||||
|
|
||||||
|
const _: () = {
|
||||||
|
if std::mem::align_of::<AllocSlab>() < std::mem::align_of::<*const ()>() {
|
||||||
|
panic!("alignment of AllocSlab is too low");
|
||||||
|
}
|
||||||
|
|
||||||
|
if std::mem::offset_of!(AllocSlab, header) % std::mem::align_of::<*const ()>() != 0 {
|
||||||
|
panic!("alignment of header not a multiple of pointers alignment");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct TypedAllocSlab<T: ?Sized + ArenaAllocated> {
|
||||||
|
slab: AllocSlab,
|
||||||
|
payload: T::Payload,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: ?Sized + ArenaAllocated> TypedAllocSlab<T> {
|
||||||
|
pub fn tag(&self) -> ArenaHeaderTag {
|
||||||
|
self.slab.header.tag()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn payload(&mut self) -> &mut T::Payload {
|
||||||
|
&mut self.payload
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn to_untyped(self: Box<Self>) -> (TypedArenaPtr<T>, UntypedArenaSlab) {
|
||||||
|
let raw_box = Box::into_raw(self);
|
||||||
|
|
||||||
|
// safety: the pointer from Box::into_raw fulfills addr_of_mut's safety requirements
|
||||||
|
let payload_ptr = unsafe { addr_of_mut!((*raw_box).payload) };
|
||||||
|
|
||||||
|
(
|
||||||
|
TypedArenaPtr(unsafe {
|
||||||
|
// safety: the pointer points into a valid allocation so it is non null
|
||||||
|
ptr::NonNull::new_unchecked(payload_ptr)
|
||||||
|
}),
|
||||||
|
UntypedArenaSlab {
|
||||||
|
// safety: pointer from Box::into_raw is never null
|
||||||
|
slab: unsafe { NonNull::new_unchecked(raw_box.cast::<AllocSlab>()) },
|
||||||
|
tag: T::tag(),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct UntypedArenaSlab {
|
||||||
|
slab: NonNull<AllocSlab>,
|
||||||
|
tag: ArenaHeaderTag,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for UntypedArenaSlab {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
unsafe { drop_slab_in_place(self.slab, self.tag) };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Arena {
|
||||||
|
base: Option<UntypedArenaSlab>,
|
||||||
|
pub f64_tbl: F64Table,
|
||||||
|
pub code_index_tbl: CodeIndexTable,
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe impl Send for Arena {}
|
||||||
|
unsafe impl Sync for Arena {}
|
||||||
|
|
||||||
|
#[allow(clippy::new_without_default)]
|
||||||
|
impl Arena {
|
||||||
|
#[inline]
|
||||||
|
pub fn new() -> Result<Self, AllocError> {
|
||||||
|
Ok(Arena {
|
||||||
|
base: None,
|
||||||
|
f64_tbl: F64Table::new()?,
|
||||||
|
code_index_tbl: CodeIndexTable::new()?,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn drop_slab_in_place(value: NonNull<AllocSlab>, tag: ArenaHeaderTag) {
|
||||||
|
macro_rules! drop_typed_slab_in_place {
|
||||||
|
($payload: ty, $value: expr) => {
|
||||||
|
<$payload as ArenaAllocated>::dealloc($value.cast::<TypedAllocSlab<$payload>>())
|
||||||
|
};
|
||||||
|
}
|
||||||
|
unsafe {
|
||||||
|
match tag {
|
||||||
|
ArenaHeaderTag::Integer => {
|
||||||
|
drop_typed_slab_in_place!(Integer, value);
|
||||||
|
}
|
||||||
|
ArenaHeaderTag::Rational => {
|
||||||
|
drop_typed_slab_in_place!(Rational, value);
|
||||||
|
}
|
||||||
|
ArenaHeaderTag::InputFileStream => {
|
||||||
|
drop_typed_slab_in_place!(InputFileStream, value);
|
||||||
|
}
|
||||||
|
ArenaHeaderTag::OutputFileStream => {
|
||||||
|
drop_typed_slab_in_place!(OutputFileStream, value);
|
||||||
|
}
|
||||||
|
ArenaHeaderTag::NamedTcpStream => {
|
||||||
|
drop_typed_slab_in_place!(NamedTcpStream, value);
|
||||||
|
}
|
||||||
|
ArenaHeaderTag::NamedTlsStream => {
|
||||||
|
#[cfg(feature = "tls")]
|
||||||
|
drop_typed_slab_in_place!(NamedTlsStream, value);
|
||||||
|
}
|
||||||
|
ArenaHeaderTag::HttpReadStream => {
|
||||||
|
#[cfg(feature = "http")]
|
||||||
|
drop_typed_slab_in_place!(HttpReadStream, value);
|
||||||
|
}
|
||||||
|
ArenaHeaderTag::HttpWriteStream => {
|
||||||
|
#[cfg(feature = "http")]
|
||||||
|
drop_typed_slab_in_place!(HttpWriteStream, value);
|
||||||
|
}
|
||||||
|
ArenaHeaderTag::ReadlineStream => {
|
||||||
|
drop_typed_slab_in_place!(ReadlineStream, value);
|
||||||
|
}
|
||||||
|
ArenaHeaderTag::StaticStringStream => {
|
||||||
|
drop_typed_slab_in_place!(StaticStringStream, value);
|
||||||
|
}
|
||||||
|
ArenaHeaderTag::ByteStream => {
|
||||||
|
drop_typed_slab_in_place!(ByteStream, value);
|
||||||
|
}
|
||||||
|
ArenaHeaderTag::CallbackStream => {
|
||||||
|
drop_typed_slab_in_place!(CallbackStream, value);
|
||||||
|
}
|
||||||
|
ArenaHeaderTag::InputChannelStream => {
|
||||||
|
drop_typed_slab_in_place!(InputChannelStream, value);
|
||||||
|
}
|
||||||
|
ArenaHeaderTag::LiveLoadState | ArenaHeaderTag::InactiveLoadState => {
|
||||||
|
drop_typed_slab_in_place!(LiveLoadState, value);
|
||||||
|
}
|
||||||
|
ArenaHeaderTag::Dropped => {}
|
||||||
|
ArenaHeaderTag::TcpListener => {
|
||||||
|
drop_typed_slab_in_place!(TcpListener, value);
|
||||||
|
}
|
||||||
|
ArenaHeaderTag::HttpListener => {
|
||||||
|
#[cfg(feature = "http")]
|
||||||
|
drop_typed_slab_in_place!(HttpListener, value);
|
||||||
|
}
|
||||||
|
ArenaHeaderTag::HttpResponse => {
|
||||||
|
#[cfg(feature = "http")]
|
||||||
|
drop_typed_slab_in_place!(HttpResponse, value);
|
||||||
|
}
|
||||||
|
ArenaHeaderTag::StandardOutputStream => {
|
||||||
|
drop_typed_slab_in_place!(StandardOutputStream, value);
|
||||||
|
}
|
||||||
|
ArenaHeaderTag::StandardErrorStream => {
|
||||||
|
drop_typed_slab_in_place!(StandardErrorStream, value);
|
||||||
|
}
|
||||||
|
ArenaHeaderTag::PipeReader => {
|
||||||
|
drop_typed_slab_in_place!(PipeReader, value);
|
||||||
|
}
|
||||||
|
ArenaHeaderTag::PipeWriter => {
|
||||||
|
drop_typed_slab_in_place!(PipeWriter, value);
|
||||||
|
}
|
||||||
|
ArenaHeaderTag::ChildProcess => {
|
||||||
|
drop_typed_slab_in_place!(Child, value);
|
||||||
|
}
|
||||||
|
ArenaHeaderTag::NullStream => {
|
||||||
|
unreachable!("NullStream is never arena allocated!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for Arena {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
// we un-nest UntypedArenaSlab to prevent stackoverflow due to the recursive drop
|
||||||
|
|
||||||
|
let mut ptr = self.base.take();
|
||||||
|
|
||||||
|
while let Some(mut slab) = ptr {
|
||||||
|
ptr = unsafe { slab.slab.as_mut() }.next.take();
|
||||||
|
drop(slab);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const_assert!(mem::size_of::<AllocSlab>() <= 24);
|
||||||
|
const_assert!(mem::size_of::<OrderedFloat<f64>>() == 8);
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use crate::arena::*;
|
||||||
|
use crate::atom_table::*;
|
||||||
|
use crate::machine::mock_wam::*;
|
||||||
|
use crate::types::*;
|
||||||
|
|
||||||
|
use crate::parser::dashu::{Integer, Rational};
|
||||||
|
use ordered_float::OrderedFloat;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn float_ptr_cast() {
|
||||||
|
let mut wam = MockWAM::new();
|
||||||
|
|
||||||
|
let f = 0f64;
|
||||||
|
let fp = float_alloc!(f, wam.machine_st.arena);
|
||||||
|
let mut cell = HeapCellValue::from(fp);
|
||||||
|
|
||||||
|
assert_eq!(cell.get_tag(), HeapCellValueTag::F64Offset);
|
||||||
|
assert!(!cell.get_mark_bit());
|
||||||
|
assert_eq!(wam.machine_st.arena.f64_tbl.get_entry(fp), OrderedFloat(f));
|
||||||
|
|
||||||
|
cell.set_mark_bit(true);
|
||||||
|
|
||||||
|
assert!(cell.get_mark_bit());
|
||||||
|
|
||||||
|
read_heap_cell!(cell,
|
||||||
|
(HeapCellValueTag::F64Offset, offset) => {
|
||||||
|
let fp = wam.machine_st.arena.f64_tbl.get_entry(offset);
|
||||||
|
assert_eq!(fp, OrderedFloat(0f64))
|
||||||
|
}
|
||||||
|
_ => { unreachable!() }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn heap_cell_value_const_cast() {
|
||||||
|
let mut wam = MockWAM::new();
|
||||||
|
|
||||||
|
#[cfg(target_pointer_width = "32")]
|
||||||
|
assert_eq!(ConsPtr::NICHE_SHIFT, 0);
|
||||||
|
|
||||||
|
#[cfg(not(target_pointer_width = "32"))]
|
||||||
|
assert_eq!(ConsPtr::NICHE_SHIFT, 3);
|
||||||
|
|
||||||
|
#[cfg(target_pointer_width = "32")]
|
||||||
|
let dummy_ptr: *const ArenaHeader = std::ptr::without_provenance(0x0000_0438);
|
||||||
|
|
||||||
|
#[cfg(target_pointer_width = "64")]
|
||||||
|
let dummy_ptr: *const ArenaHeader = std::ptr::without_provenance(0x0000_5555_ff00_0438);
|
||||||
|
|
||||||
|
assert!(dummy_ptr.is_aligned());
|
||||||
|
|
||||||
|
let const_value = HeapCellValue::from_arena_header_ptr(dummy_ptr);
|
||||||
|
|
||||||
|
match const_value.to_untyped_arena_ptr() {
|
||||||
|
Some(arena_ptr) => {
|
||||||
|
assert_eq!(
|
||||||
|
arena_ptr.into_bytes(),
|
||||||
|
const_value.to_untyped_arena_ptr_bytes()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
unreachable!();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let stream = Stream::from_static_string("test", &mut wam.machine_st.arena);
|
||||||
|
let stream_cell = HeapCellValue::from_arena_header_ptr(stream.as_ptr());
|
||||||
|
|
||||||
|
match stream_cell.to_untyped_arena_ptr() {
|
||||||
|
Some(arena_ptr) => {
|
||||||
|
assert_eq!(
|
||||||
|
arena_ptr.into_bytes(),
|
||||||
|
stream_cell.to_untyped_arena_ptr_bytes()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
unreachable!();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn heap_put_literal_tests() {
|
||||||
|
let mut wam = MockWAM::new();
|
||||||
|
|
||||||
|
// integer
|
||||||
|
|
||||||
|
let big_int: Integer = 2 * Integer::from(1u64 << 63);
|
||||||
|
let big_int_ptr: TypedArenaPtr<Integer> = arena_alloc!(big_int, &mut wam.machine_st.arena);
|
||||||
|
|
||||||
|
assert!(!big_int_ptr.as_ptr().is_null());
|
||||||
|
|
||||||
|
let cell = HeapCellValue::from(big_int_ptr);
|
||||||
|
assert_eq!(cell.get_tag(), HeapCellValueTag::Cons);
|
||||||
|
|
||||||
|
let untyped_arena_ptr = match cell.to_untyped_arena_ptr() {
|
||||||
|
Some(ptr) => ptr,
|
||||||
|
None => {
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
match_untyped_arena_ptr!(untyped_arena_ptr,
|
||||||
|
(ArenaHeaderTag::Integer, n) => {
|
||||||
|
assert_eq!(&*n, &(2 * Integer::from(1u64 << 63)))
|
||||||
|
}
|
||||||
|
_ => unreachable!()
|
||||||
|
);
|
||||||
|
|
||||||
|
read_heap_cell!(cell,
|
||||||
|
(HeapCellValueTag::Cons, cons_ptr) => {
|
||||||
|
match_untyped_arena_ptr!(cons_ptr,
|
||||||
|
(ArenaHeaderTag::Integer, n) => {
|
||||||
|
assert_eq!(&*n, &(2 * Integer::from(1u64 << 63)))
|
||||||
|
}
|
||||||
|
_ => { unreachable!() }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
_ => { unreachable!() }
|
||||||
|
);
|
||||||
|
|
||||||
|
// rational
|
||||||
|
|
||||||
|
let big_rat = Rational::from(2) * Rational::from(1u64 << 63);
|
||||||
|
let big_rat_ptr: TypedArenaPtr<Rational> = arena_alloc!(big_rat, &mut wam.machine_st.arena);
|
||||||
|
|
||||||
|
assert!(!big_rat_ptr.as_ptr().is_null());
|
||||||
|
|
||||||
|
let rat_cell = typed_arena_ptr_as_cell!(big_rat_ptr);
|
||||||
|
assert_eq!(cell.get_tag(), HeapCellValueTag::Cons);
|
||||||
|
|
||||||
|
match rat_cell.to_untyped_arena_ptr() {
|
||||||
|
Some(untyped_arena_ptr) => {
|
||||||
|
assert_eq!(
|
||||||
|
Some(big_rat_ptr.header_ptr()),
|
||||||
|
Some(untyped_arena_ptr.get_ptr()),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
unreachable!();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// assert_eq!(wam.machine_st.heap[1usize].get_tag(), HeapCellValueTag::Cons);
|
||||||
|
|
||||||
|
read_heap_cell!(rat_cell,
|
||||||
|
(HeapCellValueTag::Cons, cons_ptr) => {
|
||||||
|
match_untyped_arena_ptr!(cons_ptr,
|
||||||
|
(ArenaHeaderTag::Rational, n) => {
|
||||||
|
assert_eq!(&*n, &(Rational::from(2) * Rational::from(1u64 << 63)));
|
||||||
|
}
|
||||||
|
_ => unreachable!()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
_ => { unreachable!() }
|
||||||
|
);
|
||||||
|
|
||||||
|
// atom
|
||||||
|
|
||||||
|
let f_atom = atom!("f");
|
||||||
|
let g_atom = atom!("g");
|
||||||
|
|
||||||
|
assert_eq!(&*f_atom.as_str(), "f");
|
||||||
|
assert_eq!(&*g_atom.as_str(), "g");
|
||||||
|
|
||||||
|
let f_atom_cell = atom_as_cell!(f_atom);
|
||||||
|
let g_atom_cell = atom_as_cell!(g_atom);
|
||||||
|
|
||||||
|
assert_eq!(f_atom_cell.get_tag(), HeapCellValueTag::Atom);
|
||||||
|
|
||||||
|
match f_atom_cell.to_atom() {
|
||||||
|
Some(atom) => {
|
||||||
|
assert_eq!(f_atom, atom);
|
||||||
|
assert_eq!(&*atom.as_str(), "f");
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
unreachable!();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
read_heap_cell!(f_atom_cell,
|
||||||
|
(HeapCellValueTag::Atom, (atom, arity)) => {
|
||||||
|
assert_eq!(f_atom, atom);
|
||||||
|
assert_eq!(arity, 0);
|
||||||
|
assert_eq!(&*atom.as_str(), "f");
|
||||||
|
}
|
||||||
|
_ => { unreachable!() }
|
||||||
|
);
|
||||||
|
|
||||||
|
read_heap_cell!(g_atom_cell,
|
||||||
|
(HeapCellValueTag::Atom, (atom, arity)) => {
|
||||||
|
assert_eq!(g_atom, atom);
|
||||||
|
assert_eq!(arity, 0);
|
||||||
|
assert_eq!(&*atom.as_str(), "g");
|
||||||
|
}
|
||||||
|
_ => { unreachable!() }
|
||||||
|
);
|
||||||
|
|
||||||
|
// fixnum
|
||||||
|
|
||||||
|
let fixnum_cell = fixnum_as_cell!(Fixnum::build_with(3));
|
||||||
|
|
||||||
|
assert_eq!(fixnum_cell.get_tag(), HeapCellValueTag::Fixnum);
|
||||||
|
|
||||||
|
match fixnum_cell.to_fixnum() {
|
||||||
|
Some(n) => assert_eq!(n.get_num(), 3),
|
||||||
|
None => unreachable!(),
|
||||||
|
}
|
||||||
|
|
||||||
|
read_heap_cell!(fixnum_cell,
|
||||||
|
(HeapCellValueTag::Fixnum, n) => {
|
||||||
|
assert_eq!(n.get_num(), 3);
|
||||||
|
}
|
||||||
|
_ => { unreachable!() }
|
||||||
|
);
|
||||||
|
|
||||||
|
let fixnum_b_cell = fixnum_as_cell!(
|
||||||
|
Fixnum::build_with_checked(1i64 << 54).expect("1 << 54 fits in Fixnum")
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(fixnum_b_cell.get_tag(), HeapCellValueTag::Fixnum);
|
||||||
|
|
||||||
|
match fixnum_b_cell.to_fixnum() {
|
||||||
|
Some(n) => assert_eq!(n.get_num(), 1 << 54),
|
||||||
|
None => unreachable!(),
|
||||||
|
}
|
||||||
|
|
||||||
|
Fixnum::build_with_checked(1i64 << 56).expect_err("1 << 56 is too large for fixnum");
|
||||||
|
|
||||||
|
Fixnum::build_with_checked(i64::MAX).expect_err("i64::MAX is too large for Fixnum");
|
||||||
|
Fixnum::build_with_checked(i64::MIN).expect_err("i64::MIN is too small for Fixnum");
|
||||||
|
assert_eq!(
|
||||||
|
Fixnum::build_with_checked(-1i64)
|
||||||
|
.expect("-1 fits in fixnum")
|
||||||
|
.get_num(),
|
||||||
|
-1
|
||||||
|
);
|
||||||
|
|
||||||
|
Fixnum::build_with_checked((1i64 << 55) - 1)
|
||||||
|
.expect("(1 << 55) - 1 is the largest value that fits in Fixnum");
|
||||||
|
|
||||||
|
Fixnum::build_with_checked(-(1i64 << 55))
|
||||||
|
.expect("-(1 << 55) is the smallest value that fits in fixnum");
|
||||||
|
Fixnum::build_with_checked(-(1i64 << 55) - 1)
|
||||||
|
.expect_err("-(1<<55) - 1 is too small for Fixnum");
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
-Fixnum::build_with_checked(-1i64).expect("-1 fits in Fixnum"),
|
||||||
|
Fixnum::build_with(1)
|
||||||
|
);
|
||||||
|
|
||||||
|
// float
|
||||||
|
|
||||||
|
let float = std::f64::consts::PI;
|
||||||
|
let float_ptr = float_alloc!(float, wam.machine_st.arena);
|
||||||
|
let cell = HeapCellValue::from(float_ptr);
|
||||||
|
|
||||||
|
assert_eq!(cell.get_tag(), HeapCellValueTag::F64Offset);
|
||||||
|
|
||||||
|
// char
|
||||||
|
|
||||||
|
let c = 'c';
|
||||||
|
let char_cell = char_as_cell!(c);
|
||||||
|
|
||||||
|
read_heap_cell!(char_cell,
|
||||||
|
(HeapCellValueTag::Atom, (c, _arity)) => {
|
||||||
|
assert_eq!(&*c.as_str(), "c");
|
||||||
|
}
|
||||||
|
_ => { unreachable!() }
|
||||||
|
);
|
||||||
|
|
||||||
|
let c = 'Ћ';
|
||||||
|
let cyrillic_char_cell = char_as_cell!(c);
|
||||||
|
|
||||||
|
read_heap_cell!(cyrillic_char_cell,
|
||||||
|
(HeapCellValueTag::Atom, (c, _arity)) => {
|
||||||
|
assert_eq!(&*c.as_str(), "Ћ");
|
||||||
|
}
|
||||||
|
_ => { unreachable!() }
|
||||||
|
);
|
||||||
|
|
||||||
|
// empty list
|
||||||
|
|
||||||
|
let cell = empty_list_as_cell!();
|
||||||
|
|
||||||
|
read_heap_cell!(cell,
|
||||||
|
(HeapCellValueTag::Atom, (el, _arity)) => {
|
||||||
|
assert_eq!(el.flat_index(), empty_list_as_cell!().get_value());
|
||||||
|
assert_eq!(&*el.as_str(), "[]");
|
||||||
|
}
|
||||||
|
_ => { unreachable!() }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
672
src/arithmetic.rs
Normal file
672
src/arithmetic.rs
Normal file
@@ -0,0 +1,672 @@
|
|||||||
|
use crate::allocator::*;
|
||||||
|
use crate::arena::*;
|
||||||
|
use crate::atom_table::*;
|
||||||
|
use crate::debray_allocator::*;
|
||||||
|
use crate::forms::*;
|
||||||
|
use crate::instructions::*;
|
||||||
|
use crate::iterators::*;
|
||||||
|
use crate::offset_table::*;
|
||||||
|
use crate::targets::QueryInstruction;
|
||||||
|
use crate::types::*;
|
||||||
|
|
||||||
|
use crate::parser::ast::*;
|
||||||
|
use crate::parser::dashu::{Integer, Rational};
|
||||||
|
|
||||||
|
use crate::machine::machine_errors::*;
|
||||||
|
|
||||||
|
use dashu::base::Abs;
|
||||||
|
use dashu::base::BitTest;
|
||||||
|
use num_order::NumOrd;
|
||||||
|
use ordered_float::{Float, OrderedFloat};
|
||||||
|
|
||||||
|
use std::cell::Cell;
|
||||||
|
use std::cmp::Ordering;
|
||||||
|
use std::convert::TryFrom;
|
||||||
|
use std::f64;
|
||||||
|
use std::num::FpCategory;
|
||||||
|
use std::ops::Div;
|
||||||
|
use std::vec::Vec;
|
||||||
|
|
||||||
|
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||||
|
pub enum ArithmeticTerm {
|
||||||
|
IntermReg(usize),
|
||||||
|
Reg(RegType),
|
||||||
|
Number(Number),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for ArithmeticTerm {
|
||||||
|
fn default() -> Self {
|
||||||
|
ArithmeticTerm::Number(Number::default())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub(crate) struct ArithInstructionIterator<'a> {
|
||||||
|
state_stack: Vec<TermIterState<'a>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) type ArithCont = (CodeDeque, ArithmeticTerm);
|
||||||
|
|
||||||
|
impl<'a> ArithInstructionIterator<'a> {
|
||||||
|
fn push_subterm(&mut self, lvl: Level, term: &'a Term) {
|
||||||
|
self.state_stack
|
||||||
|
.push(TermIterState::subterm_to_state(lvl, term));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from(term: &'a Term) -> Result<Self, ArithmeticError> {
|
||||||
|
let state = match term {
|
||||||
|
Term::AnonVar => return Err(ArithmeticError::UninstantiatedVar),
|
||||||
|
Term::Clause(cell, name, terms) => {
|
||||||
|
TermIterState::Clause(Level::Shallow, 0, cell, *name, terms)
|
||||||
|
}
|
||||||
|
Term::Literal(cell, cons) => TermIterState::Literal(Level::Shallow, cell, cons),
|
||||||
|
Term::Cons(..) | Term::PartialString(..) | Term::CompleteString(..) => {
|
||||||
|
return Err(ArithmeticError::NonEvaluableFunctor(
|
||||||
|
Literal::Atom(atom!(".")),
|
||||||
|
2,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
Term::Var(cell, var_ptr) => TermIterState::Var(Level::Shallow, cell, var_ptr.clone()),
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(ArithInstructionIterator {
|
||||||
|
state_stack: vec![state],
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub(crate) enum ArithTermRef<'a> {
|
||||||
|
Literal(Literal),
|
||||||
|
Op(Level, &'a Cell<RegType>, Atom, usize), // name, arity.
|
||||||
|
Var(Level, &'a Cell<VarReg>, VarPtr),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Iterator for ArithInstructionIterator<'a> {
|
||||||
|
type Item = Result<ArithTermRef<'a>, ArithmeticError>;
|
||||||
|
|
||||||
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
|
while let Some(iter_state) = self.state_stack.pop() {
|
||||||
|
match iter_state {
|
||||||
|
TermIterState::AnonVar(_) => return Some(Err(ArithmeticError::UninstantiatedVar)),
|
||||||
|
TermIterState::Clause(lvl, child_num, cell, name, subterms) => {
|
||||||
|
let arity = subterms.len();
|
||||||
|
|
||||||
|
if child_num == arity {
|
||||||
|
return Some(Ok(ArithTermRef::Op(lvl, cell, name, arity)));
|
||||||
|
} else {
|
||||||
|
self.state_stack.push(TermIterState::Clause(
|
||||||
|
lvl,
|
||||||
|
child_num + 1,
|
||||||
|
cell,
|
||||||
|
name,
|
||||||
|
subterms,
|
||||||
|
));
|
||||||
|
|
||||||
|
self.push_subterm(lvl.child_level(), &subterms[child_num]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
TermIterState::Literal(_, _, c) => return Some(Ok(ArithTermRef::Literal(*c))),
|
||||||
|
TermIterState::Var(lvl, cell, var_ptr) => {
|
||||||
|
return Some(Ok(ArithTermRef::Var(lvl, cell, var_ptr)));
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
return Some(Err(ArithmeticError::NonEvaluableFunctor(
|
||||||
|
Literal::Atom(atom!(".")),
|
||||||
|
2,
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub(crate) struct ArithmeticEvaluator<'a> {
|
||||||
|
marker: &'a mut DebrayAllocator,
|
||||||
|
interm: Vec<ArithmeticTerm>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) trait ArithmeticTermIter<'a> {
|
||||||
|
type Iter: Iterator<Item = Result<ArithTermRef<'a>, ArithmeticError>>;
|
||||||
|
|
||||||
|
fn iter(self) -> Result<Self::Iter, ArithmeticError>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> ArithmeticTermIter<'a> for &'a Term {
|
||||||
|
type Iter = ArithInstructionIterator<'a>;
|
||||||
|
|
||||||
|
fn iter(self) -> Result<Self::Iter, ArithmeticError> {
|
||||||
|
ArithInstructionIterator::from(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn push_literal(interm: &mut Vec<ArithmeticTerm>, c: &Literal) -> Result<(), ArithmeticError> {
|
||||||
|
match c {
|
||||||
|
Literal::Fixnum(n) => interm.push(ArithmeticTerm::Number(Number::Fixnum(*n))),
|
||||||
|
Literal::Integer(n) => interm.push(ArithmeticTerm::Number(Number::Integer(*n))),
|
||||||
|
&Literal::F64(_offset, n) => {
|
||||||
|
interm.push(ArithmeticTerm::Number(Number::Float(n)));
|
||||||
|
}
|
||||||
|
Literal::Rational(n) => interm.push(ArithmeticTerm::Number(Number::Rational(*n))),
|
||||||
|
Literal::Atom(name) if name == &atom!("e") => interm.push(ArithmeticTerm::Number(
|
||||||
|
Number::Float(OrderedFloat(std::f64::consts::E)),
|
||||||
|
)),
|
||||||
|
Literal::Atom(name) if name == &atom!("pi") => interm.push(ArithmeticTerm::Number(
|
||||||
|
Number::Float(OrderedFloat(std::f64::consts::PI)),
|
||||||
|
)),
|
||||||
|
Literal::Atom(name) if name == &atom!("epsilon") => interm.push(ArithmeticTerm::Number(
|
||||||
|
Number::Float(OrderedFloat(f64::EPSILON)),
|
||||||
|
)),
|
||||||
|
_ => return Err(ArithmeticError::NonEvaluableFunctor(*c, 0)),
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> ArithmeticEvaluator<'a> {
|
||||||
|
pub(crate) fn new(marker: &'a mut DebrayAllocator) -> Self {
|
||||||
|
ArithmeticEvaluator {
|
||||||
|
marker,
|
||||||
|
interm: Vec::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_unary_instr(
|
||||||
|
&self,
|
||||||
|
name: Atom,
|
||||||
|
a1: ArithmeticTerm,
|
||||||
|
t: usize,
|
||||||
|
) -> Result<Instruction, ArithmeticError> {
|
||||||
|
match name {
|
||||||
|
atom!("abs") => Ok(Instruction::Abs(a1, t)),
|
||||||
|
atom!("-") => Ok(Instruction::Neg(a1, t)),
|
||||||
|
atom!("+") => Ok(Instruction::Plus(a1, t)),
|
||||||
|
atom!("cos") => Ok(Instruction::Cos(a1, t)),
|
||||||
|
atom!("sin") => Ok(Instruction::Sin(a1, t)),
|
||||||
|
atom!("tan") => Ok(Instruction::Tan(a1, t)),
|
||||||
|
atom!("log") => Ok(Instruction::Log(a1, t)),
|
||||||
|
atom!("exp") => Ok(Instruction::Exp(a1, t)),
|
||||||
|
atom!("sqrt") => Ok(Instruction::Sqrt(a1, t)),
|
||||||
|
atom!("acos") => Ok(Instruction::ACos(a1, t)),
|
||||||
|
atom!("asin") => Ok(Instruction::ASin(a1, t)),
|
||||||
|
atom!("atan") => Ok(Instruction::ATan(a1, t)),
|
||||||
|
atom!("float") => Ok(Instruction::Float(a1, t)),
|
||||||
|
atom!("truncate") => Ok(Instruction::Truncate(a1, t)),
|
||||||
|
atom!("round") => Ok(Instruction::Round(a1, t)),
|
||||||
|
atom!("ceiling") => Ok(Instruction::Ceiling(a1, t)),
|
||||||
|
atom!("floor") => Ok(Instruction::Floor(a1, t)),
|
||||||
|
atom!("float_integer_part") => Ok(Instruction::FloatIntegerPart(a1, t)),
|
||||||
|
atom!("float_fractional_part") => Ok(Instruction::FloatFractionalPart(a1, t)),
|
||||||
|
atom!("sign") => Ok(Instruction::Sign(a1, t)),
|
||||||
|
atom!("\\") => Ok(Instruction::BitwiseComplement(a1, t)),
|
||||||
|
_ => Err(ArithmeticError::NonEvaluableFunctor(Literal::Atom(name), 1)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_binary_instr(
|
||||||
|
&self,
|
||||||
|
name: Atom,
|
||||||
|
a1: ArithmeticTerm,
|
||||||
|
a2: ArithmeticTerm,
|
||||||
|
t: usize,
|
||||||
|
) -> Result<Instruction, ArithmeticError> {
|
||||||
|
match name {
|
||||||
|
atom!("+") => Ok(Instruction::Add(a1, a2, t)),
|
||||||
|
atom!("-") => Ok(Instruction::Sub(a1, a2, t)),
|
||||||
|
atom!("/") => Ok(Instruction::Div(a1, a2, t)),
|
||||||
|
atom!("//") => Ok(Instruction::IDiv(a1, a2, t)),
|
||||||
|
atom!("max") => Ok(Instruction::Max(a1, a2, t)),
|
||||||
|
atom!("min") => Ok(Instruction::Min(a1, a2, t)),
|
||||||
|
atom!("div") => Ok(Instruction::IntFloorDiv(a1, a2, t)),
|
||||||
|
atom!("rdiv") => Ok(Instruction::RDiv(a1, a2, t)),
|
||||||
|
atom!("*") => Ok(Instruction::Mul(a1, a2, t)),
|
||||||
|
atom!("**") => Ok(Instruction::Pow(a1, a2, t)),
|
||||||
|
atom!("^") => Ok(Instruction::IntPow(a1, a2, t)),
|
||||||
|
atom!(">>") => Ok(Instruction::Shr(a1, a2, t)),
|
||||||
|
atom!("<<") => Ok(Instruction::Shl(a1, a2, t)),
|
||||||
|
atom!("/\\") => Ok(Instruction::And(a1, a2, t)),
|
||||||
|
atom!("\\/") => Ok(Instruction::Or(a1, a2, t)),
|
||||||
|
atom!("xor") => Ok(Instruction::Xor(a1, a2, t)),
|
||||||
|
atom!("mod") => Ok(Instruction::Mod(a1, a2, t)),
|
||||||
|
atom!("rem") => Ok(Instruction::Rem(a1, a2, t)),
|
||||||
|
atom!("gcd") => Ok(Instruction::Gcd(a1, a2, t)),
|
||||||
|
atom!("atan2") => Ok(Instruction::ATan2(a1, a2, t)),
|
||||||
|
_ => Err(ArithmeticError::NonEvaluableFunctor(Literal::Atom(name), 2)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn try_add_to_free_list(&mut self, a1: ArithmeticTerm) {
|
||||||
|
if let ArithmeticTerm::IntermReg(t) = a1 {
|
||||||
|
self.marker.add_reg_to_free_list(RegType::Temp(t));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn instr_from_clause(
|
||||||
|
&mut self,
|
||||||
|
name: Atom,
|
||||||
|
arity: usize,
|
||||||
|
arg: usize,
|
||||||
|
) -> Result<Instruction, ArithmeticError> {
|
||||||
|
match arity {
|
||||||
|
1 => {
|
||||||
|
let a1 = self.interm.pop().unwrap();
|
||||||
|
|
||||||
|
self.interm.push(ArithmeticTerm::IntermReg(arg));
|
||||||
|
self.try_add_to_free_list(a1);
|
||||||
|
|
||||||
|
self.get_unary_instr(name, a1, arg)
|
||||||
|
}
|
||||||
|
2 => {
|
||||||
|
let a2 = self.interm.pop().unwrap();
|
||||||
|
let a1 = self.interm.pop().unwrap();
|
||||||
|
|
||||||
|
self.interm.push(ArithmeticTerm::IntermReg(arg));
|
||||||
|
|
||||||
|
self.try_add_to_free_list(a1);
|
||||||
|
self.try_add_to_free_list(a2);
|
||||||
|
|
||||||
|
self.get_binary_instr(name, a1, a2, arg)
|
||||||
|
}
|
||||||
|
_ => Err(ArithmeticError::NonEvaluableFunctor(
|
||||||
|
Literal::Atom(name),
|
||||||
|
arity,
|
||||||
|
)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn compile_is(
|
||||||
|
&mut self,
|
||||||
|
src: &'a Term,
|
||||||
|
term_loc: GenContext,
|
||||||
|
arg: usize,
|
||||||
|
) -> Result<ArithCont, ArithmeticError> {
|
||||||
|
let mut code = CodeDeque::new();
|
||||||
|
|
||||||
|
for term_ref in src.iter()? {
|
||||||
|
match term_ref? {
|
||||||
|
ArithTermRef::Literal(c) => push_literal(&mut self.interm, &c)?,
|
||||||
|
ArithTermRef::Var(lvl, cell, name) => {
|
||||||
|
let var_num = name.to_var_num().unwrap();
|
||||||
|
|
||||||
|
let r = if lvl == Level::Shallow {
|
||||||
|
self.marker
|
||||||
|
.mark_non_callable(var_num, arg, term_loc, cell, &mut code)
|
||||||
|
} else if term_loc.is_last() || cell.get().norm().reg_num() == 0 {
|
||||||
|
let r = self.marker.get_binding(var_num);
|
||||||
|
|
||||||
|
if r.reg_num() == 0 {
|
||||||
|
self.marker.mark_var::<QueryInstruction>(
|
||||||
|
var_num, lvl, cell, term_loc, &mut code,
|
||||||
|
);
|
||||||
|
cell.get().norm()
|
||||||
|
} else {
|
||||||
|
self.marker.increment_running_count(var_num);
|
||||||
|
r
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
self.marker.increment_running_count(var_num);
|
||||||
|
cell.get().norm()
|
||||||
|
};
|
||||||
|
|
||||||
|
self.interm.push(ArithmeticTerm::Reg(r));
|
||||||
|
}
|
||||||
|
ArithTermRef::Op(lvl, cell, name, arity) => {
|
||||||
|
self.marker
|
||||||
|
.mark_non_var::<QueryInstruction>(lvl, term_loc, cell, &mut code);
|
||||||
|
|
||||||
|
if let RegType::Temp(t) = cell.get() {
|
||||||
|
code.push_back(self.instr_from_clause(name, arity, t)?);
|
||||||
|
} else {
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok((code, self.interm.pop().unwrap()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// integer division rounding function -- 9.1.3.1.
|
||||||
|
pub(crate) fn rnd_i(n: &'_ Number, arena: &mut Arena) -> Result<Number, EvalError> {
|
||||||
|
match n {
|
||||||
|
&Number::Integer(i) => {
|
||||||
|
if let Ok(value) = Fixnum::build_with_checked(&*i) {
|
||||||
|
Ok(Number::Fixnum(value))
|
||||||
|
} else {
|
||||||
|
Ok(*n)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Number::Fixnum(_) => Ok(*n),
|
||||||
|
&Number::Float(f) => {
|
||||||
|
let f = f.floor();
|
||||||
|
|
||||||
|
const FIXNUM_MIN_TO_F: OrderedFloat<f64> = OrderedFloat(Fixnum::MIN as f64);
|
||||||
|
const FIXNUM_MAX_TO_F: OrderedFloat<f64> = OrderedFloat(Fixnum::MAX as f64);
|
||||||
|
|
||||||
|
if (FIXNUM_MIN_TO_F..=FIXNUM_MAX_TO_F).contains(&f) {
|
||||||
|
Ok(Number::Fixnum(
|
||||||
|
// Safety: We checked that the value is in range
|
||||||
|
unsafe { Fixnum::build_with_unchecked(f.into_inner() as i64) },
|
||||||
|
))
|
||||||
|
} else {
|
||||||
|
Ok(Number::Integer(arena_alloc!(
|
||||||
|
Integer::try_from(classify_float(f.0)?).unwrap_or_else(|_| {
|
||||||
|
unreachable!();
|
||||||
|
}),
|
||||||
|
arena
|
||||||
|
)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Number::Rational(r) => {
|
||||||
|
let floor = r.floor();
|
||||||
|
|
||||||
|
if let Ok(value) = Fixnum::build_with_checked(&floor) {
|
||||||
|
Ok(Number::Fixnum(value))
|
||||||
|
} else {
|
||||||
|
Ok(Number::Integer(arena_alloc!(floor, arena)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Fixnum> for Integer {
|
||||||
|
#[inline]
|
||||||
|
fn from(n: Fixnum) -> Integer {
|
||||||
|
Integer::from(n.get_num())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// floating point rounding function -- 9.1.4.1.
|
||||||
|
pub(crate) fn rnd_f(n: &Number) -> f64 {
|
||||||
|
match n {
|
||||||
|
&Number::Fixnum(n) => n.get_num() as f64,
|
||||||
|
Number::Integer(n) => n.to_f64().value(),
|
||||||
|
&Number::Float(OrderedFloat(f)) => f,
|
||||||
|
Number::Rational(r) => r.to_f64().value(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// floating point result function -- 9.1.4.2.
|
||||||
|
pub(crate) fn result_f(n: &Number) -> Result<f64, EvalError> {
|
||||||
|
classify_float(rnd_f(n))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn classify_float(f: f64) -> Result<f64, EvalError> {
|
||||||
|
match f.classify() {
|
||||||
|
FpCategory::Normal | FpCategory::Zero => Ok(f),
|
||||||
|
FpCategory::Infinite => {
|
||||||
|
if OrderedFloat(f) == OrderedFloat(f64::MAX) {
|
||||||
|
Ok(f)
|
||||||
|
} else {
|
||||||
|
Err(EvalError::FloatOverflow)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
FpCategory::Nan => Err(EvalError::Undefined),
|
||||||
|
_ => Ok(f),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub(crate) fn float_fn_to_f(n: i64) -> Result<f64, EvalError> {
|
||||||
|
classify_float(n as f64)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub(crate) fn float_i_to_f(n: &Integer) -> Result<f64, EvalError> {
|
||||||
|
classify_float(n.to_f64().value())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub(crate) fn float_r_to_f(r: &Rational) -> Result<f64, EvalError> {
|
||||||
|
classify_float(r.to_f64().value())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub(crate) fn add_f(f1: f64, f2: f64) -> Result<OrderedFloat<f64>, EvalError> {
|
||||||
|
Ok(OrderedFloat(classify_float(f1 + f2)?))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub(crate) fn mul_f(f1: f64, f2: f64) -> Result<OrderedFloat<f64>, EvalError> {
|
||||||
|
Ok(OrderedFloat(classify_float(f1 * f2)?))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn div_f(f1: f64, f2: f64) -> Result<OrderedFloat<f64>, EvalError> {
|
||||||
|
if FpCategory::Zero == f2.classify() {
|
||||||
|
Err(EvalError::ZeroDivisor)
|
||||||
|
} else {
|
||||||
|
Ok(OrderedFloat(classify_float(f1 / f2)?))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Div<Number> for Number {
|
||||||
|
type Output = Result<Number, EvalError>;
|
||||||
|
|
||||||
|
fn div(self, rhs: Number) -> Self::Output {
|
||||||
|
match (self, rhs) {
|
||||||
|
(Number::Fixnum(n1), Number::Fixnum(n2)) => Ok(Number::Float(div_f(
|
||||||
|
float_fn_to_f(n1.get_num())?,
|
||||||
|
float_fn_to_f(n2.get_num())?,
|
||||||
|
)?)),
|
||||||
|
(Number::Fixnum(n1), Number::Integer(n2)) => Ok(Number::Float(div_f(
|
||||||
|
float_fn_to_f(n1.get_num())?,
|
||||||
|
float_i_to_f(&n2)?,
|
||||||
|
)?)),
|
||||||
|
(Number::Integer(n1), Number::Fixnum(n2)) => Ok(Number::Float(div_f(
|
||||||
|
float_i_to_f(&n1)?,
|
||||||
|
float_fn_to_f(n2.get_num())?,
|
||||||
|
)?)),
|
||||||
|
(Number::Fixnum(n1), Number::Rational(n2)) => Ok(Number::Float(div_f(
|
||||||
|
float_fn_to_f(n1.get_num())?,
|
||||||
|
float_r_to_f(&n2)?,
|
||||||
|
)?)),
|
||||||
|
(Number::Rational(n1), Number::Fixnum(n2)) => Ok(Number::Float(div_f(
|
||||||
|
float_r_to_f(&n1)?,
|
||||||
|
float_fn_to_f(n2.get_num())?,
|
||||||
|
)?)),
|
||||||
|
(Number::Fixnum(n1), Number::Float(OrderedFloat(n2))) => {
|
||||||
|
Ok(Number::Float(div_f(float_fn_to_f(n1.get_num())?, n2)?))
|
||||||
|
}
|
||||||
|
(Number::Float(OrderedFloat(n1)), Number::Fixnum(n2)) => {
|
||||||
|
Ok(Number::Float(div_f(n1, float_fn_to_f(n2.get_num())?)?))
|
||||||
|
}
|
||||||
|
(Number::Integer(n1), Number::Integer(n2)) => Ok(Number::Float(div_f(
|
||||||
|
float_i_to_f(&n1)?,
|
||||||
|
float_i_to_f(&n2)?,
|
||||||
|
)?)),
|
||||||
|
(Number::Integer(n1), Number::Float(OrderedFloat(n2))) => {
|
||||||
|
Ok(Number::Float(div_f(float_i_to_f(&n1)?, n2)?))
|
||||||
|
}
|
||||||
|
(Number::Float(OrderedFloat(n2)), Number::Integer(n1)) => {
|
||||||
|
Ok(Number::Float(div_f(n2, float_i_to_f(&n1)?)?))
|
||||||
|
}
|
||||||
|
(Number::Integer(n1), Number::Rational(n2)) => Ok(Number::Float(div_f(
|
||||||
|
float_i_to_f(&n1)?,
|
||||||
|
float_r_to_f(&n2)?,
|
||||||
|
)?)),
|
||||||
|
(Number::Rational(n2), Number::Integer(n1)) => Ok(Number::Float(div_f(
|
||||||
|
float_r_to_f(&n2)?,
|
||||||
|
float_i_to_f(&n1)?,
|
||||||
|
)?)),
|
||||||
|
(Number::Rational(n1), Number::Float(OrderedFloat(n2))) => {
|
||||||
|
Ok(Number::Float(div_f(float_r_to_f(&n1)?, n2)?))
|
||||||
|
}
|
||||||
|
(Number::Float(OrderedFloat(n2)), Number::Rational(n1)) => {
|
||||||
|
Ok(Number::Float(div_f(n2, float_r_to_f(&n1)?)?))
|
||||||
|
}
|
||||||
|
(Number::Float(OrderedFloat(f1)), Number::Float(OrderedFloat(f2))) => {
|
||||||
|
Ok(Number::Float(div_f(f1, f2)?))
|
||||||
|
}
|
||||||
|
(Number::Rational(r1), Number::Rational(r2)) => Ok(Number::Float(div_f(
|
||||||
|
float_r_to_f(&r1)?,
|
||||||
|
float_r_to_f(&r2)?,
|
||||||
|
)?)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PartialEq for Number {
|
||||||
|
fn eq(&self, rhs: &Self) -> bool {
|
||||||
|
match (self, rhs) {
|
||||||
|
(&Number::Fixnum(n1), &Number::Fixnum(n2)) => n1.eq(&n2),
|
||||||
|
(&Number::Fixnum(n1), Number::Integer(n2)) => n1.get_num().num_eq(&**n2),
|
||||||
|
(Number::Integer(n1), &Number::Fixnum(n2)) => n1.num_eq(&n2.get_num()),
|
||||||
|
(&Number::Fixnum(n1), Number::Rational(n2)) => {
|
||||||
|
Integer::from(n1.get_num()).num_eq(&**n2)
|
||||||
|
}
|
||||||
|
(Number::Rational(n1), &Number::Fixnum(n2)) => n1.num_eq(&Integer::from(n2.get_num())),
|
||||||
|
(&Number::Fixnum(n1), &Number::Float(n2)) => OrderedFloat(n1.get_num() as f64).eq(&n2),
|
||||||
|
(&Number::Float(n1), &Number::Fixnum(n2)) => n1.eq(&OrderedFloat(n2.get_num() as f64)),
|
||||||
|
(Number::Integer(n1), Number::Integer(n2)) => n1.eq(n2),
|
||||||
|
(Number::Integer(n1), Number::Float(n2)) => OrderedFloat(n1.to_f64().value()).eq(n2),
|
||||||
|
(&Number::Float(n1), Number::Integer(n2)) => n1.eq(&OrderedFloat(n2.to_f64().value())),
|
||||||
|
(Number::Integer(n1), Number::Rational(n2)) => n1.num_eq(&**n2),
|
||||||
|
(Number::Rational(n1), Number::Integer(n2)) => n1.num_eq(&**n2),
|
||||||
|
(Number::Rational(n1), &Number::Float(n2)) => OrderedFloat(n1.to_f64().value()).eq(&n2),
|
||||||
|
(&Number::Float(n1), Number::Rational(n2)) => n1.eq(&OrderedFloat(n2.to_f64().value())),
|
||||||
|
(&Number::Float(f1), &Number::Float(f2)) => f1.eq(&f2),
|
||||||
|
(Number::Rational(r1), Number::Rational(r2)) => r1.eq(r2),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Eq for Number {}
|
||||||
|
|
||||||
|
impl PartialOrd<usize> for Number {
|
||||||
|
#[inline]
|
||||||
|
fn partial_cmp(&self, rhs: &usize) -> Option<Ordering> {
|
||||||
|
match self {
|
||||||
|
Number::Fixnum(n) => {
|
||||||
|
let n = n.get_num();
|
||||||
|
|
||||||
|
if n < 0i64 {
|
||||||
|
Some(Ordering::Less)
|
||||||
|
} else {
|
||||||
|
(n as usize).partial_cmp(rhs)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Number::Integer(n) => Some((n).num_cmp(rhs)),
|
||||||
|
Number::Rational(r) => Some((r).num_cmp(&Integer::from(*rhs))),
|
||||||
|
Number::Float(f) => f.partial_cmp(&OrderedFloat(*rhs as f64)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PartialEq<usize> for Number {
|
||||||
|
#[inline]
|
||||||
|
fn eq(&self, rhs: &usize) -> bool {
|
||||||
|
match self {
|
||||||
|
Number::Fixnum(n) => {
|
||||||
|
let n = n.get_num();
|
||||||
|
|
||||||
|
if n < 0i64 {
|
||||||
|
false
|
||||||
|
} else {
|
||||||
|
(n as usize).eq(rhs)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Number::Integer(n) => (n).num_eq(rhs),
|
||||||
|
Number::Rational(r) => (r).num_eq(&Integer::from(*rhs)),
|
||||||
|
Number::Float(f) => f.eq(&OrderedFloat(*rhs as f64)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PartialOrd for Number {
|
||||||
|
fn partial_cmp(&self, rhs: &Number) -> Option<Ordering> {
|
||||||
|
Some(self.cmp(rhs))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Ord for Number {
|
||||||
|
fn cmp(&self, rhs: &Number) -> Ordering {
|
||||||
|
match (self, rhs) {
|
||||||
|
(&Number::Fixnum(n1), &Number::Fixnum(n2)) => n1.get_num().cmp(&n2.get_num()),
|
||||||
|
(&Number::Fixnum(n1), Number::Integer(n2)) => Integer::from(n1.get_num()).cmp(n2),
|
||||||
|
(Number::Integer(n1), &Number::Fixnum(n2)) => (**n1).cmp(&Integer::from(n2.get_num())),
|
||||||
|
(&Number::Fixnum(n1), Number::Rational(n2)) => Rational::from(n1.get_num()).cmp(n2),
|
||||||
|
(Number::Rational(n1), &Number::Fixnum(n2)) => {
|
||||||
|
(**n1).cmp(&Rational::from(n2.get_num()))
|
||||||
|
}
|
||||||
|
(&Number::Fixnum(n1), &Number::Float(n2)) => OrderedFloat(n1.get_num() as f64).cmp(&n2),
|
||||||
|
(&Number::Float(n1), &Number::Fixnum(n2)) => n1.cmp(&OrderedFloat(n2.get_num() as f64)),
|
||||||
|
(&Number::Integer(n1), &Number::Integer(n2)) => (*n1).cmp(&*n2),
|
||||||
|
(&Number::Integer(n1), Number::Float(n2)) => OrderedFloat(n1.to_f64().value()).cmp(n2),
|
||||||
|
(&Number::Float(n1), Number::Integer(n2)) => n1.cmp(&OrderedFloat(n2.to_f64().value())),
|
||||||
|
(&Number::Integer(n1), &Number::Rational(n2)) => {
|
||||||
|
(*n1).num_partial_cmp(&*n2).unwrap_or(Ordering::Less)
|
||||||
|
}
|
||||||
|
(&Number::Rational(n1), &Number::Integer(n2)) => {
|
||||||
|
(*n1).num_partial_cmp(&*n2).unwrap_or(Ordering::Less)
|
||||||
|
}
|
||||||
|
(&Number::Rational(n1), &Number::Float(n2)) => {
|
||||||
|
OrderedFloat(n1.to_f64().value()).cmp(&n2)
|
||||||
|
}
|
||||||
|
(&Number::Float(n1), &Number::Rational(n2)) => {
|
||||||
|
n1.cmp(&OrderedFloat(n2.to_f64().value()))
|
||||||
|
}
|
||||||
|
(&Number::Float(f1), &Number::Float(f2)) => f1.cmp(&f2),
|
||||||
|
(&Number::Rational(r1), &Number::Rational(r2)) => (*r1).cmp(&*r2),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TryFrom<(HeapCellValue, &'_ F64Table)> for Number {
|
||||||
|
type Error = ();
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn try_from((value, f64_tbl): (HeapCellValue, &F64Table)) -> Result<Number, Self::Error> {
|
||||||
|
read_heap_cell!(value,
|
||||||
|
(HeapCellValueTag::Cons, c) => {
|
||||||
|
match_untyped_arena_ptr!(c,
|
||||||
|
(ArenaHeaderTag::Integer, n) => {
|
||||||
|
Ok(Number::Integer(n))
|
||||||
|
}
|
||||||
|
(ArenaHeaderTag::Rational, n) => {
|
||||||
|
Ok(Number::Rational(n))
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
Err(())
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
(HeapCellValueTag::F64Offset, offset) => {
|
||||||
|
let n = f64_tbl.get_entry(offset);
|
||||||
|
Ok(Number::Float(n))
|
||||||
|
}
|
||||||
|
(HeapCellValueTag::Fixnum | HeapCellValueTag::CutPoint, n) => {
|
||||||
|
Ok(Number::Fixnum(n))
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
Err(())
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Computes n ^ power. Ignores the sign of power.
|
||||||
|
pub(crate) fn binary_pow(mut n: Integer, power: &Integer) -> Integer {
|
||||||
|
let mut power = power.abs();
|
||||||
|
|
||||||
|
if power.is_zero() {
|
||||||
|
return Integer::ONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut oddand = Integer::ONE;
|
||||||
|
|
||||||
|
while power.num_gt(&1) {
|
||||||
|
if power.bit(0) {
|
||||||
|
oddand *= &n;
|
||||||
|
}
|
||||||
|
|
||||||
|
n = n.pow(2);
|
||||||
|
power >>= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
n * oddand
|
||||||
|
}
|
||||||
548
src/atom_table.rs
Normal file
548
src/atom_table.rs
Normal file
@@ -0,0 +1,548 @@
|
|||||||
|
use crate::machine::heap::AllocError;
|
||||||
|
use crate::parser::ast::MAX_ARITY;
|
||||||
|
use crate::raw_block::*;
|
||||||
|
use crate::types::*;
|
||||||
|
|
||||||
|
use std::cmp::Ordering;
|
||||||
|
use std::hash::{Hash, Hasher};
|
||||||
|
use std::mem;
|
||||||
|
use std::ops::Deref;
|
||||||
|
use std::ptr;
|
||||||
|
use std::str;
|
||||||
|
use std::sync::Arc;
|
||||||
|
use std::sync::Mutex;
|
||||||
|
use std::sync::RwLock;
|
||||||
|
use std::sync::Weak;
|
||||||
|
|
||||||
|
use arcu::Rcu;
|
||||||
|
use arcu::atomic::Arcu;
|
||||||
|
use arcu::epoch_counters::GlobalEpochCounterPool;
|
||||||
|
use arcu::rcu_ref::RcuRef;
|
||||||
|
use indexmap::IndexSet;
|
||||||
|
|
||||||
|
use modular_bitfield::prelude::*;
|
||||||
|
|
||||||
|
#[bitfield]
|
||||||
|
#[repr(u64)]
|
||||||
|
#[derive(Copy, Clone, Debug)]
|
||||||
|
pub struct AtomCell {
|
||||||
|
name: B48,
|
||||||
|
arity: B8,
|
||||||
|
#[allow(unused)]
|
||||||
|
f: bool,
|
||||||
|
#[allow(unused)]
|
||||||
|
m: bool,
|
||||||
|
#[allow(unused)]
|
||||||
|
is_inlined: bool,
|
||||||
|
#[allow(unused)]
|
||||||
|
tag: B5,
|
||||||
|
}
|
||||||
|
|
||||||
|
const INLINED_ATOM_MAX_LEN: usize = 6;
|
||||||
|
|
||||||
|
const_assert!(INLINED_ATOM_MAX_LEN < mem::size_of::<AtomCell>());
|
||||||
|
const_assert!(mem::size_of::<AtomCell>() == 8);
|
||||||
|
|
||||||
|
const_assert!(INLINED_ATOM_MAX_LEN < mem::size_of::<Atom>());
|
||||||
|
const_assert!(mem::size_of::<Atom>() == 8);
|
||||||
|
|
||||||
|
impl AtomCell {
|
||||||
|
#[inline]
|
||||||
|
fn new_static(index: u64) -> Self {
|
||||||
|
// upper 23 bits of index must be 0
|
||||||
|
debug_assert_eq!(index & !((1 << 49) - 1), 0);
|
||||||
|
AtomCell::new()
|
||||||
|
.with_name(index)
|
||||||
|
.with_arity(0u8)
|
||||||
|
.with_m(false)
|
||||||
|
.with_f(false)
|
||||||
|
.with_is_inlined(false)
|
||||||
|
.with_tag(HeapCellValueTag::Atom as u8)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn new_inlined(string: &str, arity: u8) -> Self {
|
||||||
|
debug_assert!(string.len() <= INLINED_ATOM_MAX_LEN);
|
||||||
|
|
||||||
|
let mut string_buf: [u8; 8] = [0u8; 8];
|
||||||
|
string_buf[..string.len()].copy_from_slice(string.as_bytes());
|
||||||
|
let encoding = u64::from_le_bytes(string_buf);
|
||||||
|
|
||||||
|
AtomCell::new()
|
||||||
|
.with_name(encoding)
|
||||||
|
.with_arity(arity)
|
||||||
|
.with_m(false)
|
||||||
|
.with_f(false)
|
||||||
|
.with_is_inlined(true)
|
||||||
|
.with_tag(HeapCellValueTag::Atom as u8)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn new_char_inlined(c: char) -> Self {
|
||||||
|
if c == '\u{0}' {
|
||||||
|
return Self::new_static(NULL_ATOM.flat_index());
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut char_buf = [0u8; 8];
|
||||||
|
c.encode_utf8(&mut char_buf);
|
||||||
|
|
||||||
|
let encoding = u64::from_le_bytes(char_buf);
|
||||||
|
|
||||||
|
AtomCell::new()
|
||||||
|
.with_name(encoding)
|
||||||
|
.with_arity(0u8)
|
||||||
|
.with_m(false)
|
||||||
|
.with_f(false)
|
||||||
|
.with_is_inlined(true)
|
||||||
|
.with_tag(HeapCellValueTag::Atom as u8)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn build_with(atom_index: u64, arity: u8) -> Self {
|
||||||
|
debug_assert!((arity as usize) <= MAX_ARITY);
|
||||||
|
|
||||||
|
AtomCell::new()
|
||||||
|
.with_name(atom_index >> 1)
|
||||||
|
.with_arity(arity)
|
||||||
|
.with_f(false)
|
||||||
|
.with_m(false)
|
||||||
|
.with_is_inlined(atom_index & 1 == 1)
|
||||||
|
.with_tag(HeapCellValueTag::Atom as u8)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn get_name(self) -> Atom {
|
||||||
|
Atom {
|
||||||
|
index: (self.name() << 1) | self.is_inlined() as u64,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn get_arity(self) -> usize {
|
||||||
|
self.arity() as usize
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn get_name_and_arity(self) -> (Atom, usize) {
|
||||||
|
(self.get_name(), self.get_arity())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||||
|
pub struct Atom {
|
||||||
|
pub index: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
include!(concat!(env!("OUT_DIR"), "/static_atoms.rs"));
|
||||||
|
|
||||||
|
// populate these in STRINGS so they can be used from build_functor
|
||||||
|
const _: Atom = atom!(".");
|
||||||
|
const _: Atom = atom!("[]");
|
||||||
|
const NULL_ATOM: Atom = atom!("\0");
|
||||||
|
|
||||||
|
impl<'a> From<&'a Atom> for Atom {
|
||||||
|
#[inline]
|
||||||
|
fn from(atom: &'a Atom) -> Self {
|
||||||
|
*atom
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl indexmap::Equivalent<Atom> for str {
|
||||||
|
fn equivalent(&self, key: &Atom) -> bool {
|
||||||
|
&*key.as_str() == self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PartialEq<str> for Atom {
|
||||||
|
fn eq(&self, other: &str) -> bool {
|
||||||
|
self.as_str().deref() == other
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PartialEq<&str> for Atom {
|
||||||
|
fn eq(&self, &other: &&str) -> bool {
|
||||||
|
self.as_str().deref() == other
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const ATOM_TABLE_INIT_SIZE: usize = 1 << 16;
|
||||||
|
const ATOM_TABLE_ALIGN: usize = 8;
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn global_atom_table() -> &'static RwLock<Weak<AtomTable>> {
|
||||||
|
static GLOBAL_ATOM_TABLE: RwLock<Weak<AtomTable>> = RwLock::new(Weak::new());
|
||||||
|
&GLOBAL_ATOM_TABLE
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn arc_atom_table() -> Option<Arc<AtomTable>> {
|
||||||
|
global_atom_table().read().unwrap().upgrade()
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RawBlockTraits for AtomTable {
|
||||||
|
#[inline]
|
||||||
|
fn init_size() -> usize {
|
||||||
|
ATOM_TABLE_INIT_SIZE
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn align() -> usize {
|
||||||
|
ATOM_TABLE_ALIGN
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[bitfield]
|
||||||
|
#[derive(Copy, Clone, Debug)]
|
||||||
|
struct AtomHeader {
|
||||||
|
#[allow(unused)]
|
||||||
|
m: bool,
|
||||||
|
len: B50,
|
||||||
|
#[allow(unused)]
|
||||||
|
padding: B13,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct AtomData {
|
||||||
|
header: AtomHeader,
|
||||||
|
data: str,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AtomHeader {
|
||||||
|
fn build_with(len: u64) -> Self {
|
||||||
|
AtomHeader::new().with_len(len).with_m(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Hash for Atom {
|
||||||
|
#[inline]
|
||||||
|
fn hash<H: Hasher>(&self, hasher: &mut H) {
|
||||||
|
self.as_str().hash(hasher)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum AtomString<'a> {
|
||||||
|
Static(&'a str),
|
||||||
|
Inlined([u8; 8]),
|
||||||
|
Dynamic(AtomTableRef<str>),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn inlined_to_str(bytes: &[u8; 8]) -> &str {
|
||||||
|
let slice_len = bytes
|
||||||
|
.iter()
|
||||||
|
.position(|&b| b == 0u8)
|
||||||
|
.unwrap_or(INLINED_ATOM_MAX_LEN);
|
||||||
|
|
||||||
|
unsafe { str::from_utf8_unchecked(&bytes[..slice_len]) }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::fmt::Debug for AtomString<'_> {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||||
|
std::fmt::Debug::fmt(self.deref(), f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::fmt::Display for AtomString<'_> {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||||
|
std::fmt::Display::fmt(self.deref(), f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::ops::Deref for AtomString<'_> {
|
||||||
|
type Target = str;
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
match self {
|
||||||
|
Self::Static(reference) => reference,
|
||||||
|
Self::Inlined(inlined) => inlined_to_str(inlined),
|
||||||
|
Self::Dynamic(guard) => guard.deref(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "repl")]
|
||||||
|
impl rustyline::completion::Candidate for AtomString<'_> {
|
||||||
|
fn display(&self) -> &str {
|
||||||
|
self.deref()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn replacement(&self) -> &str {
|
||||||
|
self.deref()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Atom {
|
||||||
|
#[inline]
|
||||||
|
fn new_inlined(string: &str) -> Self {
|
||||||
|
AtomCell::new_inlined(string, 0).get_name()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn is_static(self) -> bool {
|
||||||
|
if self.is_inlined() {
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
(self.flat_index() as usize) < STRINGS.len()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub(crate) fn flat_index(self) -> u64 {
|
||||||
|
self.index >> 1
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub(crate) fn is_inlined(self) -> bool {
|
||||||
|
self.index & 1 == 1
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn as_ptr(self) -> Option<AtomTableRef<AtomData>> {
|
||||||
|
if self.is_static() {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
let atom_table =
|
||||||
|
arc_atom_table().expect("We should only have an Atom while there is an AtomTable");
|
||||||
|
|
||||||
|
AtomTableRef::try_map(atom_table.inner.read(), |buf| unsafe {
|
||||||
|
let ptr = buf
|
||||||
|
.block
|
||||||
|
.get_unchecked(self.flat_index() as usize - STRINGS.len());
|
||||||
|
// TODO use std::ptr::from_raw_parts instead when feature ptr_metadata is stable rust-lang/rust#81513
|
||||||
|
let atom_data = &*(std::ptr::slice_from_raw_parts(ptr, 0) as *const AtomData);
|
||||||
|
let len = atom_data.header.len();
|
||||||
|
Some(&*(std::ptr::slice_from_raw_parts(ptr, len as usize) as *const AtomData))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn from(index: u64) -> Self {
|
||||||
|
Self { index }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn len(self) -> usize {
|
||||||
|
if let Some(s) = self.inlined_str() {
|
||||||
|
s.len()
|
||||||
|
} else if self.is_static() {
|
||||||
|
let index = self.flat_index();
|
||||||
|
STRINGS[index as usize].len()
|
||||||
|
} else {
|
||||||
|
let len: u64 = self.as_ptr().unwrap().header.len();
|
||||||
|
len as usize
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_empty(self) -> bool {
|
||||||
|
self.len() == 0
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn as_char(self) -> Option<char> {
|
||||||
|
let s = self.as_str();
|
||||||
|
let mut it = s.chars();
|
||||||
|
|
||||||
|
let c1 = it.next();
|
||||||
|
let c2 = it.next();
|
||||||
|
|
||||||
|
if c2.is_none() { c1 } else { None }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn inlined_str<'a>(&self) -> Option<AtomString<'a>> {
|
||||||
|
if self.is_inlined() {
|
||||||
|
Some(AtomString::Inlined(self.flat_index().to_le_bytes()))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn as_str(&self) -> AtomString<'static> {
|
||||||
|
if let Some(s) = self.inlined_str() {
|
||||||
|
s
|
||||||
|
} else if self.is_static() {
|
||||||
|
let index = self.flat_index() as usize;
|
||||||
|
AtomString::Static(STRINGS[index])
|
||||||
|
} else if let Some(ptr) = self.as_ptr() {
|
||||||
|
AtomString::Dynamic(AtomTableRef::map(ptr, |ptr| &ptr.data))
|
||||||
|
} else {
|
||||||
|
AtomString::Static(STRINGS[(self.index >> 1) as usize])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn defrock_brackets(&self, atom_tbl: &AtomTable) -> Self {
|
||||||
|
let s = self.as_str();
|
||||||
|
|
||||||
|
let sub_str = if s.starts_with('(') && s.ends_with(')') {
|
||||||
|
&s['('.len_utf8()..s.len() - ')'.len_utf8()]
|
||||||
|
} else {
|
||||||
|
return *self;
|
||||||
|
};
|
||||||
|
|
||||||
|
AtomTable::build_with(atom_tbl, sub_str)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn write_to_ptr(string: &str, ptr: *mut u8) {
|
||||||
|
unsafe {
|
||||||
|
ptr::write(ptr as *mut _, AtomHeader::build_with(string.len() as u64));
|
||||||
|
let str_ptr = ptr.add(mem::size_of::<AtomHeader>());
|
||||||
|
ptr::copy_nonoverlapping(string.as_ptr(), str_ptr, string.len());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PartialOrd for Atom {
|
||||||
|
#[inline]
|
||||||
|
fn partial_cmp(&self, other: &Atom) -> Option<Ordering> {
|
||||||
|
Some(self.cmp(other))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Ord for Atom {
|
||||||
|
#[inline]
|
||||||
|
fn cmp(&self, other: &Atom) -> Ordering {
|
||||||
|
self.as_str().cmp(&*other.as_str())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct InnerAtomTable {
|
||||||
|
block: RawBlock<AtomTable>,
|
||||||
|
pub table: Arcu<IndexSet<Atom>, GlobalEpochCounterPool>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct AtomTable {
|
||||||
|
inner: Arcu<InnerAtomTable, GlobalEpochCounterPool>,
|
||||||
|
// this lock is taking during resizing
|
||||||
|
update: Mutex<()>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub type AtomTableRef<M> = arcu::rcu_ref::RcuRef<InnerAtomTable, M>;
|
||||||
|
|
||||||
|
impl InnerAtomTable {
|
||||||
|
#[inline(always)]
|
||||||
|
fn lookup_str(self: &InnerAtomTable, string: &str) -> Option<Atom> {
|
||||||
|
STATIC_ATOMS_MAP
|
||||||
|
.get(string)
|
||||||
|
.cloned()
|
||||||
|
.or_else(|| self.table.read().get(string).cloned())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AtomTable {
|
||||||
|
#[inline]
|
||||||
|
pub fn new() -> Result<Arc<Self>, AllocError> {
|
||||||
|
let upgraded = global_atom_table().read().unwrap().upgrade();
|
||||||
|
// don't inline upgraded, otherwise temporary will be dropped too late in case of None
|
||||||
|
if let Some(atom_table) = upgraded {
|
||||||
|
Ok(atom_table)
|
||||||
|
} else {
|
||||||
|
let mut guard = global_atom_table().write().unwrap();
|
||||||
|
// try to upgrade again in case we lost the race on the write lock
|
||||||
|
if let Some(atom_table) = guard.upgrade() {
|
||||||
|
Ok(atom_table)
|
||||||
|
} else {
|
||||||
|
let atom_table = Arc::new(Self {
|
||||||
|
inner: Arcu::new(
|
||||||
|
InnerAtomTable {
|
||||||
|
block: RawBlock::new()?,
|
||||||
|
table: Arcu::new(IndexSet::new(), GlobalEpochCounterPool),
|
||||||
|
},
|
||||||
|
GlobalEpochCounterPool,
|
||||||
|
),
|
||||||
|
update: Mutex::new(()),
|
||||||
|
});
|
||||||
|
*guard = Arc::downgrade(&atom_table);
|
||||||
|
Ok(atom_table)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn retrieve() -> Arc<Self> {
|
||||||
|
global_atom_table().read().unwrap().upgrade().unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn active_table(&self) -> RcuRef<IndexSet<Atom>, IndexSet<Atom>> {
|
||||||
|
self.inner.read().table.read()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn build_with(atom_table: &AtomTable, string: &str) -> Atom {
|
||||||
|
if !string.is_empty() && string.len() <= INLINED_ATOM_MAX_LEN && !string.contains('\u{0}') {
|
||||||
|
return Atom::new_inlined(string);
|
||||||
|
}
|
||||||
|
|
||||||
|
loop {
|
||||||
|
let mut block_epoch = atom_table.inner.read();
|
||||||
|
let mut table_epoch = block_epoch.table.read();
|
||||||
|
|
||||||
|
if let Some(atom) = block_epoch.lookup_str(string) {
|
||||||
|
return atom;
|
||||||
|
}
|
||||||
|
|
||||||
|
// take a lock to prevent concurrent updates
|
||||||
|
let update_guard = atom_table.update.lock().unwrap();
|
||||||
|
|
||||||
|
let is_same_allocation = RcuRef::same_epoch(&block_epoch, &atom_table.inner.read());
|
||||||
|
let is_same_atom_list = RcuRef::same_epoch(&table_epoch, &block_epoch.table.read());
|
||||||
|
|
||||||
|
if !(is_same_allocation && is_same_atom_list) {
|
||||||
|
// some other thread raced us between our lookup and
|
||||||
|
// us aquring the update lock,
|
||||||
|
// try again
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let size = mem::size_of::<AtomHeader>() + string.len();
|
||||||
|
let size = size.next_multiple_of(AtomTable::align());
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
let len_ptr = loop {
|
||||||
|
let ptr = block_epoch.block.alloc(size);
|
||||||
|
|
||||||
|
if ptr.is_null() {
|
||||||
|
// garbage collection would go here
|
||||||
|
let new_block = block_epoch.block.grow_new().unwrap();
|
||||||
|
let new_table = Arcu::new(table_epoch.clone(), GlobalEpochCounterPool);
|
||||||
|
let new_alloc = InnerAtomTable {
|
||||||
|
block: new_block,
|
||||||
|
table: new_table,
|
||||||
|
};
|
||||||
|
atom_table.inner.replace(new_alloc);
|
||||||
|
block_epoch = atom_table.inner.read();
|
||||||
|
table_epoch = block_epoch.table.read();
|
||||||
|
} else {
|
||||||
|
break ptr;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// SAFETY: `len_ptr` was obtained from `block_epoch.block.alloc()`
|
||||||
|
let len_offset = block_epoch.block.get_offset(len_ptr);
|
||||||
|
|
||||||
|
write_to_ptr(string, len_ptr);
|
||||||
|
|
||||||
|
let atom = AtomCell::new()
|
||||||
|
.with_name((STRINGS.len() + len_offset) as u64)
|
||||||
|
.with_arity(0)
|
||||||
|
.with_f(false)
|
||||||
|
.with_m(false)
|
||||||
|
.with_is_inlined(false)
|
||||||
|
.with_tag(HeapCellValueTag::Atom as u8)
|
||||||
|
.get_name();
|
||||||
|
|
||||||
|
let mut table = table_epoch.clone();
|
||||||
|
table.insert(atom);
|
||||||
|
block_epoch.table.replace(table);
|
||||||
|
|
||||||
|
// explicit drop to ensure we don't accidentally drop it early
|
||||||
|
drop(update_guard);
|
||||||
|
|
||||||
|
return atom;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe impl Send for AtomTable {}
|
||||||
|
unsafe impl Sync for AtomTable {}
|
||||||
7
src/bin/scryer-prolog.rs
Normal file
7
src/bin/scryer-prolog.rs
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
fn main() -> std::process::ExitCode {
|
||||||
|
#[cfg(target_arch = "wasm32")]
|
||||||
|
return std::process::ExitCode::SUCCESS;
|
||||||
|
|
||||||
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
|
return scryer_prolog::run_binary();
|
||||||
|
}
|
||||||
1321
src/codegen.rs
Normal file
1321
src/codegen.rs
Normal file
File diff suppressed because it is too large
Load Diff
889
src/debray_allocator.rs
Normal file
889
src/debray_allocator.rs
Normal file
@@ -0,0 +1,889 @@
|
|||||||
|
use crate::allocator::*;
|
||||||
|
use crate::codegen::SubsumedBranchHits;
|
||||||
|
use crate::forms::{BranchNumber, GenContext, Level};
|
||||||
|
use crate::instructions::*;
|
||||||
|
use crate::machine::disjuncts::VarData;
|
||||||
|
use crate::parser::ast::*;
|
||||||
|
use crate::targets::*;
|
||||||
|
use crate::variable_records::*;
|
||||||
|
|
||||||
|
use bit_set::*;
|
||||||
|
use bitvec::prelude::*;
|
||||||
|
use fxhash::FxBuildHasher;
|
||||||
|
use indexmap::IndexMap;
|
||||||
|
|
||||||
|
use std::cell::Cell;
|
||||||
|
use std::collections::VecDeque;
|
||||||
|
use std::ops::{Deref, DerefMut};
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
pub type BranchHits = IndexMap<usize, BitVec, FxBuildHasher>; // key: var_num, value: branch arm occurrences.
|
||||||
|
|
||||||
|
#[derive(Debug, Default)]
|
||||||
|
pub struct BranchOccurrences {
|
||||||
|
pub hits: BranchHits,
|
||||||
|
pub shallow_safety: BitSet<usize>, // unset means safe, set means unsafe (after the branch merge)
|
||||||
|
pub deep_safety: BitSet<usize>,
|
||||||
|
pub num_branches: usize,
|
||||||
|
pub current_branch_idx: usize,
|
||||||
|
pub current_branch_num: Arc<BranchNumber>,
|
||||||
|
pub subsumed_hits: SubsumedBranchHits,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BranchOccurrences {
|
||||||
|
fn new(current_branch_num: Arc<BranchNumber>, num_branches: usize) -> Self {
|
||||||
|
Self {
|
||||||
|
hits: BranchHits::with_hasher(FxBuildHasher::default()),
|
||||||
|
shallow_safety: BitSet::default(),
|
||||||
|
deep_safety: BitSet::default(),
|
||||||
|
num_branches,
|
||||||
|
current_branch_idx: 0,
|
||||||
|
current_branch_num,
|
||||||
|
subsumed_hits: SubsumedBranchHits::with_hasher(FxBuildHasher::default()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn add_branch_occurrence(&mut self, var_num: usize) {
|
||||||
|
debug_assert!(self.current_branch_idx < self.num_branches);
|
||||||
|
let num_branches = self.num_branches;
|
||||||
|
|
||||||
|
let entry = self
|
||||||
|
.hits
|
||||||
|
.entry(var_num)
|
||||||
|
.or_insert_with(|| BitVec::repeat(false, num_branches));
|
||||||
|
|
||||||
|
entry.set(self.current_branch_idx, true);
|
||||||
|
self.subsumed_hits.insert(var_num);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub(crate) struct BranchStack {
|
||||||
|
stack: Vec<BranchOccurrences>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Deref for BranchStack {
|
||||||
|
type Target = Vec<BranchOccurrences>;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
&self.stack
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DerefMut for BranchStack {
|
||||||
|
#[inline]
|
||||||
|
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||||
|
&mut self.stack
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BranchStack {
|
||||||
|
fn safety_unneeded_in_branch(
|
||||||
|
&self,
|
||||||
|
safety: &VarSafetyStatus,
|
||||||
|
branch: &BranchDesignator,
|
||||||
|
) -> bool {
|
||||||
|
match safety {
|
||||||
|
VarSafetyStatus::Needed => false,
|
||||||
|
VarSafetyStatus::LocallyUnneeded(planter_branch) => planter_branch
|
||||||
|
.branch_num
|
||||||
|
.has_as_subbranch(&branch.branch_num),
|
||||||
|
VarSafetyStatus::GloballyUnneeded => true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn add_branch_occurrence(&mut self, var_num: usize) {
|
||||||
|
if let Some(occurrences) = self.last_mut() {
|
||||||
|
occurrences.add_branch_occurrence(var_num);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn add_branch_stack(&mut self, branch_num: Arc<BranchNumber>, num_branches: usize) {
|
||||||
|
self.push(BranchOccurrences::new(branch_num, num_branches));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn current_branch_designator(&self) -> BranchDesignator {
|
||||||
|
let branch_num = self
|
||||||
|
.last()
|
||||||
|
.map(|occurrences| occurrences.current_branch_num.clone())
|
||||||
|
.unwrap_or_default();
|
||||||
|
|
||||||
|
BranchDesignator { branch_num }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub(crate) fn incr_current_branch(&mut self, branch_num: Arc<BranchNumber>) {
|
||||||
|
let branch_occurrences = self.last_mut().unwrap();
|
||||||
|
branch_occurrences.current_branch_idx += 1;
|
||||||
|
branch_occurrences.current_branch_num = branch_num;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub(crate) fn drain_branches(
|
||||||
|
&mut self,
|
||||||
|
depth: usize,
|
||||||
|
) -> std::vec::Drain<'_, BranchOccurrences> {
|
||||||
|
let start_idx = self.len() - depth;
|
||||||
|
self.drain(start_idx..)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub(crate) struct DebrayAllocator {
|
||||||
|
pub(crate) var_data: VarData, // var_data replaces bindings.
|
||||||
|
pub(crate) branch_stack: BranchStack,
|
||||||
|
pub(crate) in_tail_position: bool,
|
||||||
|
arg_c: usize,
|
||||||
|
temp_lb: usize,
|
||||||
|
perm_lb: usize,
|
||||||
|
arity: usize, // 0 if not at head.
|
||||||
|
shallow_temp_mappings: IndexMap<usize, usize, FxBuildHasher>,
|
||||||
|
in_use: BitSet<usize>, // deep and non-var allocations
|
||||||
|
temp_free_list: Vec<usize>,
|
||||||
|
perm_free_list: VecDeque<(usize, usize)>, // chunk_num, var_num
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DebrayAllocator {
|
||||||
|
pub(crate) fn add_branch(&mut self) {
|
||||||
|
let branch_designator = self.branch_stack.current_branch_designator();
|
||||||
|
let subsumed_hits = {
|
||||||
|
let branch_occurrences = self.branch_stack.last_mut().unwrap();
|
||||||
|
|
||||||
|
std::mem::replace(
|
||||||
|
&mut branch_occurrences.subsumed_hits,
|
||||||
|
SubsumedBranchHits::with_hasher(FxBuildHasher::default()),
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
for var_num in subsumed_hits {
|
||||||
|
match &mut self.var_data.records[var_num].allocation {
|
||||||
|
VarAlloc::Perm(_, allocation) => {
|
||||||
|
if let PermVarAllocation::Done {
|
||||||
|
shallow_safety,
|
||||||
|
deep_safety,
|
||||||
|
..
|
||||||
|
} = allocation
|
||||||
|
{
|
||||||
|
if !self
|
||||||
|
.branch_stack
|
||||||
|
.safety_unneeded_in_branch(shallow_safety, &branch_designator)
|
||||||
|
{
|
||||||
|
let branch_occurrences = self.branch_stack.last_mut().unwrap();
|
||||||
|
branch_occurrences.shallow_safety.insert(var_num);
|
||||||
|
}
|
||||||
|
|
||||||
|
if !self
|
||||||
|
.branch_stack
|
||||||
|
.safety_unneeded_in_branch(deep_safety, &branch_designator)
|
||||||
|
{
|
||||||
|
let branch_occurrences = self.branch_stack.last_mut().unwrap();
|
||||||
|
branch_occurrences.deep_safety.insert(var_num);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
*allocation = PermVarAllocation::Pending;
|
||||||
|
}
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn pop_branch(&mut self, depth: usize, subsumed_hits: SubsumedBranchHits) {
|
||||||
|
let removed_branches = self.branch_stack.drain_branches(depth);
|
||||||
|
|
||||||
|
let (deep_safety, shallow_safety) = removed_branches.into_iter().fold(
|
||||||
|
(BitSet::default(), BitSet::default()),
|
||||||
|
|(mut deep_safety, mut shallow_safety), branch_occurrences| {
|
||||||
|
deep_safety.union_with(&branch_occurrences.deep_safety);
|
||||||
|
shallow_safety.union_with(&branch_occurrences.shallow_safety);
|
||||||
|
|
||||||
|
(deep_safety, shallow_safety)
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
let branch_designator = Arc::new(self.branch_stack.current_branch_designator());
|
||||||
|
|
||||||
|
let (deep_safety, shallow_safety) = match self.branch_stack.last_mut() {
|
||||||
|
Some(latest_branch) => {
|
||||||
|
latest_branch.deep_safety.union_with(&deep_safety);
|
||||||
|
latest_branch.shallow_safety.union_with(&shallow_safety);
|
||||||
|
|
||||||
|
(&latest_branch.deep_safety, &latest_branch.shallow_safety)
|
||||||
|
}
|
||||||
|
None => (&deep_safety, &shallow_safety),
|
||||||
|
};
|
||||||
|
|
||||||
|
for var_num in subsumed_hits.iter().cloned() {
|
||||||
|
let running_count = self.var_data.records[var_num].running_count;
|
||||||
|
let num_occurrences = self.var_data.records[var_num].num_occurrences;
|
||||||
|
|
||||||
|
match &mut self.var_data.records[var_num].allocation {
|
||||||
|
VarAlloc::Perm(_, allocation) => {
|
||||||
|
let shallow_safety = VarSafetyStatus::needed_if(
|
||||||
|
shallow_safety.contains(var_num),
|
||||||
|
&branch_designator,
|
||||||
|
);
|
||||||
|
|
||||||
|
let deep_safety = VarSafetyStatus::needed_if(
|
||||||
|
deep_safety.contains(var_num),
|
||||||
|
&branch_designator,
|
||||||
|
);
|
||||||
|
|
||||||
|
if running_count < num_occurrences {
|
||||||
|
*allocation = PermVarAllocation::Done {
|
||||||
|
shallow_safety,
|
||||||
|
deep_safety,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !self.branch_stack.is_empty() {
|
||||||
|
for var_num in subsumed_hits {
|
||||||
|
self.branch_stack.add_branch_occurrence(var_num);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_curr_arg_distinct_from(&self, var_num: usize) -> bool {
|
||||||
|
match self.shallow_temp_mappings.get(&self.arg_c).cloned() {
|
||||||
|
Some(t_var) => t_var != var_num,
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn occurs_shallowly_in_head(&self, var_num: usize, r: usize) -> bool {
|
||||||
|
match &self.var_data.records[var_num].allocation {
|
||||||
|
VarAlloc::Temp {
|
||||||
|
temp_var_data,
|
||||||
|
term_loc: GenContext::Head,
|
||||||
|
..
|
||||||
|
} => temp_var_data.use_set.contains(&(GenContext::Head, r)),
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn is_in_use(&self, r: usize) -> bool {
|
||||||
|
let in_use_range = r <= self.arity && r >= self.arg_c;
|
||||||
|
in_use_range || self.in_use.contains(r)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn alloc_with_cr(&self, var_num: usize) -> usize {
|
||||||
|
match &self.var_data.records[var_num].allocation {
|
||||||
|
VarAlloc::Temp { temp_var_data, .. } => {
|
||||||
|
for &(_, reg) in temp_var_data.use_set.iter() {
|
||||||
|
if !self.is_in_use(reg) {
|
||||||
|
return reg;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut result = 0;
|
||||||
|
|
||||||
|
for reg in self.temp_lb.. {
|
||||||
|
if !self.is_in_use(reg) && !temp_var_data.no_use_set.contains(reg) {
|
||||||
|
result = reg;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
result
|
||||||
|
}
|
||||||
|
_ => 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn alloc_with_ca(&self, var_num: usize) -> usize {
|
||||||
|
match &self.var_data.records[var_num].allocation {
|
||||||
|
VarAlloc::Temp { temp_var_data, .. } => {
|
||||||
|
for &(_, reg) in temp_var_data.use_set.iter() {
|
||||||
|
if !self.is_in_use(reg) {
|
||||||
|
return reg;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut result = 0;
|
||||||
|
|
||||||
|
for reg in self.temp_lb.. {
|
||||||
|
if !self.is_in_use(reg)
|
||||||
|
&& !temp_var_data.no_use_set.contains(reg)
|
||||||
|
&& !temp_var_data.conflict_set.contains(reg)
|
||||||
|
{
|
||||||
|
result = reg;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
result
|
||||||
|
}
|
||||||
|
_ => 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn alloc_in_last_goal_hint(&self, chunk_num: usize) -> Option<(usize, usize)> {
|
||||||
|
// we want to allocate a register to the k^{th} parameter, par_k.
|
||||||
|
// par_k may not be a temporary variable.
|
||||||
|
let k = self.arg_c;
|
||||||
|
|
||||||
|
match self.shallow_temp_mappings.get(&k).cloned() {
|
||||||
|
Some(t_var) => {
|
||||||
|
// suppose this branch fires. then t_var is a
|
||||||
|
// temp. var. belonging to the current chunk.
|
||||||
|
// consider its use set. T == par_k iff
|
||||||
|
// (GenContext::Last(_), k) is in t_var.use_set.
|
||||||
|
|
||||||
|
if let VarAlloc::Temp { temp_var_data, .. } =
|
||||||
|
&self.var_data.records[t_var].allocation
|
||||||
|
{
|
||||||
|
if !temp_var_data
|
||||||
|
.use_set
|
||||||
|
.contains(&(GenContext::Last(chunk_num), k))
|
||||||
|
{
|
||||||
|
return Some((t_var, self.alloc_with_ca(t_var)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
None
|
||||||
|
}
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn evacuate_arg<'a, Target: CompilationTarget<'a>>(
|
||||||
|
&mut self,
|
||||||
|
chunk_num: usize,
|
||||||
|
code: &mut CodeDeque,
|
||||||
|
) {
|
||||||
|
if let Some((var_num, r)) = self.alloc_in_last_goal_hint(chunk_num) {
|
||||||
|
let k = self.arg_c;
|
||||||
|
|
||||||
|
if r != k {
|
||||||
|
let r = RegType::Temp(r);
|
||||||
|
|
||||||
|
code.push_back(Target::move_to_register(r, k));
|
||||||
|
|
||||||
|
self.shallow_temp_mappings.swap_remove(&k);
|
||||||
|
self.shallow_temp_mappings.insert(r.reg_num(), var_num);
|
||||||
|
|
||||||
|
self.var_data.records[var_num]
|
||||||
|
.allocation
|
||||||
|
.set_register(r.reg_num());
|
||||||
|
self.in_use.insert(r.reg_num());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn alloc_reg_to_var<'a, Target: CompilationTarget<'a>>(
|
||||||
|
&mut self,
|
||||||
|
var_num: usize,
|
||||||
|
lvl: Level,
|
||||||
|
term_loc: GenContext,
|
||||||
|
target: &mut CodeDeque,
|
||||||
|
) -> usize {
|
||||||
|
match term_loc {
|
||||||
|
GenContext::Head => {
|
||||||
|
if let Level::Shallow = lvl {
|
||||||
|
self.evacuate_arg::<Target>(0, target);
|
||||||
|
self.alloc_with_cr(var_num)
|
||||||
|
} else {
|
||||||
|
self.alloc_with_ca(var_num)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
GenContext::Mid(_) => self.alloc_with_ca(var_num),
|
||||||
|
GenContext::Last(chunk_num) => {
|
||||||
|
if let Level::Shallow = lvl {
|
||||||
|
self.evacuate_arg::<Target>(chunk_num, target);
|
||||||
|
self.alloc_with_cr(var_num)
|
||||||
|
} else {
|
||||||
|
self.alloc_with_ca(var_num)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn alloc_reg_to_non_var(&mut self) -> usize {
|
||||||
|
let mut final_index = 0;
|
||||||
|
|
||||||
|
while let Some(r) = self.temp_free_list.pop() {
|
||||||
|
if !self.is_in_use(r) {
|
||||||
|
self.in_use.insert(r);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for index in self.temp_lb.. {
|
||||||
|
if !self.in_use.contains(index) {
|
||||||
|
final_index = index;
|
||||||
|
self.in_use.insert(final_index);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.temp_lb = final_index + 1;
|
||||||
|
final_index
|
||||||
|
}
|
||||||
|
|
||||||
|
fn in_place(&self, var_num: usize, term_loc: GenContext, r: RegType, k: usize) -> bool {
|
||||||
|
match term_loc {
|
||||||
|
GenContext::Head if !r.is_perm() => r.reg_num() == k,
|
||||||
|
_ => match &self.var_data.records[var_num].allocation {
|
||||||
|
&VarAlloc::Temp { temp_reg, .. } if r.reg_num() == k => temp_reg == k,
|
||||||
|
_ => false,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn alloc_perm_var(&mut self, var_num: usize, chunk_num: usize) -> usize {
|
||||||
|
let p = if let Some(p) = self.pop_free_perm(chunk_num) {
|
||||||
|
p
|
||||||
|
} else {
|
||||||
|
let p = self.perm_lb;
|
||||||
|
self.perm_lb += 1;
|
||||||
|
|
||||||
|
p
|
||||||
|
};
|
||||||
|
|
||||||
|
self.var_data.records[var_num].allocation = VarAlloc::Perm(p, PermVarAllocation::done());
|
||||||
|
p
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn add_reg_to_free_list(&mut self, r: RegType) {
|
||||||
|
if let RegType::Temp(r) = r {
|
||||||
|
self.in_use.remove(r);
|
||||||
|
self.temp_free_list.push(r);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn reset_free_list(&mut self) {
|
||||||
|
self.temp_free_list.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn get_binding(&self, var_num: usize) -> RegType {
|
||||||
|
self.var_data.records[var_num].allocation.as_reg_type()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn num_perm_vars(&self) -> usize {
|
||||||
|
self.perm_lb - 1
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn increment_running_count(&mut self, var_num: usize) {
|
||||||
|
self.var_data.records[var_num].running_count += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn add_perm_to_free_list(&mut self, chunk_num: usize, var_num: usize) {
|
||||||
|
if let VarAlloc::Perm(..) = &self.var_data.records[var_num].allocation {
|
||||||
|
self.perm_free_list.push_back((chunk_num, var_num));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn pop_free_perm(&mut self, chunk_num: usize) -> Option<usize> {
|
||||||
|
while let Some((perm_chunk_num, var_num)) = self.perm_free_list.front().cloned() {
|
||||||
|
if chunk_num > perm_chunk_num {
|
||||||
|
self.perm_free_list.pop_front();
|
||||||
|
|
||||||
|
match &mut self.var_data.records[var_num].allocation {
|
||||||
|
VarAlloc::Perm(p, PermVarAllocation::Pending) if *p > 0 => {
|
||||||
|
return Some(std::mem::replace(p, 0));
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn free_var(&mut self, chunk_num: usize, var_num: usize) {
|
||||||
|
if let VarAlloc::Perm(_, allocation) = &mut self.var_data.records[var_num].allocation {
|
||||||
|
*allocation = PermVarAllocation::Pending;
|
||||||
|
self.add_perm_to_free_list(chunk_num, var_num);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn mark_safe_var_unconditionally(&mut self, var_num: usize) {
|
||||||
|
let branch_designator = Arc::new(self.branch_stack.current_branch_designator());
|
||||||
|
|
||||||
|
match &mut self.var_data.records[var_num].allocation {
|
||||||
|
VarAlloc::Perm(
|
||||||
|
_,
|
||||||
|
PermVarAllocation::Done {
|
||||||
|
deep_safety,
|
||||||
|
shallow_safety,
|
||||||
|
..
|
||||||
|
},
|
||||||
|
) => {
|
||||||
|
*deep_safety = VarSafetyStatus::unneeded(&branch_designator);
|
||||||
|
*shallow_safety = VarSafetyStatus::unneeded(&branch_designator);
|
||||||
|
}
|
||||||
|
VarAlloc::Temp { safety, .. } => {
|
||||||
|
*safety = VarSafetyStatus::unneeded(&branch_designator);
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn mark_safe_var(&mut self, var_num: usize, lvl: Level, term_loc: GenContext) {
|
||||||
|
let branch_designator = Arc::new(self.branch_stack.current_branch_designator());
|
||||||
|
|
||||||
|
match &mut self.var_data.records[var_num].allocation {
|
||||||
|
VarAlloc::Perm(
|
||||||
|
_,
|
||||||
|
PermVarAllocation::Done {
|
||||||
|
deep_safety,
|
||||||
|
shallow_safety,
|
||||||
|
..
|
||||||
|
},
|
||||||
|
) => {
|
||||||
|
// GetVariable in head chunk is considered safe.
|
||||||
|
if lvl == Level::Deep {
|
||||||
|
*deep_safety = VarSafetyStatus::unneeded(&branch_designator);
|
||||||
|
*shallow_safety = VarSafetyStatus::unneeded(&branch_designator);
|
||||||
|
} else if term_loc == GenContext::Head {
|
||||||
|
*shallow_safety = VarSafetyStatus::GloballyUnneeded;
|
||||||
|
} else if let Some(&temp_var_num) = self.shallow_temp_mappings.get(&self.arg_c) {
|
||||||
|
match &mut self.var_data.records[temp_var_num].allocation {
|
||||||
|
VarAlloc::Temp {
|
||||||
|
to_perm_var_num, ..
|
||||||
|
} => {
|
||||||
|
*to_perm_var_num = Some(var_num);
|
||||||
|
}
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
VarAlloc::Temp { safety, .. } => {
|
||||||
|
*safety = VarSafetyStatus::GloballyUnneeded;
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn argument_to_value<'a, Target: CompilationTarget<'a>>(
|
||||||
|
&mut self,
|
||||||
|
var_num: usize,
|
||||||
|
r: RegType,
|
||||||
|
arg_c: usize,
|
||||||
|
) -> Instruction {
|
||||||
|
let branch_designator = Arc::new(self.branch_stack.current_branch_designator());
|
||||||
|
|
||||||
|
match &mut self.var_data.records[var_num].allocation {
|
||||||
|
VarAlloc::Perm(_, PermVarAllocation::Done { shallow_safety, .. }) => {
|
||||||
|
if !self.in_tail_position
|
||||||
|
|| self
|
||||||
|
.branch_stack
|
||||||
|
.safety_unneeded_in_branch(shallow_safety, &branch_designator)
|
||||||
|
{
|
||||||
|
Target::argument_to_value(r, arg_c)
|
||||||
|
} else {
|
||||||
|
*shallow_safety = VarSafetyStatus::unneeded(&branch_designator);
|
||||||
|
Target::unsafe_argument_to_value(r, arg_c)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
VarAlloc::Temp { .. } => {
|
||||||
|
debug_assert!(matches!(r, RegType::Temp(_)));
|
||||||
|
Target::argument_to_value(r, arg_c)
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn subterm_to_value<'a, Target: CompilationTarget<'a>>(
|
||||||
|
&mut self,
|
||||||
|
var_num: usize,
|
||||||
|
r: RegType,
|
||||||
|
) -> Instruction {
|
||||||
|
let branch_designator = Arc::new(self.branch_stack.current_branch_designator());
|
||||||
|
|
||||||
|
match &mut self.var_data.records[var_num].allocation {
|
||||||
|
VarAlloc::Perm(_, PermVarAllocation::Done { deep_safety, .. }) => {
|
||||||
|
if self
|
||||||
|
.branch_stack
|
||||||
|
.safety_unneeded_in_branch(deep_safety, &branch_designator)
|
||||||
|
{
|
||||||
|
Target::subterm_to_value(r)
|
||||||
|
} else {
|
||||||
|
*deep_safety = VarSafetyStatus::unneeded(&branch_designator);
|
||||||
|
Target::unsafe_subterm_to_value(r)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
VarAlloc::Temp { safety, .. } => {
|
||||||
|
if self
|
||||||
|
.branch_stack
|
||||||
|
.safety_unneeded_in_branch(safety, &branch_designator)
|
||||||
|
{
|
||||||
|
Target::subterm_to_value(r)
|
||||||
|
} else {
|
||||||
|
*safety = VarSafetyStatus::unneeded(&branch_designator);
|
||||||
|
Target::unsafe_subterm_to_value(r)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Allocator for DebrayAllocator {
|
||||||
|
fn new() -> DebrayAllocator {
|
||||||
|
Self {
|
||||||
|
var_data: VarData::default(),
|
||||||
|
in_tail_position: false,
|
||||||
|
arity: 0,
|
||||||
|
arg_c: 1,
|
||||||
|
temp_lb: 1,
|
||||||
|
perm_lb: 1,
|
||||||
|
shallow_temp_mappings: IndexMap::with_hasher(FxBuildHasher::default()),
|
||||||
|
in_use: BitSet::default(),
|
||||||
|
temp_free_list: vec![],
|
||||||
|
perm_free_list: VecDeque::new(),
|
||||||
|
branch_stack: BranchStack { stack: vec![] },
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn mark_anon_var<'a, Target: CompilationTarget<'a>>(
|
||||||
|
&mut self,
|
||||||
|
lvl: Level,
|
||||||
|
term_loc: GenContext,
|
||||||
|
code: &mut CodeDeque,
|
||||||
|
) -> RegType {
|
||||||
|
let r = RegType::Temp(self.alloc_reg_to_non_var());
|
||||||
|
|
||||||
|
match lvl {
|
||||||
|
Level::Deep => code.push_back(Target::subterm_to_variable(r)),
|
||||||
|
Level::Root | Level::Shallow => {
|
||||||
|
let k = self.arg_c;
|
||||||
|
|
||||||
|
if let GenContext::Last(chunk_num) = term_loc {
|
||||||
|
self.evacuate_arg::<Target>(chunk_num, code);
|
||||||
|
}
|
||||||
|
|
||||||
|
self.arg_c += 1;
|
||||||
|
|
||||||
|
code.push_back(Target::argument_to_variable(r, k));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
r
|
||||||
|
}
|
||||||
|
|
||||||
|
fn mark_non_var<'a, Target: CompilationTarget<'a>>(
|
||||||
|
&mut self,
|
||||||
|
lvl: Level,
|
||||||
|
term_loc: GenContext,
|
||||||
|
cell: &'a Cell<RegType>,
|
||||||
|
code: &mut CodeDeque,
|
||||||
|
) {
|
||||||
|
let r = cell.get();
|
||||||
|
|
||||||
|
let r = match lvl {
|
||||||
|
Level::Shallow => {
|
||||||
|
let k = self.arg_c;
|
||||||
|
|
||||||
|
if let GenContext::Last(chunk_num) = term_loc {
|
||||||
|
self.evacuate_arg::<Target>(chunk_num, code);
|
||||||
|
}
|
||||||
|
|
||||||
|
self.arg_c += 1;
|
||||||
|
RegType::Temp(k)
|
||||||
|
}
|
||||||
|
_ if r.reg_num() == 0 => RegType::Temp(self.alloc_reg_to_non_var()),
|
||||||
|
_ => {
|
||||||
|
self.in_use.insert(r.reg_num());
|
||||||
|
r
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
cell.set(r);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn mark_var<'a, Target: CompilationTarget<'a>>(
|
||||||
|
&mut self,
|
||||||
|
var_num: usize,
|
||||||
|
lvl: Level,
|
||||||
|
cell: &Cell<VarReg>,
|
||||||
|
term_loc: GenContext,
|
||||||
|
code: &mut CodeDeque,
|
||||||
|
) {
|
||||||
|
let (r, is_new_var) = match self.get_binding(var_num) {
|
||||||
|
RegType::Temp(0) => {
|
||||||
|
let o = self.alloc_reg_to_var::<Target>(var_num, lvl, term_loc, code);
|
||||||
|
cell.set(VarReg::Norm(RegType::Temp(o)));
|
||||||
|
(RegType::Temp(o), true)
|
||||||
|
}
|
||||||
|
RegType::Perm(0) => {
|
||||||
|
let p = self.alloc_perm_var(var_num, term_loc.chunk_num());
|
||||||
|
cell.set(VarReg::Norm(RegType::Perm(p)));
|
||||||
|
(RegType::Perm(p), true)
|
||||||
|
}
|
||||||
|
r @ RegType::Perm(_) => {
|
||||||
|
let is_new_var = match &mut self.var_data.records[var_num].allocation {
|
||||||
|
VarAlloc::Perm(_, allocation) => {
|
||||||
|
if allocation.pending() {
|
||||||
|
*allocation = PermVarAllocation::done();
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => unreachable!(),
|
||||||
|
};
|
||||||
|
|
||||||
|
(r, is_new_var)
|
||||||
|
}
|
||||||
|
r => (r, false),
|
||||||
|
};
|
||||||
|
|
||||||
|
self.mark_reserved_var::<Target>(var_num, lvl, cell, term_loc, code, r, is_new_var);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn mark_reserved_var<'a, Target: CompilationTarget<'a>>(
|
||||||
|
&mut self,
|
||||||
|
var_num: usize,
|
||||||
|
lvl: Level,
|
||||||
|
cell: &Cell<VarReg>,
|
||||||
|
term_loc: GenContext,
|
||||||
|
code: &mut CodeDeque,
|
||||||
|
r: RegType,
|
||||||
|
is_new_var: bool,
|
||||||
|
) {
|
||||||
|
match lvl {
|
||||||
|
Level::Root | Level::Shallow => {
|
||||||
|
let k = self.arg_c;
|
||||||
|
|
||||||
|
if self.is_curr_arg_distinct_from(var_num) {
|
||||||
|
self.evacuate_arg::<Target>(term_loc.chunk_num(), code);
|
||||||
|
}
|
||||||
|
|
||||||
|
cell.set(VarReg::ArgAndNorm(r, k));
|
||||||
|
|
||||||
|
if !self.in_place(var_num, term_loc, r, k) {
|
||||||
|
if is_new_var {
|
||||||
|
self.mark_safe_var(var_num, lvl, term_loc);
|
||||||
|
code.push_back(Target::argument_to_variable(r, k));
|
||||||
|
} else {
|
||||||
|
code.push_back(self.argument_to_value::<Target>(var_num, r, k));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.arg_c += 1;
|
||||||
|
}
|
||||||
|
Level::Deep if is_new_var => {
|
||||||
|
if let GenContext::Head = term_loc {
|
||||||
|
if self.occurs_shallowly_in_head(var_num, r.reg_num()) {
|
||||||
|
code.push_back(self.subterm_to_value::<Target>(var_num, r));
|
||||||
|
} else {
|
||||||
|
self.mark_safe_var(var_num, lvl, term_loc);
|
||||||
|
code.push_back(Target::subterm_to_variable(r));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
self.mark_safe_var(var_num, lvl, term_loc);
|
||||||
|
code.push_back(Target::subterm_to_variable(r));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Level::Deep => code.push_back(self.subterm_to_value::<Target>(var_num, r)),
|
||||||
|
}
|
||||||
|
|
||||||
|
let o = r.reg_num();
|
||||||
|
|
||||||
|
if !r.is_perm() {
|
||||||
|
self.shallow_temp_mappings.insert(o, var_num);
|
||||||
|
} else if r.is_perm() && is_new_var {
|
||||||
|
self.branch_stack.add_branch_occurrence(var_num);
|
||||||
|
}
|
||||||
|
|
||||||
|
let record = &mut self.var_data.records[var_num];
|
||||||
|
|
||||||
|
record.allocation.set_register(o);
|
||||||
|
|
||||||
|
if record.running_count < record.num_occurrences {
|
||||||
|
record.running_count += 1;
|
||||||
|
} else {
|
||||||
|
self.free_var(term_loc.chunk_num(), var_num);
|
||||||
|
}
|
||||||
|
|
||||||
|
self.in_use.insert(o);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn mark_cut_var(&mut self, var_num: usize, chunk_num: usize) -> RegType {
|
||||||
|
match self.get_binding(var_num) {
|
||||||
|
RegType::Perm(0) => RegType::Perm(self.alloc_perm_var(var_num, chunk_num)),
|
||||||
|
RegType::Temp(0) => {
|
||||||
|
let t = self.alloc_reg_to_non_var();
|
||||||
|
|
||||||
|
match &mut self.var_data.records[var_num].allocation {
|
||||||
|
VarAlloc::Temp {
|
||||||
|
temp_reg, safety, ..
|
||||||
|
} => {
|
||||||
|
*temp_reg = t;
|
||||||
|
*safety = VarSafetyStatus::GloballyUnneeded;
|
||||||
|
}
|
||||||
|
_ => unreachable!(),
|
||||||
|
};
|
||||||
|
|
||||||
|
RegType::Temp(t)
|
||||||
|
}
|
||||||
|
r => r,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn reset(&mut self) {
|
||||||
|
self.perm_lb = 1;
|
||||||
|
self.shallow_temp_mappings.clear();
|
||||||
|
self.in_use.clear();
|
||||||
|
self.temp_free_list.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn reset_contents(&mut self) {
|
||||||
|
self.in_use.clear();
|
||||||
|
self.shallow_temp_mappings.clear();
|
||||||
|
self.temp_free_list.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn advance_arg(&mut self) {
|
||||||
|
self.arg_c += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn reset_at_head(&mut self, args: &[Term]) {
|
||||||
|
self.reset_arg(args.len());
|
||||||
|
self.arity = args.len();
|
||||||
|
|
||||||
|
for (idx, arg) in args.iter().enumerate() {
|
||||||
|
if let Term::Var(_, var) = arg {
|
||||||
|
let var_num = var.to_var_num().unwrap();
|
||||||
|
let r = self.get_binding(var_num);
|
||||||
|
|
||||||
|
if !r.is_perm() && r.reg_num() == 0 {
|
||||||
|
self.in_use.insert(idx + 1);
|
||||||
|
self.shallow_temp_mappings.insert(idx + 1, var_num);
|
||||||
|
self.var_data.records[var_num]
|
||||||
|
.allocation
|
||||||
|
.set_register(idx + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn reset_arg(&mut self, arity: usize) {
|
||||||
|
self.arity = 0;
|
||||||
|
self.arg_c = 1;
|
||||||
|
self.temp_lb = arity + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn max_reg_allocated(&self) -> usize {
|
||||||
|
std::cmp::max(self.temp_lb, self.arg_c)
|
||||||
|
}
|
||||||
|
}
|
||||||
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)
|
||||||
|
).
|
||||||
|
|
||||||
51
src/examples/least_time.pl
Normal file
51
src/examples/least_time.pl
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
/* least_time.pl
|
||||||
|
*
|
||||||
|
* By Mark Thom, 2020
|
||||||
|
*
|
||||||
|
* find_min_time/2 solves a problem sometimes posed in the first round
|
||||||
|
* of Google interviews: given a time of day in 24 H format, what is the
|
||||||
|
* lexicographically least permutation of the time that is itself a
|
||||||
|
* valid time in 24 H format?
|
||||||
|
*
|
||||||
|
* Full generality is achieved using the reif library.
|
||||||
|
*/
|
||||||
|
|
||||||
|
:- module(least_time, [find_min_time/2,
|
||||||
|
write_time_nl/1]).
|
||||||
|
|
||||||
|
|
||||||
|
:- use_module(library(dcgs)).
|
||||||
|
:- use_module(library(format)).
|
||||||
|
:- use_module(library(lists)).
|
||||||
|
:- use_module(library(reif)).
|
||||||
|
|
||||||
|
|
||||||
|
valid_time([H1,H2,M1,M2], T) :-
|
||||||
|
memberd_t(H1, [0,1,2], TH1),
|
||||||
|
memberd_t(H2, [0,1,2,3,4,5,6,7,8,9], TH2),
|
||||||
|
memberd_t(M1, [0,1,2,3,4,5], TM1),
|
||||||
|
memberd_t(M2, [0,1,2,3,4,5,6,7,8,9], TM2),
|
||||||
|
( maplist(=(true), [TH1, TH2, TM1, TM2]) ->
|
||||||
|
( H1 =:= 2 ->
|
||||||
|
( H2 =< 3 ->
|
||||||
|
T = true
|
||||||
|
; T = false
|
||||||
|
)
|
||||||
|
; T = true
|
||||||
|
)
|
||||||
|
; T = false
|
||||||
|
).
|
||||||
|
|
||||||
|
|
||||||
|
permuted_times(Time, PermutedTimes) :-
|
||||||
|
setof(P, permutation(Time, P), PermutedTimes0),
|
||||||
|
tfilter(valid_time, PermutedTimes0, PermutedTimes).
|
||||||
|
|
||||||
|
|
||||||
|
find_min_time(Time, Min) :-
|
||||||
|
valid_time(Time, true),
|
||||||
|
permuted_times(Time, [Min|_]).
|
||||||
|
|
||||||
|
|
||||||
|
write_time_nl(Time) :-
|
||||||
|
format("\"~w~w:~w~w\"~n", Time).
|
||||||
@@ -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) :-
|
||||||
23
src/examples/utf8.pl
Normal file
23
src/examples/utf8.pl
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
:- use_module(library(charsio)).
|
||||||
|
:- use_module(library(lists)).
|
||||||
|
:- use_module(library(pio)).
|
||||||
|
:- use_module(library(dcgs)).
|
||||||
|
|
||||||
|
:- 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 :-
|
||||||
|
chars_utf8bytes("£\x2124\\x2764\\x1F496\\n", Bs),
|
||||||
|
maplist(char_code, Cs, Bs),
|
||||||
|
phrase_to_file(Cs, "x.txt", [type(binary)]).
|
||||||
|
|
||||||
|
read_f :-
|
||||||
|
phrase_from_file(seq(Cs), "x.txt", [type(binary)]),
|
||||||
|
maplist(char_code, Cs, Bs),
|
||||||
|
chars_utf8bytes(Chars, Bs),
|
||||||
|
write(Chars).
|
||||||
1004
src/ffi.rs
Normal file
1004
src/ffi.rs
Normal file
File diff suppressed because it is too large
Load Diff
1087
src/forms.rs
Normal file
1087
src/forms.rs
Normal file
File diff suppressed because it is too large
Load Diff
798
src/functor_macro.rs
Normal file
798
src/functor_macro.rs
Normal file
@@ -0,0 +1,798 @@
|
|||||||
|
//! A macro to construct functor terms ready to be written to the WAM
|
||||||
|
//! heap.
|
||||||
|
|
||||||
|
use crate::atom_table::*;
|
||||||
|
use crate::instructions::IndexingCodePtr;
|
||||||
|
use crate::machine::heap::Heap;
|
||||||
|
use crate::parser::ast::Fixnum;
|
||||||
|
use crate::types::*;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
|
pub(crate) enum FunctorElement {
|
||||||
|
AbsoluteCell(HeapCellValue),
|
||||||
|
Cell(HeapCellValue),
|
||||||
|
InnerFunctor(u64, Vec<FunctorElement>),
|
||||||
|
String(u64, String),
|
||||||
|
}
|
||||||
|
|
||||||
|
// helper macros
|
||||||
|
macro_rules! count {
|
||||||
|
() => (0);
|
||||||
|
( $x:tt $($xs:tt)* ) => (1 + count!($($xs)*));
|
||||||
|
}
|
||||||
|
|
||||||
|
// core macros
|
||||||
|
|
||||||
|
/*
|
||||||
|
* functor! is more declarative now, with fewer effects and more
|
||||||
|
* work done at compile time using const functions. With these
|
||||||
|
* advantages come new quirks: expressions must generally be wrapped
|
||||||
|
* in round parentheses for rustc to parse them. See the tests module
|
||||||
|
* below for examples, especially those involving atom!
|
||||||
|
* subexpressions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
macro_rules! functor {
|
||||||
|
($name:expr) => ({
|
||||||
|
vec![FunctorElement::Cell(atom_as_cell!($name))]
|
||||||
|
});
|
||||||
|
($name:expr, [$($dt:ident($($value:tt),*)),+]) => ({
|
||||||
|
build_functor!([$($dt($($value),*)),*],
|
||||||
|
[FunctorElement::Cell(atom_as_cell!($name, count!($($dt) *)))],
|
||||||
|
1,
|
||||||
|
[])
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! inner_functor {
|
||||||
|
($name:expr, $res_len:expr, [$($dt:ident($($value:tt),*)),+]) => ({
|
||||||
|
build_functor!([$($dt($($value),*)),*],
|
||||||
|
[FunctorElement::Cell(atom_as_cell!($name, count!($($dt) *)))],
|
||||||
|
1 + $res_len,
|
||||||
|
[])
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! build_functor {
|
||||||
|
([], [$($res:expr),*], $res_len:expr, [$($subfunctor:expr),*]) => ({
|
||||||
|
vec![$($res,)* $($subfunctor),*]
|
||||||
|
});
|
||||||
|
([indexing_code_ptr($e:expr) $(, $dt:ident($($value:tt),*))*],
|
||||||
|
[$($res:expr),*],
|
||||||
|
$res_len:expr,
|
||||||
|
[$($subfunctor:expr),*]) => ({
|
||||||
|
let (inner_functor, cell_size) = indexing_code_ptr($e);
|
||||||
|
let referent = if cell_size == 1 {
|
||||||
|
heap_loc_as_cell!(1u64 + count!($($dt)*) + $res_len)
|
||||||
|
} else {
|
||||||
|
str_loc_as_cell!(1u64 + count!($($dt)*) + $res_len)
|
||||||
|
};
|
||||||
|
|
||||||
|
build_functor!([$($dt($($value),*)),*],
|
||||||
|
[$($res, )* FunctorElement::Cell(referent)],
|
||||||
|
1 + cell_size + $res_len,
|
||||||
|
[$($subfunctor, )* FunctorElement::InnerFunctor(cell_size, inner_functor)])
|
||||||
|
});
|
||||||
|
([fixnum($e:expr) $(, $dt:ident($($value:tt),*))*],
|
||||||
|
[$($res:expr),*],
|
||||||
|
$res_len:expr,
|
||||||
|
[$($subfunctor:expr),*]) => ({
|
||||||
|
build_functor!([$($dt($($value),*)),*],
|
||||||
|
[$($res, )* FunctorElement::Cell(fixnum_as_cell!(/*FIXME this is not safe*/ unsafe{Fixnum::build_with_unchecked($e as i64)}))],
|
||||||
|
1 + $res_len,
|
||||||
|
[$($subfunctor),*])
|
||||||
|
});
|
||||||
|
([cell($e:expr) $(, $dt:ident($($value:tt),*))*],
|
||||||
|
[$($res:expr),*],
|
||||||
|
$res_len:expr,
|
||||||
|
[$($subfunctor:expr),*]) => ({
|
||||||
|
build_functor!([$($dt($($value),*)),*],
|
||||||
|
[$($res, )* FunctorElement::AbsoluteCell($e)],
|
||||||
|
1 + $res_len,
|
||||||
|
[$($subfunctor),*])
|
||||||
|
});
|
||||||
|
([literal($e:expr) $(, $dt:ident($($value:tt),*))*],
|
||||||
|
[$($res:expr),*],
|
||||||
|
$res_len:expr,
|
||||||
|
[$($subfunctor:expr),*]) => ({
|
||||||
|
build_functor!([$($dt($($value),*)),*],
|
||||||
|
[$($res, )* FunctorElement::AbsoluteCell(HeapCellValue::from($e))],
|
||||||
|
1 + $res_len,
|
||||||
|
[$($subfunctor),*])
|
||||||
|
});
|
||||||
|
([number($n:expr, $arena:expr) $(, $dt:ident($($value:tt),*))*],
|
||||||
|
[$($res:expr),*],
|
||||||
|
$res_len:expr,
|
||||||
|
[$($subfunctor:expr),*]) => ({
|
||||||
|
let number_cell = HeapCellValue::arena_from($n, $arena);
|
||||||
|
|
||||||
|
build_functor!([$($dt($($value),*)),*],
|
||||||
|
[$($res, )* FunctorElement::Cell(number_cell)],
|
||||||
|
1 + $res_len,
|
||||||
|
[$($subfunctor),*])
|
||||||
|
});
|
||||||
|
([list([]) $(, $dt:ident($($value:tt),*))*],
|
||||||
|
[$($res:expr),*],
|
||||||
|
$res_len:expr,
|
||||||
|
[$($subfunctor:expr),*]) => ({
|
||||||
|
build_functor!([$($dt($($value),*)),*],
|
||||||
|
[$($res, )* FunctorElement::Cell(empty_list_as_cell!())],
|
||||||
|
1 + $res_len,
|
||||||
|
[$($subfunctor),*])
|
||||||
|
});
|
||||||
|
([list([$id:ident($($id_value:tt),*) $(, $in_dt:ident($($in_value:tt),*))*]) $(, $dt:ident($($value:tt),*))*],
|
||||||
|
[$($res:expr),*],
|
||||||
|
$res_len:expr,
|
||||||
|
[$($subfunctor:expr),*]) => ({
|
||||||
|
build_functor!([functor((atom!(".")), [$id($($id_value),*), list([$($in_dt($($in_value),*)),*])])
|
||||||
|
$(, $dt($($value),*))*],
|
||||||
|
[$($res),*],
|
||||||
|
$res_len,
|
||||||
|
[$($subfunctor),*])
|
||||||
|
});
|
||||||
|
([string($s:expr) $(, $dt:ident($($value:tt),*))*], [$($res:expr),*], $res_len:expr, [$($subfunctor:expr),*]) => ({
|
||||||
|
#[allow(unused_parens)]
|
||||||
|
let string = $s;
|
||||||
|
let pstr_len = cell_index!(Heap::compute_pstr_size(&string)) as u64;
|
||||||
|
let result_len = 1 + count!($($dt)*) + $res_len;
|
||||||
|
|
||||||
|
build_functor!([$($dt($($value),*)),*],
|
||||||
|
[$($res, )* FunctorElement::Cell(pstr_loc_as_cell!(heap_index!(result_len as usize) as u64))],
|
||||||
|
1 + $res_len + pstr_len,
|
||||||
|
[$($subfunctor, )* FunctorElement::String(pstr_len, string)])
|
||||||
|
});
|
||||||
|
([atom_as_cell($n:expr) $(, $dt:ident($($value:tt),*))*], [$($res:expr),*], $res_len:expr, [$($subfunctor:expr),*]) => ({
|
||||||
|
build_functor!([$($dt($($value),*)),*],
|
||||||
|
[$($res, )* FunctorElement::Cell(atom_as_cell!($n))],
|
||||||
|
1 + $res_len,
|
||||||
|
[$($subfunctor),*])
|
||||||
|
});
|
||||||
|
([functor($stub:expr) $(, $dt:ident($($value:tt),*))*], [$($res:expr),*], $res_len:expr, [$($subfunctor:expr),*]) => ({
|
||||||
|
let result_len = 1u64 + count!($($dt)*) + $res_len;
|
||||||
|
let inner_functor_size = cell_index!(Heap::compute_functor_byte_size(&$stub)) as u64;
|
||||||
|
|
||||||
|
build_functor!([$($dt($($value),*)),*],
|
||||||
|
[$($res, )* FunctorElement::Cell(str_loc_as_cell!(result_len))],
|
||||||
|
1 + $res_len + inner_functor_size,
|
||||||
|
[$($subfunctor, )*
|
||||||
|
FunctorElement::InnerFunctor(inner_functor_size, $stub)])
|
||||||
|
});
|
||||||
|
([$id:ident($n:expr) $(, $dt:ident($($value:tt),*))*], [$($res:expr),*], $res_len:expr, [$($subfunctor:expr),*]) => ({
|
||||||
|
build_functor!([$($dt($($value),*)),*],
|
||||||
|
[$($res, )* FunctorElement::Cell($id!($n))],
|
||||||
|
1 + $res_len,
|
||||||
|
[$($subfunctor),*])
|
||||||
|
});
|
||||||
|
([functor($name:expr, [$($in_dt:ident($($in_value:tt),*)),+]) $(, $dt:ident($($value:tt),*))*],
|
||||||
|
[$($res:expr),*],
|
||||||
|
$res_len:expr,
|
||||||
|
[$($subfunctor:expr),*]) => ({
|
||||||
|
let result_len = 1u64 + count!($($dt)*) + $res_len;
|
||||||
|
let inner_functor = inner_functor!($name, 0, [$($in_dt($($in_value),*)),*]);
|
||||||
|
let inner_functor_size = cell_index!(Heap::compute_functor_byte_size(&inner_functor)) as u64;
|
||||||
|
|
||||||
|
build_functor!([$($dt($($value),*)),*],
|
||||||
|
[$($res, )* FunctorElement::Cell(str_loc_as_cell!(result_len))],
|
||||||
|
1 + $res_len + inner_functor_size,
|
||||||
|
[$($subfunctor, )*
|
||||||
|
FunctorElement::InnerFunctor(inner_functor_size, inner_functor)])
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn indexing_code_ptr(code_ptr: IndexingCodePtr) -> (Vec<FunctorElement>, u64) {
|
||||||
|
match code_ptr {
|
||||||
|
IndexingCodePtr::DynamicExternal(o) => {
|
||||||
|
(functor!(atom!("dynamic_external"), [fixnum(o)]), 2)
|
||||||
|
}
|
||||||
|
IndexingCodePtr::External(o) => (functor!(atom!("external"), [fixnum(o)]), 2),
|
||||||
|
IndexingCodePtr::Internal(o) => (functor!(atom!("internal"), [fixnum(o)]), 2),
|
||||||
|
IndexingCodePtr::Fail => (vec![FunctorElement::Cell(atom_as_cell!(atom!("fail")))], 1),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn variadic_functor(
|
||||||
|
name: Atom,
|
||||||
|
arity: usize,
|
||||||
|
iter: impl Iterator<Item = Vec<FunctorElement>>,
|
||||||
|
) -> Vec<FunctorElement> {
|
||||||
|
let mut arg_vec = vec![
|
||||||
|
FunctorElement::Cell(atom_as_cell!(name, arity)),
|
||||||
|
FunctorElement::Cell(list_loc_as_cell!(2)),
|
||||||
|
];
|
||||||
|
|
||||||
|
let key_value_pairs: Vec<_> = iter.collect();
|
||||||
|
let num_items = key_value_pairs.len();
|
||||||
|
let mut functor_offset = 0;
|
||||||
|
|
||||||
|
for (idx, kv_func) in key_value_pairs.iter().enumerate() {
|
||||||
|
let functor_size = cell_index!(Heap::compute_functor_byte_size(kv_func));
|
||||||
|
|
||||||
|
arg_vec.push(FunctorElement::Cell(str_loc_as_cell!(
|
||||||
|
2 + num_items * 2 + functor_offset
|
||||||
|
)));
|
||||||
|
arg_vec.push(FunctorElement::Cell(list_loc_as_cell!(4 + 2 * idx)));
|
||||||
|
|
||||||
|
functor_offset += functor_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
arg_vec.pop();
|
||||||
|
arg_vec.push(FunctorElement::Cell(empty_list_as_cell!()));
|
||||||
|
|
||||||
|
arg_vec.extend(key_value_pairs.into_iter().map(|kv_func| {
|
||||||
|
let inner_functor_size = cell_index!(Heap::compute_functor_byte_size(&kv_func));
|
||||||
|
FunctorElement::InnerFunctor(inner_functor_size as u64, kv_func)
|
||||||
|
}));
|
||||||
|
|
||||||
|
arg_vec
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
#[allow(unused_parens)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
use FunctorElement::*;
|
||||||
|
use indexmap::indexmap;
|
||||||
|
use std::string::String;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn basic_terms() {
|
||||||
|
let functor = functor!(
|
||||||
|
atom!("first"),
|
||||||
|
[atom_as_cell((atom!("a"))), char_as_cell('c')]
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(functor.len(), 3);
|
||||||
|
|
||||||
|
assert_eq!(functor[0], Cell(atom_as_cell!(atom!("first"), 2)));
|
||||||
|
assert_eq!(functor[1], Cell(atom_as_cell!(atom!("a"))));
|
||||||
|
assert_eq!(functor[2], Cell(char_as_cell!('c')));
|
||||||
|
|
||||||
|
let functor = functor!(
|
||||||
|
atom!("second"),
|
||||||
|
[
|
||||||
|
atom_as_cell((atom!("a"))),
|
||||||
|
functor((atom!("b")), [fixnum(1), fixnum(2)]),
|
||||||
|
char_as_cell('c')
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(functor.len(), 5);
|
||||||
|
|
||||||
|
assert_eq!(functor[0], Cell(atom_as_cell!(atom!("second"), 3)));
|
||||||
|
assert_eq!(functor[1], Cell(atom_as_cell!(atom!("a"))));
|
||||||
|
assert_eq!(functor[2], Cell(str_loc_as_cell!(4)));
|
||||||
|
assert_eq!(functor[3], Cell(char_as_cell!('c')));
|
||||||
|
assert_eq!(
|
||||||
|
functor[4],
|
||||||
|
InnerFunctor(3, functor!(atom!("b"), [fixnum(1), fixnum(2)]))
|
||||||
|
);
|
||||||
|
|
||||||
|
let functor = functor!(
|
||||||
|
atom!("third"),
|
||||||
|
[
|
||||||
|
atom_as_cell((atom!("a"))),
|
||||||
|
functor((atom!("b")), [fixnum(1), fixnum(2)]),
|
||||||
|
functor((atom!("c")), [fixnum(1), fixnum(2)]),
|
||||||
|
char_as_cell('c')
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(functor.len(), 7);
|
||||||
|
|
||||||
|
assert_eq!(functor[0], Cell(atom_as_cell!(atom!("third"), 4)));
|
||||||
|
assert_eq!(functor[1], Cell(atom_as_cell!(atom!("a"))));
|
||||||
|
assert_eq!(functor[2], Cell(str_loc_as_cell!(5)));
|
||||||
|
assert_eq!(functor[3], Cell(str_loc_as_cell!(8)));
|
||||||
|
assert_eq!(functor[4], Cell(char_as_cell!('c')));
|
||||||
|
assert_eq!(
|
||||||
|
functor[5],
|
||||||
|
InnerFunctor(3, functor!(atom!("b"), [fixnum(1), fixnum(2)]))
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
functor[6],
|
||||||
|
InnerFunctor(3, functor!(atom!("c"), [fixnum(1), fixnum(2)]))
|
||||||
|
);
|
||||||
|
|
||||||
|
let functor = functor!(
|
||||||
|
atom!("fourth"),
|
||||||
|
[
|
||||||
|
atom_as_cell((atom!("a"))),
|
||||||
|
functor((atom!("b")), [fixnum(1), fixnum(2)]),
|
||||||
|
functor((atom!("c")), [fixnum(1)]),
|
||||||
|
functor((atom!("d")), [fixnum(453), fixnum(2)]),
|
||||||
|
char_as_cell('c')
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(functor.len(), 9);
|
||||||
|
|
||||||
|
assert_eq!(functor[0], Cell(atom_as_cell!(atom!("fourth"), 5)));
|
||||||
|
assert_eq!(functor[1], Cell(atom_as_cell!(atom!("a"))));
|
||||||
|
assert_eq!(functor[2], Cell(str_loc_as_cell!(6)));
|
||||||
|
assert_eq!(functor[3], Cell(str_loc_as_cell!(9)));
|
||||||
|
assert_eq!(functor[4], Cell(str_loc_as_cell!(11)));
|
||||||
|
assert_eq!(functor[5], Cell(char_as_cell!('c')));
|
||||||
|
assert_eq!(
|
||||||
|
functor[6],
|
||||||
|
InnerFunctor(3, functor!(atom!("b"), [fixnum(1), fixnum(2)]))
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
functor[7],
|
||||||
|
InnerFunctor(2, functor!(atom!("c"), [fixnum(1)]))
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
functor[8],
|
||||||
|
InnerFunctor(3, functor!(atom!("d"), [fixnum(453), fixnum(2)]))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn basic_terms_in_heap() {
|
||||||
|
let functor = functor!(
|
||||||
|
atom!("first"),
|
||||||
|
[atom_as_cell((atom!("a"))), char_as_cell('b')]
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(functor.len(), 3);
|
||||||
|
|
||||||
|
let mut heap = Heap::new();
|
||||||
|
let mut functor_writer = Heap::functor_writer(functor);
|
||||||
|
let loc = functor_writer(&mut heap).unwrap();
|
||||||
|
|
||||||
|
assert_eq!(loc, str_loc_as_cell!(0));
|
||||||
|
|
||||||
|
assert_eq!(heap[0], atom_as_cell!(atom!("first"), 2));
|
||||||
|
assert_eq!(heap[1], atom_as_cell!(atom!("a")));
|
||||||
|
assert_eq!(heap[2], char_as_cell!('b'));
|
||||||
|
|
||||||
|
heap.truncate(2);
|
||||||
|
|
||||||
|
let functor = functor!(
|
||||||
|
atom!("second"),
|
||||||
|
[
|
||||||
|
atom_as_cell((atom!("a"))),
|
||||||
|
functor((atom!("b")), [fixnum(1), fixnum(2)]),
|
||||||
|
functor((atom!("c")), [fixnum(1), fixnum(2)]),
|
||||||
|
char_as_cell('b')
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(functor.len(), 7);
|
||||||
|
|
||||||
|
let mut functor_writer = Heap::functor_writer(functor);
|
||||||
|
let loc = functor_writer(&mut heap).unwrap();
|
||||||
|
|
||||||
|
assert_eq!(loc, str_loc_as_cell!(2));
|
||||||
|
|
||||||
|
assert_eq!(heap[2], atom_as_cell!(atom!("second"), 4));
|
||||||
|
assert_eq!(heap[3], atom_as_cell!(atom!("a")));
|
||||||
|
assert_eq!(heap[4], str_loc_as_cell!(7));
|
||||||
|
assert_eq!(heap[5], str_loc_as_cell!(10));
|
||||||
|
assert_eq!(heap[6], char_as_cell!('b'));
|
||||||
|
assert_eq!(heap[7], atom_as_cell!(atom!("b"), 2));
|
||||||
|
assert_eq!(heap[8], fixnum_as_cell!(Fixnum::build_with(1)));
|
||||||
|
assert_eq!(heap[9], fixnum_as_cell!(Fixnum::build_with(2)));
|
||||||
|
assert_eq!(heap[10], atom_as_cell!(atom!("c"), 2));
|
||||||
|
assert_eq!(heap[11], fixnum_as_cell!(Fixnum::build_with(1)));
|
||||||
|
assert_eq!(heap[12], fixnum_as_cell!(Fixnum::build_with(2)));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn nested_functors() {
|
||||||
|
let functor = functor!(
|
||||||
|
atom!("first"),
|
||||||
|
[
|
||||||
|
atom_as_cell((atom!("a"))),
|
||||||
|
functor(
|
||||||
|
(atom!("d")),
|
||||||
|
[
|
||||||
|
fixnum(1),
|
||||||
|
functor(
|
||||||
|
(atom!("b")),
|
||||||
|
[atom_as_cell((atom!("c"))), char_as_cell('c')]
|
||||||
|
)
|
||||||
|
]
|
||||||
|
),
|
||||||
|
functor((atom!("e")), [fixnum(453), fixnum(2)]),
|
||||||
|
char_as_cell('b')
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(functor.len(), 7);
|
||||||
|
|
||||||
|
assert_eq!(functor[0], Cell(atom_as_cell!(atom!("first"), 4)));
|
||||||
|
assert_eq!(functor[1], Cell(atom_as_cell!(atom!("a"))));
|
||||||
|
assert_eq!(functor[2], Cell(str_loc_as_cell!(5)));
|
||||||
|
assert_eq!(functor[3], Cell(str_loc_as_cell!(11)));
|
||||||
|
assert_eq!(functor[4], Cell(char_as_cell!('b')));
|
||||||
|
assert_eq!(
|
||||||
|
functor[5],
|
||||||
|
InnerFunctor(
|
||||||
|
6,
|
||||||
|
vec![
|
||||||
|
Cell(atom_as_cell!(atom!("d"), 2)),
|
||||||
|
Cell(fixnum_as_cell!(Fixnum::build_with(1))),
|
||||||
|
Cell(str_loc_as_cell!(3)),
|
||||||
|
InnerFunctor(
|
||||||
|
3,
|
||||||
|
functor!(atom!("b"), [atom_as_cell((atom!("c"))), char_as_cell('c')])
|
||||||
|
)
|
||||||
|
]
|
||||||
|
)
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
functor[6],
|
||||||
|
InnerFunctor(3, functor!(atom!("e"), [fixnum(453), fixnum(2)]))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn nested_functors_in_heap() {
|
||||||
|
let functor = functor!(
|
||||||
|
atom!("first"),
|
||||||
|
[
|
||||||
|
atom_as_cell((atom!("a"))),
|
||||||
|
functor(
|
||||||
|
(atom!("second")),
|
||||||
|
[
|
||||||
|
fixnum(1),
|
||||||
|
functor(
|
||||||
|
(atom!("third")),
|
||||||
|
[atom_as_cell((atom!("b"))), char_as_cell('c')]
|
||||||
|
)
|
||||||
|
]
|
||||||
|
),
|
||||||
|
functor((atom!("fourth")), [fixnum(453), fixnum(2)]),
|
||||||
|
char_as_cell('b')
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
let mut heap = Heap::new();
|
||||||
|
let mut functor_writer = Heap::functor_writer(functor);
|
||||||
|
let loc = functor_writer(&mut heap).unwrap();
|
||||||
|
|
||||||
|
assert_eq!(loc, str_loc_as_cell!(0));
|
||||||
|
|
||||||
|
assert_eq!(heap.cell_len(), 14);
|
||||||
|
|
||||||
|
assert_eq!(heap[0], atom_as_cell!(atom!("first"), 4));
|
||||||
|
assert_eq!(heap[1], atom_as_cell!(atom!("a")));
|
||||||
|
assert_eq!(heap[2], str_loc_as_cell!(5));
|
||||||
|
assert_eq!(heap[3], str_loc_as_cell!(11));
|
||||||
|
assert_eq!(heap[4], char_as_cell!('b'));
|
||||||
|
assert_eq!(heap[5], atom_as_cell!(atom!("second"), 2));
|
||||||
|
assert_eq!(heap[6], fixnum_as_cell!(Fixnum::build_with(1)));
|
||||||
|
assert_eq!(heap[7], str_loc_as_cell!(8));
|
||||||
|
assert_eq!(heap[8], atom_as_cell!(atom!("third"), 2));
|
||||||
|
assert_eq!(heap[9], atom_as_cell!(atom!("b")));
|
||||||
|
assert_eq!(heap[10], char_as_cell!('c'));
|
||||||
|
assert_eq!(heap[11], atom_as_cell!(atom!("fourth"), 2));
|
||||||
|
assert_eq!(heap[12], fixnum_as_cell!(Fixnum::build_with(453)));
|
||||||
|
assert_eq!(heap[13], fixnum_as_cell!(Fixnum::build_with(2)));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn functors_with_strings_in_heap() {
|
||||||
|
let functor = functor!(atom!("first"), [string((String::from("a string")))]);
|
||||||
|
|
||||||
|
assert_eq!(functor.len(), 3);
|
||||||
|
|
||||||
|
let mut heap = Heap::new();
|
||||||
|
let mut functor_writer = Heap::functor_writer(functor);
|
||||||
|
let loc = functor_writer(&mut heap).unwrap();
|
||||||
|
|
||||||
|
assert_eq!(loc, str_loc_as_cell!(0));
|
||||||
|
assert_eq!(heap.cell_len(), 5);
|
||||||
|
|
||||||
|
assert_eq!(heap[0], atom_as_cell!(atom!("first"), 1));
|
||||||
|
assert_eq!(heap[1], pstr_loc_as_cell!(heap_index!(2)));
|
||||||
|
assert_eq!(
|
||||||
|
heap.slice_to_str(heap_index!(2), "a string".len()),
|
||||||
|
"a string"
|
||||||
|
);
|
||||||
|
assert_eq!(heap[4], empty_list_as_cell!());
|
||||||
|
|
||||||
|
heap.truncate(0);
|
||||||
|
|
||||||
|
let functor = functor!(
|
||||||
|
atom!("second"),
|
||||||
|
[string((String::from("a stuttered\0 string")))]
|
||||||
|
);
|
||||||
|
|
||||||
|
let mut functor_writer = Heap::functor_writer(functor);
|
||||||
|
functor_writer(&mut heap).unwrap();
|
||||||
|
|
||||||
|
assert_eq!(heap.cell_len(), 10);
|
||||||
|
|
||||||
|
assert_eq!(heap[0], atom_as_cell!(atom!("second"), 1));
|
||||||
|
assert_eq!(heap[1], pstr_loc_as_cell!(heap_index!(2)));
|
||||||
|
assert_eq!(
|
||||||
|
heap.slice_to_str(heap_index!(2), "a stuttered".len()),
|
||||||
|
"a stuttered"
|
||||||
|
);
|
||||||
|
assert_eq!(heap[4], list_loc_as_cell!(5));
|
||||||
|
assert_eq!(heap[5], char_as_cell!('\u{0}'));
|
||||||
|
assert_eq!(heap[6], pstr_loc_as_cell!(heap_index!(7)));
|
||||||
|
assert_eq!(
|
||||||
|
heap.slice_to_str(heap_index!(7), " string".len()),
|
||||||
|
" string"
|
||||||
|
);
|
||||||
|
assert_eq!(heap[9], empty_list_as_cell!());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn functors_with_lists_in_heap() {
|
||||||
|
let functor = functor!(
|
||||||
|
atom!("first"),
|
||||||
|
[list([fixnum(1), atom_as_cell((atom!("a"))), fixnum(2)])]
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(functor.len(), 3);
|
||||||
|
|
||||||
|
let mut heap = Heap::new();
|
||||||
|
let mut functor_writer = Heap::functor_writer(functor);
|
||||||
|
|
||||||
|
functor_writer(&mut heap).unwrap();
|
||||||
|
|
||||||
|
assert_eq!(heap.cell_len(), 11);
|
||||||
|
|
||||||
|
assert_eq!(heap[0], atom_as_cell!(atom!("first"), 1));
|
||||||
|
assert_eq!(heap[1], str_loc_as_cell!(2));
|
||||||
|
assert_eq!(heap[2], atom_as_cell!(atom!("."), 2));
|
||||||
|
assert_eq!(heap[3], fixnum_as_cell!(Fixnum::build_with(1)));
|
||||||
|
assert_eq!(heap[4], str_loc_as_cell!(5));
|
||||||
|
assert_eq!(heap[5], atom_as_cell!(atom!("."), 2));
|
||||||
|
assert_eq!(heap[6], atom_as_cell!(atom!("a")));
|
||||||
|
assert_eq!(heap[7], str_loc_as_cell!(8));
|
||||||
|
assert_eq!(heap[8], atom_as_cell!(atom!("."), 2));
|
||||||
|
assert_eq!(heap[9], fixnum_as_cell!(Fixnum::build_with(2)));
|
||||||
|
assert_eq!(heap[10], empty_list_as_cell!());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn inlined_atoms() {
|
||||||
|
let atom_table = AtomTable::new().unwrap();
|
||||||
|
let inlined = AtomTable::build_with(&atom_table, "inline");
|
||||||
|
|
||||||
|
assert!(inlined.is_inlined());
|
||||||
|
assert_eq!(&*inlined.as_str(), "inline");
|
||||||
|
|
||||||
|
let non_inlined = AtomTable::build_with(&atom_table, "longer non-inlined atom");
|
||||||
|
|
||||||
|
assert!(!non_inlined.is_inlined());
|
||||||
|
assert_eq!(&*non_inlined.as_str(), "longer non-inlined atom");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn functors_with_indexing_code_ptr() {
|
||||||
|
let code_ptr = IndexingCodePtr::Internal(0);
|
||||||
|
let functor = functor!(
|
||||||
|
atom!("first"),
|
||||||
|
[
|
||||||
|
string((String::from("a string"))),
|
||||||
|
indexing_code_ptr(code_ptr)
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
let mut heap = Heap::new();
|
||||||
|
let mut functor_writer = Heap::functor_writer(functor);
|
||||||
|
|
||||||
|
functor_writer(&mut heap).unwrap();
|
||||||
|
|
||||||
|
assert_eq!(heap.cell_len(), 8);
|
||||||
|
|
||||||
|
assert_eq!(heap[0], atom_as_cell!(atom!("first"), 2));
|
||||||
|
assert_eq!(heap[1], pstr_loc_as_cell!(heap_index!(3)));
|
||||||
|
assert_eq!(heap[2], str_loc_as_cell!(6));
|
||||||
|
assert_eq!(
|
||||||
|
heap.slice_to_str(heap_index!(3), "a string".len()),
|
||||||
|
"a string"
|
||||||
|
);
|
||||||
|
assert_eq!(heap[5], empty_list_as_cell!());
|
||||||
|
assert_eq!(heap[6], atom_as_cell!(atom!("internal"), 1));
|
||||||
|
assert_eq!(heap[7], fixnum_as_cell!(Fixnum::build_with(0)));
|
||||||
|
|
||||||
|
heap.truncate(0);
|
||||||
|
|
||||||
|
let functor = functor!(
|
||||||
|
atom!("second"),
|
||||||
|
[
|
||||||
|
string((String::from("a string"))),
|
||||||
|
functor(
|
||||||
|
(atom!("third")),
|
||||||
|
[
|
||||||
|
atom_as_cell((atom!("a"))),
|
||||||
|
string((String::from("another string"))),
|
||||||
|
indexing_code_ptr(code_ptr)
|
||||||
|
]
|
||||||
|
)
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
let mut functor_writer = Heap::functor_writer(functor);
|
||||||
|
functor_writer(&mut heap).unwrap();
|
||||||
|
|
||||||
|
assert_eq!(heap.cell_len(), 15);
|
||||||
|
|
||||||
|
assert_eq!(heap[0], atom_as_cell!(atom!("second"), 2));
|
||||||
|
assert_eq!(heap[1], pstr_loc_as_cell!(heap_index!(3)));
|
||||||
|
assert_eq!(heap[2], str_loc_as_cell!(6));
|
||||||
|
assert_eq!(
|
||||||
|
heap.slice_to_str(heap_index!(3), "a string".len()),
|
||||||
|
"a string"
|
||||||
|
);
|
||||||
|
assert_eq!(heap[5], empty_list_as_cell!());
|
||||||
|
assert_eq!(heap[6], atom_as_cell!(atom!("third"), 3));
|
||||||
|
assert_eq!(heap[7], atom_as_cell!(atom!("a")));
|
||||||
|
assert_eq!(heap[8], pstr_loc_as_cell!(heap_index!(10)));
|
||||||
|
assert_eq!(heap[9], str_loc_as_cell!(13));
|
||||||
|
assert_eq!(
|
||||||
|
heap.slice_to_str(heap_index!(10), "another string".len()),
|
||||||
|
"another string"
|
||||||
|
);
|
||||||
|
assert_eq!(heap[12], empty_list_as_cell!());
|
||||||
|
assert_eq!(heap[13], atom_as_cell!(atom!("internal"), 1));
|
||||||
|
assert_eq!(heap[14], fixnum_as_cell!(Fixnum::build_with(0)));
|
||||||
|
|
||||||
|
let functor = functor!(
|
||||||
|
atom!("fourth"),
|
||||||
|
[
|
||||||
|
string((String::from("a string"))),
|
||||||
|
functor(
|
||||||
|
(atom!("a")),
|
||||||
|
[
|
||||||
|
functor(
|
||||||
|
(atom!("fifth")),
|
||||||
|
[
|
||||||
|
fixnum(5),
|
||||||
|
string((String::from("another string"))),
|
||||||
|
indexing_code_ptr(code_ptr)
|
||||||
|
]
|
||||||
|
),
|
||||||
|
string((String::from("and another")))
|
||||||
|
]
|
||||||
|
)
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
heap.truncate(0);
|
||||||
|
|
||||||
|
let mut functor_writer = Heap::functor_writer(functor);
|
||||||
|
functor_writer(&mut heap).unwrap();
|
||||||
|
|
||||||
|
assert_eq!(heap.cell_len(), 21);
|
||||||
|
|
||||||
|
assert_eq!(heap[0], atom_as_cell!(atom!("fourth"), 2));
|
||||||
|
assert_eq!(heap[1], pstr_loc_as_cell!(heap_index!(3)));
|
||||||
|
assert_eq!(heap[2], str_loc_as_cell!(6));
|
||||||
|
assert_eq!(
|
||||||
|
heap.slice_to_str(heap_index!(3), "a string".len()),
|
||||||
|
"a string"
|
||||||
|
);
|
||||||
|
assert_eq!(heap[5], empty_list_as_cell!());
|
||||||
|
assert_eq!(heap[6], atom_as_cell!(atom!("a"), 2));
|
||||||
|
assert_eq!(heap[7], str_loc_as_cell!(9));
|
||||||
|
assert_eq!(heap[8], pstr_loc_as_cell!(heap_index!(18))); // <-- wrong!
|
||||||
|
assert_eq!(heap[9], atom_as_cell!(atom!("fifth"), 3));
|
||||||
|
assert_eq!(heap[10], fixnum_as_cell!(Fixnum::build_with(5)));
|
||||||
|
assert_eq!(heap[11], pstr_loc_as_cell!(heap_index!(13)));
|
||||||
|
assert_eq!(heap[12], str_loc_as_cell!(16));
|
||||||
|
assert_eq!(
|
||||||
|
heap.slice_to_str(heap_index!(13), "another string".len()),
|
||||||
|
"another string"
|
||||||
|
);
|
||||||
|
assert_eq!(heap[15], empty_list_as_cell!());
|
||||||
|
assert_eq!(heap[16], atom_as_cell!(atom!("internal"), 1));
|
||||||
|
assert_eq!(heap[17], fixnum_as_cell!(Fixnum::build_with(0)));
|
||||||
|
assert_eq!(
|
||||||
|
heap.slice_to_str(heap_index!(18), "and another".len()),
|
||||||
|
"and another"
|
||||||
|
);
|
||||||
|
assert_eq!(heap[20], empty_list_as_cell!());
|
||||||
|
|
||||||
|
let constants = indexmap![
|
||||||
|
atom_as_cell!(atom!("a")) => IndexingCodePtr::External(2),
|
||||||
|
atom_as_cell!(atom!("d")) => IndexingCodePtr::External(7),
|
||||||
|
];
|
||||||
|
|
||||||
|
let functor = variadic_functor(
|
||||||
|
atom!("switch_on_constants"),
|
||||||
|
1,
|
||||||
|
constants
|
||||||
|
.iter()
|
||||||
|
.map(|(c, ptr)| functor!(atom!(":"), [cell((*c)), indexing_code_ptr((*ptr))])),
|
||||||
|
);
|
||||||
|
|
||||||
|
heap.truncate(0);
|
||||||
|
|
||||||
|
let mut functor_writer = Heap::functor_writer(functor);
|
||||||
|
functor_writer(&mut heap).unwrap();
|
||||||
|
|
||||||
|
assert_eq!(heap[0], atom_as_cell!(atom!("switch_on_constants"), 1));
|
||||||
|
assert_eq!(heap[1], list_loc_as_cell!(2));
|
||||||
|
assert_eq!(heap[2], str_loc_as_cell!(6));
|
||||||
|
assert_eq!(heap[3], list_loc_as_cell!(4));
|
||||||
|
assert_eq!(heap[4], str_loc_as_cell!(11));
|
||||||
|
assert_eq!(heap[5], empty_list_as_cell!());
|
||||||
|
assert_eq!(heap[6], atom_as_cell!(atom!(":"), 2));
|
||||||
|
assert_eq!(heap[7], atom_as_cell!(atom!("a")));
|
||||||
|
assert_eq!(heap[8], str_loc_as_cell!(9));
|
||||||
|
assert_eq!(heap[9], atom_as_cell!(atom!("external"), 1));
|
||||||
|
assert_eq!(heap[10], fixnum_as_cell!(Fixnum::build_with(2)));
|
||||||
|
assert_eq!(heap[11], atom_as_cell!(atom!(":"), 2));
|
||||||
|
assert_eq!(heap[12], atom_as_cell!(atom!("d")));
|
||||||
|
assert_eq!(heap[13], str_loc_as_cell!(14));
|
||||||
|
assert_eq!(heap[14], atom_as_cell!(atom!("external"), 1));
|
||||||
|
assert_eq!(heap[15], fixnum_as_cell!(Fixnum::build_with(7)));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn undefined_procedure_functor() {
|
||||||
|
// existence_error
|
||||||
|
let culprit = functor!(atom!("/"), [atom_as_cell((atom!("a"))), fixnum(1)]);
|
||||||
|
|
||||||
|
let stub = functor!(
|
||||||
|
atom!("existence_error"),
|
||||||
|
[
|
||||||
|
atom_as_cell((atom!("procedure"))),
|
||||||
|
functor((culprit.clone()))
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
println!("{stub:?}");
|
||||||
|
|
||||||
|
// now the error form
|
||||||
|
let lineless_error_form = functor!(atom!("error"), [functor(stub), functor(culprit)]);
|
||||||
|
|
||||||
|
println!("{lineless_error_form:?}");
|
||||||
|
|
||||||
|
let mut heap = Heap::new();
|
||||||
|
let mut functor_writer = Heap::functor_writer(lineless_error_form);
|
||||||
|
|
||||||
|
functor_writer(&mut heap).unwrap();
|
||||||
|
|
||||||
|
assert_eq!(heap[0], atom_as_cell!(atom!("error"), 2));
|
||||||
|
assert_eq!(heap[1], str_loc_as_cell!(3));
|
||||||
|
assert_eq!(heap[2], str_loc_as_cell!(9));
|
||||||
|
assert_eq!(heap[3], atom_as_cell!(atom!("existence_error"), 2));
|
||||||
|
assert_eq!(heap[4], atom_as_cell!(atom!("procedure")));
|
||||||
|
assert_eq!(heap[5], str_loc_as_cell!(6)); // is str_loc_as_cell!(3)
|
||||||
|
assert_eq!(heap[6], atom_as_cell!(atom!("/"), 2));
|
||||||
|
assert_eq!(heap[7], atom_as_cell!(atom!("a")));
|
||||||
|
assert_eq!(heap[8], fixnum_as_cell!(Fixnum::build_with(1)));
|
||||||
|
assert_eq!(heap[9], atom_as_cell!(atom!("/"), 2));
|
||||||
|
assert_eq!(heap[10], atom_as_cell!(atom!("a")));
|
||||||
|
assert_eq!(heap[11], fixnum_as_cell!(Fixnum::build_with(1)));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn argless_functor() {
|
||||||
|
let name = functor!(atom!("[]"));
|
||||||
|
|
||||||
|
assert_eq!(name.len(), 1);
|
||||||
|
|
||||||
|
let mut heap = Heap::new();
|
||||||
|
let mut functor_writer = Heap::functor_writer(name);
|
||||||
|
let loc = functor_writer(&mut heap).unwrap();
|
||||||
|
|
||||||
|
assert_eq!(loc, heap_loc_as_cell!(0));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn predefined_subfunctors() {
|
||||||
|
let stub = functor!(atom!("sub"), [atom_as_cell((atom!("[]")))]);
|
||||||
|
let name = functor!(atom!("super"), [functor(stub)]);
|
||||||
|
|
||||||
|
let mut heap = Heap::new();
|
||||||
|
let mut functor_writer = Heap::functor_writer(name);
|
||||||
|
|
||||||
|
functor_writer(&mut heap).unwrap();
|
||||||
|
|
||||||
|
assert_eq!(heap.cell_len(), 4);
|
||||||
|
|
||||||
|
assert_eq!(heap[0], atom_as_cell!(atom!("super"), 1));
|
||||||
|
assert_eq!(heap[1], str_loc_as_cell!(2));
|
||||||
|
assert_eq!(heap[2], atom_as_cell!(atom!("sub"), 1));
|
||||||
|
assert_eq!(heap[3], empty_list_as_cell!());
|
||||||
|
}
|
||||||
|
}
|
||||||
3457
src/heap_iter.rs
Normal file
3457
src/heap_iter.rs
Normal file
File diff suppressed because it is too large
Load Diff
2232
src/heap_print.rs
Normal file
2232
src/heap_print.rs
Normal file
File diff suppressed because it is too large
Load Diff
25
src/http.rs
Normal file
25
src/http.rs
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
use bytes::{Bytes, buf::Reader};
|
||||||
|
use std::sync::{Arc, Condvar, Mutex};
|
||||||
|
use tokio::sync::Notify;
|
||||||
|
|
||||||
|
use warp::http;
|
||||||
|
|
||||||
|
pub struct HttpListener {
|
||||||
|
pub incoming: std::sync::mpsc::Receiver<HttpRequest>,
|
||||||
|
pub warp_shutdown: Arc<Notify>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct HttpRequest {
|
||||||
|
pub request_data: HttpRequestData,
|
||||||
|
pub response: HttpResponse,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub type HttpResponse = Arc<(Mutex<bool>, Mutex<Option<warp::reply::Response>>, Condvar)>;
|
||||||
|
|
||||||
|
pub struct HttpRequestData {
|
||||||
|
pub method: http::Method,
|
||||||
|
pub headers: http::HeaderMap,
|
||||||
|
pub path: String,
|
||||||
|
pub query: String,
|
||||||
|
pub body: Reader<Bytes>,
|
||||||
|
}
|
||||||
1529
src/indexing.rs
Normal file
1529
src/indexing.rs
Normal file
File diff suppressed because it is too large
Load Diff
1386
src/instructions.rs
Normal file
1386
src/instructions.rs
Normal file
File diff suppressed because it is too large
Load Diff
469
src/iterators.rs
Normal file
469
src/iterators.rs
Normal file
@@ -0,0 +1,469 @@
|
|||||||
|
use crate::atom_table::*;
|
||||||
|
use crate::forms::*;
|
||||||
|
use crate::instructions::*;
|
||||||
|
use crate::parser::ast::*;
|
||||||
|
|
||||||
|
use std::cell::Cell;
|
||||||
|
use std::collections::VecDeque;
|
||||||
|
use std::iter::*;
|
||||||
|
use std::rc::Rc;
|
||||||
|
use std::sync::Arc;
|
||||||
|
use std::vec::Vec;
|
||||||
|
|
||||||
|
#[allow(clippy::borrowed_box)]
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub(crate) enum TermRef<'a> {
|
||||||
|
AnonVar(Level),
|
||||||
|
Cons(Level, &'a Cell<RegType>, &'a Term, &'a Term),
|
||||||
|
Literal(Level, &'a Cell<RegType>, &'a Literal),
|
||||||
|
Clause(Level, &'a Cell<RegType>, Atom, &'a Vec<Term>),
|
||||||
|
PartialString(Level, &'a Cell<RegType>, Rc<String>, &'a Box<Term>),
|
||||||
|
CompleteString(Level, &'a Cell<RegType>, Rc<String>),
|
||||||
|
Var(Level, &'a Cell<VarReg>, VarPtr),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::borrowed_box)]
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub(crate) enum TermIterState<'a> {
|
||||||
|
AnonVar(Level),
|
||||||
|
Clause(Level, usize, &'a Cell<RegType>, Atom, &'a Vec<Term>),
|
||||||
|
Literal(Level, &'a Cell<RegType>, &'a Literal),
|
||||||
|
InitialCons(Level, &'a Cell<RegType>, &'a Term, &'a Term),
|
||||||
|
FinalCons(Level, &'a Cell<RegType>, &'a Term, &'a Term),
|
||||||
|
InitialPartialString(Level, &'a Cell<RegType>, Rc<String>, &'a Box<Term>),
|
||||||
|
FinalPartialString(Level, &'a Cell<RegType>, Rc<String>, &'a Box<Term>),
|
||||||
|
CompleteString(Level, &'a Cell<RegType>, Rc<String>),
|
||||||
|
Var(Level, &'a Cell<VarReg>, VarPtr),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> TermIterState<'a> {
|
||||||
|
pub(crate) fn subterm_to_state(lvl: Level, term: &'a Term) -> TermIterState<'a> {
|
||||||
|
match term {
|
||||||
|
Term::AnonVar => TermIterState::AnonVar(lvl),
|
||||||
|
Term::Clause(cell, name, subterms) => {
|
||||||
|
TermIterState::Clause(lvl, 0, cell, *name, subterms)
|
||||||
|
}
|
||||||
|
Term::Cons(cell, head, tail) => {
|
||||||
|
TermIterState::InitialCons(lvl, cell, head.as_ref(), tail.as_ref())
|
||||||
|
}
|
||||||
|
Term::Literal(cell, constant) => TermIterState::Literal(lvl, cell, constant),
|
||||||
|
Term::PartialString(cell, string_buf, tail) => {
|
||||||
|
TermIterState::InitialPartialString(lvl, cell, string_buf.clone(), tail)
|
||||||
|
}
|
||||||
|
Term::CompleteString(cell, string) => {
|
||||||
|
TermIterState::CompleteString(lvl, cell, string.clone())
|
||||||
|
}
|
||||||
|
Term::Var(cell, var_ptr) => TermIterState::Var(lvl, cell, var_ptr.clone()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub(crate) struct QueryIterator<'a> {
|
||||||
|
state_stack: Vec<TermIterState<'a>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> QueryIterator<'a> {
|
||||||
|
fn push_subterm(&mut self, lvl: Level, term: &'a Term) {
|
||||||
|
self.state_stack
|
||||||
|
.push(TermIterState::subterm_to_state(lvl, term));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
fn from_rule_head_clause(terms: &'a Vec<Term>) -> Self {
|
||||||
|
let state_stack = terms
|
||||||
|
.iter()
|
||||||
|
.rev()
|
||||||
|
.map(|bt| TermIterState::subterm_to_state(Level::Shallow, bt))
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
QueryIterator { state_stack }
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
fn from_term(term: &'a Term) -> Self {
|
||||||
|
let state = match term {
|
||||||
|
Term::AnonVar
|
||||||
|
| Term::Cons(..)
|
||||||
|
| Term::Literal(..)
|
||||||
|
| Term::PartialString(..)
|
||||||
|
| Term::CompleteString(..) => {
|
||||||
|
return QueryIterator {
|
||||||
|
state_stack: vec![],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
Term::Clause(r, name, terms) => TermIterState::Clause(Level::Root, 0, r, *name, terms),
|
||||||
|
Term::Var(cell, var_ptr) => TermIterState::Var(Level::Root, cell, var_ptr.clone()),
|
||||||
|
};
|
||||||
|
|
||||||
|
QueryIterator {
|
||||||
|
state_stack: vec![state],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn extend_state(&mut self, lvl: Level, term: &'a QueryTerm) {
|
||||||
|
match term {
|
||||||
|
QueryTerm::Clause(cell, ClauseType::CallN(_), terms, _) => {
|
||||||
|
self.state_stack
|
||||||
|
.push(TermIterState::Clause(lvl, 1, cell, atom!("$call"), terms));
|
||||||
|
}
|
||||||
|
QueryTerm::Clause(cell, ct, terms, _) => {
|
||||||
|
self.state_stack
|
||||||
|
.push(TermIterState::Clause(lvl, 0, cell, ct.name(), terms));
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new(term: &'a QueryTerm) -> Self {
|
||||||
|
let mut iter = QueryIterator {
|
||||||
|
state_stack: vec![],
|
||||||
|
};
|
||||||
|
iter.extend_state(Level::Root, term);
|
||||||
|
iter
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Iterator for QueryIterator<'a> {
|
||||||
|
type Item = TermRef<'a>;
|
||||||
|
|
||||||
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
|
while let Some(iter_state) = self.state_stack.pop() {
|
||||||
|
match iter_state {
|
||||||
|
TermIterState::AnonVar(lvl) => {
|
||||||
|
return Some(TermRef::AnonVar(lvl));
|
||||||
|
}
|
||||||
|
TermIterState::Clause(lvl, child_num, cell, name, child_terms) => {
|
||||||
|
if child_num == child_terms.len() {
|
||||||
|
match name {
|
||||||
|
atom!("$call") if lvl == Level::Root => {
|
||||||
|
self.push_subterm(Level::Shallow, &child_terms[0]);
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
return match lvl {
|
||||||
|
Level::Root => None,
|
||||||
|
lvl => Some(TermRef::Clause(lvl, cell, name, child_terms)),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
self.state_stack.push(TermIterState::Clause(
|
||||||
|
lvl,
|
||||||
|
child_num + 1,
|
||||||
|
cell,
|
||||||
|
name,
|
||||||
|
child_terms,
|
||||||
|
));
|
||||||
|
|
||||||
|
self.push_subterm(lvl.child_level(), &child_terms[child_num]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
TermIterState::InitialCons(lvl, cell, head, tail) => {
|
||||||
|
self.state_stack
|
||||||
|
.push(TermIterState::FinalCons(lvl, cell, head, tail));
|
||||||
|
|
||||||
|
self.push_subterm(lvl.child_level(), tail);
|
||||||
|
self.push_subterm(lvl.child_level(), head);
|
||||||
|
}
|
||||||
|
TermIterState::InitialPartialString(lvl, cell, string, tail) => {
|
||||||
|
self.state_stack
|
||||||
|
.push(TermIterState::FinalPartialString(lvl, cell, string, tail));
|
||||||
|
self.push_subterm(lvl.child_level(), tail);
|
||||||
|
}
|
||||||
|
TermIterState::FinalPartialString(lvl, cell, string, tail) => {
|
||||||
|
return Some(TermRef::PartialString(lvl, cell, string, tail));
|
||||||
|
}
|
||||||
|
TermIterState::CompleteString(lvl, cell, string) => {
|
||||||
|
return Some(TermRef::CompleteString(lvl, cell, string));
|
||||||
|
}
|
||||||
|
TermIterState::FinalCons(lvl, cell, head, tail) => {
|
||||||
|
return Some(TermRef::Cons(lvl, cell, head, tail));
|
||||||
|
}
|
||||||
|
TermIterState::Literal(lvl, cell, constant) => {
|
||||||
|
return Some(TermRef::Literal(lvl, cell, constant));
|
||||||
|
}
|
||||||
|
TermIterState::Var(lvl, cell, var_ptr) => {
|
||||||
|
return Some(TermRef::Var(lvl, cell, var_ptr));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub(crate) struct FactIterator<'a> {
|
||||||
|
state_queue: VecDeque<TermIterState<'a>>,
|
||||||
|
iterable_root: RootIterationPolicy,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> FactIterator<'a> {
|
||||||
|
fn push_subterm(&mut self, lvl: Level, term: &'a Term) {
|
||||||
|
self.state_queue
|
||||||
|
.push_back(TermIterState::subterm_to_state(lvl, term));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn from_rule_head_clause(terms: &'a [Term]) -> Self {
|
||||||
|
let state_queue = terms
|
||||||
|
.iter()
|
||||||
|
.map(|bt| TermIterState::subterm_to_state(Level::Shallow, bt))
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
FactIterator {
|
||||||
|
state_queue,
|
||||||
|
iterable_root: RootIterationPolicy::NotIterated,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn new(term: &'a Term, iterable_root: RootIterationPolicy) -> Self {
|
||||||
|
let states = match term {
|
||||||
|
Term::AnonVar => {
|
||||||
|
vec![TermIterState::AnonVar(Level::Root)]
|
||||||
|
}
|
||||||
|
Term::Clause(cell, name, terms) => {
|
||||||
|
vec![TermIterState::Clause(Level::Root, 0, cell, *name, terms)]
|
||||||
|
}
|
||||||
|
Term::Cons(cell, head, tail) => vec![TermIterState::InitialCons(
|
||||||
|
Level::Root,
|
||||||
|
cell,
|
||||||
|
head.as_ref(),
|
||||||
|
tail.as_ref(),
|
||||||
|
)],
|
||||||
|
Term::PartialString(cell, string, tail) => {
|
||||||
|
vec![TermIterState::InitialPartialString(
|
||||||
|
Level::Root,
|
||||||
|
cell,
|
||||||
|
string.clone(),
|
||||||
|
tail,
|
||||||
|
)]
|
||||||
|
}
|
||||||
|
Term::CompleteString(cell, string) => {
|
||||||
|
vec![TermIterState::CompleteString(
|
||||||
|
Level::Root,
|
||||||
|
cell,
|
||||||
|
string.clone(),
|
||||||
|
)]
|
||||||
|
}
|
||||||
|
Term::Literal(cell, constant) => {
|
||||||
|
vec![TermIterState::Literal(Level::Root, cell, constant)]
|
||||||
|
}
|
||||||
|
Term::Var(cell, var_ptr) => {
|
||||||
|
vec![TermIterState::Var(Level::Root, cell, var_ptr.clone())]
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
FactIterator {
|
||||||
|
state_queue: VecDeque::from(states),
|
||||||
|
iterable_root,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Iterator for FactIterator<'a> {
|
||||||
|
type Item = TermRef<'a>;
|
||||||
|
|
||||||
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
|
while let Some(state) = self.state_queue.pop_front() {
|
||||||
|
match state {
|
||||||
|
TermIterState::AnonVar(lvl) => {
|
||||||
|
return Some(TermRef::AnonVar(lvl));
|
||||||
|
}
|
||||||
|
TermIterState::Clause(lvl, _, cell, name, child_terms) => {
|
||||||
|
for child_term in child_terms {
|
||||||
|
self.push_subterm(lvl.child_level(), child_term);
|
||||||
|
}
|
||||||
|
|
||||||
|
match lvl {
|
||||||
|
Level::Root if !self.iterable_root.iterable() => continue,
|
||||||
|
_ => return Some(TermRef::Clause(lvl, cell, name, child_terms)),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
TermIterState::InitialCons(lvl, cell, head, tail) => {
|
||||||
|
self.push_subterm(Level::Deep, head);
|
||||||
|
self.push_subterm(Level::Deep, tail);
|
||||||
|
|
||||||
|
return Some(TermRef::Cons(lvl, cell, head, tail));
|
||||||
|
}
|
||||||
|
TermIterState::InitialPartialString(lvl, cell, string_buf, tail) => {
|
||||||
|
self.push_subterm(Level::Deep, tail);
|
||||||
|
return Some(TermRef::PartialString(lvl, cell, string_buf, tail));
|
||||||
|
}
|
||||||
|
TermIterState::CompleteString(lvl, cell, atom) => {
|
||||||
|
return Some(TermRef::CompleteString(lvl, cell, atom));
|
||||||
|
}
|
||||||
|
TermIterState::Literal(lvl, cell, constant) => {
|
||||||
|
return Some(TermRef::Literal(lvl, cell, constant));
|
||||||
|
}
|
||||||
|
TermIterState::Var(lvl, cell, var_ptr) => {
|
||||||
|
return Some(TermRef::Var(lvl, cell, var_ptr));
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn post_order_iter(term: &Term) -> QueryIterator<'_> {
|
||||||
|
QueryIterator::from_term(term)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn breadth_first_iter(
|
||||||
|
term: &Term,
|
||||||
|
iterable_root: RootIterationPolicy,
|
||||||
|
) -> FactIterator<'_> {
|
||||||
|
FactIterator::new(term, iterable_root)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Copy, Clone)]
|
||||||
|
enum ClauseIteratorState<'a> {
|
||||||
|
RemainingChunks(&'a VecDeque<ChunkedTerms>, usize),
|
||||||
|
RemainingBranches(
|
||||||
|
&'a Vec<Arc<BranchNumber>>,
|
||||||
|
&'a Vec<VecDeque<ChunkedTerms>>,
|
||||||
|
usize,
|
||||||
|
),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub(crate) enum ClauseItem<'a> {
|
||||||
|
FirstBranch {
|
||||||
|
branch_num: &'a Arc<BranchNumber>,
|
||||||
|
num_branches: usize,
|
||||||
|
},
|
||||||
|
NextBranch {
|
||||||
|
branch_num: &'a Arc<BranchNumber>,
|
||||||
|
},
|
||||||
|
BranchEnd {
|
||||||
|
depth: usize,
|
||||||
|
},
|
||||||
|
Chunk {
|
||||||
|
terms: &'a VecDeque<QueryTerm>,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub(crate) struct ClauseIterator<'a> {
|
||||||
|
state_stack: Vec<ClauseIteratorState<'a>>,
|
||||||
|
remaining_chunks_on_stack: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn state_from_chunked_terms(chunk_vec: &VecDeque<ChunkedTerms>) -> ClauseIteratorState<'_> {
|
||||||
|
if chunk_vec.len() == 1 {
|
||||||
|
if let Some(ChunkedTerms::Branch { branch_nums, arms }) = chunk_vec.front() {
|
||||||
|
return ClauseIteratorState::RemainingBranches(branch_nums, arms, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ClauseIteratorState::RemainingChunks(chunk_vec, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> ClauseIterator<'a> {
|
||||||
|
pub fn new(clauses: &'a ChunkedTermVec) -> Self {
|
||||||
|
match state_from_chunked_terms(&clauses.chunk_vec) {
|
||||||
|
state @ ClauseIteratorState::RemainingBranches(..) => Self {
|
||||||
|
state_stack: vec![state],
|
||||||
|
remaining_chunks_on_stack: 0,
|
||||||
|
},
|
||||||
|
state @ ClauseIteratorState::RemainingChunks(..) => Self {
|
||||||
|
state_stack: vec![state],
|
||||||
|
remaining_chunks_on_stack: 1,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn in_tail_position(&self) -> bool {
|
||||||
|
self.remaining_chunks_on_stack == 0
|
||||||
|
}
|
||||||
|
|
||||||
|
fn branch_end_depth(&mut self) -> usize {
|
||||||
|
let mut depth = 1;
|
||||||
|
|
||||||
|
while let Some(state) = self.state_stack.pop() {
|
||||||
|
match state {
|
||||||
|
ClauseIteratorState::RemainingBranches(_branch_nums, terms, focus)
|
||||||
|
if terms.len() == focus =>
|
||||||
|
{
|
||||||
|
depth += 1;
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
self.state_stack.push(state);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
depth
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Iterator for ClauseIterator<'a> {
|
||||||
|
type Item = ClauseItem<'a>;
|
||||||
|
|
||||||
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
|
while let Some(state) = self.state_stack.pop() {
|
||||||
|
match state {
|
||||||
|
ClauseIteratorState::RemainingChunks(chunks, focus) if focus < chunks.len() => {
|
||||||
|
if focus + 1 < chunks.len() {
|
||||||
|
self.state_stack
|
||||||
|
.push(ClauseIteratorState::RemainingChunks(chunks, focus + 1));
|
||||||
|
} else {
|
||||||
|
self.remaining_chunks_on_stack -= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
match &chunks[focus] {
|
||||||
|
ChunkedTerms::Branch { branch_nums, arms } => {
|
||||||
|
self.state_stack
|
||||||
|
.push(ClauseIteratorState::RemainingBranches(branch_nums, arms, 0));
|
||||||
|
}
|
||||||
|
ChunkedTerms::Chunk { terms } => {
|
||||||
|
return Some(ClauseItem::Chunk { terms });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ClauseIteratorState::RemainingChunks(chunks, focus) => {
|
||||||
|
debug_assert_eq!(chunks.len(), focus);
|
||||||
|
}
|
||||||
|
ClauseIteratorState::RemainingBranches(branch_nums, branches, focus)
|
||||||
|
if focus < branches.len() =>
|
||||||
|
{
|
||||||
|
self.state_stack
|
||||||
|
.push(ClauseIteratorState::RemainingBranches(
|
||||||
|
branch_nums,
|
||||||
|
branches,
|
||||||
|
focus + 1,
|
||||||
|
));
|
||||||
|
let state = state_from_chunked_terms(&branches[focus]);
|
||||||
|
|
||||||
|
if let ClauseIteratorState::RemainingChunks(..) = &state {
|
||||||
|
self.remaining_chunks_on_stack += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.state_stack.push(state);
|
||||||
|
|
||||||
|
return if focus == 0 {
|
||||||
|
Some(ClauseItem::FirstBranch {
|
||||||
|
branch_num: &branch_nums[0],
|
||||||
|
num_branches: branches.len(),
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
Some(ClauseItem::NextBranch {
|
||||||
|
branch_num: &branch_nums[focus],
|
||||||
|
})
|
||||||
|
};
|
||||||
|
}
|
||||||
|
ClauseIteratorState::RemainingBranches(_branch_nums, branches, focus) => {
|
||||||
|
debug_assert_eq!(branches.len(), focus);
|
||||||
|
return Some(ClauseItem::BranchEnd {
|
||||||
|
depth: self.branch_end_depth(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,51 +0,0 @@
|
|||||||
use std::cell::{Cell};
|
|
||||||
use std::vec::{Vec};
|
|
||||||
|
|
||||||
pub type Var = String;
|
|
||||||
|
|
||||||
pub type Atom = String;
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub enum TopLevel {
|
|
||||||
Fact(Term),
|
|
||||||
Query(Term)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub enum Term {
|
|
||||||
Atom(Cell<usize>, Atom),
|
|
||||||
Clause(Cell<usize>, Atom, Vec<Box<Term>>),
|
|
||||||
Var(Cell<usize>, Var)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub enum FactInstruction {
|
|
||||||
GetStructure(Atom, usize, usize),
|
|
||||||
UnifyVariable(usize),
|
|
||||||
UnifyValue(usize)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub enum QueryInstruction {
|
|
||||||
PutStructure(Atom, usize, usize),
|
|
||||||
SetVariable(usize),
|
|
||||||
SetValue(usize),
|
|
||||||
}
|
|
||||||
|
|
||||||
pub type CompiledFact = Vec<FactInstruction>;
|
|
||||||
|
|
||||||
pub type CompiledQuery = Vec<QueryInstruction>;
|
|
||||||
|
|
||||||
#[derive(Clone, Copy, PartialEq)]
|
|
||||||
pub enum Addr {
|
|
||||||
HeapCell(usize),
|
|
||||||
RegNum(usize)
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Term {
|
|
||||||
pub fn set_cell(&self, cell_num: usize) {
|
|
||||||
match self {
|
|
||||||
&Term::Atom(ref cell, _) => cell.set(cell_num),
|
|
||||||
&Term::Clause(ref cell, _, _) => cell.set(cell_num),
|
|
||||||
&Term::Var(ref cell, _) => cell.set(cell_num)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,126 +0,0 @@
|
|||||||
use l0::ast::{Atom, Term, FactInstruction, QueryInstruction, Var};
|
|
||||||
use l0::iterators::{BreadthFirstIterator, PostOrderIterator};
|
|
||||||
|
|
||||||
use std::collections::{HashSet};
|
|
||||||
use std::fmt;
|
|
||||||
use std::vec::{Vec};
|
|
||||||
|
|
||||||
impl fmt::Display for QueryInstruction {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
match self {
|
|
||||||
&QueryInstruction::PutStructure(ref a, ref s, ref r) =>
|
|
||||||
write!(f, "put_structure {}/{}, X{}", a, s, r),
|
|
||||||
&QueryInstruction::SetVariable(ref r) =>
|
|
||||||
write!(f, "set_variable X{}", r),
|
|
||||||
&QueryInstruction::SetValue(ref r) =>
|
|
||||||
write!(f, "set_value X{}", r),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Display for FactInstruction {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
match self {
|
|
||||||
&FactInstruction::GetStructure(ref a, ref s, ref r) =>
|
|
||||||
write!(f, "get_structure {}/{}, X{}", a, s, r),
|
|
||||||
&FactInstruction::UnifyVariable(ref r) =>
|
|
||||||
write!(f, "unify_variable X{}", r),
|
|
||||||
&FactInstruction::UnifyValue(ref r) =>
|
|
||||||
write!(f, "unify_value X{}", r)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait CompilationTarget<'a> {
|
|
||||||
type Iterator : Iterator<Item=&'a Term>;
|
|
||||||
|
|
||||||
fn iter(term: &'a Term) -> Self::Iterator;
|
|
||||||
|
|
||||||
fn to_structure(name: Atom, arity: usize, cell_num: usize) -> Self;
|
|
||||||
fn to_value(cell_num: usize) -> Self;
|
|
||||||
fn to_variable(cell_num: usize) -> Self;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> CompilationTarget<'a> for FactInstruction {
|
|
||||||
type Iterator = BreadthFirstIterator<'a>;
|
|
||||||
|
|
||||||
fn iter(term: &'a Term) -> Self::Iterator {
|
|
||||||
term.breadth_first_iter()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn to_structure(name: Atom, arity: usize, cell_num: usize) -> Self {
|
|
||||||
FactInstruction::GetStructure(name, arity, cell_num)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn to_value(cell_num: usize) -> Self {
|
|
||||||
FactInstruction::UnifyValue(cell_num)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn to_variable(cell_num: usize) -> Self {
|
|
||||||
FactInstruction::UnifyVariable(cell_num)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> CompilationTarget<'a> for QueryInstruction {
|
|
||||||
type Iterator = PostOrderIterator<'a>;
|
|
||||||
|
|
||||||
fn iter(term: &'a Term) -> Self::Iterator {
|
|
||||||
term.post_order_iter()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn to_structure(name: Atom, arity: usize, cell_num: usize) -> Self {
|
|
||||||
QueryInstruction::PutStructure(name, arity, cell_num)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn to_value(cell_num: usize) -> Self {
|
|
||||||
QueryInstruction::SetValue(cell_num)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn to_variable(cell_num: usize) -> Self {
|
|
||||||
QueryInstruction::SetVariable(cell_num)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn subterm_to_instr<'a, Target>(subterm: &'a Term,
|
|
||||||
bindings: &mut HashSet<&'a Var>)
|
|
||||||
-> Target
|
|
||||||
where Target: CompilationTarget<'a>
|
|
||||||
{
|
|
||||||
match subterm {
|
|
||||||
&Term::Atom(ref cell_num, _) =>
|
|
||||||
Target::to_value(cell_num.get()),
|
|
||||||
&Term::Var(ref cell_num, ref atom) if bindings.contains(atom) =>
|
|
||||||
Target::to_value(cell_num.get()),
|
|
||||||
&Term::Var(ref cell_num, ref atom) => {
|
|
||||||
bindings.insert(atom);
|
|
||||||
Target::to_variable(cell_num.get())
|
|
||||||
},
|
|
||||||
&Term::Clause(ref cell_num, _, _) =>
|
|
||||||
Target::to_value(cell_num.get())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn compile_target<'a, Target>(term: &'a Term) -> Vec<Target>
|
|
||||||
where Target: CompilationTarget<'a>
|
|
||||||
{
|
|
||||||
let mut iter = Target::iter(term);
|
|
||||||
let mut target = Vec::<Target>::new();
|
|
||||||
let mut bindings = HashSet::new();
|
|
||||||
|
|
||||||
while let Some(term) = iter.next() {
|
|
||||||
match term {
|
|
||||||
&Term::Atom(ref cell_num, ref atom) =>
|
|
||||||
target.push(Target::to_structure(atom.clone(), 0, cell_num.get())),
|
|
||||||
&Term::Clause(ref cell_num, ref atom, ref terms) => {
|
|
||||||
target.push(Target::to_structure(atom.clone(), 0, cell_num.get()));
|
|
||||||
|
|
||||||
for subterm in terms {
|
|
||||||
target.push(subterm_to_instr(subterm.as_ref(), &mut bindings));
|
|
||||||
}
|
|
||||||
},
|
|
||||||
_ => {},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
target
|
|
||||||
}
|
|
||||||
@@ -1,98 +0,0 @@
|
|||||||
use l0::ast::{Term};
|
|
||||||
|
|
||||||
use std::collections::{VecDeque};
|
|
||||||
use std::vec::{Vec};
|
|
||||||
|
|
||||||
enum DepthFirstIteratorState<'a> {
|
|
||||||
// child no., the containing clause, its vector.
|
|
||||||
Clause(usize, &'a Term, &'a Vec<Box<Term>>),
|
|
||||||
NonClause(&'a Term)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct PostOrderIterator<'a> {
|
|
||||||
state_stack: Vec<DepthFirstIteratorState<'a>>
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> PostOrderIterator<'a> {
|
|
||||||
fn push_clause(&mut self,
|
|
||||||
child_num: usize,
|
|
||||||
term: &'a Term,
|
|
||||||
child_terms: &'a Vec<Box<Term>>)
|
|
||||||
{
|
|
||||||
self.state_stack.push(DepthFirstIteratorState::Clause(child_num,
|
|
||||||
term,
|
|
||||||
child_terms));
|
|
||||||
}
|
|
||||||
|
|
||||||
fn render_new_state(term: &'a Term) -> DepthFirstIteratorState<'a> {
|
|
||||||
match term {
|
|
||||||
&Term::Clause(_, _, ref child_terms) =>
|
|
||||||
DepthFirstIteratorState::Clause(0, term, child_terms),
|
|
||||||
_ => DepthFirstIteratorState::NonClause(term)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn push_term(&mut self, term: &'a Term) {
|
|
||||||
self.state_stack.push(Self::render_new_state(term));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Iterator for PostOrderIterator<'a> {
|
|
||||||
type Item = &'a Term;
|
|
||||||
|
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
|
||||||
while let Some(iter_state) = self.state_stack.pop() {
|
|
||||||
match iter_state {
|
|
||||||
DepthFirstIteratorState::Clause(child_num, term, child_terms) => {
|
|
||||||
if child_num == child_terms.len() {
|
|
||||||
return Some(term);
|
|
||||||
} else {
|
|
||||||
self.push_clause(child_num + 1, term, child_terms);
|
|
||||||
self.push_term(child_terms[child_num].as_ref());
|
|
||||||
}
|
|
||||||
},
|
|
||||||
DepthFirstIteratorState::NonClause(term) => return Some(term),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct BreadthFirstIterator<'a> {
|
|
||||||
state_queue : VecDeque<&'a Term>
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Iterator for BreadthFirstIterator<'a> {
|
|
||||||
type Item = &'a Term;
|
|
||||||
|
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
|
||||||
if let Some(term) = self.state_queue.pop_front() {
|
|
||||||
if let &Term::Clause(_, _, ref child_terms) = term {
|
|
||||||
for term in child_terms {
|
|
||||||
self.state_queue.push_back(term);
|
|
||||||
}
|
|
||||||
|
|
||||||
return Some(term);
|
|
||||||
}
|
|
||||||
|
|
||||||
return Some(term);
|
|
||||||
}
|
|
||||||
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Term {
|
|
||||||
pub fn post_order_iter(&'a self) -> PostOrderIterator<'a> {
|
|
||||||
let initial_state = PostOrderIterator::render_new_state(self);
|
|
||||||
PostOrderIterator { state_stack: vec![initial_state] }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn breadth_first_iter(&'a self) -> BreadthFirstIterator<'a> {
|
|
||||||
let mut queue = VecDeque::new();
|
|
||||||
queue.push_back(self);
|
|
||||||
|
|
||||||
BreadthFirstIterator { state_queue: queue }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
use std::cell::{Cell};
|
|
||||||
use l0::ast::{Atom, Term, TopLevel, Var};
|
|
||||||
|
|
||||||
grammar;
|
|
||||||
|
|
||||||
pub TopLevel: TopLevel = {
|
|
||||||
"?-" <t:Term> "." => TopLevel::Query(t),
|
|
||||||
<t:Term> "." => TopLevel::Fact(t),
|
|
||||||
};
|
|
||||||
|
|
||||||
Atom : Atom = {
|
|
||||||
r"[a-z][a-z0-9_]*" => <>.trim().to_string(),
|
|
||||||
};
|
|
||||||
|
|
||||||
Var : Var = {
|
|
||||||
r"[A-Z][a-z0-9_]*" => <>.trim().to_string(),
|
|
||||||
};
|
|
||||||
|
|
||||||
BoxedTerm : Box<Term> = {
|
|
||||||
<t:Term> => Box::new(t),
|
|
||||||
};
|
|
||||||
|
|
||||||
Term : Term = {
|
|
||||||
<a:Atom> "(" <ts: (<BoxedTerm> ",")*> <t:BoxedTerm> ")" => {
|
|
||||||
let mut ts = ts;
|
|
||||||
ts.push(t);
|
|
||||||
Term::Clause(Cell::new(0), a, ts)
|
|
||||||
},
|
|
||||||
<Atom> => Term::Atom(Cell::new(0), <>),
|
|
||||||
<Var> => Term::Var(Cell::new(0), <>),
|
|
||||||
};
|
|
||||||
1595
src/l0/l0_parser.rs
1595
src/l0/l0_parser.rs
File diff suppressed because it is too large
Load Diff
@@ -1,238 +0,0 @@
|
|||||||
use l0::ast::{Addr, Atom, CompiledFact, FactInstruction, QueryInstruction};
|
|
||||||
|
|
||||||
use std::vec::{Vec};
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
enum HeapCell {
|
|
||||||
NamedStr(usize, Atom),
|
|
||||||
Ref(usize),
|
|
||||||
Str(usize),
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
|
||||||
enum MachineMode {
|
|
||||||
Read,
|
|
||||||
Write
|
|
||||||
}
|
|
||||||
|
|
||||||
type Heap = Vec<HeapCell>;
|
|
||||||
|
|
||||||
type Registers = Vec<HeapCell>;
|
|
||||||
|
|
||||||
pub struct Machine {
|
|
||||||
h : usize,
|
|
||||||
s : usize,
|
|
||||||
pub fail : bool,
|
|
||||||
heap : Heap,
|
|
||||||
mode : MachineMode,
|
|
||||||
pub program : Option<CompiledFact>,
|
|
||||||
registers : Registers
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Machine {
|
|
||||||
pub fn new() -> Machine {
|
|
||||||
Machine { h : 0,
|
|
||||||
s : 0,
|
|
||||||
fail : false,
|
|
||||||
heap : Vec::with_capacity(256),
|
|
||||||
mode : MachineMode::Write,
|
|
||||||
program : None,
|
|
||||||
registers : vec![HeapCell::Ref(0); 33] }
|
|
||||||
}
|
|
||||||
|
|
||||||
fn lookup(&self, a: Addr) -> &HeapCell {
|
|
||||||
match a {
|
|
||||||
Addr::HeapCell(hc) => &self.heap[hc],
|
|
||||||
Addr::RegNum(reg) => &self.registers[reg]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn deref(&self, a: Addr) -> Addr {
|
|
||||||
let mut a = a;
|
|
||||||
|
|
||||||
loop {
|
|
||||||
if let &HeapCell::Ref(value) = self.lookup(a) {
|
|
||||||
if let Addr::HeapCell(av) = a {
|
|
||||||
if value != av {
|
|
||||||
a = Addr::HeapCell(value);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return a;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
fn is_unbound(hc: &HeapCell, index: usize) -> bool {
|
|
||||||
match hc {
|
|
||||||
&HeapCell::Ref(r) => r == index,
|
|
||||||
_ => false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//TODO: try to compress this function. currently it is dog shit.
|
|
||||||
fn bind(&mut self, a: Addr, val: usize) {
|
|
||||||
let mut a = a;
|
|
||||||
|
|
||||||
loop {
|
|
||||||
match a {
|
|
||||||
Addr::RegNum(reg) => {
|
|
||||||
if let HeapCell::Ref(hc) = self.registers[reg] {
|
|
||||||
a = Addr::HeapCell(hc);
|
|
||||||
} else if Machine::is_unbound(&self.heap[val], val) {
|
|
||||||
self.heap[val] = self.registers[reg].clone();
|
|
||||||
break;
|
|
||||||
} else {
|
|
||||||
self.fail = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
Addr::HeapCell(hc) if Machine::is_unbound(&self.heap[hc], hc) => {
|
|
||||||
self.heap[hc] = HeapCell::Ref(val);
|
|
||||||
break;
|
|
||||||
},
|
|
||||||
Addr::HeapCell(hc) if Machine::is_unbound(&self.heap[val], val) => {
|
|
||||||
self.heap[val] = HeapCell::Ref(hc);
|
|
||||||
break;
|
|
||||||
},
|
|
||||||
_ => {
|
|
||||||
self.fail = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn unify(&mut self, a1: Addr, a2: Addr) {
|
|
||||||
let mut pdl : Vec<Addr> = vec![a1, a2];
|
|
||||||
|
|
||||||
self.fail = false;
|
|
||||||
|
|
||||||
while !(pdl.is_empty() || self.fail) {
|
|
||||||
let d1 = self.deref(pdl.pop().unwrap());
|
|
||||||
let d2 = self.deref(pdl.pop().unwrap());
|
|
||||||
|
|
||||||
if d1 != d2 {
|
|
||||||
match (self.lookup(d1), self.lookup(d2)) {
|
|
||||||
(&HeapCell::Ref(hc), _) =>
|
|
||||||
self.bind(d2, hc),
|
|
||||||
(_, &HeapCell::Ref(hc)) =>
|
|
||||||
self.bind(d1, hc),
|
|
||||||
(&HeapCell::Str(a1), &HeapCell::Str(a2)) => {
|
|
||||||
let r1 = &self.heap[a1];
|
|
||||||
let r2 = &self.heap[a2];
|
|
||||||
|
|
||||||
if let &HeapCell::NamedStr(n1, ref f1) = r1 {
|
|
||||||
if let &HeapCell::NamedStr(n2, ref f2) = r2 {
|
|
||||||
if n1 == n2 && *f1 == *f2 {
|
|
||||||
for i in 1 .. n1 {
|
|
||||||
pdl.push(Addr::HeapCell(a1 + i));
|
|
||||||
pdl.push(Addr::HeapCell(a2 + i));
|
|
||||||
}
|
|
||||||
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
self.fail = true;
|
|
||||||
},
|
|
||||||
_ => self.fail = true,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn execute_query_instr<'a, 'b : 'a>(&'a mut self, instr: &'b QueryInstruction) {
|
|
||||||
match instr {
|
|
||||||
&QueryInstruction::PutStructure(ref name, arity, reg) => {
|
|
||||||
self.heap.push(HeapCell::Str(self.h + 1));
|
|
||||||
self.heap.push(HeapCell::NamedStr(arity, name.clone()));
|
|
||||||
|
|
||||||
self.registers[reg] = self.heap[self.h].clone();
|
|
||||||
|
|
||||||
self.h += 2;
|
|
||||||
},
|
|
||||||
&QueryInstruction::SetVariable(reg) => {
|
|
||||||
self.heap.push(HeapCell::Ref(self.h));
|
|
||||||
self.registers[reg] = self.heap[self.h].clone();
|
|
||||||
|
|
||||||
self.h += 1;
|
|
||||||
},
|
|
||||||
&QueryInstruction::SetValue(reg) => {
|
|
||||||
self.heap.push(self.registers[reg].clone());
|
|
||||||
self.h += 1;
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn execute_fact_instr<'a, 'b : 'a>(&'a mut self, instr: &'b FactInstruction) {
|
|
||||||
match instr {
|
|
||||||
&FactInstruction::GetStructure(ref name, arity, reg) => {
|
|
||||||
let addr = self.deref(Addr::RegNum(reg));
|
|
||||||
|
|
||||||
match self.lookup(addr) {
|
|
||||||
&HeapCell::Str(a) => {
|
|
||||||
let result = &self.heap[a];
|
|
||||||
|
|
||||||
if let &HeapCell::NamedStr(named_arity, ref named_str) = result {
|
|
||||||
if arity == named_arity && *name == *named_str {
|
|
||||||
self.s = a + 1;
|
|
||||||
self.mode = MachineMode::Read;
|
|
||||||
} else {
|
|
||||||
self.fail = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
&HeapCell::Ref(r) => {
|
|
||||||
self.heap.push(HeapCell::Str(self.h + 1));
|
|
||||||
self.heap.push(HeapCell::NamedStr(arity, name.clone()));
|
|
||||||
|
|
||||||
let h = self.h;
|
|
||||||
|
|
||||||
self.bind(Addr::HeapCell(r), h);
|
|
||||||
|
|
||||||
self.h += 2;
|
|
||||||
self.mode = MachineMode::Write;
|
|
||||||
},
|
|
||||||
_ => {
|
|
||||||
self.fail = true;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
},
|
|
||||||
&FactInstruction::UnifyVariable(reg) => {
|
|
||||||
match self.mode {
|
|
||||||
MachineMode::Read => self.registers[reg] = self.heap[self.s].clone(),
|
|
||||||
MachineMode::Write => {
|
|
||||||
self.heap.push(HeapCell::Ref(self.h));
|
|
||||||
self.registers[reg] = self.heap[self.h].clone();
|
|
||||||
self.h += 1;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
self.s += 1;
|
|
||||||
},
|
|
||||||
&FactInstruction::UnifyValue(reg) => {
|
|
||||||
let s = self.s;
|
|
||||||
|
|
||||||
match self.mode {
|
|
||||||
MachineMode::Read => self.unify(Addr::RegNum(reg), Addr::HeapCell(s)),
|
|
||||||
MachineMode::Write => {
|
|
||||||
self.heap.push(self.registers[reg].clone());
|
|
||||||
self.h += 1;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
self.s += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn reset_heap(&mut self) {
|
|
||||||
let program = self.program.take();
|
|
||||||
|
|
||||||
*self = Machine::new();
|
|
||||||
self.program = program;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
mod l0_parser;
|
|
||||||
|
|
||||||
pub mod ast;
|
|
||||||
pub mod iterators;
|
|
||||||
pub mod parser;
|
|
||||||
pub mod codegen;
|
|
||||||
pub mod machine;
|
|
||||||
@@ -1,52 +0,0 @@
|
|||||||
use l0::ast::{Term, TopLevel, Var};
|
|
||||||
use l0::l0_parser::{parse_TopLevel};
|
|
||||||
|
|
||||||
use std::collections::{HashMap};
|
|
||||||
|
|
||||||
extern crate lalrpop_util as __lalrpop_util;
|
|
||||||
|
|
||||||
pub type ParseResult<'a> =
|
|
||||||
Result<TopLevel, __lalrpop_util::ParseError<usize,(usize, &'a str),()>>;
|
|
||||||
|
|
||||||
pub fn parse_top_level<'a>(input: &'a str) -> ParseResult {
|
|
||||||
let result = parse_TopLevel(&*input);
|
|
||||||
|
|
||||||
if let Ok(result) = result {
|
|
||||||
return Ok(mark_cells(result));
|
|
||||||
}
|
|
||||||
|
|
||||||
result
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn mark_cells(tl: TopLevel) -> TopLevel {
|
|
||||||
match tl {
|
|
||||||
TopLevel::Fact(term) => TopLevel::Fact(mark_term_cells(term)),
|
|
||||||
TopLevel::Query(term) => TopLevel::Query(mark_term_cells(term))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn mark_term_cells(term: Term) -> Term {
|
|
||||||
let mut cell_num = 1;
|
|
||||||
|
|
||||||
{
|
|
||||||
let mut bindings: HashMap<&Var, usize> = HashMap::new();
|
|
||||||
let mut iter = term.breadth_first_iter();
|
|
||||||
|
|
||||||
while let Some(term) = iter.next() {
|
|
||||||
if let &Term::Var(ref cell, ref var) = term {
|
|
||||||
let cell_num_in_map = bindings.entry(var).or_insert(cell_num);
|
|
||||||
|
|
||||||
if *cell_num_in_map != cell_num {
|
|
||||||
cell.set(*cell_num_in_map);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
term.set_cell(cell_num);
|
|
||||||
cell_num += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
term
|
|
||||||
}
|
|
||||||
123
src/l1/ast.rs
123
src/l1/ast.rs
@@ -1,123 +0,0 @@
|
|||||||
use std::cell::Cell;
|
|
||||||
use std::fmt;
|
|
||||||
use std::vec::Vec;
|
|
||||||
|
|
||||||
pub type Var = String;
|
|
||||||
|
|
||||||
pub type Atom = String;
|
|
||||||
|
|
||||||
pub enum TopLevel {
|
|
||||||
Fact(Term),
|
|
||||||
Query(Term)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
|
||||||
pub enum Level {
|
|
||||||
Shallow, Deep
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Display for Level {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
match self {
|
|
||||||
&Level::Shallow => write!(f, "A"),
|
|
||||||
&Level::Deep => write!(f, "X")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
|
||||||
pub enum Reg {
|
|
||||||
ArgAndNorm(usize, usize),
|
|
||||||
Norm(usize)
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Reg {
|
|
||||||
pub fn has_arg(&self) -> bool {
|
|
||||||
match self {
|
|
||||||
&Reg::ArgAndNorm(_, _) => true,
|
|
||||||
_ => false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn norm(&self) -> usize {
|
|
||||||
match self {
|
|
||||||
&Reg::ArgAndNorm(_, norm) | &Reg::Norm(norm) => norm
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub enum Term {
|
|
||||||
Atom(Cell<usize>, Atom),
|
|
||||||
Clause(Cell<usize>, Atom, Vec<Box<Term>>),
|
|
||||||
Var(Cell<Reg>, Var)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub enum TermRef<'a> {
|
|
||||||
Atom(Level, &'a Cell<usize>, &'a Atom),
|
|
||||||
Clause(Level, &'a Cell<usize>, &'a Atom, &'a Vec<Box<Term>>),
|
|
||||||
Var(Level, &'a Cell<Reg>, &'a Var)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub enum FactInstruction {
|
|
||||||
GetStructure(Level, Atom, usize, usize),
|
|
||||||
GetValue(usize, usize),
|
|
||||||
GetVariable(usize, usize),
|
|
||||||
Proceed,
|
|
||||||
UnifyVariable(usize),
|
|
||||||
UnifyValue(usize)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub enum QueryInstruction {
|
|
||||||
Call(Atom, usize),
|
|
||||||
PutStructure(Level, Atom, usize, usize),
|
|
||||||
PutValue(usize, usize),
|
|
||||||
PutVariable(usize, usize),
|
|
||||||
SetVariable(usize),
|
|
||||||
SetValue(usize),
|
|
||||||
}
|
|
||||||
|
|
||||||
pub type CompiledFact = Vec<FactInstruction>;
|
|
||||||
|
|
||||||
pub type CompiledQuery = Vec<QueryInstruction>;
|
|
||||||
|
|
||||||
#[derive(Clone, Copy, PartialEq)]
|
|
||||||
pub enum Addr {
|
|
||||||
HeapCell(usize),
|
|
||||||
RegNum(usize)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub enum HeapCellValue {
|
|
||||||
NamedStr(usize, Atom),
|
|
||||||
Ref(usize),
|
|
||||||
Str(usize),
|
|
||||||
}
|
|
||||||
|
|
||||||
pub type Heap = Vec<HeapCellValue>;
|
|
||||||
|
|
||||||
pub type Registers = Vec<HeapCellValue>;
|
|
||||||
|
|
||||||
impl Term {
|
|
||||||
pub fn subterms(&self) -> usize {
|
|
||||||
match self {
|
|
||||||
&Term::Clause(_, _, ref terms) => terms.len(),
|
|
||||||
_ => 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn name(&self) -> &Atom {
|
|
||||||
match self {
|
|
||||||
&Term::Atom(_, ref atom)
|
|
||||||
| &Term::Var(_, ref atom)
|
|
||||||
| &Term::Clause(_, ref atom, _) => atom
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn arity(&self) -> usize {
|
|
||||||
match self {
|
|
||||||
&Term::Atom(_, _) | &Term::Var(_, _) => 0,
|
|
||||||
&Term::Clause(_, _, ref child_terms) => child_terms.len()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,312 +0,0 @@
|
|||||||
use l1::ast::{Atom, CompiledFact, CompiledQuery, FactInstruction,
|
|
||||||
Level, QueryInstruction, Reg, Term, TermRef, Var};
|
|
||||||
use l1::iterators::{FactIterator, QueryIterator};
|
|
||||||
|
|
||||||
use std::cell::Cell;
|
|
||||||
use std::collections::HashMap;
|
|
||||||
use std::fmt;
|
|
||||||
use std::vec::Vec;
|
|
||||||
|
|
||||||
impl fmt::Display for QueryInstruction {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
match self {
|
|
||||||
&QueryInstruction::Call(ref name, ref arity) =>
|
|
||||||
write!(f, "call {}/{}", name, arity),
|
|
||||||
&QueryInstruction::PutStructure(ref lvl, ref a, ref s, ref r) =>
|
|
||||||
write!(f, "put_structure {}/{}, {}{}", a, s, lvl, r),
|
|
||||||
&QueryInstruction::PutValue(ref a, ref x) =>
|
|
||||||
write!(f, "put_value X{}, A{}", x, a),
|
|
||||||
&QueryInstruction::PutVariable(ref a, ref x) =>
|
|
||||||
write!(f, "put_variable X{}, A{}", x, a),
|
|
||||||
&QueryInstruction::SetVariable(ref r) =>
|
|
||||||
write!(f, "set_variable X{}", r),
|
|
||||||
&QueryInstruction::SetValue(ref r) =>
|
|
||||||
write!(f, "set_value X{}", r),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Display for FactInstruction {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
match self {
|
|
||||||
&FactInstruction::GetStructure(ref lvl, ref a, ref s, ref r) =>
|
|
||||||
write!(f, "get_structure {}/{}, {}{}", a, s, lvl, r),
|
|
||||||
&FactInstruction::GetValue(ref a, ref x) =>
|
|
||||||
write!(f, "get_value X{}, A{}", x, a),
|
|
||||||
&FactInstruction::GetVariable(ref a, ref x) =>
|
|
||||||
write!(f, "get_variable X{}, A{}", x, a),
|
|
||||||
&FactInstruction::Proceed =>
|
|
||||||
write!(f, "proceed"),
|
|
||||||
&FactInstruction::UnifyVariable(ref r) =>
|
|
||||||
write!(f, "unify_variable X{}", r),
|
|
||||||
&FactInstruction::UnifyValue(ref r) =>
|
|
||||||
write!(f, "unify_value X{}", r)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct TermMarker<'a> {
|
|
||||||
bindings: HashMap<&'a Var, Reg>,
|
|
||||||
arg_c: usize,
|
|
||||||
norm_c: usize
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> TermMarker<'a> {
|
|
||||||
fn new(term: &'a Term) -> TermMarker<'a> {
|
|
||||||
TermMarker { bindings: HashMap::new(),
|
|
||||||
arg_c: 1,
|
|
||||||
norm_c: term.subterms() + 1 }
|
|
||||||
}
|
|
||||||
|
|
||||||
fn contains_var(&self, var: &'a Var) -> bool {
|
|
||||||
self.bindings.contains_key(var)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get(&self, var: &'a Var) -> Reg {
|
|
||||||
*self.bindings.get(var).unwrap()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn insert(&mut self, var: &'a Var, r: Reg) {
|
|
||||||
self.bindings.insert(var, r);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn mark_non_var(&mut self, lvl: Level, cell: &Cell<usize>) {
|
|
||||||
if cell.get() == 0 {
|
|
||||||
match lvl {
|
|
||||||
Level::Deep => {
|
|
||||||
let norm = self.norm_c;
|
|
||||||
self.norm_c += 1;
|
|
||||||
cell.set(norm);
|
|
||||||
},
|
|
||||||
Level::Shallow => {
|
|
||||||
let arg = self.arg_c;
|
|
||||||
self.arg_c += 1;
|
|
||||||
cell.set(arg);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn mark_var(&mut self, lvl: Level, var: &'a Var) -> Reg {
|
|
||||||
if self.contains_var(var) {
|
|
||||||
let reg = self.get(var);
|
|
||||||
|
|
||||||
match lvl {
|
|
||||||
Level::Deep => Reg::Norm(reg.norm()),
|
|
||||||
Level::Shallow if reg.has_arg() => {
|
|
||||||
let arg = self.arg_c;
|
|
||||||
self.arg_c += 1;
|
|
||||||
|
|
||||||
Reg::ArgAndNorm(arg, reg.norm())
|
|
||||||
},
|
|
||||||
Level::Shallow => {
|
|
||||||
let norm = reg.norm();
|
|
||||||
let reg = Reg::ArgAndNorm(self.arg_c, norm);
|
|
||||||
|
|
||||||
self.arg_c += 1;
|
|
||||||
self.insert(var, reg);
|
|
||||||
|
|
||||||
reg
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
let reg = match lvl {
|
|
||||||
Level::Deep => Reg::Norm(self.norm_c),
|
|
||||||
Level::Shallow => {
|
|
||||||
let reg = Reg::ArgAndNorm(self.arg_c, self.norm_c);
|
|
||||||
self.arg_c += 1;
|
|
||||||
reg
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
self.norm_c += 1;
|
|
||||||
self.insert(var, reg);
|
|
||||||
reg
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
trait CompilationTarget<'a> {
|
|
||||||
type Iterator : Iterator<Item=TermRef<'a>>;
|
|
||||||
|
|
||||||
fn iter(&'a Term) -> Self::Iterator;
|
|
||||||
|
|
||||||
fn to_structure(Level, Atom, usize, usize) -> Self;
|
|
||||||
|
|
||||||
fn argument_to_variable(usize, usize) -> Self;
|
|
||||||
fn argument_to_value(usize, usize) -> Self;
|
|
||||||
fn subterm_to_variable(usize) -> Self;
|
|
||||||
fn subterm_to_value(usize) -> Self;
|
|
||||||
|
|
||||||
fn clause_arg_to_instr(usize) -> Self;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> CompilationTarget<'a> for FactInstruction {
|
|
||||||
type Iterator = FactIterator<'a>;
|
|
||||||
|
|
||||||
fn iter(term: &'a Term) -> Self::Iterator {
|
|
||||||
term.breadth_first_iter()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn to_structure(lvl: Level, atom: Atom, arity: usize, cell_num: usize) -> Self {
|
|
||||||
FactInstruction::GetStructure(lvl, atom, arity, cell_num)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn argument_to_variable(arg: usize, val: usize) -> Self {
|
|
||||||
FactInstruction::GetVariable(arg, val)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn argument_to_value(arg: usize, val: usize) -> Self {
|
|
||||||
FactInstruction::GetValue(arg, val)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn subterm_to_variable(val: usize) -> Self {
|
|
||||||
FactInstruction::UnifyVariable(val)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn subterm_to_value(val: usize) -> Self {
|
|
||||||
FactInstruction::UnifyValue(val)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn clause_arg_to_instr(val: usize) -> Self {
|
|
||||||
FactInstruction::UnifyVariable(val)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> CompilationTarget<'a> for QueryInstruction {
|
|
||||||
type Iterator = QueryIterator<'a>;
|
|
||||||
|
|
||||||
fn iter(term: &'a Term) -> Self::Iterator {
|
|
||||||
term.post_order_iter()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn to_structure(lvl: Level, atom: Atom, arity: usize, cell_num: usize) -> Self {
|
|
||||||
QueryInstruction::PutStructure(lvl, atom, arity, cell_num)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn argument_to_variable(arg: usize, val: usize) -> Self {
|
|
||||||
QueryInstruction::PutVariable(arg, val)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn argument_to_value(arg: usize, val: usize) -> Self {
|
|
||||||
QueryInstruction::PutValue(arg, val)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn subterm_to_variable(val: usize) -> Self {
|
|
||||||
QueryInstruction::SetVariable(val)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn subterm_to_value(val: usize) -> Self {
|
|
||||||
QueryInstruction::SetValue(val)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn clause_arg_to_instr(val: usize) -> Self {
|
|
||||||
QueryInstruction::SetValue(val)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn to_structure<'a, Target>(tm: &mut TermMarker<'a>,
|
|
||||||
lvl: Level,
|
|
||||||
name: &'a Atom,
|
|
||||||
cell: &'a Cell<usize>,
|
|
||||||
arity: usize)
|
|
||||||
-> Target
|
|
||||||
where Target: CompilationTarget<'a>
|
|
||||||
{
|
|
||||||
tm.mark_non_var(lvl, cell);
|
|
||||||
Target::to_structure(lvl, name.clone(), arity, cell.get())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn non_var_subterm<'a, Target>(tm: &mut TermMarker<'a>, cell: &'a Cell<usize>)
|
|
||||||
-> Target
|
|
||||||
where Target: CompilationTarget<'a>
|
|
||||||
{
|
|
||||||
tm.mark_non_var(Level::Deep, cell);
|
|
||||||
Target::clause_arg_to_instr(cell.get())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn var_term<'a, Target>(tm: &mut TermMarker<'a>,
|
|
||||||
lvl: Level,
|
|
||||||
cell: &'a Cell<Reg>,
|
|
||||||
var: &'a Var)
|
|
||||||
-> Target
|
|
||||||
where Target: CompilationTarget<'a>
|
|
||||||
{
|
|
||||||
if !tm.contains_var(var) {
|
|
||||||
let reg = tm.mark_var(lvl, var);
|
|
||||||
cell.set(reg);
|
|
||||||
|
|
||||||
match reg {
|
|
||||||
Reg::ArgAndNorm(arg, norm) =>
|
|
||||||
Target::argument_to_variable(arg, norm),
|
|
||||||
Reg::Norm(norm) =>
|
|
||||||
Target::subterm_to_variable(norm)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
let reg = tm.mark_var(lvl, var);
|
|
||||||
cell.set(reg);
|
|
||||||
|
|
||||||
match reg {
|
|
||||||
Reg::ArgAndNorm(arg, norm) =>
|
|
||||||
Target::argument_to_value(arg, norm),
|
|
||||||
Reg::Norm(norm) =>
|
|
||||||
Target::subterm_to_value(norm)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn subterm_to_instr<'a, Target>(tm: &mut TermMarker<'a>, subterm: &'a Term)
|
|
||||||
-> Target
|
|
||||||
where Target: CompilationTarget<'a>
|
|
||||||
{
|
|
||||||
match subterm {
|
|
||||||
&Term::Atom(ref cell, _) | &Term::Clause(ref cell, _, _) =>
|
|
||||||
non_var_subterm(tm, cell),
|
|
||||||
&Term::Var(ref cell, ref var) =>
|
|
||||||
var_term(tm, Level::Deep, cell, var)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn compile_target<'a, Target>(term: &'a Term) -> Vec<Target>
|
|
||||||
where Target: CompilationTarget<'a>
|
|
||||||
{
|
|
||||||
let iter = Target::iter(term);
|
|
||||||
let mut target = Vec::<Target>::new();
|
|
||||||
let mut marker = TermMarker::new(term);
|
|
||||||
|
|
||||||
for term in iter {
|
|
||||||
match term {
|
|
||||||
TermRef::Atom(lvl, term, atom) =>
|
|
||||||
target.push(to_structure(&mut marker, lvl, atom, term, 0)),
|
|
||||||
TermRef::Clause(lvl, term, atom, terms) => {
|
|
||||||
target.push(to_structure(&mut marker, lvl, atom, term, terms.len()));
|
|
||||||
|
|
||||||
for subterm in terms {
|
|
||||||
target.push(subterm_to_instr(&mut marker, subterm.as_ref()));
|
|
||||||
}
|
|
||||||
},
|
|
||||||
TermRef::Var(lvl @ Level::Shallow, ref cell, ref var) =>
|
|
||||||
target.push(var_term(&mut marker, lvl, cell, var)),
|
|
||||||
_ => {}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
target
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn compile_fact(term: &Term) -> CompiledFact {
|
|
||||||
let mut compiled_fact = compile_target(term);
|
|
||||||
|
|
||||||
compiled_fact.push(FactInstruction::Proceed);
|
|
||||||
compiled_fact
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn compile_query<'a>(term: &'a Term) -> CompiledQuery {
|
|
||||||
let mut compiled_query = compile_target(term);
|
|
||||||
|
|
||||||
if let &Term::Clause(_, ref atom, ref terms) = term {
|
|
||||||
compiled_query.push(QueryInstruction::Call(atom.clone(), terms.len()));
|
|
||||||
}
|
|
||||||
|
|
||||||
compiled_query
|
|
||||||
}
|
|
||||||
@@ -1,175 +0,0 @@
|
|||||||
use l1::ast::{Atom, Level, Reg, Term, TermRef, Var};
|
|
||||||
|
|
||||||
use std::cell::Cell;
|
|
||||||
use std::collections::VecDeque;
|
|
||||||
use std::vec::Vec;
|
|
||||||
|
|
||||||
enum IteratorState<'a> {
|
|
||||||
Atom(Level, &'a Cell<usize>, &'a Atom),
|
|
||||||
Clause(Level, usize, &'a Cell<usize>, &'a Atom, &'a Vec<Box<Term>>),
|
|
||||||
IsolatedAtom(&'a Cell<usize>, &'a Atom),
|
|
||||||
IsolatedVar(&'a Cell<Reg>, &'a Var),
|
|
||||||
RootClause(usize, &'a Vec<Box<Term>>),
|
|
||||||
Var(Level, &'a Cell<Reg>, &'a Var)
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> IteratorState<'a> {
|
|
||||||
fn to_state(lvl: Level, term: &'a Term) -> IteratorState<'a>
|
|
||||||
{
|
|
||||||
match term {
|
|
||||||
&Term::Atom(ref cell, ref atom) =>
|
|
||||||
IteratorState::Atom(lvl, cell, atom),
|
|
||||||
&Term::Clause(ref cell, ref atom, ref child_terms) =>
|
|
||||||
IteratorState::Clause(lvl, 0, cell, atom, child_terms),
|
|
||||||
&Term::Var(ref cell, ref var) =>
|
|
||||||
IteratorState::Var(lvl, cell, var)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct QueryIterator<'a> {
|
|
||||||
state_stack: Vec<IteratorState<'a>>
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> QueryIterator<'a> {
|
|
||||||
fn push_clause(&mut self,
|
|
||||||
lvl: Level,
|
|
||||||
child_num: usize,
|
|
||||||
cell: &'a Cell<usize>,
|
|
||||||
name: &'a Atom,
|
|
||||||
child_terms: &'a Vec<Box<Term>>)
|
|
||||||
{
|
|
||||||
self.state_stack.push(IteratorState::Clause(lvl,
|
|
||||||
child_num,
|
|
||||||
cell,
|
|
||||||
name,
|
|
||||||
child_terms));
|
|
||||||
}
|
|
||||||
|
|
||||||
fn push_root_clause(&mut self,
|
|
||||||
child_num: usize,
|
|
||||||
child_terms: &'a Vec<Box<Term>>)
|
|
||||||
{
|
|
||||||
self.state_stack.push(IteratorState::RootClause(child_num, child_terms));
|
|
||||||
}
|
|
||||||
|
|
||||||
fn push_subterm(&mut self, lvl: Level, term: &'a Term) {
|
|
||||||
self.state_stack.push(IteratorState::to_state(lvl, term));
|
|
||||||
}
|
|
||||||
|
|
||||||
fn new(term: &'a Term) -> QueryIterator<'a> {
|
|
||||||
let state = match term {
|
|
||||||
&Term::Atom(ref cell, ref atom) =>
|
|
||||||
IteratorState::IsolatedAtom(cell, atom),
|
|
||||||
&Term::Clause(_, _, ref terms) =>
|
|
||||||
IteratorState::RootClause(0, terms),
|
|
||||||
&Term::Var(ref cell, ref var) =>
|
|
||||||
IteratorState::IsolatedVar(cell, var)
|
|
||||||
};
|
|
||||||
|
|
||||||
QueryIterator { state_stack: vec![state] }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Iterator for QueryIterator<'a> {
|
|
||||||
type Item = TermRef<'a>;
|
|
||||||
|
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
|
||||||
while let Some(iter_state) = self.state_stack.pop() {
|
|
||||||
match iter_state {
|
|
||||||
IteratorState::Atom(lvl, cell, atom) =>
|
|
||||||
return Some(TermRef::Atom(lvl, cell, atom)),
|
|
||||||
IteratorState::Clause(lvl, child_num, cell, atom, child_terms) => {
|
|
||||||
if child_num == child_terms.len() {
|
|
||||||
return Some(TermRef::Clause(lvl, cell, atom, child_terms));
|
|
||||||
} else {
|
|
||||||
self.push_clause(lvl, child_num + 1, cell, atom, child_terms);
|
|
||||||
self.push_subterm(Level::Deep, child_terms[child_num].as_ref());
|
|
||||||
}
|
|
||||||
},
|
|
||||||
IteratorState::IsolatedAtom(cell, atom) =>
|
|
||||||
return Some(TermRef::Atom(Level::Shallow, cell, atom)),
|
|
||||||
IteratorState::IsolatedVar(cell, var) =>
|
|
||||||
return Some(TermRef::Var(Level::Shallow, cell, var)),
|
|
||||||
IteratorState::RootClause(child_num, child_terms) => {
|
|
||||||
if child_num == child_terms.len() {
|
|
||||||
return None;
|
|
||||||
} else {
|
|
||||||
self.push_root_clause(child_num + 1, child_terms);
|
|
||||||
self.push_subterm(Level::Shallow, child_terms[child_num].as_ref());
|
|
||||||
}
|
|
||||||
},
|
|
||||||
IteratorState::Var(lvl, cell, var) =>
|
|
||||||
return Some(TermRef::Var(lvl, cell, var))
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct FactIterator<'a> {
|
|
||||||
state_queue: VecDeque<IteratorState<'a>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> FactIterator<'a> {
|
|
||||||
fn push_subterm(&mut self, lvl: Level, term: &'a Term) {
|
|
||||||
self.state_queue.push_back(IteratorState::to_state(lvl, term));
|
|
||||||
}
|
|
||||||
|
|
||||||
fn new(term: &'a Term) -> FactIterator<'a> {
|
|
||||||
let states = match term {
|
|
||||||
&Term::Atom(ref cell, ref atom) =>
|
|
||||||
vec![IteratorState::IsolatedAtom(cell, atom)],
|
|
||||||
&Term::Clause(_, _, ref terms) =>
|
|
||||||
vec![IteratorState::RootClause(0, terms)],
|
|
||||||
&Term::Var(ref cell, ref var) =>
|
|
||||||
vec![IteratorState::IsolatedVar(cell, var)]
|
|
||||||
};
|
|
||||||
|
|
||||||
FactIterator { state_queue: VecDeque::from(states) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Iterator for FactIterator<'a> {
|
|
||||||
type Item = TermRef<'a>;
|
|
||||||
|
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
|
||||||
while let Some(state) = self.state_queue.pop_front() {
|
|
||||||
match state {
|
|
||||||
IteratorState::Atom(lvl, cell, atom) =>
|
|
||||||
return Some(TermRef::Atom(lvl, cell, atom)),
|
|
||||||
IteratorState::Clause(lvl, _, cell, atom, child_terms) => {
|
|
||||||
for child_term in child_terms {
|
|
||||||
self.push_subterm(Level::Deep, child_term);
|
|
||||||
}
|
|
||||||
|
|
||||||
return Some(TermRef::Clause(lvl, cell, atom, child_terms));
|
|
||||||
},
|
|
||||||
IteratorState::IsolatedAtom(cell, atom) =>
|
|
||||||
return Some(TermRef::Atom(Level::Shallow, cell, atom)),
|
|
||||||
IteratorState::IsolatedVar(cell, var) =>
|
|
||||||
return Some(TermRef::Var(Level::Shallow, cell, var)),
|
|
||||||
IteratorState::RootClause(_, child_terms) => {
|
|
||||||
for child_term in child_terms {
|
|
||||||
self.push_subterm(Level::Shallow, child_term);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
IteratorState::Var(lvl, cell, var) =>
|
|
||||||
return Some(TermRef::Var(lvl, cell, var))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Term {
|
|
||||||
pub fn post_order_iter(&self) -> QueryIterator {
|
|
||||||
QueryIterator::new(self)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn breadth_first_iter(&self) -> FactIterator {
|
|
||||||
FactIterator::new(self)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
use std::cell::Cell;
|
|
||||||
|
|
||||||
use l1::ast::{Atom, Reg, Term, TopLevel, Var};
|
|
||||||
|
|
||||||
grammar;
|
|
||||||
|
|
||||||
pub TopLevel: TopLevel = {
|
|
||||||
"?-" <t:Term> "." => TopLevel::Query(t),
|
|
||||||
<t:Term> "." => TopLevel::Fact(t),
|
|
||||||
};
|
|
||||||
|
|
||||||
Atom : Atom = {
|
|
||||||
r"[a-z][a-z0-9_]*" => <>.trim().to_string(),
|
|
||||||
};
|
|
||||||
|
|
||||||
Var : Var = {
|
|
||||||
r"[A-Z][a-z0-9_]*" => <>.trim().to_string(),
|
|
||||||
};
|
|
||||||
|
|
||||||
BoxedTerm : Box<Term> = {
|
|
||||||
<t:Term> => Box::new(t),
|
|
||||||
};
|
|
||||||
|
|
||||||
Term : Term = {
|
|
||||||
<a:Atom> "(" <ts: (<BoxedTerm> ",")*> <t:BoxedTerm> ")" => {
|
|
||||||
let mut ts = ts;
|
|
||||||
ts.push(t);
|
|
||||||
Term::Clause(Cell::new(0), a, ts)
|
|
||||||
},
|
|
||||||
<Atom> => Term::Atom(Cell::new(0), <>),
|
|
||||||
<Var> => Term::Var(Cell::new(Reg::Norm(0)), <>)
|
|
||||||
};
|
|
||||||
1595
src/l1/l1_parser.rs
1595
src/l1/l1_parser.rs
File diff suppressed because it is too large
Load Diff
@@ -1,309 +0,0 @@
|
|||||||
use l1::ast::{Addr, Atom, CompiledFact, CompiledQuery,
|
|
||||||
FactInstruction, Heap, HeapCellValue, QueryInstruction,
|
|
||||||
Registers};
|
|
||||||
|
|
||||||
use std::collections::HashMap;
|
|
||||||
use std::vec::Vec;
|
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
|
||||||
enum MachineMode {
|
|
||||||
Read,
|
|
||||||
Write
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Machine {
|
|
||||||
h : usize,
|
|
||||||
s : usize,
|
|
||||||
p : usize,
|
|
||||||
code : CompiledFact,
|
|
||||||
code_dir : HashMap<(Atom, usize), usize>,
|
|
||||||
fail : bool,
|
|
||||||
heap : Heap,
|
|
||||||
mode : MachineMode,
|
|
||||||
registers : Registers
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Machine {
|
|
||||||
pub fn new() -> Machine {
|
|
||||||
Machine { h : 0,
|
|
||||||
s : 0,
|
|
||||||
p : 0,
|
|
||||||
code : Vec::new(),
|
|
||||||
code_dir : HashMap::new(),
|
|
||||||
fail : false,
|
|
||||||
heap : Vec::with_capacity(256),
|
|
||||||
mode : MachineMode::Write,
|
|
||||||
registers : vec![HeapCellValue::Ref(0); 32] }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn add_fact(&mut self, mut fact: CompiledFact, name: Atom, arity: usize)
|
|
||||||
{
|
|
||||||
let index = self.code.len();
|
|
||||||
|
|
||||||
self.code.append(&mut fact);
|
|
||||||
self.code_dir.insert((name, arity), index);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn failed(&self) -> bool {
|
|
||||||
self.fail
|
|
||||||
}
|
|
||||||
|
|
||||||
fn lookup(&self, a: Addr) -> &HeapCellValue {
|
|
||||||
match a {
|
|
||||||
Addr::HeapCell(hc) => &self.heap[hc],
|
|
||||||
Addr::RegNum(reg) => &self.registers[reg]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn deref(&self, a: Addr) -> Addr {
|
|
||||||
let mut a = a;
|
|
||||||
|
|
||||||
loop {
|
|
||||||
if let &HeapCellValue::Ref(value) = self.lookup(a) {
|
|
||||||
if let Addr::HeapCell(av) = a {
|
|
||||||
if value != av {
|
|
||||||
a = Addr::HeapCell(value);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
a = Addr::HeapCell(value);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return a;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
fn is_unbound(hc: &HeapCellValue, index: usize) -> bool {
|
|
||||||
match hc {
|
|
||||||
&HeapCellValue::Ref(r) => r == index,
|
|
||||||
_ => false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//TODO: try to compress this function.
|
|
||||||
fn bind(&mut self, a: Addr, val: usize) {
|
|
||||||
let mut a = a;
|
|
||||||
|
|
||||||
loop {
|
|
||||||
match a {
|
|
||||||
Addr::RegNum(reg) => {
|
|
||||||
if let HeapCellValue::Ref(hc) = self.registers[reg] {
|
|
||||||
a = Addr::HeapCell(hc);
|
|
||||||
} else if Machine::is_unbound(&self.heap[val], val) {
|
|
||||||
self.heap[val] = self.registers[reg].clone();
|
|
||||||
break;
|
|
||||||
} else {
|
|
||||||
self.fail = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
Addr::HeapCell(hc) if Machine::is_unbound(&self.heap[hc], hc) => {
|
|
||||||
self.heap[hc] = HeapCellValue::Ref(val);
|
|
||||||
break;
|
|
||||||
},
|
|
||||||
Addr::HeapCell(hc) if Machine::is_unbound(&self.heap[val], val) => {
|
|
||||||
self.heap[val] = HeapCellValue::Ref(hc);
|
|
||||||
break;
|
|
||||||
},
|
|
||||||
_ => {
|
|
||||||
self.fail = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn unify(&mut self, a1: Addr, a2: Addr) {
|
|
||||||
let mut pdl = vec![a1, a2];
|
|
||||||
|
|
||||||
self.fail = false;
|
|
||||||
|
|
||||||
while !(pdl.is_empty() || self.fail) {
|
|
||||||
let d1 = self.deref(pdl.pop().unwrap());
|
|
||||||
let d2 = self.deref(pdl.pop().unwrap());
|
|
||||||
|
|
||||||
if d1 != d2 {
|
|
||||||
match (self.lookup(d1), self.lookup(d2)) {
|
|
||||||
(&HeapCellValue::Ref(hc), _) =>
|
|
||||||
self.bind(d2, hc),
|
|
||||||
(_, &HeapCellValue::Ref(hc)) =>
|
|
||||||
self.bind(d1, hc),
|
|
||||||
(&HeapCellValue::Str(a1), &HeapCellValue::Str(a2)) => {
|
|
||||||
let r1 = &self.heap[a1];
|
|
||||||
let r2 = &self.heap[a2];
|
|
||||||
|
|
||||||
if let &HeapCellValue::NamedStr(n1, ref f1) = r1 {
|
|
||||||
if let &HeapCellValue::NamedStr(n2, ref f2) = r2 {
|
|
||||||
if n1 == n2 && *f1 == *f2 {
|
|
||||||
for i in 1 .. n1 {
|
|
||||||
pdl.push(Addr::HeapCell(a1 + i));
|
|
||||||
pdl.push(Addr::HeapCell(a2 + i));
|
|
||||||
}
|
|
||||||
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
self.fail = true;
|
|
||||||
},
|
|
||||||
_ => self.fail = true,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn execute_fact(&mut self) {
|
|
||||||
loop {
|
|
||||||
if let &FactInstruction::Proceed = &self.code[self.p] {
|
|
||||||
break;
|
|
||||||
} else if self.fail {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
let fact_instr = self.code[self.p].clone();
|
|
||||||
self.execute_fact_instr(fact_instr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn execute_query(&mut self, query: &CompiledQuery) {
|
|
||||||
for instr in query {
|
|
||||||
self.execute_query_instr(instr);
|
|
||||||
|
|
||||||
if self.fail {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn execute_query_instr<'a, 'b: 'a>(&'a mut self, instr: &'b QueryInstruction) {
|
|
||||||
match instr {
|
|
||||||
&QueryInstruction::Call(ref name, arity) => {
|
|
||||||
// why is Option<&T> not Deref?!?!?
|
|
||||||
// is it because if the value is None, there's nothing to
|
|
||||||
// dereference?
|
|
||||||
let compiled_fact_index =
|
|
||||||
self.code_dir.get(&(name.clone(), arity))
|
|
||||||
.map(|index| *index);
|
|
||||||
|
|
||||||
match compiled_fact_index {
|
|
||||||
Some(compiled_fact_index) => {
|
|
||||||
self.p = compiled_fact_index;
|
|
||||||
self.execute_fact();
|
|
||||||
},
|
|
||||||
None => self.fail = true,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
&QueryInstruction::PutStructure(_, ref name, arity, reg) => {
|
|
||||||
self.heap.push(HeapCellValue::Str(self.h + 1));
|
|
||||||
self.heap.push(HeapCellValue::NamedStr(arity, name.clone()));
|
|
||||||
|
|
||||||
self.registers[reg] = self.heap[self.h].clone();
|
|
||||||
|
|
||||||
self.h += 2;
|
|
||||||
},
|
|
||||||
&QueryInstruction::PutValue(arg, norm) =>
|
|
||||||
self.registers[arg] = self.registers[norm].clone(),
|
|
||||||
&QueryInstruction::PutVariable(arg, norm) => {
|
|
||||||
self.heap.push(HeapCellValue::Ref(self.h));
|
|
||||||
|
|
||||||
self.registers[norm] = self.heap[self.h].clone();
|
|
||||||
self.registers[arg] = self.heap[self.h].clone();
|
|
||||||
|
|
||||||
self.h += 1;
|
|
||||||
},
|
|
||||||
&QueryInstruction::SetVariable(reg) => {
|
|
||||||
self.heap.push(HeapCellValue::Ref(self.h));
|
|
||||||
self.registers[reg] = self.heap[self.h].clone();
|
|
||||||
|
|
||||||
self.h += 1;
|
|
||||||
},
|
|
||||||
&QueryInstruction::SetValue(reg) => {
|
|
||||||
self.heap.push(self.registers[reg].clone());
|
|
||||||
self.h += 1;
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn execute_fact_instr(&mut self, instr: FactInstruction) {
|
|
||||||
match instr {
|
|
||||||
FactInstruction::Proceed => return,
|
|
||||||
FactInstruction::GetStructure(_, name, arity, reg) => {
|
|
||||||
let addr = self.deref(Addr::RegNum(reg));
|
|
||||||
|
|
||||||
match self.lookup(addr) {
|
|
||||||
&HeapCellValue::Str(a) => {
|
|
||||||
let result = &self.heap[a];
|
|
||||||
|
|
||||||
if let &HeapCellValue::NamedStr(named_arity, ref named_str) = result {
|
|
||||||
if arity == named_arity && *name == *named_str {
|
|
||||||
self.s = a + 1;
|
|
||||||
self.mode = MachineMode::Read;
|
|
||||||
} else {
|
|
||||||
self.fail = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
&HeapCellValue::Ref(r) => {
|
|
||||||
self.heap.push(HeapCellValue::Str(self.h + 1));
|
|
||||||
self.heap.push(HeapCellValue::NamedStr(arity, name));
|
|
||||||
|
|
||||||
let h = self.h;
|
|
||||||
|
|
||||||
self.bind(Addr::HeapCell(r), h);
|
|
||||||
|
|
||||||
self.h += 2;
|
|
||||||
self.mode = MachineMode::Write;
|
|
||||||
},
|
|
||||||
_ => {
|
|
||||||
self.fail = true;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
},
|
|
||||||
FactInstruction::GetVariable(arg, norm) =>
|
|
||||||
self.registers[norm] = self.registers[arg].clone(),
|
|
||||||
FactInstruction::GetValue(arg, norm) =>
|
|
||||||
self.unify(Addr::RegNum(norm), Addr::RegNum(arg)),
|
|
||||||
FactInstruction::UnifyVariable(reg) => {
|
|
||||||
match self.mode {
|
|
||||||
MachineMode::Read => self.registers[reg] = self.heap[self.s].clone(),
|
|
||||||
MachineMode::Write => {
|
|
||||||
self.heap.push(HeapCellValue::Ref(self.h));
|
|
||||||
self.registers[reg] = self.heap[self.h].clone();
|
|
||||||
self.h += 1;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
self.s += 1;
|
|
||||||
},
|
|
||||||
FactInstruction::UnifyValue(reg) => {
|
|
||||||
let s = self.s;
|
|
||||||
|
|
||||||
match self.mode {
|
|
||||||
MachineMode::Read => self.unify(Addr::RegNum(reg), Addr::HeapCell(s)),
|
|
||||||
MachineMode::Write => {
|
|
||||||
self.heap.push(self.registers[reg].clone());
|
|
||||||
self.h += 1;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
self.s += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
self.p += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn reset_machine_state(&mut self) {
|
|
||||||
self.h = 0;
|
|
||||||
self.s = 0;
|
|
||||||
self.p = 0;
|
|
||||||
|
|
||||||
self.fail = false;
|
|
||||||
self.heap = Vec::with_capacity(256);
|
|
||||||
self.mode = MachineMode::Write;
|
|
||||||
self.registers = vec![HeapCellValue::Ref(0); 32];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
pub mod ast;
|
|
||||||
pub mod iterators;
|
|
||||||
pub mod l1_parser;
|
|
||||||
pub mod codegen;
|
|
||||||
pub mod machine;
|
|
||||||
253
src/l2/ast.rs
253
src/l2/ast.rs
@@ -1,253 +0,0 @@
|
|||||||
use std::cell::Cell;
|
|
||||||
use std::fmt;
|
|
||||||
use std::ops::{Add, AddAssign};
|
|
||||||
use std::vec::Vec;
|
|
||||||
|
|
||||||
pub type Var = String;
|
|
||||||
|
|
||||||
pub type Atom = String;
|
|
||||||
|
|
||||||
pub enum TopLevel {
|
|
||||||
Fact(Term),
|
|
||||||
Rule(Rule),
|
|
||||||
Query(Term)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
|
||||||
pub enum Level {
|
|
||||||
Shallow, Deep
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Display for Level {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
match self {
|
|
||||||
&Level::Shallow => write!(f, "A"),
|
|
||||||
&Level::Deep => write!(f, "X")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
|
||||||
pub enum RegType {
|
|
||||||
Perm(usize),
|
|
||||||
Temp(usize)
|
|
||||||
}
|
|
||||||
|
|
||||||
impl RegType {
|
|
||||||
pub fn reg_num(self) -> usize {
|
|
||||||
match self {
|
|
||||||
RegType::Perm(reg_num) | RegType::Temp(reg_num) => reg_num
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn is_perm(self) -> bool {
|
|
||||||
match self {
|
|
||||||
RegType::Perm(_) => true,
|
|
||||||
_ => false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Display for VarReg {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
match self {
|
|
||||||
&VarReg::Norm(RegType::Perm(reg)) => write!(f, "Y{}", reg),
|
|
||||||
&VarReg::Norm(RegType::Temp(reg)) => write!(f, "X{}", reg),
|
|
||||||
&VarReg::ArgAndNorm(RegType::Perm(reg), arg) =>
|
|
||||||
write!(f, "Y{} A{}", reg, arg),
|
|
||||||
&VarReg::ArgAndNorm(RegType::Temp(reg), arg) =>
|
|
||||||
write!(f, "X{} A{}", reg, arg)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<RegType> for Addr {
|
|
||||||
fn from(reg: RegType) -> Addr {
|
|
||||||
match reg {
|
|
||||||
RegType::Perm(reg) => Addr::StackCell(reg),
|
|
||||||
RegType::Temp(reg) => Addr::RegNum(reg)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Display for RegType {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
match self {
|
|
||||||
&RegType::Perm(val) => write!(f, "Y{}", val),
|
|
||||||
&RegType::Temp(val) => write!(f, "X{}", val)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
|
||||||
pub enum VarReg {
|
|
||||||
ArgAndNorm(RegType, usize),
|
|
||||||
Norm(RegType)
|
|
||||||
}
|
|
||||||
|
|
||||||
impl VarReg {
|
|
||||||
pub fn norm(self) -> RegType {
|
|
||||||
match self {
|
|
||||||
VarReg::ArgAndNorm(reg, _) | VarReg::Norm(reg) => reg
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn root_register(self) -> usize {
|
|
||||||
match self {
|
|
||||||
VarReg::ArgAndNorm(_, root) => root,
|
|
||||||
VarReg::Norm(root) => root.reg_num()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub enum Term {
|
|
||||||
Atom(Cell<RegType>, Atom),
|
|
||||||
Clause(Cell<RegType>, Atom, Vec<Box<Term>>),
|
|
||||||
Var(Cell<VarReg>, Var)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Rule {
|
|
||||||
pub head: (Term, Term),
|
|
||||||
pub clauses: Vec<Term>
|
|
||||||
}
|
|
||||||
|
|
||||||
pub enum TermRef<'a> {
|
|
||||||
Atom(Level, &'a Cell<RegType>, &'a Atom),
|
|
||||||
Clause(Level, &'a Cell<RegType>, &'a Atom, &'a Vec<Box<Term>>),
|
|
||||||
Var(Level, &'a Cell<VarReg>, &'a Var)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub enum FactInstruction {
|
|
||||||
GetStructure(Level, Atom, usize, RegType),
|
|
||||||
GetValue(RegType, usize),
|
|
||||||
GetVariable(RegType, usize),
|
|
||||||
UnifyVariable(RegType),
|
|
||||||
UnifyValue(RegType)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub enum QueryInstruction {
|
|
||||||
PutStructure(Level, Atom, usize, RegType),
|
|
||||||
PutValue(RegType, usize),
|
|
||||||
PutVariable(RegType, usize),
|
|
||||||
SetVariable(RegType),
|
|
||||||
SetValue(RegType)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub enum ControlInstruction {
|
|
||||||
Allocate(usize),
|
|
||||||
Call(Atom, usize),
|
|
||||||
Deallocate,
|
|
||||||
Proceed
|
|
||||||
}
|
|
||||||
|
|
||||||
pub type CompiledFact = Vec<FactInstruction>;
|
|
||||||
|
|
||||||
pub type CompiledQuery = Vec<QueryInstruction>;
|
|
||||||
|
|
||||||
pub enum Line {
|
|
||||||
Control(ControlInstruction),
|
|
||||||
Fact(CompiledFact),
|
|
||||||
Query(CompiledQuery)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub type Code = Vec<Line>;
|
|
||||||
|
|
||||||
#[derive(Clone, Copy, PartialEq)]
|
|
||||||
pub enum Addr {
|
|
||||||
HeapCell(usize),
|
|
||||||
RegNum(usize),
|
|
||||||
StackCell(usize),
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, PartialEq)]
|
|
||||||
pub enum HeapCellValue {
|
|
||||||
NamedStr(usize, Atom),
|
|
||||||
Ref(usize),
|
|
||||||
Str(usize)
|
|
||||||
}
|
|
||||||
|
|
||||||
impl HeapCellValue {
|
|
||||||
pub fn as_ref(&self, focus: usize) -> HeapCellRef {
|
|
||||||
match self {
|
|
||||||
&HeapCellValue::Ref(r) => HeapCellRef::Ref(r),
|
|
||||||
&HeapCellValue::Str(s) => HeapCellRef::Str(s),
|
|
||||||
&HeapCellValue::NamedStr(_, _) => HeapCellRef::Str(focus)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Copy, Clone)]
|
|
||||||
pub enum HeapCellRef {
|
|
||||||
Ref(usize),
|
|
||||||
Str(usize)
|
|
||||||
}
|
|
||||||
|
|
||||||
impl HeapCellRef {
|
|
||||||
pub fn heap_offset(&self) -> usize {
|
|
||||||
match self {
|
|
||||||
&HeapCellRef::Ref(r) | &HeapCellRef::Str(r) => r
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<HeapCellRef> for HeapCellValue {
|
|
||||||
fn from(hcr: HeapCellRef) -> HeapCellValue {
|
|
||||||
match hcr {
|
|
||||||
HeapCellRef::Ref(r) => HeapCellValue::Ref(r),
|
|
||||||
HeapCellRef::Str(s) => HeapCellValue::Str(s)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
|
||||||
pub enum CodePtr {
|
|
||||||
DirEntry(usize),
|
|
||||||
TopLevel
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Add<usize> for CodePtr {
|
|
||||||
type Output = CodePtr;
|
|
||||||
fn add(self, rhs: usize) -> Self::Output {
|
|
||||||
match self {
|
|
||||||
CodePtr::DirEntry(p) => CodePtr::DirEntry(p + rhs),
|
|
||||||
CodePtr::TopLevel => CodePtr::TopLevel
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl AddAssign<usize> for CodePtr {
|
|
||||||
fn add_assign(&mut self, rhs: usize) {
|
|
||||||
match self {
|
|
||||||
&mut CodePtr::DirEntry(ref mut p) => *p += rhs,
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub type Heap = Vec<HeapCellValue>;
|
|
||||||
|
|
||||||
pub type Registers = Vec<HeapCellRef>;
|
|
||||||
|
|
||||||
impl Term {
|
|
||||||
pub fn subterms(&self) -> usize {
|
|
||||||
match self {
|
|
||||||
&Term::Clause(_, _, ref terms) => terms.len(),
|
|
||||||
_ => 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn name(&self) -> &Atom {
|
|
||||||
match self {
|
|
||||||
&Term::Atom(_, ref atom)
|
|
||||||
| &Term::Var(_, ref atom)
|
|
||||||
| &Term::Clause(_, ref atom, _) => atom
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn arity(&self) -> usize {
|
|
||||||
match self {
|
|
||||||
&Term::Atom(_, _) | &Term::Var(_, _) => 0,
|
|
||||||
&Term::Clause(_, _, ref child_terms) => child_terms.len()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,469 +0,0 @@
|
|||||||
use l2::ast::*;
|
|
||||||
use l2::iterators::{FactIterator, QueryIterator};
|
|
||||||
|
|
||||||
use std::cell::Cell;
|
|
||||||
use std::cmp::max;
|
|
||||||
use std::collections::HashMap;
|
|
||||||
use std::fmt;
|
|
||||||
use std::vec::Vec;
|
|
||||||
|
|
||||||
impl fmt::Display for FactInstruction {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
match self {
|
|
||||||
&FactInstruction::GetStructure(Level::Deep, ref name, ref arity, ref r) =>
|
|
||||||
write!(f, "get_structure {}/{}, {}", name, arity, r),
|
|
||||||
&FactInstruction::GetStructure(Level::Shallow, ref name, ref arity, ref r) =>
|
|
||||||
write!(f, "get_structure {}/{}, A{}", name, arity, r.reg_num()),
|
|
||||||
&FactInstruction::GetValue(ref x, ref a) =>
|
|
||||||
write!(f, "get_value {}, A{}", x, a),
|
|
||||||
&FactInstruction::GetVariable(ref x, ref a) =>
|
|
||||||
write!(f, "get_variable {}, A{}", x, a),
|
|
||||||
&FactInstruction::UnifyVariable(ref r) =>
|
|
||||||
write!(f, "unify_variable {}", r),
|
|
||||||
&FactInstruction::UnifyValue(ref r) =>
|
|
||||||
write!(f, "unify_value {}", r)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Display for QueryInstruction {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
match self {
|
|
||||||
&QueryInstruction::PutStructure(Level::Deep, ref name, ref arity, ref r) =>
|
|
||||||
write!(f, "put_structure {}/{}, A{}", name, arity, r.reg_num()),
|
|
||||||
&QueryInstruction::PutStructure(Level::Shallow, ref name, ref arity, ref r) =>
|
|
||||||
write!(f, "put_structure {}/{}, {}", name, arity, r),
|
|
||||||
&QueryInstruction::PutValue(ref x, ref a) =>
|
|
||||||
write!(f, "put_value {}, A{}", x, a),
|
|
||||||
&QueryInstruction::PutVariable(ref x, ref a) =>
|
|
||||||
write!(f, "put_variable {}, A{}", x, a),
|
|
||||||
&QueryInstruction::SetVariable(ref r) =>
|
|
||||||
write!(f, "set_variable {}", r),
|
|
||||||
&QueryInstruction::SetValue(ref r) =>
|
|
||||||
write!(f, "set_value {}", r),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Display for ControlInstruction {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
match self {
|
|
||||||
&ControlInstruction::Allocate(num_cells) =>
|
|
||||||
write!(f, "allocate {}", num_cells),
|
|
||||||
&ControlInstruction::Call(ref name, ref arity) =>
|
|
||||||
write!(f, "call {}/{}", name, arity),
|
|
||||||
&ControlInstruction::Deallocate =>
|
|
||||||
write!(f, "deallocate"),
|
|
||||||
&ControlInstruction::Proceed =>
|
|
||||||
write!(f, "proceed")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
trait CompilationTarget<'a> {
|
|
||||||
type Iterator : Iterator<Item=TermRef<'a>>;
|
|
||||||
|
|
||||||
fn iter(&'a Term) -> Self::Iterator;
|
|
||||||
|
|
||||||
fn to_structure(Level, Atom, usize, RegType) -> Self;
|
|
||||||
|
|
||||||
fn argument_to_variable(RegType, usize) -> Self;
|
|
||||||
fn argument_to_value(RegType, usize) -> Self;
|
|
||||||
fn subterm_to_variable(RegType) -> Self;
|
|
||||||
fn subterm_to_value(RegType) -> Self;
|
|
||||||
|
|
||||||
fn clause_arg_to_instr(RegType) -> Self;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> CompilationTarget<'a> for FactInstruction {
|
|
||||||
type Iterator = FactIterator<'a>;
|
|
||||||
|
|
||||||
fn iter(term: &'a Term) -> Self::Iterator {
|
|
||||||
term.breadth_first_iter()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn to_structure(lvl: Level, atom: Atom, arity: usize, reg: RegType) -> Self {
|
|
||||||
FactInstruction::GetStructure(lvl, atom, arity, reg)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn argument_to_variable(arg: RegType, val: usize) -> Self {
|
|
||||||
FactInstruction::GetVariable(arg, val)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn argument_to_value(arg: RegType, val: usize) -> Self {
|
|
||||||
FactInstruction::GetValue(arg, val)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn subterm_to_variable(val: RegType) -> Self {
|
|
||||||
FactInstruction::UnifyVariable(val)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn subterm_to_value(val: RegType) -> Self {
|
|
||||||
FactInstruction::UnifyValue(val)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn clause_arg_to_instr(val: RegType) -> Self {
|
|
||||||
FactInstruction::UnifyVariable(val)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> CompilationTarget<'a> for QueryInstruction {
|
|
||||||
type Iterator = QueryIterator<'a>;
|
|
||||||
|
|
||||||
fn iter(term: &'a Term) -> Self::Iterator {
|
|
||||||
term.post_order_iter()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn to_structure(lvl: Level, atom: Atom, arity: usize, reg: RegType) -> Self {
|
|
||||||
QueryInstruction::PutStructure(lvl, atom, arity, reg)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn argument_to_variable(arg: RegType, val: usize) -> Self {
|
|
||||||
QueryInstruction::PutVariable(arg, val)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn argument_to_value(arg: RegType, val: usize) -> Self {
|
|
||||||
QueryInstruction::PutValue(arg, val)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn subterm_to_variable(val: RegType) -> Self {
|
|
||||||
QueryInstruction::SetVariable(val)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn subterm_to_value(val: RegType) -> Self {
|
|
||||||
QueryInstruction::SetValue(val)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn clause_arg_to_instr(val: RegType) -> Self {
|
|
||||||
QueryInstruction::SetValue(val)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct TermMarker<'a> {
|
|
||||||
bindings: HashMap<&'a Var, VarReg>,
|
|
||||||
arg_c: usize,
|
|
||||||
perm_c: usize,
|
|
||||||
temp_c: usize
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> TermMarker<'a> {
|
|
||||||
fn new() -> TermMarker<'a> {
|
|
||||||
TermMarker { bindings: HashMap::new(),
|
|
||||||
arg_c: 1,
|
|
||||||
perm_c: 1,
|
|
||||||
temp_c: 1 }
|
|
||||||
}
|
|
||||||
|
|
||||||
fn contains_var(&self, var: &'a Var) -> bool {
|
|
||||||
self.bindings.contains_key(var)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get(&self, var: &'a Var) -> VarReg {
|
|
||||||
*self.bindings.get(var).unwrap()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn insert(&mut self, var: &'a Var, r: VarReg) {
|
|
||||||
self.bindings.insert(var, r);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn mark_non_var(&mut self, lvl: Level, cell: &Cell<RegType>) {
|
|
||||||
let reg_type = cell.get();
|
|
||||||
|
|
||||||
if reg_type.reg_num() == 0 {
|
|
||||||
match lvl {
|
|
||||||
Level::Deep if reg_type.is_perm() => {
|
|
||||||
let perm = self.perm_c;
|
|
||||||
self.perm_c += 1;
|
|
||||||
cell.set(RegType::Perm(perm));
|
|
||||||
},
|
|
||||||
Level::Deep => {
|
|
||||||
let temp = self.temp_c;
|
|
||||||
self.temp_c += 1;
|
|
||||||
cell.set(RegType::Temp(temp));
|
|
||||||
},
|
|
||||||
Level::Shallow if reg_type.is_perm() => {
|
|
||||||
let arg = self.arg_c;
|
|
||||||
self.arg_c += 1;
|
|
||||||
cell.set(RegType::Perm(arg));
|
|
||||||
},
|
|
||||||
Level::Shallow => {
|
|
||||||
let arg = self.arg_c;
|
|
||||||
self.arg_c += 1;
|
|
||||||
cell.set(RegType::Temp(arg));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn mark_old_var(&mut self, lvl: Level, var: &'a Var) -> VarReg
|
|
||||||
{
|
|
||||||
let reg = self.get(var);
|
|
||||||
|
|
||||||
match lvl {
|
|
||||||
Level::Deep => VarReg::Norm(reg.norm()),
|
|
||||||
Level::Shallow => {
|
|
||||||
let reg = VarReg::ArgAndNorm(reg.norm(), self.arg_c);
|
|
||||||
|
|
||||||
self.arg_c += 1;
|
|
||||||
self.insert(var, reg);
|
|
||||||
|
|
||||||
reg
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn mark_new_var(&mut self, lvl: Level, var: &'a Var, reg: RegType) -> VarReg
|
|
||||||
{
|
|
||||||
let inner_reg = if reg.is_perm() {
|
|
||||||
let perm = self.perm_c;
|
|
||||||
self.perm_c += 1;
|
|
||||||
RegType::Perm(perm)
|
|
||||||
} else {
|
|
||||||
let temp = self.temp_c;
|
|
||||||
self.temp_c += 1;
|
|
||||||
RegType::Temp(temp)
|
|
||||||
};
|
|
||||||
|
|
||||||
let reg = match lvl {
|
|
||||||
Level::Deep => VarReg::Norm(inner_reg),
|
|
||||||
Level::Shallow => {
|
|
||||||
let reg = VarReg::ArgAndNorm(inner_reg, self.arg_c);
|
|
||||||
self.arg_c += 1;
|
|
||||||
reg
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
self.insert(var, reg);
|
|
||||||
reg
|
|
||||||
}
|
|
||||||
|
|
||||||
fn advance_at_header(&mut self, term: &'a Term) {
|
|
||||||
self.arg_c = 1;
|
|
||||||
self.temp_c = max(term.subterms(), self.temp_c) + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn advance(&mut self, term: &'a Term) {
|
|
||||||
self.arg_c = 1;
|
|
||||||
self.temp_c = term.subterms() + 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Copy, Clone)]
|
|
||||||
enum TermStatus {
|
|
||||||
New, Old, Recurrent
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct CodeGenerator<'a> {
|
|
||||||
marker: TermMarker<'a>
|
|
||||||
}
|
|
||||||
|
|
||||||
type VariableFixture<'a> = (TermStatus, Vec<&'a Cell<VarReg>>);
|
|
||||||
type VariableFixtures<'a> = HashMap<&'a Var, VariableFixture<'a>>;
|
|
||||||
|
|
||||||
impl<'a> CodeGenerator<'a> {
|
|
||||||
pub fn new() -> Self {
|
|
||||||
CodeGenerator { marker: TermMarker::new() }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn vars(&self) -> &HashMap<&Var, VarReg> {
|
|
||||||
&self.marker.bindings
|
|
||||||
}
|
|
||||||
|
|
||||||
fn to_structure<Target>(&mut self,
|
|
||||||
lvl: Level,
|
|
||||||
name: &'a Atom,
|
|
||||||
cell: &'a Cell<RegType>,
|
|
||||||
arity: usize)
|
|
||||||
-> Target
|
|
||||||
where Target: CompilationTarget<'a>
|
|
||||||
{
|
|
||||||
self.marker.mark_non_var(lvl, cell);
|
|
||||||
Target::to_structure(lvl, name.clone(), arity, cell.get())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn var_term<Target>(&mut self,
|
|
||||||
lvl: Level,
|
|
||||||
cell: &'a Cell<VarReg>,
|
|
||||||
var: &'a Var)
|
|
||||||
-> Target
|
|
||||||
where Target: CompilationTarget<'a>
|
|
||||||
{
|
|
||||||
if !self.marker.contains_var(var) {
|
|
||||||
let reg = self.marker.mark_new_var(lvl, var, cell.get().norm());
|
|
||||||
cell.set(reg);
|
|
||||||
|
|
||||||
match reg {
|
|
||||||
VarReg::ArgAndNorm(arg, norm) =>
|
|
||||||
Target::argument_to_variable(arg, norm),
|
|
||||||
VarReg::Norm(norm) =>
|
|
||||||
Target::subterm_to_variable(norm)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
let reg = self.marker.mark_old_var(lvl, var);
|
|
||||||
cell.set(reg);
|
|
||||||
|
|
||||||
match reg {
|
|
||||||
VarReg::ArgAndNorm(arg, norm) =>
|
|
||||||
Target::argument_to_value(arg, norm),
|
|
||||||
VarReg::Norm(norm) =>
|
|
||||||
Target::subterm_to_value(norm)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn non_var_subterm<Target>(&mut self, cell: &'a Cell<RegType>) -> Target
|
|
||||||
where Target: CompilationTarget<'a>
|
|
||||||
{
|
|
||||||
self.marker.mark_non_var(Level::Deep, cell);
|
|
||||||
Target::clause_arg_to_instr(cell.get())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn subterm_to_instr<Target>(&mut self, subterm: &'a Term) -> Target
|
|
||||||
where Target: CompilationTarget<'a>
|
|
||||||
{
|
|
||||||
match subterm {
|
|
||||||
&Term::Atom(ref cell, _) | &Term::Clause(ref cell, _, _) =>
|
|
||||||
self.non_var_subterm(cell),
|
|
||||||
&Term::Var(ref cell, ref var) =>
|
|
||||||
self.var_term(Level::Deep, cell, var)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn compile_target<Target>(&mut self, term: &'a Term) -> Vec<Target>
|
|
||||||
where Target: CompilationTarget<'a>
|
|
||||||
{
|
|
||||||
let iter = Target::iter(term);
|
|
||||||
let mut target = Vec::new();
|
|
||||||
|
|
||||||
for term in iter {
|
|
||||||
match term {
|
|
||||||
TermRef::Atom(lvl, term, atom) =>
|
|
||||||
target.push(self.to_structure(lvl, atom, term, 0)),
|
|
||||||
TermRef::Clause(lvl, term, atom, terms) => {
|
|
||||||
target.push(self.to_structure(lvl, atom, term, terms.len()));
|
|
||||||
|
|
||||||
for subterm in terms {
|
|
||||||
target.push(self.subterm_to_instr(subterm.as_ref()));
|
|
||||||
}
|
|
||||||
},
|
|
||||||
TermRef::Var(lvl @ Level::Shallow, ref cell, ref var) =>
|
|
||||||
target.push(self.var_term(lvl, cell, var)),
|
|
||||||
_ => {}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
target
|
|
||||||
}
|
|
||||||
|
|
||||||
fn mark_vars_in_term<Iter>(iter: Iter, vs: &mut VariableFixtures<'a>)
|
|
||||||
where Iter : Iterator<Item=TermRef<'a>>
|
|
||||||
{
|
|
||||||
for term in iter {
|
|
||||||
if let TermRef::Var(_, reg_cell, var) = term {
|
|
||||||
let mut status = vs.entry(var)
|
|
||||||
.or_insert((TermStatus::New, Vec::new()));
|
|
||||||
|
|
||||||
status.1.push(reg_cell);
|
|
||||||
|
|
||||||
match status.0 {
|
|
||||||
TermStatus::Old => status.0 = TermStatus::Recurrent,
|
|
||||||
_ => {}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for &mut (ref mut term_status, ref mut cb) in vs.values_mut() {
|
|
||||||
match *term_status {
|
|
||||||
TermStatus::New => *term_status = TermStatus::Old,
|
|
||||||
TermStatus::Recurrent => {
|
|
||||||
for cell_reg in cb.drain(0..) {
|
|
||||||
cell_reg.set(VarReg::Norm(RegType::Perm(0)));
|
|
||||||
}
|
|
||||||
},
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn mark_perm_vars(rule: &'a Rule) -> VariableFixtures {
|
|
||||||
let &Rule { head: (ref p0, ref p1), ref clauses } = rule;
|
|
||||||
let mut vfs = HashMap::new();
|
|
||||||
|
|
||||||
let iter = p0.breadth_first_iter().chain(p1.breadth_first_iter());
|
|
||||||
|
|
||||||
Self::mark_vars_in_term(iter, &mut vfs);
|
|
||||||
|
|
||||||
for term in clauses {
|
|
||||||
Self::mark_vars_in_term(term.breadth_first_iter(), &mut vfs);
|
|
||||||
}
|
|
||||||
|
|
||||||
vfs
|
|
||||||
}
|
|
||||||
|
|
||||||
fn add_conditional_call(compiled_query: &mut Code, term: &Term) {
|
|
||||||
match term {
|
|
||||||
&Term::Atom(_, ref atom) => {
|
|
||||||
let call = ControlInstruction::Call(atom.clone(), 0);
|
|
||||||
compiled_query.push(Line::Control(call));
|
|
||||||
},
|
|
||||||
&Term::Clause(_, ref atom, ref terms) => {
|
|
||||||
let call = ControlInstruction::Call(atom.clone(), terms.len());
|
|
||||||
compiled_query.push(Line::Control(call));
|
|
||||||
},
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn compile_rule(&mut self, rule: &'a Rule) -> Code {
|
|
||||||
let vfs = Self::mark_perm_vars(&rule);
|
|
||||||
let &Rule { head: (ref p0, ref p1), ref clauses } = rule;
|
|
||||||
let mut perm_vars = 0;
|
|
||||||
|
|
||||||
for &(term_status, _) in vfs.values() {
|
|
||||||
if let TermStatus::Recurrent = term_status {
|
|
||||||
perm_vars += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut body = Vec::new();
|
|
||||||
|
|
||||||
body.push(Line::Control(ControlInstruction::Allocate(perm_vars)));
|
|
||||||
|
|
||||||
self.marker.advance(p0);
|
|
||||||
body.push(Line::Fact(self.compile_target(p0)));
|
|
||||||
|
|
||||||
self.marker.advance_at_header(p1);
|
|
||||||
body.push(Line::Query(self.compile_target(p1)));
|
|
||||||
Self::add_conditional_call(&mut body, p1);
|
|
||||||
|
|
||||||
body = clauses.iter()
|
|
||||||
.map(|ref term| self.compile_query(term))
|
|
||||||
.fold(body, |mut body, ref mut cqs| {
|
|
||||||
body.append(cqs);
|
|
||||||
body
|
|
||||||
});
|
|
||||||
|
|
||||||
body.push(Line::Control(ControlInstruction::Deallocate));
|
|
||||||
|
|
||||||
body
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn compile_fact(&mut self, term: &'a Term) -> Code {
|
|
||||||
self.marker.advance(term);
|
|
||||||
|
|
||||||
let mut compiled_fact = vec![Line::Fact(self.compile_target(term))];
|
|
||||||
let proceed = Line::Control(ControlInstruction::Proceed);
|
|
||||||
|
|
||||||
compiled_fact.push(proceed);
|
|
||||||
compiled_fact
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn compile_query(&mut self, term: &'a Term) -> Code {
|
|
||||||
self.marker.advance(term);
|
|
||||||
|
|
||||||
let mut compiled_query = vec![Line::Query(self.compile_target(term))];
|
|
||||||
Self::add_conditional_call(&mut compiled_query, term);
|
|
||||||
|
|
||||||
compiled_query
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,64 +0,0 @@
|
|||||||
use l2::ast::*;
|
|
||||||
|
|
||||||
use std::vec::Vec;
|
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
|
||||||
pub enum HeapCellView<'a> {
|
|
||||||
Str(usize, &'a Atom),
|
|
||||||
Var(usize)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct HeapCellViewer<'a> {
|
|
||||||
heap: &'a Heap,
|
|
||||||
state_stack: Vec<(usize, &'a HeapCellValue)>
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> HeapCellViewer<'a> {
|
|
||||||
pub fn new(heap: &'a Heap, focus: usize) -> Self {
|
|
||||||
HeapCellViewer {
|
|
||||||
heap: heap,
|
|
||||||
state_stack: vec![(focus, &heap[focus])]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn follow(&self, value: &'a HeapCellValue) -> &'a HeapCellValue {
|
|
||||||
match value {
|
|
||||||
&HeapCellValue::NamedStr(_, _) => value,
|
|
||||||
&HeapCellValue::Ref(cell_num) | &HeapCellValue::Str(cell_num) =>
|
|
||||||
&self.heap[cell_num],
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Iterator for HeapCellViewer<'a> {
|
|
||||||
type Item = HeapCellView<'a>;
|
|
||||||
|
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
|
||||||
while let Some(hcv) = self.state_stack.pop() {
|
|
||||||
match hcv {
|
|
||||||
(focus, &HeapCellValue::NamedStr(arity, ref name)) => {
|
|
||||||
for i in (1 .. arity + 1).rev() {
|
|
||||||
self.state_stack.push((focus + i, &self.heap[focus + i]));
|
|
||||||
}
|
|
||||||
|
|
||||||
return Some(HeapCellView::Str(arity, name));
|
|
||||||
},
|
|
||||||
(_, &HeapCellValue::Ref(cell_num)) => {
|
|
||||||
let new_hcv = self.follow(hcv.1);
|
|
||||||
|
|
||||||
if hcv.1 == new_hcv {
|
|
||||||
return Some(HeapCellView::Var(cell_num));
|
|
||||||
} else {
|
|
||||||
self.state_stack.push((cell_num, new_hcv));
|
|
||||||
}
|
|
||||||
},
|
|
||||||
(_, &HeapCellValue::Str(cell_num)) => {
|
|
||||||
let new_hcv = self.follow(hcv.1);
|
|
||||||
self.state_stack.push((cell_num, new_hcv));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,175 +0,0 @@
|
|||||||
use l2::ast::*;
|
|
||||||
|
|
||||||
use std::cell::Cell;
|
|
||||||
use std::collections::VecDeque;
|
|
||||||
use std::vec::Vec;
|
|
||||||
|
|
||||||
enum IteratorState<'a> {
|
|
||||||
Atom(Level, &'a Cell<RegType>, &'a Atom),
|
|
||||||
Clause(Level, usize, &'a Cell<RegType>, &'a Atom, &'a Vec<Box<Term>>),
|
|
||||||
IsolatedAtom(&'a Cell<RegType>, &'a Atom),
|
|
||||||
IsolatedVar(&'a Cell<VarReg>, &'a Var),
|
|
||||||
RootClause(usize, &'a Vec<Box<Term>>),
|
|
||||||
Var(Level, &'a Cell<VarReg>, &'a Var)
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> IteratorState<'a> {
|
|
||||||
fn to_state(lvl: Level, term: &'a Term) -> IteratorState<'a>
|
|
||||||
{
|
|
||||||
match term {
|
|
||||||
&Term::Atom(ref cell, ref atom) =>
|
|
||||||
IteratorState::Atom(lvl, cell, atom),
|
|
||||||
&Term::Clause(ref cell, ref atom, ref child_terms) =>
|
|
||||||
IteratorState::Clause(lvl, 0, cell, atom, child_terms),
|
|
||||||
&Term::Var(ref cell, ref var) =>
|
|
||||||
IteratorState::Var(lvl, cell, var)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct QueryIterator<'a> {
|
|
||||||
state_stack: Vec<IteratorState<'a>>
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> QueryIterator<'a> {
|
|
||||||
fn push_clause(&mut self,
|
|
||||||
lvl: Level,
|
|
||||||
child_num: usize,
|
|
||||||
cell: &'a Cell<RegType>,
|
|
||||||
name: &'a Atom,
|
|
||||||
child_terms: &'a Vec<Box<Term>>)
|
|
||||||
{
|
|
||||||
self.state_stack.push(IteratorState::Clause(lvl,
|
|
||||||
child_num,
|
|
||||||
cell,
|
|
||||||
name,
|
|
||||||
child_terms));
|
|
||||||
}
|
|
||||||
|
|
||||||
fn push_root_clause(&mut self,
|
|
||||||
child_num: usize,
|
|
||||||
child_terms: &'a Vec<Box<Term>>)
|
|
||||||
{
|
|
||||||
self.state_stack.push(IteratorState::RootClause(child_num, child_terms));
|
|
||||||
}
|
|
||||||
|
|
||||||
fn push_subterm(&mut self, lvl: Level, term: &'a Term) {
|
|
||||||
self.state_stack.push(IteratorState::to_state(lvl, term));
|
|
||||||
}
|
|
||||||
|
|
||||||
fn new(term: &'a Term) -> QueryIterator<'a> {
|
|
||||||
let state = match term {
|
|
||||||
&Term::Atom(ref cell, ref atom) =>
|
|
||||||
IteratorState::IsolatedAtom(cell, atom),
|
|
||||||
&Term::Clause(_, _, ref terms) =>
|
|
||||||
IteratorState::RootClause(0, terms),
|
|
||||||
&Term::Var(ref cell, ref var) =>
|
|
||||||
IteratorState::IsolatedVar(cell, var)
|
|
||||||
};
|
|
||||||
|
|
||||||
QueryIterator { state_stack: vec![state] }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Iterator for QueryIterator<'a> {
|
|
||||||
type Item = TermRef<'a>;
|
|
||||||
|
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
|
||||||
while let Some(iter_state) = self.state_stack.pop() {
|
|
||||||
match iter_state {
|
|
||||||
IteratorState::Atom(lvl, cell, atom) =>
|
|
||||||
return Some(TermRef::Atom(lvl, cell, atom)),
|
|
||||||
IteratorState::Clause(lvl, child_num, cell, atom, child_terms) => {
|
|
||||||
if child_num == child_terms.len() {
|
|
||||||
return Some(TermRef::Clause(lvl, cell, atom, child_terms));
|
|
||||||
} else {
|
|
||||||
self.push_clause(lvl, child_num + 1, cell, atom, child_terms);
|
|
||||||
self.push_subterm(Level::Deep, child_terms[child_num].as_ref());
|
|
||||||
}
|
|
||||||
},
|
|
||||||
IteratorState::IsolatedAtom(cell, atom) =>
|
|
||||||
return Some(TermRef::Atom(Level::Shallow, cell, atom)),
|
|
||||||
IteratorState::IsolatedVar(cell, var) =>
|
|
||||||
return Some(TermRef::Var(Level::Shallow, cell, var)),
|
|
||||||
IteratorState::RootClause(child_num, child_terms) => {
|
|
||||||
if child_num == child_terms.len() {
|
|
||||||
return None;
|
|
||||||
} else {
|
|
||||||
self.push_root_clause(child_num + 1, child_terms);
|
|
||||||
self.push_subterm(Level::Shallow, child_terms[child_num].as_ref());
|
|
||||||
}
|
|
||||||
},
|
|
||||||
IteratorState::Var(lvl, cell, var) =>
|
|
||||||
return Some(TermRef::Var(lvl, cell, var))
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct FactIterator<'a> {
|
|
||||||
state_queue: VecDeque<IteratorState<'a>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> FactIterator<'a> {
|
|
||||||
fn push_subterm(&mut self, lvl: Level, term: &'a Term) {
|
|
||||||
self.state_queue.push_back(IteratorState::to_state(lvl, term));
|
|
||||||
}
|
|
||||||
|
|
||||||
fn new(term: &'a Term) -> FactIterator<'a> {
|
|
||||||
let states = match term {
|
|
||||||
&Term::Atom(ref cell, ref atom) =>
|
|
||||||
vec![IteratorState::IsolatedAtom(cell, atom)],
|
|
||||||
&Term::Clause(_, _, ref terms) =>
|
|
||||||
vec![IteratorState::RootClause(0, terms)],
|
|
||||||
&Term::Var(ref cell, ref var) =>
|
|
||||||
vec![IteratorState::IsolatedVar(cell, var)]
|
|
||||||
};
|
|
||||||
|
|
||||||
FactIterator { state_queue: VecDeque::from(states) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Iterator for FactIterator<'a> {
|
|
||||||
type Item = TermRef<'a>;
|
|
||||||
|
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
|
||||||
while let Some(state) = self.state_queue.pop_front() {
|
|
||||||
match state {
|
|
||||||
IteratorState::Atom(lvl, cell, atom) =>
|
|
||||||
return Some(TermRef::Atom(lvl, cell, atom)),
|
|
||||||
IteratorState::Clause(lvl, _, cell, atom, child_terms) => {
|
|
||||||
for child_term in child_terms {
|
|
||||||
self.push_subterm(Level::Deep, child_term);
|
|
||||||
}
|
|
||||||
|
|
||||||
return Some(TermRef::Clause(lvl, cell, atom, child_terms));
|
|
||||||
},
|
|
||||||
IteratorState::IsolatedAtom(cell, atom) =>
|
|
||||||
return Some(TermRef::Atom(Level::Shallow, cell, atom)),
|
|
||||||
IteratorState::IsolatedVar(cell, var) =>
|
|
||||||
return Some(TermRef::Var(Level::Shallow, cell, var)),
|
|
||||||
IteratorState::RootClause(_, child_terms) => {
|
|
||||||
for child_term in child_terms {
|
|
||||||
self.push_subterm(Level::Shallow, child_term);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
IteratorState::Var(lvl, cell, var) =>
|
|
||||||
return Some(TermRef::Var(lvl, cell, var))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Term {
|
|
||||||
pub fn post_order_iter(&self) -> QueryIterator {
|
|
||||||
QueryIterator::new(self)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn breadth_first_iter(&self) -> FactIterator {
|
|
||||||
FactIterator::new(self)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,45 +0,0 @@
|
|||||||
use l2::ast::*;
|
|
||||||
|
|
||||||
use std::cell::Cell;
|
|
||||||
|
|
||||||
grammar;
|
|
||||||
|
|
||||||
pub TopLevel: TopLevel = {
|
|
||||||
"?-" <t:Term> "." => TopLevel::Query(t),
|
|
||||||
<r:Rule> "." => TopLevel::Rule(r),
|
|
||||||
<t:Term> "." => TopLevel::Fact(t),
|
|
||||||
};
|
|
||||||
|
|
||||||
Atom : Atom = {
|
|
||||||
r"[a-z][a-z0-9_]*" => <>.trim().to_string(),
|
|
||||||
};
|
|
||||||
|
|
||||||
BoxedTerm : Box<Term> = {
|
|
||||||
<t:Term> => Box::new(t),
|
|
||||||
};
|
|
||||||
|
|
||||||
Clause : Term = {
|
|
||||||
<a:Atom> "(" <ts: (<BoxedTerm> ",")*> <t:BoxedTerm> ")" => {
|
|
||||||
let mut ts = ts;
|
|
||||||
ts.push(t);
|
|
||||||
Term::Clause(Cell::new(RegType::Temp(0)), a, ts)
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
Rule : Rule = {
|
|
||||||
<c:Clause> ":-" <h:Term> <cs: ("," <Term>)*> =>
|
|
||||||
Rule { head: (c, h), clauses: cs },
|
|
||||||
<a:Atom> ":-" <h:Term> <cs: ("," <Term>)*> =>
|
|
||||||
Rule { head: (Term::Atom(Cell::new(RegType::Temp(0)), a), h),
|
|
||||||
clauses: cs }
|
|
||||||
};
|
|
||||||
|
|
||||||
Term : Term = {
|
|
||||||
<Clause> => <>,
|
|
||||||
<Atom> => Term::Atom(Cell::new(RegType::Temp(0)), <>),
|
|
||||||
<Var> => Term::Var(Cell::new(VarReg::Norm(RegType::Temp(0))), <>),
|
|
||||||
};
|
|
||||||
|
|
||||||
Var : Var = {
|
|
||||||
r"[A-Z][a-z0-9_]*" => <>.trim().to_string(),
|
|
||||||
};
|
|
||||||
1883
src/l2/l2_parser.rs
1883
src/l2/l2_parser.rs
File diff suppressed because it is too large
Load Diff
@@ -1,456 +0,0 @@
|
|||||||
use l2::ast::*;
|
|
||||||
use l2::codegen::*;
|
|
||||||
use l2::heapview::*;
|
|
||||||
use l2::stack::*;
|
|
||||||
|
|
||||||
use std::collections::HashMap;
|
|
||||||
use std::vec::Vec;
|
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
|
||||||
enum MachineMode {
|
|
||||||
Read,
|
|
||||||
Write
|
|
||||||
}
|
|
||||||
|
|
||||||
struct MachineState {
|
|
||||||
h: usize,
|
|
||||||
s: usize,
|
|
||||||
p: CodePtr,
|
|
||||||
cp: CodePtr,
|
|
||||||
fail: bool,
|
|
||||||
heap: Heap,
|
|
||||||
mode: MachineMode,
|
|
||||||
stack: Stack,
|
|
||||||
registers: Registers
|
|
||||||
}
|
|
||||||
|
|
||||||
type CodeDir = HashMap<(Atom, usize), usize>;
|
|
||||||
|
|
||||||
pub struct Machine {
|
|
||||||
ms: MachineState,
|
|
||||||
code: Code,
|
|
||||||
code_dir: CodeDir
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Machine {
|
|
||||||
pub fn new() -> Self {
|
|
||||||
Machine {
|
|
||||||
ms: MachineState::new(),
|
|
||||||
code: Vec::new(),
|
|
||||||
code_dir: HashMap::new()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn failed(&self) -> bool {
|
|
||||||
self.ms.fail
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn add_fact(&mut self, fact: &Term, mut code: Code) {
|
|
||||||
let p = self.code.len();
|
|
||||||
let name = fact.name().clone();
|
|
||||||
let arity = fact.arity();
|
|
||||||
|
|
||||||
self.code.append(&mut code);
|
|
||||||
self.code_dir.insert((name, arity), p);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn add_rule(&mut self, rule: &Rule, mut code: Code) {
|
|
||||||
let p = self.code.len();
|
|
||||||
let name = rule.head.0.name().clone();
|
|
||||||
let arity = rule.head.0.arity();
|
|
||||||
|
|
||||||
self.code.append(&mut code);
|
|
||||||
self.code_dir.insert((name, arity), p);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn execute_instr(&mut self, instr: &Line) -> bool {
|
|
||||||
let mut instr = instr;
|
|
||||||
|
|
||||||
loop {
|
|
||||||
match instr {
|
|
||||||
&Line::Fact(ref fact) => {
|
|
||||||
for fact_instr in fact {
|
|
||||||
self.ms.execute_fact_instr(&fact_instr);
|
|
||||||
}
|
|
||||||
self.ms.p += 1;
|
|
||||||
},
|
|
||||||
&Line::Query(ref query) => {
|
|
||||||
for query_instr in query {
|
|
||||||
self.ms.execute_query_instr(&query_instr);
|
|
||||||
}
|
|
||||||
self.ms.p += 1;
|
|
||||||
},
|
|
||||||
&Line::Control(ref control_instr) =>
|
|
||||||
self.ms.execute_ctrl_instr(&self.code_dir, control_instr),
|
|
||||||
}
|
|
||||||
|
|
||||||
if self.failed() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
match self.ms.p {
|
|
||||||
CodePtr::DirEntry(p) if p < self.code.len() =>
|
|
||||||
instr = &self.code[p],
|
|
||||||
_ => break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
fn heap_view(&self, var_dir: HashMap<&Var, HeapCellRef>) -> String {
|
|
||||||
let mut result = String::new();
|
|
||||||
|
|
||||||
for (var, hcr) in var_dir {
|
|
||||||
let mut arities = Vec::new();
|
|
||||||
let viewer = HeapCellViewer::new(&self.ms.heap, hcr.heap_offset());
|
|
||||||
|
|
||||||
if result != "" {
|
|
||||||
result += "\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
result += var.as_str();
|
|
||||||
result += " = ";
|
|
||||||
|
|
||||||
for view in viewer {
|
|
||||||
match arities.pop() {
|
|
||||||
Some(n) => arities.push(n-1),
|
|
||||||
None => {}
|
|
||||||
}
|
|
||||||
|
|
||||||
if !(arities.is_empty() || result.ends_with("(")) {
|
|
||||||
result += ", ";
|
|
||||||
}
|
|
||||||
|
|
||||||
match view {
|
|
||||||
HeapCellView::Str(arity, ref name) => {
|
|
||||||
result += name.as_str();
|
|
||||||
|
|
||||||
if arity > 0 {
|
|
||||||
arities.push(arity);
|
|
||||||
result += "(";
|
|
||||||
}
|
|
||||||
},
|
|
||||||
HeapCellView::Var(cell_num) => {
|
|
||||||
result += "_";
|
|
||||||
result += cell_num.to_string().as_str();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
while let Some(&0) = arities.last() {
|
|
||||||
result += ")";
|
|
||||||
arities.pop();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
result
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn run_query(&mut self, code: Code, cg: &CodeGenerator) -> Option<String>
|
|
||||||
{
|
|
||||||
let mut succeeded = true;
|
|
||||||
|
|
||||||
for instr in code.iter().take(1) {
|
|
||||||
succeeded = self.execute_instr(&instr);
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut heap_locs = HashMap::new();
|
|
||||||
|
|
||||||
if succeeded {
|
|
||||||
for (var, vr) in cg.vars() {
|
|
||||||
let hcr = self.ms.registers[vr.root_register()];
|
|
||||||
heap_locs.insert(*var, hcr);
|
|
||||||
}
|
|
||||||
|
|
||||||
for instr in code.iter().skip(1) {
|
|
||||||
succeeded = self.execute_instr(&instr);
|
|
||||||
if !succeeded {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if succeeded {
|
|
||||||
Some(self.heap_view(heap_locs))
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn reset(&mut self) {
|
|
||||||
self.ms.reset();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl MachineState {
|
|
||||||
fn new() -> MachineState {
|
|
||||||
MachineState { h: 0,
|
|
||||||
s: 0,
|
|
||||||
p: CodePtr::TopLevel,
|
|
||||||
cp: CodePtr::TopLevel,
|
|
||||||
fail: false,
|
|
||||||
heap: Vec::with_capacity(256),
|
|
||||||
mode: MachineMode::Write,
|
|
||||||
stack: Stack::new(),
|
|
||||||
registers: vec![HeapCellRef::Ref(0); 32] }
|
|
||||||
}
|
|
||||||
|
|
||||||
fn register_mut(&mut self, r: RegType) -> &mut HeapCellRef {
|
|
||||||
match r {
|
|
||||||
RegType::Temp(r) => &mut self.registers[r],
|
|
||||||
RegType::Perm(r) => &mut self.stack[r]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn lookup(&self, a: Addr) -> HeapCellRef {
|
|
||||||
match a {
|
|
||||||
Addr::HeapCell(r) => self.heap[r].as_ref(r),
|
|
||||||
Addr::RegNum(r) => self.registers[r],
|
|
||||||
Addr::StackCell(s) => self.stack[s]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn deref(&self, a: Addr) -> Addr {
|
|
||||||
let mut a = a;
|
|
||||||
|
|
||||||
loop {
|
|
||||||
if let HeapCellRef::Ref(value) = self.lookup(a) {
|
|
||||||
if let Addr::HeapCell(av) = a {
|
|
||||||
if value != av {
|
|
||||||
a = Addr::HeapCell(value);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
a = Addr::HeapCell(value);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return a;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
fn is_unbound(hc: &HeapCellValue, index: usize) -> bool {
|
|
||||||
match hc {
|
|
||||||
&HeapCellValue::Ref(r) => r == index,
|
|
||||||
_ => false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn bind(&mut self, a: Addr, val: usize) {
|
|
||||||
let mut a = a;
|
|
||||||
|
|
||||||
loop {
|
|
||||||
match a {
|
|
||||||
addr @ Addr::RegNum(_) | addr @ Addr::StackCell(_) => {
|
|
||||||
if let HeapCellRef::Ref(hc) = self.lookup(addr) {
|
|
||||||
a = Addr::HeapCell(hc);
|
|
||||||
} else if Self::is_unbound(&self.heap[val], val) {
|
|
||||||
self.heap[val] = HeapCellValue::from(self.lookup(addr));
|
|
||||||
break;
|
|
||||||
} else {
|
|
||||||
self.fail = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
Addr::HeapCell(hc) => {
|
|
||||||
if Self::is_unbound(&self.heap[hc], hc) {
|
|
||||||
self.heap[hc] = HeapCellValue::Ref(val);
|
|
||||||
break;
|
|
||||||
} else if Self::is_unbound(&self.heap[val], val) {
|
|
||||||
self.heap[val] = HeapCellValue::Ref(hc);
|
|
||||||
break;
|
|
||||||
} else {
|
|
||||||
self.fail = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn unify(&mut self, a1: Addr, a2: Addr) {
|
|
||||||
let mut pdl = vec![a1, a2];
|
|
||||||
|
|
||||||
self.fail = false;
|
|
||||||
|
|
||||||
while !(pdl.is_empty() || self.fail) {
|
|
||||||
let d1 = self.deref(pdl.pop().unwrap());
|
|
||||||
let d2 = self.deref(pdl.pop().unwrap());
|
|
||||||
|
|
||||||
if d1 != d2 {
|
|
||||||
match (self.lookup(d1), self.lookup(d2)) {
|
|
||||||
(HeapCellRef::Ref(hc), _) =>
|
|
||||||
self.bind(d2, hc),
|
|
||||||
(_, HeapCellRef::Ref(hc)) =>
|
|
||||||
self.bind(d1, hc),
|
|
||||||
(HeapCellRef::Str(a1), HeapCellRef::Str(a2)) => {
|
|
||||||
let r1 = &self.heap[a1];
|
|
||||||
let r2 = &self.heap[a2];
|
|
||||||
|
|
||||||
if let &HeapCellValue::NamedStr(n1, ref f1) = r1 {
|
|
||||||
if let &HeapCellValue::NamedStr(n2, ref f2) = r2 {
|
|
||||||
if n1 == n2 && *f1 == *f2 {
|
|
||||||
for i in 1 .. n1 + 1 {
|
|
||||||
pdl.push(Addr::HeapCell(a1 + i));
|
|
||||||
pdl.push(Addr::HeapCell(a2 + i));
|
|
||||||
}
|
|
||||||
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
self.fail = true;
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn execute_query_instr(&mut self, instr: &QueryInstruction) {
|
|
||||||
match instr {
|
|
||||||
&QueryInstruction::PutStructure(_, ref name, arity, reg) => {
|
|
||||||
self.heap.push(HeapCellValue::Str(self.h + 1));
|
|
||||||
self.heap.push(HeapCellValue::NamedStr(arity, name.clone()));
|
|
||||||
|
|
||||||
*self.register_mut(reg) = HeapCellRef::Str(self.h + 1);
|
|
||||||
|
|
||||||
self.h += 2;
|
|
||||||
},
|
|
||||||
&QueryInstruction::PutValue(norm, arg) =>
|
|
||||||
self.registers[arg] = match norm {
|
|
||||||
RegType::Temp(reg) => self.registers[reg],
|
|
||||||
RegType::Perm(reg) => self.stack[reg]
|
|
||||||
},
|
|
||||||
&QueryInstruction::PutVariable(norm, arg) => {
|
|
||||||
self.heap.push(HeapCellValue::Ref(self.h));
|
|
||||||
|
|
||||||
*self.register_mut(norm) = HeapCellRef::Ref(self.h);
|
|
||||||
self.registers[arg] = HeapCellRef::Ref(self.h);
|
|
||||||
|
|
||||||
self.h += 1;
|
|
||||||
},
|
|
||||||
&QueryInstruction::SetVariable(reg) => {
|
|
||||||
self.heap.push(HeapCellValue::Ref(self.h));
|
|
||||||
*self.register_mut(reg) = HeapCellRef::Ref(self.h);
|
|
||||||
|
|
||||||
self.h += 1;
|
|
||||||
},
|
|
||||||
&QueryInstruction::SetValue(reg) => {
|
|
||||||
let heap_val = self.lookup(Addr::from(reg));
|
|
||||||
self.heap.push(HeapCellValue::from(heap_val));
|
|
||||||
|
|
||||||
self.h += 1;
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn execute_fact_instr(&mut self, instr: &FactInstruction) {
|
|
||||||
match instr {
|
|
||||||
&FactInstruction::GetStructure(_, ref name, arity, reg) => {
|
|
||||||
let addr = self.deref(Addr::from(reg));
|
|
||||||
|
|
||||||
match self.lookup(addr) {
|
|
||||||
HeapCellRef::Str(a) => {
|
|
||||||
let result = &self.heap[a];
|
|
||||||
|
|
||||||
if let &HeapCellValue::NamedStr(narity, ref str) = result {
|
|
||||||
if narity == arity && *name == *str {
|
|
||||||
self.s = a + 1;
|
|
||||||
self.mode = MachineMode::Read;
|
|
||||||
} else {
|
|
||||||
self.fail = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
HeapCellRef::Ref(_) => {
|
|
||||||
self.heap.push(HeapCellValue::Str(self.h + 1));
|
|
||||||
self.heap.push(HeapCellValue::NamedStr(arity, name.clone()));
|
|
||||||
|
|
||||||
let h = self.h;
|
|
||||||
|
|
||||||
self.bind(addr, h);
|
|
||||||
|
|
||||||
self.h += 2;
|
|
||||||
self.mode = MachineMode::Write;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
},
|
|
||||||
&FactInstruction::GetVariable(norm, arg) =>
|
|
||||||
*self.register_mut(norm) = self.registers[arg],
|
|
||||||
&FactInstruction::GetValue(norm, arg) =>
|
|
||||||
self.unify(Addr::from(norm), Addr::RegNum(arg)),
|
|
||||||
&FactInstruction::UnifyVariable(reg) => {
|
|
||||||
match self.mode {
|
|
||||||
MachineMode::Read =>
|
|
||||||
*self.register_mut(reg) = self.heap[self.s].as_ref(self.s),
|
|
||||||
MachineMode::Write => {
|
|
||||||
self.heap.push(HeapCellValue::Ref(self.h));
|
|
||||||
*self.register_mut(reg) = HeapCellRef::Ref(self.h);
|
|
||||||
self.h += 1;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
self.s += 1;
|
|
||||||
},
|
|
||||||
&FactInstruction::UnifyValue(reg) => {
|
|
||||||
let s = self.s;
|
|
||||||
|
|
||||||
match self.mode {
|
|
||||||
MachineMode::Read =>
|
|
||||||
self.unify(Addr::from(reg), Addr::HeapCell(s)),
|
|
||||||
MachineMode::Write => {
|
|
||||||
let heap_val = self.lookup(Addr::from(reg));
|
|
||||||
self.heap.push(HeapCellValue::from(heap_val));
|
|
||||||
self.h += 1;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
self.s += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn execute_ctrl_instr(&mut self, code_dir: &CodeDir, instr: &ControlInstruction)
|
|
||||||
{
|
|
||||||
match instr {
|
|
||||||
&ControlInstruction::Allocate(num_cells) => {
|
|
||||||
self.stack.push(self.cp, num_cells);
|
|
||||||
self.p += 1;
|
|
||||||
},
|
|
||||||
&ControlInstruction::Call(ref name, arity) => {
|
|
||||||
let compiled_tl_index = code_dir.get(&(name.clone(), arity))
|
|
||||||
.map(|index| *index);
|
|
||||||
|
|
||||||
match compiled_tl_index {
|
|
||||||
Some(compiled_tl_index) => {
|
|
||||||
self.cp = self.p + 1;
|
|
||||||
self.p = CodePtr::DirEntry(compiled_tl_index);
|
|
||||||
},
|
|
||||||
None => self.fail = true
|
|
||||||
};
|
|
||||||
},
|
|
||||||
&ControlInstruction::Deallocate => {
|
|
||||||
self.p = self.stack.get_cp();
|
|
||||||
self.stack.pop();
|
|
||||||
},
|
|
||||||
&ControlInstruction::Proceed =>
|
|
||||||
self.p = self.cp,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
fn reset(&mut self) {
|
|
||||||
self.h = 0;
|
|
||||||
self.s = 0;
|
|
||||||
self.p = CodePtr::TopLevel;
|
|
||||||
self.cp = CodePtr::TopLevel;
|
|
||||||
|
|
||||||
self.fail = false;
|
|
||||||
self.heap.clear();
|
|
||||||
self.mode = MachineMode::Write;
|
|
||||||
self.stack = Stack::new();
|
|
||||||
self.registers = vec![HeapCellRef::Ref(0); 32];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
pub mod ast;
|
|
||||||
pub mod heapview;
|
|
||||||
pub mod iterators;
|
|
||||||
pub mod l2_parser;
|
|
||||||
pub mod codegen;
|
|
||||||
pub mod machine;
|
|
||||||
pub mod stack;
|
|
||||||
@@ -1,60 +0,0 @@
|
|||||||
use l2::ast::*;
|
|
||||||
|
|
||||||
use std::ops::{Index, IndexMut};
|
|
||||||
use std::vec::Vec;
|
|
||||||
|
|
||||||
struct Frame {
|
|
||||||
cp: CodePtr,
|
|
||||||
perms: Vec<HeapCellRef>
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Frame {
|
|
||||||
fn new(cp: CodePtr, n: usize) -> Self {
|
|
||||||
Frame {
|
|
||||||
cp: cp,
|
|
||||||
perms: vec![HeapCellRef::Ref(0); n]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn read_pv(&self, i: usize) -> &HeapCellRef {
|
|
||||||
self.perms.index(i)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn read_pv_mut(&mut self, i: usize) -> &mut HeapCellRef {
|
|
||||||
self.perms.index_mut(i)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Stack(Vec<Frame>);
|
|
||||||
|
|
||||||
impl Stack {
|
|
||||||
pub fn new() -> Self {
|
|
||||||
Stack(Vec::new())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn push(&mut self, cp: CodePtr, n: usize) {
|
|
||||||
self.0.push(Frame::new(cp, n));
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_cp(&self) -> CodePtr {
|
|
||||||
self.0.last().unwrap().cp
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn pop(&mut self) {
|
|
||||||
self.0.pop();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Index<usize> for Stack {
|
|
||||||
type Output = HeapCellRef;
|
|
||||||
|
|
||||||
fn index(&self, index: usize) -> &Self::Output {
|
|
||||||
self.0.last().unwrap().read_pv(index - 1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl IndexMut<usize> for Stack {
|
|
||||||
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
|
|
||||||
self.0.last_mut().unwrap().read_pv_mut(index - 1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,80 +0,0 @@
|
|||||||
use l3::ast::*;
|
|
||||||
|
|
||||||
use std::ops::{Index, IndexMut};
|
|
||||||
use std::vec::Vec;
|
|
||||||
|
|
||||||
pub struct Frame {
|
|
||||||
pub global_index: usize,
|
|
||||||
pub e: usize,
|
|
||||||
pub cp: CodePtr,
|
|
||||||
perms: Vec<Addr>
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Frame {
|
|
||||||
fn new(global_index: usize, e: usize, cp: CodePtr, n: usize) -> Self {
|
|
||||||
Frame {
|
|
||||||
global_index: global_index,
|
|
||||||
e: e,
|
|
||||||
cp: cp,
|
|
||||||
perms: vec![Addr::HeapCell(0); n]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct AndStack(Vec<Frame>);
|
|
||||||
|
|
||||||
impl AndStack {
|
|
||||||
pub fn new() -> Self {
|
|
||||||
AndStack(Vec::new())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn push(&mut self, global_index: usize, e: usize, cp: CodePtr, n: usize) {
|
|
||||||
self.0.push(Frame::new(global_index, e, cp, n));
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn top(&self) -> Option<&Frame> {
|
|
||||||
self.0.last()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn len(&self) -> usize {
|
|
||||||
self.0.len()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn clear(&mut self) {
|
|
||||||
self.0.clear()
|
|
||||||
}
|
|
||||||
|
|
||||||
// drop the last n frames.
|
|
||||||
pub fn drop_frames(&mut self, n: usize) {
|
|
||||||
let len = self.0.len();
|
|
||||||
self.0.truncate(len - n);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Index<usize> for AndStack {
|
|
||||||
type Output = Frame;
|
|
||||||
|
|
||||||
fn index(&self, index: usize) -> &Self::Output {
|
|
||||||
self.0.index(index)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl IndexMut<usize> for AndStack {
|
|
||||||
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
|
|
||||||
self.0.index_mut(index)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Index<usize> for Frame {
|
|
||||||
type Output = Addr;
|
|
||||||
|
|
||||||
fn index(&self, index: usize) -> &Self::Output {
|
|
||||||
self.perms.index(index - 1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl IndexMut<usize> for Frame {
|
|
||||||
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
|
|
||||||
self.perms.index_mut(index - 1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
303
src/l3/ast.rs
303
src/l3/ast.rs
@@ -1,303 +0,0 @@
|
|||||||
use std::cell::Cell;
|
|
||||||
use std::collections::HashMap;
|
|
||||||
use std::ops::{Add, AddAssign};
|
|
||||||
use std::vec::Vec;
|
|
||||||
|
|
||||||
pub type Var = String;
|
|
||||||
|
|
||||||
pub type Atom = String;
|
|
||||||
|
|
||||||
pub enum PredicateClause {
|
|
||||||
Fact(Term),
|
|
||||||
Rule(Rule)
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PredicateClause {
|
|
||||||
pub fn name(&self) -> &Atom {
|
|
||||||
match self {
|
|
||||||
&PredicateClause::Fact(ref t) => t.name(),
|
|
||||||
&PredicateClause::Rule(ref rule) => rule.head.0.name()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn arity(&self) -> usize {
|
|
||||||
match self {
|
|
||||||
&PredicateClause::Fact(ref t) => t.arity(),
|
|
||||||
&PredicateClause::Rule(ref rule) => rule.head.0.arity()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub enum TopLevel {
|
|
||||||
Fact(Term),
|
|
||||||
Predicate(Vec<PredicateClause>),
|
|
||||||
Query(Term),
|
|
||||||
Rule(Rule)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
|
||||||
pub enum Level {
|
|
||||||
Deep, Shallow
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
|
||||||
pub enum RegType {
|
|
||||||
Perm(usize),
|
|
||||||
Temp(usize)
|
|
||||||
}
|
|
||||||
|
|
||||||
impl RegType {
|
|
||||||
pub fn reg_num(self) -> usize {
|
|
||||||
match self {
|
|
||||||
RegType::Perm(reg_num) | RegType::Temp(reg_num) => reg_num
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn is_perm(self) -> bool {
|
|
||||||
match self {
|
|
||||||
RegType::Perm(_) => true,
|
|
||||||
_ => false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
|
||||||
pub enum VarReg {
|
|
||||||
ArgAndNorm(RegType, usize),
|
|
||||||
Norm(RegType)
|
|
||||||
}
|
|
||||||
|
|
||||||
impl VarReg {
|
|
||||||
pub fn norm(self) -> RegType {
|
|
||||||
match self {
|
|
||||||
VarReg::ArgAndNorm(reg, _) | VarReg::Norm(reg) => reg
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn root_register(self) -> usize {
|
|
||||||
match self {
|
|
||||||
VarReg::ArgAndNorm(_, root) => root,
|
|
||||||
VarReg::Norm(root) => root.reg_num()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub enum Term {
|
|
||||||
Atom(Cell<RegType>, Atom),
|
|
||||||
Clause(Cell<RegType>, Atom, Vec<Box<Term>>),
|
|
||||||
Var(Cell<VarReg>, Var)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Rule {
|
|
||||||
pub head: (Term, Term),
|
|
||||||
pub clauses: Vec<Term>
|
|
||||||
}
|
|
||||||
|
|
||||||
pub enum TermRef<'a> {
|
|
||||||
Atom(Level, &'a Cell<RegType>, &'a Atom),
|
|
||||||
Clause(Level, &'a Cell<RegType>, &'a Atom, &'a Vec<Box<Term>>),
|
|
||||||
Var(Level, &'a Cell<VarReg>, &'a Var)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub enum FactInstruction {
|
|
||||||
GetStructure(Level, Atom, usize, RegType),
|
|
||||||
GetValue(RegType, usize),
|
|
||||||
GetVariable(RegType, usize),
|
|
||||||
UnifyVariable(RegType),
|
|
||||||
UnifyValue(RegType)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub enum QueryInstruction {
|
|
||||||
PutStructure(Level, Atom, usize, RegType),
|
|
||||||
PutValue(RegType, usize),
|
|
||||||
PutVariable(RegType, usize),
|
|
||||||
SetVariable(RegType),
|
|
||||||
SetValue(RegType)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub enum ChoiceInstruction {
|
|
||||||
RetryMeElse(usize),
|
|
||||||
TrustMe,
|
|
||||||
TryMeElse(usize)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub enum ControlInstruction {
|
|
||||||
Allocate(usize),
|
|
||||||
Call(Atom, usize),
|
|
||||||
Deallocate,
|
|
||||||
Proceed
|
|
||||||
}
|
|
||||||
|
|
||||||
pub type CompiledFact = Vec<FactInstruction>;
|
|
||||||
|
|
||||||
pub type CompiledQuery = Vec<QueryInstruction>;
|
|
||||||
|
|
||||||
pub enum Line {
|
|
||||||
Choice(ChoiceInstruction),
|
|
||||||
Control(ControlInstruction),
|
|
||||||
Fact(CompiledFact),
|
|
||||||
Query(CompiledQuery)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub enum LineOrCodeOffset<'a> {
|
|
||||||
Instruction(&'a Line),
|
|
||||||
Offset(usize)
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> From<&'a Line> for LineOrCodeOffset<'a> {
|
|
||||||
fn from(line: &'a Line) -> Self {
|
|
||||||
LineOrCodeOffset::Instruction(line)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub type Code = Vec<Line>;
|
|
||||||
|
|
||||||
#[derive(Clone, Copy, PartialEq)]
|
|
||||||
pub enum Addr {
|
|
||||||
HeapCell(usize),
|
|
||||||
StackCell(usize, usize),
|
|
||||||
Str(usize)
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Addr {
|
|
||||||
pub fn is_ref(self) -> bool {
|
|
||||||
match self {
|
|
||||||
Addr::HeapCell(_) | Addr::StackCell(_, _) => true,
|
|
||||||
_ => false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn as_ref(self) -> Option<Ref> {
|
|
||||||
match self {
|
|
||||||
Addr::HeapCell(hc) => Some(Ref::HeapCell(hc)),
|
|
||||||
Addr::StackCell(fr, sc) => Some(Ref::StackCell(fr, sc)),
|
|
||||||
_ => None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<Ref> for Addr {
|
|
||||||
fn from(r: Ref) -> Self {
|
|
||||||
match r {
|
|
||||||
Ref::HeapCell(hc) => Addr::HeapCell(hc),
|
|
||||||
Ref::StackCell(fr, sc) => Addr::StackCell(fr, sc)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Copy, PartialEq)]
|
|
||||||
pub enum Ref {
|
|
||||||
HeapCell(usize),
|
|
||||||
StackCell(usize, usize)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, PartialEq)]
|
|
||||||
pub enum HeapCellValue {
|
|
||||||
NamedStr(usize, Atom),
|
|
||||||
Ref(Ref),
|
|
||||||
Str(usize)
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<Addr> for HeapCellValue {
|
|
||||||
fn from(addr: Addr) -> HeapCellValue {
|
|
||||||
match addr {
|
|
||||||
Addr::HeapCell(hc) =>
|
|
||||||
HeapCellValue::Ref(Ref::HeapCell(hc)),
|
|
||||||
Addr::StackCell(fr, sc) =>
|
|
||||||
HeapCellValue::Ref(Ref::StackCell(fr, sc)),
|
|
||||||
Addr::Str(hc) =>
|
|
||||||
HeapCellValue::Str(hc)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl HeapCellValue {
|
|
||||||
pub fn as_addr(&self, focus: usize) -> Addr {
|
|
||||||
match self {
|
|
||||||
&HeapCellValue::Ref(r) => Addr::from(r),
|
|
||||||
&HeapCellValue::Str(s) => Addr::Str(s),
|
|
||||||
&HeapCellValue::NamedStr(_, _) => Addr::Str(focus)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
|
||||||
pub enum CodePtr {
|
|
||||||
DirEntry(usize),
|
|
||||||
TopLevel
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for CodePtr {
|
|
||||||
fn default() -> Self {
|
|
||||||
CodePtr::TopLevel
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Add<usize> for CodePtr {
|
|
||||||
type Output = CodePtr;
|
|
||||||
|
|
||||||
fn add(self, rhs: usize) -> Self::Output {
|
|
||||||
match self {
|
|
||||||
CodePtr::DirEntry(p) => CodePtr::DirEntry(p + rhs),
|
|
||||||
CodePtr::TopLevel => CodePtr::TopLevel
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl AddAssign<usize> for CodePtr {
|
|
||||||
fn add_assign(&mut self, rhs: usize) {
|
|
||||||
match self {
|
|
||||||
&mut CodePtr::DirEntry(ref mut p) => *p += rhs,
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub type Heap = Vec<HeapCellValue>;
|
|
||||||
|
|
||||||
pub type Registers = Vec<Addr>;
|
|
||||||
|
|
||||||
impl Term {
|
|
||||||
pub fn subterms(&self) -> usize {
|
|
||||||
match self {
|
|
||||||
&Term::Clause(_, _, ref terms) => terms.len(),
|
|
||||||
_ => 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn name(&self) -> &Atom {
|
|
||||||
match self {
|
|
||||||
&Term::Atom(_, ref atom)
|
|
||||||
| &Term::Var(_, ref atom)
|
|
||||||
| &Term::Clause(_, ref atom, _) => atom
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn arity(&self) -> usize {
|
|
||||||
match self {
|
|
||||||
&Term::Atom(_, _) | &Term::Var(_, _) => 0,
|
|
||||||
&Term::Clause(_, _, ref child_terms) => child_terms.len()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub type HeapVarDict = HashMap<Var, Addr>;
|
|
||||||
|
|
||||||
pub enum EvalResult {
|
|
||||||
EntryFailure,
|
|
||||||
EntrySuccess,
|
|
||||||
InitialQuerySuccess(HeapVarDict),
|
|
||||||
QueryFailure,
|
|
||||||
SubsequentQuerySuccess,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl EvalResult {
|
|
||||||
#[allow(dead_code)]
|
|
||||||
pub fn failed_query(&self) -> bool {
|
|
||||||
if let &EvalResult::QueryFailure = self {
|
|
||||||
true
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,447 +0,0 @@
|
|||||||
use l3::ast::*;
|
|
||||||
use l3::iterators::{FactIterator, QueryIterator};
|
|
||||||
|
|
||||||
use std::cell::Cell;
|
|
||||||
use std::cmp::max;
|
|
||||||
use std::collections::HashMap;
|
|
||||||
use std::vec::Vec;
|
|
||||||
|
|
||||||
trait CompilationTarget<'a> {
|
|
||||||
type Iterator : Iterator<Item=TermRef<'a>>;
|
|
||||||
|
|
||||||
fn iter(&'a Term) -> Self::Iterator;
|
|
||||||
|
|
||||||
fn to_structure(Level, Atom, usize, RegType) -> Self;
|
|
||||||
|
|
||||||
fn argument_to_variable(RegType, usize) -> Self;
|
|
||||||
fn argument_to_value(RegType, usize) -> Self;
|
|
||||||
fn subterm_to_variable(RegType) -> Self;
|
|
||||||
fn subterm_to_value(RegType) -> Self;
|
|
||||||
|
|
||||||
fn clause_arg_to_instr(RegType) -> Self;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> CompilationTarget<'a> for FactInstruction {
|
|
||||||
type Iterator = FactIterator<'a>;
|
|
||||||
|
|
||||||
fn iter(term: &'a Term) -> Self::Iterator {
|
|
||||||
term.breadth_first_iter()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn to_structure(lvl: Level, atom: Atom, arity: usize, reg: RegType) -> Self {
|
|
||||||
FactInstruction::GetStructure(lvl, atom, arity, reg)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn argument_to_variable(arg: RegType, val: usize) -> Self {
|
|
||||||
FactInstruction::GetVariable(arg, val)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn argument_to_value(arg: RegType, val: usize) -> Self {
|
|
||||||
FactInstruction::GetValue(arg, val)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn subterm_to_variable(val: RegType) -> Self {
|
|
||||||
FactInstruction::UnifyVariable(val)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn subterm_to_value(val: RegType) -> Self {
|
|
||||||
FactInstruction::UnifyValue(val)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn clause_arg_to_instr(val: RegType) -> Self {
|
|
||||||
FactInstruction::UnifyVariable(val)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> CompilationTarget<'a> for QueryInstruction {
|
|
||||||
type Iterator = QueryIterator<'a>;
|
|
||||||
|
|
||||||
fn iter(term: &'a Term) -> Self::Iterator {
|
|
||||||
term.post_order_iter()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn to_structure(lvl: Level, atom: Atom, arity: usize, reg: RegType) -> Self {
|
|
||||||
QueryInstruction::PutStructure(lvl, atom, arity, reg)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn argument_to_variable(arg: RegType, val: usize) -> Self {
|
|
||||||
QueryInstruction::PutVariable(arg, val)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn argument_to_value(arg: RegType, val: usize) -> Self {
|
|
||||||
QueryInstruction::PutValue(arg, val)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn subterm_to_variable(val: RegType) -> Self {
|
|
||||||
QueryInstruction::SetVariable(val)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn subterm_to_value(val: RegType) -> Self {
|
|
||||||
QueryInstruction::SetValue(val)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn clause_arg_to_instr(val: RegType) -> Self {
|
|
||||||
QueryInstruction::SetValue(val)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct TermMarker<'a> {
|
|
||||||
bindings: HashMap<&'a Var, VarReg>,
|
|
||||||
arg_c: usize,
|
|
||||||
perm_c: usize,
|
|
||||||
temp_c: usize
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> TermMarker<'a> {
|
|
||||||
fn new() -> TermMarker<'a> {
|
|
||||||
TermMarker { bindings: HashMap::new(),
|
|
||||||
arg_c: 1,
|
|
||||||
perm_c: 1,
|
|
||||||
temp_c: 1 }
|
|
||||||
}
|
|
||||||
|
|
||||||
fn reset(&mut self) {
|
|
||||||
self.bindings.clear();
|
|
||||||
self.perm_c = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn contains_var(&self, var: &'a Var) -> bool {
|
|
||||||
self.bindings.contains_key(var)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get(&self, var: &'a Var) -> VarReg {
|
|
||||||
*self.bindings.get(var).unwrap()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn insert(&mut self, var: &'a Var, r: VarReg) {
|
|
||||||
self.bindings.insert(var, r);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn mark_non_var(&mut self, lvl: Level, cell: &Cell<RegType>) {
|
|
||||||
let reg_type = cell.get();
|
|
||||||
|
|
||||||
if reg_type.reg_num() == 0 {
|
|
||||||
match lvl {
|
|
||||||
Level::Deep if reg_type.is_perm() => {
|
|
||||||
let perm = self.perm_c;
|
|
||||||
self.perm_c += 1;
|
|
||||||
cell.set(RegType::Perm(perm));
|
|
||||||
},
|
|
||||||
Level::Deep => {
|
|
||||||
let temp = self.temp_c;
|
|
||||||
self.temp_c += 1;
|
|
||||||
cell.set(RegType::Temp(temp));
|
|
||||||
},
|
|
||||||
Level::Shallow if reg_type.is_perm() => {
|
|
||||||
let arg = self.arg_c;
|
|
||||||
self.arg_c += 1;
|
|
||||||
cell.set(RegType::Perm(arg));
|
|
||||||
},
|
|
||||||
Level::Shallow => {
|
|
||||||
let arg = self.arg_c;
|
|
||||||
self.arg_c += 1;
|
|
||||||
cell.set(RegType::Temp(arg));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn mark_old_var(&mut self, lvl: Level, var: &'a Var) -> VarReg
|
|
||||||
{
|
|
||||||
let reg = self.get(var);
|
|
||||||
|
|
||||||
match lvl {
|
|
||||||
Level::Deep => VarReg::Norm(reg.norm()),
|
|
||||||
Level::Shallow => {
|
|
||||||
let reg = VarReg::ArgAndNorm(reg.norm(), self.arg_c);
|
|
||||||
|
|
||||||
self.arg_c += 1;
|
|
||||||
self.insert(var, reg);
|
|
||||||
|
|
||||||
reg
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn mark_new_var(&mut self, lvl: Level, var: &'a Var, reg: RegType) -> VarReg
|
|
||||||
{
|
|
||||||
let inner_reg = if reg.is_perm() {
|
|
||||||
let perm = self.perm_c;
|
|
||||||
self.perm_c += 1;
|
|
||||||
RegType::Perm(perm)
|
|
||||||
} else {
|
|
||||||
let temp = self.temp_c;
|
|
||||||
self.temp_c += 1;
|
|
||||||
RegType::Temp(temp)
|
|
||||||
};
|
|
||||||
|
|
||||||
let reg = match lvl {
|
|
||||||
Level::Deep => VarReg::Norm(inner_reg),
|
|
||||||
Level::Shallow => {
|
|
||||||
let reg = VarReg::ArgAndNorm(inner_reg, self.arg_c);
|
|
||||||
self.arg_c += 1;
|
|
||||||
reg
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
self.insert(var, reg);
|
|
||||||
reg
|
|
||||||
}
|
|
||||||
|
|
||||||
fn advance_at_head(&mut self, term: &'a Term) {
|
|
||||||
self.arg_c = 1;
|
|
||||||
self.temp_c = max(term.subterms(), self.temp_c) + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn advance(&mut self, term: &'a Term) {
|
|
||||||
self.arg_c = 1;
|
|
||||||
self.temp_c = term.subterms() + 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Copy, Clone)]
|
|
||||||
enum TermStatus {
|
|
||||||
New, Old, Recurrent
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct CodeGenerator<'a> {
|
|
||||||
marker: TermMarker<'a>
|
|
||||||
}
|
|
||||||
|
|
||||||
type VariableFixture<'a> = (TermStatus, Vec<&'a Cell<VarReg>>);
|
|
||||||
type VariableFixtures<'a> = HashMap<&'a Var, VariableFixture<'a>>;
|
|
||||||
|
|
||||||
impl<'a> CodeGenerator<'a> {
|
|
||||||
pub fn new() -> Self {
|
|
||||||
CodeGenerator { marker: TermMarker::new() }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn vars(&self) -> &HashMap<&Var, VarReg> {
|
|
||||||
&self.marker.bindings
|
|
||||||
}
|
|
||||||
|
|
||||||
fn to_structure<Target>(&mut self,
|
|
||||||
lvl: Level,
|
|
||||||
name: &'a Atom,
|
|
||||||
cell: &'a Cell<RegType>,
|
|
||||||
arity: usize)
|
|
||||||
-> Target
|
|
||||||
where Target: CompilationTarget<'a>
|
|
||||||
{
|
|
||||||
self.marker.mark_non_var(lvl, cell);
|
|
||||||
Target::to_structure(lvl, name.clone(), arity, cell.get())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn var_term<Target>(&mut self,
|
|
||||||
lvl: Level,
|
|
||||||
cell: &'a Cell<VarReg>,
|
|
||||||
var: &'a Var)
|
|
||||||
-> Target
|
|
||||||
where Target: CompilationTarget<'a>
|
|
||||||
{
|
|
||||||
if !self.marker.contains_var(var) {
|
|
||||||
let reg = self.marker.mark_new_var(lvl, var, cell.get().norm());
|
|
||||||
cell.set(reg);
|
|
||||||
|
|
||||||
match reg {
|
|
||||||
VarReg::ArgAndNorm(arg, norm) =>
|
|
||||||
Target::argument_to_variable(arg, norm),
|
|
||||||
VarReg::Norm(norm) =>
|
|
||||||
Target::subterm_to_variable(norm)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
let reg = self.marker.mark_old_var(lvl, var);
|
|
||||||
cell.set(reg);
|
|
||||||
|
|
||||||
match reg {
|
|
||||||
VarReg::ArgAndNorm(arg, norm) =>
|
|
||||||
Target::argument_to_value(arg, norm),
|
|
||||||
VarReg::Norm(norm) =>
|
|
||||||
Target::subterm_to_value(norm)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn non_var_subterm<Target>(&mut self, cell: &'a Cell<RegType>) -> Target
|
|
||||||
where Target: CompilationTarget<'a>
|
|
||||||
{
|
|
||||||
self.marker.mark_non_var(Level::Deep, cell);
|
|
||||||
Target::clause_arg_to_instr(cell.get())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn subterm_to_instr<Target>(&mut self, subterm: &'a Term) -> Target
|
|
||||||
where Target: CompilationTarget<'a>
|
|
||||||
{
|
|
||||||
match subterm {
|
|
||||||
&Term::Atom(ref cell, _) | &Term::Clause(ref cell, _, _) =>
|
|
||||||
self.non_var_subterm(cell),
|
|
||||||
&Term::Var(ref cell, ref var) =>
|
|
||||||
self.var_term(Level::Deep, cell, var)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn compile_target<Target>(&mut self, term: &'a Term) -> Vec<Target>
|
|
||||||
where Target: CompilationTarget<'a>
|
|
||||||
{
|
|
||||||
let iter = Target::iter(term);
|
|
||||||
let mut target = Vec::new();
|
|
||||||
|
|
||||||
for term in iter {
|
|
||||||
match term {
|
|
||||||
TermRef::Atom(lvl, term, atom) =>
|
|
||||||
target.push(self.to_structure(lvl, atom, term, 0)),
|
|
||||||
TermRef::Clause(lvl, term, atom, terms) => {
|
|
||||||
target.push(self.to_structure(lvl, atom, term, terms.len()));
|
|
||||||
|
|
||||||
for subterm in terms {
|
|
||||||
target.push(self.subterm_to_instr(subterm.as_ref()));
|
|
||||||
}
|
|
||||||
},
|
|
||||||
TermRef::Var(lvl @ Level::Shallow, ref cell, ref var) =>
|
|
||||||
target.push(self.var_term(lvl, cell, var)),
|
|
||||||
_ => {}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
target
|
|
||||||
}
|
|
||||||
|
|
||||||
fn mark_vars_in_term<Iter>(iter: Iter, vs: &mut VariableFixtures<'a>)
|
|
||||||
where Iter : Iterator<Item=TermRef<'a>>
|
|
||||||
{
|
|
||||||
for term in iter {
|
|
||||||
if let TermRef::Var(_, reg_cell, var) = term {
|
|
||||||
let mut status = vs.entry(var)
|
|
||||||
.or_insert((TermStatus::New, Vec::new()));
|
|
||||||
|
|
||||||
status.1.push(reg_cell);
|
|
||||||
|
|
||||||
match status.0 {
|
|
||||||
TermStatus::Old => status.0 = TermStatus::Recurrent,
|
|
||||||
_ => {}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for &mut (ref mut term_status, ref mut cb) in vs.values_mut() {
|
|
||||||
match *term_status {
|
|
||||||
TermStatus::New => *term_status = TermStatus::Old,
|
|
||||||
TermStatus::Recurrent => {
|
|
||||||
for cell_reg in cb.drain(0..) {
|
|
||||||
cell_reg.set(VarReg::Norm(RegType::Perm(0)));
|
|
||||||
}
|
|
||||||
},
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn mark_perm_vars(rule: &'a Rule) -> VariableFixtures {
|
|
||||||
let &Rule { head: (ref p0, ref p1), ref clauses } = rule;
|
|
||||||
let mut vfs = HashMap::new();
|
|
||||||
|
|
||||||
let iter = p0.breadth_first_iter().chain(p1.breadth_first_iter());
|
|
||||||
|
|
||||||
Self::mark_vars_in_term(iter, &mut vfs);
|
|
||||||
|
|
||||||
for term in clauses {
|
|
||||||
Self::mark_vars_in_term(term.breadth_first_iter(), &mut vfs);
|
|
||||||
}
|
|
||||||
|
|
||||||
vfs
|
|
||||||
}
|
|
||||||
|
|
||||||
fn add_conditional_call(compiled_query: &mut Code, term: &Term) {
|
|
||||||
match term {
|
|
||||||
&Term::Atom(_, ref atom) => {
|
|
||||||
let call = ControlInstruction::Call(atom.clone(), 0);
|
|
||||||
compiled_query.push(Line::Control(call));
|
|
||||||
},
|
|
||||||
&Term::Clause(_, ref atom, ref terms) => {
|
|
||||||
let call = ControlInstruction::Call(atom.clone(), terms.len());
|
|
||||||
compiled_query.push(Line::Control(call));
|
|
||||||
},
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn compile_rule(&mut self, rule: &'a Rule) -> Code {
|
|
||||||
let vfs = Self::mark_perm_vars(&rule);
|
|
||||||
let &Rule { head: (ref p0, ref p1), ref clauses } = rule;
|
|
||||||
let mut perm_vars = 0;
|
|
||||||
|
|
||||||
for &(term_status, _) in vfs.values() {
|
|
||||||
if let TermStatus::Recurrent = term_status {
|
|
||||||
perm_vars += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut body = Vec::new();
|
|
||||||
|
|
||||||
body.push(Line::Control(ControlInstruction::Allocate(perm_vars)));
|
|
||||||
|
|
||||||
self.marker.advance(p0);
|
|
||||||
body.push(Line::Fact(self.compile_target(p0)));
|
|
||||||
|
|
||||||
self.marker.advance_at_head(p1);
|
|
||||||
body.push(Line::Query(self.compile_target(p1)));
|
|
||||||
|
|
||||||
Self::add_conditional_call(&mut body, p1);
|
|
||||||
|
|
||||||
body = clauses.iter()
|
|
||||||
.map(|ref term| self.compile_query(term))
|
|
||||||
.fold(body, |mut body, ref mut cqs| {
|
|
||||||
body.append(cqs);
|
|
||||||
body
|
|
||||||
});
|
|
||||||
|
|
||||||
body.push(Line::Control(ControlInstruction::Deallocate));
|
|
||||||
body
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn compile_fact(&mut self, term: &'a Term) -> Code {
|
|
||||||
self.marker.advance(term);
|
|
||||||
|
|
||||||
let mut compiled_fact = vec![Line::Fact(self.compile_target(term))];
|
|
||||||
let proceed = Line::Control(ControlInstruction::Proceed);
|
|
||||||
|
|
||||||
compiled_fact.push(proceed);
|
|
||||||
compiled_fact
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn compile_query(&mut self, term: &'a Term) -> Code {
|
|
||||||
self.marker.advance(term);
|
|
||||||
|
|
||||||
let mut compiled_query = vec![Line::Query(self.compile_target(term))];
|
|
||||||
Self::add_conditional_call(&mut compiled_query, term);
|
|
||||||
|
|
||||||
compiled_query
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn compile_predicate(&mut self, clauses: &'a Vec<PredicateClause>) -> Code
|
|
||||||
{
|
|
||||||
let mut code = Vec::new();
|
|
||||||
|
|
||||||
for (i, clause) in clauses.iter().enumerate() {
|
|
||||||
self.marker.reset();
|
|
||||||
|
|
||||||
let mut clause_code = match clause {
|
|
||||||
&PredicateClause::Fact(ref fact) =>
|
|
||||||
self.compile_fact(fact),
|
|
||||||
&PredicateClause::Rule(ref rule) =>
|
|
||||||
self.compile_rule(rule)
|
|
||||||
};
|
|
||||||
|
|
||||||
let choice = match i {
|
|
||||||
0 => ChoiceInstruction::TryMeElse(clause_code.len() + 1),
|
|
||||||
_ if i == clauses.len() - 1 => ChoiceInstruction::TrustMe,
|
|
||||||
_ => ChoiceInstruction::RetryMeElse(clause_code.len() + 1)
|
|
||||||
};
|
|
||||||
|
|
||||||
code.push(Line::Choice(choice));
|
|
||||||
code.append(&mut clause_code);
|
|
||||||
}
|
|
||||||
|
|
||||||
code
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,86 +0,0 @@
|
|||||||
use l3::and_stack::*;
|
|
||||||
use l3::ast::*;
|
|
||||||
|
|
||||||
use std::vec::Vec;
|
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
|
||||||
pub enum HeapCellView<'a> {
|
|
||||||
Str(usize, &'a Atom),
|
|
||||||
HeapVar(usize),
|
|
||||||
StackVar(usize, usize)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct HeapCellViewer<'a> {
|
|
||||||
heap: &'a Heap,
|
|
||||||
and_stack: &'a AndStack,
|
|
||||||
state_stack: Vec<Addr>
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> HeapCellViewer<'a> {
|
|
||||||
pub fn new(heap: &'a Heap, and_stack: &'a AndStack, focus: Addr) -> Self {
|
|
||||||
HeapCellViewer {
|
|
||||||
heap: heap,
|
|
||||||
and_stack: and_stack,
|
|
||||||
state_stack: vec![focus]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn follow_stack_ref(&mut self, mut fr: usize, mut sc: usize) -> HeapCellView<'a>
|
|
||||||
{
|
|
||||||
loop {
|
|
||||||
match self.and_stack[fr][sc] {
|
|
||||||
Addr::HeapCell(hc) | Addr::Str(hc) =>
|
|
||||||
return self.follow_heap_ref(hc),
|
|
||||||
Addr::StackCell(fr1, sc1) => {
|
|
||||||
if fr1 == fr && sc1 == sc {
|
|
||||||
return HeapCellView::StackVar(fr, sc);
|
|
||||||
}
|
|
||||||
|
|
||||||
fr = fr1; sc = sc1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn follow_heap_ref(&mut self, mut focus: usize) -> HeapCellView<'a> {
|
|
||||||
loop {
|
|
||||||
match &self.heap[focus] {
|
|
||||||
&HeapCellValue::NamedStr(arity, ref name) => {
|
|
||||||
for i in (1 .. arity + 1).rev() {
|
|
||||||
self.state_stack.push(Addr::HeapCell(focus + i));
|
|
||||||
}
|
|
||||||
|
|
||||||
return HeapCellView::Str(arity, name);
|
|
||||||
},
|
|
||||||
&HeapCellValue::Ref(Ref::HeapCell(hc)) => {
|
|
||||||
if focus == hc {
|
|
||||||
return HeapCellView::HeapVar(hc);
|
|
||||||
} else {
|
|
||||||
focus = hc;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
&HeapCellValue::Ref(Ref::StackCell(fr, sc)) =>
|
|
||||||
return self.follow_stack_ref(fr, sc),
|
|
||||||
&HeapCellValue::Str(cell_num) =>
|
|
||||||
focus = cell_num,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Iterator for HeapCellViewer<'a> {
|
|
||||||
type Item = HeapCellView<'a>;
|
|
||||||
|
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
|
||||||
if let Some(addr) = self.state_stack.pop() {
|
|
||||||
match addr {
|
|
||||||
Addr::HeapCell(hc) | Addr::Str(hc) =>
|
|
||||||
return Some(self.follow_heap_ref(hc)),
|
|
||||||
Addr::StackCell(fr, sc) =>
|
|
||||||
return Some(self.follow_stack_ref(fr, sc))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
255
src/l3/io.rs
255
src/l3/io.rs
@@ -1,255 +0,0 @@
|
|||||||
use l3::ast::*;
|
|
||||||
use l3::codegen::*;
|
|
||||||
use l3::l3_parser::*;
|
|
||||||
use l3::machine::*;
|
|
||||||
|
|
||||||
use termion::raw::IntoRawMode;
|
|
||||||
use termion::input::TermRead;
|
|
||||||
use termion::event::Key;
|
|
||||||
|
|
||||||
use std::io::{Write, stdin, stdout};
|
|
||||||
use std::fmt;
|
|
||||||
|
|
||||||
impl fmt::Display for FactInstruction {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
match self {
|
|
||||||
&FactInstruction::GetStructure(Level::Deep, ref name, ref arity, ref r) =>
|
|
||||||
write!(f, "get_structure {}/{}, {}", name, arity, r),
|
|
||||||
&FactInstruction::GetStructure(Level::Shallow, ref name, ref arity, ref r) =>
|
|
||||||
write!(f, "get_structure {}/{}, A{}", name, arity, r.reg_num()),
|
|
||||||
&FactInstruction::GetValue(ref x, ref a) =>
|
|
||||||
write!(f, "get_value {}, A{}", x, a),
|
|
||||||
&FactInstruction::GetVariable(ref x, ref a) =>
|
|
||||||
write!(f, "get_variable {}, A{}", x, a),
|
|
||||||
&FactInstruction::UnifyVariable(ref r) =>
|
|
||||||
write!(f, "unify_variable {}", r),
|
|
||||||
&FactInstruction::UnifyValue(ref r) =>
|
|
||||||
write!(f, "unify_value {}", r)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Display for QueryInstruction {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
match self {
|
|
||||||
&QueryInstruction::PutStructure(Level::Deep, ref name, ref arity, ref r) =>
|
|
||||||
write!(f, "put_structure {}/{}, {}", name, arity, r.reg_num()),
|
|
||||||
&QueryInstruction::PutStructure(Level::Shallow, ref name, ref arity, ref r) =>
|
|
||||||
write!(f, "put_structure {}/{}, A{}", name, arity, r.reg_num()),
|
|
||||||
&QueryInstruction::PutValue(ref x, ref a) =>
|
|
||||||
write!(f, "put_value {}, A{}", x, a),
|
|
||||||
&QueryInstruction::PutVariable(ref x, ref a) =>
|
|
||||||
write!(f, "put_variable {}, A{}", x, a),
|
|
||||||
&QueryInstruction::SetVariable(ref r) =>
|
|
||||||
write!(f, "set_variable {}", r),
|
|
||||||
&QueryInstruction::SetValue(ref r) =>
|
|
||||||
write!(f, "set_value {}", r),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Display for ControlInstruction {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
match self {
|
|
||||||
&ControlInstruction::Allocate(num_cells) =>
|
|
||||||
write!(f, "allocate {}", num_cells),
|
|
||||||
&ControlInstruction::Call(ref name, ref arity) =>
|
|
||||||
write!(f, "call {}/{}", name, arity),
|
|
||||||
&ControlInstruction::Deallocate =>
|
|
||||||
write!(f, "deallocate"),
|
|
||||||
&ControlInstruction::Proceed =>
|
|
||||||
write!(f, "proceed")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Display for ChoiceInstruction {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
match self {
|
|
||||||
&ChoiceInstruction::TryMeElse(offset) =>
|
|
||||||
write!(f, "try_me_else {}", offset),
|
|
||||||
&ChoiceInstruction::RetryMeElse(offset) =>
|
|
||||||
write!(f, "retry_me_else {}", offset),
|
|
||||||
&ChoiceInstruction::TrustMe =>
|
|
||||||
write!(f, "trust_me")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Display for Level {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
match self {
|
|
||||||
&Level::Shallow => write!(f, "A"),
|
|
||||||
&Level::Deep => write!(f, "X")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Display for VarReg {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
match self {
|
|
||||||
&VarReg::Norm(RegType::Perm(reg)) => write!(f, "Y{}", reg),
|
|
||||||
&VarReg::Norm(RegType::Temp(reg)) => write!(f, "X{}", reg),
|
|
||||||
&VarReg::ArgAndNorm(RegType::Perm(reg), arg) =>
|
|
||||||
write!(f, "Y{} A{}", reg, arg),
|
|
||||||
&VarReg::ArgAndNorm(RegType::Temp(reg), arg) =>
|
|
||||||
write!(f, "X{} A{}", reg, arg)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Display for RegType {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
match self {
|
|
||||||
&RegType::Perm(val) => write!(f, "Y{}", val),
|
|
||||||
&RegType::Temp(val) => write!(f, "X{}", val)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
fn is_consistent(predicate: &Vec<PredicateClause>) -> bool {
|
|
||||||
let name = predicate.first().unwrap().name();
|
|
||||||
let arity = predicate.first().unwrap().arity();
|
|
||||||
|
|
||||||
for clause in predicate.iter().skip(1) {
|
|
||||||
if !(name == clause.name() && arity == clause.arity()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(dead_code)]
|
|
||||||
pub fn print_code(code: &Code) {
|
|
||||||
for clause in code {
|
|
||||||
match clause {
|
|
||||||
&Line::Fact(ref fact) =>
|
|
||||||
for fact_instr in fact {
|
|
||||||
println!("{}", fact_instr);
|
|
||||||
},
|
|
||||||
&Line::Choice(ref choice) =>
|
|
||||||
println!("{}", choice),
|
|
||||||
&Line::Control(ref control) =>
|
|
||||||
println!("{}", control),
|
|
||||||
&Line::Query(ref query) =>
|
|
||||||
for query_instr in query {
|
|
||||||
println!("{}", query_instr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn read() -> String {
|
|
||||||
let _ = stdout().flush();
|
|
||||||
|
|
||||||
let mut buffer = String::new();
|
|
||||||
let mut result = String::new();
|
|
||||||
|
|
||||||
let stdin = stdin();
|
|
||||||
stdin.read_line(&mut buffer).unwrap();
|
|
||||||
|
|
||||||
if &*buffer.trim() == ":{" {
|
|
||||||
buffer.clear();
|
|
||||||
|
|
||||||
stdin.read_line(&mut buffer).unwrap();
|
|
||||||
|
|
||||||
while &*buffer.trim() != "}:" {
|
|
||||||
result += buffer.as_str();
|
|
||||||
buffer.clear();
|
|
||||||
stdin.read_line(&mut buffer).unwrap();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
result = buffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
result
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn eval(wam: &mut Machine, buffer: &str) -> EvalResult
|
|
||||||
{
|
|
||||||
let result = parse_TopLevel(buffer);
|
|
||||||
let mut cg = CodeGenerator::new();
|
|
||||||
|
|
||||||
match &result {
|
|
||||||
&Ok(TopLevel::Predicate(ref clauses)) => {
|
|
||||||
if is_consistent(clauses) {
|
|
||||||
let compiled_pred = cg.compile_predicate(clauses);
|
|
||||||
wam.add_predicate(clauses, compiled_pred);
|
|
||||||
|
|
||||||
EvalResult::EntrySuccess
|
|
||||||
} else {
|
|
||||||
let msg = r"Error: predicate is inconsistent.
|
|
||||||
Each predicate must have the same name and arity.";
|
|
||||||
|
|
||||||
println!("{}", msg);
|
|
||||||
EvalResult::EntryFailure
|
|
||||||
}
|
|
||||||
},
|
|
||||||
&Ok(TopLevel::Fact(ref fact)) => {
|
|
||||||
let compiled_fact = cg.compile_fact(&fact);
|
|
||||||
wam.add_fact(fact, compiled_fact);
|
|
||||||
EvalResult::EntrySuccess
|
|
||||||
},
|
|
||||||
&Ok(TopLevel::Rule(ref rule)) => {
|
|
||||||
let compiled_rule = cg.compile_rule(&rule);
|
|
||||||
wam.add_rule(rule, compiled_rule);
|
|
||||||
EvalResult::EntrySuccess
|
|
||||||
},
|
|
||||||
&Ok(TopLevel::Query(ref query)) => {
|
|
||||||
let compiled_query = cg.compile_query(&query);
|
|
||||||
wam.run_query(compiled_query, &cg)
|
|
||||||
},
|
|
||||||
&Err(_) => {
|
|
||||||
println!("Grammatical error of some kind!");
|
|
||||||
EvalResult::EntryFailure
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn print(wam: &mut Machine, result: EvalResult) {
|
|
||||||
match result {
|
|
||||||
EvalResult::InitialQuerySuccess(heap_locs) => {
|
|
||||||
println!("yes");
|
|
||||||
|
|
||||||
'outer: loop {
|
|
||||||
let mut result = EvalResult::QueryFailure;
|
|
||||||
let bindings = wam.heap_view(&heap_locs);
|
|
||||||
|
|
||||||
let stdin = stdin();
|
|
||||||
let mut stdout = stdout().into_raw_mode().unwrap();
|
|
||||||
|
|
||||||
write!(stdout, "{}\n\r", bindings).unwrap();
|
|
||||||
stdout.flush().unwrap();
|
|
||||||
|
|
||||||
if !wam.or_stack_is_empty() {
|
|
||||||
write!(stdout, "Press ; to continue or A to abort.\n\r").unwrap();
|
|
||||||
stdout.flush().unwrap();
|
|
||||||
|
|
||||||
for c in stdin.keys() {
|
|
||||||
match c.unwrap() {
|
|
||||||
Key::Char(';') => {
|
|
||||||
result = wam.continue_query();
|
|
||||||
break;
|
|
||||||
},
|
|
||||||
Key::Char('a') | Key::Char('A') =>
|
|
||||||
break 'outer,
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
if let &EvalResult::QueryFailure = &result {
|
|
||||||
write!(stdout, "no\n\r").unwrap();
|
|
||||||
stdout.flush().unwrap();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
EvalResult::QueryFailure => println!("no"),
|
|
||||||
_ => {}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -1,175 +0,0 @@
|
|||||||
use l3::ast::*;
|
|
||||||
|
|
||||||
use std::cell::Cell;
|
|
||||||
use std::collections::VecDeque;
|
|
||||||
use std::vec::Vec;
|
|
||||||
|
|
||||||
enum IteratorState<'a> {
|
|
||||||
Atom(Level, &'a Cell<RegType>, &'a Atom),
|
|
||||||
Clause(Level, usize, &'a Cell<RegType>, &'a Atom, &'a Vec<Box<Term>>),
|
|
||||||
IsolatedAtom(&'a Cell<RegType>, &'a Atom),
|
|
||||||
IsolatedVar(&'a Cell<VarReg>, &'a Var),
|
|
||||||
RootClause(usize, &'a Vec<Box<Term>>),
|
|
||||||
Var(Level, &'a Cell<VarReg>, &'a Var)
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> IteratorState<'a> {
|
|
||||||
fn to_state(lvl: Level, term: &'a Term) -> IteratorState<'a>
|
|
||||||
{
|
|
||||||
match term {
|
|
||||||
&Term::Atom(ref cell, ref atom) =>
|
|
||||||
IteratorState::Atom(lvl, cell, atom),
|
|
||||||
&Term::Clause(ref cell, ref atom, ref child_terms) =>
|
|
||||||
IteratorState::Clause(lvl, 0, cell, atom, child_terms),
|
|
||||||
&Term::Var(ref cell, ref var) =>
|
|
||||||
IteratorState::Var(lvl, cell, var)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct QueryIterator<'a> {
|
|
||||||
state_stack: Vec<IteratorState<'a>>
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> QueryIterator<'a> {
|
|
||||||
fn push_clause(&mut self,
|
|
||||||
lvl: Level,
|
|
||||||
child_num: usize,
|
|
||||||
cell: &'a Cell<RegType>,
|
|
||||||
name: &'a Atom,
|
|
||||||
child_terms: &'a Vec<Box<Term>>)
|
|
||||||
{
|
|
||||||
self.state_stack.push(IteratorState::Clause(lvl,
|
|
||||||
child_num,
|
|
||||||
cell,
|
|
||||||
name,
|
|
||||||
child_terms));
|
|
||||||
}
|
|
||||||
|
|
||||||
fn push_root_clause(&mut self,
|
|
||||||
child_num: usize,
|
|
||||||
child_terms: &'a Vec<Box<Term>>)
|
|
||||||
{
|
|
||||||
self.state_stack.push(IteratorState::RootClause(child_num, child_terms));
|
|
||||||
}
|
|
||||||
|
|
||||||
fn push_subterm(&mut self, lvl: Level, term: &'a Term) {
|
|
||||||
self.state_stack.push(IteratorState::to_state(lvl, term));
|
|
||||||
}
|
|
||||||
|
|
||||||
fn new(term: &'a Term) -> QueryIterator<'a> {
|
|
||||||
let state = match term {
|
|
||||||
&Term::Atom(ref cell, ref atom) =>
|
|
||||||
IteratorState::IsolatedAtom(cell, atom),
|
|
||||||
&Term::Clause(_, _, ref terms) =>
|
|
||||||
IteratorState::RootClause(0, terms),
|
|
||||||
&Term::Var(ref cell, ref var) =>
|
|
||||||
IteratorState::IsolatedVar(cell, var)
|
|
||||||
};
|
|
||||||
|
|
||||||
QueryIterator { state_stack: vec![state] }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Iterator for QueryIterator<'a> {
|
|
||||||
type Item = TermRef<'a>;
|
|
||||||
|
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
|
||||||
while let Some(iter_state) = self.state_stack.pop() {
|
|
||||||
match iter_state {
|
|
||||||
IteratorState::Atom(lvl, cell, atom) =>
|
|
||||||
return Some(TermRef::Atom(lvl, cell, atom)),
|
|
||||||
IteratorState::Clause(lvl, child_num, cell, atom, child_terms) => {
|
|
||||||
if child_num == child_terms.len() {
|
|
||||||
return Some(TermRef::Clause(lvl, cell, atom, child_terms));
|
|
||||||
} else {
|
|
||||||
self.push_clause(lvl, child_num + 1, cell, atom, child_terms);
|
|
||||||
self.push_subterm(Level::Deep, child_terms[child_num].as_ref());
|
|
||||||
}
|
|
||||||
},
|
|
||||||
IteratorState::IsolatedAtom(cell, atom) =>
|
|
||||||
return Some(TermRef::Atom(Level::Shallow, cell, atom)),
|
|
||||||
IteratorState::IsolatedVar(cell, var) =>
|
|
||||||
return Some(TermRef::Var(Level::Shallow, cell, var)),
|
|
||||||
IteratorState::RootClause(child_num, child_terms) => {
|
|
||||||
if child_num == child_terms.len() {
|
|
||||||
return None;
|
|
||||||
} else {
|
|
||||||
self.push_root_clause(child_num + 1, child_terms);
|
|
||||||
self.push_subterm(Level::Shallow, child_terms[child_num].as_ref());
|
|
||||||
}
|
|
||||||
},
|
|
||||||
IteratorState::Var(lvl, cell, var) =>
|
|
||||||
return Some(TermRef::Var(lvl, cell, var))
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct FactIterator<'a> {
|
|
||||||
state_queue: VecDeque<IteratorState<'a>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> FactIterator<'a> {
|
|
||||||
fn push_subterm(&mut self, lvl: Level, term: &'a Term) {
|
|
||||||
self.state_queue.push_back(IteratorState::to_state(lvl, term));
|
|
||||||
}
|
|
||||||
|
|
||||||
fn new(term: &'a Term) -> FactIterator<'a> {
|
|
||||||
let states = match term {
|
|
||||||
&Term::Atom(ref cell, ref atom) =>
|
|
||||||
vec![IteratorState::IsolatedAtom(cell, atom)],
|
|
||||||
&Term::Clause(_, _, ref terms) =>
|
|
||||||
vec![IteratorState::RootClause(0, terms)],
|
|
||||||
&Term::Var(ref cell, ref var) =>
|
|
||||||
vec![IteratorState::IsolatedVar(cell, var)]
|
|
||||||
};
|
|
||||||
|
|
||||||
FactIterator { state_queue: VecDeque::from(states) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Iterator for FactIterator<'a> {
|
|
||||||
type Item = TermRef<'a>;
|
|
||||||
|
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
|
||||||
while let Some(state) = self.state_queue.pop_front() {
|
|
||||||
match state {
|
|
||||||
IteratorState::Atom(lvl, cell, atom) =>
|
|
||||||
return Some(TermRef::Atom(lvl, cell, atom)),
|
|
||||||
IteratorState::Clause(lvl, _, cell, atom, child_terms) => {
|
|
||||||
for child_term in child_terms {
|
|
||||||
self.push_subterm(Level::Deep, child_term);
|
|
||||||
}
|
|
||||||
|
|
||||||
return Some(TermRef::Clause(lvl, cell, atom, child_terms));
|
|
||||||
},
|
|
||||||
IteratorState::IsolatedAtom(cell, atom) =>
|
|
||||||
return Some(TermRef::Atom(Level::Shallow, cell, atom)),
|
|
||||||
IteratorState::IsolatedVar(cell, var) =>
|
|
||||||
return Some(TermRef::Var(Level::Shallow, cell, var)),
|
|
||||||
IteratorState::RootClause(_, child_terms) => {
|
|
||||||
for child_term in child_terms {
|
|
||||||
self.push_subterm(Level::Shallow, child_term);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
IteratorState::Var(lvl, cell, var) =>
|
|
||||||
return Some(TermRef::Var(lvl, cell, var))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Term {
|
|
||||||
pub fn post_order_iter(&self) -> QueryIterator {
|
|
||||||
QueryIterator::new(self)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn breadth_first_iter(&self) -> FactIterator {
|
|
||||||
FactIterator::new(self)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,59 +0,0 @@
|
|||||||
use l3::ast::*;
|
|
||||||
|
|
||||||
use std::cell::Cell;
|
|
||||||
|
|
||||||
grammar;
|
|
||||||
|
|
||||||
pub TopLevel: TopLevel = {
|
|
||||||
"?-" <t:Term> "." => TopLevel::Query(t),
|
|
||||||
<Predicate> => TopLevel::Predicate(<>),
|
|
||||||
<Rule> "." => TopLevel::Rule(<>),
|
|
||||||
<Term> "." => TopLevel::Fact(<>)
|
|
||||||
};
|
|
||||||
|
|
||||||
Atom : Atom = {
|
|
||||||
r"[a-z][a-z0-9_]*" => <>.trim().to_string(),
|
|
||||||
};
|
|
||||||
|
|
||||||
BoxedTerm : Box<Term> = {
|
|
||||||
<t:Term> => Box::new(t)
|
|
||||||
};
|
|
||||||
|
|
||||||
Clause : Term = {
|
|
||||||
<a:Atom> "(" <ts: (<BoxedTerm> ",")*> <t:BoxedTerm> ")" => {
|
|
||||||
let mut ts = ts;
|
|
||||||
ts.push(t);
|
|
||||||
Term::Clause(Cell::new(RegType::Temp(0)), a, ts)
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
Predicate : Vec<PredicateClause> = {
|
|
||||||
<pcs: (<PredicateClause>)+> <pc: PredicateClause> => {
|
|
||||||
let mut pcs = pcs;
|
|
||||||
pcs.push(pc);
|
|
||||||
pcs
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
PredicateClause : PredicateClause = {
|
|
||||||
<Rule> "." => PredicateClause::Rule(<>),
|
|
||||||
<Term> "." => PredicateClause::Fact(<>)
|
|
||||||
};
|
|
||||||
|
|
||||||
Rule : Rule = {
|
|
||||||
<c:Clause> ":-" <h:Term> <cs: ("," <Term>)*> =>
|
|
||||||
Rule { head: (c, h), clauses: cs },
|
|
||||||
<a:Atom> ":-" <h:Term> <cs: ("," <Term>)*> =>
|
|
||||||
Rule { head: (Term::Atom(Cell::new(RegType::Temp(0)), a), h),
|
|
||||||
clauses: cs }
|
|
||||||
};
|
|
||||||
|
|
||||||
Term : Term = {
|
|
||||||
<Clause> => <>,
|
|
||||||
<Atom> => Term::Atom(Cell::new(RegType::Temp(0)), <>),
|
|
||||||
<Var> => Term::Var(Cell::new(VarReg::Norm(RegType::Temp(0))), <>)
|
|
||||||
};
|
|
||||||
|
|
||||||
Var : Var = {
|
|
||||||
r"[A-Z][a-z0-9_]*" => <>.trim().to_string(),
|
|
||||||
};
|
|
||||||
2177
src/l3/l3_parser.rs
2177
src/l3/l3_parser.rs
File diff suppressed because it is too large
Load Diff
@@ -1,677 +0,0 @@
|
|||||||
use l3::ast::*;
|
|
||||||
use l3::codegen::*;
|
|
||||||
use l3::heapview::*;
|
|
||||||
use l3::and_stack::*;
|
|
||||||
use l3::or_stack::*;
|
|
||||||
|
|
||||||
use std::collections::HashMap;
|
|
||||||
use std::ops::{Index, IndexMut};
|
|
||||||
use std::vec::Vec;
|
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
|
||||||
enum MachineMode {
|
|
||||||
Read,
|
|
||||||
Write
|
|
||||||
}
|
|
||||||
|
|
||||||
struct MachineState {
|
|
||||||
h: usize,
|
|
||||||
s: usize,
|
|
||||||
p: CodePtr,
|
|
||||||
b: usize,
|
|
||||||
e: usize,
|
|
||||||
num_of_args: usize,
|
|
||||||
cp: CodePtr,
|
|
||||||
fail: bool,
|
|
||||||
heap: Heap,
|
|
||||||
mode: MachineMode,
|
|
||||||
and_stack: AndStack,
|
|
||||||
or_stack: OrStack,
|
|
||||||
registers: Registers,
|
|
||||||
trail: Vec<Ref>,
|
|
||||||
tr: usize,
|
|
||||||
hb: usize
|
|
||||||
}
|
|
||||||
|
|
||||||
type CodeDir = HashMap<(Atom, usize), usize>;
|
|
||||||
|
|
||||||
impl Index<RegType> for MachineState {
|
|
||||||
type Output = Addr;
|
|
||||||
|
|
||||||
fn index(&self, reg: RegType) -> &Self::Output {
|
|
||||||
match reg {
|
|
||||||
RegType::Temp(temp) => &self.registers[temp],
|
|
||||||
RegType::Perm(perm) => {
|
|
||||||
let e = self.e;
|
|
||||||
&self.and_stack[e][perm]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl IndexMut<RegType> for MachineState {
|
|
||||||
fn index_mut(&mut self, reg: RegType) -> &mut Self::Output {
|
|
||||||
match reg {
|
|
||||||
RegType::Temp(temp) => &mut self.registers[temp],
|
|
||||||
RegType::Perm(perm) => {
|
|
||||||
let e = self.e;
|
|
||||||
&mut self.and_stack[e][perm]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Machine {
|
|
||||||
ms: MachineState,
|
|
||||||
code: Code,
|
|
||||||
code_dir: CodeDir
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Machine {
|
|
||||||
pub fn new() -> Self {
|
|
||||||
Machine {
|
|
||||||
ms: MachineState::new(),
|
|
||||||
code: Vec::new(),
|
|
||||||
code_dir: HashMap::new()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn failed(&self) -> bool {
|
|
||||||
self.ms.fail
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn add_fact(&mut self, fact: &Term, mut code: Code) {
|
|
||||||
let p = self.code.len();
|
|
||||||
let name = fact.name().clone();
|
|
||||||
let arity = fact.arity();
|
|
||||||
|
|
||||||
self.code.append(&mut code);
|
|
||||||
self.code_dir.insert((name, arity), p);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn add_rule(&mut self, rule: &Rule, mut code: Code) {
|
|
||||||
let p = self.code.len();
|
|
||||||
let name = rule.head.0.name().clone();
|
|
||||||
let arity = rule.head.0.arity();
|
|
||||||
|
|
||||||
self.code.append(&mut code);
|
|
||||||
self.code_dir.insert((name, arity), p);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn add_predicate(&mut self, pred: &Vec<PredicateClause>, mut code: Code)
|
|
||||||
{
|
|
||||||
let p = self.code.len();
|
|
||||||
let name = pred.first().unwrap().name().clone();
|
|
||||||
let arity = pred.first().unwrap().arity();
|
|
||||||
|
|
||||||
self.code.append(&mut code);
|
|
||||||
self.code_dir.insert((name, arity), p);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn execute_instr<'a>(&mut self, instr_src: LineOrCodeOffset<'a>) -> bool
|
|
||||||
{
|
|
||||||
let mut instr = match instr_src {
|
|
||||||
LineOrCodeOffset::Instruction(instr) => instr,
|
|
||||||
LineOrCodeOffset::Offset(p) => &self.code[p]
|
|
||||||
};
|
|
||||||
|
|
||||||
loop {
|
|
||||||
match instr {
|
|
||||||
&Line::Choice(ref choice_instr) =>
|
|
||||||
self.ms.execute_choice_instr(choice_instr),
|
|
||||||
&Line::Fact(ref fact) => {
|
|
||||||
for fact_instr in fact {
|
|
||||||
self.ms.execute_fact_instr(&fact_instr);
|
|
||||||
}
|
|
||||||
self.ms.p += 1;
|
|
||||||
},
|
|
||||||
&Line::Query(ref query) => {
|
|
||||||
for query_instr in query {
|
|
||||||
self.ms.execute_query_instr(&query_instr);
|
|
||||||
}
|
|
||||||
self.ms.p += 1;
|
|
||||||
},
|
|
||||||
&Line::Control(ref control_instr) =>
|
|
||||||
self.ms.execute_ctrl_instr(&self.code_dir, control_instr),
|
|
||||||
}
|
|
||||||
|
|
||||||
if self.failed() {
|
|
||||||
let p = self.ms
|
|
||||||
.or_stack
|
|
||||||
.top()
|
|
||||||
.map(|fr| fr.bp)
|
|
||||||
.unwrap_or_default();
|
|
||||||
|
|
||||||
if let CodePtr::TopLevel = p {
|
|
||||||
return false;
|
|
||||||
} else {
|
|
||||||
self.ms.fail = false;
|
|
||||||
self.ms.p = p;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
match self.ms.p {
|
|
||||||
CodePtr::DirEntry(p) if p < self.code.len() =>
|
|
||||||
instr = &self.code[p],
|
|
||||||
_ => break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn heap_view(&self, var_dir: &HeapVarDict) -> String {
|
|
||||||
let mut result = String::new();
|
|
||||||
|
|
||||||
for (var, addr) in var_dir {
|
|
||||||
let mut arities = Vec::new();
|
|
||||||
let viewer = HeapCellViewer::new(&self.ms.heap,
|
|
||||||
&self.ms.and_stack,
|
|
||||||
*addr);
|
|
||||||
|
|
||||||
if result != "" {
|
|
||||||
result += "\n\r";
|
|
||||||
}
|
|
||||||
|
|
||||||
result += var.as_str();
|
|
||||||
result += " = ";
|
|
||||||
|
|
||||||
for view in viewer {
|
|
||||||
match arities.pop() {
|
|
||||||
Some(n) => arities.push(n-1),
|
|
||||||
None => {}
|
|
||||||
}
|
|
||||||
|
|
||||||
if !(arities.is_empty() || result.ends_with("(")) {
|
|
||||||
result += ", ";
|
|
||||||
}
|
|
||||||
|
|
||||||
match view {
|
|
||||||
HeapCellView::Str(arity, ref name) => {
|
|
||||||
result += name.as_str();
|
|
||||||
|
|
||||||
if arity > 0 {
|
|
||||||
arities.push(arity);
|
|
||||||
result += "(";
|
|
||||||
}
|
|
||||||
},
|
|
||||||
HeapCellView::HeapVar(cell_num) => {
|
|
||||||
result += "_";
|
|
||||||
result += cell_num.to_string().as_str();
|
|
||||||
},
|
|
||||||
HeapCellView::StackVar(fr, sc) => {
|
|
||||||
result += "_s_";
|
|
||||||
result += fr.to_string().as_str();
|
|
||||||
result += "_";
|
|
||||||
result += sc.to_string().as_str();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
while let Some(&0) = arities.last() {
|
|
||||||
result += ")";
|
|
||||||
arities.pop();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
result
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn run_query(&mut self, code: Code, cg: &CodeGenerator) -> EvalResult
|
|
||||||
{
|
|
||||||
let mut succeeded = true;
|
|
||||||
let mut heap_locs = HashMap::new();
|
|
||||||
|
|
||||||
for instr in code.iter().take(1) {
|
|
||||||
succeeded = self.execute_instr(LineOrCodeOffset::from(instr));
|
|
||||||
}
|
|
||||||
|
|
||||||
if succeeded {
|
|
||||||
for (var, vr) in cg.vars() {
|
|
||||||
let addr = self.ms.registers[vr.root_register()];
|
|
||||||
heap_locs.insert((*var).clone(), addr);
|
|
||||||
}
|
|
||||||
|
|
||||||
for instr in code.iter().skip(1) {
|
|
||||||
succeeded = self.execute_instr(LineOrCodeOffset::from(instr));
|
|
||||||
if !succeeded {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if succeeded {
|
|
||||||
EvalResult::InitialQuerySuccess(heap_locs)
|
|
||||||
} else {
|
|
||||||
EvalResult::QueryFailure
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn or_stack_is_empty(&self) -> bool {
|
|
||||||
self.ms.or_stack.is_empty()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn continue_query(&mut self) -> EvalResult
|
|
||||||
{
|
|
||||||
if !self.or_stack_is_empty() {
|
|
||||||
let b = self.ms.b;
|
|
||||||
self.ms.p = self.ms.or_stack[b].bp;
|
|
||||||
|
|
||||||
let succeeded = if let CodePtr::DirEntry(p) = self.ms.p {
|
|
||||||
self.execute_instr(LineOrCodeOffset::Offset(p))
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
};
|
|
||||||
|
|
||||||
if succeeded {
|
|
||||||
EvalResult::SubsequentQuerySuccess
|
|
||||||
} else {
|
|
||||||
EvalResult::QueryFailure
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
EvalResult::QueryFailure
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn reset(&mut self) {
|
|
||||||
self.ms.reset();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl MachineState {
|
|
||||||
fn new() -> MachineState {
|
|
||||||
MachineState { h: 0,
|
|
||||||
s: 0,
|
|
||||||
p: CodePtr::TopLevel,
|
|
||||||
b: 0,
|
|
||||||
e: 0,
|
|
||||||
num_of_args: 0,
|
|
||||||
cp: CodePtr::TopLevel,
|
|
||||||
fail: false,
|
|
||||||
heap: Vec::with_capacity(256),
|
|
||||||
mode: MachineMode::Write,
|
|
||||||
and_stack: AndStack::new(),
|
|
||||||
or_stack: OrStack::new(),
|
|
||||||
registers: vec![Addr::HeapCell(0); 32],
|
|
||||||
trail: Vec::new(),
|
|
||||||
tr: 0,
|
|
||||||
hb: 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn num_frames(&self) -> usize {
|
|
||||||
self.and_stack.len() + self.or_stack.len()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn store(&self, a: Addr) -> Addr {
|
|
||||||
match a {
|
|
||||||
Addr::HeapCell(r) => self.heap[r].as_addr(r),
|
|
||||||
Addr::StackCell(fr, sc) => self.and_stack[fr][sc],
|
|
||||||
addr => addr
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn deref(&self, a: Addr) -> Addr {
|
|
||||||
let mut a = a;
|
|
||||||
|
|
||||||
loop {
|
|
||||||
let value = self.store(a);
|
|
||||||
|
|
||||||
if value.is_ref() && value != a {
|
|
||||||
a = value;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
return a;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
fn bind(&mut self, r1: Ref, a2: Addr) {
|
|
||||||
let t2 = self.store(a2);
|
|
||||||
|
|
||||||
match r1 {
|
|
||||||
Ref::StackCell(fr, sc) =>
|
|
||||||
self.and_stack[fr][sc] = t2,
|
|
||||||
Ref::HeapCell(hc) =>
|
|
||||||
self.heap[hc] = HeapCellValue::from(t2)
|
|
||||||
};
|
|
||||||
|
|
||||||
self.trail(r1);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn unify(&mut self, a1: Addr, a2: Addr) {
|
|
||||||
let mut pdl = vec![a1, a2];
|
|
||||||
|
|
||||||
self.fail = false;
|
|
||||||
|
|
||||||
while !(pdl.is_empty() || self.fail) {
|
|
||||||
let d1 = self.deref(pdl.pop().unwrap());
|
|
||||||
let d2 = self.deref(pdl.pop().unwrap());
|
|
||||||
|
|
||||||
if d1 != d2 {
|
|
||||||
match (self.store(d1), self.store(d2)) {
|
|
||||||
(Addr::HeapCell(hc), _) =>
|
|
||||||
self.bind(Ref::HeapCell(hc), d2),
|
|
||||||
(_, Addr::HeapCell(hc)) =>
|
|
||||||
self.bind(Ref::HeapCell(hc), d1),
|
|
||||||
(Addr::StackCell(fr, sc), _) =>
|
|
||||||
self.bind(Ref::StackCell(fr, sc), d2),
|
|
||||||
(_, Addr::StackCell(fr, sc)) =>
|
|
||||||
self.bind(Ref::StackCell(fr, sc), d1),
|
|
||||||
(Addr::Str(a1), Addr::Str(a2)) => {
|
|
||||||
let r1 = &self.heap[a1];
|
|
||||||
let r2 = &self.heap[a2];
|
|
||||||
|
|
||||||
if let &HeapCellValue::NamedStr(n1, ref f1) = r1 {
|
|
||||||
if let &HeapCellValue::NamedStr(n2, ref f2) = r2 {
|
|
||||||
if n1 == n2 && *f1 == *f2 {
|
|
||||||
for i in 1 .. n1 + 1 {
|
|
||||||
pdl.push(Addr::HeapCell(a1 + i));
|
|
||||||
pdl.push(Addr::HeapCell(a2 + i));
|
|
||||||
}
|
|
||||||
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
self.fail = true;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn trail(&mut self, r: Ref) {
|
|
||||||
match r {
|
|
||||||
Ref::HeapCell(hc) => {
|
|
||||||
if hc < self.hb {
|
|
||||||
self.trail.push(r);
|
|
||||||
self.tr += 1;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
Ref::StackCell(fr, _) => {
|
|
||||||
let fr_gi = self.and_stack[fr].global_index;
|
|
||||||
let b_gi = if !self.or_stack.is_empty() {
|
|
||||||
self.or_stack[self.b].global_index
|
|
||||||
} else {
|
|
||||||
0
|
|
||||||
};
|
|
||||||
|
|
||||||
if fr_gi < b_gi {
|
|
||||||
self.trail.push(r);
|
|
||||||
self.tr += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn unwind_trail(&mut self, a1: usize, a2: usize) {
|
|
||||||
for i in a1 .. a2 {
|
|
||||||
match self.trail[i] {
|
|
||||||
Ref::HeapCell(r) =>
|
|
||||||
self.heap[r] = HeapCellValue::Ref(self.trail[i]),
|
|
||||||
Ref::StackCell(fr, sc) =>
|
|
||||||
self.and_stack[fr][sc] = Addr::StackCell(fr, sc)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn execute_query_instr(&mut self, instr: &QueryInstruction) {
|
|
||||||
match instr {
|
|
||||||
&QueryInstruction::PutStructure(_, ref name, arity, reg) => {
|
|
||||||
self.heap.push(HeapCellValue::Str(self.h + 1));
|
|
||||||
self.heap.push(HeapCellValue::NamedStr(arity, name.clone()));
|
|
||||||
|
|
||||||
self[reg] = Addr::Str(self.h + 1);
|
|
||||||
|
|
||||||
self.h += 2;
|
|
||||||
},
|
|
||||||
&QueryInstruction::PutValue(norm, arg) =>
|
|
||||||
self.registers[arg] = self[norm],
|
|
||||||
&QueryInstruction::PutVariable(norm, arg) => {
|
|
||||||
self.heap.push(HeapCellValue::Ref(Ref::HeapCell(self.h)));
|
|
||||||
|
|
||||||
self[norm] = Addr::HeapCell(self.h);
|
|
||||||
self.registers[arg] = Addr::HeapCell(self.h);
|
|
||||||
|
|
||||||
self.h += 1;
|
|
||||||
},
|
|
||||||
&QueryInstruction::SetVariable(reg) => {
|
|
||||||
self.heap.push(HeapCellValue::Ref(Ref::HeapCell(self.h)));
|
|
||||||
self[reg] = Addr::HeapCell(self.h);
|
|
||||||
|
|
||||||
self.h += 1;
|
|
||||||
},
|
|
||||||
&QueryInstruction::SetValue(reg) => {
|
|
||||||
let heap_val = self[reg];
|
|
||||||
self.heap.push(HeapCellValue::from(heap_val));
|
|
||||||
|
|
||||||
self.h += 1;
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn execute_fact_instr(&mut self, instr: &FactInstruction) {
|
|
||||||
match instr {
|
|
||||||
&FactInstruction::GetStructure(_, ref name, arity, reg) => {
|
|
||||||
let addr = self.deref(self[reg]);
|
|
||||||
|
|
||||||
match self.store(addr) {
|
|
||||||
Addr::Str(a) => {
|
|
||||||
let result = &self.heap[a];
|
|
||||||
|
|
||||||
if let &HeapCellValue::NamedStr(narity, ref str) = result {
|
|
||||||
if narity == arity && *name == *str {
|
|
||||||
self.s = a + 1;
|
|
||||||
self.mode = MachineMode::Read;
|
|
||||||
} else {
|
|
||||||
self.fail = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
Addr::HeapCell(_) | Addr::StackCell(_, _) => {
|
|
||||||
self.heap.push(HeapCellValue::Str(self.h + 1));
|
|
||||||
self.heap.push(HeapCellValue::NamedStr(arity, name.clone()));
|
|
||||||
|
|
||||||
let h = self.h;
|
|
||||||
|
|
||||||
self.bind(addr.as_ref().unwrap(), Addr::HeapCell(h));
|
|
||||||
|
|
||||||
self.h += 2;
|
|
||||||
self.mode = MachineMode::Write;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
},
|
|
||||||
&FactInstruction::GetVariable(norm, arg) =>
|
|
||||||
self[norm] = self.registers[arg],
|
|
||||||
&FactInstruction::GetValue(norm, arg) => {
|
|
||||||
let norm_addr = self[norm];
|
|
||||||
let reg_addr = self.registers[arg];
|
|
||||||
|
|
||||||
self.unify(norm_addr, reg_addr);
|
|
||||||
},
|
|
||||||
&FactInstruction::UnifyVariable(reg) => {
|
|
||||||
match self.mode {
|
|
||||||
MachineMode::Read =>
|
|
||||||
self[reg] = self.heap[self.s].as_addr(self.s),
|
|
||||||
MachineMode::Write => {
|
|
||||||
self.heap.push(HeapCellValue::Ref(Ref::HeapCell(self.h)));
|
|
||||||
self[reg] = Addr::HeapCell(self.h);
|
|
||||||
self.h += 1;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
self.s += 1;
|
|
||||||
},
|
|
||||||
&FactInstruction::UnifyValue(reg) => {
|
|
||||||
let s = self.s;
|
|
||||||
|
|
||||||
match self.mode {
|
|
||||||
MachineMode::Read => {
|
|
||||||
let reg_addr = self[reg];
|
|
||||||
self.unify(reg_addr, Addr::HeapCell(s));
|
|
||||||
},
|
|
||||||
MachineMode::Write => {
|
|
||||||
let heap_val = self.store(self[reg]);
|
|
||||||
self.heap.push(HeapCellValue::from(heap_val));
|
|
||||||
self.h += 1;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
self.s += 1;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
fn execute_ctrl_instr(&mut self, code_dir: &CodeDir, instr: &ControlInstruction)
|
|
||||||
{
|
|
||||||
match instr {
|
|
||||||
&ControlInstruction::Allocate(num_cells) => {
|
|
||||||
let num_frames = self.num_frames();
|
|
||||||
|
|
||||||
self.and_stack.push(num_frames + 1, self.e, self.cp, num_cells);
|
|
||||||
|
|
||||||
self.e = self.and_stack.len() - 1;
|
|
||||||
self.p += 1;
|
|
||||||
},
|
|
||||||
&ControlInstruction::Call(ref name, arity) => {
|
|
||||||
let compiled_tl_index = code_dir.get(&(name.clone(), arity))
|
|
||||||
.map(|index| *index);
|
|
||||||
|
|
||||||
match compiled_tl_index {
|
|
||||||
Some(compiled_tl_index) => {
|
|
||||||
self.cp = self.p + 1;
|
|
||||||
self.num_of_args = arity;
|
|
||||||
self.p = CodePtr::DirEntry(compiled_tl_index);
|
|
||||||
},
|
|
||||||
None => self.fail = true
|
|
||||||
};
|
|
||||||
},
|
|
||||||
&ControlInstruction::Deallocate => {
|
|
||||||
let e = self.e;
|
|
||||||
|
|
||||||
let num_frame_e = self.and_stack.top().unwrap().global_index;
|
|
||||||
let num_frame_b = self.or_stack
|
|
||||||
.top()
|
|
||||||
.map(|fr| fr.global_index)
|
|
||||||
.unwrap_or(0);
|
|
||||||
|
|
||||||
self.p = self.and_stack[e].cp;
|
|
||||||
self.e = self.and_stack[e].e;
|
|
||||||
|
|
||||||
if num_frame_e > num_frame_b {
|
|
||||||
let top_e = self.and_stack.top().unwrap().e;
|
|
||||||
self.and_stack.drop_frames(top_e - self.e + 1);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
&ControlInstruction::Proceed =>
|
|
||||||
self.p = self.cp,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
fn execute_choice_instr(&mut self, instr: &ChoiceInstruction)
|
|
||||||
{
|
|
||||||
match instr {
|
|
||||||
&ChoiceInstruction::TryMeElse(offset) => {
|
|
||||||
let n = self.num_of_args;
|
|
||||||
let num_frames = self.num_frames();
|
|
||||||
|
|
||||||
self.or_stack.push(num_frames + 1,
|
|
||||||
self.e,
|
|
||||||
self.cp,
|
|
||||||
self.b,
|
|
||||||
self.p + offset,
|
|
||||||
self.tr,
|
|
||||||
self.h,
|
|
||||||
self.num_of_args);
|
|
||||||
|
|
||||||
self.b = self.or_stack.len() - 1;
|
|
||||||
let b = self.b;
|
|
||||||
|
|
||||||
for i in 1 .. n + 1 {
|
|
||||||
self.or_stack[b][i] = self.registers[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
self.hb = self.h;
|
|
||||||
self.p += 1;
|
|
||||||
},
|
|
||||||
&ChoiceInstruction::RetryMeElse(offset) => {
|
|
||||||
let b = self.b;
|
|
||||||
let n = self.or_stack[b].num_args();
|
|
||||||
|
|
||||||
for i in 1 .. n + 1 {
|
|
||||||
self.registers[i] = self.or_stack[b][i];
|
|
||||||
}
|
|
||||||
|
|
||||||
self.e = self.or_stack[b].e;
|
|
||||||
self.cp = self.or_stack[b].cp;
|
|
||||||
|
|
||||||
self.or_stack[b].bp = self.p + offset;
|
|
||||||
|
|
||||||
let old_tr = self.or_stack[b].tr;
|
|
||||||
let curr_tr = self.tr;
|
|
||||||
|
|
||||||
self.unwind_trail(old_tr, curr_tr);
|
|
||||||
self.tr = self.or_stack[b].tr;
|
|
||||||
|
|
||||||
self.trail.truncate(self.tr);
|
|
||||||
self.heap.truncate(self.or_stack[b].h);
|
|
||||||
|
|
||||||
self.h = self.or_stack[b].h;
|
|
||||||
self.hb = self.h;
|
|
||||||
|
|
||||||
self.p += 1;
|
|
||||||
},
|
|
||||||
&ChoiceInstruction::TrustMe => {
|
|
||||||
let b = self.b;
|
|
||||||
let n = self.or_stack[b].num_args();
|
|
||||||
|
|
||||||
for i in 1 .. n + 1 {
|
|
||||||
self.registers[i] = self.or_stack[b][i];
|
|
||||||
}
|
|
||||||
|
|
||||||
self.e = self.or_stack[b].e;
|
|
||||||
self.cp = self.or_stack[b].cp;
|
|
||||||
|
|
||||||
let old_tr = self.or_stack[b].tr;
|
|
||||||
let curr_tr = self.tr;
|
|
||||||
|
|
||||||
self.unwind_trail(old_tr, curr_tr);
|
|
||||||
|
|
||||||
self.tr = self.or_stack[b].tr;
|
|
||||||
self.trail.truncate(self.tr);
|
|
||||||
|
|
||||||
self.h = self.or_stack[b].h;
|
|
||||||
self.heap.truncate(self.h);
|
|
||||||
|
|
||||||
self.b = self.or_stack[b].b;
|
|
||||||
|
|
||||||
self.or_stack.pop();
|
|
||||||
|
|
||||||
self.hb = self.h;
|
|
||||||
self.p += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn reset(&mut self) {
|
|
||||||
self.h = 0;
|
|
||||||
self.hb = 0;
|
|
||||||
self.e = 0;
|
|
||||||
self.b = 0;
|
|
||||||
self.s = 0;
|
|
||||||
self.tr = 0;
|
|
||||||
self.p = CodePtr::TopLevel;
|
|
||||||
self.cp = CodePtr::TopLevel;
|
|
||||||
self.num_of_args = 0;
|
|
||||||
|
|
||||||
self.fail = false;
|
|
||||||
self.trail.clear();
|
|
||||||
self.heap.clear();
|
|
||||||
self.mode = MachineMode::Write;
|
|
||||||
self.and_stack.clear();
|
|
||||||
self.or_stack.clear();
|
|
||||||
self.registers = vec![Addr::HeapCell(0); 32];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
pub mod and_stack;
|
|
||||||
pub mod ast;
|
|
||||||
pub mod codegen;
|
|
||||||
pub mod heapview;
|
|
||||||
pub mod io;
|
|
||||||
pub mod iterators;
|
|
||||||
pub mod l3_parser;
|
|
||||||
pub mod machine;
|
|
||||||
pub mod or_stack;
|
|
||||||
@@ -1,112 +0,0 @@
|
|||||||
use l3::ast::*;
|
|
||||||
|
|
||||||
use std::ops::{Index, IndexMut};
|
|
||||||
use std::vec::Vec;
|
|
||||||
|
|
||||||
pub struct Frame {
|
|
||||||
pub global_index: usize,
|
|
||||||
pub e: usize,
|
|
||||||
pub cp: CodePtr,
|
|
||||||
pub b: usize,
|
|
||||||
pub bp: CodePtr,
|
|
||||||
pub tr: usize,
|
|
||||||
pub h: usize,
|
|
||||||
args: Vec<Addr>
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Frame {
|
|
||||||
fn new(global_index: usize,
|
|
||||||
e: usize,
|
|
||||||
cp: CodePtr,
|
|
||||||
b: usize,
|
|
||||||
bp: CodePtr,
|
|
||||||
tr: usize,
|
|
||||||
h: usize,
|
|
||||||
n: usize)
|
|
||||||
-> Self
|
|
||||||
{
|
|
||||||
Frame {
|
|
||||||
global_index: global_index,
|
|
||||||
e: e,
|
|
||||||
cp: cp,
|
|
||||||
b: b,
|
|
||||||
bp: bp,
|
|
||||||
tr: tr,
|
|
||||||
h: h,
|
|
||||||
args: vec![Addr::HeapCell(0); n]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn num_args(&self) -> usize {
|
|
||||||
self.args.len()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct OrStack(Vec<Frame>);
|
|
||||||
|
|
||||||
impl OrStack {
|
|
||||||
pub fn new() -> Self {
|
|
||||||
OrStack(Vec::new())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn push(&mut self,
|
|
||||||
global_index: usize,
|
|
||||||
e: usize,
|
|
||||||
cp: CodePtr,
|
|
||||||
b: usize,
|
|
||||||
bp: CodePtr,
|
|
||||||
tr: usize,
|
|
||||||
h: usize,
|
|
||||||
n: usize)
|
|
||||||
{
|
|
||||||
self.0.push(Frame::new(global_index, e, cp, b, bp, tr, h, n));
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn len(&self) -> usize {
|
|
||||||
self.0.len()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn clear(&mut self) {
|
|
||||||
self.0.clear()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn top(&self) -> Option<&Frame> {
|
|
||||||
self.0.last()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn pop(&mut self) {
|
|
||||||
self.0.pop();
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn is_empty(&self) -> bool {
|
|
||||||
self.0.is_empty()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Index<usize> for OrStack {
|
|
||||||
type Output = Frame;
|
|
||||||
|
|
||||||
fn index(&self, index: usize) -> &Self::Output {
|
|
||||||
self.0.index(index)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl IndexMut<usize> for OrStack {
|
|
||||||
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
|
|
||||||
self.0.index_mut(index)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Index<usize> for Frame {
|
|
||||||
type Output = Addr;
|
|
||||||
|
|
||||||
fn index(&self, index: usize) -> &Self::Output {
|
|
||||||
self.args.index(index - 1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl IndexMut<usize> for Frame {
|
|
||||||
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
|
|
||||||
self.args.index_mut(index - 1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user