Compare commits
1372 Commits
waalge/dir
...
waalge/new
Author | SHA1 | Date |
---|---|---|
![]() |
5a8ef1aef0 | |
![]() |
94ff20253b | |
![]() |
57311d123c | |
![]() |
e2fb28b4ce | |
![]() |
66e39898a1 | |
![]() |
e12d7e807d | |
![]() |
7a93c55d0b | |
![]() |
b5047d623a | |
![]() |
c740e4639f | |
![]() |
eec08fcbd9 | |
![]() |
18054eed1a | |
![]() |
dc38186f33 | |
![]() |
4ea6fdffe8 | |
![]() |
10c1b46bf7 | |
![]() |
5960065a03 | |
![]() |
a51f7285c1 | |
![]() |
c523b0153d | |
![]() |
51a8ddcc0b | |
![]() |
da982510dc | |
![]() |
fafb89d838 | |
![]() |
d24a71ee04 | |
![]() |
1a75568027 | |
![]() |
d1a1d0ec01 | |
![]() |
8ac09025f5 | |
![]() |
cd42f51f1a | |
![]() |
634b2e0f79 | |
![]() |
d350bc1935 | |
![]() |
362eb75329 | |
![]() |
e87d7a1101 | |
![]() |
d39d70a5d8 | |
![]() |
1227a8a7db | |
![]() |
6b04a78e78 | |
![]() |
1bc15f78ea | |
![]() |
a4aaf4d2d7 | |
![]() |
27bf40260e | |
![]() |
25e4b42cd0 | |
![]() |
6e94d502a7 | |
![]() |
7655a6ecbe | |
![]() |
b4d142ca9d | |
![]() |
fa203ba9a2 | |
![]() |
8591bedc1e | |
![]() |
1a15440d24 | |
![]() |
9dbe66bc0c | |
![]() |
342676f530 | |
![]() |
61184fbb86 | |
![]() |
5eac774443 | |
![]() |
753b41dc99 | |
![]() |
9601c1034b | |
![]() |
7966cc0165 | |
![]() |
3b3fcb666f | |
![]() |
ecf4592be1 | |
![]() |
64f7886b23 | |
![]() |
b340de2cfd | |
![]() |
ca161d8a68 | |
![]() |
def268d966 | |
![]() |
9369cbc1a3 | |
![]() |
43e859f1ba | |
![]() |
20385a7ecd | |
![]() |
97ee1a8ba6 | |
![]() |
2489e0fdd0 | |
![]() |
2b7ca0e4a1 | |
![]() |
93d0191489 | |
![]() |
e97fe332b1 | |
![]() |
8e90a933c6 | |
![]() |
7c4e044423 | |
![]() |
f42cd83f10 | |
![]() |
ab39eb82ce | |
![]() |
413932d86b | |
![]() |
8d8f91b76e | |
![]() |
a7741ec286 | |
![]() |
3e076dd895 | |
![]() |
b3e6c3ab6b | |
![]() |
b04bb40532 | |
![]() |
365b3bf5bf | |
![]() |
7f13fca1a4 | |
![]() |
4b95db4f88 | |
![]() |
523b270a8f | |
![]() |
53685dd1d5 | |
![]() |
9dd3ead3df | |
![]() |
a18af83786 | |
![]() |
5fd349f571 | |
![]() |
5d4b3e69b9 | |
![]() |
e8f74985d5 | |
![]() |
c7ae161a39 | |
![]() |
79d0e45099 | |
![]() |
f4dbe1624a | |
![]() |
19fe1d37e7 | |
![]() |
b0cad2bf1d | |
![]() |
5204831bac | |
![]() |
538181f145 | |
![]() |
31819fe197 | |
![]() |
356d845a9a | |
![]() |
e4e8ca8a6d | |
![]() |
c8731c98c7 | |
![]() |
5fe6e3f77b | |
![]() |
c6c5cddead | |
![]() |
2bbc699a25 | |
![]() |
513ca27717 | |
![]() |
e8d97028ad | |
![]() |
51b6b77db8 | |
![]() |
0060804d1a | |
![]() |
5737556efc | |
![]() |
9533903acc | |
![]() |
d5f8d3ab78 | |
![]() |
92f5bf529f | |
![]() |
7c6f3278ba | |
![]() |
9a29f4e876 | |
![]() |
a35d4f383f | |
![]() |
bdab4d99b4 | |
![]() |
b6e5bf68c5 | |
![]() |
466dfca4f2 | |
![]() |
555bbc7a48 | |
![]() |
ac9c71e32a | |
![]() |
3d77b5c378 | |
![]() |
e8cf43d7ec | |
![]() |
d3e95bd000 | |
![]() |
eb37ed0da5 | |
![]() |
4f1de2d3b5 | |
![]() |
c3af748b76 | |
![]() |
fa2aa0a3e8 | |
![]() |
a8b37820e8 | |
![]() |
7155b4e45d | |
![]() |
3fddab4724 | |
![]() |
18e79db4b2 | |
![]() |
83ac723a50 | |
![]() |
dd77fa7e53 | |
![]() |
3f149ab346 | |
![]() |
91843b2c0e | |
![]() |
43182721f5 | |
![]() |
b50fa91d4c | |
![]() |
b26e16e319 | |
![]() |
6b145d5594 | |
![]() |
75b5332288 | |
![]() |
47a15cf8b2 | |
![]() |
12c0d0bc04 | |
![]() |
d6c728c0f6 | |
![]() |
7047c7720e | |
![]() |
0f8cb19ede | |
![]() |
a9a7a4f977 | |
![]() |
799546b654 | |
![]() |
9cf908d07f | |
![]() |
4fb13af49f | |
![]() |
debbae4fda | |
![]() |
a1045352d7 | |
![]() |
16e222e997 | |
![]() |
3f2de2665d | |
![]() |
8d13b0b706 | |
![]() |
362ca2544f | |
![]() |
30e66be568 | |
![]() |
49ef3a740c | |
![]() |
7c52094b15 | |
![]() |
6413f2c1cc | |
![]() |
8a3bbfc89a | |
![]() |
defce9be4e | |
![]() |
0905146140 | |
![]() |
74d197077d | |
![]() |
7741be64f8 | |
![]() |
5879dcfd4c | |
![]() |
616dec8f03 | |
![]() |
0c0369ad61 | |
![]() |
b6d99142f9 | |
![]() |
8db4a60986 | |
![]() |
28916c1ef9 | |
![]() |
943d90a99e | |
![]() |
b7ea6ea391 | |
![]() |
5ec147e6c7 | |
![]() |
04fb11084c | |
![]() |
19e30b10f9 | |
![]() |
888b7e34c6 | |
![]() |
1f692bc93e | |
![]() |
be31a7ce38 | |
![]() |
20ac89fc33 | |
![]() |
140cb02be0 | |
![]() |
6a438bc8cd | |
![]() |
2f33c4a8f4 | |
![]() |
8933688c68 | |
![]() |
c370a4aa6a | |
![]() |
a6bc0f7157 | |
![]() |
2be76d7cda | |
![]() |
575f0f9a9a | |
![]() |
0a8f1f4930 | |
![]() |
f60df16bc2 | |
![]() |
007b85b864 | |
![]() |
038f6ecbfd | |
![]() |
f8be81baa5 | |
![]() |
9f6daa8cd5 | |
![]() |
7bfc01413b | |
![]() |
ddfe01ee88 | |
![]() |
53af366b59 | |
![]() |
8d60f08f65 | |
![]() |
6d0fe560e2 | |
![]() |
fed464278d | |
![]() |
7aefa85de1 | |
![]() |
5dfa3e7cca | |
![]() |
5414fd8f04 | |
![]() |
75c059bf65 | |
![]() |
55d381fbfc | |
![]() |
e3e889f875 | |
![]() |
a06383d333 | |
![]() |
ef89691331 | |
![]() |
4a8bec4caa | |
![]() |
e772ff1787 | |
![]() |
6c2e3272da | |
![]() |
71f90ad49f | |
![]() |
a909e9eb0a | |
![]() |
38e8c6264d | |
![]() |
9063549f2e | |
![]() |
f35afe8d65 | |
![]() |
f674f9ee97 | |
![]() |
cd0a9440e8 | |
![]() |
79cf0b8d97 | |
![]() |
c21466831c | |
![]() |
e31c6de04e | |
![]() |
8bccbd9e00 | |
![]() |
745f14ccb2 | |
![]() |
6bbc6a8f2f | |
![]() |
d337e601cb | |
![]() |
9943c2cc7a | |
![]() |
b78aee2acc | |
![]() |
efeda9a998 | |
![]() |
48535636ed | |
![]() |
d615b4f889 | |
![]() |
4003343444 | |
![]() |
0510ca58f7 | |
![]() |
ee8f608c0b | |
![]() |
d74e36d0bc | |
![]() |
ff25fbd970 | |
![]() |
b57f840cad | |
![]() |
c87f459ce7 | |
![]() |
3521a8c921 | |
![]() |
af9a785d65 | |
![]() |
1198d7a5ae | |
![]() |
0c9ea196be | |
![]() |
e9edd20c21 | |
![]() |
52a39629b7 | |
![]() |
8c2fdf9ad4 | |
![]() |
ed55f03aa2 | |
![]() |
442010d056 | |
![]() |
73522296aa | |
![]() |
ff1464b462 | |
![]() |
d8723c5497 | |
![]() |
4589c51cd3 | |
![]() |
c57009bf99 | |
![]() |
c706d6072d | |
![]() |
f9acbd3bcb | |
![]() |
047f422d0d | |
![]() |
6a6bf6f65f | |
![]() |
5943d94c6c | |
![]() |
fe205e360f | |
![]() |
7ec3f2e8df | |
![]() |
5b61a75088 | |
![]() |
be7c0c8012 | |
![]() |
f86d550ca0 | |
![]() |
3aa9e0c4b7 | |
![]() |
3fac7002d4 | |
![]() |
953ee6b5d1 | |
![]() |
b9456b5946 | |
![]() |
e174532bfd | |
![]() |
79099675d4 | |
![]() |
c2c4bddfb3 | |
![]() |
5cf0a4d294 | |
![]() |
823492c27b | |
![]() |
972e9bd763 | |
![]() |
03a348040b | |
![]() |
90d75d4a13 | |
![]() |
00b8a39236 | |
![]() |
79840248c0 | |
![]() |
f94e40daf4 | |
![]() |
cf3180996a | |
![]() |
00907c2bcc | |
![]() |
7f26db401c | |
![]() |
6b8be61b6e | |
![]() |
0d8d80e5a7 | |
![]() |
466a4f0b39 | |
![]() |
471bbe2175 | |
![]() |
b984f0455a | |
![]() |
4287fa3f4a | |
![]() |
9e866a5ec1 | |
![]() |
1d9034573b | |
![]() |
fff90f7df5 | |
![]() |
0de5cbc74e | |
![]() |
c98e32d3e9 | |
![]() |
8dfaa1bf90 | |
![]() |
a71d7c260c | |
![]() |
c92b260260 | |
![]() |
c3b287507e | |
![]() |
05a3d5fb2a | |
![]() |
842001dc0d | |
![]() |
70e760cbaa | |
![]() |
9aa9070f56 | |
![]() |
fbe6f02fd1 | |
![]() |
7435dfd0e5 | |
![]() |
d1ee90a3a0 | |
![]() |
0f905045e7 | |
![]() |
6e67fe837b | |
![]() |
c3e39301e2 | |
![]() |
39c1b5a68a | |
![]() |
b479a289cf | |
![]() |
44e42d608d | |
![]() |
7eee3ce63c | |
![]() |
10c829edfa | |
![]() |
0ff12b9246 | |
![]() |
8b869c0a32 | |
![]() |
0b6b672149 | |
![]() |
35b7066163 | |
![]() |
802e8272c5 | |
![]() |
2bb2f11090 | |
![]() |
32e6705423 | |
![]() |
520ceff83d | |
![]() |
b104356fb9 | |
![]() |
42784965d2 | |
![]() |
2cb87f4f8f | |
![]() |
f879f6d183 | |
![]() |
fe5c5650a1 | |
![]() |
5067aad0d8 | |
![]() |
7501538053 | |
![]() |
bfc93bf076 | |
![]() |
f244b9c496 | |
![]() |
50dad1fdfe | |
![]() |
cfca0da4e9 | |
![]() |
6b6bace8a5 | |
![]() |
eea8dc7d0a | |
![]() |
b158469144 | |
![]() |
f56b9bbbc7 | |
![]() |
62b1b932f9 | |
![]() |
821f7bd8c7 | |
![]() |
f848bad3f2 | |
![]() |
fdf7a81288 | |
![]() |
c454dc72eb | |
![]() |
508d88035b | |
![]() |
445ffc483d | |
![]() |
ff4a480242 | |
![]() |
0dec4dc533 | |
![]() |
cab58e5aab | |
![]() |
213ad48de7 | |
![]() |
eb4a43719c | |
![]() |
3b94717c58 | |
![]() |
52c8ca6cee | |
![]() |
72059eacee | |
![]() |
6e4a16d8e0 | |
![]() |
59bc9e04ad | |
![]() |
b36250d183 | |
![]() |
6fd9b34b92 | |
![]() |
53c461294b | |
![]() |
31627897d7 | |
![]() |
0800901135 | |
![]() |
51fd503317 | |
![]() |
0a1992acd2 | |
![]() |
224f31b1d7 | |
![]() |
56ff4ec678 | |
![]() |
7ad5491ea9 | |
![]() |
33370b8637 | |
![]() |
4249ef2509 | |
![]() |
f5c4e185d4 | |
![]() |
8a461d5bd5 | |
![]() |
4cf81a19b1 | |
![]() |
d7e9fef4d3 | |
![]() |
23a3134642 | |
![]() |
d23a5b2f11 | |
![]() |
8b30f064a2 | |
![]() |
021679b8ac | |
![]() |
a132a2e486 | |
![]() |
93a141bfa4 | |
![]() |
49ddcccd12 | |
![]() |
aefbc6e1b9 | |
![]() |
846c16087e | |
![]() |
ea8003af8f | |
![]() |
9610237616 | |
![]() |
c3a61706b5 | |
![]() |
05504b9762 | |
![]() |
663695558c | |
![]() |
0be5229f1c | |
![]() |
6ba9a312f0 | |
![]() |
dd5badd884 | |
![]() |
9ea54afd12 | |
![]() |
a6c5dbb5ad | |
![]() |
c4abf2e8f4 | |
![]() |
aa872846bb | |
![]() |
9d8fdf787c | |
![]() |
91e0e2493a | |
![]() |
1ae6640cd0 | |
![]() |
8c121f6d97 | |
![]() |
e3b1cf1093 | |
![]() |
e6bb13def6 | |
![]() |
5160ab49de | |
![]() |
9296516f5a | |
![]() |
a07f8cbc58 | |
![]() |
ec7f659539 | |
![]() |
6454266b06 | |
![]() |
6de1d91104 | |
![]() |
2dca0c4185 | |
![]() |
fbe2f82582 | |
![]() |
c9d0da0c22 | |
![]() |
4645257e62 | |
![]() |
09c065d332 | |
![]() |
f14dfdf8e1 | |
![]() |
ea032c90f2 | |
![]() |
86aed1baa5 | |
![]() |
643e43f8aa | |
![]() |
1c58da4d86 | |
![]() |
bf5a406ffb | |
![]() |
b28d4a6e9f | |
![]() |
34d5bc71b1 | |
![]() |
91aa435f37 | |
![]() |
b8bb480bff | |
![]() |
4645fd3e28 | |
![]() |
732147b36a | |
![]() |
53b5a5ccee | |
![]() |
9dc4c915f3 | |
![]() |
9e08f9b4e6 | |
![]() |
26c3e95a06 | |
![]() |
28c1922600 | |
![]() |
d36edb4e01 | |
![]() |
49190b485a | |
![]() |
327449e320 | |
![]() |
594a304190 | |
![]() |
63863c948f | |
![]() |
c286ada08d | |
![]() |
1001e83374 | |
![]() |
dfce9c1d96 | |
![]() |
67493ad847 | |
![]() |
987a5fa779 | |
![]() |
06ac851458 | |
![]() |
967c264bfe | |
![]() |
89890f3b4b | |
![]() |
30ddfa23d9 | |
![]() |
2922c0aa6f | |
![]() |
d6fd37c80e | |
![]() |
a9d782e206 | |
![]() |
5afcc9b0c1 | |
![]() |
f8236817fe | |
![]() |
beb5ac4643 | |
![]() |
754ed07408 | |
![]() |
f9719af23e | |
![]() |
976262c2e6 | |
![]() |
61a991cb23 | |
![]() |
46b82fac86 | |
![]() |
e074037838 | |
![]() |
30d3898b5b | |
![]() |
52974aed75 | |
![]() |
20e606e645 | |
![]() |
28d2ee7186 | |
![]() |
f14dab9547 | |
![]() |
5b0a1716b5 | |
![]() |
65afb11546 | |
![]() |
f2ff9a2ee3 | |
![]() |
1d16cbf386 | |
![]() |
c62821e02a | |
![]() |
8f825f68b1 | |
![]() |
fe7d744946 | |
![]() |
0145237bbe | |
![]() |
e9f7e96970 | |
![]() |
c52ba9c873 | |
![]() |
fef3626498 | |
![]() |
5da7db355f | |
![]() |
8b86ee8219 | |
![]() |
5bdea11cc1 | |
![]() |
f1cfc84e67 | |
![]() |
9907dd6c64 | |
![]() |
4bd9125b86 | |
![]() |
f695276bf7 | |
![]() |
b5ac5bc949 | |
![]() |
f0f1296906 | |
![]() |
cc9df04093 | |
![]() |
41b941e0e3 | |
![]() |
00d1927dad | |
![]() |
aeb079334e | |
![]() |
8f343abaa1 | |
![]() |
e09f6bbc87 | |
![]() |
df939e20ce | |
![]() |
7da35d5d73 | |
![]() |
579abb7d3d | |
![]() |
5024bd3f9c | |
![]() |
1b8805825b | |
![]() |
b2c42febaf | |
![]() |
d99c014bf7 | |
![]() |
1e195156d7 | |
![]() |
372b186103 | |
![]() |
de870e2529 | |
![]() |
0ebffa2b9e | |
![]() |
3ddd088780 | |
![]() |
858dfccc82 | |
![]() |
b6da42baf2 | |
![]() |
4d42c6cb19 | |
![]() |
257bd23019 | |
![]() |
216dab99d4 | |
![]() |
87f4ed359b | |
![]() |
71ed844db0 | |
![]() |
d7ec2131ef | |
![]() |
7f4ca60d9a | |
![]() |
00cd7ce97f | |
![]() |
5e1908897f | |
![]() |
2070576e46 | |
![]() |
e9e26b969a | |
![]() |
649e5163fc | |
![]() |
5694d9f9cb | |
![]() |
28515e70ec | |
![]() |
4c1bee5091 | |
![]() |
740e140c89 | |
![]() |
b367ec2113 | |
![]() |
ad3c9f24b7 | |
![]() |
c9a15194a0 | |
![]() |
cb8f51d7a5 | |
![]() |
2f9f554e78 | |
![]() |
cb4c01f46b | |
![]() |
338fc0eba6 | |
![]() |
2605dc6aa4 | |
![]() |
ed73df302a | |
![]() |
ff50d4d2cf | |
![]() |
3f46559dbe | |
![]() |
2c8abe4a69 | |
![]() |
59cfa209d7 | |
![]() |
e2bc3a9fc4 | |
![]() |
c48f15a957 | |
![]() |
e1f39ae539 | |
![]() |
5ce30b2632 | |
![]() |
8e0f32a577 | |
![]() |
3d06129d9b | |
![]() |
c3ad52b50f | |
![]() |
d6cc450ce4 | |
![]() |
c1a913f420 | |
![]() |
7f38b55c1c | |
![]() |
c16bd06e97 | |
![]() |
edf82f773c | |
![]() |
f5c4f4cb37 | |
![]() |
489eff7f5b | |
![]() |
e28b0df840 | |
![]() |
050d003b27 | |
![]() |
f306f1715a | |
![]() |
3bc3792aa3 | |
![]() |
4ca73c4cdf | |
![]() |
c1c2cd97b7 | |
![]() |
a3c14d881d | |
![]() |
7ff6eba869 | |
![]() |
ea3e79c132 | |
![]() |
27b3536f09 | |
![]() |
e87063824c | |
![]() |
eadf709411 | |
![]() |
b546e42766 | |
![]() |
8881a88ae3 | |
![]() |
1ed4fa1c69 | |
![]() |
81219cfbdd | |
![]() |
26ef25ba8d | |
![]() |
ff0407a245 | |
![]() |
6d7b851c70 | |
![]() |
c5de9adcd3 | |
![]() |
c86978b5ac | |
![]() |
8a6957dfd0 | |
![]() |
8c67be55ce | |
![]() |
83c0566afb | |
![]() |
392b54aa0e | |
![]() |
4cbde9942a | |
![]() |
6df1fcb9b0 | |
![]() |
f8ce46d0f4 | |
![]() |
30436a8a9c | |
![]() |
893e9c9855 | |
![]() |
878298cc8e | |
![]() |
967f4348ed | |
![]() |
0a660c6a21 | |
![]() |
99c35a6459 | |
![]() |
a124bdbb05 | |
![]() |
7b71389519 | |
![]() |
ef70c6b8a8 | |
![]() |
1070347203 | |
![]() |
b2661ef90a | |
![]() |
68f1dcc65d | |
![]() |
0e9baf4944 | |
![]() |
2f61f59b60 | |
![]() |
14903f7352 | |
![]() |
b669db8516 | |
![]() |
b3d0c3ec04 | |
![]() |
a44ed4c1a8 | |
![]() |
b1f0dfdacd | |
![]() |
d8d2fb0ebc | |
![]() |
58779401e8 | |
![]() |
fc0e88018e | |
![]() |
1091eba3c3 | |
![]() |
03a5a9293c | |
![]() |
7cb548a749 | |
![]() |
2cb2c7fa1f | |
![]() |
390bccd406 | |
![]() |
92a1da69d9 | |
![]() |
3dd94983bd | |
![]() |
46c7cb797a | |
![]() |
ebe415cfc9 | |
![]() |
5c59b816ea | |
![]() |
91a7e77ab4 | |
![]() |
897b5d1d7e | |
![]() |
3020af7cd7 | |
![]() |
cbf3ef2854 | |
![]() |
d7574e738f | |
![]() |
999e408a28 | |
![]() |
7b5ad961e2 | |
![]() |
cb1ca84dad | |
![]() |
30dd1f60e7 | |
![]() |
75b076552c | |
![]() |
3c332ca42a | |
![]() |
26f68c2fb4 | |
![]() |
fd226be51f | |
![]() |
a8c8cf41cf | |
![]() |
963d275bb8 | |
![]() |
21b60896f0 | |
![]() |
f950ae7d3d | |
![]() |
9e78f0fc2a | |
![]() |
61a021f9e3 | |
![]() |
d05d8e7de6 | |
![]() |
a9c8054819 | |
![]() |
db8eb6a108 | |
![]() |
925a11be69 | |
![]() |
24560e9acd | |
![]() |
6c052f44a1 | |
![]() |
3c66da75d6 | |
![]() |
9d4c09c722 | |
![]() |
0b2786e335 | |
![]() |
063f3d0835 | |
![]() |
c5faffe946 | |
![]() |
949f16f34a | |
![]() |
945a3f743b | |
![]() |
4f99c81dee | |
![]() |
ff4ddfbe1b | |
![]() |
d39dbd6697 | |
![]() |
d25b8f91c7 | |
![]() |
23713ce6fa | |
![]() |
17ddbfaafa | |
![]() |
5fc338a1eb | |
![]() |
5cb1e23008 | |
![]() |
cac119338d | |
![]() |
aa3896e92a | |
![]() |
79ccc55499 | |
![]() |
dac3308620 | |
![]() |
8ed930ac5a | |
![]() |
3cdb21ad6b | |
![]() |
a11b1fa56a | |
![]() |
9322020a5e | |
![]() |
f50f7e42db | |
![]() |
9d49be46b8 | |
![]() |
033cc26313 | |
![]() |
1d462314c4 | |
![]() |
7d67f1497c | |
![]() |
b63bd9b9e0 | |
![]() |
2abf626e25 | |
![]() |
fdbe811bf1 | |
![]() |
b27fcf38e5 | |
![]() |
7c5b9aa35e | |
![]() |
d22ee6e086 | |
![]() |
0ba6d23efa | |
![]() |
e02bc2a58a | |
![]() |
98bd61a0cd | |
![]() |
b5f27026e2 | |
![]() |
ce2c723d0c | |
![]() |
21b1e29f09 | |
![]() |
a6003c3be9 | |
![]() |
a5a0734629 | |
![]() |
075668b52e | |
![]() |
54a89d3e69 | |
![]() |
a3f7b48ec3 | |
![]() |
4e8042fd06 | |
![]() |
eee1d1bf1e | |
![]() |
96387e3437 | |
![]() |
80858387f6 | |
![]() |
a09069b828 | |
![]() |
0f9dbfd874 | |
![]() |
ee280bc309 | |
![]() |
c20ff6b160 | |
![]() |
5cec2544b3 | |
![]() |
25e9db4f6c | |
![]() |
dc9bab4f5c | |
![]() |
bee2b712de | |
![]() |
4f8e900aac | |
![]() |
898ef74457 | |
![]() |
8495f98c1d | |
![]() |
61936cb91e | |
![]() |
d1ba8db889 | |
![]() |
6515efeb73 | |
![]() |
b09e0316fa | |
![]() |
9986bc6bfd | |
![]() |
1caed3e87c | |
![]() |
3f254dbe6b | |
![]() |
fd50473a32 | |
![]() |
038c5b2d34 | |
![]() |
cdf564fc9d | |
![]() |
0343aeca34 | |
![]() |
3055c5ef52 | |
![]() |
191a3e9134 | |
![]() |
e71470747f | |
![]() |
9127dcdd6e | |
![]() |
8f31b45e36 | |
![]() |
f10cf73905 | |
![]() |
22b618116e | |
![]() |
502a13756a | |
![]() |
961806617f | |
![]() |
3820d2af14 | |
![]() |
7af4ef53ab | |
![]() |
1d72838f83 | |
![]() |
b16880a170 | |
![]() |
cc99eceda8 | |
![]() |
5840ce34af | |
![]() |
7b32d4ae30 | |
![]() |
945b4155cd | |
![]() |
97247ce949 | |
![]() |
b6b52ba508 | |
![]() |
f02b9b0f0c | |
![]() |
4fbb4fe2db | |
![]() |
7e8e959251 | |
![]() |
a57dcf3307 | |
![]() |
435dd0d213 | |
![]() |
df898bf239 | |
![]() |
1f530f3b24 | |
![]() |
0e0bed3c9d | |
![]() |
d4069148c7 | |
![]() |
be7d07fa99 | |
![]() |
c169596c76 | |
![]() |
191e4d47b3 | |
![]() |
ec18127191 | |
![]() |
80a9393db7 | |
![]() |
ee54266d1f | |
![]() |
37627e3527 | |
![]() |
6ba74125c7 | |
![]() |
cf86a20256 | |
![]() |
c7dcb2c256 | |
![]() |
22b86a5f82 | |
![]() |
d581183cc6 | |
![]() |
b761d6a76d | |
![]() |
bffa678178 | |
![]() |
7f0df40b4e | |
![]() |
c51741cc35 | |
![]() |
ebd6c3a56e | |
![]() |
ace58e368c | |
![]() |
77faee672e | |
![]() |
bbe7c0bc01 | |
![]() |
96da70149d | |
![]() |
d6cc9bdfbe | |
![]() |
d73f8fd6c2 | |
![]() |
cb0ae0c074 | |
![]() |
d55b7844f0 | |
![]() |
2b5ed95df5 | |
![]() |
836e853827 | |
![]() |
9d99b509b2 | |
![]() |
fe6710935d | |
![]() |
e944f10372 | |
![]() |
49ca7e1f75 | |
![]() |
a9d596f4cb | |
![]() |
c906501836 | |
![]() |
64f580bb82 | |
![]() |
9636a4de03 | |
![]() |
bc161f761b | |
![]() |
a578728a94 | |
![]() |
ed9f5c6ef7 | |
![]() |
877d10ef22 | |
![]() |
eb07365e73 | |
![]() |
94f383762c | |
![]() |
bf429fbdbf | |
![]() |
dcec8ecfe6 | |
![]() |
541d96f558 | |
![]() |
275db2fd11 | |
![]() |
ae396c0224 | |
![]() |
1edd1a1fa3 | |
![]() |
e9122de061 | |
![]() |
dabaae8ca6 | |
![]() |
97b0cf6813 | |
![]() |
eb709d6fc3 | |
![]() |
fab6d5aff7 | |
![]() |
8e558d893f | |
![]() |
0d599f7e2d | |
![]() |
23a22a65cb | |
![]() |
a3fbe6c155 | |
![]() |
e217423145 | |
![]() |
bdd84dc952 | |
![]() |
892da06e14 | |
![]() |
4c97240900 | |
![]() |
0f926d3c31 | |
![]() |
bff822ea7f | |
![]() |
59996850c1 | |
![]() |
8ffa68d2f0 | |
![]() |
c9ab1aec98 | |
![]() |
f8377af0c8 | |
![]() |
9c5556aa1e | |
![]() |
25ebdc2527 | |
![]() |
ad4840958c | |
![]() |
f14bab69c0 | |
![]() |
2bc433f61e | |
![]() |
b146db8c95 | |
![]() |
52795692d6 | |
![]() |
966a20f691 | |
![]() |
4d432513e0 | |
![]() |
4097d1edb2 | |
![]() |
fbeb611e5f | |
![]() |
3e922c0a52 | |
![]() |
c7cd89d127 | |
![]() |
df3baa082e | |
![]() |
c9dd281b45 | |
![]() |
27eb1a3e04 | |
![]() |
e14f091b86 | |
![]() |
d971d9818b | |
![]() |
af6c107187 | |
![]() |
06ca22c26a | |
![]() |
4e928f39db | |
![]() |
2aaa46e54c | |
![]() |
c6ef37cc5c | |
![]() |
4e0aaf970f | |
![]() |
62963f7fc2 | |
![]() |
7d8fdc0f22 | |
![]() |
258b5abf23 | |
![]() |
3b55a32583 | |
![]() |
58d586c5cf | |
![]() |
8f84eb382f | |
![]() |
9a52258e14 | |
![]() |
2f72510102 | |
![]() |
7c2bae0904 | |
![]() |
658984e157 | |
![]() |
5d6bcaabe9 | |
![]() |
8e8e0de044 | |
![]() |
6a4841dd7f | |
![]() |
69aefc8c48 | |
![]() |
362acd43a3 | |
![]() |
dd1c7d675f | |
![]() |
50faf81c0f | |
![]() |
b68f99cf24 | |
![]() |
c2bc5848dd | |
![]() |
900b73b21a | |
![]() |
fbda31d980 | |
![]() |
7a2537432a | |
![]() |
a7b9d4bb22 | |
![]() |
30841fe000 | |
![]() |
1134b8d7d0 | |
![]() |
c2dc47fa0b | |
![]() |
26e563a9be | |
![]() |
775a34bc47 | |
![]() |
3df5bcd96d | |
![]() |
70ea3c9598 | |
![]() |
2db15d59be | |
![]() |
bbc9fc5762 | |
![]() |
cf61387a41 | |
![]() |
93347d8e7b | |
![]() |
5b4fedd084 | |
![]() |
41fdcbdfae | |
![]() |
bfcfc5c41b | |
![]() |
5272f5ecee | |
![]() |
14f1025f0b | |
![]() |
c766f44601 | |
![]() |
c29d163900 | |
![]() |
a703db4d14 | |
![]() |
3762473a60 | |
![]() |
aadf3cfb48 | |
![]() |
bfb4455e0f | |
![]() |
84c4ccaf4c | |
![]() |
4ff11f4229 | |
![]() |
2b8e99a1b8 | |
![]() |
d698f76e3c | |
![]() |
ff5491caa0 | |
![]() |
d18caaeecb | |
![]() |
50c37c7a14 | |
![]() |
2018a18d15 | |
![]() |
46c357df7b | |
![]() |
8d59ba1c77 | |
![]() |
a15fead982 | |
![]() |
20917bbd5b | |
![]() |
028528899c | |
![]() |
da6e5ec6d1 | |
![]() |
c7dd4d0e48 | |
![]() |
fc3bc4d9ff | |
![]() |
70d4d7fdeb | |
![]() |
b0eade209b | |
![]() |
b6b57c776f | |
![]() |
9e3f348c6c | |
![]() |
0ccfe60072 | |
![]() |
ac0c73a56a | |
![]() |
3582c5569d | |
![]() |
4c5a449d83 | |
![]() |
6e2f9b9eb9 | |
![]() |
056e3d76ea | |
![]() |
6c6be3f53d | |
![]() |
51f1da2505 | |
![]() |
b807d58e89 | |
![]() |
dc195b22d4 | |
![]() |
713b16e25d | |
![]() |
d1c784ed49 | |
![]() |
3938d74bb6 | |
![]() |
6b97ab71fe | |
![]() |
4ab3b61200 | |
![]() |
575dde9885 | |
![]() |
8702c736d0 | |
![]() |
806a74c192 | |
![]() |
9f96e4bc5a | |
![]() |
a12c374258 | |
![]() |
cf51b30045 | |
![]() |
3c8460e6af | |
![]() |
20ce19dfb1 | |
![]() |
0e2995e16e | |
![]() |
3b4c6cb2aa | |
![]() |
e25be7643e | |
![]() |
982eff449e | |
![]() |
b46206bfe2 | |
![]() |
bcc2a0fd12 | |
![]() |
258c224e21 | |
![]() |
d8cdeba6fd | |
![]() |
551941392e | |
![]() |
444bccf19c | |
![]() |
a83220c8d9 | |
![]() |
3a534271e7 | |
![]() |
81e93b4309 | |
![]() |
3a7a0c1971 | |
![]() |
16c15ee48a | |
![]() |
8584adc1b7 | |
![]() |
ede6c22267 | |
![]() |
115ff61abe | |
![]() |
78d2049d7b | |
![]() |
09ca2b4955 | |
![]() |
defd36ad8c | |
![]() |
1ab6d050af | |
![]() |
589bb9a4b3 | |
![]() |
9d563612f3 | |
![]() |
4c00c9e7de | |
![]() |
1431bec32f | |
![]() |
b15e6c296b | |
![]() |
ae0b428658 | |
![]() |
00e1942999 | |
![]() |
dc61e11813 | |
![]() |
36a0b317ad | |
![]() |
3c81ebf137 | |
![]() |
51f1f2b67f | |
![]() |
e523ae63f3 | |
![]() |
3a44c45b48 | |
![]() |
eda4e259d6 | |
![]() |
82fc82ceee | |
![]() |
956c3d6cf0 | |
![]() |
b50e4ab63a | |
![]() |
9ee2d58ba3 | |
![]() |
50ebfc6090 | |
![]() |
54a1b50138 | |
![]() |
bf96c3afd2 | |
![]() |
cb6fd59dbd | |
![]() |
25a837ab3f | |
![]() |
8a90e9eda0 | |
![]() |
94f9fa9cab | |
![]() |
0f10b343f1 | |
![]() |
51cc7d68eb | |
![]() |
1f6e719fde | |
![]() |
2b4137dc24 | |
![]() |
af90b38bf8 | |
![]() |
6fa272bd34 | |
![]() |
42fdecf41f | |
![]() |
858e45f3f3 | |
![]() |
3d131a5d09 | |
![]() |
59c784778e | |
![]() |
e67d5863a1 | |
![]() |
627c6b576e | |
![]() |
f79b37d551 | |
![]() |
d27ea98a8f | |
![]() |
86146ae7f4 | |
![]() |
81e29539c8 | |
![]() |
e439cb5924 | |
![]() |
0e2b8ae251 | |
![]() |
1796147264 | |
![]() |
9f263c46f8 | |
![]() |
328514182e | |
![]() |
06672fce05 | |
![]() |
d26524048e | |
![]() |
c7af27a6ba | |
![]() |
f934e87b1d | |
![]() |
cda1716d47 | |
![]() |
742a728d53 | |
![]() |
316842876d | |
![]() |
4bd8ab890a | |
![]() |
0ae631a1fe | |
![]() |
4a8fecb70a | |
![]() |
8b62873ef5 | |
![]() |
ff462fa8ea | |
![]() |
f722af1149 | |
![]() |
2216f387c3 | |
![]() |
7992a50bec | |
![]() |
30a6b77116 | |
![]() |
c50a9cb5bd | |
![]() |
394cac86b8 | |
![]() |
4fc65cc600 | |
![]() |
43e84d7af7 | |
![]() |
c7a1ff0959 | |
![]() |
355e38d6e2 | |
![]() |
412945af3a | |
![]() |
aa51ce3e3e | |
![]() |
71cfb6f6af | |
![]() |
7b452c21f0 | |
![]() |
4c60be368e | |
![]() |
b6acdde552 | |
![]() |
d06f2f6008 | |
![]() |
eefd26c6fa | |
![]() |
fb56700bde | |
![]() |
89e518f878 | |
![]() |
ba76c1d2cf | |
![]() |
022503e254 | |
![]() |
1b1636ab0e | |
![]() |
0cfcd78039 | |
![]() |
8c619954d3 | |
![]() |
ceb6d63e95 | |
![]() |
6a10be3e82 | |
![]() |
a0ec92897b | |
![]() |
2cd1379aec | |
![]() |
c0c9f2f432 | |
![]() |
058a190294 | |
![]() |
51079b8590 | |
![]() |
4015550f55 | |
![]() |
249581e1bc | |
![]() |
8fdedb754e | |
![]() |
88e21449c5 | |
![]() |
5c688b1404 | |
![]() |
07122aaa88 | |
![]() |
b25e82ed36 | |
![]() |
772e73ae48 | |
![]() |
3ac35f4e00 | |
![]() |
d0bc782f75 | |
![]() |
92488e535a | |
![]() |
825e65d7a3 | |
![]() |
4b04517aba | |
![]() |
2647e4aae6 | |
![]() |
0a1e0d7bee | |
![]() |
b17b7f287c | |
![]() |
7c4cabada9 | |
![]() |
38e8255328 | |
![]() |
c50d4d1396 | |
![]() |
1503b525b2 | |
![]() |
858a9621fc | |
![]() |
1f411cde0e | |
![]() |
2dab62857f | |
![]() |
832ca81a8c | |
![]() |
7015a9badc | |
![]() |
2159053cb5 | |
![]() |
a46a7e82b7 | |
![]() |
f7dd2de17b | |
![]() |
6ce30bd949 | |
![]() |
d5820bb20a | |
![]() |
2980e8e21d | |
![]() |
c2725abcea | |
![]() |
a23bc32fa2 | |
![]() |
40c0fa7d77 | |
![]() |
7645a9460f | |
![]() |
6c039708c3 | |
![]() |
777d30b8ac | |
![]() |
4adedaac15 | |
![]() |
1ca81ec133 | |
![]() |
d04094560b | |
![]() |
4bb424ba78 | |
![]() |
5945a9515b | |
![]() |
5068da3a17 | |
![]() |
771f6d1601 | |
![]() |
689a41ded4 | |
![]() |
45177cd08b | |
![]() |
63f96d13ca | |
![]() |
78b0789cbc | |
![]() |
abd18656e3 | |
![]() |
2ed91780f4 | |
![]() |
7118253401 | |
![]() |
7680d33663 | |
![]() |
6869f73033 | |
![]() |
1567e42875 | |
![]() |
0382e5ce12 | |
![]() |
df992cba67 | |
![]() |
9ab458dcc6 | |
![]() |
ed909055b5 | |
![]() |
308fb47e40 | |
![]() |
dfa0378404 | |
![]() |
3f8f624a7b | |
![]() |
58d98b3325 | |
![]() |
b6f6064aaf | |
![]() |
b80db2f7f8 | |
![]() |
d53d2665b2 | |
![]() |
c910e0054e | |
![]() |
7073fd29b3 | |
![]() |
8b89ba3b93 | |
![]() |
d51374aac1 | |
![]() |
3675762c3e | |
![]() |
90aea6476a | |
![]() |
6ce85e1662 | |
![]() |
49ae8152f8 | |
![]() |
8a3a465237 | |
![]() |
cdcd8172e6 | |
![]() |
318ae6aad4 | |
![]() |
5243c36ed6 | |
![]() |
18db1c394a | |
![]() |
f101581813 | |
![]() |
0d2ac952d0 | |
![]() |
446ef11606 | |
![]() |
d50fb99b75 | |
![]() |
7d319077e6 | |
![]() |
5d56d41a68 | |
![]() |
2f694b01cb | |
![]() |
4eebd4628b | |
![]() |
7427bac4a0 | |
![]() |
598ec5eaef | |
![]() |
49bd4ba33d | |
![]() |
d2202a705c | |
![]() |
4dd17dacf3 | |
![]() |
3e283a59ec | |
![]() |
46c58dbd61 | |
![]() |
28b699c86a | |
![]() |
5f8e256050 | |
![]() |
17832fc5af | |
![]() |
d6f74b5932 | |
![]() |
c0513da032 | |
![]() |
f6eff7ec58 | |
![]() |
5986163ba7 | |
![]() |
d965467a53 | |
![]() |
c550b4766d | |
![]() |
e48ac6b592 | |
![]() |
763516eb96 | |
![]() |
699d0a537c | |
![]() |
66ade8e3e3 | |
![]() |
c4221730bf | |
![]() |
41e26b216b | |
![]() |
a08405c607 | |
![]() |
e5801f9c19 | |
![]() |
10b9dc2042 | |
![]() |
596ce49327 | |
![]() |
e8bcbecf31 | |
![]() |
55f89a7ff4 | |
![]() |
52dfc13f8f | |
![]() |
c764a6f99c | |
![]() |
4649a5a9d2 | |
![]() |
8964675670 | |
![]() |
68d9a21c6a | |
![]() |
a86f08c6d1 | |
![]() |
7a6ddc45a0 | |
![]() |
44021cde19 | |
![]() |
9335522df4 | |
![]() |
98cb01413b | |
![]() |
c2bf6e5682 | |
![]() |
a524836c94 | |
![]() |
524d0dadf5 | |
![]() |
d56d5180cf | |
![]() |
bd61a2ddf3 | |
![]() |
8a1c824dd7 | |
![]() |
78ff6cf178 | |
![]() |
135dbd8335 | |
![]() |
fb6cbbec8b | |
![]() |
d131ec563b | |
![]() |
add513790d | |
![]() |
82ceb5b696 | |
![]() |
4aa5bda9eb | |
![]() |
83f0dd2cbe | |
![]() |
fb2ca0e3e0 | |
![]() |
a2068ff062 | |
![]() |
335560b81f | |
![]() |
5e2a78173b | |
![]() |
4c278e2f9d | |
![]() |
dbd4fe2aab | |
![]() |
14a6141046 | |
![]() |
37ec2b121b | |
![]() |
f5fb84f104 | |
![]() |
3c11c95e01 | |
![]() |
b4837c7ee6 | |
![]() |
3fc469b7c7 | |
![]() |
47596f0324 | |
![]() |
1bcc9e8524 | |
![]() |
8e75007a5f | |
![]() |
38d15c677f | |
![]() |
1ca3499128 | |
![]() |
eb0b4dd6d8 | |
![]() |
b8737a1021 | |
![]() |
534eb62a07 | |
![]() |
1cab479b81 | |
![]() |
2f80d07132 | |
![]() |
f4310bcf33 | |
![]() |
ae3053522e | |
![]() |
794fc93084 | |
![]() |
0b38855ce4 | |
![]() |
ced818c455 | |
![]() |
0fb9837ddf | |
![]() |
984237075a | |
![]() |
74b8ab62b2 | |
![]() |
a4aa51ed2d | |
![]() |
ecc5769c64 | |
![]() |
5b018b7c07 | |
![]() |
4ca8681ca0 | |
![]() |
1ecdf38842 | |
![]() |
ee4001d2c8 | |
![]() |
91d4cb9b12 | |
![]() |
4650c64f6b | |
![]() |
f379039efc | |
![]() |
1dea348a2e | |
![]() |
7b915b7dcf | |
![]() |
d808197507 | |
![]() |
bc0824f4eb | |
![]() |
9a4f181a0f | |
![]() |
06347c3efa | |
![]() |
c711a97e69 | |
![]() |
15efeb3069 | |
![]() |
5381762e50 | |
![]() |
76ff09ba0e | |
![]() |
87087a1811 | |
![]() |
3c3a7f2423 | |
![]() |
65fb3a640a | |
![]() |
a72628a4dc | |
![]() |
a45001376d | |
![]() |
d042d55d42 | |
![]() |
9782c094b7 | |
![]() |
8ba5946c32 | |
![]() |
5cfc3de7bf | |
![]() |
6b70292dfb | |
![]() |
1de7b2866a | |
![]() |
819a0a20e6 | |
![]() |
c9b01ab365 | |
![]() |
85901dc141 | |
![]() |
40e1d39f8b | |
![]() |
33d6d3049e | |
![]() |
e566c4e1de | |
![]() |
dfe433ea46 | |
![]() |
097d1fa893 | |
![]() |
437a95bfe8 | |
![]() |
a87a8a7b35 | |
![]() |
dca09811c1 | |
![]() |
fb967d4c7b | |
![]() |
51c44c6a30 | |
![]() |
cd3a02416f | |
![]() |
756e16c14b | |
![]() |
baa6917af5 | |
![]() |
d01766d735 | |
![]() |
67986d9416 | |
![]() |
d4b9f22ac3 | |
![]() |
1715496d5b | |
![]() |
0e7f1597bf | |
![]() |
b075d85b40 | |
![]() |
b3494a7f63 | |
![]() |
a7062ccb88 | |
![]() |
747e057d05 | |
![]() |
379368c530 | |
![]() |
2f0211a7b1 | |
![]() |
780a61e3e8 | |
![]() |
d3fe241ccd | |
![]() |
7883aff5f7 | |
![]() |
89c55a23fa | |
![]() |
0eec4c188a | |
![]() |
084b900b2a | |
![]() |
c6f764d2db | |
![]() |
139226cdab | |
![]() |
c1b8040ae2 | |
![]() |
961e323c36 | |
![]() |
051e9a6851 | |
![]() |
690e41261e | |
![]() |
be20426329 | |
![]() |
f5a49c4df4 | |
![]() |
6d90c27587 | |
![]() |
2600937447 | |
![]() |
b138cb0ccd | |
![]() |
649039c993 | |
![]() |
050c41c8dc | |
![]() |
8cf92ce8ed | |
![]() |
c95f43ae07 | |
![]() |
20aa54b5ca | |
![]() |
a45e04fd9b | |
![]() |
2456801b17 | |
![]() |
f4d0f231d7 | |
![]() |
80e4a5c6a2 | |
![]() |
ae216bd932 | |
![]() |
6ecb3f08b0 | |
![]() |
0ff64e3bac | |
![]() |
e14d51600f | |
![]() |
2c2f3c90fb | |
![]() |
05eb281f40 | |
![]() |
e4ef386c44 | |
![]() |
ab3a418b9c | |
![]() |
4a1ae9f412 | |
![]() |
ca4a9fcd3d | |
![]() |
8af253e1df | |
![]() |
2f7784f31e | |
![]() |
eda388fb29 | |
![]() |
252f68de17 | |
![]() |
367dabafb5 | |
![]() |
f464eb3702 | |
![]() |
0d99afe5e2 | |
![]() |
90c7753201 | |
![]() |
65984ed15b | |
![]() |
dba0e11ba7 | |
![]() |
fc948f0029 | |
![]() |
c45caaefc8 | |
![]() |
09f889b121 | |
![]() |
586a2d7972 | |
![]() |
71a941e0b0 | |
![]() |
6254eeb2ed | |
![]() |
f7d278a472 | |
![]() |
1d9878c5ee | |
![]() |
624fdee9ea | |
![]() |
36c80f36c1 | |
![]() |
29599879b2 | |
![]() |
6a1b2db698 | |
![]() |
7bf22fa58b | |
![]() |
281a8363c0 | |
![]() |
bfa4cc2efc | |
![]() |
a45ff692a6 | |
![]() |
db79468435 | |
![]() |
aca79bd728 | |
![]() |
3189a60bdb | |
![]() |
80b950b8aa | |
![]() |
186e1235fd | |
![]() |
1ee7492f1f | |
![]() |
49a0a91103 | |
![]() |
f5c7d222aa | |
![]() |
5aecb96668 | |
![]() |
0b8266dfd1 | |
![]() |
02948616cd | |
![]() |
a689b8748f | |
![]() |
4e3ced5b75 | |
![]() |
018453f6b1 | |
![]() |
f03ed41e03 | |
![]() |
03dd13dc7d | |
![]() |
e8fa8f5423 | |
![]() |
c6f90a999b | |
![]() |
389699f485 | |
![]() |
dcb3a9b45b | |
![]() |
3545bad3c4 | |
![]() |
52ebc9b6c1 | |
![]() |
58b327e5b3 | |
![]() |
2f4319f162 | |
![]() |
960a15c4ec | |
![]() |
72b6f0f847 | |
![]() |
6eeb282dee | |
![]() |
518bea5be4 | |
![]() |
18ea44adb0 | |
![]() |
55dd1a1a56 | |
![]() |
02ce3761ae | |
![]() |
8641c305f4 | |
![]() |
5ad8b520fd | |
![]() |
5a51764cff | |
![]() |
a099c01734 | |
![]() |
c0f09856d3 | |
![]() |
62660e04b5 | |
![]() |
ae9de11e77 | |
![]() |
947c118175 | |
![]() |
9704cafefe | |
![]() |
55ae708e3e | |
![]() |
2b7e7ead1c | |
![]() |
7d4e136467 | |
![]() |
fd83c9a739 | |
![]() |
b3714ca9d0 | |
![]() |
2c61ecd4bb | |
![]() |
a3afb62861 | |
![]() |
95af421f95 | |
![]() |
05b6b2a97d | |
![]() |
c025073056 | |
![]() |
f6e163d16d | |
![]() |
5bcc425f0f | |
![]() |
023be88bf6 | |
![]() |
f94c8213b6 | |
![]() |
0854d71836 | |
![]() |
d731757123 | |
![]() |
96959011e9 | |
![]() |
ba3265054c | |
![]() |
7cee9a4d15 | |
![]() |
cd726b561e | |
![]() |
59362e3d8c | |
![]() |
65bb7e48e2 | |
![]() |
c359bd35d7 | |
![]() |
83ade9335f | |
![]() |
5e097d42ba | |
![]() |
d25bb9ae60 | |
![]() |
4e4a477ff1 | |
![]() |
17eef195a9 | |
![]() |
266b6bbb7d | |
![]() |
60ac8ab591 | |
![]() |
675b737898 | |
![]() |
4f7f39292d | |
![]() |
00b255e960 | |
![]() |
f3cab94ae1 | |
![]() |
75e18d485d | |
![]() |
a6b230aad4 | |
![]() |
7e531d0da1 | |
![]() |
b6ac39f322 | |
![]() |
ef2fc57ca9 | |
![]() |
f1100e901d | |
![]() |
de2791fe82 | |
![]() |
0061bcf78d | |
![]() |
e8a71cd63b | |
![]() |
03efb46e6f | |
![]() |
55887d3a45 |
|
@ -1,3 +1,4 @@
|
|||
Cargo.lock linguist-generated=true merge=binary linguist-vendored
|
||||
Cargo.nix linguist-generated=true merge=binary linguist-vendored
|
||||
flake.lock linguist-generated=true merge=binary linguist-vendored
|
||||
**/*.snap merge=binary linguist-vendored
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
* @aiken-lang/maintainers
|
|
@ -0,0 +1,5 @@
|
|||
- name: Musl build setup
|
||||
if: ${{ runner.os == 'Linux' }}
|
||||
run: |
|
||||
sudo apt-get install -y pkg-config libssl-dev musl musl-dev musl-tools
|
||||
rustup target add x86_64-unknown-linux-musl
|
|
@ -1,137 +1,363 @@
|
|||
# This file was autogenerated by cargo-dist: https://opensource.axo.dev/cargo-dist/
|
||||
#
|
||||
# Copyright 2022-2024, axodotdev
|
||||
# SPDX-License-Identifier: MIT or Apache-2.0
|
||||
#
|
||||
# CI that:
|
||||
#
|
||||
# * checks for a Git Tag that looks like a release
|
||||
# * builds artifacts with cargo-dist (archives, installers, hashes)
|
||||
# * uploads those artifacts to temporary workflow zip
|
||||
# * on success, uploads the artifacts to a GitHub Release
|
||||
#
|
||||
# Note that the GitHub Release will be created with a generated
|
||||
# title/body based on your changelogs.
|
||||
|
||||
name: Release
|
||||
permissions:
|
||||
"contents": "write"
|
||||
|
||||
# This task will run whenever you push a git tag that looks like a version
|
||||
# like "1.0.0", "v0.1.0-prerelease.1", "my-app/0.1.0", "releases/v1.0.0", etc.
|
||||
# Various formats will be parsed into a VERSION and an optional PACKAGE_NAME, where
|
||||
# PACKAGE_NAME must be the name of a Cargo package in your workspace, and VERSION
|
||||
# must be a Cargo-style SemVer Version (must have at least major.minor.patch).
|
||||
#
|
||||
# If PACKAGE_NAME is specified, then the announcement will be for that
|
||||
# package (erroring out if it doesn't have the given version or isn't cargo-dist-able).
|
||||
#
|
||||
# If PACKAGE_NAME isn't specified, then the announcement will be for all
|
||||
# (cargo-dist-able) packages in the workspace with that version (this mode is
|
||||
# intended for workspaces with only one dist-able package, or with all dist-able
|
||||
# packages versioned/released in lockstep).
|
||||
#
|
||||
# If you push multiple tags at once, separate instances of this workflow will
|
||||
# spin up, creating an independent announcement for each one. However, GitHub
|
||||
# will hard limit this to 3 tags per commit, as it will assume more tags is a
|
||||
# mistake.
|
||||
#
|
||||
# If there's a prerelease-style suffix to the version, then the release(s)
|
||||
# will be marked as a prerelease.
|
||||
on:
|
||||
pull_request:
|
||||
push:
|
||||
tags: ["v*.*.*"]
|
||||
|
||||
env:
|
||||
CARGO_TERM_COLOR: always
|
||||
tags:
|
||||
- '**[0-9]+.[0-9]+.[0-9]+*'
|
||||
|
||||
jobs:
|
||||
prepare:
|
||||
name: Prepare release
|
||||
runs-on: ubuntu-latest
|
||||
# Run 'cargo dist plan' (or host) to determine what tasks we need to do
|
||||
plan:
|
||||
runs-on: "ubuntu-20.04"
|
||||
outputs:
|
||||
tag_name: ${{ steps.release_info.outputs.tag_name }}
|
||||
release_name: ${{ steps.release_info.outputs.release_name }}
|
||||
# release_notes: ${{ steps.extract_release_notes.outputs.release_notes }}
|
||||
|
||||
val: ${{ steps.plan.outputs.manifest }}
|
||||
tag: ${{ !github.event.pull_request && github.ref_name || '' }}
|
||||
tag-flag: ${{ !github.event.pull_request && format('--tag={0}', github.ref_name) || '' }}
|
||||
publishing: ${{ !github.event.pull_request }}
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Compute release name and tag
|
||||
id: release_info
|
||||
run: |
|
||||
echo "tag_name=${GITHUB_REF_NAME}" >> $GITHUB_OUTPUT
|
||||
echo "release_name=${GITHUB_REF_NAME}" >> $GITHUB_OUTPUT
|
||||
|
||||
# - name: Extract release notes
|
||||
# id: extract_release_notes
|
||||
# run: echo "release_notes=\"$(sed -n '/^## .*$/,$p' CHANGELOG.md | sed '1d;/^## /,$d')\"" >> $GITHUB_OUTPUT
|
||||
|
||||
release:
|
||||
name: ${{ matrix.job.target }} (${{ matrix.job.os }})
|
||||
runs-on: ${{ matrix.job.os }}
|
||||
needs: prepare
|
||||
strategy:
|
||||
matrix:
|
||||
job:
|
||||
# os: used for the runner
|
||||
# platform: a generic platform name
|
||||
# target: used by Cargo
|
||||
# arch: either 386, arm64 or amd64
|
||||
- os: ubuntu-latest
|
||||
platform: linux
|
||||
target: x86_64-unknown-linux-gnu
|
||||
arch: amd64
|
||||
# - os: ubuntu-latest
|
||||
# platform: linux
|
||||
# target: aarch64-unknown-linux-gnu
|
||||
# arch: arm64
|
||||
- os: macos-latest
|
||||
platform: darwin
|
||||
target: x86_64-apple-darwin
|
||||
arch: amd64
|
||||
- os: macos-latest
|
||||
platform: darwin
|
||||
target: aarch64-apple-darwin
|
||||
arch: arm64
|
||||
- os: windows-latest
|
||||
platform: win32
|
||||
target: x86_64-pc-windows-msvc
|
||||
arch: amd64
|
||||
- os: windows-latest
|
||||
platform: win32
|
||||
target: aarch64-pc-windows-msvc
|
||||
arch: arm64
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Install toolchain
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
profile: minimal
|
||||
toolchain: stable
|
||||
target: ${{ matrix.job.target }}
|
||||
override: true
|
||||
|
||||
- uses: Swatinem/rust-cache@v1
|
||||
with:
|
||||
cache-on-failure: true
|
||||
|
||||
- name: Apple M1 setup
|
||||
if: ${{ matrix.job.target == 'aarch64-apple-darwin' }}
|
||||
run: |
|
||||
echo "SDKROOT=$(xcrun -sdk macosx --show-sdk-path)" >> $GITHUB_ENV
|
||||
echo "MACOSX_DEPLOYMENT_TARGET=$(xcrun -sdk macosx --show-sdk-platform-version)" >> $GITHUB_ENV
|
||||
|
||||
- name: Linux ARM setup
|
||||
if: ${{ matrix.job.target == 'aarch64-unknown-linux-gnu' }}
|
||||
run: |
|
||||
sudo apt-get update -y
|
||||
sudo apt-get install -y gcc-aarch64-linux-gnu libssl-dev:armhf
|
||||
echo "CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER=aarch64-linux-gnu-gcc" >> $GITHUB_ENV
|
||||
|
||||
- name: Build binaries
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: build
|
||||
args: --release --bins --target ${{ matrix.job.target }}
|
||||
|
||||
- name: Archive binaries
|
||||
id: artifacts
|
||||
env:
|
||||
PLATFORM_NAME: ${{ matrix.job.platform }}
|
||||
TARGET: ${{ matrix.job.target }}
|
||||
ARCH: ${{ matrix.job.arch }}
|
||||
VERSION_NAME: ${{ needs.prepare.outputs.tag_name }}
|
||||
run: |
|
||||
if [ "$PLATFORM_NAME" == "linux" ]; then
|
||||
tar -czvf "aiken_${VERSION_NAME}_${PLATFORM_NAME}_${ARCH}.tar.gz" -C ./target/${TARGET}/release aiken
|
||||
echo "::set-output name=file_name::aiken_${VERSION_NAME}_${PLATFORM_NAME}_${ARCH}.tar.gz"
|
||||
elif [ "$PLATFORM_NAME" == "darwin" ]; then
|
||||
# We need to use gtar here otherwise the archive is corrupt.
|
||||
# See: https://github.com/actions/virtual-environments/issues/2619
|
||||
gtar -czvf "aiken_${VERSION_NAME}_${PLATFORM_NAME}_${ARCH}.tar.gz" -C ./target/${TARGET}/release aiken
|
||||
echo "::set-output name=file_name::aiken_${VERSION_NAME}_${PLATFORM_NAME}_${ARCH}.tar.gz"
|
||||
else
|
||||
cd ./target/${TARGET}/release
|
||||
7z a -tzip "aiken_${VERSION_NAME}_${PLATFORM_NAME}_${ARCH}.zip" aiken.exe
|
||||
mv "aiken_${VERSION_NAME}_${PLATFORM_NAME}_${ARCH}.zip" ../../../
|
||||
echo "::set-output name=file_name::aiken_${VERSION_NAME}_${PLATFORM_NAME}_${ARCH}.zip"
|
||||
fi
|
||||
submodules: recursive
|
||||
- name: Install cargo-dist
|
||||
# we specify bash to get pipefail; it guards against the `curl` command
|
||||
# failing. otherwise `sh` won't catch that `curl` returned non-0
|
||||
shell: bash
|
||||
|
||||
# Creates the release for this specific version
|
||||
- name: Create release
|
||||
uses: softprops/action-gh-release@v1
|
||||
run: "curl --proto '=https' --tlsv1.2 -LsSf https://github.com/axodotdev/cargo-dist/releases/download/v0.22.1/cargo-dist-installer.sh | sh"
|
||||
- name: Cache cargo-dist
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: ${{ needs.prepare.outputs.release_name }}
|
||||
tag_name: ${{ needs.prepare.outputs.tag_name }}
|
||||
files: |
|
||||
${{ steps.artifacts.outputs.file_name }}
|
||||
name: cargo-dist-cache
|
||||
path: ~/.cargo/bin/cargo-dist
|
||||
# sure would be cool if github gave us proper conditionals...
|
||||
# so here's a doubly-nested ternary-via-truthiness to try to provide the best possible
|
||||
# functionality based on whether this is a pull_request, and whether it's from a fork.
|
||||
# (PRs run on the *source* but secrets are usually on the *target* -- that's *good*
|
||||
# but also really annoying to build CI around when it needs secrets to work right.)
|
||||
- id: plan
|
||||
run: |
|
||||
cargo dist ${{ (!github.event.pull_request && format('host --steps=create --tag={0}', github.ref_name)) || 'plan' }} --output-format=json > plan-dist-manifest.json
|
||||
echo "cargo dist ran successfully"
|
||||
cat plan-dist-manifest.json
|
||||
echo "manifest=$(jq -c "." plan-dist-manifest.json)" >> "$GITHUB_OUTPUT"
|
||||
- name: "Upload dist-manifest.json"
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: artifacts-plan-dist-manifest
|
||||
path: plan-dist-manifest.json
|
||||
|
||||
# Build and packages all the platform-specific things
|
||||
build-local-artifacts:
|
||||
name: build-local-artifacts (${{ join(matrix.targets, ', ') }})
|
||||
# Let the initial task tell us to not run (currently very blunt)
|
||||
needs:
|
||||
- plan
|
||||
if: ${{ fromJson(needs.plan.outputs.val).ci.github.artifacts_matrix.include != null && (needs.plan.outputs.publishing == 'true' || fromJson(needs.plan.outputs.val).ci.github.pr_run_mode == 'upload') }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
# Target platforms/runners are computed by cargo-dist in create-release.
|
||||
# Each member of the matrix has the following arguments:
|
||||
#
|
||||
# - runner: the github runner
|
||||
# - dist-args: cli flags to pass to cargo dist
|
||||
# - install-dist: expression to run to install cargo-dist on the runner
|
||||
#
|
||||
# Typically there will be:
|
||||
# - 1 "global" task that builds universal installers
|
||||
# - N "local" tasks that build each platform's binaries and platform-specific installers
|
||||
matrix: ${{ fromJson(needs.plan.outputs.val).ci.github.artifacts_matrix }}
|
||||
runs-on: ${{ matrix.runner }}
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
BUILD_MANIFEST_NAME: target/distrib/${{ join(matrix.targets, '-') }}-dist-manifest.json
|
||||
steps:
|
||||
- name: enable windows longpaths
|
||||
run: |
|
||||
git config --global core.longpaths true
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: recursive
|
||||
- name: "Musl build setup"
|
||||
if: "${{ runner.os == 'Linux' }}"
|
||||
run: |
|
||||
sudo apt-get install -y pkg-config libssl-dev musl musl-dev musl-tools
|
||||
rustup target add x86_64-unknown-linux-musl
|
||||
- name: Install cargo-dist
|
||||
run: ${{ matrix.install_dist }}
|
||||
# Get the dist-manifest
|
||||
- name: Fetch local artifacts
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
pattern: artifacts-*
|
||||
path: target/distrib/
|
||||
merge-multiple: true
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
${{ matrix.packages_install }}
|
||||
- name: Build artifacts
|
||||
run: |
|
||||
# Actually do builds and make zips and whatnot
|
||||
cargo dist build ${{ needs.plan.outputs.tag-flag }} --print=linkage --output-format=json ${{ matrix.dist_args }} > dist-manifest.json
|
||||
echo "cargo dist ran successfully"
|
||||
- id: cargo-dist
|
||||
name: Post-build
|
||||
# We force bash here just because github makes it really hard to get values up
|
||||
# to "real" actions without writing to env-vars, and writing to env-vars has
|
||||
# inconsistent syntax between shell and powershell.
|
||||
shell: bash
|
||||
run: |
|
||||
# Parse out what we just built and upload it to scratch storage
|
||||
echo "paths<<EOF" >> "$GITHUB_OUTPUT"
|
||||
jq --raw-output ".upload_files[]" dist-manifest.json >> "$GITHUB_OUTPUT"
|
||||
echo "EOF" >> "$GITHUB_OUTPUT"
|
||||
|
||||
cp dist-manifest.json "$BUILD_MANIFEST_NAME"
|
||||
- name: "Upload artifacts"
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: artifacts-build-local-${{ join(matrix.targets, '_') }}
|
||||
path: |
|
||||
${{ steps.cargo-dist.outputs.paths }}
|
||||
${{ env.BUILD_MANIFEST_NAME }}
|
||||
|
||||
# Build and package all the platform-agnostic(ish) things
|
||||
build-global-artifacts:
|
||||
needs:
|
||||
- plan
|
||||
- build-local-artifacts
|
||||
runs-on: "ubuntu-20.04"
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
BUILD_MANIFEST_NAME: target/distrib/global-dist-manifest.json
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: recursive
|
||||
- name: Install cached cargo-dist
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: cargo-dist-cache
|
||||
path: ~/.cargo/bin/
|
||||
- run: chmod +x ~/.cargo/bin/cargo-dist
|
||||
# Get all the local artifacts for the global tasks to use (for e.g. checksums)
|
||||
- name: Fetch local artifacts
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
pattern: artifacts-*
|
||||
path: target/distrib/
|
||||
merge-multiple: true
|
||||
- id: cargo-dist
|
||||
shell: bash
|
||||
run: |
|
||||
cargo dist build ${{ needs.plan.outputs.tag-flag }} --output-format=json "--artifacts=global" > dist-manifest.json
|
||||
echo "cargo dist ran successfully"
|
||||
|
||||
# Parse out what we just built and upload it to scratch storage
|
||||
echo "paths<<EOF" >> "$GITHUB_OUTPUT"
|
||||
jq --raw-output ".upload_files[]" dist-manifest.json >> "$GITHUB_OUTPUT"
|
||||
echo "EOF" >> "$GITHUB_OUTPUT"
|
||||
|
||||
cp dist-manifest.json "$BUILD_MANIFEST_NAME"
|
||||
- name: "Upload artifacts"
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: artifacts-build-global
|
||||
path: |
|
||||
${{ steps.cargo-dist.outputs.paths }}
|
||||
${{ env.BUILD_MANIFEST_NAME }}
|
||||
# Determines if we should publish/announce
|
||||
host:
|
||||
needs:
|
||||
- plan
|
||||
- build-local-artifacts
|
||||
- build-global-artifacts
|
||||
# Only run if we're "publishing", and only if local and global didn't fail (skipped is fine)
|
||||
if: ${{ always() && needs.plan.outputs.publishing == 'true' && (needs.build-global-artifacts.result == 'skipped' || needs.build-global-artifacts.result == 'success') && (needs.build-local-artifacts.result == 'skipped' || needs.build-local-artifacts.result == 'success') }}
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
runs-on: "ubuntu-20.04"
|
||||
outputs:
|
||||
val: ${{ steps.host.outputs.manifest }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: recursive
|
||||
- name: Install cached cargo-dist
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: cargo-dist-cache
|
||||
path: ~/.cargo/bin/
|
||||
- run: chmod +x ~/.cargo/bin/cargo-dist
|
||||
# Fetch artifacts from scratch-storage
|
||||
- name: Fetch artifacts
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
pattern: artifacts-*
|
||||
path: target/distrib/
|
||||
merge-multiple: true
|
||||
- id: host
|
||||
shell: bash
|
||||
run: |
|
||||
cargo dist host ${{ needs.plan.outputs.tag-flag }} --steps=upload --steps=release --output-format=json > dist-manifest.json
|
||||
echo "artifacts uploaded and released successfully"
|
||||
cat dist-manifest.json
|
||||
echo "manifest=$(jq -c "." dist-manifest.json)" >> "$GITHUB_OUTPUT"
|
||||
- name: "Upload dist-manifest.json"
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
# Overwrite the previous copy
|
||||
name: artifacts-dist-manifest
|
||||
path: dist-manifest.json
|
||||
# Create a GitHub Release while uploading all files to it
|
||||
- name: "Download GitHub Artifacts"
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
pattern: artifacts-*
|
||||
path: artifacts
|
||||
merge-multiple: true
|
||||
- name: Cleanup
|
||||
run: |
|
||||
# Remove the granular manifests
|
||||
rm -f artifacts/*-dist-manifest.json
|
||||
- name: Create GitHub Release
|
||||
env:
|
||||
PRERELEASE_FLAG: "${{ fromJson(steps.host.outputs.manifest).announcement_is_prerelease && '--prerelease' || '' }}"
|
||||
ANNOUNCEMENT_TITLE: "${{ fromJson(steps.host.outputs.manifest).announcement_title }}"
|
||||
ANNOUNCEMENT_BODY: "${{ fromJson(steps.host.outputs.manifest).announcement_github_body }}"
|
||||
RELEASE_COMMIT: "${{ github.sha }}"
|
||||
run: |
|
||||
# Write and read notes from a file to avoid quoting breaking things
|
||||
echo "$ANNOUNCEMENT_BODY" > $RUNNER_TEMP/notes.txt
|
||||
|
||||
gh release create "${{ needs.plan.outputs.tag }}" --target "$RELEASE_COMMIT" $PRERELEASE_FLAG --title "$ANNOUNCEMENT_TITLE" --notes-file "$RUNNER_TEMP/notes.txt" artifacts/*
|
||||
|
||||
publish-homebrew-formula:
|
||||
needs:
|
||||
- plan
|
||||
- host
|
||||
runs-on: "ubuntu-20.04"
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
PLAN: ${{ needs.plan.outputs.val }}
|
||||
GITHUB_USER: "axo bot"
|
||||
GITHUB_EMAIL: "admin+bot@axo.dev"
|
||||
if: ${{ !fromJson(needs.plan.outputs.val).announcement_is_prerelease || fromJson(needs.plan.outputs.val).publish_prereleases }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
repository: "aiken-lang/homebrew-tap"
|
||||
token: ${{ secrets.HOMEBREW_TAP_TOKEN }}
|
||||
# So we have access to the formula
|
||||
- name: Fetch homebrew formulae
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
pattern: artifacts-*
|
||||
path: Formula/
|
||||
merge-multiple: true
|
||||
# This is extra complex because you can make your Formula name not match your app name
|
||||
# so we need to find releases with a *.rb file, and publish with that filename.
|
||||
- name: Commit formula files
|
||||
run: |
|
||||
git config --global user.name "${GITHUB_USER}"
|
||||
git config --global user.email "${GITHUB_EMAIL}"
|
||||
|
||||
for release in $(echo "$PLAN" | jq --compact-output '.releases[] | select([.artifacts[] | endswith(".rb")] | any)'); do
|
||||
filename=$(echo "$release" | jq '.artifacts[] | select(endswith(".rb"))' --raw-output)
|
||||
name=$(echo "$filename" | sed "s/\.rb$//")
|
||||
version=$(echo "$release" | jq .app_version --raw-output)
|
||||
|
||||
export PATH="/home/linuxbrew/.linuxbrew/bin:$PATH"
|
||||
brew update
|
||||
# We avoid reformatting user-provided data such as the app description and homepage.
|
||||
brew style --except-cops FormulaAudit/Homepage,FormulaAudit/Desc,FormulaAuditStrict --fix "Formula/${filename}" || true
|
||||
|
||||
git add "Formula/${filename}"
|
||||
git commit -m "${name} ${version}"
|
||||
done
|
||||
git push
|
||||
|
||||
publish-npm:
|
||||
needs:
|
||||
- plan
|
||||
- host
|
||||
runs-on: "ubuntu-20.04"
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
PLAN: ${{ needs.plan.outputs.val }}
|
||||
if: ${{ !fromJson(needs.plan.outputs.val).announcement_is_prerelease || fromJson(needs.plan.outputs.val).publish_prereleases }}
|
||||
steps:
|
||||
- name: Fetch npm packages
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
pattern: artifacts-*
|
||||
path: npm/
|
||||
merge-multiple: true
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: '20.x'
|
||||
registry-url: 'https://registry.npmjs.org'
|
||||
- run: |
|
||||
for release in $(echo "$PLAN" | jq --compact-output '.releases[] | select([.artifacts[] | endswith("-npm-package.tar.gz")] | any)'); do
|
||||
pkg=$(echo "$release" | jq '.artifacts[] | select(endswith("-npm-package.tar.gz"))' --raw-output)
|
||||
npm publish --access public "./npm/${pkg}"
|
||||
done
|
||||
env:
|
||||
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
||||
|
||||
announce:
|
||||
needs:
|
||||
- plan
|
||||
- host
|
||||
- publish-homebrew-formula
|
||||
- publish-npm
|
||||
# use "always() && ..." to allow us to wait for all publish jobs while
|
||||
# still allowing individual publish jobs to skip themselves (for prereleases).
|
||||
# "host" however must run to completion, no skipping allowed!
|
||||
if: ${{ always() && needs.host.result == 'success' && (needs.publish-homebrew-formula.result == 'skipped' || needs.publish-homebrew-formula.result == 'success') && (needs.publish-npm.result == 'skipped' || needs.publish-npm.result == 'success') }}
|
||||
runs-on: "ubuntu-20.04"
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: recursive
|
||||
|
|
|
@ -11,22 +11,76 @@ env:
|
|||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: Swatinem/rust-cache@v2
|
||||
with:
|
||||
save-if: ${{ github.ref == 'refs/heads/main' }}
|
||||
key: ${{ runner.os }}-cache-build-v${{ inputs.cache-version }}
|
||||
- name: Build release
|
||||
run: |
|
||||
sudo apt-get install -y pkg-config libssl-dev musl musl-dev musl-tools
|
||||
rustup target add x86_64-unknown-linux-musl
|
||||
cargo install --path=crates/aiken --target=x86_64-unknown-linux-musl
|
||||
mv $(which aiken) aiken
|
||||
ldd aiken
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: aiken-${{ github.sha }}-${{ runner.arch }}-${{ runner.os }}
|
||||
path: ./aiken
|
||||
|
||||
acceptance_tests:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Build
|
||||
run: cargo build --verbose --workspace
|
||||
- name: Run unit tests
|
||||
run: cargo test --verbose --workspace
|
||||
- uses: actions/checkout@v4
|
||||
- uses: Swatinem/rust-cache@v2
|
||||
with:
|
||||
save-if: ${{ github.ref == 'refs/heads/main' }}
|
||||
key: ${{ runner.os }}-cache-build-v${{ inputs.cache-version }}
|
||||
- name: Run examples
|
||||
run: |
|
||||
cargo run -r -- check examples/hello_world
|
||||
cargo run -r -- check examples/gift_card
|
||||
- name: Run acceptance tests
|
||||
working-directory: examples/acceptance_tests
|
||||
run: |
|
||||
cargo install cbor-diag-cli
|
||||
bash ci
|
||||
shell: bash
|
||||
|
||||
unit_tests:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: Swatinem/rust-cache@v2
|
||||
with:
|
||||
save-if: ${{ github.ref == 'refs/heads/main' }}
|
||||
key: ${{ runner.os }}-cache-tests-v${{ inputs.cache-version }}
|
||||
- name: Run unit tests
|
||||
run: cargo test --verbose --workspace
|
||||
|
||||
benchmarks:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: Swatinem/rust-cache@v2
|
||||
with:
|
||||
save-if: ${{ github.ref == 'refs/heads/main' }}
|
||||
key: ${{ runner.os }}-cache-build-v${{ inputs.cache-version }}
|
||||
- name: Run benchmarks
|
||||
run: |
|
||||
cargo run -r -- check benchmarks
|
||||
|
||||
checks:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: Swatinem/rust-cache@v2
|
||||
with:
|
||||
save-if: ${{ github.ref == 'refs/heads/main' }}
|
||||
key: ${{ runner.os }}-cache-unit-v${{ inputs.cache-version }}
|
||||
- name: Format
|
||||
run: cargo fmt --all -- --check
|
||||
- name: Clippy
|
||||
run: cargo clippy --all-targets --all-features -- -D warnings
|
||||
# - name: Audit
|
||||
# run: cargo audit
|
||||
|
|
|
@ -2,4 +2,5 @@
|
|||
/target
|
||||
.idea
|
||||
_site/
|
||||
temp
|
||||
temp/
|
||||
scratch/
|
||||
|
|
642
CHANGELOG.md
642
CHANGELOG.md
|
@ -1,5 +1,626 @@
|
|||
# Changelog
|
||||
|
||||
## v1.1.7 - 2024-11-19
|
||||
|
||||
### Changed
|
||||
|
||||
- **aiken**: Move JSON schema help for `check` under a new dedicated flag `--show-json-schema`. @KtorZ
|
||||
- **aiken-lang**: Fix pattern-matching on list wildcard sometimes causing compiler crash following the new _decision trees_ approach. @MicroProofs
|
||||
- **uplc**, **aiken**, **aiken-lang**: Update internal dependencies to pallas-0.31.0. @KtorZ
|
||||
|
||||
## v1.1.6 - 2024-11-13
|
||||
|
||||
### Added
|
||||
|
||||
- **aiken**: Optionally provide blueprint file location when using `blueprint apply`. @Riley-Kilgore
|
||||
- **aiken**: Output test results as structured JSON when the target output is not a TTY terminal. @Riley-Kilgore, @KtorZ
|
||||
|
||||
### Changed
|
||||
|
||||
- **aiken**: Fix validator selection for `apply`, `address` and `policy` commands. Parameters are also now correctly applied to all handlers of a given validator, instead of needing to be manually targetted one-by-one. @KtorZ
|
||||
- **aiken**: Add more flexibility around the management of Plutus blueprint files for `build`, `address`, `policy` and `apply` commands. See [#1055](https://github.com/aiken-lang/aiken/issues/1055). @KtorZ
|
||||
- **aiken**: Rename `--filter_traces` to `--trace_filter` for more consistency with `--trace_level`. An alias for `--filter_traces` still exists for backward compatibility. @KtorZ
|
||||
- **aiken-project**: Fix `aiken docs` wrongly formatting list constants as tuples. See [#1048](https://github.com/aiken-lang/aiken/issues/1048). @KtorZ
|
||||
- **aiken-project**: Fix `aiken docs` source linking crashing when generating docs for config modules. See [#1044](https://github.com/aiken-lang/aiken/issues/1044). @KtorZ
|
||||
- **aiken-project**: Fix `aiken docs` generating very long lines for constants. @KtorZ
|
||||
- **aiken-lang**: Leverage [Decision Trees](https://www.cs.tufts.edu/comp/150FP/archive/luc-maranget/jun08.pdf) for compiling pattern matches to UPLC. @MicroProofs
|
||||
- **aiken-lang**: Rework optimization passes to safely reduce different kinds of patterns for each pass over the uplc. @MicroProofs
|
||||
- **aiken-lang**: Implement a looping mechanism to reduce uplc with deletion optimizations until term count remains the same. @MicroProofs
|
||||
|
||||
### Removed
|
||||
|
||||
- N/A
|
||||
|
||||
## v1.1.5 - 2024-10-19
|
||||
|
||||
### Added
|
||||
|
||||
- N/A
|
||||
|
||||
### Changed
|
||||
|
||||
- **uplc**: Fix costing of byteStringToInteger builtins. @Microproofs
|
||||
- **aiken-lang**: Fix data-type reification from `Void`; somehow missing from known definition :facepalm:. @KtorZ
|
||||
|
||||
### Removed
|
||||
|
||||
- N/A
|
||||
|
||||
## v1.1.4 - 2024-10-01
|
||||
|
||||
### Added
|
||||
|
||||
- N/A
|
||||
|
||||
### Changed
|
||||
|
||||
- **aiken-project**: Generate empty redeemer for `else` handler, to keep full compliance with the blueprint spec. @KtorZ
|
||||
- **aiken-lang**: Forbid constants evaluating to generic or unbound functions. Same restrictions as for validators or any exported UPLC programs apply here. @KtorZ & @MicroProofs
|
||||
- **aiken-lang**: Fix compiler crash on trace + expect as last expression of a clause. See #1029. @KtorZ
|
||||
- **aiken-lang**: Fix redundant warning on introduced identifiers when destructuring validator params. @KtorZ
|
||||
- **aiken-lsp**: Compile project using verbose tracing, to avoid having the language server complain about unused imports. @KtorZ
|
||||
- **uplc**: Fix (again :grimacing:) cost-models for PlutusV1 & PlutusV2. @MicroProofs
|
||||
|
||||
### Removed
|
||||
|
||||
- N/A
|
||||
|
||||
## v1.1.3 - 2024-09-20
|
||||
|
||||
### Added
|
||||
|
||||
- N/A
|
||||
|
||||
### Changed
|
||||
|
||||
- **aiken-project**: Fix documentation link-tree generation messing up with modules when re-inserting the same module. @KtorZ
|
||||
- **aiken-project**: Provide intermediate feedback when looking for counterexamples during property tests. @KtorZ
|
||||
- **aiken-lang**: Fix formatter adding extra unnecessary newlines after literal lists clause values or assignments. @KtorZ
|
||||
- **aiken-lang**: Fix formatting of long multi-line if/is expressions. @KtorZ
|
||||
- **aiken-lang**: Fix extraneous white-space added by the formatter after multiline alternative patterns. @KtorZ
|
||||
- **aiken-lang**: Fix incorrect warning about unused variable when softcasting without explicit right-pattern. @KtorZ
|
||||
- **aiken-lang**: Fix soft cast and hard cast on same type issues that lead to validator errors. @Microproofs
|
||||
- **aiken-lang**: Bls constants are automatically converted to a hoisted compressed form with uncompress builtin call. @Microproofs
|
||||
- **uplc**: Fix cost-models for PlutusV1 & PlutusV2. @MicroProofs
|
||||
|
||||
### Removed
|
||||
|
||||
- N/A
|
||||
|
||||
## v1.1.2 - 2024-09-13
|
||||
|
||||
### Added
|
||||
|
||||
- N/A
|
||||
|
||||
### Changed
|
||||
|
||||
- **aiken-lang**: Fix issues with static recursive optimization. See [#1009](https://github.com/aiken-lang/aiken/issues/1009) @Microproofs
|
||||
- **aiken-lang**: Aiken IR now interns variables while building up to ensure uniqueness for local vars. @Microproofs
|
||||
- **aiken-lang**: Fix reification of `Data` (failing to reify) & `PRNG` (missing variants' arguments). @KtorZ
|
||||
- **aiken-lang**: Adjust reification of `String` to be shown as plain UTF-8 text strings (instead of hex-encoded byte array). @KtorZ
|
||||
- **aiken-lang**: Fix formatting of long if-condition over multiline. @KtorZ & @Microproofs
|
||||
- **aiken-lang**: Fix formatting of standalone logical binary chains (`and` & `or`) in functions. @KtorZ
|
||||
- **uplc**: Fix script context generation failure on missing datum when evaluating transactions. @solidsnakedev
|
||||
|
||||
### Removed
|
||||
|
||||
- N/A
|
||||
|
||||
## v1.1.1 - 2024-09-10
|
||||
|
||||
### Added
|
||||
|
||||
- N/A
|
||||
|
||||
### Changed
|
||||
|
||||
- **aiken-lang**: Fix validator's else handler generation. See [#1015](https://github.com/aiken-lang/aiken/issues/1015) @KtorZ
|
||||
- **aiken-lang**: Fix underflow in error message reported by the validator arity. See [#1013](https://github.com/aiken-lang/aiken/issues/1013) @KtorZ
|
||||
- **aiken-lang**: Fix list-pattern needlessly formatting over multiple lines. @KtorZ
|
||||
- **aiken-lang**: Fix formatter on long alternative patterns spanning over multiple lines. @KtorZ
|
||||
- **aiken-lang**: Fix needed parentheses under trace-if-false operator for todo, fail, unop & pipelines; removed when formatting. @KtorZ
|
||||
- **aiken-lang**: Fix formatter removing curly braces around multi-line constants. It's fine to not have curly braces, but it's the Aiken signature after all. @KtorZ
|
||||
- **aiken-lang**: Improve LSP suggestion for module imports. @Riley-Kilgore
|
||||
|
||||
### Removed
|
||||
|
||||
- N/A
|
||||
|
||||
## v1.1.0 - 2024-09-03
|
||||
|
||||
### Added
|
||||
|
||||
- **aiken-lang**: also authorize (complete) patterns in function arguments list instead of only variable names. @KtorZ
|
||||
|
||||
- **aiken-lang**: new syntax for soft casting otherwise known as `if/is`. See [#959](https://github.com/aiken-lang/aiken/pull/959) or [Control Flow - soft casting](https://aiken-lang.org/language-tour/control-flow#soft-casting-with-ifis) for more details. @rvcas
|
||||
|
||||
- **aiken-lang**: optimization: pre-evaluate constant arguments to lambdas when safe to do so. @MicroProofs
|
||||
|
||||
- **aiken-lang**: infer type when immediately possible during a patterned type-cast. See [#969](https://github.com/aiken-lang/aiken/pull/979). @KtorZ
|
||||
|
||||
- **aiken-lang**: add support for `mk_cons` and `mk_pair_data` builtins. See [#964](https://github.com/aiken-lang/aiken/issues/964). @KtorZ
|
||||
|
||||
- **aiken-lang**: pattern-matching on bytearrays is now available. See [#989](https://github.com/aiken-lang/aiken/issues/989). @KtorZ
|
||||
|
||||
- **aiken-project**: conditional configuration and environment. See [#937](https://github.com/aiken-lang/aiken/issues/937). @KtorZ
|
||||
|
||||
- **aiken-project**: warning on compiler version mismatch. See [de870e2](https://github.com/aiken-lang/aiken/commit/de870e2529eb2336957e228cd30d4850ec2619a2). @rvcas
|
||||
|
||||
- **aiken-project**: source links to generated documentation for types, constants and functions. @KtorZ
|
||||
|
||||
- **aiken-project**: comments containing Markdown section headings (`#`, `##`, `###` etc.) will now be preserved and rendered in generated documentation. @KtorZ
|
||||
|
||||
- **aiken-project**: modules starting with `@hidden` in their docs will be skipped from docs generation. @KtorZ
|
||||
|
||||
- **aiken-project**: preserve type-aliases as titles in blueprint generated schemas. @KtorZ
|
||||
|
||||
- **uplc**: support evaluation of Plutus V3 transactions, including new purposes introduced in Conway. @KtorZ
|
||||
|
||||
### Changed
|
||||
|
||||
- **aiken-lang**: zero-arg functions are **no longer** evaluated at compile-time. However, constants can now hold _any_ expression and are fully evaluated at compile-time. Use `const` whenever a zero-arg function was used, unless you do want to defer execution. @KtorZ @MicroProofs.
|
||||
|
||||
- **aiken-lang**: fix zero-arg builtins `mk_nil_data` and `mk_nil_pair_data` invokation. @KtorZ
|
||||
|
||||
- **aiken-lang**: rename some builtins. @KtorZ
|
||||
|
||||
| old name | new name |
|
||||
| --- | --- |
|
||||
| `mk_nil_data` | `new_list` |
|
||||
| `mk_pair_data` | `new_pair` |
|
||||
| `mk_nil_pair_data` | `new_pairs` |
|
||||
|
||||
- **aiken-lang**: duplicate import lines are now automatically merged instead of raising a warning. However, imports can no longer appear anywhere in the file and must come as the first definitions. @KtorZ
|
||||
|
||||
- **aiken-lang**: remove warning on discarded expect, allowing to keep 'side-effects' when necessary. See [#967](https://github.com/aiken-lang/aiken/pull/967). @KtorZ
|
||||
|
||||
- **aiken-lang**: allow expect as last (or only) expression in function body, when clauses and if branches. Such expressions unify with `Void`. See [#1000](https://github.com/aiken-lang/aiken/pull/1000). @KtorZ
|
||||
|
||||
- **aiken-lang**: allow tests to return `Void`. Tests that return `Void` are treated the same as tests that return `True`. See [#1000](https://github.com/aiken-lang/aiken/pull/1000). @KtorZ
|
||||
|
||||
- **aiken-lang**: rework traces to be (1) variadic, (2) generic in its arguments and (3) structured. @KtorZ
|
||||
|
||||
In more details:
|
||||
|
||||
1. Enables the `trace` keyword to take one, two or any argument really separated by comma after the first. For example:
|
||||
|
||||
```ak
|
||||
trace @"a classic trace"
|
||||
|
||||
// ..
|
||||
|
||||
trace @"condition_1": @"foo"
|
||||
|
||||
// ...
|
||||
|
||||
trace @"condition_2": @"foo", @"bar"
|
||||
```
|
||||
|
||||
2. Enables the `trace` keyword to not only take strings as arguments; but any
|
||||
data-type that is serialisable (i.e. that can be cast to Data). It is fundamentally identical to calling the [`cbor.diagnostic`](https://aiken-lang.github.io/stdlib/aiken/cbor.html#diagnostic) function from the standard lib; except that this is done and glued with the rest of the trace automatically.
|
||||
|
||||
```ak
|
||||
trace @"condition_1": [1, 2, 3]
|
||||
|
||||
// ...
|
||||
|
||||
let my_var = Some("foo")
|
||||
trace my_var
|
||||
```
|
||||
|
||||
3. Changes the behavior of the `--trace-level compact` mode to now:
|
||||
|
||||
- remove trace-if-false (`?` operator) traces entirely in this mode;
|
||||
- only keep the label (first trace argument) and error when it isn't a string.
|
||||
|
||||
See also [#978](https://github.com/aiken-lang/aiken/pull/978).
|
||||
|
||||
- **aiken-lang**: rework formatter behaviour on long-lines, especially in the presence of binary operators. @KtorZ
|
||||
|
||||
- **aiken-lang**: provide better errors for unknown types used in cyclic type definitions. @KtorZ
|
||||
|
||||
- **aiken-project**: fix blueprint's apply truncating last character of outputs. See [#987](https://github.com/aiken-lang/aiken/issues/987). @KtorZ
|
||||
|
||||
- **aiken-project**: provide better error (include input ref) when inputs are missing during transaction evaluation. See [#974](https://github.com/aiken-lang/aiken/issues/974). @KtorZ
|
||||
|
||||
- **aiken-project**: module inhabitants are no longer alphabetically sorted when generating documentation. Instead, the order in which they are defined in the module is used. @KtorZ
|
||||
|
||||
- **aiken-project**: the sidebar links to modules within a package is now fully hierarchical and (hopefully) better-looking. @KtorZ
|
||||
|
||||
### Removed
|
||||
|
||||
- **aiken-lang**: clause guards are no longer part of the language. See [#886](https://github.com/aiken-lang/aiken/issues/886). @KtorZ.
|
||||
|
||||
## v1.0.29-alpha - 2024-06-06
|
||||
|
||||
### Added
|
||||
|
||||
- **aiken-lang**: new LSP quickfix for 'use let' warning. @KtorZ
|
||||
|
||||
### Changed
|
||||
|
||||
- **aiken-lang**: the keyword `fail` on property-based test semantic has changed and now consider a test to succeed only if **every** execution of the test failed (instead of just one). The previous behavior can be recovered by adding the keyword `once` after `fail`. @KtorZ
|
||||
|
||||
### Fixed
|
||||
|
||||
- **aiken-lang**: fixed the number of 'after x tests' number reported on property test failure, which was off by one. @KtorZ
|
||||
- **aiken-lang**: fixed parsing of single hex digits. @KtorZ
|
||||
|
||||
## v1.0.28-alpha - 2024-05-23
|
||||
|
||||
### Added
|
||||
|
||||
- **aiken**: install shell completions automatically. @freexploit
|
||||
- **aiken**: added export command that exports regular function definitons. @rvcas
|
||||
- **aiken-project**: compiler version field to `aiken.toml` @rvcas
|
||||
- **aiken-project**: plutus version field to `aiken.toml` @rvcas
|
||||
- **aiken-lsp**: hover and goto definition support on list tail. @rvcas
|
||||
- **aiken-lsp**: hover on prop test via expression. @rvcas
|
||||
- **aiken-lang**: new builtin types in the prelude `Pair` and `Pairs`. @KtorZ @Microproofs
|
||||
- **aiken-lang**: Codegen now generates uplc version 1.1.0 scripts when running build with plutus v3.
|
||||
|
||||
### Fixed
|
||||
|
||||
- **aiken-lang**: formatter should not erase `pub` on validators. @rvcas
|
||||
- **aiken-lang**: error on using tuple index when a tuple is returned by a generic function. @rvcas
|
||||
- **aiken-lang**: backpassing with expect gives a warning on pattern matches. @rvcas
|
||||
- **aiken-lang**: fix a regression in the Type-checker introduced in v1.0.25-alpha regarding types comparison. See #917. @KtorZ
|
||||
- **aiken-lang**: fix incongruous generics after type-checking which caused [] to be treated as a list in cases where it needed to be an empty map primitive. See #922. @KtorZ
|
||||
- **aiken-lang**: fix for generic constrs being used as functions causing type mismatch errors. @Microproofs
|
||||
- **aiken-lang**: fix for error occuring when a field holds Data that is not a constr type when compiler traces are on. @Microproofs
|
||||
- **aiken-lang**: fix for curry optimization involving 2 constants #945. @MicroProofs
|
||||
- **aiken-lang**: fix compiler wrongly requiring MillerLoopResult to be 'serialisable' when manipulated as a top-level value. See #921. @KtorZ
|
||||
- **aiken-lang**: fix type-checker oversight regarding serialisation of generics. See #939. @KtorZ
|
||||
- **aiken-lang**: fix type-checker not raising error when comparing non-serialisable types. See #940. @KtorZ
|
||||
- **aiken-project**: show a warning when ignoring modules in lib/validator because they have an invalid name. See #916. @KtorZ
|
||||
|
||||
### Changed
|
||||
|
||||
> [!WARNING]
|
||||
>
|
||||
> **BREAKING-CHANGE**
|
||||
>
|
||||
> 2-tuples `(a, b)` are now treated the same as 3+ tuples -- which directly impacts the way that Aiken now deserialise those, especially when nested inside a `List`.
|
||||
>
|
||||
> To deserialize into a list of 2-tuple (`List<(a, b)>`), one is now expected to provide a CBOR array of arrays (of 2 elements). Previously, this would require to provide a CBOR map! The downside of the latter is that CBOR serialization libraries do not necessarily preserve the order of keys in a map which could cause issues down the line, in particular with Aiken's dictionnaries.
|
||||
>
|
||||
> To recover the old behavior when desired, Aiken introduces a new type `Pair<a, b>` to the language. So any existing program can be migrated by switching any occurences of `(a, b)` to `Pair<a, b>`.
|
||||
>
|
||||
> However, it is often preferable to use 2-tuples where possible. The main place you will see usage of `Pair` is in the script context because its form is imposed by the ledger.
|
||||
|
||||
- **aiken-lang**: altered internal representation of 2-tuples to distinguish them from pairs. @KtorZ @Microproofs
|
||||
- **aiken-lang**: some more code gen cleanup. @Microproofs
|
||||
- **aiken-lang**: new optimization for wrapped builtins found in the stdlib. @Microproofs
|
||||
- **aiken-project**: slightly restyle warnings to be less noisy. @KtorZ
|
||||
|
||||
## v1.0.26-alpha - 2024-03-25
|
||||
|
||||
### Fixed
|
||||
|
||||
- **aiken-lang**: allow casting of types to Data in function pipiing. @KtorZ
|
||||
|
||||
## v1.0.25-alpha - 2024-03-22
|
||||
|
||||
### Added
|
||||
|
||||
- **aiken-lang**: Data now has a generic argument that can be used to specify the blueprint type. @KtorZ
|
||||
- **aiken-lang**: New types `PRNG` and `Fuzzer` in the prelude. @KtorZ
|
||||
- **aiken-lang**: Test definitions now accept an (optional) argument alongside a new keyword `via` to specify fuzzers. @KtorZ
|
||||
- **aiken-project**: Property-based testing framework with integrated shrinking and case labelling. @KtorZ
|
||||
- **aiken-project**: Unit tests now show assertion operands as Aiken expression instead of raw UPLC . @KtorZ
|
||||
- **aiken**: The `check` command now accept an extra arg `--seed` to provide an initial seed for the pseudo-random generator of properties. @KtorZ
|
||||
- **uplc**: add `integerToByteString` and `byteStringToInteger` builtins. @rvcas @Microproofs
|
||||
- **aiken-lang**: add `integer_to_byte_string` and `byte_string_to_integer` `aiken/builtins`. @rvcas
|
||||
- **uplc**: more conformance tests for `integerToByteString` and `byteStringToInteger` along with new ones. @rvcas
|
||||
- **aikup**: error message when version is not found. @rvcas
|
||||
- **aiken**: support outputting mainnet addresses for validators. @rvcas
|
||||
- **aiken-lang**: added serde to CheckedModule to encode modules as cbor. @rvcas
|
||||
- **aiken-lang**: Strings can contain a nul byte using the escape sequence `\0`. @KtorZ
|
||||
- **aiken**: The `check` command now accept an extra (optional) option `--max-success` to control the number of property-test iterations to perform. @KtorZ
|
||||
- **aiken**: The `docs` command now accept an optional flag `--include-dependencies` to include all dependencies in the generated documentation. @KtorZ
|
||||
- **aiken-lang**: Implement [function backpassing](https://www.roc-lang.org/tutorial#backpassing) as a syntactic sugar. @KtorZ
|
||||
- **aiken-lang**: Extend backpassing to support multiple patterns/arguments. @rvcas
|
||||
|
||||
### Fixed
|
||||
|
||||
- **aiken-lang**: Boolean operators (`||` and `&&`) were (somewhat) left-associative. This is now fixed and changed to right-associativity. @KtorZ
|
||||
- **uplc**: `serialise_data` builtin wrongly encoding some larger ints as tagged CBOR bigints, instead of plain integers over 9 bytes. @KtorZ
|
||||
- **aiken-project**: Unit tests reports are now inline with the test with less noise. @KtorZ
|
||||
- **aiken-lang**: Data deserialization for primitive types (pairs, bools, void) now do full checks on the Data structure. @Microproofs
|
||||
- **aiken-lang**: The identity reducer optimization was not removing the identity function before. That is fixed now.@Microproofs
|
||||
- **aiken-lang**: Inner opaque types can now be properly destructured by expect and when patterns. @Microproofs
|
||||
- **aiken-lang**: A codegen specific name-unique interner is now used to preserve lambda scoping. @Microproofs
|
||||
- **aiken-lang**: if there is only one clause we want to present a warning that suggests that a `let` binding should be used instead but only if it's an exhaustive pattern. @rvcas
|
||||
- **aiken-lang**: support nested void matching @rvcas
|
||||
- **uplc**: fix constr identity (`constr-3.uplc`) conformance test. @rvcas
|
||||
- **aiken-lang**: disallow `MLResult` in a type definition. @rvcas
|
||||
- **aiken-lang**: reversed deserialization of bls types out of data types. @rvcas
|
||||
- **aiken-lang**: validator args unexpectedly unbound causing code gen crashes. @rvcas
|
||||
- **aiken-lang**: allow implicitly discarded values when right-hand side unified with `Void`. @KtorZ
|
||||
- **aiken-lang**: allow zero arg mutually recursive functions. @Microproofs
|
||||
- **aiken-lang**: function aliases now resolved to the module and function name in codegen. @Microproofs
|
||||
- **aiken-lang**: fix indentation of pipelines to remain a multiple of the base indent increment. @KtorZ
|
||||
- **aiken-lang**: forbid presence of non-serialisable data-types in compound structures like List and Tuple. @KtorZ
|
||||
- **aiken-lang**: fix 'given' arity reported by 'incorrect arity' error message. @rvcas
|
||||
|
||||
### Changed
|
||||
|
||||
- **aiken-lang**: Discards will now also type check the validator arguments instead of completely ignoring them. @Microproofs
|
||||
- **aiken-lang**: Further improvements to tracing when using expect casting from Data. @Microproofs
|
||||
- **aiken-lang**: The set of curriable builtins with arguments that occur 3 or more times are now hoisted in scope with the arguments curried. @Microproofs
|
||||
- **aiken-lang**: Improved the way the lambda inliner works to prevent unnecessary inlining into functions. @Microproofs
|
||||
- **aiken-lang**: Simplifications to the AirTree type in codegen. @Microproofs
|
||||
- **aiken-lang**: CONSTR_FIELD_EXPOSER and CONSTR_INDEX_EXPOSER now inline the builtins instead. @Microproofs
|
||||
- **aiken-lang**: SubtractInteger with a constant as the second arg is now flipped to addInteger with a negated constant. @Microproofs
|
||||
- **aiken-lang**: Validator arguments are now checked per arg instead of after all args are applied. @Microproofs
|
||||
- **aiken-project**: remove test definitions from dependency modules. @rvcas
|
||||
- **aiken-project**: ignore warnings from dependency modules. @rvcas
|
||||
- **aiken-project**: parse sources in parallel, this resulted in a nice speedup. @rvcas
|
||||
- **aiken-lang**: You can no longer use expect on opaque types in various situations. @rvcas & @KtorZ
|
||||
|
||||
## v1.0.24-alpha - 2024-01-31
|
||||
|
||||
### Added
|
||||
|
||||
- **aiken**: New aliases for `check` (aiken c) and `build` (aiken b) commands. @Kuly14
|
||||
|
||||
### Fixed
|
||||
|
||||
- **aiken-lang**: Fixed an issue with expects on lists that used discards. This fixes
|
||||
the validator issues being seen for previously succeeding validators on 1.0.21-alpha. @MicroProofs
|
||||
- **aiken-lang**: Out of Span issue is now solved. This also fixes incorrectly selected
|
||||
traces from the wrong module, which in some cases lead to the out of span issue. @MicroProofs
|
||||
- **aiken-lang**: Calling head_list on a list of pairs no longer throws a type error. @MicroProofs
|
||||
|
||||
## v1.0.23-alpha - 2024-01-24
|
||||
|
||||
### Fixed
|
||||
|
||||
- **aiken-lang**: Now using correct discard match for constructor field access.
|
||||
- **aiken-lang**: The list_access_to_uplc now always returns a lambda wrapped
|
||||
term even with only discards. This fixes an apply error being seen by a few
|
||||
people.
|
||||
|
||||
## v1.0.22-alpha - 2024-01-24
|
||||
|
||||
### Added
|
||||
|
||||
- **aiken**: New `--trace-level` option for the `check` and `build` commands to
|
||||
allow chosing the verbosity level of traces amongst three levels: silent,
|
||||
compact & verbose. @MicroProofs @KtorZ
|
||||
- **aiken**: New `--filter-traces` option for the `check` and `build` commands
|
||||
to enable restricting traces with more granularity between user-defined
|
||||
- **aiken-lang**: Most builtin errors are now caught and instead catched trace
|
||||
errors are thrown. The exception is BLS primitives.
|
||||
|
||||
### Fixed
|
||||
|
||||
- **aiken-lang**: Fix flat encoding and decoding of large integer values. @KtorZ
|
||||
- **aiken-lang**: Traces should not have following expressions formatted into a
|
||||
block. @rvcas
|
||||
- **aiken-lang**: Sequences should not be erased if the sole expression is an
|
||||
assignment. @rvcas
|
||||
- **aiken-lang**: Should not be able to assign an assignment to an assignment.
|
||||
@rvcas
|
||||
- **aiken-lang**: Should not be able to have an assignment in a logical op
|
||||
chain. @rvcas
|
||||
- **aiken**: Ensures that test expected to fail that return `False` are
|
||||
considered to pass & improve error reporting when they fail. @KtorZ
|
||||
- **aiken-lang**: Fix generic edge case involving tuples.
|
||||
- **aiken**: `aiken new` now uses the current version for the github action.
|
||||
- **aiken-lang**: Using the head_list builtin on assoc lists now works.
|
||||
|
||||
### Removed
|
||||
|
||||
- **aiken**: The options `--keep-traces` (on the `build` command) and
|
||||
`--no-traces` (on the `check` command) have been removed; superseded by the
|
||||
new options. @MicroProofs @KtorZ
|
||||
|
||||
> [!TIP]
|
||||
>
|
||||
> - If you've been using `aiken check --no-traces`, you can recover the old
|
||||
> behavior by doing `aiken check --trace-level silent`.
|
||||
> - If you've been using `aiken build --keep-traces`, you can recover the old
|
||||
> behavior by doing `aiken build --trace-level verbose`.
|
||||
|
||||
## v1.0.21-alpha - 2023-12-04
|
||||
|
||||
### Added
|
||||
|
||||
- **aiken**: `--watch` flag on the `build`, `check` and `docs` commands to
|
||||
automatically watch and re-execute the command on file changes.
|
||||
@Quantumplation & @KtorZ
|
||||
- acceptance tests 28-30 @MicroProofs
|
||||
- **aiken-lang**: expose BLS builtins and types @MicroProofs & @rvcas
|
||||
- **aiken-lsp**: implement hover info for tuples, lists, and contructor pattern
|
||||
elements @rvcas
|
||||
- **aiken-lsp**: implement hover on when clause patterns @rvcas
|
||||
- **aiken-lsp**: hover support for the optional multi validator fn @rvcas
|
||||
- **aiken-lsp**: implement quickfix for "utf8 byte array is valid hex string"
|
||||
warning @rvcas
|
||||
- **uplc**: add all BLS builtins and types @MicroProofs & @rvcas
|
||||
- **uplc**: add plutus conformance tests from
|
||||
[here](https://github.com/input-output-hk/plutus/tree/master/plutus-conformance/test-cases/uplc/evaluation).
|
||||
@MicroProofs & @rvcas
|
||||
- **uplc**: case and constr cost models @MicroProofs
|
||||
|
||||
### Changed
|
||||
|
||||
- **aiken**: update to pallas v0.20.0 @rvcas
|
||||
- **aiken-project**: switch blueprint validator tests now uses insta
|
||||
@MicroProofs
|
||||
- **aiken-project**: update to pallas v0.20.0 @rvcas
|
||||
- **aiken-lang**: use a better algorithm for inlining single occurrences
|
||||
@MicroProofs
|
||||
- **uplc**: update to pallas v0.20.0 @rvcas
|
||||
- **uplc**: remove `flat-rs` crate and use it through pallas_codec instead
|
||||
|
||||
### Fixed
|
||||
|
||||
- **aiken-lang**: formatting unable to have newline after expect bool shortcut
|
||||
@rvcas
|
||||
- **aiken-lang**: formatter incorrectly erasing blocks in certain situations
|
||||
@rvcas
|
||||
- **aiken-lang**: use a distinct warning for discarded let assignments to avoid
|
||||
confusion @rvcas
|
||||
- **aiken-lang**: allow spread operator on positional constructor arguments
|
||||
@rvcas
|
||||
- **aiken-lsp**: and/or chains hovering on nested elements not working @rvcas
|
||||
- **uplc**: delay typemismatch errors in the machine runtime (caught by
|
||||
conformance tests) @rvcas
|
||||
|
||||
## v1.0.20-alpha - 2023-10-25
|
||||
|
||||
### Added
|
||||
|
||||
- **aiken-project**: The `plutus.json` blueprint now contains a `compiler.name`
|
||||
and `compiler.version` fields.
|
||||
- **aiken-prokect**: Added compiler and system information to panic error
|
||||
report.
|
||||
- **aiken-lsp**: Added quickfix suggestions for unknown variables, modules and
|
||||
constructors.
|
||||
|
||||
### Changed
|
||||
|
||||
- **aiken-lang**: Added validator specific error when validator returns false
|
||||
- **aiken-lang**: Running a multi-validator with traces on will let you know
|
||||
which validator function is running
|
||||
- **aiken-lang**: Multi-validator with traces will give a better error when the
|
||||
'spend' redeemer is not properly wrapped with a constr
|
||||
- **aiken-lang**: Code gen traces are referenced instead of being inlined
|
||||
leading to smaller validators
|
||||
|
||||
### Fixed
|
||||
|
||||
- **aiken-lang**: improved error messages for `a |> b(x)`.
|
||||
- **uplc**: Fixed cost model issue when using div, quot, rem, mod.
|
||||
- **aiken-lsp**: Improved hovering suggestions and type annotations.
|
||||
|
||||
## v1.0.19-alpha - 2023-09-29
|
||||
|
||||
### Fixed
|
||||
|
||||
- **aiken-lang**: Fixed small typo in `hoist_dependent_functions` lead to
|
||||
internal cyclic calls not being recognized.
|
||||
|
||||
## v1.0.18-alpha - 2023-09-29
|
||||
|
||||
### Added
|
||||
|
||||
- **aiken-lang**: Code gen now allows for mutual recursion
|
||||
|
||||
### Fixed
|
||||
|
||||
- **aiken-lang**: fixed stack overflow with unbound typing being passed into a
|
||||
function with inferred types
|
||||
- **aiken-lang**: expect on tuples greater than 2 checks the length to ensure
|
||||
tuple lists are the same length as the type.
|
||||
|
||||
### Changed
|
||||
|
||||
- **aiken-lang**: (Code Gen): Rename some of the types to use aliases
|
||||
- **aiken-lang**: (Code Gen): Remove the use of Air::RecordAccess and TupleIndex
|
||||
and replace them with functions that directly get the item at the specified
|
||||
index. Also improves performance.
|
||||
- **uplc**: Added more cases to the inline optimization function to allow the
|
||||
removal of further unnecessary lambda bindings.
|
||||
|
||||
## v1.0.17-alpha - 2023-09-20
|
||||
|
||||
### Added
|
||||
|
||||
- **aiken**: add ability to force warnings to cause a failing exit code on
|
||||
check, build, and docs
|
||||
- **aiken-lang**: automatically resolve and fetch latest revision of a package
|
||||
on build when a branch is specified as version
|
||||
- **uplc**: Add Case and Constr Terms; This includes their flat serialization
|
||||
and evaluation
|
||||
|
||||
### Fixed
|
||||
|
||||
- **uplc**: trim whitespace when loading files with hex strings to avoid
|
||||
confusing errors #720
|
||||
- **uplc**: uplc `Constant::Data` formatting
|
||||
- **aiken-lang**: code gen fixes including nested constr when matches and expect
|
||||
on None
|
||||
- **aiken-lang**: empty records properly parse as record sugar
|
||||
- **aiken-lang**: escape sequences are now properly preserved after formatting
|
||||
- **aiken-lang**: fixed parser ambiguity when using record constructor in if
|
||||
conditions followed by single-line var expressions #735
|
||||
- **aiken-project**: when a module name has a hyphen we should behave like rust
|
||||
and force an underscore
|
||||
|
||||
## v1.0.16-alpha - 2023-08-24
|
||||
|
||||
### Removed
|
||||
|
||||
- **aiken**: `aiken new` no longer accept an `--empty` flag. Projects are
|
||||
generated empty by default.
|
||||
|
||||
## v1.0.15-alpha - 2023-08-19
|
||||
|
||||
### Added
|
||||
|
||||
- **aiken**: Parameters for `blueprint apply` can now be built interactively.
|
||||
|
||||
### Changed
|
||||
|
||||
- **aiken-lang**: Opaque types are now properly handled in code gen (i.e. in
|
||||
code gen functions, in datums/redeemers, in from data casts).
|
||||
- **aiken**: `blueprint apply` now expects only one OPTIONAL argument. When not
|
||||
provided, the parameter will be prompted interactively.
|
||||
- **aiken-lang**: New tests for code gen around opaque types.
|
||||
- **aiken-lang**: `traverse_with_tree` now has a boolean parameter to determine
|
||||
when `with` is called.
|
||||
|
||||
### Removed
|
||||
|
||||
- **aiken**: `blueprint apply` no longer accept a target directory. The command
|
||||
has to be executed within the same directory as the `aiken.toml`.
|
||||
|
||||
## v1.0.14-alpha - 2023-08-16
|
||||
|
||||
### Added
|
||||
|
||||
- **aiken**: `new` command now fetches latest stdlib version
|
||||
- **aiken-lang**: new `and` and `or` chaining
|
||||
```
|
||||
and {
|
||||
1 == 1,
|
||||
or {
|
||||
2 == 2,
|
||||
3 != 2,
|
||||
True,
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
### Changed
|
||||
|
||||
- **aiken-lang**: significantly improved pattern matching exhuastiveness
|
||||
checking
|
||||
- **aiken-lang**: Tx Simulate now returns a list of execution budgets for each
|
||||
redeemer instead of calculating the total units required to run all the
|
||||
scripts.
|
||||
- **aiken-lang**: Now code gen uses a tree abstraction to build the Aiken
|
||||
Intermediary Representation. This now fixes quite a number of minor issues
|
||||
while making the code more maintainable. This is a large leap towards a stable
|
||||
version and future updates will be on further simplifying and stabilizing the
|
||||
tree abstraction.
|
||||
- **aiken-lang**: Zero argument anonymous functions now are implemted as a
|
||||
delayed function body and calling them simply does force
|
||||
- **aiken-lang**: Matching on int in expect and when cases is now implemented
|
||||
- **aiken-lang**: Using assign in nested pattern matches is now implemented
|
||||
- **aiken-lang**: Using List<Data> as a validator params only checks the type is
|
||||
a list and does not attempt to check each item
|
||||
- **aiken-lang**: Recursion optimization to prevent static parameters from being
|
||||
passed through every recursion
|
||||
- **aiken-lang**: aliased import of single type throws compiler error
|
||||
- **aiken-lsp**: fix diagnostics and formatting on windows vscode
|
||||
- **aiken**: decode should always print to textual
|
||||
- **uplc**: pair type formatting
|
||||
|
||||
## v1.0.13-alpha - 2023-07-15
|
||||
|
||||
### Added
|
||||
|
@ -8,24 +629,28 @@
|
|||
|
||||
### Fixed
|
||||
|
||||
- **aiken-lang**: fail, todo, and trace had issues with sequences and expressions
|
||||
- **aiken-lang**: fail, todo, and trace had issues with sequences and
|
||||
expressions
|
||||
|
||||
## v1.0.12-alpha - 2023-07-14
|
||||
|
||||
### Added
|
||||
|
||||
- **aiken**: added a `blueprint policy` command to compute the policy ID of a minting script
|
||||
- **aiken**: added a `blueprint policy` command to compute the policy ID of a
|
||||
minting script
|
||||
- **uplc**: parsing and pretty printing for PlutusData
|
||||
|
||||
### Fixed
|
||||
|
||||
- **aiken-lang**: Prevent mutual recursion caused by conflicting function names for generic expect type
|
||||
- **aiken-lang**: Prevent mutual recursion caused by conflicting function names
|
||||
for generic expect type
|
||||
- **aiken-lang**: UPLC evaluation of large integers literals (> max u64)
|
||||
- **aiken-lang**: Parsing of error / todo keywords in when cases
|
||||
- **aiken-lang**: Parsing of negative integer patterns and constants
|
||||
- **aiken-lang**: automatically infer unused validator args as `Data`
|
||||
- **aiken-lang**: test crashing when referencing validators
|
||||
- **aiken**: mem and cpu values were not showing in white terminals, switched to cyan
|
||||
- **aiken**: mem and cpu values were not showing in white terminals, switched to
|
||||
cyan
|
||||
|
||||
### Changed
|
||||
|
||||
|
@ -52,8 +677,10 @@
|
|||
|
||||
### Fixed
|
||||
|
||||
- **aiken-lang**: Explain discards and expect a bit better in the unused var warning
|
||||
- **aiken-lang**: Fix expect \_ = ... not including the cast from data logic if the type is data and right hand has a type annotation
|
||||
- **aiken-lang**: Explain discards and expect a bit better in the unused var
|
||||
warning
|
||||
- **aiken-lang**: Fix expect \_ = ... not including the cast from data logic if
|
||||
the type is data and right hand has a type annotation
|
||||
- **aiken-lang**: Fix for the final clause of a when expecting another clause
|
||||
afterwards in nested list cases.
|
||||
- **aiken-lang**: Fix for all elements were being destructured in tuple clauses
|
||||
|
@ -61,7 +688,8 @@
|
|||
- **aiken-lang**: Fix for tuple clause not consuming the next case causing
|
||||
incomplete contracts. Now tuple clause will always consume the next case
|
||||
unless it is the final clause
|
||||
- **aiken-lang**: Fix for builtins using the incorrect data to type conversion when used as a function param.
|
||||
- **aiken-lang**: Fix for builtins using the incorrect data to type conversion
|
||||
when used as a function param.
|
||||
|
||||
## v1.0.10-alpha - 2023-06-13
|
||||
|
||||
|
|
|
@ -71,14 +71,44 @@
|
|||
|
||||
Want to give some financial support? Have a look at the ways to sponsor below for more details.
|
||||
|
||||
- [rvcas](https://github.com/sponsors/rvcas/)
|
||||
- [microproofs](https://github.com/sponsors/microproofs/)
|
||||
- [rvcas](https://github.com/sponsors/rvcas)
|
||||
- [microproofs](https://github.com/sponsors/microproofs)
|
||||
- [ktorz](https://github.com/sponsors/KtorZ)
|
||||
|
||||
Want to support with crypto?
|
||||
|
||||
- Our Ada address is `addr1q83nlzwu4zjeu927m8t24xa68upgmwgt5w29ww5ka695hc5rez2r4q7gcvj7z0ma6d88w3j220szsqk05sn43ghcsn4szvuklq`
|
||||
- Our Ada handle is `$aiken_lang`
|
||||
|
||||
## Releasing
|
||||
|
||||
To be able to create a release you need to be on the [maintainers](https://github.com/orgs/aiken-lang/teams/maintainers) team.
|
||||
This means that only core team members can create releases. We have a
|
||||
[github action](https://github.com/aiken-lang/aiken/blob/main/.github/workflows/release.yml) for creating the binaries and a github release.
|
||||
The process follows these steps:
|
||||
|
||||
1. `cargo release --execute`
|
||||
2. After a release is created by the github action fill in the release notes. Try to tag contributors so that they show up in the release.
|
||||
3. Screenshot the result of `aikup` and post on twitter saying "We've just released vx.x.x". [example](https://twitter.com/aiken_eng/status/1693084816931987930?s=20)
|
||||
|
||||
> `cargo release` takes arguments and flags to tell it how to bump the version number. Examples include `cargo release 1.0.16-alpha` and `cargo release major`.
|
||||
>
|
||||
> The root `Cargo.toml` in the repo contains this configuration for `cargo release`:
|
||||
>
|
||||
> ```toml
|
||||
> [workspace.metadata.release]
|
||||
> shared-version = true
|
||||
> tag-name = "v{{version}}"
|
||||
> ```
|
||||
|
||||
> [!IMPORTANT]
|
||||
>
|
||||
> Since v1.1.4, we have switched to producing statically linked binary with musl, preventing issues with openssl on various linux platforms. However, this changes the artifact name
|
||||
> from: `aiken-x86_64-unknown-linux-gnu.tar.gz` to `aiken-x86_64-unknown-linux-musl.tar.gz`. Consequently, we've patched `aikup` in version v0.0.11, but people using previous
|
||||
> version will fail to install aiken through aikup. So for a little a while, we need to manually re-upload a `-gnu.tar.gz` archive (which can be obtained by simply renaming the musl one) so that aikup can keep fetching artifacts on Linux prior to version `v0.0.11`. We can cease doing that once enough time has reasonably passed and enough people have switched to aikup.
|
||||
>
|
||||
> Ideally, we should introduce an `upgrade` command to aikup, and have some kind of notification system that indicates to people that they should upgrade their aikup installer.
|
||||
|
||||
## About Issues
|
||||
|
||||
### :bug: How To Report A Bug
|
||||
|
|
File diff suppressed because it is too large
Load Diff
60
Cargo.toml
60
Cargo.toml
|
@ -1,18 +1,70 @@
|
|||
[workspace]
|
||||
members = ["crates/*"]
|
||||
|
||||
[profile.release]
|
||||
strip = true
|
||||
resolver = "2"
|
||||
|
||||
[workspace.metadata.release]
|
||||
shared-version = true
|
||||
tag-name = "v{{version}}"
|
||||
|
||||
# Config for 'cargo dist'
|
||||
[workspace.metadata.dist]
|
||||
# The preferred cargo-dist version to use in CI (Cargo.toml SemVer syntax)
|
||||
cargo-dist-version = "0.22.1"
|
||||
# CI backends to support
|
||||
ci = "github"
|
||||
# The installers to generate for each app
|
||||
installers = ["shell", "powershell", "npm", "homebrew"]
|
||||
# A GitHub repo to push Homebrew formulas to
|
||||
tap = "aiken-lang/homebrew-tap"
|
||||
# Target platforms to build apps for (Rust target-triple syntax)
|
||||
targets = ["aarch64-apple-darwin", "x86_64-apple-darwin", "x86_64-unknown-linux-musl", "x86_64-pc-windows-msvc"]
|
||||
# The archive format to use for windows builds (defaults .zip)
|
||||
windows-archive = ".tar.gz"
|
||||
# The archive format to use for non-windows builds (defaults .tar.xz)
|
||||
unix-archive = ".tar.gz"
|
||||
# A namespace to use when publishing this package to the npm registry
|
||||
npm-scope = "@aiken-lang"
|
||||
# Publish jobs to run in CI
|
||||
publish-jobs = ["homebrew", "npm"]
|
||||
# Which actions to run on pull requests
|
||||
pr-run-mode = "plan"
|
||||
# Whether to install an updater program
|
||||
install-updater = false
|
||||
# Path that installers should place binaries in
|
||||
install-path = "~/.aiken/bin"
|
||||
# Whether to publish prereleases to package managers
|
||||
publish-prereleases = true
|
||||
# Inject build steps into the build-local-artifacts job to prepare the container.
|
||||
# This is needed to install libssl-dev and musl tools for producing statically linked
|
||||
# binary on Linux and avoid weird segfaults.
|
||||
#
|
||||
# Note: should be a path relative to the .github/workflows/ directory, and
|
||||
# which should point to a .yml file containing the github workflow steps just
|
||||
# as one would normally write them in a workflow.
|
||||
github-build-setup = "../musl-build-setup.yml"
|
||||
|
||||
# Cargo-dist uses ubuntu-20.04 by default, causing issues in various cases
|
||||
# because it links with openssl-1.1 whereas recent distro ships with 3.x
|
||||
[workspace.metadata.dist.github-custom-runners]
|
||||
x86_64-unknown-linux-musl = "ubuntu-22.04"
|
||||
|
||||
[workspace.dependencies]
|
||||
insta = { version = "1.30.0", features = ["yaml"] }
|
||||
walkdir = "2.3.2"
|
||||
insta = { version = "1.30.0", features = ["yaml", "json", "redactions"] }
|
||||
miette = { version = "7.2.0" }
|
||||
pallas-addresses = "0.31.0"
|
||||
pallas-codec = { version = "0.31.0", features = ["num-bigint"] }
|
||||
pallas-crypto = "0.31.0"
|
||||
pallas-primitives = "0.31.0"
|
||||
pallas-traverse = "0.31.0"
|
||||
|
||||
[profile.dev.package.insta]
|
||||
opt-level = 3
|
||||
|
||||
[profile.dev.package.similar]
|
||||
opt-level = 3
|
||||
|
||||
# The profile that 'cargo dist' will build with
|
||||
[profile.dist]
|
||||
inherits = "release"
|
||||
lto = "thin"
|
||||
|
|
3
LICENSE
3
LICENSE
|
@ -187,7 +187,8 @@
|
|||
identification within third-party archives.
|
||||
|
||||
Copyright 2016-2022 Louis Pilfold (as Gleam)
|
||||
Copyright 2022-Present TxPipe & Lucas Rosa (as Aiken)
|
||||
Copyright 2022-2024 Cardano Foundation (as Aiken)
|
||||
Copyright 2024-Present PRAGMA (as Aiken)
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
|
|
40
README.md
40
README.md
|
@ -1,36 +1,46 @@
|
|||
<div align="center">
|
||||
<img src="https://raw.githubusercontent.com/aiken-lang/branding/main/assets/logo-light.png?sanitize=true#gh-dark-mode-only" alt="Aiken" height="150" />
|
||||
<img src="https://raw.githubusercontent.com/aiken-lang/branding/main/assets/logo-dark.png?sanitize=true#gh-light-mode-only" alt="Aiken" height="150" />
|
||||
<picture>
|
||||
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/aiken-lang/branding/main/assets/logo-light.png">
|
||||
<source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/aiken-lang/branding/main/assets/logo-dark.png">
|
||||
<img alt="Aiken" src="https://raw.githubusercontent.com/aiken-lang/branding/main/assets/logo-dark.png" height="150">
|
||||
</picture>
|
||||
<hr />
|
||||
<h2 align="center" style="border-bottom: none">A modern smart contract platform for Cardano</h2>
|
||||
|
||||
[](https://github.com/aiken-lang/aiken/blob/main/LICENSE)
|
||||
[](https://crates.io/crates/aiken)
|
||||
[](https://github.com/aiken-lang/aiken/actions/workflows/tests.yml)
|
||||
[](https://github.com/aiken-lang/aiken/blob/main/LICENSE)
|
||||
[](https://github.com/aiken-lang/aiken/actions/workflows/tests.yml)
|
||||
[](https://x.com/aiken_eng)
|
||||
|
||||
[](https://crates.io/crates/aiken)
|
||||
[](https://www.npmjs.com/package/@aiken-lang/aiken)
|
||||
|
||||
<hr/>
|
||||
</div>
|
||||
|
||||
## Installation
|
||||
## Getting Started
|
||||
|
||||
- [Linux/MacOS](https://aiken-lang.org/installation-instructions#from-aikup-linux--macos-only)
|
||||
- [Windows](https://aiken-lang.org/installation-instructions#from-sources-all-platforms)
|
||||
- [nix](https://aiken-lang.org/installation-instructions#from-nix-flakes-linux--macos-only)
|
||||
- [Installation instructions](https://aiken-lang.org/installation-instructions)
|
||||
|
||||
### How to use
|
||||
- [Online playground](https://play.aiken-lang.org/)
|
||||
|
||||
For more information please see the [user manual](https://aiken-lang.org).
|
||||
- [Beginner checklist](https://aiken-lang.org/fundamentals/getting-started#checklist)
|
||||
|
||||
### Hello, World!
|
||||
|
||||
Wanna get started right-away? Complete the [_Hello, World!_ tutorial](https://aiken-lang.org/example--hello-world/basics)!
|
||||
|
||||
## Contributing
|
||||
|
||||
Want to contribute? See [CONTRIBUTING.md](./CONTRIBUTING.md) to know how.
|
||||
|
||||
---
|
||||
## Changelog
|
||||
|
||||
> **Note**
|
||||
>
|
||||
> The name comes from [Howard Aiken](https://en.wikipedia.org/wiki/Howard_H._Aiken), an American physicist and a pioneer in computing.
|
||||
Be on top of any updates using the [CHANGELOG](https://github.com/aiken-lang/aiken/blob/main/CHANGELOG.md) and the [Project Tracking](https://github.com/orgs/aiken-lang/projects/2/views/1).
|
||||
|
||||
## Stats
|
||||
|
||||

|
||||
|
||||
> [!NOTE]
|
||||
>
|
||||
> The name comes from [Howard Aiken](https://en.wikipedia.org/wiki/Howard_H._Aiken), an American physicist and a pioneer in computing.
|
||||
|
|
|
@ -1,17 +0,0 @@
|
|||
# `aikup`
|
||||
|
||||
Update or revert to a specific Aiken version with ease.
|
||||
|
||||
## Installing
|
||||
|
||||
```sh
|
||||
curl -sSfL https://install.aiken-lang.org | bash
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
To install a specific **version** (in this case the `v0.1.0`):
|
||||
|
||||
```sh
|
||||
aikup install v0.1.0
|
||||
```
|
197
aikup/aikup
197
aikup/aikup
|
@ -1,197 +0,0 @@
|
|||
#!/usr/bin/env bash
|
||||
set -e
|
||||
|
||||
AIKEN_DIR=${AIKEN_DIR-"$HOME/.aiken"}
|
||||
AIKEN_BIN_DIR="$AIKEN_DIR/bin"
|
||||
|
||||
BINS=(aiken)
|
||||
|
||||
export RUSTFLAGS="-C target-cpu=native"
|
||||
|
||||
main() {
|
||||
need_cmd git
|
||||
need_cmd curl
|
||||
|
||||
while [[ $1 ]]; do
|
||||
case $1 in
|
||||
--) shift; break;;
|
||||
|
||||
install) shift; AIKUP_VERSION=$1;;
|
||||
-l|--list)
|
||||
list_versions
|
||||
exit 0
|
||||
;;
|
||||
-h|--help)
|
||||
usage
|
||||
exit 0
|
||||
;;
|
||||
*)
|
||||
warn "unknown option: $1"
|
||||
usage
|
||||
exit 1
|
||||
esac; shift
|
||||
done
|
||||
|
||||
if [ -z "$AIKUP_VERSION" ]; then
|
||||
AIKUP_VERSION=$(get_latest_release)
|
||||
say "no version specified; installing latest: $AIKUP_VERSION"
|
||||
fi
|
||||
|
||||
# Print the banner after successfully parsing args
|
||||
banner
|
||||
|
||||
AIKUP_REPO="aiken-lang/aiken"
|
||||
|
||||
AIKUP_TAG=$AIKUP_VERSION
|
||||
|
||||
# Normalize versions
|
||||
if [[ "$AIKUP_VERSION" == [[:digit:]]* ]]; then
|
||||
# Add v prefix
|
||||
AIKUP_VERSION="v${AIKUP_VERSION}"
|
||||
AIKUP_TAG="${AIKUP_VERSION}"
|
||||
fi
|
||||
|
||||
say "installing aiken (version ${AIKUP_VERSION}, tag ${AIKUP_TAG})"
|
||||
|
||||
PLATFORM="$(uname -s)"
|
||||
case $PLATFORM in
|
||||
Linux)
|
||||
PLATFORM="linux"
|
||||
;;
|
||||
Darwin)
|
||||
PLATFORM="darwin"
|
||||
;;
|
||||
*)
|
||||
err "unsupported platform: $PLATFORM"
|
||||
;;
|
||||
esac
|
||||
|
||||
ARCHITECTURE="$(uname -m)"
|
||||
if [ "${ARCHITECTURE}" = "x86_64" ]; then
|
||||
# Redirect stderr to /dev/null to avoid printing errors if non Rosetta.
|
||||
if [ "$(sysctl -n sysctl.proc_translated 2>/dev/null)" = "1" ]; then
|
||||
ARCHITECTURE="arm64" # Rosetta.
|
||||
else
|
||||
ARCHITECTURE="amd64" # Intel.
|
||||
fi
|
||||
elif [ "${ARCHITECTURE}" = "arm64" ] ||[ "${ARCHITECTURE}" = "aarch64" ] ; then
|
||||
ARCHITECTURE="arm64" # Arm.
|
||||
else
|
||||
ARCHITECTURE="amd64" # Amd.
|
||||
fi
|
||||
|
||||
# Compute the URL of the release tarball in the Aiken repository.
|
||||
RELEASE_URL="https://github.com/${AIKUP_REPO}/releases/download/${AIKUP_TAG}/"
|
||||
BIN_TARBALL_URL="${RELEASE_URL}aiken_${AIKUP_VERSION}_${PLATFORM}_${ARCHITECTURE}.tar.gz"
|
||||
|
||||
# Download the binaries tarball and unpack it into the .aiken bin directory.
|
||||
say "downloading aiken"
|
||||
ensure curl -# -L "$BIN_TARBALL_URL" | tar -xzC "$AIKEN_BIN_DIR"
|
||||
|
||||
for bin in "${BINS[@]}"; do
|
||||
bin_path="$AIKEN_BIN_DIR/$bin"
|
||||
|
||||
# Print installed msg
|
||||
say "installed - $("$bin_path" --version)"
|
||||
|
||||
# Check if the default path of the binary is not in AIKEN_BIN_DIR
|
||||
which_path="$(which "$bin")"
|
||||
if [ "$which_path" != "$bin_path" ]; then
|
||||
warn ""
|
||||
cat 1>&2 <<EOF
|
||||
There are multiple binaries with the name '$bin' present in your 'PATH'.
|
||||
This may be the result of installing '$bin' using another method,
|
||||
like Cargo or other package managers.
|
||||
You may need to run 'rm $which_path' or move '$AIKEN_BIN_DIR'
|
||||
in your 'PATH' to allow the newly installed version to take precedence!
|
||||
EOF
|
||||
fi
|
||||
done
|
||||
|
||||
say "done"
|
||||
}
|
||||
|
||||
usage() {
|
||||
cat 1>&2 <<EOF
|
||||
The installer for Aiken.
|
||||
|
||||
Update or revert to a specific Aiken version with ease.
|
||||
|
||||
USAGE:
|
||||
aikup <SUBCOMMAND>
|
||||
|
||||
OPTIONS:
|
||||
-l, --list List available versions
|
||||
-h, --help Print help information
|
||||
|
||||
SUBCOMMANDS:
|
||||
install Install a specific version
|
||||
EOF
|
||||
}
|
||||
|
||||
list_versions() {
|
||||
say "available versions"
|
||||
curl -sSL "https://api.github.com/repos/aiken-lang/aiken/tags" |
|
||||
grep -E '"name": "v[1-9]' |
|
||||
sed 's/.*\(v[^"]*\)",.*/\1/'
|
||||
}
|
||||
|
||||
get_latest_release () {
|
||||
curl --silent "https://api.github.com/repos/aiken-lang/aiken/releases/latest" |
|
||||
grep '"tag_name":' |
|
||||
sed -E 's/.*"([^"]+)".*/\1/'
|
||||
}
|
||||
|
||||
say() {
|
||||
printf "aikup: %s\n" "$1"
|
||||
}
|
||||
|
||||
warn() {
|
||||
say "warning: ${1}" >&2
|
||||
}
|
||||
|
||||
err() {
|
||||
say "$1" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
need_cmd() {
|
||||
if ! check_cmd "$1"; then
|
||||
err "need '$1' (command not found)"
|
||||
fi
|
||||
}
|
||||
|
||||
check_cmd() {
|
||||
command -v "$1" > /dev/null 2>&1
|
||||
}
|
||||
|
||||
# Run a command that should never fail. If the command fails execution
|
||||
# will immediately terminate with an error showing the failing
|
||||
# command.
|
||||
ensure() {
|
||||
if ! "$@"; then err "command failed: $*"; fi
|
||||
}
|
||||
|
||||
# Banner Function for Aiken
|
||||
banner() {
|
||||
printf '
|
||||
|
||||
================================================================================
|
||||
|
||||
░█▀▀▄░▀█▀░▒█░▄▀░▒█▀▀▀░▒█▄░▒█ Modern and modular toolkit
|
||||
▒█▄▄█░▒█░░▒█▀▄░░▒█▀▀▀░▒█▒█▒█ for Cardano Smart Contract development.
|
||||
▒█░▒█░▄█▄░▒█░▒█░▒█▄▄▄░▒█░░▀█ Written in Rust.
|
||||
|
||||
================================================================================
|
||||
|
||||
Repo : https://github.com/aiken-lang/aiken
|
||||
Docs : https://aiken-lang.org/
|
||||
Chat : https://discord.gg/Vc3x8N9nz2
|
||||
Contribute : https://github.com/aiken-lang/aiken/blob/main/CONTRIBUTING.md
|
||||
|
||||
================================================================================
|
||||
'
|
||||
}
|
||||
|
||||
|
||||
main "$@" || exit 1
|
|
@ -1,51 +0,0 @@
|
|||
#!/usr/bin/env bash
|
||||
set -e
|
||||
|
||||
echo Installing aikup...
|
||||
|
||||
AIKEN_DIR=${AIKEN_DIR-"$HOME/.aiken"}
|
||||
AIKEN_BIN_DIR="$AIKEN_DIR/bin"
|
||||
|
||||
BIN_URL="https://raw.githubusercontent.com/aiken-lang/aiken/main/aikup/aikup"
|
||||
BIN_PATH="$AIKEN_BIN_DIR/aikup"
|
||||
|
||||
# Create the .aiken bin directory and aikup binary if it doesn't exist.
|
||||
mkdir -p $AIKEN_BIN_DIR
|
||||
curl -# -L $BIN_URL -o $BIN_PATH
|
||||
chmod +x $BIN_PATH
|
||||
|
||||
# Store the correct profile file (i.e. .profile for bash or .zshrc for ZSH).
|
||||
case $SHELL in
|
||||
*/zsh)
|
||||
PROFILE=$HOME/.zshrc
|
||||
PREF_SHELL=zsh
|
||||
INJECT="export PATH=\"\$PATH:$AIKEN_BIN_DIR\""
|
||||
;;
|
||||
*/bash)
|
||||
PROFILE=$HOME/.bashrc
|
||||
PREF_SHELL=bash
|
||||
INJECT="export PATH=\"\$PATH:$AIKEN_BIN_DIR\""
|
||||
;;
|
||||
*/fish)
|
||||
PROFILE=$HOME/.config/fish/config.fish
|
||||
PREF_SHELL=fish
|
||||
INJECT="fish_add_path $AIKEN_BIN_DIR"
|
||||
;;
|
||||
*/ash)
|
||||
PROFILE=$HOME/.profile
|
||||
PREF_SHELL=ash
|
||||
INJECT="export PATH=\"\$PATH:$AIKEN_BIN_DIR\""
|
||||
;;
|
||||
*)
|
||||
echo "aikup: could not detect shell, manually add ${AIKEN_BIN_DIR} to your PATH."
|
||||
exit 1
|
||||
esac
|
||||
|
||||
# Only add aikup if it isn't already in PATH.
|
||||
if [[ ":$PATH:" != *":${AIKEN_BIN_DIR}:"* ]]; then
|
||||
# Add the aikup directory to the path and ensure the old PATH variables remain.
|
||||
echo >> $PROFILE && echo "$INJECT" >> $PROFILE
|
||||
fi
|
||||
|
||||
echo && echo "Detected your preferred shell is ${PREF_SHELL} and added aikup to PATH. Run 'source ${PROFILE}' or start a new terminal session to use aikup."
|
||||
echo "Then, simply run 'aikup' to install Aiken."
|
|
@ -0,0 +1,6 @@
|
|||
# Aiken compilation artifacts
|
||||
artifacts/
|
||||
# Aiken's project working directory
|
||||
build/
|
||||
# Aiken's default documentation export
|
||||
docs/
|
|
@ -0,0 +1,170 @@
|
|||
# (No Fib) Benchmarks
|
||||
|
||||
This folder contains a set of benchmarks inspired and ported from the [plutus-benchmarks](https://github.com/IntersectMBO/plutus/tree/master/plutus-benchmark/nofib#plutus-nofib-benchmarks), written in Haskell. The idea is to provide benchmarks which can capture more realistic patterns and behaviours than usual "Fibonacci" benchmarks often used for benchmarking applications but falling short in capturing real-world scenarios.
|
||||
|
||||
Note that the primary use-case of those benchmarks is to compare Aiken with itself across compiler versions. As optimizations get implemented, it comes as a supplimentary means to assess their impact.
|
||||
|
||||
## Summary
|
||||
|
||||
Results are summarized below, relatively to the previous version. For brevity, we only report versions for which there's a deviation from a previous version.
|
||||
|
||||
<!--
|
||||
Plutus-Tx
|
||||
|
||||
Script Size CPU budget Memory budget
|
||||
-----------------------------------------------------------------
|
||||
clausify/F1 1573 3316814452 19803348
|
||||
clausify/F2 1573 4329805760 25708376
|
||||
clausify/F3 1573 11847889335 70086982
|
||||
clausify/F4 1573 26924400260 152296076
|
||||
clausify/F5 1573 57792275160 340971480
|
||||
knights/4x4 2049 16660243968 86107706
|
||||
knights/6x6 2049 49595956778 271079788
|
||||
knights/8x8 2049 89757683708 495426680
|
||||
primes/05digits 1501 9617902676 37194205
|
||||
primes/08digits 1501 15888515320 60723255
|
||||
primes/10digits 1501 18980946392 71916641
|
||||
primes/20digits 1501 36493682732 137260387
|
||||
primes/30digits 1501 57224069574 214186802
|
||||
primes/40digits 1501 75870264649 282727215
|
||||
primes/50digits 1501 93666987132 345920797
|
||||
queens4x4/bt 1867 5135006267 28184130
|
||||
queens4x4/bm 1867 6345082859 35502236
|
||||
queens4x4/bjbt1 1867 6252769293 34895616
|
||||
queens4x4/bjbt2 1867 5820721293 32195316
|
||||
queens4x4/fc 1867 13740412571 78668768
|
||||
queens5x5/bt 1867 71081240426 381100320
|
||||
queens5x5/bm 1867 71574838831 400366576
|
||||
queens5x5/bjbt1 1867 82536005114 449984088
|
||||
queens5x5/bjbt2 1867 79887717114 433432288
|
||||
queens5x5/fc 1867 179227518621 1023295666
|
||||
-->
|
||||
|
||||
<!--
|
||||
v1.1.0
|
||||
|
||||
┍━ benchmarks/clausify/benchmark ━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
│ PASS [mem: 53769377, cpu: 16198154564] bench_clausify_f1
|
||||
│ PASS [mem: 67108683, cpu: 20169891270] bench_clausify_f2
|
||||
│ PASS [mem: 179606857, cpu: 53923018831] bench_clausify_f3
|
||||
│ PASS [mem: 231444137, cpu: 70014384566] bench_clausify_f4
|
||||
│ PASS [mem: 874286879, cpu: 262421671684] bench_clausify_f5
|
||||
┕━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 5 tests | 5 passed | 0 failed
|
||||
|
||||
┍━ benchmarks/knights/benchmark ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
│ PASS [mem: 172246681, cpu: 57037226471] bench_knights_100_4x4
|
||||
│ PASS [mem: 321690197, cpu: 137399466410] bench_knights_100_6x6
|
||||
│ PASS [mem: 601026745, cpu: 281418742606] bench_knights_100_8x8
|
||||
┕━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 3 tests | 3 passed | 0 failed
|
||||
|
||||
|
||||
v1.0.29-alpha & v1.0.28-alpha
|
||||
|
||||
┍━ benchmarks/clausify/benchmark ━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
│ PASS [mem: 53769377, cpu: 21594809455] bench_clausify_f1
|
||||
│ PASS [mem: 67108683, cpu: 26864755594] bench_clausify_f2
|
||||
│ PASS [mem: 179606857, cpu: 71814854199] bench_clausify_f3
|
||||
│ PASS [mem: 231444137, cpu: 93024749730] bench_clausify_f4
|
||||
│ PASS [mem: 874286879, cpu: 349894049008] bench_clausify_f5
|
||||
┕━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 5 tests | 5 passed | 0 failed
|
||||
|
||||
┍━ benchmarks/knights ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
│ PASS [mem: 172256715, cpu: 71851995726] bench_knights_100_4x4
|
||||
│ PASS [mem: 321712271, cpu: 159767368294] bench_knights_100_6x6
|
||||
│ PASS [mem: 601065675, cpu: 319834775948] bench_knights_100_8x8
|
||||
┕━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 3 tests | 3 passed | 0 failed
|
||||
|
||||
==== There's no 1.0.27-alpha
|
||||
|
||||
v1.0.26-alpha & V1.0.25-alpha
|
||||
|
||||
┍━ benchmarks/clausify/benchmark ━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
│ PASS [mem: 52538257, cpu: 20243486892] bench_clausify_f1
|
||||
│ PASS [mem: 65404263, cpu: 25235091975] bench_clausify_f2
|
||||
│ PASS [mem: 174866054, cpu: 67523028814] bench_clausify_f3
|
||||
│ PASS [mem: 225087758, cpu: 88367835856] bench_clausify_f4
|
||||
│ PASS [mem: 851294369, cpu: 328896952793] bench_clausify_f5
|
||||
┕━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 5 tests | 5 passed | 0 failed
|
||||
|
||||
┍━ benchmarks/knights ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
│ PASS [mem: 171421863, cpu: 72861467671] bench_knights_100_4x4
|
||||
│ PASS [mem: 354137347, cpu: 174027736310] bench_knights_100_6x6
|
||||
│ PASS [mem: 688090183, cpu: 356296429240] bench_knights_100_8x8
|
||||
┕━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 3 tests | 3 passed | 0 failed
|
||||
|
||||
v1.0.24-alpha & V1.0.23-alpha
|
||||
|
||||
┍━ benchmarks/clausify/benchmark ━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
│ PASS [mem: 64738801, cpu: 24123180244] bench_clausify_f1
|
||||
│ PASS [mem: 80280627, cpu: 29901360387] bench_clausify_f2
|
||||
│ PASS [mem: 214423277, cpu: 79840016473] bench_clausify_f3
|
||||
│ PASS [mem: 269232481, cpu: 101739948515] bench_clausify_f4
|
||||
│ PASS [mem: 1045036759, cpu: 389233562263] bench_clausify_f5
|
||||
┕━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 5 tests | 5 passed | 0 failed
|
||||
|
||||
┍━ benchmarks/knights ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
│ PASS [mem: 180946463, cpu: 75052125671] bench_knights_100_4x4
|
||||
│ PASS [mem: 374910247, cpu: 178805503310] bench_knights_100_6x6
|
||||
│ PASS [mem: 729107683, cpu: 365730454240] bench_knights_100_8x8
|
||||
┕━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 3 tests | 3 passed | 0 failed
|
||||
|
||||
==== There's no 1.0.22-alpha
|
||||
|
||||
V1.0.21-alpha
|
||||
|
||||
┍━ benchmarks/clausify/benchmark ━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
│ PASS [mem: 64738801, cpu: 24123180244] bench_clausify_f1
|
||||
│ PASS [mem: 80280627, cpu: 29901360387] bench_clausify_f2
|
||||
│ PASS [mem: 214423277, cpu: 79840016473] bench_clausify_f3
|
||||
│ PASS [mem: 269232481, cpu: 101739948515] bench_clausify_f4
|
||||
│ PASS [mem: 1045036759, cpu: 389233562263] bench_clausify_f5
|
||||
┕━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 5 tests | 5 passed | 0 failed
|
||||
|
||||
┍━ benchmarks/knights ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
│ PASS [mem: 180697463, cpu: 74944457471] bench_knights_100_4x4
|
||||
│ PASS [mem: 374661247, cpu: 178697835110] bench_knights_100_6x6
|
||||
│ PASS [mem: 728858683, cpu: 365622786040] bench_knights_100_8x8
|
||||
┕━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 3 tests | 3 passed | 0 failed
|
||||
|
||||
V1.0.20-alpha, v1.0.19-alpha & v1.0.18-alpha
|
||||
|
||||
┍━ benchmarks/clausify/benchmark ━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
│ PASS [mem: 64861501, cpu: 24151401244] bench_clausify_f1
|
||||
│ PASS [mem: 80442927, cpu: 29938689387] bench_clausify_f2
|
||||
│ PASS [mem: 214833977, cpu: 79934477473] bench_clausify_f3
|
||||
│ PASS [mem: 269959981, cpu: 101907273515] bench_clausify_f4
|
||||
│ PASS [mem: 1046684059, cpu: 389612441263] bench_clausify_f5
|
||||
┕━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 5 tests | 5 passed | 0 failed
|
||||
|
||||
┍━ benchmarks/knights ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
│ PASS [mem: 182244075, cpu: 75300076471] bench_knights_100_4x4
|
||||
│ PASS [mem: 380548699, cpu: 180051720110] bench_knights_100_6x6
|
||||
│ PASS [mem: 740194031, cpu: 368229509040] bench_knights_100_8x8
|
||||
┕━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 3 tests | 3 passed | 0 failed
|
||||
-->
|
||||
|
||||
### CPU
|
||||
|
||||
| Benchmark | `v1.1.0` | vs `v1.0.29` | vs `v1.0.25` | vs `v1.0.23` | vs `v1.0.21` |
|
||||
| --- | ---: | ---: | ---: | ---: | ---: |
|
||||
| `clausify_f1` | 16198154564 | -24.99% | -6.26% | +11.71% | +11.71% |
|
||||
| `clausify_f2` | 20169891270 | -24.92% | -6.07% | +11.30% | +11.30% |
|
||||
| `clausify_f3` | 53923018831 | -24.91% | -5.98% | +11.17% | +11.17% |
|
||||
| `clausify_f4` | 70014384566 | -24.74% | -5.01% | +9.37% | +9.37% |
|
||||
| `clausify_f5` | 262421671684 | -25.00% | -6.00% | +11.24% | +11.24% |
|
||||
| `knights_100_4x4` | 57037226471 | -20.62% | +1.40% | +4.45% | +4.30% |
|
||||
| `knights_100_6x6` | 137399466410 | -14.00% | +8.93% | +11.92% | +11.85% |
|
||||
| `knights_100_8x8` | 281418742606 | -12.00% | +11.40% | +14.35% | +14.32% |
|
||||
|
||||
### Mem
|
||||
|
||||
| Benchmark | `v1.1.0` | vs `v1.0.29` | vs `v1.0.25` | vs `v1.0.23` | vs `v1.0.21` |
|
||||
| --- | ---: | ---: | ---: | ---: | ---: |
|
||||
| `clausify_f1` | 53769377 | ± 0.00% | -2.29% | +20.40% | +20.40% |
|
||||
| `clausify_f2` | 67108683 | ± 0.00% | -2.54% | +19.63% | +19.63% |
|
||||
| `clausify_f3` | 179606857 | ± 0.00% | -2.64% | +19.38% | +19.38% |
|
||||
| `clausify_f4` | 231444137 | ± 0.00% | -2.75% | +16.33% | +16.33% |
|
||||
| `clausify_f5` | 874286879 | ± 0.00% | -2.63% | +19.53% | +19.53% |
|
||||
| `knights_100_4x4` | 172246681 | -0.01% | -0.48% | +5.04% | +4.90% |
|
||||
| `knights_100_6x6` | 321690197 | -0.01% | +10.08% | +16.54% | +16.46% |
|
||||
| `knights_100_8x8` | 601026745 | -0.01% | +14.48% | +21.30% | +21.26% |
|
|
@ -11,3 +11,6 @@ name = "aiken-lang/stdlib"
|
|||
version = "main"
|
||||
requirements = []
|
||||
source = "github"
|
||||
|
||||
[etags]
|
||||
"aiken-lang/stdlib@main" = [{ secs_since_epoch = 1725022066, nanos_since_epoch = 34627000 }, "21da5761ffd088c964cb038888826da8a6ea1d8c26f6f4e8a1dc6e97a64fe3f7"]
|
|
@ -0,0 +1,14 @@
|
|||
name = "aiken/benchmarks"
|
||||
version = "0.0.0"
|
||||
license = "Apache-2.0"
|
||||
description = "Aiken contracts for project 'aiken/benchmarks'"
|
||||
|
||||
[repository]
|
||||
user = "aiken"
|
||||
project = "benchmarks"
|
||||
platform = "github"
|
||||
|
||||
[[dependencies]]
|
||||
name = "aiken-lang/stdlib"
|
||||
version = "main"
|
||||
source = "github"
|
|
@ -0,0 +1,300 @@
|
|||
use aiken/collection/list
|
||||
use aiken/primitive/int
|
||||
|
||||
// ------------------------------------------------------------------ Benchmarks
|
||||
|
||||
test bench_clausify_f1() {
|
||||
run_clausify(F1) == []
|
||||
}
|
||||
|
||||
test bench_clausify_f2() {
|
||||
run_clausify(F2) == []
|
||||
}
|
||||
|
||||
test bench_clausify_f3() {
|
||||
run_clausify(F3) == [([1], [])]
|
||||
}
|
||||
|
||||
test bench_clausify_f4() {
|
||||
run_clausify(F4) == [
|
||||
([1], [2, 3, 4, 5, 6, 7]),
|
||||
([1, 2, 3], [4, 5, 6, 7]),
|
||||
([1, 2, 3, 4, 5], [6, 7]),
|
||||
([1, 2, 3, 4, 5, 6, 7], []),
|
||||
([1, 2, 3, 4, 6], [5, 7]),
|
||||
([1, 2, 3, 4, 7], [5, 6]),
|
||||
([1, 2, 3, 5, 6], [4, 7]),
|
||||
([1, 2, 3, 5, 7], [4, 6]),
|
||||
([1, 2, 3, 6, 7], [4, 5]),
|
||||
([1, 2, 4], [3, 5, 6, 7]),
|
||||
([1, 2, 4, 5, 6], [3, 7]),
|
||||
([1, 2, 4, 5, 7], [3, 6]),
|
||||
([1, 2, 4, 6, 7], [3, 5]),
|
||||
([1, 2, 5], [3, 4, 6, 7]),
|
||||
([1, 2, 5, 6, 7], [3, 4]),
|
||||
([1, 2, 6], [3, 4, 5, 7]),
|
||||
([1, 2, 7], [3, 4, 5, 6]),
|
||||
([1, 3, 4], [2, 5, 6, 7]),
|
||||
([1, 3, 4, 5, 6], [2, 7]),
|
||||
([1, 3, 4, 5, 7], [2, 6]),
|
||||
([1, 3, 4, 6, 7], [2, 5]),
|
||||
([1, 3, 5], [2, 4, 6, 7]),
|
||||
([1, 3, 5, 6, 7], [2, 4]),
|
||||
([1, 3, 6], [2, 4, 5, 7]),
|
||||
([1, 3, 7], [2, 4, 5, 6]),
|
||||
([1, 4, 5], [2, 3, 6, 7]),
|
||||
([1, 4, 5, 6, 7], [2, 3]),
|
||||
([1, 4, 6], [2, 3, 5, 7]),
|
||||
([1, 4, 7], [2, 3, 5, 6]),
|
||||
([1, 5, 6], [2, 3, 4, 7]),
|
||||
([1, 5, 7], [2, 3, 4, 6]),
|
||||
([1, 6, 7], [2, 3, 4, 5]),
|
||||
([2], [1, 3, 4, 5, 6, 7]),
|
||||
([2, 3, 4], [1, 5, 6, 7]),
|
||||
([2, 3, 4, 5, 6], [1, 7]),
|
||||
([2, 3, 4, 5, 7], [1, 6]),
|
||||
([2, 3, 4, 6, 7], [1, 5]),
|
||||
([2, 3, 5], [1, 4, 6, 7]),
|
||||
([2, 3, 5, 6, 7], [1, 4]),
|
||||
([2, 3, 6], [1, 4, 5, 7]),
|
||||
([2, 3, 7], [1, 4, 5, 6]),
|
||||
([2, 4, 5], [1, 3, 6, 7]),
|
||||
([2, 4, 5, 6, 7], [1, 3]),
|
||||
([2, 4, 6], [1, 3, 5, 7]),
|
||||
([2, 4, 7], [1, 3, 5, 6]),
|
||||
([2, 5, 6], [1, 3, 4, 7]),
|
||||
([2, 5, 7], [1, 3, 4, 6]),
|
||||
([2, 6, 7], [1, 3, 4, 5]),
|
||||
([3], [1, 2, 4, 5, 6, 7]),
|
||||
([3, 4, 5], [1, 2, 6, 7]),
|
||||
([3, 4, 5, 6, 7], [1, 2]),
|
||||
([3, 4, 6], [1, 2, 5, 7]),
|
||||
([3, 4, 7], [1, 2, 5, 6]),
|
||||
([3, 5, 6], [1, 2, 4, 7]),
|
||||
([3, 5, 7], [1, 2, 4, 6]),
|
||||
([3, 6, 7], [1, 2, 4, 5]),
|
||||
([4], [1, 2, 3, 5, 6, 7]),
|
||||
([4, 5, 6], [1, 2, 3, 7]),
|
||||
([4, 5, 7], [1, 2, 3, 6]),
|
||||
([4, 6, 7], [1, 2, 3, 5]),
|
||||
([5], [1, 2, 3, 4, 6, 7]),
|
||||
([5, 6, 7], [1, 2, 3, 4]),
|
||||
([6], [1, 2, 3, 4, 5, 7]),
|
||||
([7], [1, 2, 3, 4, 5, 6]),
|
||||
]
|
||||
}
|
||||
|
||||
test bench_clausify_f5() {
|
||||
run_clausify(F5) == []
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------- Setup
|
||||
|
||||
type Var =
|
||||
Int
|
||||
|
||||
type LRVars =
|
||||
(List<Var>, List<Var>)
|
||||
|
||||
type Formula {
|
||||
Sym(Var)
|
||||
Not(Formula)
|
||||
Dis(Formula, Formula)
|
||||
Con(Formula, Formula)
|
||||
Imp(Formula, Formula)
|
||||
Eqv(Formula, Formula)
|
||||
}
|
||||
|
||||
type StaticFormula {
|
||||
F1
|
||||
F2
|
||||
F3
|
||||
F4
|
||||
F5
|
||||
}
|
||||
|
||||
fn run_clausify(static_formula: StaticFormula) -> List<LRVars> {
|
||||
static_formula
|
||||
|> get_formula
|
||||
|> clauses
|
||||
}
|
||||
|
||||
fn get_formula(static_formula: StaticFormula) -> Formula {
|
||||
when static_formula is {
|
||||
// (a = a) = (a = a) = (a = a)
|
||||
F1 ->
|
||||
Eqv(Eqv(Sym(1), Sym(1)), Eqv(Eqv(Sym(1), Sym(1)), Eqv(Sym(1), Sym(1))))
|
||||
|
||||
// (a = a = a) = (a = a = a)
|
||||
F2 ->
|
||||
Eqv(Eqv(Sym(1), Eqv(Sym(1), Sym(1))), Eqv(Sym(1), Eqv(Sym(1), Sym(1))))
|
||||
|
||||
// (a = a = a) = (a = a) = (a = a)
|
||||
F3 ->
|
||||
Eqv(
|
||||
Eqv(Sym(1), Eqv(Sym(1), Sym(1))),
|
||||
Eqv(Eqv(Sym(1), Sym(1)), Eqv(Sym(1), Sym(1))),
|
||||
)
|
||||
|
||||
// (a = b = c) = (d = e) = (f = g)
|
||||
F4 ->
|
||||
Eqv(
|
||||
Eqv(Sym(1), Eqv(Sym(2), Sym(3))),
|
||||
Eqv(Eqv(Sym(4), Sym(5)), Eqv(Sym(6), Sym(7))),
|
||||
)
|
||||
|
||||
// (a = a = a) = (a = a = a) = (a = a)
|
||||
F5 ->
|
||||
Eqv(
|
||||
Eqv(Sym(1), Eqv(Sym(1), Sym(1))),
|
||||
Eqv(Eqv(Sym(1), Eqv(Sym(1), Sym(1))), Eqv(Sym(1), Sym(1))),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fn clauses(formula: Formula) -> List<LRVars> {
|
||||
formula
|
||||
|> elim
|
||||
|> negin
|
||||
|> disin
|
||||
|> split
|
||||
|> unicl
|
||||
}
|
||||
|
||||
fn clause(formula: Formula) -> LRVars {
|
||||
do_clause(formula, ([], []))
|
||||
}
|
||||
|
||||
fn do_clause(formula: Formula, vars: LRVars) -> LRVars {
|
||||
when formula is {
|
||||
Dis(p, q) -> do_clause(p, do_clause(q, vars))
|
||||
Sym(s) -> (insert_ordered(vars.1st, s, int.compare), vars.2nd)
|
||||
Not(Sym(s)) -> (vars.1st, insert_ordered(vars.2nd, s, int.compare))
|
||||
_ -> fail
|
||||
}
|
||||
}
|
||||
|
||||
fn conjunct(formula: Formula) -> Bool {
|
||||
when formula is {
|
||||
Con(_, _) -> True
|
||||
_ -> False
|
||||
}
|
||||
}
|
||||
|
||||
/// eliminate connectives other than not, disjunction and conjunction
|
||||
fn elim(formula: Formula) -> Formula {
|
||||
when formula is {
|
||||
Sym(s) -> Sym(s)
|
||||
Not(p) -> Not(elim(p))
|
||||
Dis(p, q) -> Dis(elim(p), elim(q))
|
||||
Con(p, q) -> Con(elim(p), elim(q))
|
||||
Imp(p, q) -> Dis(Not(elim(p)), elim(q))
|
||||
Eqv(f1, f2) -> Con(elim(Imp(f1, f2)), elim(Imp(f2, f1)))
|
||||
}
|
||||
}
|
||||
|
||||
/// -- shift negation to innermost positions
|
||||
fn negin(formula: Formula) -> Formula {
|
||||
when formula is {
|
||||
Not(Not(p)) -> negin(p)
|
||||
Not(Con(p, q)) -> Dis(negin(Not(p)), negin(Not(q)))
|
||||
Not(Dis(p, q)) -> Con(negin(Not(p)), negin(Not(q)))
|
||||
Dis(p, q) -> Dis(negin(p), negin(q))
|
||||
Con(p, q) -> Con(negin(p), negin(q))
|
||||
p -> p
|
||||
}
|
||||
}
|
||||
|
||||
/// shift disjunction within conjunction
|
||||
fn disin(formula: Formula) -> Formula {
|
||||
when formula is {
|
||||
Dis(p, Con(q, r)) -> Con(disin(Dis(p, q)), disin(Dis(p, r)))
|
||||
Dis(Con(p, q), r) -> Con(disin(Dis(p, r)), disin(Dis(q, r)))
|
||||
Dis(p, q) -> {
|
||||
let dp = disin(p)
|
||||
let dq = disin(q)
|
||||
if conjunct(dp) || conjunct(dq) {
|
||||
disin(Dis(dp, dq))
|
||||
} else {
|
||||
Dis(dp, dq)
|
||||
}
|
||||
}
|
||||
Con(p, q) -> Con(disin(p), disin(q))
|
||||
p -> p
|
||||
}
|
||||
}
|
||||
|
||||
/// split conjunctive proposition into a list of conjuncts
|
||||
fn split(formula: Formula) -> List<Formula> {
|
||||
do_split(formula, [])
|
||||
}
|
||||
|
||||
fn do_split(f: Formula, fs: List<Formula>) -> List<Formula> {
|
||||
when f is {
|
||||
Con(p, q) -> do_split(p, do_split(q, fs))
|
||||
_ -> [f, ..fs]
|
||||
}
|
||||
}
|
||||
|
||||
/// form unique clausal axioms excluding tautologies
|
||||
fn unicl(formulas: List<Formula>) -> List<LRVars> {
|
||||
list.foldr(
|
||||
formulas,
|
||||
[],
|
||||
fn(p, xs) {
|
||||
let cp = clause(p)
|
||||
if tautclause(cp) {
|
||||
xs
|
||||
} else {
|
||||
insert_ordered(xs, cp, compare_lr_vars)
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
/// does any symbol appear in both consequent and antecedent of clause
|
||||
fn tautclause(var: LRVars) -> Bool {
|
||||
list.any(var.1st, list.has(var.2nd, _))
|
||||
}
|
||||
|
||||
/// insertion of an item into an ordered list
|
||||
fn insert_ordered(es: List<a>, e: a, compare: fn(a, a) -> Ordering) -> List<a> {
|
||||
when es is {
|
||||
[] -> [e]
|
||||
[head, ..tail] ->
|
||||
when compare(e, head) is {
|
||||
Less -> [e, ..es]
|
||||
Greater -> [head, ..insert_ordered(tail, e, compare)]
|
||||
Equal -> es
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn compare_lr_vars(a: LRVars, b: LRVars) -> Ordering {
|
||||
when compare_list(a.1st, b.1st) is {
|
||||
Equal -> compare_list(a.2nd, b.2nd)
|
||||
ord -> ord
|
||||
}
|
||||
}
|
||||
|
||||
fn compare_list(xs: List<Int>, ys: List<Int>) -> Ordering {
|
||||
when xs is {
|
||||
[] ->
|
||||
when ys is {
|
||||
[] -> Equal
|
||||
_ -> Less
|
||||
}
|
||||
[x, ..xs] ->
|
||||
when ys is {
|
||||
[] -> Greater
|
||||
[y, ..ys] -> {
|
||||
let ord = int.compare(x, y)
|
||||
if ord == Equal {
|
||||
compare_list(xs, ys)
|
||||
} else {
|
||||
ord
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,198 @@
|
|||
use aiken/collection/list
|
||||
use benchmarks/knights/heuristic.{descendants, start_tour, tour_finished}
|
||||
use benchmarks/knights/queue.{Queue}
|
||||
use benchmarks/knights/types.{ChessSet, Solution}
|
||||
|
||||
// ------------------------------------------------------------------ Benchmarks
|
||||
|
||||
test bench_knights_100_4x4() {
|
||||
run_knights(100, 4) == []
|
||||
}
|
||||
|
||||
test bench_knights_100_6x6() {
|
||||
run_knights(100, 6) == solution_100_6x6
|
||||
}
|
||||
|
||||
test bench_knights_100_8x8() {
|
||||
run_knights(100, 8) == solution_100_8x8
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------- Setup
|
||||
|
||||
fn run_knights(depth: Int, board_size: Int) -> Solution {
|
||||
depth_search(depth, root(board_size), grow, done) |> queue.to_list
|
||||
}
|
||||
|
||||
fn depth_search(
|
||||
depth: Int,
|
||||
xs: Queue<a>,
|
||||
grow: fn(a) -> List<a>,
|
||||
done: fn(a) -> Bool,
|
||||
) -> Queue<a> {
|
||||
if depth == 0 || queue.is_empty(xs) {
|
||||
queue.empty
|
||||
} else if done(queue.head(xs)) {
|
||||
depth_search(depth - 1, queue.remove_front(xs), grow, done)
|
||||
|> queue.append_front(queue.head(xs))
|
||||
} else {
|
||||
queue.append_all_front(queue.remove_front(xs), grow(queue.head(xs)))
|
||||
|> depth_search(depth - 1, _, grow, done)
|
||||
}
|
||||
}
|
||||
|
||||
fn root(size: Int) -> Queue<(Int, ChessSet)> {
|
||||
queue.append_all_front(queue.empty, mk_starts(size))
|
||||
}
|
||||
|
||||
fn mk_starts(size: Int) -> List<(Int, ChessSet)> {
|
||||
let it = interval(1, size)
|
||||
|
||||
let l =
|
||||
list.flat_map(
|
||||
it,
|
||||
fn(x) { list.map(it, fn(y) { start_tour((x, y), size) }) },
|
||||
)
|
||||
|
||||
let length = list.length(l)
|
||||
|
||||
expect length == size * size
|
||||
|
||||
list.zip(list.repeat(1 - length, length), l)
|
||||
}
|
||||
|
||||
fn interval(a: Int, b: Int) -> List<Int> {
|
||||
if a > b {
|
||||
[]
|
||||
} else {
|
||||
[a, ..interval(a + 1, b)]
|
||||
}
|
||||
}
|
||||
|
||||
fn grow(item: (Int, ChessSet)) -> List<(Int, ChessSet)> {
|
||||
let (x, y) = item
|
||||
descendants(y) |> list.map(fn(list_item) { (x + 1, list_item) })
|
||||
}
|
||||
|
||||
fn done(item: (Int, ChessSet)) -> Bool {
|
||||
tour_finished(item.2nd)
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------ Fixtures
|
||||
|
||||
const solution_100_6x6: Solution =
|
||||
[
|
||||
(
|
||||
0,
|
||||
ChessSet {
|
||||
size: 6,
|
||||
move_number: 36,
|
||||
start: Some((1, 1)),
|
||||
visited: [
|
||||
(3, 2), (5, 3), (6, 1), (4, 2), (3, 4), (2, 6), (4, 5), (6, 6), (5, 4),
|
||||
(6, 2), (4, 1), (2, 2), (1, 4), (3, 3), (2, 1), (1, 3), (2, 5), (4, 6),
|
||||
(6, 5), (4, 4), (5, 2), (6, 4), (5, 6), (3, 5), (1, 6), (2, 4), (1, 2),
|
||||
(3, 1), (4, 3), (5, 1), (6, 3), (5, 5), (3, 6), (1, 5), (2, 3), (1, 1),
|
||||
],
|
||||
},
|
||||
),
|
||||
(
|
||||
0,
|
||||
ChessSet {
|
||||
size: 6,
|
||||
move_number: 36,
|
||||
start: Some((1, 1)),
|
||||
visited: [
|
||||
(3, 2), (5, 3), (6, 1), (4, 2), (3, 4), (2, 2), (4, 1), (6, 2), (5, 4),
|
||||
(6, 6), (4, 5), (2, 6), (1, 4), (3, 3), (2, 1), (1, 3), (2, 5), (4, 6),
|
||||
(6, 5), (4, 4), (5, 2), (6, 4), (5, 6), (3, 5), (1, 6), (2, 4), (1, 2),
|
||||
(3, 1), (4, 3), (5, 1), (6, 3), (5, 5), (3, 6), (1, 5), (2, 3), (1, 1),
|
||||
],
|
||||
},
|
||||
),
|
||||
(
|
||||
0,
|
||||
ChessSet {
|
||||
size: 6,
|
||||
move_number: 36,
|
||||
start: Some((1, 1)),
|
||||
visited: [
|
||||
(3, 2), (5, 3), (6, 1), (4, 2), (3, 4), (2, 2), (1, 4), (2, 6), (4, 5),
|
||||
(6, 6), (5, 4), (6, 2), (4, 1), (3, 3), (2, 1), (1, 3), (2, 5), (4, 6),
|
||||
(6, 5), (4, 4), (5, 2), (6, 4), (5, 6), (3, 5), (1, 6), (2, 4), (1, 2),
|
||||
(3, 1), (4, 3), (5, 1), (6, 3), (5, 5), (3, 6), (1, 5), (2, 3), (1, 1),
|
||||
],
|
||||
},
|
||||
),
|
||||
(
|
||||
0,
|
||||
ChessSet {
|
||||
size: 6,
|
||||
move_number: 36,
|
||||
start: Some((1, 1)),
|
||||
visited: [
|
||||
(3, 2), (5, 3), (6, 1), (4, 2), (3, 4), (2, 6), (1, 4), (2, 2), (4, 1),
|
||||
(6, 2), (5, 4), (6, 6), (4, 5), (3, 3), (2, 1), (1, 3), (2, 5), (4, 6),
|
||||
(6, 5), (4, 4), (5, 2), (6, 4), (5, 6), (3, 5), (1, 6), (2, 4), (1, 2),
|
||||
(3, 1), (4, 3), (5, 1), (6, 3), (5, 5), (3, 6), (1, 5), (2, 3), (1, 1),
|
||||
],
|
||||
},
|
||||
),
|
||||
]
|
||||
|
||||
const solution_100_8x8: Solution =
|
||||
[
|
||||
(
|
||||
0,
|
||||
ChessSet {
|
||||
size: 8,
|
||||
move_number: 64,
|
||||
start: Some((1, 1)),
|
||||
visited: [
|
||||
(3, 2), (4, 4), (5, 6), (6, 4), (8, 5), (7, 7), (6, 5), (8, 4), (7, 2),
|
||||
(5, 3), (3, 4), (4, 6), (5, 8), (6, 6), (4, 5), (3, 7), (1, 8), (2, 6),
|
||||
(4, 7), (5, 5), (6, 3), (5, 1), (4, 3), (3, 5), (5, 4), (7, 3), (8, 1),
|
||||
(6, 2), (4, 1), (2, 2), (1, 4), (3, 3), (2, 5), (1, 3), (2, 1), (4, 2),
|
||||
(6, 1), (8, 2), (7, 4), (8, 6), (7, 8), (5, 7), (3, 8), (1, 7), (3, 6),
|
||||
(2, 8), (1, 6), (2, 4), (1, 2), (3, 1), (5, 2), (7, 1), (8, 3), (7, 5),
|
||||
(8, 7), (6, 8), (7, 6), (8, 8), (6, 7), (4, 8), (2, 7), (1, 5), (2, 3),
|
||||
(1, 1),
|
||||
],
|
||||
},
|
||||
),
|
||||
(
|
||||
0,
|
||||
ChessSet {
|
||||
size: 8,
|
||||
move_number: 64,
|
||||
start: Some((1, 1)),
|
||||
visited: [
|
||||
(3, 2), (4, 4), (5, 6), (7, 7), (8, 5), (6, 4), (7, 2), (8, 4), (6, 5),
|
||||
(5, 3), (3, 4), (4, 6), (5, 8), (6, 6), (4, 5), (3, 7), (1, 8), (2, 6),
|
||||
(4, 7), (5, 5), (6, 3), (5, 1), (4, 3), (3, 5), (5, 4), (7, 3), (8, 1),
|
||||
(6, 2), (4, 1), (2, 2), (1, 4), (3, 3), (2, 5), (1, 3), (2, 1), (4, 2),
|
||||
(6, 1), (8, 2), (7, 4), (8, 6), (7, 8), (5, 7), (3, 8), (1, 7), (3, 6),
|
||||
(2, 8), (1, 6), (2, 4), (1, 2), (3, 1), (5, 2), (7, 1), (8, 3), (7, 5),
|
||||
(8, 7), (6, 8), (7, 6), (8, 8), (6, 7), (4, 8), (2, 7), (1, 5), (2, 3),
|
||||
(1, 1),
|
||||
],
|
||||
},
|
||||
),
|
||||
(
|
||||
0,
|
||||
ChessSet {
|
||||
size: 8,
|
||||
move_number: 64,
|
||||
start: Some((1, 1)),
|
||||
visited: [
|
||||
(3, 2), (4, 4), (6, 5), (8, 4), (7, 2), (5, 3), (3, 4), (4, 6), (5, 8),
|
||||
(7, 7), (5, 6), (6, 4), (8, 5), (6, 6), (4, 5), (3, 7), (1, 8), (2, 6),
|
||||
(4, 7), (5, 5), (6, 3), (5, 1), (4, 3), (3, 5), (5, 4), (7, 3), (8, 1),
|
||||
(6, 2), (4, 1), (2, 2), (1, 4), (3, 3), (2, 5), (1, 3), (2, 1), (4, 2),
|
||||
(6, 1), (8, 2), (7, 4), (8, 6), (7, 8), (5, 7), (3, 8), (1, 7), (3, 6),
|
||||
(2, 8), (1, 6), (2, 4), (1, 2), (3, 1), (5, 2), (7, 1), (8, 3), (7, 5),
|
||||
(8, 7), (6, 8), (7, 6), (8, 8), (6, 7), (4, 8), (2, 7), (1, 5), (2, 3),
|
||||
(1, 1),
|
||||
],
|
||||
},
|
||||
),
|
||||
]
|
|
@ -0,0 +1,56 @@
|
|||
use aiken/collection/list
|
||||
use benchmarks/knights/types.{ChessSet, Tile}
|
||||
|
||||
pub fn create_board(size: Int, init_square: Tile) -> ChessSet {
|
||||
ChessSet {
|
||||
size,
|
||||
move_number: 1,
|
||||
start: Some(init_square),
|
||||
visited: [init_square],
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add_piece(board: ChessSet, tile: Tile) -> ChessSet {
|
||||
ChessSet {
|
||||
..board,
|
||||
move_number: board.move_number + 1,
|
||||
visited: [tile, ..board.visited],
|
||||
}
|
||||
}
|
||||
|
||||
pub fn first_piece(board: ChessSet) -> Tile {
|
||||
expect Some(tile) = board.start
|
||||
tile
|
||||
}
|
||||
|
||||
pub fn last_piece(board: ChessSet) -> Tile {
|
||||
when board.visited is {
|
||||
[] -> fail
|
||||
[x, ..] -> x
|
||||
}
|
||||
}
|
||||
|
||||
pub fn delete_first(board: ChessSet) -> ChessSet {
|
||||
let ChessSet { move_number, visited, .. } = board
|
||||
|
||||
expect Some(new_visited) = list.init(visited)
|
||||
|
||||
ChessSet {
|
||||
..board,
|
||||
move_number: move_number - 1,
|
||||
start: second_last(visited),
|
||||
visited: new_visited,
|
||||
}
|
||||
}
|
||||
|
||||
fn second_last(visited: List<a>) -> Option<a> {
|
||||
when list.reverse(visited) is {
|
||||
[] -> fail
|
||||
[_] -> None
|
||||
[_, a, ..] -> Some(a)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_square_free(board: ChessSet, tile: Tile) -> Bool {
|
||||
!list.has(board.visited, tile)
|
||||
}
|
|
@ -0,0 +1,169 @@
|
|||
use aiken/builtin
|
||||
use aiken/collection/list
|
||||
use aiken/primitive/int
|
||||
use benchmarks/knights/chess_set.{
|
||||
add_piece, create_board, delete_first, first_piece, is_square_free, last_piece,
|
||||
}
|
||||
use benchmarks/knights/sort.{quicksort}
|
||||
use benchmarks/knights/types.{ChessSet, Tile}
|
||||
|
||||
type Direction {
|
||||
UL
|
||||
UR
|
||||
DL
|
||||
DR
|
||||
LU
|
||||
LD
|
||||
RU
|
||||
RD
|
||||
}
|
||||
|
||||
const direction_list = [UL, UR, DL, DR, LU, LD, RU, RD]
|
||||
|
||||
fn move(direction: Direction, tile: Tile) -> Tile {
|
||||
let (x, y) = tile
|
||||
when direction is {
|
||||
UL -> (x - 1, y - 2)
|
||||
UR -> (x + 1, y - 2)
|
||||
DL -> (x - 1, y + 2)
|
||||
DR -> (x + 1, y + 2)
|
||||
LU -> (x - 2, y - 1)
|
||||
LD -> (x - 2, y + 1)
|
||||
RU -> (x + 2, y - 1)
|
||||
RD -> (x + 2, y + 1)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn start_tour(st: Tile, size: Int) -> ChessSet {
|
||||
expect 0 = builtin.remainder_integer(size, 2)
|
||||
create_board(size, st)
|
||||
}
|
||||
|
||||
pub fn tour_finished(board: ChessSet) -> Bool {
|
||||
let ChessSet { move_number, size, .. } = board
|
||||
move_number == size * size && can_jump_first(board)
|
||||
}
|
||||
|
||||
pub fn descendants(board: ChessSet) -> List<ChessSet> {
|
||||
if and {
|
||||
can_jump_first(board),
|
||||
board
|
||||
|> first_piece
|
||||
|> add_piece(board, _)
|
||||
|> dead_end,
|
||||
} {
|
||||
[]
|
||||
} else {
|
||||
let singles = single_descend(board)
|
||||
|
||||
when singles is {
|
||||
[] ->
|
||||
board
|
||||
|> desc_and_no
|
||||
|> quicksort(compare_chess_set)
|
||||
|> list.map(fn(t) { t.2nd })
|
||||
[_] -> singles
|
||||
_ -> []
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn can_jump_first(board: ChessSet) -> Bool {
|
||||
can_move_to(delete_first(board), first_piece(board))
|
||||
}
|
||||
|
||||
pub fn dead_end(board: ChessSet) -> Bool {
|
||||
board |> possible_moves |> builtin.null_list
|
||||
}
|
||||
|
||||
pub fn single_descend(board: ChessSet) -> List<ChessSet> {
|
||||
list.filter_map(
|
||||
desc_and_no(board),
|
||||
fn(item) {
|
||||
let (moves, board) = item
|
||||
if moves == 1 {
|
||||
Some(board)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
pub fn desc_and_no(board: ChessSet) -> List<(Int, ChessSet)> {
|
||||
board
|
||||
|> all_descend
|
||||
|> list.map(
|
||||
fn(item) {
|
||||
(item |> delete_first |> possible_moves |> list.length, item)
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
pub fn can_move_to(board: ChessSet, tile: Tile) -> Bool {
|
||||
let (x, y) = tile
|
||||
let size = board.size
|
||||
and {
|
||||
x >= 1,
|
||||
x <= size,
|
||||
y >= 1,
|
||||
y <= size,
|
||||
is_square_free(board, tile),
|
||||
}
|
||||
}
|
||||
|
||||
fn can_move(board: ChessSet, direction: Direction) -> Bool {
|
||||
board |> can_move_to(move(direction, last_piece(board)))
|
||||
}
|
||||
|
||||
pub fn all_descend(board: ChessSet) -> List<ChessSet> {
|
||||
board
|
||||
|> possible_moves
|
||||
|> list.map(move_knight(board, _))
|
||||
}
|
||||
|
||||
fn move_knight(board: ChessSet, direction: Direction) -> ChessSet {
|
||||
add_piece(board, move(direction, last_piece(board)))
|
||||
}
|
||||
|
||||
fn possible_moves(board: ChessSet) -> List<Direction> {
|
||||
direction_list |> list.filter(can_move(board, _))
|
||||
}
|
||||
|
||||
fn compare_chess_set(a: (Int, ChessSet), b: (Int, ChessSet)) -> Ordering {
|
||||
if a.1st != b.1st {
|
||||
int.compare(a.1st, b.1st)
|
||||
} else {
|
||||
compare_list(a.2nd.visited, b.2nd.visited)
|
||||
}
|
||||
}
|
||||
|
||||
fn compare_list(xs: List<Tile>, ys: List<Tile>) -> Ordering {
|
||||
when xs is {
|
||||
[] ->
|
||||
when ys is {
|
||||
[] -> Equal
|
||||
_ -> Less
|
||||
}
|
||||
[x, ..xs] ->
|
||||
when ys is {
|
||||
[] -> Greater
|
||||
[y, ..ys] -> {
|
||||
let ord = compare_tile(x, y)
|
||||
if ord == Equal {
|
||||
compare_list(xs, ys)
|
||||
} else {
|
||||
ord
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn compare_tile(a: Tile, b: Tile) -> Ordering {
|
||||
if a.1st == b.1st {
|
||||
int.compare(a.2nd, b.2nd)
|
||||
} else {
|
||||
int.compare(a.1st, b.1st)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
use aiken/collection/list
|
||||
|
||||
pub opaque type Queue<a> {
|
||||
inner: List<a>,
|
||||
}
|
||||
|
||||
pub const empty: Queue<a> = [] |> Queue
|
||||
|
||||
pub fn to_list(self: Queue<a>) -> List<a> {
|
||||
self.inner
|
||||
}
|
||||
|
||||
pub fn is_empty(self: Queue<a>) -> Bool {
|
||||
when self.inner is {
|
||||
[] -> True
|
||||
_ -> False
|
||||
}
|
||||
}
|
||||
|
||||
pub fn append_front(self: Queue<a>, item: a) -> Queue<a> {
|
||||
list.push(self.inner, item) |> Queue
|
||||
}
|
||||
|
||||
pub fn append_all_front(self: Queue<a>, items: List<a>) -> Queue<a> {
|
||||
list.concat(items, self.inner) |> Queue
|
||||
}
|
||||
|
||||
pub fn remove_front(self: Queue<a>) -> Queue<a> {
|
||||
expect [_, ..rest] = self.inner
|
||||
rest |> Queue
|
||||
}
|
||||
|
||||
pub fn head(self: Queue<a>) -> a {
|
||||
expect [q, ..] = self.inner
|
||||
q
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
use aiken/collection/list
|
||||
|
||||
pub fn quicksort(xs: List<a>, compare: fn(a, a) -> Ordering) -> List<a> {
|
||||
when xs is {
|
||||
[] -> []
|
||||
[head, ..tail] -> {
|
||||
let before =
|
||||
tail
|
||||
|> list.filter(fn(x) { compare(x, head) == Less })
|
||||
|> quicksort(compare)
|
||||
let after =
|
||||
tail
|
||||
|> list.filter(fn(x) { compare(x, head) != Less })
|
||||
|> quicksort(compare)
|
||||
list.concat(before, [head, ..after])
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
pub type Tile =
|
||||
(Int, Int)
|
||||
|
||||
pub type ChessSet {
|
||||
size: Int,
|
||||
move_number: Int,
|
||||
start: Option<Tile>,
|
||||
visited: List<Tile>,
|
||||
}
|
||||
|
||||
pub type Solution =
|
||||
List<(Int, ChessSet)>
|
|
@ -0,0 +1,14 @@
|
|||
{
|
||||
"preamble": {
|
||||
"title": "aiken/benchmarks",
|
||||
"description": "Aiken contracts for project 'aiken/benchmarks'",
|
||||
"version": "0.0.0",
|
||||
"plutusVersion": "v2",
|
||||
"compiler": {
|
||||
"name": "Aiken",
|
||||
"version": "v1.0.29-alpha+dfce9c1"
|
||||
},
|
||||
"license": "Apache-2.0"
|
||||
},
|
||||
"validators": []
|
||||
}
|
|
@ -1,41 +1,52 @@
|
|||
[package]
|
||||
name = "aiken-lang"
|
||||
description = "The Aiken compiler"
|
||||
version = "1.0.13-alpha"
|
||||
version = "1.1.7"
|
||||
edition = "2021"
|
||||
repository = "https://github.com/aiken-lang/aiken"
|
||||
homepage = "https://github.com/aiken-lang/aiken"
|
||||
license = "Apache-2.0"
|
||||
authors = [
|
||||
"Lucas Rosa <x@rvcas.dev>",
|
||||
"Kasey White <kwhitemsg@gmail.com>",
|
||||
"KtorZ <matthias.benkort@gmail.com>",
|
||||
"Lucas Rosa <x@rvcas.dev>",
|
||||
"Kasey White <kwhitemsg@gmail.com>",
|
||||
"KtorZ <matthias.benkort@gmail.com>",
|
||||
]
|
||||
rust-version = "1.66.1"
|
||||
rust-version = "1.70.0"
|
||||
build = "build.rs"
|
||||
|
||||
[dependencies]
|
||||
blst = "0.3.11"
|
||||
cryptoxide = "0.4.4"
|
||||
hex = "0.4.3"
|
||||
indexmap = "1.9.2"
|
||||
indoc = "2.0.1"
|
||||
itertools = "0.10.5"
|
||||
miette = "5.9.0"
|
||||
miette.workspace = true
|
||||
num-bigint = "0.4.3"
|
||||
ordinal = "0.3.2"
|
||||
owo-colors = { version = "3.5.0", features = ["supports-colors"] }
|
||||
pallas-primitives.workspace = true
|
||||
patricia_tree = "0.8.0"
|
||||
petgraph = "0.6.3"
|
||||
pretty = "0.12.3"
|
||||
serde = { version = "1.0.197", features = ["derive", "rc"] }
|
||||
strum = "0.24.1"
|
||||
thiserror = "1.0.39"
|
||||
uplc = { path = '../uplc', version = "1.1.7" }
|
||||
vec1 = "1.10.1"
|
||||
uplc = { path = '../uplc', version = "1.0.13-alpha" }
|
||||
num-bigint = "0.4.3"
|
||||
|
||||
[target.'cfg(not(target_family="wasm"))'.dependencies]
|
||||
chumsky = "0.9.2"
|
||||
[target.'cfg(target_family="wasm")'.dependencies]
|
||||
chumsky = { version = "0.9.2", features = [
|
||||
"ahash",
|
||||
"std",
|
||||
"ahash",
|
||||
"std",
|
||||
], default-features = false }
|
||||
|
||||
[dev-dependencies]
|
||||
indoc = "2.0.1"
|
||||
insta.workspace = true
|
||||
pretty_assertions = "1.3.0"
|
||||
|
||||
[build-dependencies]
|
||||
built = { version = "0.7.1", features = ["git2"] }
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,352 @@
|
|||
use crate::{
|
||||
ast::{Annotation, Span},
|
||||
tipo::{Type, TypeAliasAnnotation, TypeVar},
|
||||
};
|
||||
use std::{cell::RefCell, rc::Rc};
|
||||
|
||||
pub const BOOL: &str = "Bool";
|
||||
pub const BOOL_CONSTRUCTORS: &[&str] = &["False", "True"];
|
||||
pub const BYTE_ARRAY: &str = "ByteArray";
|
||||
pub const DATA: &str = "Data";
|
||||
pub const FUZZER: &str = "Fuzzer";
|
||||
pub const G1_ELEMENT: &str = "G1Element";
|
||||
pub const G2_ELEMENT: &str = "G2Element";
|
||||
pub const INT: &str = "Int";
|
||||
pub const LIST: &str = "List";
|
||||
pub const MILLER_LOOP_RESULT: &str = "MillerLoopResult";
|
||||
pub const OPTION: &str = "Option";
|
||||
pub const OPTION_CONSTRUCTORS: &[&str] = &["Some", "None"];
|
||||
pub const NEVER: &str = "Never";
|
||||
pub const NEVER_CONSTRUCTORS: &[&str] = &["__hole", "Never"];
|
||||
pub const ORDERING: &str = "Ordering";
|
||||
pub const ORDERING_CONSTRUCTORS: &[&str] = &["Less", "Equal", "Greater"];
|
||||
pub const PAIR: &str = "Pair";
|
||||
pub const PAIRS: &str = "Pairs";
|
||||
pub const PRNG: &str = "PRNG";
|
||||
pub const PRNG_CONSTRUCTORS: &[&str] = &["Seeded", "Replayed"];
|
||||
pub const REDEEMER_WRAPPER: &str = "RedeemerWrapper";
|
||||
pub const STRING: &str = "String";
|
||||
pub const VOID: &str = "Void";
|
||||
pub const VOID_CONSTRUCTORS: &[&str] = &["Void"];
|
||||
|
||||
pub const SCRIPT_CONTEXT: &str = "__ScriptContext";
|
||||
pub const SCRIPT_CONTEXT_CONSTRUCTORS: &[&str] = &["__ScriptContext"];
|
||||
pub const SCRIPT_CONTEXT_TRANSACTION: &str = "__Transaction";
|
||||
pub const SCRIPT_CONTEXT_REDEEMER: &str = "__Redeemer";
|
||||
pub const SCRIPT_CONTEXT_PURPOSE: &str = "__ScriptPurpose";
|
||||
|
||||
pub const SCRIPT_PURPOSE: &str = "__ScriptPurpose";
|
||||
pub const SCRIPT_PURPOSE_MINT: &str = "__Mint";
|
||||
pub const SCRIPT_PURPOSE_SPEND: &str = "__Spend";
|
||||
pub const SCRIPT_PURPOSE_WITHDRAW: &str = "__Withdraw";
|
||||
pub const SCRIPT_PURPOSE_PUBLISH: &str = "__Publish";
|
||||
pub const SCRIPT_PURPOSE_VOTE: &str = "__Vote";
|
||||
pub const SCRIPT_PURPOSE_PROPOSE: &str = "__Propose";
|
||||
pub const SCRIPT_PURPOSE_CONSTRUCTORS: &[&str] = &[
|
||||
SCRIPT_PURPOSE_MINT,
|
||||
SCRIPT_PURPOSE_SPEND,
|
||||
SCRIPT_PURPOSE_WITHDRAW,
|
||||
SCRIPT_PURPOSE_PUBLISH,
|
||||
SCRIPT_PURPOSE_VOTE,
|
||||
SCRIPT_PURPOSE_PROPOSE,
|
||||
];
|
||||
|
||||
pub const VALIDATOR_ELSE: &str = "else";
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Types
|
||||
|
||||
impl Type {
|
||||
pub fn data() -> Rc<Type> {
|
||||
Rc::new(Type::App {
|
||||
public: true,
|
||||
contains_opaque: false,
|
||||
name: DATA.to_string(),
|
||||
module: "".to_string(),
|
||||
args: vec![],
|
||||
alias: None,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn int() -> Rc<Type> {
|
||||
Rc::new(Type::App {
|
||||
public: true,
|
||||
contains_opaque: false,
|
||||
name: INT.to_string(),
|
||||
module: "".to_string(),
|
||||
args: vec![],
|
||||
alias: None,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn bool() -> Rc<Self> {
|
||||
Rc::new(Type::App {
|
||||
args: vec![],
|
||||
public: true,
|
||||
contains_opaque: false,
|
||||
name: BOOL.to_string(),
|
||||
module: "".to_string(),
|
||||
alias: None,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn byte_array() -> Rc<Type> {
|
||||
Rc::new(Type::App {
|
||||
args: vec![],
|
||||
public: true,
|
||||
contains_opaque: false,
|
||||
name: BYTE_ARRAY.to_string(),
|
||||
module: "".to_string(),
|
||||
alias: None,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn g1_element() -> Rc<Type> {
|
||||
Rc::new(Type::App {
|
||||
public: true,
|
||||
contains_opaque: false,
|
||||
module: "".to_string(),
|
||||
name: G1_ELEMENT.to_string(),
|
||||
args: vec![],
|
||||
alias: None,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn g2_element() -> Rc<Type> {
|
||||
Rc::new(Type::App {
|
||||
public: true,
|
||||
contains_opaque: false,
|
||||
module: "".to_string(),
|
||||
name: G2_ELEMENT.to_string(),
|
||||
args: vec![],
|
||||
alias: None,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn miller_loop_result() -> Rc<Type> {
|
||||
Rc::new(Type::App {
|
||||
public: true,
|
||||
contains_opaque: false,
|
||||
module: "".to_string(),
|
||||
name: MILLER_LOOP_RESULT.to_string(),
|
||||
args: vec![],
|
||||
alias: None,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn tuple(elems: Vec<Rc<Type>>) -> Rc<Type> {
|
||||
Rc::new(Type::Tuple { elems, alias: None })
|
||||
}
|
||||
|
||||
pub fn pair(fst: Rc<Type>, snd: Rc<Type>) -> Rc<Type> {
|
||||
Rc::new(Type::Pair {
|
||||
fst,
|
||||
snd,
|
||||
alias: None,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn script_purpose() -> Rc<Type> {
|
||||
Rc::new(Type::App {
|
||||
args: vec![],
|
||||
public: true,
|
||||
contains_opaque: false,
|
||||
name: SCRIPT_PURPOSE.to_string(),
|
||||
module: "".to_string(),
|
||||
alias: None,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn script_context() -> Rc<Type> {
|
||||
Rc::new(Type::App {
|
||||
args: vec![],
|
||||
public: true,
|
||||
contains_opaque: false,
|
||||
name: SCRIPT_CONTEXT.to_string(),
|
||||
module: "".to_string(),
|
||||
alias: None,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn prng() -> Rc<Type> {
|
||||
Rc::new(Type::App {
|
||||
args: vec![],
|
||||
public: true,
|
||||
contains_opaque: false,
|
||||
name: PRNG.to_string(),
|
||||
module: "".to_string(),
|
||||
alias: None,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn fuzzer(a: Rc<Type>) -> Rc<Type> {
|
||||
let prng_annotation = Annotation::Constructor {
|
||||
location: Span::empty(),
|
||||
module: None,
|
||||
name: PRNG.to_string(),
|
||||
arguments: vec![],
|
||||
};
|
||||
|
||||
Rc::new(Type::Fn {
|
||||
args: vec![Type::prng()],
|
||||
ret: Type::option(Type::tuple(vec![Type::prng(), a])),
|
||||
alias: Some(
|
||||
TypeAliasAnnotation {
|
||||
alias: FUZZER.to_string(),
|
||||
parameters: vec!["a".to_string()],
|
||||
annotation: Annotation::Fn {
|
||||
location: Span::empty(),
|
||||
arguments: vec![prng_annotation.clone()],
|
||||
ret: Annotation::Constructor {
|
||||
location: Span::empty(),
|
||||
module: None,
|
||||
name: OPTION.to_string(),
|
||||
arguments: vec![Annotation::Tuple {
|
||||
location: Span::empty(),
|
||||
elems: vec![
|
||||
prng_annotation,
|
||||
Annotation::Var {
|
||||
location: Span::empty(),
|
||||
name: "a".to_string(),
|
||||
},
|
||||
],
|
||||
}],
|
||||
}
|
||||
.into(),
|
||||
},
|
||||
}
|
||||
.into(),
|
||||
),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn map(k: Rc<Type>, v: Rc<Type>) -> Rc<Type> {
|
||||
Rc::new(Type::App {
|
||||
public: true,
|
||||
contains_opaque: false,
|
||||
module: "".to_string(),
|
||||
name: LIST.to_string(),
|
||||
args: vec![Type::pair(k, v)],
|
||||
alias: Some(
|
||||
TypeAliasAnnotation {
|
||||
alias: PAIRS.to_string(),
|
||||
parameters: vec!["k".to_string(), "v".to_string()],
|
||||
annotation: Annotation::Constructor {
|
||||
location: Span::empty(),
|
||||
module: None,
|
||||
name: LIST.to_string(),
|
||||
arguments: vec![Annotation::Pair {
|
||||
location: Span::empty(),
|
||||
fst: Box::new(Annotation::Var {
|
||||
location: Span::empty(),
|
||||
name: "k".to_string(),
|
||||
}),
|
||||
snd: Box::new(Annotation::Var {
|
||||
location: Span::empty(),
|
||||
name: "v".to_string(),
|
||||
}),
|
||||
}],
|
||||
},
|
||||
}
|
||||
.into(),
|
||||
),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn list(t: Rc<Type>) -> Rc<Type> {
|
||||
Rc::new(Type::App {
|
||||
public: true,
|
||||
contains_opaque: t.contains_opaque(),
|
||||
name: LIST.to_string(),
|
||||
module: "".to_string(),
|
||||
args: vec![t],
|
||||
alias: None,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn string() -> Rc<Type> {
|
||||
Rc::new(Type::App {
|
||||
args: vec![],
|
||||
public: true,
|
||||
contains_opaque: false,
|
||||
name: STRING.to_string(),
|
||||
module: "".to_string(),
|
||||
alias: None,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn void() -> Rc<Type> {
|
||||
Rc::new(Type::App {
|
||||
args: vec![],
|
||||
public: true,
|
||||
contains_opaque: false,
|
||||
name: VOID.to_string(),
|
||||
module: "".to_string(),
|
||||
alias: None,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn option(a: Rc<Type>) -> Rc<Type> {
|
||||
Rc::new(Type::App {
|
||||
public: true,
|
||||
contains_opaque: a.contains_opaque(),
|
||||
name: OPTION.to_string(),
|
||||
module: "".to_string(),
|
||||
args: vec![a],
|
||||
alias: None,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn never() -> Rc<Type> {
|
||||
Rc::new(Type::App {
|
||||
public: true,
|
||||
contains_opaque: false,
|
||||
name: NEVER.to_string(),
|
||||
module: "".to_string(),
|
||||
args: vec![],
|
||||
alias: None,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn ordering() -> Rc<Type> {
|
||||
Rc::new(Type::App {
|
||||
public: true,
|
||||
contains_opaque: false,
|
||||
name: ORDERING.to_string(),
|
||||
module: "".to_string(),
|
||||
args: vec![],
|
||||
alias: None,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn function(args: Vec<Rc<Type>>, ret: Rc<Type>) -> Rc<Type> {
|
||||
Rc::new(Type::Fn {
|
||||
ret,
|
||||
args,
|
||||
alias: None,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn generic_var(id: u64) -> Rc<Type> {
|
||||
let tipo = Rc::new(RefCell::new(TypeVar::Generic { id }));
|
||||
|
||||
Rc::new(Type::Var { tipo, alias: None })
|
||||
}
|
||||
|
||||
pub fn unbound_var(id: u64) -> Rc<Type> {
|
||||
let tipo = Rc::new(RefCell::new(TypeVar::Unbound { id }));
|
||||
|
||||
Rc::new(Type::Var { tipo, alias: None })
|
||||
}
|
||||
|
||||
pub fn wrapped_redeemer(redeemer: Rc<Type>) -> Rc<Type> {
|
||||
Rc::new(Type::App {
|
||||
public: true,
|
||||
contains_opaque: false,
|
||||
module: "".to_string(),
|
||||
name: REDEEMER_WRAPPER.to_string(),
|
||||
args: vec![redeemer],
|
||||
alias: None,
|
||||
})
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,3 @@
|
|||
pub trait ExtraData {
|
||||
fn extra_data(&self) -> Option<String>;
|
||||
}
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -1,430 +1,225 @@
|
|||
use indexmap::IndexSet;
|
||||
use std::sync::Arc;
|
||||
use uplc::builtins::DefaultFunction;
|
||||
|
||||
use crate::{
|
||||
ast::{BinOp, UnOp},
|
||||
ast::{BinOp, Curve, UnOp},
|
||||
tipo::{Type, ValueConstructor},
|
||||
};
|
||||
use indexmap::IndexSet;
|
||||
use std::rc::Rc;
|
||||
use uplc::builtins::DefaultFunction;
|
||||
|
||||
use super::scope::Scope;
|
||||
#[derive(Debug, Clone, PartialEq, Copy)]
|
||||
pub enum ExpectLevel {
|
||||
Full,
|
||||
Items,
|
||||
None,
|
||||
}
|
||||
|
||||
impl From<bool> for ExpectLevel {
|
||||
fn from(value: bool) -> Self {
|
||||
if value {
|
||||
ExpectLevel::Full
|
||||
} else {
|
||||
ExpectLevel::None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub enum FunctionVariants {
|
||||
Standard(Vec<String>),
|
||||
Recursive {
|
||||
params: Vec<String>,
|
||||
recursive_nonstatic_params: Vec<String>,
|
||||
},
|
||||
Cyclic(Vec<Vec<String>>),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub enum Air {
|
||||
// Primitives
|
||||
Int {
|
||||
scope: Scope,
|
||||
value: String,
|
||||
},
|
||||
String {
|
||||
scope: Scope,
|
||||
value: String,
|
||||
},
|
||||
ByteArray {
|
||||
scope: Scope,
|
||||
bytes: Vec<u8>,
|
||||
},
|
||||
CurvePoint {
|
||||
point: Curve,
|
||||
},
|
||||
Bool {
|
||||
scope: Scope,
|
||||
value: bool,
|
||||
},
|
||||
List {
|
||||
scope: Scope,
|
||||
count: usize,
|
||||
tipo: Arc<Type>,
|
||||
tipo: Rc<Type>,
|
||||
tail: bool,
|
||||
},
|
||||
Tuple {
|
||||
scope: Scope,
|
||||
tipo: Arc<Type>,
|
||||
tipo: Rc<Type>,
|
||||
count: usize,
|
||||
},
|
||||
Void {
|
||||
scope: Scope,
|
||||
Pair {
|
||||
tipo: Rc<Type>,
|
||||
},
|
||||
Void,
|
||||
Var {
|
||||
scope: Scope,
|
||||
constructor: ValueConstructor,
|
||||
name: String,
|
||||
variant_name: String,
|
||||
},
|
||||
// Functions
|
||||
Call {
|
||||
scope: Scope,
|
||||
count: usize,
|
||||
tipo: Arc<Type>,
|
||||
tipo: Rc<Type>,
|
||||
},
|
||||
DefineFunc {
|
||||
scope: Scope,
|
||||
func_name: String,
|
||||
module_name: String,
|
||||
params: Vec<String>,
|
||||
recursive: bool,
|
||||
variant_name: String,
|
||||
variant: FunctionVariants,
|
||||
},
|
||||
Fn {
|
||||
scope: Scope,
|
||||
params: Vec<String>,
|
||||
allow_inline: bool,
|
||||
},
|
||||
Builtin {
|
||||
scope: Scope,
|
||||
count: usize,
|
||||
func: DefaultFunction,
|
||||
tipo: Arc<Type>,
|
||||
tipo: Rc<Type>,
|
||||
},
|
||||
// Operators
|
||||
BinOp {
|
||||
scope: Scope,
|
||||
name: BinOp,
|
||||
tipo: Arc<Type>,
|
||||
tipo: Rc<Type>,
|
||||
argument_tipo: Rc<Type>,
|
||||
},
|
||||
UnOp {
|
||||
scope: Scope,
|
||||
op: UnOp,
|
||||
},
|
||||
// Assignment
|
||||
Let {
|
||||
scope: Scope,
|
||||
name: String,
|
||||
},
|
||||
UnWrapData {
|
||||
scope: Scope,
|
||||
tipo: Arc<Type>,
|
||||
SoftCastLet {
|
||||
name: String,
|
||||
tipo: Rc<Type>,
|
||||
},
|
||||
WrapData {
|
||||
scope: Scope,
|
||||
tipo: Arc<Type>,
|
||||
CastFromData {
|
||||
tipo: Rc<Type>,
|
||||
full_cast: bool,
|
||||
},
|
||||
AssertConstr {
|
||||
scope: Scope,
|
||||
constr_index: usize,
|
||||
CastToData {
|
||||
tipo: Rc<Type>,
|
||||
},
|
||||
AssertBool {
|
||||
scope: Scope,
|
||||
is_true: bool,
|
||||
},
|
||||
// When
|
||||
When {
|
||||
scope: Scope,
|
||||
tipo: Arc<Type>,
|
||||
tipo: Rc<Type>,
|
||||
subject_name: String,
|
||||
subject_tipo: Rc<Type>,
|
||||
},
|
||||
Clause {
|
||||
scope: Scope,
|
||||
tipo: Arc<Type>,
|
||||
subject_tipo: Rc<Type>,
|
||||
subject_name: String,
|
||||
complex_clause: bool,
|
||||
},
|
||||
ListClause {
|
||||
scope: Scope,
|
||||
tipo: Arc<Type>,
|
||||
subject_tipo: Rc<Type>,
|
||||
tail_name: String,
|
||||
next_tail_name: Option<String>,
|
||||
complex_clause: bool,
|
||||
},
|
||||
WrapClause {
|
||||
scope: Scope,
|
||||
next_tail_name: Option<(String, String)>,
|
||||
},
|
||||
WrapClause,
|
||||
TupleClause {
|
||||
scope: Scope,
|
||||
tipo: Arc<Type>,
|
||||
subject_tipo: Rc<Type>,
|
||||
indices: IndexSet<(usize, String)>,
|
||||
predefined_indices: IndexSet<(usize, String)>,
|
||||
subject_name: String,
|
||||
count: usize,
|
||||
complex_clause: bool,
|
||||
},
|
||||
PairClause {
|
||||
subject_tipo: Rc<Type>,
|
||||
subject_name: String,
|
||||
fst_name: Option<String>,
|
||||
snd_name: Option<String>,
|
||||
complex_clause: bool,
|
||||
},
|
||||
ClauseGuard {
|
||||
scope: Scope,
|
||||
subject_name: String,
|
||||
tipo: Arc<Type>,
|
||||
subject_tipo: Rc<Type>,
|
||||
},
|
||||
ListClauseGuard {
|
||||
scope: Scope,
|
||||
tipo: Arc<Type>,
|
||||
subject_tipo: Rc<Type>,
|
||||
tail_name: String,
|
||||
next_tail_name: Option<String>,
|
||||
inverse: bool,
|
||||
},
|
||||
Finally {
|
||||
scope: Scope,
|
||||
TupleGuard {
|
||||
subject_tipo: Rc<Type>,
|
||||
indices: IndexSet<(usize, String)>,
|
||||
subject_name: String,
|
||||
},
|
||||
PairGuard {
|
||||
subject_tipo: Rc<Type>,
|
||||
subject_name: String,
|
||||
fst_name: Option<String>,
|
||||
snd_name: Option<String>,
|
||||
},
|
||||
Finally,
|
||||
// If
|
||||
If {
|
||||
scope: Scope,
|
||||
tipo: Arc<Type>,
|
||||
tipo: Rc<Type>,
|
||||
},
|
||||
// Record Creation
|
||||
Record {
|
||||
scope: Scope,
|
||||
Constr {
|
||||
tag: usize,
|
||||
tipo: Arc<Type>,
|
||||
tipo: Rc<Type>,
|
||||
count: usize,
|
||||
},
|
||||
RecordUpdate {
|
||||
scope: Scope,
|
||||
highest_index: usize,
|
||||
indices: Vec<(usize, Arc<Type>)>,
|
||||
tipo: Arc<Type>,
|
||||
indices: Vec<(usize, Rc<Type>)>,
|
||||
tipo: Rc<Type>,
|
||||
},
|
||||
// Field Access
|
||||
RecordAccess {
|
||||
scope: Scope,
|
||||
record_index: u64,
|
||||
tipo: Arc<Type>,
|
||||
},
|
||||
FieldsExpose {
|
||||
scope: Scope,
|
||||
indices: Vec<(usize, String, Arc<Type>)>,
|
||||
check_last_item: bool,
|
||||
indices: Vec<(usize, String, Rc<Type>)>,
|
||||
is_expect: bool,
|
||||
},
|
||||
// ListAccess
|
||||
ListAccessor {
|
||||
scope: Scope,
|
||||
tipo: Arc<Type>,
|
||||
tipo: Rc<Type>,
|
||||
names: Vec<String>,
|
||||
tail: bool,
|
||||
check_last_item: bool,
|
||||
},
|
||||
ListExpose {
|
||||
scope: Scope,
|
||||
tipo: Arc<Type>,
|
||||
tail_head_names: Vec<(String, String)>,
|
||||
tail: Option<(String, String)>,
|
||||
expect_level: ExpectLevel,
|
||||
},
|
||||
// Tuple Access
|
||||
TupleAccessor {
|
||||
scope: Scope,
|
||||
names: Vec<String>,
|
||||
tipo: Arc<Type>,
|
||||
check_last_item: bool,
|
||||
tipo: Rc<Type>,
|
||||
is_expect: bool,
|
||||
},
|
||||
TupleIndex {
|
||||
scope: Scope,
|
||||
tipo: Arc<Type>,
|
||||
tuple_index: usize,
|
||||
// Pair Access
|
||||
PairAccessor {
|
||||
fst: Option<String>,
|
||||
snd: Option<String>,
|
||||
tipo: Rc<Type>,
|
||||
is_expect: bool,
|
||||
},
|
||||
ExtractField {
|
||||
tipo: Rc<Type>,
|
||||
},
|
||||
// Misc.
|
||||
ErrorTerm {
|
||||
scope: Scope,
|
||||
tipo: Arc<Type>,
|
||||
tipo: Rc<Type>,
|
||||
validator: bool,
|
||||
},
|
||||
Trace {
|
||||
scope: Scope,
|
||||
tipo: Arc<Type>,
|
||||
},
|
||||
NoOp {
|
||||
scope: Scope,
|
||||
},
|
||||
FieldsEmpty {
|
||||
scope: Scope,
|
||||
},
|
||||
ListEmpty {
|
||||
scope: Scope,
|
||||
tipo: Rc<Type>,
|
||||
},
|
||||
}
|
||||
|
||||
impl Air {
|
||||
pub fn scope(&self) -> Scope {
|
||||
match self {
|
||||
Air::Int { scope, .. }
|
||||
| Air::String { scope, .. }
|
||||
| Air::ByteArray { scope, .. }
|
||||
| Air::Bool { scope, .. }
|
||||
| Air::List { scope, .. }
|
||||
| Air::Tuple { scope, .. }
|
||||
| Air::Void { scope }
|
||||
| Air::Var { scope, .. }
|
||||
| Air::Call { scope, .. }
|
||||
| Air::DefineFunc { scope, .. }
|
||||
| Air::Fn { scope, .. }
|
||||
| Air::Builtin { scope, .. }
|
||||
| Air::BinOp { scope, .. }
|
||||
| Air::UnOp { scope, .. }
|
||||
| Air::Let { scope, .. }
|
||||
| Air::UnWrapData { scope, .. }
|
||||
| Air::WrapData { scope, .. }
|
||||
| Air::AssertConstr { scope, .. }
|
||||
| Air::AssertBool { scope, .. }
|
||||
| Air::When { scope, .. }
|
||||
| Air::Clause { scope, .. }
|
||||
| Air::ListClause { scope, .. }
|
||||
| Air::WrapClause { scope }
|
||||
| Air::TupleClause { scope, .. }
|
||||
| Air::ClauseGuard { scope, .. }
|
||||
| Air::ListClauseGuard { scope, .. }
|
||||
| Air::Finally { scope }
|
||||
| Air::If { scope, .. }
|
||||
| Air::Record { scope, .. }
|
||||
| Air::RecordUpdate { scope, .. }
|
||||
| Air::RecordAccess { scope, .. }
|
||||
| Air::FieldsExpose { scope, .. }
|
||||
| Air::FieldsEmpty { scope }
|
||||
| Air::ListEmpty { scope }
|
||||
| Air::ListAccessor { scope, .. }
|
||||
| Air::ListExpose { scope, .. }
|
||||
| Air::TupleAccessor { scope, .. }
|
||||
| Air::TupleIndex { scope, .. }
|
||||
| Air::ErrorTerm { scope, .. }
|
||||
| Air::Trace { scope, .. }
|
||||
| Air::NoOp { scope, .. } => scope.clone(),
|
||||
}
|
||||
}
|
||||
pub fn scope_mut(&mut self) -> &mut Scope {
|
||||
match self {
|
||||
Air::Int { scope, .. }
|
||||
| Air::String { scope, .. }
|
||||
| Air::ByteArray { scope, .. }
|
||||
| Air::Bool { scope, .. }
|
||||
| Air::List { scope, .. }
|
||||
| Air::Tuple { scope, .. }
|
||||
| Air::Void { scope }
|
||||
| Air::Var { scope, .. }
|
||||
| Air::Call { scope, .. }
|
||||
| Air::DefineFunc { scope, .. }
|
||||
| Air::Fn { scope, .. }
|
||||
| Air::Builtin { scope, .. }
|
||||
| Air::BinOp { scope, .. }
|
||||
| Air::UnOp { scope, .. }
|
||||
| Air::Let { scope, .. }
|
||||
| Air::UnWrapData { scope, .. }
|
||||
| Air::WrapData { scope, .. }
|
||||
| Air::AssertConstr { scope, .. }
|
||||
| Air::AssertBool { scope, .. }
|
||||
| Air::When { scope, .. }
|
||||
| Air::Clause { scope, .. }
|
||||
| Air::ListClause { scope, .. }
|
||||
| Air::WrapClause { scope }
|
||||
| Air::TupleClause { scope, .. }
|
||||
| Air::ClauseGuard { scope, .. }
|
||||
| Air::ListClauseGuard { scope, .. }
|
||||
| Air::Finally { scope }
|
||||
| Air::If { scope, .. }
|
||||
| Air::Record { scope, .. }
|
||||
| Air::RecordUpdate { scope, .. }
|
||||
| Air::RecordAccess { scope, .. }
|
||||
| Air::FieldsExpose { scope, .. }
|
||||
| Air::FieldsEmpty { scope }
|
||||
| Air::ListEmpty { scope }
|
||||
| Air::ListAccessor { scope, .. }
|
||||
| Air::ListExpose { scope, .. }
|
||||
| Air::TupleAccessor { scope, .. }
|
||||
| Air::TupleIndex { scope, .. }
|
||||
| Air::ErrorTerm { scope, .. }
|
||||
| Air::Trace { scope, .. }
|
||||
| Air::NoOp { scope, .. } => scope,
|
||||
}
|
||||
}
|
||||
pub fn tipo(&self) -> Option<Arc<Type>> {
|
||||
match self {
|
||||
Air::Int { .. } => Some(
|
||||
Type::App {
|
||||
public: true,
|
||||
module: String::new(),
|
||||
name: "Int".to_string(),
|
||||
args: vec![],
|
||||
}
|
||||
.into(),
|
||||
),
|
||||
Air::String { .. } => Some(
|
||||
Type::App {
|
||||
public: true,
|
||||
module: String::new(),
|
||||
name: "String".to_string(),
|
||||
args: vec![],
|
||||
}
|
||||
.into(),
|
||||
),
|
||||
Air::ByteArray { .. } => Some(
|
||||
Type::App {
|
||||
public: true,
|
||||
module: String::new(),
|
||||
name: "ByteArray".to_string(),
|
||||
args: vec![],
|
||||
}
|
||||
.into(),
|
||||
),
|
||||
Air::Bool { .. } => Some(
|
||||
Type::App {
|
||||
public: true,
|
||||
module: String::new(),
|
||||
name: "Bool".to_string(),
|
||||
args: vec![],
|
||||
}
|
||||
.into(),
|
||||
),
|
||||
Air::Void { .. } => Some(
|
||||
Type::App {
|
||||
public: true,
|
||||
module: String::new(),
|
||||
name: "Void".to_string(),
|
||||
args: vec![],
|
||||
}
|
||||
.into(),
|
||||
),
|
||||
Air::WrapData { .. } => Some(
|
||||
Type::App {
|
||||
public: true,
|
||||
module: String::new(),
|
||||
name: "Data".to_string(),
|
||||
args: vec![],
|
||||
}
|
||||
.into(),
|
||||
),
|
||||
Air::Var { constructor, .. } => Some(constructor.tipo.clone()),
|
||||
Air::List { tipo, .. }
|
||||
| Air::Tuple { tipo, .. }
|
||||
| Air::Call { tipo, .. }
|
||||
| Air::Builtin { tipo, .. }
|
||||
| Air::BinOp { tipo, .. }
|
||||
| Air::UnWrapData { tipo, .. }
|
||||
| Air::When { tipo, .. }
|
||||
| Air::Clause { tipo, .. }
|
||||
| Air::ListClause { tipo, .. }
|
||||
| Air::TupleClause { tipo, .. }
|
||||
| Air::ClauseGuard { tipo, .. }
|
||||
| Air::If { tipo, .. }
|
||||
| Air::ListClauseGuard { tipo, .. }
|
||||
| Air::Record { tipo, .. }
|
||||
| Air::RecordUpdate { tipo, .. }
|
||||
| Air::RecordAccess { tipo, .. }
|
||||
| Air::ListAccessor { tipo, .. }
|
||||
| Air::ListExpose { tipo, .. }
|
||||
| Air::TupleAccessor { tipo, .. }
|
||||
| Air::TupleIndex { tipo, .. }
|
||||
| Air::ErrorTerm { tipo, .. }
|
||||
| Air::Trace { tipo, .. } => Some(tipo.clone()),
|
||||
Air::DefineFunc { .. }
|
||||
| Air::Fn { .. }
|
||||
| Air::Let { .. }
|
||||
| Air::WrapClause { .. }
|
||||
| Air::AssertConstr { .. }
|
||||
| Air::AssertBool { .. }
|
||||
| Air::Finally { .. }
|
||||
| Air::FieldsExpose { .. }
|
||||
| Air::FieldsEmpty { .. }
|
||||
| Air::ListEmpty { .. }
|
||||
| Air::NoOp { .. } => None,
|
||||
Air::UnOp { op, .. } => match op {
|
||||
UnOp::Not => Some(
|
||||
Type::App {
|
||||
public: true,
|
||||
module: String::new(),
|
||||
name: "Bool".to_string(),
|
||||
args: vec![],
|
||||
}
|
||||
.into(),
|
||||
),
|
||||
UnOp::Negate => Some(
|
||||
Type::App {
|
||||
public: true,
|
||||
module: String::new(),
|
||||
name: "Int".to_string(),
|
||||
args: vec![],
|
||||
}
|
||||
.into(),
|
||||
),
|
||||
},
|
||||
}
|
||||
}
|
||||
NoOp,
|
||||
FieldsEmpty,
|
||||
ListEmpty,
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,57 @@
|
|||
use std::collections::HashMap;
|
||||
|
||||
use vec1::{vec1, Vec1};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct AirInterner {
|
||||
identifiers: HashMap<String, Vec1<usize>>,
|
||||
current: usize,
|
||||
}
|
||||
|
||||
impl Default for AirInterner {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
/// Interner that uses previous uniques to prevent future unique collisions
|
||||
/// when performing optimizations
|
||||
impl AirInterner {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
identifiers: HashMap::new(),
|
||||
current: 0,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn intern(&mut self, text: String) {
|
||||
if let Some(u) = self.identifiers.get_mut(&text) {
|
||||
u.push(self.current);
|
||||
|
||||
self.current += 1;
|
||||
} else {
|
||||
self.identifiers.insert(text, vec1!(self.current));
|
||||
|
||||
self.current += 1;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn pop_text(&mut self, text: String) {
|
||||
if let Some(mut u) = self.identifiers.remove(&text) {
|
||||
if u.len() != 1 {
|
||||
u.pop().unwrap();
|
||||
self.identifiers.insert(text, u);
|
||||
}
|
||||
} else {
|
||||
unreachable!("Looking up a missing text: {}", text);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn lookup_interned(&self, text: &String) -> String {
|
||||
if let Some(u) = self.identifiers.get(text) {
|
||||
format!("{}_id_{}", text, *u.last())
|
||||
} else {
|
||||
unreachable!("Looking up a missing text: {}", text);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,147 +0,0 @@
|
|||
#[derive(Debug, Clone, Default, Eq, PartialEq)]
|
||||
pub struct Scope(pub(self) Vec<u64>);
|
||||
|
||||
impl From<Vec<u64>> for Scope {
|
||||
fn from(value: Vec<u64>) -> Self {
|
||||
Self(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl Scope {
|
||||
pub fn push(&mut self, value: u64) {
|
||||
self.0.push(value);
|
||||
}
|
||||
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.0.is_empty()
|
||||
}
|
||||
|
||||
/// Find the common ancestor with the replacement,
|
||||
/// remove it from `self`, and then prepend the
|
||||
/// `replacement` to `self`.
|
||||
pub fn replace(&mut self, mut replacement: Scope) {
|
||||
let common = self.common_ancestor(&replacement);
|
||||
|
||||
// we know that common will always be in the front of the
|
||||
// scope Vec so we can always drain `0..common.len()`.
|
||||
self.0.drain(0..common.0.len());
|
||||
|
||||
replacement.0.extend(self.0.iter());
|
||||
self.0 = replacement.0;
|
||||
}
|
||||
|
||||
pub fn common_ancestor(&self, other: &Self) -> Scope {
|
||||
let longest_length = self.0.len().max(other.0.len());
|
||||
|
||||
if *self.0 == *other.0 {
|
||||
return self.clone();
|
||||
}
|
||||
|
||||
for index in 0..longest_length {
|
||||
if self.0.get(index).is_none() {
|
||||
return self.clone();
|
||||
} else if other.0.get(index).is_none() {
|
||||
return other.clone();
|
||||
} else if self.0[index] != other.0[index] {
|
||||
return Scope(self.0[0..index].to_vec());
|
||||
}
|
||||
}
|
||||
|
||||
Scope::default()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use pretty_assertions::assert_eq;
|
||||
|
||||
use super::Scope;
|
||||
|
||||
#[test]
|
||||
fn common_ancestor_equal_vecs() {
|
||||
let ancestor = Scope(vec![1, 2, 3, 4, 5, 6]);
|
||||
|
||||
let descendant = Scope(vec![1, 2, 3, 4, 5, 6]);
|
||||
|
||||
let result = ancestor.common_ancestor(&descendant);
|
||||
|
||||
assert_eq!(result, Scope(vec![1, 2, 3, 4, 5, 6]))
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn common_ancestor_equal_ancestor() {
|
||||
let ancestor = Scope(vec![1, 2, 3, 4]);
|
||||
|
||||
let descendant = Scope(vec![1, 2, 3, 4, 5, 6]);
|
||||
|
||||
let result = ancestor.common_ancestor(&descendant);
|
||||
|
||||
assert_eq!(result, Scope(vec![1, 2, 3, 4]));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn common_ancestor_not_subset() {
|
||||
let ancestor = Scope(vec![1, 2, 3, 4, 5]);
|
||||
|
||||
let descendant = Scope(vec![1, 2, 3, 7, 8]);
|
||||
|
||||
let result = ancestor.common_ancestor(&descendant);
|
||||
|
||||
assert_eq!(result, Scope(vec![1, 2, 3]));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn common_ancestor_not_found() {
|
||||
let ancestor = Scope(vec![1, 2, 3, 4, 5, 6]);
|
||||
|
||||
let descendant = Scope(vec![4, 5, 6]);
|
||||
|
||||
let result = ancestor.common_ancestor(&descendant);
|
||||
|
||||
assert_eq!(result, Scope::default());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn common_ancestor_no_shared_values() {
|
||||
let ancestor = Scope(vec![1, 2, 3]);
|
||||
|
||||
let descendant = Scope(vec![4, 5, 6]);
|
||||
|
||||
let result = ancestor.common_ancestor(&descendant);
|
||||
|
||||
assert_eq!(result, Scope::default());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn replace_same_value() {
|
||||
let mut value = Scope(vec![1, 2, 3, 4, 5, 6]);
|
||||
|
||||
let replacement = Scope(vec![1, 2, 3, 4, 5, 6]);
|
||||
|
||||
value.replace(replacement);
|
||||
|
||||
assert_eq!(value, Scope(vec![1, 2, 3, 4, 5, 6]));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn replace_with_pattern() {
|
||||
let mut value = Scope(vec![1, 2, 3, 4, 5]);
|
||||
|
||||
let replacement = Scope(vec![1, 2, 8, 9]);
|
||||
|
||||
value.replace(replacement);
|
||||
|
||||
assert_eq!(value, Scope(vec![1, 2, 8, 9, 3, 4, 5]));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn replace_with_no_pattern() {
|
||||
let mut value = Scope(vec![1, 2, 3, 4, 5]);
|
||||
|
||||
let replacement = Scope(vec![8, 9]);
|
||||
|
||||
value.replace(replacement);
|
||||
|
||||
assert_eq!(value, Scope(vec![8, 9, 1, 2, 3, 4, 5]));
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,316 @@
|
|||
use std::{fmt::Display, rc::Rc};
|
||||
|
||||
use itertools::Itertools;
|
||||
use uplc::{builder::CONSTR_FIELDS_EXPOSER, builtins::DefaultFunction};
|
||||
|
||||
use crate::expr::Type;
|
||||
|
||||
use super::{
|
||||
builder::CodeGenSpecialFuncs,
|
||||
decision_tree::{get_tipo_by_path, CaseTest, Path},
|
||||
tree::AirTree,
|
||||
};
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum Builtin {
|
||||
HeadList(Rc<Type>),
|
||||
ExtractField(Rc<Type>),
|
||||
TailList,
|
||||
UnConstrFields,
|
||||
FstPair(Rc<Type>),
|
||||
SndPair(Rc<Type>),
|
||||
}
|
||||
|
||||
impl PartialEq for Builtin {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
matches!(
|
||||
(self, other),
|
||||
(Builtin::HeadList(_), Builtin::HeadList(_))
|
||||
| (Builtin::ExtractField(_), Builtin::ExtractField(_))
|
||||
| (Builtin::TailList, Builtin::TailList)
|
||||
| (Builtin::UnConstrFields, Builtin::UnConstrFields)
|
||||
| (Builtin::FstPair(_), Builtin::FstPair(_))
|
||||
| (Builtin::SndPair(_), Builtin::SndPair(_))
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for Builtin {}
|
||||
|
||||
impl Builtin {
|
||||
fn produce_air(self, special_funcs: &mut CodeGenSpecialFuncs, arg: AirTree) -> AirTree {
|
||||
match self {
|
||||
Builtin::HeadList(t) => AirTree::builtin(DefaultFunction::HeadList, t, vec![arg]),
|
||||
Builtin::ExtractField(t) => AirTree::extract_field(t, arg),
|
||||
Builtin::TailList => AirTree::builtin(
|
||||
DefaultFunction::TailList,
|
||||
Type::list(Type::data()),
|
||||
vec![arg],
|
||||
),
|
||||
Builtin::UnConstrFields => AirTree::call(
|
||||
special_funcs.use_function_tree(CONSTR_FIELDS_EXPOSER.to_string()),
|
||||
Type::list(Type::data()),
|
||||
vec![arg],
|
||||
),
|
||||
|
||||
Builtin::FstPair(t) => AirTree::builtin(DefaultFunction::FstPair, t, vec![arg]),
|
||||
Builtin::SndPair(t) => AirTree::builtin(DefaultFunction::SndPair, t, vec![arg]),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn tipo(&self) -> Rc<Type> {
|
||||
match self {
|
||||
Builtin::HeadList(t) => t.clone(),
|
||||
Builtin::ExtractField(t) => t.clone(),
|
||||
Builtin::TailList => Type::list(Type::data()),
|
||||
Builtin::UnConstrFields => Type::list(Type::data()),
|
||||
Builtin::FstPair(t) => t.clone(),
|
||||
Builtin::SndPair(t) => t.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for Builtin {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Builtin::HeadList(_) => write!(f, "head"),
|
||||
Builtin::ExtractField(_) => write!(f, "extractfield"),
|
||||
Builtin::TailList => write!(f, "tail"),
|
||||
Builtin::UnConstrFields => write!(f, "unconstrfields"),
|
||||
Builtin::FstPair(_) => write!(f, "fst"),
|
||||
Builtin::SndPair(_) => write!(f, "snd"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Eq, Clone, Debug)]
|
||||
pub struct Builtins {
|
||||
pub vec: Vec<Builtin>,
|
||||
}
|
||||
|
||||
impl Default for Builtins {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
impl Builtins {
|
||||
pub fn new() -> Self {
|
||||
Builtins { vec: vec![] }
|
||||
}
|
||||
|
||||
pub fn new_from_list_case(case: CaseTest) -> Self {
|
||||
Self {
|
||||
vec: match case {
|
||||
CaseTest::List(i) | CaseTest::ListWithTail(i) => {
|
||||
(0..i).fold(vec![], |mut acc, _index| {
|
||||
acc.push(Builtin::TailList);
|
||||
acc
|
||||
})
|
||||
}
|
||||
_ => unreachable!(),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_from_path(subject_tipo: Rc<Type>, path: Vec<Path>) -> Self {
|
||||
Self {
|
||||
vec: path
|
||||
.into_iter()
|
||||
.fold((vec![], vec![]), |(mut builtins, mut rebuilt_path), i| {
|
||||
rebuilt_path.push(i.clone());
|
||||
let is_list = matches!(i, Path::List(_));
|
||||
|
||||
match i {
|
||||
Path::Pair(i) => {
|
||||
if i == 0 {
|
||||
builtins.push(Builtin::FstPair(get_tipo_by_path(
|
||||
subject_tipo.clone(),
|
||||
&rebuilt_path,
|
||||
)));
|
||||
} else if i == 1 {
|
||||
builtins.push(Builtin::SndPair(get_tipo_by_path(
|
||||
subject_tipo.clone(),
|
||||
&rebuilt_path,
|
||||
)));
|
||||
} else {
|
||||
unreachable!()
|
||||
}
|
||||
|
||||
(builtins, rebuilt_path)
|
||||
}
|
||||
Path::List(i) | Path::Tuple(i) => {
|
||||
for _ in 0..i {
|
||||
builtins.push(Builtin::TailList);
|
||||
}
|
||||
|
||||
if is_list {
|
||||
builtins.push(Builtin::HeadList(get_tipo_by_path(
|
||||
subject_tipo.clone(),
|
||||
&rebuilt_path,
|
||||
)));
|
||||
} else {
|
||||
builtins.push(Builtin::ExtractField(get_tipo_by_path(
|
||||
subject_tipo.clone(),
|
||||
&rebuilt_path,
|
||||
)));
|
||||
}
|
||||
|
||||
(builtins, rebuilt_path)
|
||||
}
|
||||
Path::Constr(_rc, i) => {
|
||||
builtins.push(Builtin::UnConstrFields);
|
||||
|
||||
for _ in 0..i {
|
||||
builtins.push(Builtin::TailList);
|
||||
}
|
||||
|
||||
builtins.push(Builtin::ExtractField(get_tipo_by_path(
|
||||
subject_tipo.clone(),
|
||||
&rebuilt_path,
|
||||
)));
|
||||
|
||||
(builtins, rebuilt_path)
|
||||
}
|
||||
|
||||
Path::ListTail(i) => {
|
||||
for _ in 0..i {
|
||||
builtins.push(Builtin::TailList);
|
||||
}
|
||||
|
||||
(builtins, rebuilt_path)
|
||||
}
|
||||
Path::OpaqueConstr(_) => (builtins, rebuilt_path),
|
||||
}
|
||||
})
|
||||
.0,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn pop(&mut self) {
|
||||
self.vec.pop();
|
||||
}
|
||||
|
||||
pub fn len(&self) -> usize {
|
||||
self.vec.len()
|
||||
}
|
||||
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.vec.is_empty()
|
||||
}
|
||||
|
||||
pub fn merge(mut self, other: Self) -> Self {
|
||||
self.vec.extend(other.vec);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn produce_air(
|
||||
self,
|
||||
special_funcs: &mut CodeGenSpecialFuncs,
|
||||
prev_name: String,
|
||||
subject_tipo: Rc<Type>,
|
||||
then: AirTree,
|
||||
) -> AirTree {
|
||||
let (_, _, name_builtins) = self.vec.into_iter().fold(
|
||||
(prev_name, subject_tipo, vec![]),
|
||||
|(prev_name, prev_tipo, mut acc), item| {
|
||||
let next_name = format!("{}_{}", prev_name, item);
|
||||
let next_tipo = item.tipo();
|
||||
|
||||
acc.push((prev_name, prev_tipo, next_name.clone(), item));
|
||||
|
||||
(next_name, next_tipo, acc)
|
||||
},
|
||||
);
|
||||
|
||||
name_builtins
|
||||
.into_iter()
|
||||
.rfold(then, |then, (prev_name, prev_tipo, next_name, builtin)| {
|
||||
AirTree::let_assignment(
|
||||
next_name,
|
||||
builtin.produce_air(special_funcs, AirTree::local_var(prev_name, prev_tipo)),
|
||||
then,
|
||||
)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for Builtins {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{}", self.vec.iter().map(|i| i.to_string()).join("_"))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct TreeSet {
|
||||
children: Vec<TreeNode>,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct TreeNode {
|
||||
node: Builtin,
|
||||
children: Vec<TreeNode>,
|
||||
}
|
||||
|
||||
impl TreeNode {
|
||||
fn diff_union_builtins(&mut self, builtins: Builtins) -> Builtins {
|
||||
if let Some((first, rest)) = builtins.vec.split_first() {
|
||||
if let Some(item) = self.children.iter_mut().find(|item| first == &item.node) {
|
||||
item.diff_union_builtins(Builtins { vec: rest.to_vec() })
|
||||
} else {
|
||||
self.children
|
||||
.extend(TreeSet::new_from_builtins(builtins.clone()).children);
|
||||
|
||||
builtins
|
||||
}
|
||||
} else {
|
||||
builtins
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for TreeSet {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
impl TreeSet {
|
||||
pub fn new() -> Self {
|
||||
TreeSet { children: vec![] }
|
||||
}
|
||||
|
||||
pub fn new_from_builtins(builtins: Builtins) -> Self {
|
||||
TreeSet {
|
||||
children: builtins
|
||||
.vec
|
||||
.into_iter()
|
||||
.map(|item| TreeNode {
|
||||
node: item,
|
||||
children: vec![],
|
||||
})
|
||||
.rev()
|
||||
.reduce(|prev, mut current| {
|
||||
current.children.push(prev);
|
||||
current
|
||||
})
|
||||
.into_iter()
|
||||
.collect_vec(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn diff_union_builtins(&mut self, builtins: Builtins) -> Builtins {
|
||||
if let Some((first, rest)) = builtins.vec.split_first() {
|
||||
if let Some(item) = self.children.iter_mut().find(|item| first == &item.node) {
|
||||
item.diff_union_builtins(Builtins { vec: rest.to_vec() })
|
||||
} else {
|
||||
self.children
|
||||
.extend(TreeSet::new_from_builtins(builtins.clone()).children);
|
||||
|
||||
builtins
|
||||
}
|
||||
} else {
|
||||
builtins
|
||||
}
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -5,13 +5,19 @@ use std::sync::{
|
|||
|
||||
pub mod ast;
|
||||
pub mod builtins;
|
||||
pub mod error;
|
||||
pub mod expr;
|
||||
pub mod format;
|
||||
pub mod gen_uplc;
|
||||
pub mod levenshtein;
|
||||
pub mod line_numbers;
|
||||
pub mod parser;
|
||||
pub mod plutus_version;
|
||||
pub mod pretty;
|
||||
pub mod test_framework;
|
||||
pub mod tipo;
|
||||
pub mod utils;
|
||||
pub mod version;
|
||||
|
||||
#[derive(Debug, Default, Clone)]
|
||||
pub struct IdGenerator {
|
||||
|
@ -28,5 +34,37 @@ impl IdGenerator {
|
|||
}
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! aiken_fn {
|
||||
($module_types:expr, $id_gen:expr, $src:expr) => {{
|
||||
let (untyped_module, _) = $crate::parser::module($src, $crate::ast::ModuleKind::Lib)
|
||||
.expect("failed to parse module.");
|
||||
|
||||
let module_name = "";
|
||||
|
||||
let mut warnings = vec![];
|
||||
|
||||
let typed_module = untyped_module
|
||||
.infer(
|
||||
$id_gen,
|
||||
$crate::ast::ModuleKind::Lib,
|
||||
module_name,
|
||||
$module_types,
|
||||
$crate::ast::Tracing::silent(),
|
||||
&mut warnings,
|
||||
None,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
if let Some($crate::ast::Definition::Fn(typed_fn)) =
|
||||
typed_module.definitions.into_iter().last()
|
||||
{
|
||||
typed_fn
|
||||
} else {
|
||||
unreachable!()
|
||||
}
|
||||
}};
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
|
|
@ -0,0 +1,126 @@
|
|||
use std::fmt::{self, Display};
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Clone, serde::Serialize, serde::Deserialize)]
|
||||
pub struct LineNumbers {
|
||||
line_starts: Vec<usize>,
|
||||
length: usize,
|
||||
last: Option<usize>,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Clone, Copy)]
|
||||
pub struct LineColumn {
|
||||
pub line: usize,
|
||||
pub column: usize,
|
||||
}
|
||||
|
||||
impl Display for LineColumn {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
|
||||
f.write_str(&format!("L{};{}", self.line, self.column))
|
||||
}
|
||||
}
|
||||
|
||||
impl LineNumbers {
|
||||
pub fn new(src: &str) -> Self {
|
||||
let line_starts: Vec<usize> = std::iter::once(0)
|
||||
.chain(src.match_indices('\n').map(|(i, _)| i + 1))
|
||||
.collect();
|
||||
|
||||
let length = src.len();
|
||||
|
||||
Self {
|
||||
length,
|
||||
last: line_starts.last().cloned(),
|
||||
line_starts: if length > 0 { line_starts } else { Vec::new() },
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the line number for a byte index
|
||||
pub fn line_number(&self, byte_index: usize) -> Option<usize> {
|
||||
self.line_starts
|
||||
.binary_search(&byte_index)
|
||||
.map(|l| Some(l + 1))
|
||||
.unwrap_or_else(|next_index| {
|
||||
if Some(next_index) >= self.last {
|
||||
None
|
||||
} else {
|
||||
Some(next_index)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub fn line_and_column_number(&self, byte_index: usize) -> Option<LineColumn> {
|
||||
let line = self.line_number(byte_index)?;
|
||||
let column = byte_index - self.line_starts.get(line - 1).copied().unwrap_or_default() + 1;
|
||||
Some(LineColumn { line, column })
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn byte_index(&self, line: usize, character: usize) -> usize {
|
||||
match self.line_starts.get(line) {
|
||||
Some(line_index) => *line_index + character,
|
||||
None => self.length,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use chumsky::text::Character;
|
||||
use indoc::indoc;
|
||||
|
||||
fn assert_line_column(src: &str, ix: usize, lcol: Option<LineColumn>) {
|
||||
let lines = LineNumbers::new(src);
|
||||
|
||||
println!("{lines:?}");
|
||||
|
||||
let byte = src
|
||||
.as_bytes()
|
||||
.get(ix)
|
||||
.map(|b| {
|
||||
if b.is_ascii() {
|
||||
format!("{}", b.to_char())
|
||||
} else {
|
||||
format!("{b}")
|
||||
}
|
||||
})
|
||||
.unwrap_or_else(|| "OUT-OF-BOUNDS".to_string());
|
||||
|
||||
assert_eq!(
|
||||
lines.line_and_column_number(ix),
|
||||
lcol,
|
||||
"\n{src}\n--> at index {ix} ({byte})\n",
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn out_of_range_byte_index() {
|
||||
let src = indoc! { r#""# };
|
||||
assert_line_column(src, 42, None);
|
||||
assert_line_column(src, 0, None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn basic() {
|
||||
let src = indoc! { r#"
|
||||
foo
|
||||
bar
|
||||
"# };
|
||||
|
||||
assert_line_column(src, 0, Some(LineColumn { line: 1, column: 1 }));
|
||||
assert_line_column(src, 2, Some(LineColumn { line: 1, column: 3 }));
|
||||
assert_line_column(src, 4, Some(LineColumn { line: 2, column: 1 }));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unicode() {
|
||||
let src = indoc! { r#"
|
||||
💩
|
||||
foo
|
||||
"# };
|
||||
|
||||
assert_line_column(src, 0, Some(LineColumn { line: 1, column: 1 }));
|
||||
assert_line_column(src, 2, Some(LineColumn { line: 1, column: 3 }));
|
||||
assert_line_column(src, 5, Some(LineColumn { line: 2, column: 1 }));
|
||||
}
|
||||
}
|
|
@ -10,15 +10,15 @@ pub mod pattern;
|
|||
pub mod token;
|
||||
mod utils;
|
||||
|
||||
use crate::{ast, line_numbers::LineNumbers};
|
||||
pub use annotation::parser as annotation;
|
||||
pub use definition::parser as definition;
|
||||
pub use expr::parser as expression;
|
||||
pub use pattern::parser as pattern;
|
||||
|
||||
use crate::ast;
|
||||
use chumsky::prelude::*;
|
||||
pub use definition::{import::parser as import, parser as definition};
|
||||
use error::ParseError;
|
||||
pub use expr::parser as expression;
|
||||
use extra::ModuleExtra;
|
||||
use indexmap::IndexMap;
|
||||
pub use pattern::parser as pattern;
|
||||
|
||||
pub fn module(
|
||||
src: &str,
|
||||
|
@ -28,10 +28,54 @@ pub fn module(
|
|||
|
||||
let stream = chumsky::Stream::from_iter(ast::Span::create(tokens.len(), 1), tokens.into_iter());
|
||||
|
||||
let definitions = definition().repeated().then_ignore(end()).parse(stream)?;
|
||||
let definitions = import()
|
||||
.repeated()
|
||||
.map(|imports| {
|
||||
let mut store = IndexMap::new();
|
||||
|
||||
for import in imports.into_iter() {
|
||||
let key = (import.module, import.as_name);
|
||||
match store.remove(&key) {
|
||||
None => {
|
||||
store.insert(key, (import.location, import.unqualified));
|
||||
}
|
||||
Some((location, unqualified)) => {
|
||||
let mut merged_unqualified = Vec::new();
|
||||
merged_unqualified.extend(unqualified);
|
||||
merged_unqualified.extend(import.unqualified);
|
||||
store.insert(key, (location, merged_unqualified));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
store
|
||||
.into_iter()
|
||||
.map(|((module, as_name), (location, unqualified))| {
|
||||
ast::Definition::Use(ast::Use {
|
||||
module,
|
||||
as_name,
|
||||
location,
|
||||
unqualified,
|
||||
package: (),
|
||||
})
|
||||
})
|
||||
.collect::<Vec<ast::UntypedDefinition>>()
|
||||
})
|
||||
.then(definition().repeated())
|
||||
.map(|(imports, others)| {
|
||||
let mut defs = Vec::new();
|
||||
defs.extend(imports);
|
||||
defs.extend(others);
|
||||
defs
|
||||
})
|
||||
.then_ignore(end())
|
||||
.parse(stream)?;
|
||||
|
||||
let lines = LineNumbers::new(src);
|
||||
|
||||
let module = ast::UntypedModule {
|
||||
kind,
|
||||
lines,
|
||||
definitions,
|
||||
docs: vec![],
|
||||
name: "".to_string(),
|
||||
|
@ -45,6 +89,16 @@ pub fn module(
|
|||
mod tests {
|
||||
use crate::assert_module;
|
||||
|
||||
#[test]
|
||||
fn merge_imports() {
|
||||
assert_module!(
|
||||
r#"
|
||||
use aiken/list.{bar, foo}
|
||||
use aiken/list.{baz}
|
||||
"#
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn windows_newline() {
|
||||
assert_module!("use aiken/list\r\n");
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
use chumsky::prelude::*;
|
||||
|
||||
use crate::ast;
|
||||
|
||||
use super::{error::ParseError, token::Token};
|
||||
use crate::{
|
||||
ast::{self, well_known},
|
||||
builtins::PRELUDE,
|
||||
};
|
||||
use chumsky::prelude::*;
|
||||
|
||||
pub fn parser() -> impl Parser<Token, ast::Annotation, Error = ParseError> {
|
||||
recursive(|expression| {
|
||||
|
@ -14,6 +15,31 @@ pub fn parser() -> impl Parser<Token, ast::Annotation, Error = ParseError> {
|
|||
name,
|
||||
}
|
||||
}),
|
||||
// Pair
|
||||
select! {Token::Name { name } if name == PRELUDE => name}
|
||||
.then_ignore(just(Token::Dot))
|
||||
.or_not()
|
||||
.then_ignore(select! {Token::UpName { name } if name == well_known::PAIR => name})
|
||||
.ignore_then(
|
||||
expression
|
||||
.clone()
|
||||
.separated_by(just(Token::Comma))
|
||||
.exactly(2)
|
||||
.delimited_by(just(Token::Less), just(Token::Greater)),
|
||||
)
|
||||
.map_with_span(|elems: Vec<ast::Annotation>, span| ast::Annotation::Pair {
|
||||
location: span,
|
||||
fst: elems
|
||||
.first()
|
||||
.expect("Pair should have exactly 2 elements")
|
||||
.to_owned()
|
||||
.into(),
|
||||
snd: elems
|
||||
.last()
|
||||
.expect("Pair should have exactly 2 elements")
|
||||
.to_owned()
|
||||
.into(),
|
||||
}),
|
||||
// Tuple
|
||||
expression
|
||||
.clone()
|
||||
|
|
|
@ -1,16 +1,16 @@
|
|||
use chumsky::prelude::*;
|
||||
|
||||
use super::Chain;
|
||||
use crate::{
|
||||
expr::UntypedExpr,
|
||||
parser::{token::Token, ParseError},
|
||||
};
|
||||
use chumsky::prelude::*;
|
||||
|
||||
pub(crate) fn parser() -> impl Parser<Token, Chain, Error = ParseError> {
|
||||
just(Token::Dot)
|
||||
.ignore_then(select! {
|
||||
Token::Name { name } => name,
|
||||
})
|
||||
.ignore_then(choice((
|
||||
select! { Token::Else => "else".to_string() },
|
||||
select! { Token::Name { name } => name, },
|
||||
)))
|
||||
.map_with_span(Chain::FieldAccess)
|
||||
}
|
||||
|
||||
|
@ -28,3 +28,18 @@ pub(crate) fn constructor() -> impl Parser<Token, UntypedExpr, Error = ParseErro
|
|||
}),
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::assert_expr;
|
||||
|
||||
#[test]
|
||||
fn field_access_else_1() {
|
||||
assert_expr!("foo.else");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn field_access_else_2() {
|
||||
assert_expr!("foo.bar.else");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
---
|
||||
source: crates/aiken-lang/src/parser/chain/field_access.rs
|
||||
description: "Code:\n\nfoo.else"
|
||||
---
|
||||
FieldAccess {
|
||||
location: 0..8,
|
||||
label: "else",
|
||||
container: Var {
|
||||
location: 0..3,
|
||||
name: "foo",
|
||||
},
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
---
|
||||
source: crates/aiken-lang/src/parser/chain/field_access.rs
|
||||
description: "Code:\n\nfoo.bar.else"
|
||||
---
|
||||
FieldAccess {
|
||||
location: 0..12,
|
||||
label: "else",
|
||||
container: FieldAccess {
|
||||
location: 0..7,
|
||||
label: "bar",
|
||||
container: Var {
|
||||
location: 0..3,
|
||||
name: "foo",
|
||||
},
|
||||
},
|
||||
}
|
|
@ -1,9 +1,8 @@
|
|||
use chumsky::prelude::*;
|
||||
|
||||
use crate::{
|
||||
ast,
|
||||
parser::{annotation, error::ParseError, literal, token::Token, utils},
|
||||
parser::{annotation, error::ParseError, expr::pure_expression, token::Token, utils},
|
||||
};
|
||||
use chumsky::prelude::*;
|
||||
|
||||
pub fn parser() -> impl Parser<Token, ast::UntypedDefinition, Error = ParseError> {
|
||||
utils::optional_flag(Token::Pub)
|
||||
|
@ -15,7 +14,11 @@ pub fn parser() -> impl Parser<Token, ast::UntypedDefinition, Error = ParseError
|
|||
.or_not(),
|
||||
)
|
||||
.then_ignore(just(Token::Equal))
|
||||
.then(value())
|
||||
.then(recursive(|sequence| {
|
||||
recursive(|expression| pure_expression(sequence.clone(), expression))
|
||||
.then(sequence.repeated())
|
||||
.foldl(|current, next| current.append_in_sequence(next))
|
||||
}))
|
||||
.map_with_span(|(((public, name), annotation), value), span| {
|
||||
ast::UntypedDefinition::ModuleConstant(ast::ModuleConstant {
|
||||
doc: None,
|
||||
|
@ -23,40 +26,32 @@ pub fn parser() -> impl Parser<Token, ast::UntypedDefinition, Error = ParseError
|
|||
public,
|
||||
name,
|
||||
annotation,
|
||||
value: Box::new(value),
|
||||
tipo: (),
|
||||
value,
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
pub fn value() -> impl Parser<Token, ast::Constant, Error = ParseError> {
|
||||
let constant_string_parser =
|
||||
select! {Token::String {value} => value}.map_with_span(|value, span| {
|
||||
ast::Constant::String {
|
||||
location: span,
|
||||
value,
|
||||
}
|
||||
});
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::assert_definition;
|
||||
|
||||
let constant_int_parser =
|
||||
literal::int().map_with_span(|(value, base), location| ast::Constant::Int {
|
||||
location,
|
||||
value,
|
||||
base,
|
||||
});
|
||||
|
||||
let constant_bytearray_parser =
|
||||
literal::bytearray(
|
||||
|bytes, preferred_format, location| ast::Constant::ByteArray {
|
||||
location,
|
||||
bytes,
|
||||
preferred_format,
|
||||
},
|
||||
#[test]
|
||||
fn g1_element_constant() {
|
||||
assert_definition!(
|
||||
r#"
|
||||
pub const point =
|
||||
#<Bls12_381, G1>"950dfd33da2682260c76038dfb8bad6e84ae9d599a3c151815945ac1e6ef6b1027cd917f3907479d20d636ce437a41f5"
|
||||
"#
|
||||
);
|
||||
}
|
||||
|
||||
choice((
|
||||
constant_string_parser,
|
||||
constant_int_parser,
|
||||
constant_bytearray_parser,
|
||||
))
|
||||
#[test]
|
||||
fn g2_element_constant() {
|
||||
assert_definition!(
|
||||
r#"
|
||||
pub const point =
|
||||
#<Bls12_381, G2>"b0629fa1158c2d23a10413fe91d381a84d25e31d041cd0377d25828498fd02011b35893938ced97535395e4815201e67108bcd4665e0db25d602d76fa791fab706c54abf5e1a9e44b4ac1e6badf3d2ac0328f5e30be341677c8bac5dda7682f1"
|
||||
"#
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,9 +1,8 @@
|
|||
use chumsky::prelude::*;
|
||||
|
||||
use crate::{
|
||||
ast,
|
||||
parser::{annotation, error::ParseError, token::Token, utils},
|
||||
};
|
||||
use chumsky::prelude::*;
|
||||
|
||||
pub fn parser() -> impl Parser<Token, ast::UntypedDefinition, Error = ParseError> {
|
||||
let unlabeled_constructor_type_args = annotation()
|
||||
|
@ -54,16 +53,26 @@ pub fn parser() -> impl Parser<Token, ast::UntypedDefinition, Error = ParseError
|
|||
|(((public, opaque), (name, parameters)), constructors), span| {
|
||||
ast::UntypedDefinition::DataType(ast::DataType {
|
||||
location: span,
|
||||
constructors: constructors
|
||||
.into_iter()
|
||||
.map(|mut constructor| {
|
||||
if constructor.sugar {
|
||||
constructor.name = name.clone();
|
||||
}
|
||||
constructors: if constructors.is_empty() {
|
||||
vec![ast::RecordConstructor {
|
||||
location: span,
|
||||
arguments: vec![],
|
||||
doc: None,
|
||||
name: name.clone(),
|
||||
sugar: true,
|
||||
}]
|
||||
} else {
|
||||
constructors
|
||||
.into_iter()
|
||||
.map(|mut constructor| {
|
||||
if constructor.sugar {
|
||||
constructor.name.clone_from(&name);
|
||||
}
|
||||
|
||||
constructor
|
||||
})
|
||||
.collect(),
|
||||
constructor
|
||||
})
|
||||
.collect()
|
||||
},
|
||||
doc: None,
|
||||
name,
|
||||
opaque,
|
||||
|
@ -119,4 +128,25 @@ mod tests {
|
|||
"#
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn record_sugar() {
|
||||
assert_definition!(
|
||||
r#"
|
||||
pub type Foo {
|
||||
wow: Int,
|
||||
}
|
||||
"#
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn empty_record_sugar() {
|
||||
assert_definition!(
|
||||
r#"
|
||||
pub type Foo {
|
||||
}
|
||||
"#
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,10 +1,9 @@
|
|||
use chumsky::prelude::*;
|
||||
|
||||
use crate::{
|
||||
ast,
|
||||
expr::UntypedExpr,
|
||||
parser::{annotation, error::ParseError, expr, token::Token, utils},
|
||||
parser::{annotation, error::ParseError, expr, pattern, token::Token, utils},
|
||||
};
|
||||
use chumsky::prelude::*;
|
||||
|
||||
pub fn parser() -> impl Parser<Token, ast::UntypedDefinition, Error = ParseError> {
|
||||
utils::optional_flag(Token::Pub)
|
||||
|
@ -41,7 +40,7 @@ pub fn parser() -> impl Parser<Token, ast::UntypedDefinition, Error = ParseError
|
|||
public,
|
||||
return_annotation,
|
||||
return_type: (),
|
||||
can_error: true,
|
||||
on_test_failure: ast::OnTestFailure::FailImmediately,
|
||||
})
|
||||
},
|
||||
)
|
||||
|
@ -51,39 +50,45 @@ pub fn param(is_validator_param: bool) -> impl Parser<Token, ast::UntypedArg, Er
|
|||
choice((
|
||||
select! {Token::Name {name} => name}
|
||||
.then(select! {Token::DiscardName {name} => name})
|
||||
.map_with_span(|(label, name), span| ast::ArgName::Discarded {
|
||||
label,
|
||||
name,
|
||||
location: span,
|
||||
.map_with_span(|(label, name), span| {
|
||||
ast::ArgBy::ByName(ast::ArgName::Discarded {
|
||||
label,
|
||||
name,
|
||||
location: span,
|
||||
})
|
||||
}),
|
||||
select! {Token::DiscardName {name} => name}.map_with_span(|name, span| {
|
||||
ast::ArgName::Discarded {
|
||||
ast::ArgBy::ByName(ast::ArgName::Discarded {
|
||||
label: name.clone(),
|
||||
name,
|
||||
location: span,
|
||||
}
|
||||
})
|
||||
}),
|
||||
select! {Token::Name {name} => name}
|
||||
.then(select! {Token::Name {name} => name})
|
||||
.map_with_span(move |(label, name), span| ast::ArgName::Named {
|
||||
label,
|
||||
.map_with_span(|(label, name), span| {
|
||||
ast::ArgBy::ByName(ast::ArgName::Named {
|
||||
label,
|
||||
name,
|
||||
location: span,
|
||||
})
|
||||
}),
|
||||
select! {Token::Name {name} => name}.map_with_span(|name, span| {
|
||||
ast::ArgBy::ByName(ast::ArgName::Named {
|
||||
label: name.clone(),
|
||||
name,
|
||||
location: span,
|
||||
is_validator_param,
|
||||
}),
|
||||
select! {Token::Name {name} => name}.map_with_span(move |name, span| ast::ArgName::Named {
|
||||
label: name.clone(),
|
||||
name,
|
||||
location: span,
|
||||
is_validator_param,
|
||||
})
|
||||
}),
|
||||
pattern().map(ast::ArgBy::ByPattern),
|
||||
))
|
||||
.then(just(Token::Colon).ignore_then(annotation()).or_not())
|
||||
.map_with_span(|(arg_name, annotation), span| ast::Arg {
|
||||
.map_with_span(move |(by, annotation), span| ast::UntypedArg {
|
||||
location: span,
|
||||
annotation,
|
||||
tipo: (),
|
||||
arg_name,
|
||||
doc: None,
|
||||
is_validator_param,
|
||||
by,
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -108,4 +113,47 @@ mod tests {
|
|||
"#
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn function_assignment_only() {
|
||||
assert_definition!(
|
||||
r#"
|
||||
fn run() {
|
||||
let x = 1 + 1
|
||||
}
|
||||
"#
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn function_by_pattern_no_annotation() {
|
||||
assert_definition!(
|
||||
r#"
|
||||
fn foo(Foo { my_field }) {
|
||||
my_field * 2
|
||||
}
|
||||
"#
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn function_by_pattern_with_annotation() {
|
||||
assert_definition!(
|
||||
r#"
|
||||
fn foo(Foo { my_field }: Foo) {
|
||||
my_field * 2
|
||||
}
|
||||
"#
|
||||
);
|
||||
}
|
||||
#[test]
|
||||
fn function_by_pattern_with_alias() {
|
||||
assert_definition!(
|
||||
r#"
|
||||
fn foo(Foo { my_field, .. } as x) {
|
||||
my_field * x.my_other_field
|
||||
}
|
||||
"#
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,11 +1,10 @@
|
|||
use chumsky::prelude::*;
|
||||
|
||||
use crate::{
|
||||
ast,
|
||||
parser::{error::ParseError, token::Token},
|
||||
};
|
||||
use chumsky::prelude::*;
|
||||
|
||||
pub fn parser() -> impl Parser<Token, ast::UntypedDefinition, Error = ParseError> {
|
||||
pub fn parser() -> impl Parser<Token, ast::UntypedUse, Error = ParseError> {
|
||||
let unqualified_import = choice((
|
||||
select! {Token::Name { name } => name}.then(
|
||||
just(Token::As)
|
||||
|
@ -22,7 +21,6 @@ pub fn parser() -> impl Parser<Token, ast::UntypedDefinition, Error = ParseError
|
|||
name,
|
||||
location: span,
|
||||
as_name,
|
||||
layer: Default::default(),
|
||||
});
|
||||
|
||||
let unqualified_imports = just(Token::Dot)
|
||||
|
@ -44,30 +42,28 @@ pub fn parser() -> impl Parser<Token, ast::UntypedDefinition, Error = ParseError
|
|||
.then(as_name);
|
||||
|
||||
just(Token::Use).ignore_then(module_path).map_with_span(
|
||||
|((module, unqualified), as_name), span| {
|
||||
ast::UntypedDefinition::Use(ast::Use {
|
||||
module,
|
||||
as_name,
|
||||
unqualified: unqualified.unwrap_or_default(),
|
||||
package: (),
|
||||
location: span,
|
||||
})
|
||||
|((module, unqualified), as_name), span| ast::Use {
|
||||
module,
|
||||
as_name,
|
||||
unqualified: unqualified.unwrap_or_default(),
|
||||
package: (),
|
||||
location: span,
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::assert_definition;
|
||||
use crate::assert_import;
|
||||
|
||||
#[test]
|
||||
fn import_basic() {
|
||||
assert_definition!("use aiken/list");
|
||||
assert_import!("use aiken/list");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn import_unqualified() {
|
||||
assert_definition!(
|
||||
assert_import!(
|
||||
r#"
|
||||
use std/address.{Address as A, thing as w}
|
||||
"#
|
||||
|
@ -76,6 +72,6 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn import_alias() {
|
||||
assert_definition!("use aiken/list as foo");
|
||||
assert_import!("use aiken/list as foo");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,25 +3,22 @@ use chumsky::prelude::*;
|
|||
pub mod constant;
|
||||
mod data_type;
|
||||
mod function;
|
||||
mod import;
|
||||
pub mod import;
|
||||
mod test;
|
||||
mod type_alias;
|
||||
mod validator;
|
||||
|
||||
use super::{error::ParseError, token::Token};
|
||||
use crate::ast;
|
||||
pub use constant::parser as constant;
|
||||
pub use data_type::parser as data_type;
|
||||
pub use function::parser as function;
|
||||
pub use import::parser as import;
|
||||
pub use test::parser as test;
|
||||
pub use type_alias::parser as type_alias;
|
||||
pub use validator::parser as validator;
|
||||
|
||||
use super::{error::ParseError, token::Token};
|
||||
use crate::ast;
|
||||
|
||||
pub fn parser() -> impl Parser<Token, ast::UntypedDefinition, Error = ParseError> {
|
||||
choice((
|
||||
import(),
|
||||
data_type(),
|
||||
type_alias(),
|
||||
validator(),
|
||||
|
|
60
crates/aiken-lang/src/parser/definition/snapshots/def_invalid_property_test.snap
vendored
Normal file
60
crates/aiken-lang/src/parser/definition/snapshots/def_invalid_property_test.snap
vendored
Normal file
|
@ -0,0 +1,60 @@
|
|||
---
|
||||
source: crates/aiken-lang/src/parser/definition/test.rs
|
||||
description: "Code:\n\ntest foo(x via f, y via g) {\n True\n}\n"
|
||||
---
|
||||
Test(
|
||||
Function {
|
||||
arguments: [
|
||||
ArgVia {
|
||||
arg: UntypedArg {
|
||||
by: ByName(
|
||||
Named {
|
||||
name: "x",
|
||||
label: "x",
|
||||
location: 9..10,
|
||||
},
|
||||
),
|
||||
location: 9..10,
|
||||
annotation: None,
|
||||
doc: None,
|
||||
is_validator_param: false,
|
||||
},
|
||||
via: Var {
|
||||
location: 15..16,
|
||||
name: "f",
|
||||
},
|
||||
},
|
||||
ArgVia {
|
||||
arg: UntypedArg {
|
||||
by: ByName(
|
||||
Named {
|
||||
name: "y",
|
||||
label: "y",
|
||||
location: 18..19,
|
||||
},
|
||||
),
|
||||
location: 18..19,
|
||||
annotation: None,
|
||||
doc: None,
|
||||
is_validator_param: false,
|
||||
},
|
||||
via: Var {
|
||||
location: 24..25,
|
||||
name: "g",
|
||||
},
|
||||
},
|
||||
],
|
||||
body: Var {
|
||||
location: 33..37,
|
||||
name: "True",
|
||||
},
|
||||
doc: None,
|
||||
location: 0..26,
|
||||
name: "foo",
|
||||
public: false,
|
||||
return_annotation: None,
|
||||
return_type: (),
|
||||
end_position: 38,
|
||||
on_test_failure: FailImmediately,
|
||||
},
|
||||
)
|
|
@ -0,0 +1,45 @@
|
|||
---
|
||||
source: crates/aiken-lang/src/parser/definition/test.rs
|
||||
description: "Code:\n\ntest foo(x via fuzz.any_int) {\n True\n}\n"
|
||||
---
|
||||
Test(
|
||||
Function {
|
||||
arguments: [
|
||||
ArgVia {
|
||||
arg: UntypedArg {
|
||||
by: ByName(
|
||||
Named {
|
||||
name: "x",
|
||||
label: "x",
|
||||
location: 9..10,
|
||||
},
|
||||
),
|
||||
location: 9..10,
|
||||
annotation: None,
|
||||
doc: None,
|
||||
is_validator_param: false,
|
||||
},
|
||||
via: FieldAccess {
|
||||
location: 15..27,
|
||||
label: "any_int",
|
||||
container: Var {
|
||||
location: 15..19,
|
||||
name: "fuzz",
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
body: Var {
|
||||
location: 35..39,
|
||||
name: "True",
|
||||
},
|
||||
doc: None,
|
||||
location: 0..28,
|
||||
name: "foo",
|
||||
public: false,
|
||||
return_annotation: None,
|
||||
return_type: (),
|
||||
end_position: 40,
|
||||
on_test_failure: FailImmediately,
|
||||
},
|
||||
)
|
52
crates/aiken-lang/src/parser/definition/snapshots/def_property_test_annotated_fuzzer.snap
vendored
Normal file
52
crates/aiken-lang/src/parser/definition/snapshots/def_property_test_annotated_fuzzer.snap
vendored
Normal file
|
@ -0,0 +1,52 @@
|
|||
---
|
||||
source: crates/aiken-lang/src/parser/definition/test.rs
|
||||
description: "Code:\n\ntest foo(x: Int via foo()) {\n True\n}\n"
|
||||
---
|
||||
Test(
|
||||
Function {
|
||||
arguments: [
|
||||
ArgVia {
|
||||
arg: UntypedArg {
|
||||
by: ByName(
|
||||
Named {
|
||||
name: "x",
|
||||
label: "x",
|
||||
location: 9..10,
|
||||
},
|
||||
),
|
||||
location: 9..15,
|
||||
annotation: Some(
|
||||
Constructor {
|
||||
location: 12..15,
|
||||
module: None,
|
||||
name: "Int",
|
||||
arguments: [],
|
||||
},
|
||||
),
|
||||
doc: None,
|
||||
is_validator_param: false,
|
||||
},
|
||||
via: Call {
|
||||
arguments: [],
|
||||
fun: Var {
|
||||
location: 20..23,
|
||||
name: "foo",
|
||||
},
|
||||
location: 20..25,
|
||||
},
|
||||
},
|
||||
],
|
||||
body: Var {
|
||||
location: 33..37,
|
||||
name: "True",
|
||||
},
|
||||
doc: None,
|
||||
location: 0..26,
|
||||
name: "foo",
|
||||
public: false,
|
||||
return_annotation: None,
|
||||
return_type: (),
|
||||
end_position: 38,
|
||||
on_test_failure: FailImmediately,
|
||||
},
|
||||
)
|
|
@ -0,0 +1,21 @@
|
|||
---
|
||||
source: crates/aiken-lang/src/parser/definition/test.rs
|
||||
description: "Code:\n\ntest foo() {\n True\n}\n"
|
||||
---
|
||||
Test(
|
||||
Function {
|
||||
arguments: [],
|
||||
body: Var {
|
||||
location: 17..21,
|
||||
name: "True",
|
||||
},
|
||||
doc: None,
|
||||
location: 0..10,
|
||||
name: "foo",
|
||||
public: false,
|
||||
return_annotation: None,
|
||||
return_type: (),
|
||||
end_position: 22,
|
||||
on_test_failure: FailImmediately,
|
||||
},
|
||||
)
|
|
@ -14,18 +14,25 @@ Test(
|
|||
location: 45..50,
|
||||
name: "False",
|
||||
},
|
||||
pattern: Constructor {
|
||||
is_record: false,
|
||||
location: 38..42,
|
||||
name: "True",
|
||||
arguments: [],
|
||||
module: None,
|
||||
constructor: (),
|
||||
with_spread: false,
|
||||
tipo: (),
|
||||
patterns: [
|
||||
AssignmentPattern {
|
||||
pattern: Constructor {
|
||||
is_record: false,
|
||||
location: 38..42,
|
||||
name: "True",
|
||||
arguments: [],
|
||||
module: None,
|
||||
constructor: (),
|
||||
spread_location: None,
|
||||
tipo: (),
|
||||
},
|
||||
annotation: None,
|
||||
location: 38..42,
|
||||
},
|
||||
],
|
||||
kind: Expect {
|
||||
backpassing: false,
|
||||
},
|
||||
kind: Expect,
|
||||
annotation: None,
|
||||
},
|
||||
Var {
|
||||
location: 54..59,
|
||||
|
@ -40,6 +47,6 @@ Test(
|
|||
return_annotation: None,
|
||||
return_type: (),
|
||||
end_position: 60,
|
||||
can_error: true,
|
||||
on_test_failure: SucceedEventually,
|
||||
},
|
||||
)
|
||||
|
|
|
@ -1,101 +1,161 @@
|
|||
---
|
||||
source: crates/aiken-lang/src/parser/definition/validator.rs
|
||||
description: "Code:\n\nvalidator {\n fn foo(datum, rdmr, ctx) {\n True\n }\n\n fn bar(rdmr, ctx) {\n True\n }\n}\n"
|
||||
description: "Code:\n\nvalidator thing {\n spend (datum, rdmr, ctx) {\n True\n }\n\n mint (rdmr, ctx) {\n True\n }\n}\n"
|
||||
---
|
||||
Validator(
|
||||
Validator {
|
||||
doc: None,
|
||||
end_position: 90,
|
||||
fun: Function {
|
||||
arguments: [
|
||||
Arg {
|
||||
arg_name: Named {
|
||||
name: "datum",
|
||||
label: "datum",
|
||||
location: 21..26,
|
||||
is_validator_param: false,
|
||||
},
|
||||
location: 21..26,
|
||||
annotation: None,
|
||||
tipo: (),
|
||||
},
|
||||
Arg {
|
||||
arg_name: Named {
|
||||
name: "rdmr",
|
||||
label: "rdmr",
|
||||
location: 28..32,
|
||||
is_validator_param: false,
|
||||
},
|
||||
location: 28..32,
|
||||
annotation: None,
|
||||
tipo: (),
|
||||
},
|
||||
Arg {
|
||||
arg_name: Named {
|
||||
name: "ctx",
|
||||
label: "ctx",
|
||||
location: 34..37,
|
||||
is_validator_param: false,
|
||||
},
|
||||
location: 34..37,
|
||||
annotation: None,
|
||||
tipo: (),
|
||||
},
|
||||
],
|
||||
body: Var {
|
||||
location: 45..49,
|
||||
name: "True",
|
||||
},
|
||||
doc: None,
|
||||
location: 14..38,
|
||||
name: "foo",
|
||||
public: false,
|
||||
return_annotation: None,
|
||||
return_type: (),
|
||||
end_position: 52,
|
||||
can_error: true,
|
||||
},
|
||||
other_fun: Some(
|
||||
end_position: 95,
|
||||
handlers: [
|
||||
Function {
|
||||
arguments: [
|
||||
Arg {
|
||||
arg_name: Named {
|
||||
name: "rdmr",
|
||||
label: "rdmr",
|
||||
location: 64..68,
|
||||
is_validator_param: false,
|
||||
},
|
||||
location: 64..68,
|
||||
UntypedArg {
|
||||
by: ByName(
|
||||
Named {
|
||||
name: "datum",
|
||||
label: "datum",
|
||||
location: 27..32,
|
||||
},
|
||||
),
|
||||
location: 27..32,
|
||||
annotation: None,
|
||||
tipo: (),
|
||||
doc: None,
|
||||
is_validator_param: false,
|
||||
},
|
||||
Arg {
|
||||
arg_name: Named {
|
||||
name: "ctx",
|
||||
label: "ctx",
|
||||
location: 70..73,
|
||||
is_validator_param: false,
|
||||
},
|
||||
location: 70..73,
|
||||
UntypedArg {
|
||||
by: ByName(
|
||||
Named {
|
||||
name: "rdmr",
|
||||
label: "rdmr",
|
||||
location: 34..38,
|
||||
},
|
||||
),
|
||||
location: 34..38,
|
||||
annotation: None,
|
||||
tipo: (),
|
||||
doc: None,
|
||||
is_validator_param: false,
|
||||
},
|
||||
UntypedArg {
|
||||
by: ByName(
|
||||
Named {
|
||||
name: "ctx",
|
||||
label: "ctx",
|
||||
location: 40..43,
|
||||
},
|
||||
),
|
||||
location: 40..43,
|
||||
annotation: None,
|
||||
doc: None,
|
||||
is_validator_param: false,
|
||||
},
|
||||
],
|
||||
body: Var {
|
||||
location: 81..85,
|
||||
location: 51..55,
|
||||
name: "True",
|
||||
},
|
||||
doc: None,
|
||||
location: 57..74,
|
||||
name: "bar",
|
||||
public: false,
|
||||
return_annotation: None,
|
||||
location: 20..44,
|
||||
name: "spend",
|
||||
public: true,
|
||||
return_annotation: Some(
|
||||
Constructor {
|
||||
location: 26..44,
|
||||
module: None,
|
||||
name: "Bool",
|
||||
arguments: [],
|
||||
},
|
||||
),
|
||||
return_type: (),
|
||||
end_position: 88,
|
||||
can_error: true,
|
||||
end_position: 58,
|
||||
on_test_failure: FailImmediately,
|
||||
},
|
||||
),
|
||||
Function {
|
||||
arguments: [
|
||||
UntypedArg {
|
||||
by: ByName(
|
||||
Named {
|
||||
name: "rdmr",
|
||||
label: "rdmr",
|
||||
location: 69..73,
|
||||
},
|
||||
),
|
||||
location: 69..73,
|
||||
annotation: None,
|
||||
doc: None,
|
||||
is_validator_param: false,
|
||||
},
|
||||
UntypedArg {
|
||||
by: ByName(
|
||||
Named {
|
||||
name: "ctx",
|
||||
label: "ctx",
|
||||
location: 75..78,
|
||||
},
|
||||
),
|
||||
location: 75..78,
|
||||
annotation: None,
|
||||
doc: None,
|
||||
is_validator_param: false,
|
||||
},
|
||||
],
|
||||
body: Var {
|
||||
location: 86..90,
|
||||
name: "True",
|
||||
},
|
||||
doc: None,
|
||||
location: 63..79,
|
||||
name: "mint",
|
||||
public: true,
|
||||
return_annotation: Some(
|
||||
Constructor {
|
||||
location: 68..79,
|
||||
module: None,
|
||||
name: "Bool",
|
||||
arguments: [],
|
||||
},
|
||||
),
|
||||
return_type: (),
|
||||
end_position: 93,
|
||||
on_test_failure: FailImmediately,
|
||||
},
|
||||
],
|
||||
location: 0..9,
|
||||
name: "thing",
|
||||
params: [],
|
||||
fallback: Function {
|
||||
arguments: [
|
||||
UntypedArg {
|
||||
by: ByName(
|
||||
Discarded {
|
||||
name: "_",
|
||||
label: "_",
|
||||
location: 0..9,
|
||||
},
|
||||
),
|
||||
location: 0..9,
|
||||
annotation: None,
|
||||
doc: None,
|
||||
is_validator_param: false,
|
||||
},
|
||||
],
|
||||
body: ErrorTerm {
|
||||
location: 0..9,
|
||||
},
|
||||
doc: None,
|
||||
location: 0..9,
|
||||
name: "else",
|
||||
public: true,
|
||||
return_annotation: Some(
|
||||
Constructor {
|
||||
location: 0..9,
|
||||
module: None,
|
||||
name: "Bool",
|
||||
arguments: [],
|
||||
},
|
||||
),
|
||||
return_type: (),
|
||||
end_position: 8,
|
||||
on_test_failure: FailImmediately,
|
||||
},
|
||||
},
|
||||
)
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
---
|
||||
source: crates/aiken-lang/src/parser/definition/data_type.rs
|
||||
description: "Code:\n\npub type Foo {\n}\n"
|
||||
---
|
||||
DataType(
|
||||
DataType {
|
||||
constructors: [
|
||||
RecordConstructor {
|
||||
location: 0..16,
|
||||
name: "Foo",
|
||||
arguments: [],
|
||||
doc: None,
|
||||
sugar: true,
|
||||
},
|
||||
],
|
||||
doc: None,
|
||||
location: 0..16,
|
||||
name: "Foo",
|
||||
opaque: false,
|
||||
parameters: [],
|
||||
public: true,
|
||||
typed_parameters: [],
|
||||
},
|
||||
)
|
|
@ -0,0 +1,161 @@
|
|||
---
|
||||
source: crates/aiken-lang/src/parser/definition/validator.rs
|
||||
description: "Code:\n\nvalidator thing {\n spend (datum, rdmr, ctx) {\n True\n }\n\n mint (rdmr, ctx) {\n True\n }\n\n else (_) {\n fail\n }\n}\n"
|
||||
---
|
||||
Validator(
|
||||
Validator {
|
||||
doc: None,
|
||||
end_position: 122,
|
||||
handlers: [
|
||||
Function {
|
||||
arguments: [
|
||||
UntypedArg {
|
||||
by: ByName(
|
||||
Named {
|
||||
name: "datum",
|
||||
label: "datum",
|
||||
location: 27..32,
|
||||
},
|
||||
),
|
||||
location: 27..32,
|
||||
annotation: None,
|
||||
doc: None,
|
||||
is_validator_param: false,
|
||||
},
|
||||
UntypedArg {
|
||||
by: ByName(
|
||||
Named {
|
||||
name: "rdmr",
|
||||
label: "rdmr",
|
||||
location: 34..38,
|
||||
},
|
||||
),
|
||||
location: 34..38,
|
||||
annotation: None,
|
||||
doc: None,
|
||||
is_validator_param: false,
|
||||
},
|
||||
UntypedArg {
|
||||
by: ByName(
|
||||
Named {
|
||||
name: "ctx",
|
||||
label: "ctx",
|
||||
location: 40..43,
|
||||
},
|
||||
),
|
||||
location: 40..43,
|
||||
annotation: None,
|
||||
doc: None,
|
||||
is_validator_param: false,
|
||||
},
|
||||
],
|
||||
body: Var {
|
||||
location: 51..55,
|
||||
name: "True",
|
||||
},
|
||||
doc: None,
|
||||
location: 20..44,
|
||||
name: "spend",
|
||||
public: true,
|
||||
return_annotation: Some(
|
||||
Constructor {
|
||||
location: 26..44,
|
||||
module: None,
|
||||
name: "Bool",
|
||||
arguments: [],
|
||||
},
|
||||
),
|
||||
return_type: (),
|
||||
end_position: 58,
|
||||
on_test_failure: FailImmediately,
|
||||
},
|
||||
Function {
|
||||
arguments: [
|
||||
UntypedArg {
|
||||
by: ByName(
|
||||
Named {
|
||||
name: "rdmr",
|
||||
label: "rdmr",
|
||||
location: 69..73,
|
||||
},
|
||||
),
|
||||
location: 69..73,
|
||||
annotation: None,
|
||||
doc: None,
|
||||
is_validator_param: false,
|
||||
},
|
||||
UntypedArg {
|
||||
by: ByName(
|
||||
Named {
|
||||
name: "ctx",
|
||||
label: "ctx",
|
||||
location: 75..78,
|
||||
},
|
||||
),
|
||||
location: 75..78,
|
||||
annotation: None,
|
||||
doc: None,
|
||||
is_validator_param: false,
|
||||
},
|
||||
],
|
||||
body: Var {
|
||||
location: 86..90,
|
||||
name: "True",
|
||||
},
|
||||
doc: None,
|
||||
location: 63..79,
|
||||
name: "mint",
|
||||
public: true,
|
||||
return_annotation: Some(
|
||||
Constructor {
|
||||
location: 68..79,
|
||||
module: None,
|
||||
name: "Bool",
|
||||
arguments: [],
|
||||
},
|
||||
),
|
||||
return_type: (),
|
||||
end_position: 93,
|
||||
on_test_failure: FailImmediately,
|
||||
},
|
||||
],
|
||||
location: 0..9,
|
||||
name: "thing",
|
||||
params: [],
|
||||
fallback: Function {
|
||||
arguments: [
|
||||
UntypedArg {
|
||||
by: ByName(
|
||||
Discarded {
|
||||
name: "_",
|
||||
label: "_",
|
||||
location: 104..105,
|
||||
},
|
||||
),
|
||||
location: 104..105,
|
||||
annotation: None,
|
||||
doc: None,
|
||||
is_validator_param: false,
|
||||
},
|
||||
],
|
||||
body: ErrorTerm {
|
||||
location: 113..117,
|
||||
},
|
||||
doc: None,
|
||||
location: 103..106,
|
||||
name: "else",
|
||||
public: true,
|
||||
return_annotation: Some(
|
||||
Constructor {
|
||||
location: 103..106,
|
||||
module: None,
|
||||
name: "Bool",
|
||||
arguments: [],
|
||||
},
|
||||
),
|
||||
return_type: (),
|
||||
end_position: 120,
|
||||
on_test_failure: FailImmediately,
|
||||
},
|
||||
},
|
||||
)
|
51
crates/aiken-lang/src/parser/definition/snapshots/function_assignment_only.snap
vendored
Normal file
51
crates/aiken-lang/src/parser/definition/snapshots/function_assignment_only.snap
vendored
Normal file
|
@ -0,0 +1,51 @@
|
|||
---
|
||||
source: crates/aiken-lang/src/parser/definition/function.rs
|
||||
description: "Code:\n\nfn run() {\n let x = 1 + 1\n}\n"
|
||||
---
|
||||
Fn(
|
||||
Function {
|
||||
arguments: [],
|
||||
body: Assignment {
|
||||
location: 13..26,
|
||||
value: BinOp {
|
||||
location: 21..26,
|
||||
name: AddInt,
|
||||
left: UInt {
|
||||
location: 21..22,
|
||||
value: "1",
|
||||
base: Decimal {
|
||||
numeric_underscore: false,
|
||||
},
|
||||
},
|
||||
right: UInt {
|
||||
location: 25..26,
|
||||
value: "1",
|
||||
base: Decimal {
|
||||
numeric_underscore: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
patterns: [
|
||||
AssignmentPattern {
|
||||
pattern: Var {
|
||||
location: 17..18,
|
||||
name: "x",
|
||||
},
|
||||
annotation: None,
|
||||
location: 17..18,
|
||||
},
|
||||
],
|
||||
kind: Let {
|
||||
backpassing: false,
|
||||
},
|
||||
},
|
||||
doc: None,
|
||||
location: 0..8,
|
||||
name: "run",
|
||||
public: false,
|
||||
return_annotation: None,
|
||||
return_type: (),
|
||||
end_position: 27,
|
||||
on_test_failure: FailImmediately,
|
||||
},
|
||||
)
|
62
crates/aiken-lang/src/parser/definition/snapshots/function_by_pattern_no_annotation.snap
vendored
Normal file
62
crates/aiken-lang/src/parser/definition/snapshots/function_by_pattern_no_annotation.snap
vendored
Normal file
|
@ -0,0 +1,62 @@
|
|||
---
|
||||
source: crates/aiken-lang/src/parser/definition/function.rs
|
||||
description: "Code:\n\nfn foo(Foo { my_field }) {\n my_field * 2\n}\n"
|
||||
---
|
||||
Fn(
|
||||
Function {
|
||||
arguments: [
|
||||
UntypedArg {
|
||||
by: ByPattern(
|
||||
Constructor {
|
||||
is_record: true,
|
||||
location: 7..23,
|
||||
name: "Foo",
|
||||
arguments: [
|
||||
CallArg {
|
||||
label: Some(
|
||||
"my_field",
|
||||
),
|
||||
location: 13..21,
|
||||
value: Var {
|
||||
location: 13..21,
|
||||
name: "my_field",
|
||||
},
|
||||
},
|
||||
],
|
||||
module: None,
|
||||
constructor: (),
|
||||
spread_location: None,
|
||||
tipo: (),
|
||||
},
|
||||
),
|
||||
location: 7..23,
|
||||
annotation: None,
|
||||
doc: None,
|
||||
is_validator_param: false,
|
||||
},
|
||||
],
|
||||
body: BinOp {
|
||||
location: 31..43,
|
||||
name: MultInt,
|
||||
left: Var {
|
||||
location: 31..39,
|
||||
name: "my_field",
|
||||
},
|
||||
right: UInt {
|
||||
location: 42..43,
|
||||
value: "2",
|
||||
base: Decimal {
|
||||
numeric_underscore: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
doc: None,
|
||||
location: 0..24,
|
||||
name: "foo",
|
||||
public: false,
|
||||
return_annotation: None,
|
||||
return_type: (),
|
||||
end_position: 44,
|
||||
on_test_failure: FailImmediately,
|
||||
},
|
||||
)
|
69
crates/aiken-lang/src/parser/definition/snapshots/function_by_pattern_with_alias.snap
vendored
Normal file
69
crates/aiken-lang/src/parser/definition/snapshots/function_by_pattern_with_alias.snap
vendored
Normal file
|
@ -0,0 +1,69 @@
|
|||
---
|
||||
source: crates/aiken-lang/src/parser/definition/function.rs
|
||||
description: "Code:\n\nfn foo(Foo { my_field, .. } as x) {\n my_field * x.my_other_field\n}\n"
|
||||
---
|
||||
Fn(
|
||||
Function {
|
||||
arguments: [
|
||||
UntypedArg {
|
||||
by: ByPattern(
|
||||
Assign {
|
||||
name: "x",
|
||||
location: 7..32,
|
||||
pattern: Constructor {
|
||||
is_record: true,
|
||||
location: 7..27,
|
||||
name: "Foo",
|
||||
arguments: [
|
||||
CallArg {
|
||||
label: Some(
|
||||
"my_field",
|
||||
),
|
||||
location: 13..21,
|
||||
value: Var {
|
||||
location: 13..21,
|
||||
name: "my_field",
|
||||
},
|
||||
},
|
||||
],
|
||||
module: None,
|
||||
constructor: (),
|
||||
spread_location: Some(
|
||||
23..25,
|
||||
),
|
||||
tipo: (),
|
||||
},
|
||||
},
|
||||
),
|
||||
location: 7..32,
|
||||
annotation: None,
|
||||
doc: None,
|
||||
is_validator_param: false,
|
||||
},
|
||||
],
|
||||
body: BinOp {
|
||||
location: 40..67,
|
||||
name: MultInt,
|
||||
left: Var {
|
||||
location: 40..48,
|
||||
name: "my_field",
|
||||
},
|
||||
right: FieldAccess {
|
||||
location: 51..67,
|
||||
label: "my_other_field",
|
||||
container: Var {
|
||||
location: 51..52,
|
||||
name: "x",
|
||||
},
|
||||
},
|
||||
},
|
||||
doc: None,
|
||||
location: 0..33,
|
||||
name: "foo",
|
||||
public: false,
|
||||
return_annotation: None,
|
||||
return_type: (),
|
||||
end_position: 68,
|
||||
on_test_failure: FailImmediately,
|
||||
},
|
||||
)
|
69
crates/aiken-lang/src/parser/definition/snapshots/function_by_pattern_with_annotation.snap
vendored
Normal file
69
crates/aiken-lang/src/parser/definition/snapshots/function_by_pattern_with_annotation.snap
vendored
Normal file
|
@ -0,0 +1,69 @@
|
|||
---
|
||||
source: crates/aiken-lang/src/parser/definition/function.rs
|
||||
description: "Code:\n\nfn foo(Foo { my_field }: Foo) {\n my_field * 2\n}\n"
|
||||
---
|
||||
Fn(
|
||||
Function {
|
||||
arguments: [
|
||||
UntypedArg {
|
||||
by: ByPattern(
|
||||
Constructor {
|
||||
is_record: true,
|
||||
location: 7..23,
|
||||
name: "Foo",
|
||||
arguments: [
|
||||
CallArg {
|
||||
label: Some(
|
||||
"my_field",
|
||||
),
|
||||
location: 13..21,
|
||||
value: Var {
|
||||
location: 13..21,
|
||||
name: "my_field",
|
||||
},
|
||||
},
|
||||
],
|
||||
module: None,
|
||||
constructor: (),
|
||||
spread_location: None,
|
||||
tipo: (),
|
||||
},
|
||||
),
|
||||
location: 7..28,
|
||||
annotation: Some(
|
||||
Constructor {
|
||||
location: 25..28,
|
||||
module: None,
|
||||
name: "Foo",
|
||||
arguments: [],
|
||||
},
|
||||
),
|
||||
doc: None,
|
||||
is_validator_param: false,
|
||||
},
|
||||
],
|
||||
body: BinOp {
|
||||
location: 36..48,
|
||||
name: MultInt,
|
||||
left: Var {
|
||||
location: 36..44,
|
||||
name: "my_field",
|
||||
},
|
||||
right: UInt {
|
||||
location: 47..48,
|
||||
value: "2",
|
||||
base: Decimal {
|
||||
numeric_underscore: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
doc: None,
|
||||
location: 0..29,
|
||||
name: "foo",
|
||||
public: false,
|
||||
return_annotation: None,
|
||||
return_type: (),
|
||||
end_position: 49,
|
||||
on_test_failure: FailImmediately,
|
||||
},
|
||||
)
|
|
@ -11,10 +11,11 @@ Fn(
|
|||
then: ErrorTerm {
|
||||
location: 0..15,
|
||||
},
|
||||
text: String {
|
||||
label: String {
|
||||
location: 0..15,
|
||||
value: "aiken::todo",
|
||||
},
|
||||
arguments: [],
|
||||
},
|
||||
doc: None,
|
||||
location: 0..12,
|
||||
|
@ -23,6 +24,6 @@ Fn(
|
|||
return_annotation: None,
|
||||
return_type: (),
|
||||
end_position: 14,
|
||||
can_error: true,
|
||||
on_test_failure: FailImmediately,
|
||||
},
|
||||
)
|
||||
|
|
|
@ -11,10 +11,11 @@ Fn(
|
|||
then: ErrorTerm {
|
||||
location: 0..11,
|
||||
},
|
||||
text: String {
|
||||
label: String {
|
||||
location: 0..11,
|
||||
value: "aiken::todo",
|
||||
},
|
||||
arguments: [],
|
||||
},
|
||||
doc: None,
|
||||
location: 0..8,
|
||||
|
@ -23,6 +24,6 @@ Fn(
|
|||
return_annotation: None,
|
||||
return_type: (),
|
||||
end_position: 10,
|
||||
can_error: true,
|
||||
on_test_failure: FailImmediately,
|
||||
},
|
||||
)
|
||||
|
|
|
@ -0,0 +1,53 @@
|
|||
---
|
||||
source: crates/aiken-lang/src/parser/definition/constant.rs
|
||||
description: "Code:\n\npub const point =\n #<Bls12_381, G1>\"950dfd33da2682260c76038dfb8bad6e84ae9d599a3c151815945ac1e6ef6b1027cd917f3907479d20d636ce437a41f5\"\n"
|
||||
---
|
||||
ModuleConstant(
|
||||
ModuleConstant {
|
||||
doc: None,
|
||||
location: 0..134,
|
||||
public: true,
|
||||
name: "point",
|
||||
annotation: None,
|
||||
value: CurvePoint {
|
||||
location: 20..134,
|
||||
point: Bls12_381(
|
||||
G1(
|
||||
blst_p1 {
|
||||
x: blst_fp {
|
||||
l: [
|
||||
6044239372598254900,
|
||||
11111890802926526657,
|
||||
302563157772145122,
|
||||
17359147598889707489,
|
||||
6255098506247414666,
|
||||
1773881592225990778,
|
||||
],
|
||||
},
|
||||
y: blst_fp {
|
||||
l: [
|
||||
9961536754182800925,
|
||||
16512912018612749997,
|
||||
10822258563185590636,
|
||||
17742512098199848220,
|
||||
16542676355910829810,
|
||||
1246663995533626329,
|
||||
],
|
||||
},
|
||||
z: blst_fp {
|
||||
l: [
|
||||
8505329371266088957,
|
||||
17002214543764226050,
|
||||
6865905132761471162,
|
||||
8632934651105793861,
|
||||
6631298214892334189,
|
||||
1582556514881692819,
|
||||
],
|
||||
},
|
||||
},
|
||||
),
|
||||
),
|
||||
preferred_format: HexadecimalString,
|
||||
},
|
||||
},
|
||||
)
|
|
@ -0,0 +1,95 @@
|
|||
---
|
||||
source: crates/aiken-lang/src/parser/definition/constant.rs
|
||||
description: "Code:\n\npub const point =\n #<Bls12_381, G2>\"b0629fa1158c2d23a10413fe91d381a84d25e31d041cd0377d25828498fd02011b35893938ced97535395e4815201e67108bcd4665e0db25d602d76fa791fab706c54abf5e1a9e44b4ac1e6badf3d2ac0328f5e30be341677c8bac5dda7682f1\"\n"
|
||||
---
|
||||
ModuleConstant(
|
||||
ModuleConstant {
|
||||
doc: None,
|
||||
location: 0..230,
|
||||
public: true,
|
||||
name: "point",
|
||||
annotation: None,
|
||||
value: CurvePoint {
|
||||
location: 20..230,
|
||||
point: Bls12_381(
|
||||
G2(
|
||||
blst_p2 {
|
||||
x: blst_fp2 {
|
||||
fp: [
|
||||
blst_fp {
|
||||
l: [
|
||||
17730081354175209597,
|
||||
14393386882433024580,
|
||||
15392237588654399813,
|
||||
13132804324748058634,
|
||||
437180824693959563,
|
||||
1209861931331675905,
|
||||
],
|
||||
},
|
||||
blst_fp {
|
||||
l: [
|
||||
16640134302799489459,
|
||||
13200372101402265278,
|
||||
3491868243815184488,
|
||||
15749231165976205625,
|
||||
10700844509881097270,
|
||||
978652262052845623,
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
y: blst_fp2 {
|
||||
fp: [
|
||||
blst_fp {
|
||||
l: [
|
||||
15138882304466955413,
|
||||
4159460337006967255,
|
||||
16059739792181277381,
|
||||
4673287545394659101,
|
||||
6265740687822174786,
|
||||
1492317236631555918,
|
||||
],
|
||||
},
|
||||
blst_fp {
|
||||
l: [
|
||||
7482650483077279660,
|
||||
1528034342759119680,
|
||||
1732030343867801117,
|
||||
8394128533480400141,
|
||||
6497663211870147931,
|
||||
683724859415636652,
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
z: blst_fp2 {
|
||||
fp: [
|
||||
blst_fp {
|
||||
l: [
|
||||
8505329371266088957,
|
||||
17002214543764226050,
|
||||
6865905132761471162,
|
||||
8632934651105793861,
|
||||
6631298214892334189,
|
||||
1582556514881692819,
|
||||
],
|
||||
},
|
||||
blst_fp {
|
||||
l: [
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
),
|
||||
),
|
||||
preferred_format: HexadecimalString,
|
||||
},
|
||||
},
|
||||
)
|
|
@ -2,17 +2,15 @@
|
|||
source: crates/aiken-lang/src/parser/definition/import.rs
|
||||
description: "Code:\n\nuse aiken/list as foo"
|
||||
---
|
||||
Use(
|
||||
Use {
|
||||
as_name: Some(
|
||||
"foo",
|
||||
),
|
||||
location: 0..21,
|
||||
module: [
|
||||
"aiken",
|
||||
"list",
|
||||
],
|
||||
package: (),
|
||||
unqualified: [],
|
||||
},
|
||||
)
|
||||
Use {
|
||||
as_name: Some(
|
||||
"foo",
|
||||
),
|
||||
location: 0..21,
|
||||
module: [
|
||||
"aiken",
|
||||
"list",
|
||||
],
|
||||
package: (),
|
||||
unqualified: [],
|
||||
}
|
||||
|
|
|
@ -2,15 +2,13 @@
|
|||
source: crates/aiken-lang/src/parser/definition/import.rs
|
||||
description: "Code:\n\nuse aiken/list"
|
||||
---
|
||||
Use(
|
||||
Use {
|
||||
as_name: None,
|
||||
location: 0..14,
|
||||
module: [
|
||||
"aiken",
|
||||
"list",
|
||||
],
|
||||
package: (),
|
||||
unqualified: [],
|
||||
},
|
||||
)
|
||||
Use {
|
||||
as_name: None,
|
||||
location: 0..14,
|
||||
module: [
|
||||
"aiken",
|
||||
"list",
|
||||
],
|
||||
package: (),
|
||||
unqualified: [],
|
||||
}
|
||||
|
|
|
@ -2,32 +2,28 @@
|
|||
source: crates/aiken-lang/src/parser/definition/import.rs
|
||||
description: "Code:\n\nuse std/address.{Address as A, thing as w}\n"
|
||||
---
|
||||
Use(
|
||||
Use {
|
||||
as_name: None,
|
||||
location: 0..42,
|
||||
module: [
|
||||
"std",
|
||||
"address",
|
||||
],
|
||||
package: (),
|
||||
unqualified: [
|
||||
UnqualifiedImport {
|
||||
location: 17..29,
|
||||
name: "Address",
|
||||
as_name: Some(
|
||||
"A",
|
||||
),
|
||||
layer: Value,
|
||||
},
|
||||
UnqualifiedImport {
|
||||
location: 31..41,
|
||||
name: "thing",
|
||||
as_name: Some(
|
||||
"w",
|
||||
),
|
||||
layer: Value,
|
||||
},
|
||||
],
|
||||
},
|
||||
)
|
||||
Use {
|
||||
as_name: None,
|
||||
location: 0..42,
|
||||
module: [
|
||||
"std",
|
||||
"address",
|
||||
],
|
||||
package: (),
|
||||
unqualified: [
|
||||
UnqualifiedImport {
|
||||
location: 17..29,
|
||||
name: "Address",
|
||||
as_name: Some(
|
||||
"A",
|
||||
),
|
||||
},
|
||||
UnqualifiedImport {
|
||||
location: 31..41,
|
||||
name: "thing",
|
||||
as_name: Some(
|
||||
"w",
|
||||
),
|
||||
},
|
||||
],
|
||||
}
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
---
|
||||
source: crates/aiken-lang/src/parser/definition/data_type.rs
|
||||
description: "Code:\n\npub type Foo {\n wow: Int,\n}\n"
|
||||
---
|
||||
DataType(
|
||||
DataType {
|
||||
constructors: [
|
||||
RecordConstructor {
|
||||
location: 13..28,
|
||||
name: "Foo",
|
||||
arguments: [
|
||||
RecordConstructorArg {
|
||||
label: Some(
|
||||
"wow",
|
||||
),
|
||||
annotation: Constructor {
|
||||
location: 22..25,
|
||||
module: None,
|
||||
name: "Int",
|
||||
arguments: [],
|
||||
},
|
||||
location: 17..25,
|
||||
tipo: (),
|
||||
doc: None,
|
||||
},
|
||||
],
|
||||
doc: None,
|
||||
sugar: true,
|
||||
},
|
||||
],
|
||||
doc: None,
|
||||
location: 0..28,
|
||||
name: "Foo",
|
||||
opaque: false,
|
||||
parameters: [],
|
||||
public: true,
|
||||
typed_parameters: [],
|
||||
},
|
||||
)
|
|
@ -1,62 +1,112 @@
|
|||
---
|
||||
source: crates/aiken-lang/src/parser/definition/validator.rs
|
||||
description: "Code:\n\nvalidator {\n fn foo(datum, rdmr, ctx) {\n True\n }\n}\n"
|
||||
description: "Code:\n\nvalidator hello {\n spend (datum, rdmr, ctx) {\n True\n }\n}\n"
|
||||
---
|
||||
Validator(
|
||||
Validator {
|
||||
doc: None,
|
||||
end_position: 54,
|
||||
fun: Function {
|
||||
end_position: 60,
|
||||
handlers: [
|
||||
Function {
|
||||
arguments: [
|
||||
UntypedArg {
|
||||
by: ByName(
|
||||
Named {
|
||||
name: "datum",
|
||||
label: "datum",
|
||||
location: 27..32,
|
||||
},
|
||||
),
|
||||
location: 27..32,
|
||||
annotation: None,
|
||||
doc: None,
|
||||
is_validator_param: false,
|
||||
},
|
||||
UntypedArg {
|
||||
by: ByName(
|
||||
Named {
|
||||
name: "rdmr",
|
||||
label: "rdmr",
|
||||
location: 34..38,
|
||||
},
|
||||
),
|
||||
location: 34..38,
|
||||
annotation: None,
|
||||
doc: None,
|
||||
is_validator_param: false,
|
||||
},
|
||||
UntypedArg {
|
||||
by: ByName(
|
||||
Named {
|
||||
name: "ctx",
|
||||
label: "ctx",
|
||||
location: 40..43,
|
||||
},
|
||||
),
|
||||
location: 40..43,
|
||||
annotation: None,
|
||||
doc: None,
|
||||
is_validator_param: false,
|
||||
},
|
||||
],
|
||||
body: Var {
|
||||
location: 51..55,
|
||||
name: "True",
|
||||
},
|
||||
doc: None,
|
||||
location: 20..44,
|
||||
name: "spend",
|
||||
public: true,
|
||||
return_annotation: Some(
|
||||
Constructor {
|
||||
location: 26..44,
|
||||
module: None,
|
||||
name: "Bool",
|
||||
arguments: [],
|
||||
},
|
||||
),
|
||||
return_type: (),
|
||||
end_position: 58,
|
||||
on_test_failure: FailImmediately,
|
||||
},
|
||||
],
|
||||
location: 0..9,
|
||||
name: "hello",
|
||||
params: [],
|
||||
fallback: Function {
|
||||
arguments: [
|
||||
Arg {
|
||||
arg_name: Named {
|
||||
name: "datum",
|
||||
label: "datum",
|
||||
location: 21..26,
|
||||
is_validator_param: false,
|
||||
},
|
||||
location: 21..26,
|
||||
UntypedArg {
|
||||
by: ByName(
|
||||
Discarded {
|
||||
name: "_",
|
||||
label: "_",
|
||||
location: 0..9,
|
||||
},
|
||||
),
|
||||
location: 0..9,
|
||||
annotation: None,
|
||||
tipo: (),
|
||||
},
|
||||
Arg {
|
||||
arg_name: Named {
|
||||
name: "rdmr",
|
||||
label: "rdmr",
|
||||
location: 28..32,
|
||||
is_validator_param: false,
|
||||
},
|
||||
location: 28..32,
|
||||
annotation: None,
|
||||
tipo: (),
|
||||
},
|
||||
Arg {
|
||||
arg_name: Named {
|
||||
name: "ctx",
|
||||
label: "ctx",
|
||||
location: 34..37,
|
||||
is_validator_param: false,
|
||||
},
|
||||
location: 34..37,
|
||||
annotation: None,
|
||||
tipo: (),
|
||||
doc: None,
|
||||
is_validator_param: false,
|
||||
},
|
||||
],
|
||||
body: Var {
|
||||
location: 45..49,
|
||||
name: "True",
|
||||
body: ErrorTerm {
|
||||
location: 0..9,
|
||||
},
|
||||
doc: None,
|
||||
location: 14..38,
|
||||
name: "foo",
|
||||
public: false,
|
||||
return_annotation: None,
|
||||
location: 0..9,
|
||||
name: "else",
|
||||
public: true,
|
||||
return_annotation: Some(
|
||||
Constructor {
|
||||
location: 0..9,
|
||||
module: None,
|
||||
name: "Bool",
|
||||
arguments: [],
|
||||
},
|
||||
),
|
||||
return_type: (),
|
||||
end_position: 52,
|
||||
can_error: true,
|
||||
end_position: 8,
|
||||
on_test_failure: FailImmediately,
|
||||
},
|
||||
other_fun: None,
|
||||
location: 0..9,
|
||||
params: [],
|
||||
},
|
||||
)
|
||||
|
|
|
@ -1,30 +1,44 @@
|
|||
use chumsky::prelude::*;
|
||||
|
||||
use crate::{
|
||||
ast,
|
||||
ast::OnTestFailure,
|
||||
expr::UntypedExpr,
|
||||
parser::{error::ParseError, expr, token::Token},
|
||||
parser::{
|
||||
annotation,
|
||||
chain::{call::parser as call, field_access, tuple_index::parser as tuple_index, Chain},
|
||||
error::ParseError,
|
||||
expr::{self, bytearray, int as uint, list, string, tuple, var},
|
||||
pattern,
|
||||
token::Token,
|
||||
},
|
||||
};
|
||||
use chumsky::prelude::*;
|
||||
|
||||
pub fn parser() -> impl Parser<Token, ast::UntypedDefinition, Error = ParseError> {
|
||||
// TODO: can remove Token::Bang after a few releases (curr v1.0.11)
|
||||
just(Token::Bang)
|
||||
.ignored()
|
||||
.or_not()
|
||||
.then_ignore(just(Token::Test))
|
||||
.then(select! {Token::Name {name} => name})
|
||||
.then_ignore(just(Token::LeftParen))
|
||||
.then_ignore(just(Token::RightParen))
|
||||
.then(just(Token::Fail).ignored().or_not())
|
||||
just(Token::Test)
|
||||
.ignore_then(select! {Token::Name {name} => name})
|
||||
.then(
|
||||
via()
|
||||
.separated_by(just(Token::Comma))
|
||||
.allow_trailing()
|
||||
.delimited_by(just(Token::LeftParen), just(Token::RightParen)),
|
||||
)
|
||||
.then(
|
||||
just(Token::Fail)
|
||||
.ignore_then(just(Token::Once).ignored().or_not().map(|once| {
|
||||
once.map(|_| OnTestFailure::SucceedImmediately)
|
||||
.unwrap_or(OnTestFailure::SucceedEventually)
|
||||
}))
|
||||
.or_not(),
|
||||
)
|
||||
.map_with_span(|name, span| (name, span))
|
||||
.then(
|
||||
expr::sequence()
|
||||
.or_not()
|
||||
.delimited_by(just(Token::LeftBrace), just(Token::RightBrace)),
|
||||
)
|
||||
.map_with_span(|((((old_fail, name), fail), span_end), body), span| {
|
||||
.map_with_span(|((((name, arguments), fail), span_end), body), span| {
|
||||
ast::UntypedDefinition::Test(ast::Function {
|
||||
arguments: vec![],
|
||||
arguments,
|
||||
body: body.unwrap_or_else(|| UntypedExpr::todo(None, span)),
|
||||
doc: None,
|
||||
location: span_end,
|
||||
|
@ -33,15 +47,101 @@ pub fn parser() -> impl Parser<Token, ast::UntypedDefinition, Error = ParseError
|
|||
public: false,
|
||||
return_annotation: None,
|
||||
return_type: (),
|
||||
can_error: fail.is_some() || old_fail.is_some(),
|
||||
on_test_failure: fail.unwrap_or(OnTestFailure::FailImmediately),
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
pub fn via() -> impl Parser<Token, ast::UntypedArgVia, Error = ParseError> {
|
||||
choice((
|
||||
select! {Token::DiscardName {name} => name}.map_with_span(|name, span| {
|
||||
ast::ArgBy::ByName(ast::ArgName::Discarded {
|
||||
label: name.clone(),
|
||||
name,
|
||||
location: span,
|
||||
})
|
||||
}),
|
||||
select! {Token::Name {name} => name}.map_with_span(|name, location| {
|
||||
ast::ArgBy::ByName(ast::ArgName::Named {
|
||||
label: name.clone(),
|
||||
name,
|
||||
location,
|
||||
})
|
||||
}),
|
||||
pattern().map(ast::ArgBy::ByPattern),
|
||||
))
|
||||
.then(just(Token::Colon).ignore_then(annotation()).or_not())
|
||||
.map_with_span(|(arg_name, annotation), location| (arg_name, annotation, location))
|
||||
.then_ignore(just(Token::Via))
|
||||
.then(fuzzer())
|
||||
.map(|((by, annotation, location), via)| ast::ArgVia {
|
||||
arg: ast::UntypedArg {
|
||||
by,
|
||||
annotation,
|
||||
location,
|
||||
doc: None,
|
||||
is_validator_param: false,
|
||||
},
|
||||
via,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn fuzzer<'a>() -> impl Parser<Token, UntypedExpr, Error = ParseError> + 'a {
|
||||
recursive(|expression| {
|
||||
let chain = choice((
|
||||
tuple_index(),
|
||||
field_access::parser(),
|
||||
call(expression.clone()),
|
||||
));
|
||||
|
||||
let int = || {
|
||||
just(Token::Minus)
|
||||
.to(ast::UnOp::Negate)
|
||||
.map_with_span(|op, span| (op, span))
|
||||
.or_not()
|
||||
.then(uint())
|
||||
.map(|(op, value)| match op {
|
||||
None => value,
|
||||
Some((op, location)) => UntypedExpr::UnOp {
|
||||
op,
|
||||
location,
|
||||
value: Box::new(value),
|
||||
},
|
||||
})
|
||||
};
|
||||
|
||||
choice((
|
||||
int(),
|
||||
string(),
|
||||
bytearray(),
|
||||
tuple(expression.clone()),
|
||||
list(expression.clone()),
|
||||
var(),
|
||||
))
|
||||
.then(chain.repeated())
|
||||
.foldl(|expr, chain| match chain {
|
||||
Chain::Call(args, span) => expr.call(args, span),
|
||||
Chain::FieldAccess(label, span) => expr.field_access(label, span),
|
||||
Chain::TupleIndex(index, span) => expr.tuple_index(index, span),
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::assert_definition;
|
||||
|
||||
#[test]
|
||||
fn def_test() {
|
||||
assert_definition!(
|
||||
r#"
|
||||
test foo() {
|
||||
True
|
||||
}
|
||||
"#
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn def_test_fail() {
|
||||
assert_definition!(
|
||||
|
@ -54,4 +154,37 @@ mod tests {
|
|||
"#
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn def_property_test() {
|
||||
assert_definition!(
|
||||
r#"
|
||||
test foo(x via fuzz.any_int) {
|
||||
True
|
||||
}
|
||||
"#
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn def_invalid_property_test() {
|
||||
assert_definition!(
|
||||
r#"
|
||||
test foo(x via f, y via g) {
|
||||
True
|
||||
}
|
||||
"#
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn def_property_test_annotated_fuzzer() {
|
||||
assert_definition!(
|
||||
r#"
|
||||
test foo(x: Int via foo()) {
|
||||
True
|
||||
}
|
||||
"#
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,62 +1,112 @@
|
|||
use chumsky::prelude::*;
|
||||
|
||||
use super::function::param;
|
||||
use crate::{
|
||||
ast,
|
||||
parser::{error::ParseError, token::Token},
|
||||
ast::{self, well_known},
|
||||
expr::UntypedExpr,
|
||||
parser::{annotation, error::ParseError, expr, token::Token},
|
||||
};
|
||||
|
||||
use super::function;
|
||||
use chumsky::prelude::*;
|
||||
|
||||
pub fn parser() -> impl Parser<Token, ast::UntypedDefinition, Error = ParseError> {
|
||||
just(Token::Validator)
|
||||
.ignore_then(
|
||||
function::param(true)
|
||||
.ignore_then(select! {Token::Name {name} => name})
|
||||
.then(
|
||||
param(true)
|
||||
.separated_by(just(Token::Comma))
|
||||
.allow_trailing()
|
||||
.delimited_by(just(Token::LeftParen), just(Token::RightParen))
|
||||
.map_with_span(|arguments, span| (arguments, span))
|
||||
.or_not(),
|
||||
)
|
||||
// so far: validator my_validator(arg1: Whatever)
|
||||
.then(
|
||||
function()
|
||||
select! {Token::Name {name} => name}
|
||||
.then(args_and_body())
|
||||
.map_with_span(|(name, mut function), span| {
|
||||
function.name = name;
|
||||
function.location.start = span.start;
|
||||
|
||||
function
|
||||
})
|
||||
.repeated()
|
||||
.at_least(1)
|
||||
.at_most(2)
|
||||
.delimited_by(just(Token::LeftBrace), just(Token::RightBrace))
|
||||
.map(|defs| {
|
||||
defs.into_iter().map(|def| {
|
||||
let ast::UntypedDefinition::Fn(fun) = def else {
|
||||
unreachable!("It should be a fn definition");
|
||||
};
|
||||
.then(
|
||||
just(Token::Else)
|
||||
.ignore_then(args_and_body().map_with_span(|mut function, span| {
|
||||
function.name = well_known::VALIDATOR_ELSE.to_string();
|
||||
function.location.start = span.start;
|
||||
|
||||
fun
|
||||
})
|
||||
}),
|
||||
function
|
||||
}))
|
||||
.or_not(),
|
||||
)
|
||||
.delimited_by(just(Token::LeftBrace), just(Token::RightBrace)),
|
||||
)
|
||||
.map_with_span(|(opt_extra_params, mut functions), span| {
|
||||
let (params, params_span) = opt_extra_params.unwrap_or((
|
||||
vec![],
|
||||
ast::Span {
|
||||
start: 0,
|
||||
end: span.start + "validator".len(),
|
||||
},
|
||||
));
|
||||
.map_with_span(
|
||||
|((name, opt_extra_params), (handlers, opt_catch_all)), span| {
|
||||
let (params, params_span) = opt_extra_params.unwrap_or((
|
||||
vec![],
|
||||
ast::Span {
|
||||
start: 0,
|
||||
end: span.start + "validator".len(),
|
||||
},
|
||||
));
|
||||
|
||||
ast::UntypedDefinition::Validator(ast::Validator {
|
||||
doc: None,
|
||||
fun: functions
|
||||
.next()
|
||||
.expect("unwrapping safe because there's 'at_least(1)' function"),
|
||||
other_fun: functions.next(),
|
||||
location: ast::Span {
|
||||
let location = ast::Span {
|
||||
start: span.start,
|
||||
// capture the span from the optional params
|
||||
end: params_span.end,
|
||||
},
|
||||
params,
|
||||
end_position: span.end - 1,
|
||||
})
|
||||
})
|
||||
};
|
||||
|
||||
ast::UntypedDefinition::Validator(ast::Validator {
|
||||
doc: None,
|
||||
name,
|
||||
handlers,
|
||||
location,
|
||||
params,
|
||||
end_position: span.end - 1,
|
||||
fallback: opt_catch_all
|
||||
.unwrap_or(ast::UntypedValidator::default_fallback(location)),
|
||||
})
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
pub fn args_and_body() -> impl Parser<Token, ast::UntypedFunction, Error = ParseError> {
|
||||
param(false)
|
||||
.separated_by(just(Token::Comma))
|
||||
.allow_trailing()
|
||||
.delimited_by(just(Token::LeftParen), just(Token::RightParen))
|
||||
.map_with_span(|arguments, span| (arguments, span))
|
||||
.then(just(Token::RArrow).ignore_then(annotation()).or_not())
|
||||
.then(
|
||||
expr::sequence()
|
||||
.or_not()
|
||||
.delimited_by(just(Token::LeftBrace), just(Token::RightBrace)),
|
||||
)
|
||||
.map_with_span(
|
||||
|(((arguments, args_span), return_annotation), body), span| {
|
||||
let location = ast::Span {
|
||||
start: span.start,
|
||||
end: return_annotation
|
||||
.as_ref()
|
||||
.map(|l| l.location().end)
|
||||
.unwrap_or_else(|| args_span.end),
|
||||
};
|
||||
|
||||
ast::Function {
|
||||
arguments,
|
||||
body: body.unwrap_or_else(|| UntypedExpr::todo(None, span)),
|
||||
doc: None,
|
||||
location,
|
||||
end_position: span.end - 1,
|
||||
name: "temp".to_string(),
|
||||
public: true,
|
||||
return_annotation: return_annotation
|
||||
.or(Some(ast::Annotation::boolean(location))),
|
||||
return_type: (),
|
||||
on_test_failure: ast::OnTestFailure::FailImmediately,
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
@ -67,8 +117,8 @@ mod tests {
|
|||
fn validator() {
|
||||
assert_definition!(
|
||||
r#"
|
||||
validator {
|
||||
fn foo(datum, rdmr, ctx) {
|
||||
validator hello {
|
||||
spend (datum, rdmr, ctx) {
|
||||
True
|
||||
}
|
||||
}
|
||||
|
@ -80,16 +130,37 @@ mod tests {
|
|||
fn double_validator() {
|
||||
assert_definition!(
|
||||
r#"
|
||||
validator {
|
||||
fn foo(datum, rdmr, ctx) {
|
||||
validator thing {
|
||||
spend (datum, rdmr, ctx) {
|
||||
True
|
||||
}
|
||||
|
||||
fn bar(rdmr, ctx) {
|
||||
mint (rdmr, ctx) {
|
||||
True
|
||||
}
|
||||
}
|
||||
"#
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fallback() {
|
||||
assert_definition!(
|
||||
r#"
|
||||
validator thing {
|
||||
spend (datum, rdmr, ctx) {
|
||||
True
|
||||
}
|
||||
|
||||
mint (rdmr, ctx) {
|
||||
True
|
||||
}
|
||||
|
||||
else (_) {
|
||||
fail
|
||||
}
|
||||
}
|
||||
"#
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
use crate::{ast::Span, parser::token::Token};
|
||||
use crate::{
|
||||
ast::{CurveType, Span},
|
||||
parser::token::Token,
|
||||
};
|
||||
use indoc::formatdoc;
|
||||
use miette::Diagnostic;
|
||||
use owo_colors::{OwoColorize, Stream::Stdout};
|
||||
|
@ -6,9 +9,33 @@ use std::collections::HashSet;
|
|||
|
||||
#[derive(Debug, Clone, Diagnostic, thiserror::Error)]
|
||||
#[error("{kind}\n")]
|
||||
#[diagnostic(
|
||||
help(
|
||||
"{}",
|
||||
match kind {
|
||||
ErrorKind::Unexpected(..) if !expected.is_empty() => {
|
||||
format!(
|
||||
"I am looking for one of the following patterns:\n{}",
|
||||
expected
|
||||
.iter()
|
||||
.map(|x| format!(
|
||||
"→ {}",
|
||||
x.to_aiken()
|
||||
.if_supports_color(Stdout, |s| s.purple())
|
||||
))
|
||||
.collect::<Vec<_>>()
|
||||
.join("\n")
|
||||
)
|
||||
},
|
||||
_ => {
|
||||
kind.help().map(|x| x.to_string()).unwrap_or_default()
|
||||
}
|
||||
}
|
||||
)
|
||||
)]
|
||||
pub struct ParseError {
|
||||
pub kind: ErrorKind,
|
||||
#[label]
|
||||
#[label("{}", .label.unwrap_or_default())]
|
||||
pub span: Span,
|
||||
#[allow(dead_code)]
|
||||
while_parsing: Option<(Span, &'static str)>,
|
||||
|
@ -25,6 +52,26 @@ impl ParseError {
|
|||
self
|
||||
}
|
||||
|
||||
pub fn expected_but_got(expected: Pattern, got: Pattern, span: Span) -> Self {
|
||||
Self {
|
||||
kind: ErrorKind::Unexpected(got),
|
||||
expected: HashSet::from_iter([expected]),
|
||||
span,
|
||||
while_parsing: None,
|
||||
label: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn invalid_assignment_right_hand_side(span: Span) -> Self {
|
||||
Self {
|
||||
kind: ErrorKind::UnfinishedAssignmentRightHandSide,
|
||||
span,
|
||||
while_parsing: None,
|
||||
expected: HashSet::new(),
|
||||
label: Some("invalid assignment right-hand side"),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn invalid_tuple_index(span: Span, index: String, suffix: Option<String>) -> Self {
|
||||
let hint = suffix.map(|suffix| format!("Did you mean '{index}{suffix}'?"));
|
||||
Self {
|
||||
|
@ -36,13 +83,39 @@ impl ParseError {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn invalid_when_clause_guard(span: Span) -> Self {
|
||||
pub fn deprecated_when_clause_guard(span: Span) -> Self {
|
||||
Self {
|
||||
kind: ErrorKind::InvalidWhenClause,
|
||||
kind: ErrorKind::DeprecatedWhenClause,
|
||||
span,
|
||||
while_parsing: None,
|
||||
expected: HashSet::new(),
|
||||
label: Some("invalid clause guard"),
|
||||
label: Some("deprecated"),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn point_not_on_curve(curve: CurveType, span: Span) -> Self {
|
||||
Self {
|
||||
kind: ErrorKind::PointNotOnCurve { curve },
|
||||
span,
|
||||
while_parsing: None,
|
||||
expected: HashSet::new(),
|
||||
label: Some("out off curve"),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn unknown_point_curve(curve: String, point: Option<String>, span: Span) -> Self {
|
||||
let label = if point.is_some() {
|
||||
Some("unknown curve")
|
||||
} else {
|
||||
Some("unknown point")
|
||||
};
|
||||
|
||||
Self {
|
||||
kind: ErrorKind::UnknownCurvePoint { curve, point },
|
||||
span,
|
||||
while_parsing: None,
|
||||
expected: HashSet::new(),
|
||||
label,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -75,6 +148,26 @@ impl ParseError {
|
|||
label: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn match_on_curve(span: Span) -> Self {
|
||||
Self {
|
||||
kind: ErrorKind::PatternMatchOnCurvePoint,
|
||||
span,
|
||||
while_parsing: None,
|
||||
expected: HashSet::new(),
|
||||
label: Some("cannot pattern-match on curve point"),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn match_string(span: Span) -> Self {
|
||||
Self {
|
||||
kind: ErrorKind::PatternMatchOnString,
|
||||
span,
|
||||
while_parsing: None,
|
||||
expected: HashSet::new(),
|
||||
label: Some("cannot pattern-match on string"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq for ParseError {
|
||||
|
@ -124,7 +217,7 @@ pub enum ErrorKind {
|
|||
UnexpectedEnd,
|
||||
|
||||
#[error("{0}")]
|
||||
#[diagnostic(help("{}", .0.help().unwrap_or_else(|| Box::new(""))))]
|
||||
#[diagnostic(help("{}", .0.help().unwrap_or_else(|| Box::new("")))) ]
|
||||
Unexpected(Pattern),
|
||||
|
||||
#[error("I discovered an invalid tuple index.")]
|
||||
|
@ -134,6 +227,25 @@ pub enum ErrorKind {
|
|||
hint: Option<String>,
|
||||
},
|
||||
|
||||
#[error("I spotted an unfinished assignment.")]
|
||||
#[diagnostic(
|
||||
help(
|
||||
"{} and {} bindings must be followed by a valid, complete, expression.",
|
||||
"let".if_supports_color(Stdout, |s| s.yellow()),
|
||||
"expect".if_supports_color(Stdout, |s| s.yellow()),
|
||||
),
|
||||
)]
|
||||
UnfinishedAssignmentRightHandSide,
|
||||
|
||||
#[error("I tripped over a {}", fmt_curve_type(.curve))]
|
||||
PointNotOnCurve { curve: CurveType },
|
||||
|
||||
#[error("I tripped over a {}", fmt_unknown_curve(.curve, .point))]
|
||||
UnknownCurvePoint {
|
||||
curve: String,
|
||||
point: Option<String>,
|
||||
},
|
||||
|
||||
#[error("I tripped over a malformed hexadecimal digits.")]
|
||||
#[diagnostic(help("{}", formatdoc! {
|
||||
r#"When numbers starts with '0x', they are treated as hexadecimal numbers. Thus, only digits from 0-9 or letter from a-f (or A-F) can be used following a '0x' number declaration. Plus, hexadecimal digits always go by pairs, so the total number of digits must be even (not counting leading zeros)."#
|
||||
|
@ -157,33 +269,55 @@ pub enum ErrorKind {
|
|||
}))]
|
||||
MalformedBase16StringLiteral,
|
||||
|
||||
#[error("I came across a bytearray declared using two different notations")]
|
||||
#[error("I came across a bytearray declared using two different notations.")]
|
||||
#[diagnostic(url("https://aiken-lang.org/language-tour/primitive-types#bytearray"))]
|
||||
#[diagnostic(help("Either use decimal or hexadecimal notation, but don't mix them."))]
|
||||
HybridNotationInByteArray,
|
||||
|
||||
#[error("I failed to understand a when clause guard.")]
|
||||
#[diagnostic(url("https://aiken-lang.org/language-tour/control-flow#checking-equality-and-ordering-in-patterns"))]
|
||||
#[error("I found a now-deprecated clause guard in a when/is expression.")]
|
||||
#[diagnostic(help("{}", formatdoc! {
|
||||
r#"Clause guards are not as capable as standard expressions. While you can combine multiple clauses using '{operator_or}' and '{operator_and}', you can't do any arithmetic in there. They are mainly meant to compare pattern variables to some known constants using simple binary operators.
|
||||
|
||||
For example, the following clauses are well-formed:
|
||||
|
||||
{good} (x, _) if x == 10 -> ...
|
||||
{good} (_, y) if y > 0 && y < 10 -> ...
|
||||
{good} (x, y) if x && (y > 0 || y < 10) -> ...
|
||||
|
||||
However, those aren't:
|
||||
|
||||
{bad} (x, _) if x % 3 == 0 -> ...
|
||||
{bad} (x, y) if x + y > 42 -> ...
|
||||
r#"Clause guards have been removed from Aiken. They were underused, considered potentially harmful and created needless complexity in the compiler. If you were using clause guards, our apologies, but you can now update your code and move the clause guards patterns inside a nested if/else expression.
|
||||
"#
|
||||
, operator_or = "||".if_supports_color(Stdout, |s| s.yellow())
|
||||
, operator_and = "&&".if_supports_color(Stdout, |s| s.yellow())
|
||||
, good = "✔️".if_supports_color(Stdout, |s| s.green())
|
||||
, bad = "✖️".if_supports_color(Stdout, |s| s.red())
|
||||
}))]
|
||||
InvalidWhenClause,
|
||||
DeprecatedWhenClause,
|
||||
|
||||
#[error("I choked on a curve point in a bytearray pattern.")]
|
||||
#[diagnostic(help(
|
||||
"You can pattern-match on bytearrays just fine, but not on G1 nor G2 elements. Use if/else with an equality if you have to compare those."
|
||||
))]
|
||||
PatternMatchOnCurvePoint,
|
||||
|
||||
#[error("I refuse to cooperate and match a utf-8 string.")]
|
||||
#[diagnostic(help(
|
||||
"You can pattern-match on bytearrays but not on strings. Note that I can parse utf-8 encoded bytearrays just fine, so you probably want to drop the extra '@' and only manipulate bytearrays wherever you need to. On-chain, strings shall be avoided as much as possible."
|
||||
))]
|
||||
PatternMatchOnString,
|
||||
}
|
||||
|
||||
fn fmt_curve_type(curve: &CurveType) -> String {
|
||||
match curve {
|
||||
CurveType::Bls12_381(point) => {
|
||||
format!("{point} point that is not in the bls12_381 curve")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn fmt_unknown_curve(curve: &String, point: &Option<String>) -> String {
|
||||
match point {
|
||||
Some(point) => {
|
||||
format!(
|
||||
"{} which is an unknown point for curve {}",
|
||||
point.if_supports_color(Stdout, |s| s.purple()),
|
||||
curve.if_supports_color(Stdout, |s| s.purple()),
|
||||
)
|
||||
}
|
||||
None => {
|
||||
format!(
|
||||
"{} which is an unknown curve",
|
||||
curve.if_supports_color(Stdout, |s| s.purple())
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash, Diagnostic, thiserror::Error)]
|
||||
|
@ -194,15 +328,6 @@ pub enum Pattern {
|
|||
#[error("I found an unexpected token '{0}'.")]
|
||||
#[diagnostic(help("Try removing it!"))]
|
||||
Token(Token),
|
||||
#[error("I found an unexpected literal value.")]
|
||||
#[diagnostic(help("Try removing it!"))]
|
||||
Literal,
|
||||
#[error("I found an unexpected type name.")]
|
||||
#[diagnostic(help("Try removing it!"))]
|
||||
TypeIdent,
|
||||
#[error("I found an unexpected identifier.")]
|
||||
#[diagnostic(help("Try removing it!"))]
|
||||
TermIdent,
|
||||
#[error("I found an unexpected end of input.")]
|
||||
End,
|
||||
#[error("I found a malformed list spread pattern.")]
|
||||
|
@ -211,11 +336,6 @@ pub enum Pattern {
|
|||
#[error("I found an out-of-bound byte literal.")]
|
||||
#[diagnostic(help("Bytes must be between 0-255."))]
|
||||
Byte,
|
||||
#[error("I found an unexpected pattern.")]
|
||||
#[diagnostic(help(
|
||||
"If no label is provided then only variables\nmatching a field name are allowed."
|
||||
))]
|
||||
RecordPunning,
|
||||
#[error("I found an unexpected label.")]
|
||||
#[diagnostic(help("You can only use labels surrounded by curly braces"))]
|
||||
Label,
|
||||
|
@ -224,11 +344,27 @@ pub enum Pattern {
|
|||
Discard,
|
||||
}
|
||||
|
||||
impl Pattern {
|
||||
fn to_aiken(&self) -> String {
|
||||
use Pattern::*;
|
||||
match self {
|
||||
Token(tok) => tok.to_string(),
|
||||
Char(c) => c.to_string(),
|
||||
End => "<END OF FILE>".to_string(),
|
||||
Match => "A pattern (a discard, a var, etc...)".to_string(),
|
||||
Byte => "A byte between [0; 255]".to_string(),
|
||||
Label => "A label".to_string(),
|
||||
Discard => "_".to_string(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<char> for Pattern {
|
||||
fn from(c: char) -> Self {
|
||||
Self::Char(c)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Token> for Pattern {
|
||||
fn from(tok: Token) -> Self {
|
||||
Self::Token(tok)
|
||||
|
|
|
@ -0,0 +1,72 @@
|
|||
use chumsky::prelude::*;
|
||||
|
||||
use crate::{
|
||||
ast::LogicalOpChainKind,
|
||||
expr::UntypedExpr,
|
||||
parser::{error::ParseError, token::Token},
|
||||
};
|
||||
|
||||
pub fn parser(
|
||||
expression: Recursive<'_, Token, UntypedExpr, ParseError>,
|
||||
) -> impl Parser<Token, UntypedExpr, Error = ParseError> + '_ {
|
||||
choice((
|
||||
just(Token::And).to(LogicalOpChainKind::And),
|
||||
just(Token::Or).to(LogicalOpChainKind::Or),
|
||||
))
|
||||
.then(
|
||||
expression
|
||||
.separated_by(just(Token::Comma))
|
||||
.allow_trailing()
|
||||
.delimited_by(just(Token::LeftBrace), just(Token::RightBrace)),
|
||||
)
|
||||
.map_with_span(|(kind, exprs), span| UntypedExpr::LogicalOpChain {
|
||||
kind,
|
||||
expressions: exprs,
|
||||
location: span,
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::assert_expr;
|
||||
|
||||
#[test]
|
||||
fn and_chain() {
|
||||
assert_expr!(
|
||||
r#"
|
||||
and {
|
||||
1 == 2,
|
||||
something,
|
||||
}
|
||||
"#
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn or_chain() {
|
||||
assert_expr!(
|
||||
r#"
|
||||
or {
|
||||
1 == 2,
|
||||
something,
|
||||
}
|
||||
"#
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn and_or_chain() {
|
||||
assert_expr!(
|
||||
r#"
|
||||
or {
|
||||
1 == 2,
|
||||
something,
|
||||
and {
|
||||
1 == 2,
|
||||
something,
|
||||
},
|
||||
}
|
||||
"#
|
||||
);
|
||||
}
|
||||
}
|
|
@ -1,10 +1,9 @@
|
|||
use chumsky::prelude::*;
|
||||
|
||||
use crate::{
|
||||
ast,
|
||||
expr::{FnStyle, UntypedExpr},
|
||||
parser::{error::ParseError, token::Token},
|
||||
};
|
||||
use chumsky::prelude::*;
|
||||
|
||||
pub fn parser() -> impl Parser<Token, UntypedExpr, Error = ParseError> {
|
||||
select! {
|
||||
|
@ -41,27 +40,27 @@ pub fn parser() -> impl Parser<Token, UntypedExpr, Error = ParseError> {
|
|||
};
|
||||
|
||||
let arguments = vec![
|
||||
ast::Arg {
|
||||
arg_name: ast::ArgName::Named {
|
||||
ast::UntypedArg {
|
||||
by: ast::ArgBy::ByName(ast::ArgName::Named {
|
||||
name: "left".to_string(),
|
||||
label: "left".to_string(),
|
||||
location,
|
||||
is_validator_param: false,
|
||||
},
|
||||
}),
|
||||
is_validator_param: false,
|
||||
annotation: arg_annotation.clone(),
|
||||
doc: None,
|
||||
location,
|
||||
tipo: (),
|
||||
},
|
||||
ast::Arg {
|
||||
arg_name: ast::ArgName::Named {
|
||||
ast::UntypedArg {
|
||||
by: ast::ArgBy::ByName(ast::ArgName::Named {
|
||||
name: "right".to_string(),
|
||||
label: "right".to_string(),
|
||||
location,
|
||||
is_validator_param: false,
|
||||
},
|
||||
}),
|
||||
is_validator_param: false,
|
||||
annotation: arg_annotation,
|
||||
doc: None,
|
||||
location,
|
||||
tipo: (),
|
||||
},
|
||||
];
|
||||
|
||||
|
|
|
@ -1,10 +1,9 @@
|
|||
use chumsky::prelude::*;
|
||||
|
||||
use crate::{
|
||||
ast,
|
||||
expr::{FnStyle, UntypedExpr},
|
||||
parser::{annotation, error::ParseError, token::Token},
|
||||
parser::{annotation, error::ParseError, pattern, token::Token},
|
||||
};
|
||||
use chumsky::prelude::*;
|
||||
|
||||
pub fn parser(
|
||||
sequence: Recursive<'_, Token, UntypedExpr, ParseError>,
|
||||
|
@ -33,25 +32,28 @@ pub fn params() -> impl Parser<Token, ast::UntypedArg, Error = ParseError> {
|
|||
// TODO: return a better error when a label is provided `UnexpectedLabel`
|
||||
choice((
|
||||
select! {Token::DiscardName {name} => name}.map_with_span(|name, span| {
|
||||
ast::ArgName::Discarded {
|
||||
ast::ArgBy::ByName(ast::ArgName::Discarded {
|
||||
label: name.clone(),
|
||||
name,
|
||||
location: span,
|
||||
}
|
||||
})
|
||||
}),
|
||||
select! {Token::Name {name} => name}.map_with_span(|name, span| ast::ArgName::Named {
|
||||
label: name.clone(),
|
||||
name,
|
||||
location: span,
|
||||
is_validator_param: false,
|
||||
select! {Token::Name {name} => name}.map_with_span(|name, span| {
|
||||
ast::ArgBy::ByName(ast::ArgName::Named {
|
||||
label: name.clone(),
|
||||
name,
|
||||
location: span,
|
||||
})
|
||||
}),
|
||||
pattern().map(ast::ArgBy::ByPattern),
|
||||
))
|
||||
.then(just(Token::Colon).ignore_then(annotation()).or_not())
|
||||
.map_with_span(|(arg_name, annotation), span| ast::Arg {
|
||||
.map_with_span(|(by, annotation), span| ast::UntypedArg {
|
||||
is_validator_param: false,
|
||||
location: span,
|
||||
annotation,
|
||||
tipo: (),
|
||||
arg_name,
|
||||
doc: None,
|
||||
by,
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -63,4 +65,19 @@ mod tests {
|
|||
fn anonymous_function_basic() {
|
||||
assert_expr!(r#"fn (a: Int) -> Int { a + 1 }"#);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn anonymous_function_by_pattern_no_annotation() {
|
||||
assert_expr!(r#"fn (Foo { my_field }) { my_field * 2 }"#);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn anonymous_function_by_pattern_with_annotation() {
|
||||
assert_expr!(r#"fn (Foo { my_field } : Foo) { my_field * 2 }"#);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn anonymous_function_by_pattern_with_alias() {
|
||||
assert_expr!(r#"fn (Foo { my_field, .. } as x) { my_field * my_other_field }"#);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,28 +1,52 @@
|
|||
use chumsky::prelude::*;
|
||||
|
||||
use crate::{
|
||||
ast,
|
||||
ast::{self, Span},
|
||||
expr::UntypedExpr,
|
||||
parser::{annotation, error::ParseError, pattern, token::Token},
|
||||
};
|
||||
use chumsky::prelude::*;
|
||||
|
||||
pub fn let_(
|
||||
r: Recursive<'_, Token, UntypedExpr, ParseError>,
|
||||
) -> impl Parser<Token, UntypedExpr, Error = ParseError> + '_ {
|
||||
just(Token::Let)
|
||||
.ignore_then(pattern())
|
||||
.then(just(Token::Colon).ignore_then(annotation()).or_not())
|
||||
.then_ignore(just(Token::Equal))
|
||||
.ignore_then(assignment_patterns())
|
||||
.then(choice((just(Token::Equal), just(Token::LArrow))))
|
||||
.then(r.clone())
|
||||
.map_with_span(
|
||||
move |((pattern, annotation), value), span| UntypedExpr::Assignment {
|
||||
.validate(move |((patterns, kind), value), span, emit| {
|
||||
if matches!(value, UntypedExpr::Assignment { .. }) {
|
||||
emit(ParseError::invalid_assignment_right_hand_side(span))
|
||||
}
|
||||
|
||||
let patterns = patterns
|
||||
.try_into()
|
||||
.expect("We use at_least(1) so this should never be empty");
|
||||
|
||||
UntypedExpr::Assignment {
|
||||
location: span,
|
||||
value: Box::new(value),
|
||||
pattern,
|
||||
kind: ast::AssignmentKind::Let,
|
||||
annotation,
|
||||
},
|
||||
)
|
||||
patterns,
|
||||
kind: ast::AssignmentKind::Let {
|
||||
backpassing: kind == Token::LArrow,
|
||||
},
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn assignment_patterns() -> impl Parser<Token, Vec<ast::AssignmentPattern>, Error = ParseError> {
|
||||
assignment_pattern()
|
||||
.separated_by(just(Token::Comma))
|
||||
.allow_trailing()
|
||||
.at_least(1)
|
||||
}
|
||||
|
||||
pub fn assignment_pattern() -> impl Parser<Token, ast::AssignmentPattern, Error = ParseError> {
|
||||
pattern()
|
||||
.then(just(Token::Colon).ignore_then(annotation()).or_not())
|
||||
.map_with_span(|(pattern, annotation), span| ast::AssignmentPattern {
|
||||
pattern,
|
||||
annotation,
|
||||
location: span,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn expect(
|
||||
|
@ -30,35 +54,37 @@ pub fn expect(
|
|||
) -> impl Parser<Token, UntypedExpr, Error = ParseError> + '_ {
|
||||
just(Token::Expect)
|
||||
.ignore_then(
|
||||
pattern()
|
||||
.then(just(Token::Colon).ignore_then(annotation()).or_not())
|
||||
.then_ignore(just(Token::Equal))
|
||||
assignment_patterns()
|
||||
.then(choice((just(Token::Equal), just(Token::LArrow))))
|
||||
.or_not(),
|
||||
)
|
||||
.then(r.clone())
|
||||
.map_with_span(move |(opt_pattern, value), span| {
|
||||
let (pattern, annotation) = opt_pattern.unwrap_or_else(|| {
|
||||
(
|
||||
ast::UntypedPattern::Constructor {
|
||||
is_record: false,
|
||||
location: span,
|
||||
name: "True".to_string(),
|
||||
arguments: vec![],
|
||||
module: None,
|
||||
constructor: (),
|
||||
with_spread: false,
|
||||
tipo: (),
|
||||
},
|
||||
.validate(move |(opt_pattern, value), span, emit| {
|
||||
if matches!(value, UntypedExpr::Assignment { .. }) {
|
||||
emit(ParseError::invalid_assignment_right_hand_side(span))
|
||||
}
|
||||
|
||||
let (patterns, kind) = opt_pattern.unwrap_or_else(|| {
|
||||
let filler_true = ast::AssignmentPattern::new(
|
||||
ast::UntypedPattern::true_(span),
|
||||
None,
|
||||
)
|
||||
Span::empty(),
|
||||
);
|
||||
|
||||
(vec![filler_true], Token::Equal)
|
||||
});
|
||||
|
||||
let patterns = patterns
|
||||
.try_into()
|
||||
.expect("We use at_least(1) so this should never be empty");
|
||||
|
||||
UntypedExpr::Assignment {
|
||||
location: span,
|
||||
patterns,
|
||||
value: Box::new(value),
|
||||
pattern,
|
||||
kind: ast::AssignmentKind::Expect,
|
||||
annotation,
|
||||
kind: ast::AssignmentKind::Expect {
|
||||
backpassing: kind == Token::LArrow,
|
||||
},
|
||||
}
|
||||
})
|
||||
}
|
||||
|
@ -86,4 +112,42 @@ mod tests {
|
|||
fn expect_trace_if_false() {
|
||||
assert_expr!("expect foo?");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn expect_unfinished_let() {
|
||||
assert_expr!(
|
||||
"
|
||||
let a =
|
||||
// foo
|
||||
let b = 42
|
||||
"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn expect_let_in_let() {
|
||||
assert_expr!("let a = { let b = 42 }");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn expect_let_in_let_return() {
|
||||
assert_expr!(
|
||||
"
|
||||
let a = {
|
||||
let b = 42
|
||||
b
|
||||
}
|
||||
"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn expect_let_in_let_parens() {
|
||||
assert_expr!("let a = ( let b = 42 )");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn expect_expect_let() {
|
||||
assert_expr!("expect { let a = 42 } = foo");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,6 +17,16 @@ pub fn parser(
|
|||
just(Token::RightParen),
|
||||
),
|
||||
))
|
||||
.map_with_span(|e, span| {
|
||||
if matches!(e, UntypedExpr::Assignment { .. }) {
|
||||
UntypedExpr::Sequence {
|
||||
location: span,
|
||||
expressions: vec![e],
|
||||
}
|
||||
} else {
|
||||
e
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
@ -24,15 +34,24 @@ mod tests {
|
|||
use crate::assert_expr;
|
||||
|
||||
#[test]
|
||||
fn block_basic() {
|
||||
fn block_let() {
|
||||
assert_expr!(
|
||||
r#"
|
||||
let b = {
|
||||
let x = 4
|
||||
|
||||
x + 5
|
||||
}
|
||||
"#
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn block_single() {
|
||||
assert_expr!(
|
||||
r#"{
|
||||
foo
|
||||
}
|
||||
"#
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,13 +1,43 @@
|
|||
use chumsky::prelude::*;
|
||||
use uplc::machine::runtime::Compressable;
|
||||
|
||||
use crate::parser::{error::ParseError, expr::UntypedExpr, literal::bytearray, token::Token};
|
||||
use crate::{
|
||||
ast,
|
||||
parser::{error::ParseError, expr::UntypedExpr, literal::bytearray, token::Token},
|
||||
};
|
||||
|
||||
pub fn parser() -> impl Parser<Token, UntypedExpr, Error = ParseError> {
|
||||
bytearray(|bytes, preferred_format, location| UntypedExpr::ByteArray {
|
||||
location,
|
||||
bytes,
|
||||
preferred_format,
|
||||
})
|
||||
bytearray(
|
||||
|bytes, preferred_format, curve, location, emit| match curve {
|
||||
Some(curve @ ast::CurveType::Bls12_381(point)) => {
|
||||
let point = match point {
|
||||
ast::Bls12_381PointType::G1 => {
|
||||
blst::blst_p1::uncompress(&bytes).map(ast::Bls12_381Point::G1)
|
||||
}
|
||||
ast::Bls12_381PointType::G2 => {
|
||||
blst::blst_p2::uncompress(&bytes).map(ast::Bls12_381Point::G2)
|
||||
}
|
||||
};
|
||||
|
||||
let point = point.unwrap_or_else(|_err| {
|
||||
emit(ParseError::point_not_on_curve(curve, location));
|
||||
|
||||
ast::Bls12_381Point::default()
|
||||
});
|
||||
|
||||
UntypedExpr::CurvePoint {
|
||||
location,
|
||||
point: ast::Curve::Bls12_381(point).into(),
|
||||
preferred_format,
|
||||
}
|
||||
}
|
||||
None => UntypedExpr::ByteArray {
|
||||
location,
|
||||
bytes,
|
||||
preferred_format,
|
||||
},
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
@ -28,4 +58,19 @@ mod tests {
|
|||
fn bytearray_utf8_encoded() {
|
||||
assert_expr!("\"aiken\"");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn bytearray_utf8_escaped() {
|
||||
assert_expr!("\"\\\"aiken\\\"\"");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn g1_element() {
|
||||
assert_expr!("#<Bls12_381, G1>\"950dfd33da2682260c76038dfb8bad6e84ae9d599a3c151815945ac1e6ef6b1027cd917f3907479d20d636ce437a41f5\"");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn g2_element() {
|
||||
assert_expr!("#<Bls12_381, G2>\"b0629fa1158c2d23a10413fe91d381a84d25e31d041cd0377d25828498fd02011b35893938ced97535395e4815201e67108bcd4665e0db25d602d76fa791fab706c54abf5e1a9e44b4ac1e6badf3d2ac0328f5e30be341677c8bac5dda7682f1\"");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,20 +1,11 @@
|
|||
use chumsky::prelude::*;
|
||||
|
||||
use super::anonymous_binop::parser as anonymous_binop;
|
||||
use super::anonymous_function::parser as anonymous_function;
|
||||
use super::assignment;
|
||||
use super::block::parser as block;
|
||||
use super::bytearray::parser as bytearray;
|
||||
use super::if_else::parser as if_else;
|
||||
use super::int::parser as int;
|
||||
use super::list::parser as list;
|
||||
use super::record::parser as record;
|
||||
use super::record_update::parser as record_update;
|
||||
use super::string::parser as string;
|
||||
use super::tuple::parser as tuple;
|
||||
use super::var::parser as var;
|
||||
use super::when::parser as when;
|
||||
|
||||
use super::{
|
||||
and_or_chain, anonymous_binop::parser as anonymous_binop,
|
||||
anonymous_function::parser as anonymous_function, assignment, block::parser as block,
|
||||
bytearray::parser as bytearray, if_else::parser as if_else, int::parser as int,
|
||||
list::parser as list, pair::parser as pair, record::parser as record,
|
||||
record_update::parser as record_update, string::parser as string, tuple::parser as tuple,
|
||||
var::parser as var, when::parser as when,
|
||||
};
|
||||
use crate::{
|
||||
expr::UntypedExpr,
|
||||
parser::{
|
||||
|
@ -23,6 +14,7 @@ use crate::{
|
|||
token::Token,
|
||||
},
|
||||
};
|
||||
use chumsky::prelude::*;
|
||||
|
||||
pub fn parser<'a>(
|
||||
sequence: Recursive<'a, Token, UntypedExpr, ParseError>,
|
||||
|
@ -33,6 +25,7 @@ pub fn parser<'a>(
|
|||
field_access::parser(),
|
||||
call(expression.clone()),
|
||||
));
|
||||
|
||||
chain_start(sequence, expression)
|
||||
.then(chain.repeated())
|
||||
.foldl(|expr, chain| match chain {
|
||||
|
@ -57,9 +50,11 @@ pub fn chain_start<'a>(
|
|||
choice((
|
||||
string(),
|
||||
int(),
|
||||
pair(expression.clone()),
|
||||
record_update(expression.clone()),
|
||||
record(expression.clone()),
|
||||
field_access::constructor(),
|
||||
and_or_chain(expression.clone()),
|
||||
var(),
|
||||
tuple(expression.clone()),
|
||||
bytearray(),
|
||||
|
|
|
@ -1,14 +1,13 @@
|
|||
use chumsky::prelude::*;
|
||||
|
||||
use crate::{
|
||||
ast::TraceKind,
|
||||
expr::UntypedExpr,
|
||||
parser::{
|
||||
error::ParseError,
|
||||
error::{ParseError, Pattern},
|
||||
expr::{string, when::clause},
|
||||
token::Token,
|
||||
},
|
||||
};
|
||||
use chumsky::prelude::*;
|
||||
|
||||
pub fn parser<'a>(
|
||||
expression: Recursive<'a, Token, UntypedExpr, ParseError>,
|
||||
|
@ -29,13 +28,36 @@ pub fn parser<'a>(
|
|||
.map_with_span(UntypedExpr::fail),
|
||||
just(Token::Trace)
|
||||
.ignore_then(choice((string::hybrid(), expression.clone())))
|
||||
.then(
|
||||
choice((just(Token::Colon), just(Token::Comma)))
|
||||
.then(
|
||||
choice((string::hybrid(), expression.clone()))
|
||||
.separated_by(just(Token::Comma)),
|
||||
)
|
||||
.validate(|(token, arguments), span, emit| {
|
||||
if token != Token::Colon {
|
||||
emit(ParseError::expected_but_got(
|
||||
Pattern::Token(Token::Colon),
|
||||
Pattern::Token(token),
|
||||
span.map(|start, _end| (start, start + 1)),
|
||||
))
|
||||
}
|
||||
|
||||
arguments
|
||||
})
|
||||
.or_not()
|
||||
.map(|opt| opt.unwrap_or_default()),
|
||||
)
|
||||
.then(sequence.clone().or_not())
|
||||
.map_with_span(|(text, then_), span| UntypedExpr::Trace {
|
||||
kind: TraceKind::Trace,
|
||||
location: span,
|
||||
then: Box::new(then_.unwrap_or_else(|| UntypedExpr::todo(None, span))),
|
||||
text: Box::new(text),
|
||||
}),
|
||||
.map_with_span(
|
||||
|((label, arguments), continuation), span| UntypedExpr::Trace {
|
||||
kind: TraceKind::Trace,
|
||||
location: span,
|
||||
then: Box::new(continuation.unwrap_or_else(|| UntypedExpr::todo(None, span))),
|
||||
label: Box::new(label),
|
||||
arguments,
|
||||
},
|
||||
),
|
||||
))
|
||||
}
|
||||
|
||||
|
@ -115,6 +137,26 @@ mod tests {
|
|||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn trace_string() {
|
||||
assert_expr!(
|
||||
r#"
|
||||
trace @"foo"
|
||||
a
|
||||
"#
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn trace_bytearray() {
|
||||
assert_expr!(
|
||||
r#"
|
||||
trace "foo"
|
||||
a
|
||||
"#
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn trace_expr() {
|
||||
assert_expr!(
|
||||
|
@ -129,7 +171,25 @@ mod tests {
|
|||
fn trace_expr_todo() {
|
||||
assert_expr!(
|
||||
r#"
|
||||
trace some_var
|
||||
trace some_var
|
||||
"#
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn trace_labelled() {
|
||||
assert_expr!(
|
||||
r#"
|
||||
trace foo: "bar"
|
||||
"#
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn trace_variadic() {
|
||||
assert_expr!(
|
||||
r#"
|
||||
trace "foo": @"bar", baz
|
||||
"#
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,41 +1,21 @@
|
|||
use chumsky::prelude::*;
|
||||
|
||||
use super::block;
|
||||
use crate::{
|
||||
ast,
|
||||
expr::UntypedExpr,
|
||||
parser::{error::ParseError, token::Token},
|
||||
parser::{annotation, error::ParseError, pattern, token::Token},
|
||||
};
|
||||
|
||||
use super::block;
|
||||
use chumsky::prelude::*;
|
||||
|
||||
pub fn parser<'a>(
|
||||
sequence: Recursive<'a, Token, UntypedExpr, ParseError>,
|
||||
expression: Recursive<'a, Token, UntypedExpr, ParseError>,
|
||||
) -> impl Parser<Token, UntypedExpr, Error = ParseError> + 'a {
|
||||
just(Token::If)
|
||||
.ignore_then(
|
||||
expression
|
||||
.clone()
|
||||
.then(block(sequence.clone()))
|
||||
.map_with_span(|(condition, body), span| ast::IfBranch {
|
||||
condition,
|
||||
body,
|
||||
location: span,
|
||||
}),
|
||||
)
|
||||
.ignore_then(if_branch(sequence.clone(), expression.clone()))
|
||||
.then(
|
||||
just(Token::Else)
|
||||
.ignore_then(just(Token::If))
|
||||
.ignore_then(
|
||||
expression
|
||||
.clone()
|
||||
.then(block(sequence.clone()))
|
||||
.map_with_span(|(condition, body), span| ast::IfBranch {
|
||||
condition,
|
||||
body,
|
||||
location: span,
|
||||
}),
|
||||
)
|
||||
.ignore_then(if_branch(sequence.clone(), expression))
|
||||
.repeated(),
|
||||
)
|
||||
.then_ignore(just(Token::Else))
|
||||
|
@ -53,6 +33,52 @@ pub fn parser<'a>(
|
|||
})
|
||||
}
|
||||
|
||||
fn if_branch<'a>(
|
||||
sequence: Recursive<'a, Token, UntypedExpr, ParseError>,
|
||||
expression: Recursive<'a, Token, UntypedExpr, ParseError>,
|
||||
) -> impl Parser<Token, ast::UntypedIfBranch, Error = ParseError> + 'a {
|
||||
expression
|
||||
.then(
|
||||
just(Token::Is)
|
||||
.ignore_then(
|
||||
pattern()
|
||||
.then_ignore(just(Token::Colon))
|
||||
.or_not()
|
||||
.then(annotation())
|
||||
.map_with_span(|(pattern, annotation), span| (pattern, annotation, span)),
|
||||
)
|
||||
.or_not(),
|
||||
)
|
||||
.then(block(sequence))
|
||||
.map_with_span(|((condition, is), body), span| {
|
||||
let is = is.map(|(pattern, annotation, is_span)| {
|
||||
let pattern = pattern.unwrap_or_else(|| match &condition {
|
||||
UntypedExpr::Var { name, location } => ast::Pattern::Var {
|
||||
name: name.clone(),
|
||||
location: *location,
|
||||
},
|
||||
_ => ast::Pattern::Discard {
|
||||
location: is_span,
|
||||
name: "_".to_string(),
|
||||
},
|
||||
});
|
||||
|
||||
ast::AssignmentPattern {
|
||||
pattern,
|
||||
annotation: Some(annotation),
|
||||
location: is_span,
|
||||
}
|
||||
});
|
||||
|
||||
ast::IfBranch {
|
||||
condition,
|
||||
body,
|
||||
is,
|
||||
location: span,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::assert_expr;
|
||||
|
@ -71,4 +97,64 @@ mod tests {
|
|||
"#
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn if_else_ambiguous_record() {
|
||||
assert_expr!(
|
||||
r#"
|
||||
if ec1 == Infinity {
|
||||
ec2
|
||||
} else if ec1 == Foo { foo } {
|
||||
ec1
|
||||
} else {
|
||||
Infinity
|
||||
}
|
||||
"#
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn if_else_with_soft_cast() {
|
||||
assert_expr!(
|
||||
r#"
|
||||
if ec1 is Some(x): Option<Int> {
|
||||
ec2
|
||||
} else if ec1 is Foo { foo }: Foo {
|
||||
ec1
|
||||
} else if ec1 is Option<Int> {
|
||||
let Some(x) = ec1
|
||||
|
||||
x
|
||||
} else {
|
||||
Infinity
|
||||
}
|
||||
"#
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn if_soft_cast_discard_assign() {
|
||||
assert_expr!(
|
||||
r#"
|
||||
if foo() is Foo {
|
||||
todo
|
||||
} else {
|
||||
todo
|
||||
}
|
||||
"#
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn if_soft_cast_not_var_condition() {
|
||||
assert_expr!(
|
||||
r#"
|
||||
if foo() is Foo { a }: Foo {
|
||||
todo
|
||||
} else {
|
||||
todo
|
||||
}
|
||||
"#
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
use chumsky::prelude::*;
|
||||
use vec1::Vec1;
|
||||
|
||||
mod and_or_chain;
|
||||
mod anonymous_binop;
|
||||
pub mod anonymous_function;
|
||||
pub mod assignment;
|
||||
|
@ -11,6 +12,7 @@ mod fail_todo_trace;
|
|||
mod if_else;
|
||||
mod int;
|
||||
mod list;
|
||||
mod pair;
|
||||
mod record;
|
||||
mod record_update;
|
||||
mod sequence;
|
||||
|
@ -19,6 +21,9 @@ mod tuple;
|
|||
mod var;
|
||||
pub mod when;
|
||||
|
||||
use super::{error::ParseError, token::Token};
|
||||
use crate::{ast, expr::UntypedExpr};
|
||||
pub use and_or_chain::parser as and_or_chain;
|
||||
pub use anonymous_function::parser as anonymous_function;
|
||||
pub use block::parser as block;
|
||||
pub use bytearray::parser as bytearray;
|
||||
|
@ -27,6 +32,7 @@ pub use fail_todo_trace::parser as fail_todo_trace;
|
|||
pub use if_else::parser as if_else;
|
||||
pub use int::parser as int;
|
||||
pub use list::parser as list;
|
||||
pub use pair::parser as pair;
|
||||
pub use record::parser as record;
|
||||
pub use record_update::parser as record_update;
|
||||
pub use sequence::parser as sequence;
|
||||
|
@ -35,9 +41,6 @@ pub use tuple::parser as tuple;
|
|||
pub use var::parser as var;
|
||||
pub use when::parser as when;
|
||||
|
||||
use super::{error::ParseError, token::Token};
|
||||
use crate::{ast, expr::UntypedExpr};
|
||||
|
||||
pub fn parser(
|
||||
sequence: Recursive<'_, Token, UntypedExpr, ParseError>,
|
||||
) -> impl Parser<Token, UntypedExpr, Error = ParseError> + '_ {
|
||||
|
@ -140,28 +143,62 @@ pub fn pure_expression<'a>(
|
|||
.boxed();
|
||||
|
||||
// Conjunction
|
||||
//
|
||||
// NOTE: This can be written in a nicer way with `foldl_with` in chumsky =^ 1.0.0.
|
||||
// DO NOT however try to write this as:
|
||||
//
|
||||
// comparison
|
||||
// .clone()
|
||||
// .then(op)
|
||||
// .repeated
|
||||
// .then(comparison)
|
||||
// .foldr(...)
|
||||
//
|
||||
// This has somehow incredibly slow performances in Chumsky. Hence the approach below.
|
||||
let op = just(Token::AmperAmper).to(ast::BinOp::And);
|
||||
let conjunction = comparison
|
||||
.clone()
|
||||
.map(|e| vec![e])
|
||||
.clone()
|
||||
.then(op.then(comparison).repeated())
|
||||
.foldl(|a, (op, b)| UntypedExpr::BinOp {
|
||||
location: a.location().union(b.location()),
|
||||
name: op,
|
||||
left: Box::new(a),
|
||||
right: Box::new(b),
|
||||
.foldl(|a, (_op, b)| {
|
||||
let mut tail = vec![b];
|
||||
tail.extend(a);
|
||||
tail
|
||||
})
|
||||
.map(|xs| {
|
||||
xs.into_iter()
|
||||
.reduce(|right, left| UntypedExpr::BinOp {
|
||||
location: left.location().union(right.location()),
|
||||
name: ast::BinOp::And,
|
||||
left: Box::new(left),
|
||||
right: Box::new(right),
|
||||
})
|
||||
.unwrap()
|
||||
})
|
||||
.boxed();
|
||||
|
||||
// NOTE: see comment about conjunctions just above.
|
||||
// Disjunction
|
||||
let op = just(Token::VbarVbar).to(ast::BinOp::Or);
|
||||
let disjunction = conjunction
|
||||
.clone()
|
||||
.map(|e| vec![e])
|
||||
.then(op.then(conjunction).repeated())
|
||||
.foldl(|a, (op, b)| UntypedExpr::BinOp {
|
||||
location: a.location().union(b.location()),
|
||||
name: op,
|
||||
left: Box::new(a),
|
||||
right: Box::new(b),
|
||||
.foldl(|a, (_op, b)| {
|
||||
let mut tail = vec![b];
|
||||
tail.extend(a);
|
||||
tail
|
||||
})
|
||||
.map(|xs| {
|
||||
xs.into_iter()
|
||||
.reduce(|right, left| UntypedExpr::BinOp {
|
||||
location: left.location().union(right.location()),
|
||||
name: ast::BinOp::Or,
|
||||
left: Box::new(left),
|
||||
right: Box::new(right),
|
||||
})
|
||||
.unwrap()
|
||||
})
|
||||
.boxed();
|
||||
|
||||
|
|
|
@ -0,0 +1,54 @@
|
|||
use crate::{
|
||||
ast::well_known,
|
||||
builtins::PRELUDE,
|
||||
expr::UntypedExpr,
|
||||
parser::{error::ParseError, token::Token},
|
||||
};
|
||||
use chumsky::prelude::*;
|
||||
|
||||
pub fn parser(
|
||||
r: Recursive<'_, Token, UntypedExpr, ParseError>,
|
||||
) -> impl Parser<Token, UntypedExpr, Error = ParseError> + '_ {
|
||||
select! {Token::Name { name } if name == PRELUDE => name}
|
||||
.then_ignore(just(Token::Dot))
|
||||
.or_not()
|
||||
.then_ignore(select! {Token::UpName { name } if name == well_known::PAIR => name})
|
||||
.ignore_then(
|
||||
r.clone()
|
||||
.separated_by(just(Token::Comma))
|
||||
.exactly(2)
|
||||
.allow_trailing()
|
||||
.delimited_by(
|
||||
choice((just(Token::LeftParen), just(Token::NewLineLeftParen))),
|
||||
just(Token::RightParen),
|
||||
)
|
||||
.map_with_span(|elems, location| UntypedExpr::Pair {
|
||||
location,
|
||||
fst: elems
|
||||
.first()
|
||||
.expect("Pair should have exactly 2 elements")
|
||||
.to_owned()
|
||||
.into(),
|
||||
snd: elems
|
||||
.last()
|
||||
.expect("Pair should have exactly 2 elements")
|
||||
.to_owned()
|
||||
.into(),
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::assert_expr;
|
||||
|
||||
#[test]
|
||||
fn basic_pair() {
|
||||
assert_expr!(r#"Pair(1, 2)"#);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn pair_from_prelude() {
|
||||
assert_expr!(r#"aiken.Pair(1, 2)"#);
|
||||
}
|
||||
}
|
|
@ -72,6 +72,38 @@ pub fn parser(
|
|||
},
|
||||
),
|
||||
))
|
||||
// NOTE: There's an ambiguity when the record shorthand syntax is used
|
||||
// from within an if-else statement in the case of single-variable if-branch.
|
||||
//
|
||||
// For example, imagine the following:
|
||||
//
|
||||
// ```
|
||||
// if season == Summer {
|
||||
// foo
|
||||
// } else {
|
||||
// bar
|
||||
// }
|
||||
// ```
|
||||
//
|
||||
// Without that next odd parser combinator, the parser would parse:
|
||||
//
|
||||
// ```
|
||||
// if season == Summer { foo }
|
||||
// else {
|
||||
// bar
|
||||
// }
|
||||
// ```
|
||||
//
|
||||
// And immediately choke on the next `else` because the if-branch body has
|
||||
// already been consumed and interpreted as a record definition. So the next
|
||||
// combinator ensures that we give priority back to an if-then statement rather
|
||||
// than to the record definition.
|
||||
.then_ignore(
|
||||
just(Token::RightBrace)
|
||||
.ignore_then(just(Token::Else))
|
||||
.not()
|
||||
.rewind(),
|
||||
)
|
||||
.map(|(value, name)| ast::CallArg {
|
||||
location: value.location(),
|
||||
value,
|
||||
|
@ -155,6 +187,11 @@ pub fn parser(
|
|||
mod tests {
|
||||
use crate::assert_expr;
|
||||
|
||||
#[test]
|
||||
fn record_enum() {
|
||||
assert_expr!(r#"Winter"#);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn record_create_labeled() {
|
||||
assert_expr!(r#"User { name: "Aiken", age, thing: 2 }"#);
|
||||
|
|
|
@ -1,9 +1,8 @@
|
|||
use chumsky::prelude::*;
|
||||
|
||||
use crate::{
|
||||
expr::UntypedExpr,
|
||||
parser::{error::ParseError, token::Token},
|
||||
};
|
||||
use chumsky::prelude::*;
|
||||
|
||||
pub fn parser() -> impl Parser<Token, UntypedExpr, Error = ParseError> {
|
||||
recursive(|sequence| {
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
---
|
||||
source: crates/aiken-lang/src/parser/expr/and_or_chain.rs
|
||||
description: "Code:\n\nand {\n 1 == 2,\n something,\n}\n"
|
||||
---
|
||||
LogicalOpChain {
|
||||
kind: And,
|
||||
expressions: [
|
||||
BinOp {
|
||||
location: 8..14,
|
||||
name: Eq,
|
||||
left: UInt {
|
||||
location: 8..9,
|
||||
value: "1",
|
||||
base: Decimal {
|
||||
numeric_underscore: false,
|
||||
},
|
||||
},
|
||||
right: UInt {
|
||||
location: 13..14,
|
||||
value: "2",
|
||||
base: Decimal {
|
||||
numeric_underscore: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
Var {
|
||||
location: 18..27,
|
||||
name: "something",
|
||||
},
|
||||
],
|
||||
location: 0..30,
|
||||
}
|
|
@ -0,0 +1,60 @@
|
|||
---
|
||||
source: crates/aiken-lang/src/parser/expr/and_or_chain.rs
|
||||
description: "Code:\n\nor {\n 1 == 2,\n something,\n and {\n 1 == 2,\n something,\n },\n}\n"
|
||||
---
|
||||
LogicalOpChain {
|
||||
kind: Or,
|
||||
expressions: [
|
||||
BinOp {
|
||||
location: 7..13,
|
||||
name: Eq,
|
||||
left: UInt {
|
||||
location: 7..8,
|
||||
value: "1",
|
||||
base: Decimal {
|
||||
numeric_underscore: false,
|
||||
},
|
||||
},
|
||||
right: UInt {
|
||||
location: 12..13,
|
||||
value: "2",
|
||||
base: Decimal {
|
||||
numeric_underscore: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
Var {
|
||||
location: 17..26,
|
||||
name: "something",
|
||||
},
|
||||
LogicalOpChain {
|
||||
kind: And,
|
||||
expressions: [
|
||||
BinOp {
|
||||
location: 40..46,
|
||||
name: Eq,
|
||||
left: UInt {
|
||||
location: 40..41,
|
||||
value: "1",
|
||||
base: Decimal {
|
||||
numeric_underscore: false,
|
||||
},
|
||||
},
|
||||
right: UInt {
|
||||
location: 45..46,
|
||||
value: "2",
|
||||
base: Decimal {
|
||||
numeric_underscore: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
Var {
|
||||
location: 52..61,
|
||||
name: "something",
|
||||
},
|
||||
],
|
||||
location: 30..66,
|
||||
},
|
||||
],
|
||||
location: 0..69,
|
||||
}
|
|
@ -6,13 +6,14 @@ Fn {
|
|||
location: 0..28,
|
||||
fn_style: Plain,
|
||||
arguments: [
|
||||
Arg {
|
||||
arg_name: Named {
|
||||
name: "a",
|
||||
label: "a",
|
||||
location: 4..5,
|
||||
is_validator_param: false,
|
||||
},
|
||||
UntypedArg {
|
||||
by: ByName(
|
||||
Named {
|
||||
name: "a",
|
||||
label: "a",
|
||||
location: 4..5,
|
||||
},
|
||||
),
|
||||
location: 4..10,
|
||||
annotation: Some(
|
||||
Constructor {
|
||||
|
@ -22,7 +23,8 @@ Fn {
|
|||
arguments: [],
|
||||
},
|
||||
),
|
||||
tipo: (),
|
||||
doc: None,
|
||||
is_validator_param: false,
|
||||
},
|
||||
],
|
||||
body: BinOp {
|
||||
|
|
55
crates/aiken-lang/src/parser/expr/snapshots/anonymous_function_by_pattern_no_annotation.snap
vendored
Normal file
55
crates/aiken-lang/src/parser/expr/snapshots/anonymous_function_by_pattern_no_annotation.snap
vendored
Normal file
|
@ -0,0 +1,55 @@
|
|||
---
|
||||
source: crates/aiken-lang/src/parser/expr/anonymous_function.rs
|
||||
description: "Code:\n\nfn (Foo { my_field }) { my_field * 2 }"
|
||||
---
|
||||
Fn {
|
||||
location: 0..38,
|
||||
fn_style: Plain,
|
||||
arguments: [
|
||||
UntypedArg {
|
||||
by: ByPattern(
|
||||
Constructor {
|
||||
is_record: true,
|
||||
location: 4..20,
|
||||
name: "Foo",
|
||||
arguments: [
|
||||
CallArg {
|
||||
label: Some(
|
||||
"my_field",
|
||||
),
|
||||
location: 10..18,
|
||||
value: Var {
|
||||
location: 10..18,
|
||||
name: "my_field",
|
||||
},
|
||||
},
|
||||
],
|
||||
module: None,
|
||||
constructor: (),
|
||||
spread_location: None,
|
||||
tipo: (),
|
||||
},
|
||||
),
|
||||
location: 4..20,
|
||||
annotation: None,
|
||||
doc: None,
|
||||
is_validator_param: false,
|
||||
},
|
||||
],
|
||||
body: BinOp {
|
||||
location: 24..36,
|
||||
name: MultInt,
|
||||
left: Var {
|
||||
location: 24..32,
|
||||
name: "my_field",
|
||||
},
|
||||
right: UInt {
|
||||
location: 35..36,
|
||||
value: "2",
|
||||
base: Decimal {
|
||||
numeric_underscore: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
return_annotation: None,
|
||||
}
|
58
crates/aiken-lang/src/parser/expr/snapshots/anonymous_function_by_pattern_with_alias.snap
vendored
Normal file
58
crates/aiken-lang/src/parser/expr/snapshots/anonymous_function_by_pattern_with_alias.snap
vendored
Normal file
|
@ -0,0 +1,58 @@
|
|||
---
|
||||
source: crates/aiken-lang/src/parser/expr/anonymous_function.rs
|
||||
description: "Code:\n\nfn (Foo { my_field, .. } as x) { my_field * my_other_field }"
|
||||
---
|
||||
Fn {
|
||||
location: 0..60,
|
||||
fn_style: Plain,
|
||||
arguments: [
|
||||
UntypedArg {
|
||||
by: ByPattern(
|
||||
Assign {
|
||||
name: "x",
|
||||
location: 4..29,
|
||||
pattern: Constructor {
|
||||
is_record: true,
|
||||
location: 4..24,
|
||||
name: "Foo",
|
||||
arguments: [
|
||||
CallArg {
|
||||
label: Some(
|
||||
"my_field",
|
||||
),
|
||||
location: 10..18,
|
||||
value: Var {
|
||||
location: 10..18,
|
||||
name: "my_field",
|
||||
},
|
||||
},
|
||||
],
|
||||
module: None,
|
||||
constructor: (),
|
||||
spread_location: Some(
|
||||
20..22,
|
||||
),
|
||||
tipo: (),
|
||||
},
|
||||
},
|
||||
),
|
||||
location: 4..29,
|
||||
annotation: None,
|
||||
doc: None,
|
||||
is_validator_param: false,
|
||||
},
|
||||
],
|
||||
body: BinOp {
|
||||
location: 33..58,
|
||||
name: MultInt,
|
||||
left: Var {
|
||||
location: 33..41,
|
||||
name: "my_field",
|
||||
},
|
||||
right: Var {
|
||||
location: 44..58,
|
||||
name: "my_other_field",
|
||||
},
|
||||
},
|
||||
return_annotation: None,
|
||||
}
|
62
crates/aiken-lang/src/parser/expr/snapshots/anonymous_function_by_pattern_with_annotation.snap
vendored
Normal file
62
crates/aiken-lang/src/parser/expr/snapshots/anonymous_function_by_pattern_with_annotation.snap
vendored
Normal file
|
@ -0,0 +1,62 @@
|
|||
---
|
||||
source: crates/aiken-lang/src/parser/expr/anonymous_function.rs
|
||||
description: "Code:\n\nfn (Foo { my_field } : Foo) { my_field * 2 }"
|
||||
---
|
||||
Fn {
|
||||
location: 0..44,
|
||||
fn_style: Plain,
|
||||
arguments: [
|
||||
UntypedArg {
|
||||
by: ByPattern(
|
||||
Constructor {
|
||||
is_record: true,
|
||||
location: 4..20,
|
||||
name: "Foo",
|
||||
arguments: [
|
||||
CallArg {
|
||||
label: Some(
|
||||
"my_field",
|
||||
),
|
||||
location: 10..18,
|
||||
value: Var {
|
||||
location: 10..18,
|
||||
name: "my_field",
|
||||
},
|
||||
},
|
||||
],
|
||||
module: None,
|
||||
constructor: (),
|
||||
spread_location: None,
|
||||
tipo: (),
|
||||
},
|
||||
),
|
||||
location: 4..26,
|
||||
annotation: Some(
|
||||
Constructor {
|
||||
location: 23..26,
|
||||
module: None,
|
||||
name: "Foo",
|
||||
arguments: [],
|
||||
},
|
||||
),
|
||||
doc: None,
|
||||
is_validator_param: false,
|
||||
},
|
||||
],
|
||||
body: BinOp {
|
||||
location: 30..42,
|
||||
name: MultInt,
|
||||
left: Var {
|
||||
location: 30..38,
|
||||
name: "my_field",
|
||||
},
|
||||
right: UInt {
|
||||
location: 41..42,
|
||||
value: "2",
|
||||
base: Decimal {
|
||||
numeric_underscore: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
return_annotation: None,
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
---
|
||||
source: crates/aiken-lang/src/parser/expr/pair.rs
|
||||
description: "Code:\n\nPair(1, 2)"
|
||||
---
|
||||
Pair {
|
||||
location: 4..10,
|
||||
fst: UInt {
|
||||
location: 5..6,
|
||||
value: "1",
|
||||
base: Decimal {
|
||||
numeric_underscore: false,
|
||||
},
|
||||
},
|
||||
snd: UInt {
|
||||
location: 8..9,
|
||||
value: "2",
|
||||
base: Decimal {
|
||||
numeric_underscore: false,
|
||||
},
|
||||
},
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue