mirror of
https://github.com/irmen/prog8.git
synced 2025-06-14 11:23:37 +00:00
Compare commits
3058 Commits
Author | SHA1 | Date | |
---|---|---|---|
c86c0912f8 | |||
268b0c9365 | |||
099fe280ba | |||
f786f60e9c | |||
f40e1eb1f2 | |||
8b9da65357 | |||
2cbbe0d48a | |||
b6e1fb3ba8 | |||
bdccffbb8e | |||
5a85474712 | |||
f50899c6fa | |||
4daa909f32 | |||
4555edf369 | |||
529ea5bf58 | |||
fe011de934 | |||
0653d430a7 | |||
a587f6e9a0 | |||
3850e1dbb5 | |||
91cde072e0 | |||
2ca4aed566 | |||
5071da6784 | |||
4c1e2f3110 | |||
2727a4dcb3 | |||
126d4c69e6 | |||
7657edcb7d | |||
580e786952 | |||
c0ae35b3a3 | |||
c3dc74788a | |||
379d241a0d | |||
1f49e8fe75 | |||
d70cfbb661 | |||
5482ac0302 | |||
131d5ceb4f | |||
512ddd1694 | |||
14a213bff9 | |||
d586846bc5 | |||
ef4efcb112 | |||
b01555d75e | |||
3804fba0f1 | |||
f93b7e3303 | |||
73baaeff1f | |||
7c79cdbd2f | |||
8ea032ed66 | |||
e7a0cb636c | |||
02f3f5d0f5 | |||
1e9bbd662b | |||
8644a4ae91 | |||
1e85f7812f | |||
80d88b3c61 | |||
d2827a7431 | |||
28c721fa7d | |||
8f799567cf | |||
9e8cc8b54d | |||
cc59069876 | |||
697d54e10a | |||
1679ca79b4 | |||
124ec77b58 | |||
3675d7961b | |||
f8aaa2d13c | |||
b7afda781a | |||
535ec13072 | |||
26d0a174db | |||
b2e821755c | |||
2e303041c1 | |||
96bed8f57f | |||
86d4a4309f | |||
1a1ab0dac6 | |||
ba8c3d14f7 | |||
617ea15c3a | |||
ef192a5778 | |||
565973c520 | |||
25b1043572 | |||
1ebfff7c7b | |||
8341f9c066 | |||
28cac291de | |||
8fa14a10e2 | |||
55dbd095ed | |||
31ad8bdd8d | |||
181f3e9eb1 | |||
50c3d809dc | |||
58f696d00a | |||
f603c543d3 | |||
6aaa0f928e | |||
feb8aa435e | |||
310e8f15cd | |||
da03941582 | |||
dcbb36a3bd | |||
53558f5c1d | |||
189399d5f8 | |||
5406a992f5 | |||
bc9683cc54 | |||
2eed75f602 | |||
d58f9f56c4 | |||
2e35f3c3a3 | |||
5c6bd9c091 | |||
857d2eefca | |||
90f1e7fd6a | |||
18e37accf9 | |||
cc53d698bf | |||
cb86206698 | |||
d77b1944fb | |||
a58cb43c4a | |||
88574c87c4 | |||
3a7a7091c0 | |||
906b137a7c | |||
42e2c5f605 | |||
cc13a51493 | |||
f569ce6141 | |||
4958463e75 | |||
2360625927 | |||
8badc40883 | |||
844c97930f | |||
5c09dc10ae | |||
9fd9e9ab5f | |||
35c477b5a6 | |||
ae0cadb383 | |||
984230e8fa | |||
a874aec6a1 | |||
ea1daa97d3 | |||
fb0d9b46b0 | |||
9da70bdf05 | |||
d640cfbe13 | |||
51a05ec4b7 | |||
1f5706bbeb | |||
25c9b2fea4 | |||
154f9b300f | |||
d78ce77536 | |||
b4fb43bc80 | |||
e0e01f794e | |||
08865dbb4e | |||
b9ad7e0e55 | |||
07158a6f1a | |||
957c42bc1d | |||
f784da2da6 | |||
c080fbe59a | |||
d70b8303b1 | |||
1d38c3582a | |||
9438e996d7 | |||
3b4a5e27f7 | |||
648d9fc269 | |||
54fccec7d7 | |||
4f9693055e | |||
555c50ee10 | |||
bf98ceca2c | |||
573cecb087 | |||
1b528491c2 | |||
4bdabe1961 | |||
a3fa527378 | |||
84f5ffa426 | |||
25d2b42283 | |||
300d1a871c | |||
2fcb83a39f | |||
3ba1d00a7c | |||
64164c1c72 | |||
3ee6058524 | |||
93a0a41e73 | |||
e7ab7b6d7a | |||
7d4dc3c063 | |||
a50400b7d1 | |||
f89f1a84d0 | |||
688dce6145 | |||
b88f550c5b | |||
9864abd393 | |||
c702c4a6df | |||
77e376f6bf | |||
491e5dbcfb | |||
a5c7393561 | |||
7fd3e9bb7d | |||
459e9f8f3b | |||
5b1143bcb3 | |||
fddd390d31 | |||
e514eeba17 | |||
c11a52b278 | |||
85e87dfe2e | |||
cb47e2c149 | |||
0fc9aa6b2d | |||
155896c4c7 | |||
178e60bba0 | |||
9f84aa5fb2 | |||
66fc109ce5 | |||
a231872821 | |||
7cfb33a448 | |||
3b798097b9 | |||
6fb05bdefc | |||
64ea72ed4d | |||
89425088ce | |||
925b9d845d | |||
ad074076c2 | |||
a2194c43a6 | |||
4b23b1dc86 | |||
9005c7994a | |||
4a47e15b1c | |||
09cbdf410a | |||
df6a43c7f0 | |||
4ce130dc8b | |||
94d76aa82c | |||
73609636c5 | |||
66b06d6c40 | |||
eeeb8d81f4 | |||
6f727aff88 | |||
518e5a30c2 | |||
bbba4b3d60 | |||
967adb9a87 | |||
040a6c62de | |||
483d193ced | |||
62458216c9 | |||
76b05cb5fd | |||
570b574b93 | |||
a82f211f9a | |||
504c80cddf | |||
4b4af9b527 | |||
28b383f888 | |||
40ce7725a1 | |||
1f2d46628e | |||
c9535049c8 | |||
9317cf8a35 | |||
1cd754f05d | |||
97b8cb748d | |||
84d9040b57 | |||
fdd18c615c | |||
c14f6cfc2b | |||
326eab3dd1 | |||
6da1f7eb4c | |||
1e82483152 | |||
6e2fd41a8b | |||
9927af1095 | |||
7585b6ef6f | |||
a6159702da | |||
0247fb0d84 | |||
6de760885f | |||
9851d14fb9 | |||
d5fc69d3e4 | |||
a40d120f2a | |||
fcdd9414d9 | |||
272a1001a8 | |||
2a52241f1c | |||
d8f1822c12 | |||
ce7d094adb | |||
a0cf1889a3 | |||
38ef394e15 | |||
abbf7c7cb0 | |||
ca5f7ae32f | |||
cbc4b75e50 | |||
65ddcf91d0 | |||
5280e1b449 | |||
b6ffb81909 | |||
e9edffa9f0 | |||
0dd1c17ff4 | |||
aef211e5f3 | |||
66829203d8 | |||
7a0eaf3148 | |||
fa5479ee5f | |||
03412cacba | |||
01a38a0b11 | |||
f43c14bd78 | |||
fb23452383 | |||
ab7dde1450 | |||
8d9bc2f5ff | |||
7651ccc84e | |||
1a6b95b388 | |||
78ec1e7512 | |||
7e38d26c33 | |||
ed09dd4e9e | |||
5731b79554 | |||
eaa22a9d13 | |||
b2bdfe8482 | |||
fea531be9a | |||
7c69d38588 | |||
a088ee56b0 | |||
ae669af904 | |||
d1ddf05e38 | |||
51279a98b3 | |||
bf33a4f82d | |||
fff0d741c3 | |||
e83d0ee820 | |||
09f3eecf56 | |||
2bd4326ff6 | |||
c13168b60c | |||
ea3871d0c4 | |||
70a2b11271 | |||
3cf39e072e | |||
413b86cc4a | |||
a6107fcfdf | |||
a064ade1e0 | |||
df35aa7942 | |||
cd49c5f88d | |||
1541ad2160 | |||
c78b7b1a24 | |||
9c7a645e18 | |||
4acf38031a | |||
4cd7271e30 | |||
3f630ab1b0 | |||
04cb684fd4 | |||
4c843571ea | |||
1326498802 | |||
b7ebd8c4a6 | |||
24e0a69480 | |||
4bcb2bdede | |||
d27f3eb8a4 | |||
d3e4481112 | |||
1d1d6b3d98 | |||
90b8a22a71 | |||
8dbfb8ab76 | |||
e29ff1c848 | |||
585f6ffc9b | |||
46b94c17d6 | |||
7af8007447 | |||
16a2b2f566 | |||
ea2a90c3c5 | |||
5cda750e5e | |||
4e143d45c8 | |||
4c50980d81 | |||
2954f5f04d | |||
cac4c1eb1e | |||
0b1f30d98c | |||
c7b1e8d772 | |||
a4f7512d44 | |||
0d3ad80659 | |||
aba1a73e28 | |||
dca31b2ca3 | |||
0cb378ca31 | |||
cf551d2cc7 | |||
ac0c8a68f6 | |||
5986dcdd2f | |||
6be6eb2227 | |||
d34015eec5 | |||
255c5bfaca | |||
01c6754928 | |||
8eaf884f69 | |||
699a2bb7ab | |||
4a2dcd20d1 | |||
4e98fb75d6 | |||
64e66e732f | |||
7aec627f6b | |||
59a2fec176 | |||
edc5a5a94f | |||
c5b7edad82 | |||
124ffac4e4 | |||
6d2a36fb2b | |||
28b43b3e1d | |||
f7feaf158d | |||
2396f707c6 | |||
d4d8e1b1ba | |||
44fec2c729 | |||
a80a6913e3 | |||
0eac04c220 | |||
29dd758302 | |||
5c45adc7f0 | |||
ad22cf08cd | |||
2c2ae64194 | |||
97c2dadd16 | |||
b36e1e3baf | |||
2da35fec17 | |||
bdeac74cfc | |||
6516d7cb15 | |||
31cf76042d | |||
c4c4dcf2b3 | |||
03145630f8 | |||
e2fcac322f | |||
beaff4d650 | |||
79af96ddde | |||
e439720c9d | |||
48d0185ea4 | |||
e2592b4e0b | |||
2967866e3d | |||
b566ea5c3f | |||
8f6eaeac2c | |||
b4facaeb3c | |||
d12b7ccc6b | |||
453e8bd0a0 | |||
9204d390ae | |||
b70ce0015c | |||
d113827753 | |||
c67f877857 | |||
0ec719e429 | |||
17f7b11148 | |||
966b017670 | |||
4c98070b3c | |||
3681d6ee1c | |||
0af17cdc33 | |||
2aae1f5e30 | |||
d18f2a7bfd | |||
9046fe8d3a | |||
78c7ee247a | |||
d5adb85e5b | |||
69f953fd9b | |||
484677b4b1 | |||
b10a8e728f | |||
25f25a8767 | |||
0c053e4a2c | |||
3f6521cc9b | |||
a074491d5b | |||
a291164953 | |||
43c55b58d2 | |||
e7298f8162 | |||
ddf990296b | |||
ead8aa7800 | |||
7a9dd1ac9b | |||
1c97c22eff | |||
bbf621a8c4 | |||
8efa89165c | |||
4f8aaf9244 | |||
a97edef380 | |||
eefae24aa3 | |||
54bffc91ae | |||
63f5ef9e14 | |||
034f27a8dd | |||
c2f6311367 | |||
6f00a48772 | |||
b3dba67405 | |||
c9a4235669 | |||
ae0d52274c | |||
8973763866 | |||
3d799ae7fe | |||
8b10115390 | |||
d2e010c439 | |||
15867ab423 | |||
22c9e99fa3 | |||
ee262f6aad | |||
af64af2397 | |||
1feead2260 | |||
d3dcd24b4d | |||
fd1e6796ef | |||
3ea0f0cbaa | |||
f3e3311598 | |||
0dc50a93a4 | |||
fda8e61be4 | |||
ac1d4b4a7a | |||
c719e274d5 | |||
e4990f8ec5 | |||
62afd3342e | |||
6e8a89e6f1 | |||
aa2437cfb8 | |||
4a710ecdfc | |||
3ef5bdfeda | |||
7915dda35f | |||
9120e16683 | |||
a1ebc7090d | |||
054b4636e0 | |||
e3e7b060b7 | |||
5ac9c75521 | |||
07710e0995 | |||
d6a67f5f2b | |||
2675623aea | |||
94263c43d0 | |||
d8ec03874f | |||
a7247f5b8b | |||
4d37581694 | |||
5d7ddebcad | |||
53df0eb707 | |||
8babad9c7c | |||
8db7aa07bd | |||
42f4b06ac8 | |||
f4b50368ba | |||
db80417bd7 | |||
7a6f2ecc8c | |||
f5d556a7f9 | |||
2aae46d632 | |||
19ebc6d6b3 | |||
f88c29e083 | |||
6ed9899dc7 | |||
9de7698a5c | |||
112d2d6058 | |||
ddb8346711 | |||
8dd3faf395 | |||
35f3e8708b | |||
cfe3fcc9e7 | |||
66a6659a6e | |||
88ae3daa42 | |||
08b8fe01ab | |||
731132d4b3 | |||
98acff802f | |||
5f11f485a2 | |||
34f3169dda | |||
a3ef8f814b | |||
385dd6fc23 | |||
9af4168ae2 | |||
a5e0e31b74 | |||
b385dc8c26 | |||
92c012b55a | |||
641f6c05d8 | |||
788f6b44a6 | |||
63a4525f06 | |||
3e34a3ef72 | |||
0c5e8ca199 | |||
ff23fb0086 | |||
56f41d5e34 | |||
4700a239b9 | |||
bd5abfb969 | |||
b93fa75377 | |||
681ce9c60c | |||
dd0f0fe415 | |||
119040fc50 | |||
551e5688da | |||
56c1035581 | |||
ba1e907c79 | |||
2a3a27c56d | |||
647af34f5b | |||
993be6394e | |||
9a27505315 | |||
2e37f5dee3 | |||
03e486c082 | |||
edc83305a4 | |||
66e7c51064 | |||
60244aaf16 | |||
443391c700 | |||
47dbafacd4 | |||
5b6811d073 | |||
7516116bb7 | |||
e6014ea4dd | |||
362abfe284 | |||
ad4880997a | |||
592becc126 | |||
c38765301e | |||
5f27426f59 | |||
d924f8bff8 | |||
d14c61b160 | |||
fe2b67998c | |||
04df3c9f7f | |||
de3d0b40dc | |||
4db4a5f1b2 | |||
5a0524ff4d | |||
5b7801eea1 | |||
fbe231793b | |||
6a9269111e | |||
a94cfd34f5 | |||
28eae5a0fd | |||
1818738fc8 | |||
7e1e7a0780 | |||
1fc79ff6dd | |||
3535c1acda | |||
33c8caac8f | |||
51d708bbdd | |||
a5a918df84 | |||
820541e427 | |||
e63a8f0c01 | |||
c11a9b8709 | |||
80f39e8097 | |||
2a8b65e29c | |||
4bdf50145e | |||
3a9919a377 | |||
eef8ae00b8 | |||
ed15fac691 | |||
f739e679e4 | |||
fc0fae8caf | |||
f46896fd74 | |||
52649a8e4f | |||
bdfb01f6a0 | |||
1137e57393 | |||
267ea13e8c | |||
04f7b772a3 | |||
42c7569791 | |||
6d29b00a80 | |||
9f1bd2d7d6 | |||
9826d7c494 | |||
c6bf57b390 | |||
bfcf07c1a2 | |||
4d7e96d423 | |||
449461e412 | |||
607275ec66 | |||
e55cde2a81 | |||
84afb374e6 | |||
da1620807f | |||
f39ef8f565 | |||
fe8b6e820c | |||
f29d24e96a | |||
620ffe54ec | |||
ceaa4cd07d | |||
af17f903ee | |||
c532e28841 | |||
dba0846866 | |||
bed629998a | |||
bc2ede76bf | |||
2a1fec2ed2 | |||
004048e5a7 | |||
b941d6f1e4 | |||
37b346740b | |||
f5e332daf7 | |||
fe9a9fc5cb | |||
cc57477b99 | |||
a1574a7187 | |||
a5110b1f96 | |||
006713fe13 | |||
7868e672e0 | |||
e1a133c2c0 | |||
c77cd0da39 | |||
577333f2c4 | |||
7d8cdcbfea | |||
c5c4c6f111 | |||
73be754680 | |||
acd841dbb6 | |||
6b52ba9397 | |||
10d12f73d6 | |||
cd9119655c | |||
41afeccd51 | |||
6b87cbb703 | |||
32afcbfe42 | |||
bc2b38daf4 | |||
f40b7b62bb | |||
1ca3f64bf0 | |||
92527b4c1d | |||
c48012c385 | |||
a282b17286 | |||
58d9463f16 | |||
047decd552 | |||
82e0877e64 | |||
040d75dafa | |||
4e1686f6e3 | |||
b5e691f367 | |||
325f55f22d | |||
9724f2db7d | |||
5f20f321f0 | |||
d4b087ea3f | |||
8ff10724d1 | |||
1581381467 | |||
96b5a30f60 | |||
0e17a0474a | |||
b27368175d | |||
aba36f7c92 | |||
a3fa946300 | |||
01bbc2234e | |||
58e1864144 | |||
88458f5355 | |||
a4f697bae1 | |||
8201408f16 | |||
8b8caa1c2e | |||
4dc50cb551 | |||
5522a305ab | |||
d7f72056fc | |||
64c9c9b7fe | |||
98e1c843e4 | |||
906d9d858c | |||
16c1309df1 | |||
6eacf1bddd | |||
6c8c8e11cc | |||
e941d2665a | |||
68669dbef0 | |||
6a48de9a9f | |||
9d6d98930b | |||
3cc858db12 | |||
386a391fd9 | |||
d33aed4ed5 | |||
73ec8c31ad | |||
24944ad49e | |||
26ed231f61 | |||
8485b8429f | |||
358215e4dd | |||
f874942075 | |||
2cadb546d5 | |||
344a1b9eb8 | |||
3c77f8a020 | |||
8e00408e3e | |||
abcdfd8e28 | |||
b0f5b6925d | |||
ef79d0c43e | |||
78b4288005 | |||
680f5d21ee | |||
c71aa0895f | |||
9f8e61789a | |||
932035cdc5 | |||
ef198f1493 | |||
48ef856c0b | |||
9aea2b22c4 | |||
e0055bc431 | |||
9553248ed6 | |||
39d2194d8f | |||
0800033b47 | |||
64d8943b7d | |||
444e97b00b | |||
1816bda7ea | |||
d4a2031c07 | |||
8cf0b6cf51 | |||
f2010bf7a5 | |||
8f56a7fe69 | |||
64c132ee0a | |||
84a7e86fe3 | |||
a8c09d6144 | |||
87c46ba730 | |||
0f83dc6491 | |||
cc22861719 | |||
a14c192ea3 | |||
b3d98be862 | |||
43027a4728 | |||
03831a7394 | |||
fdbbd181ea | |||
69075376dc | |||
504d1440cc | |||
9e33b8b8da | |||
0cfcc5cd29 | |||
e0de662f8e | |||
66a836d094 | |||
80095f4962 | |||
828d83dbef | |||
7de665d1e4 | |||
0a356ba73a | |||
41de8caa13 | |||
968609d06d | |||
3b199a2a87 | |||
0c1018ec61 | |||
bc3f2db3de | |||
06bedb7adb | |||
45a9751217 | |||
e8da62aa29 | |||
ddb2ff4216 | |||
f27e3478b9 | |||
38dc7fb7bd | |||
aa4cd13c31 | |||
4a4b6c04a1 | |||
37fa3b34a2 | |||
f8084e7955 | |||
4d5119ce3e | |||
d85c347a6c | |||
7dd758a753 | |||
806654fc44 | |||
8e6b91cb9e | |||
334e6dca28 | |||
f2daa17b92 | |||
6d9fccacb1 | |||
37638e7ed0 | |||
8a0e650511 | |||
8ba5a0d90c | |||
bfd3edb617 | |||
56ba24962c | |||
19a2110ba2 | |||
242a3eec63 | |||
fee46f2e54 | |||
6aed7e429a | |||
517ea82b99 | |||
99c29343de | |||
892fa76883 | |||
d446b57d05 | |||
0e086d788b | |||
498841d45d | |||
d1f8ee1e56 | |||
07feb5c925 | |||
75fd263e85 | |||
1e1f444cab | |||
89cc7e5fa9 | |||
265e7aefbf | |||
1c55a6c6dc | |||
8f18b5b8a7 | |||
f790182f0b | |||
813007a5d8 | |||
d03ff1e4d0 | |||
932bbd0381 | |||
01bd648cb2 | |||
779a5606a7 | |||
ccc11e49d2 | |||
d28c994ecd | |||
5d88717f32 | |||
e35cfd4971 | |||
bcc4bf5c2b | |||
a0594cbce3 | |||
078bfefe41 | |||
9c1b11d605 | |||
44d82f9190 | |||
37fcde30d6 | |||
09c6cb4d6b | |||
b428343c2a | |||
dfce292294 | |||
2b8f613a00 | |||
2eb137618e | |||
4bb2b8ca9b | |||
5179562fb2 | |||
0a4de45453 | |||
ffdc658dc8 | |||
7530f4407b | |||
73864c8101 | |||
f948917124 | |||
0d44492086 | |||
38a22fbc99 | |||
8ae435549d | |||
9b113c0cbb | |||
0e0fac8c4b | |||
4cd9bb8f99 | |||
ad9eaeafeb | |||
6cd392909c | |||
49ec430592 | |||
09f3fbeb38 | |||
e7698686fa | |||
66d939df0d | |||
6bc079c7b7 | |||
299419917e | |||
69f6afe420 | |||
b7279a3d9e | |||
e14b854d7b | |||
8bd7c601c0 | |||
997288fa03 | |||
0f26b39997 | |||
ae66fcac1e | |||
43944a94eb | |||
eba0bde6f3 | |||
4544af441b | |||
a8be94de6b | |||
b24df31c2b | |||
332ba8ed7e | |||
58400f53bc | |||
01c2112881 | |||
a546c2247d | |||
0da9142009 | |||
796add0ee2 | |||
00b32f64e6 | |||
f97b3f23e2 | |||
08a079a96e | |||
e98e951834 | |||
2668bf8519 | |||
dd4c073e18 | |||
c7c72f00c7 | |||
ef1c665b9a | |||
d56565be25 | |||
e076b3aedc | |||
ae3b2ddf5f | |||
1bdc427d73 | |||
6a639ce533 | |||
d91ca8b197 | |||
a01c0a283d | |||
5c393091a0 | |||
01b680504b | |||
8e4319cd5a | |||
5a776dd690 | |||
cce08d95db | |||
28c1b208c1 | |||
3844bf1f72 | |||
745d192563 | |||
ee782e92ac | |||
afbc91d1fc | |||
f998888d6d | |||
7d8b42d63e | |||
6ebd4e821f | |||
d1806bfdc3 | |||
1d2d7155da | |||
b09e0a05bf | |||
c609e982fe | |||
2b227b43fe | |||
48f09f71ab | |||
ead8c59bda | |||
db52a9466c | |||
1509de390e | |||
88a1aa4f3d | |||
172e78e8f2 | |||
36bfef567d | |||
e40ebd75a2 | |||
992732f2cb | |||
b58a3ba1bb | |||
afe521b0c9 | |||
5d9caef45f | |||
278e2f5605 | |||
1e299bf360 | |||
8dfa0bc38c | |||
fde136fb7b | |||
ee4da1a757 | |||
ae2d96c455 | |||
6d8fbe0877 | |||
2fa1d8f2e8 | |||
533090a68e | |||
1dff59e1d6 | |||
44d232f52a | |||
5f6cff739a | |||
2764d235a9 | |||
45debff89f | |||
c45fbe6310 | |||
9ef9c24388 | |||
6a40f23578 | |||
6a0a6b4751 | |||
0bee6f6b41 | |||
82a15b5a16 | |||
11b7c4459e | |||
98570ac456 | |||
1b2296ad5b | |||
16851746d6 | |||
935450a45f | |||
ba67fd318b | |||
08ac459a41 | |||
a83e9d9a0a | |||
62d3f01948 | |||
af5ca2d0b8 | |||
ab4bcdf12d | |||
a6756d2cea | |||
f81061dd42 | |||
8e2c304b3c | |||
f21adaa3ef | |||
2637939e62 | |||
faf05582f8 | |||
161c02ced3 | |||
ff8de8e42d | |||
09d506194f | |||
42db3085df | |||
ad14c88fde | |||
0c9daf6eaf | |||
86c6530e46 | |||
159f80d629 | |||
aa949165c7 | |||
d22359b6e7 | |||
d73709653d | |||
405926e811 | |||
36758f41a4 | |||
7ebc9c79cf | |||
e0668b55b9 | |||
76c09da961 | |||
7e3b8c2c59 | |||
ecca854c7c | |||
3b0d7ea960 | |||
f70fa42eac | |||
5698de6cf4 | |||
c5a333a904 | |||
ff324955dd | |||
70436f5dca | |||
31177a2b1b | |||
4de012fc49 | |||
ee2888e744 | |||
efe4df92dc | |||
723ab54f97 | |||
d9389afc66 | |||
e7178ee496 | |||
d5f35bb3fb | |||
72f1a779f2 | |||
3277544295 | |||
98d2c64d5d | |||
f68b46fc60 | |||
d54ab856e7 | |||
16b24fadea | |||
b3803cbdf1 | |||
2ceaa25181 | |||
513611c5a6 | |||
7ec4ba40ad | |||
92374e122b | |||
94f12732ab | |||
0904712a00 | |||
32becdbced | |||
34aa21f7d9 | |||
cc81dd7d3e | |||
335213b55f | |||
13ab4166c0 | |||
3dc5a0e7f8 | |||
e15c5cde53 | |||
d88c09b098 | |||
893b383bdf | |||
dd7c9d62e6 | |||
97c5c90eff | |||
1fb94e7a7b | |||
daca87c6d0 | |||
203ec5fa46 | |||
9ea69c07b8 | |||
68539d6cc9 | |||
f75fd0811e | |||
836bc9d456 | |||
a37769aafe | |||
68e62e4bd2 | |||
a5cd3728c9 | |||
a48ce35f0b | |||
e1835b5775 | |||
433832b329 | |||
ee81da14d6 | |||
6395d1908e | |||
989a5a2f8a | |||
b7a622c68e | |||
a8507b437d | |||
e505bf9ccf | |||
a289b32053 | |||
c3f1f09ad1 | |||
70ee2026ff | |||
690782bf60 | |||
755cc4835e | |||
a684ea46e4 | |||
8fbe13f99d | |||
452e9e275f | |||
cd40088636 | |||
9b9e6f4af5 | |||
ae6eeadf54 | |||
5268b05060 | |||
390263a34e | |||
55646edc3e | |||
8d177beb78 | |||
1da0c59182 | |||
36e8f10d2b | |||
cdf5a8f20f | |||
eb64d92333 | |||
eb55da63ef | |||
918302f79b | |||
9d7131d9f6 | |||
229c1114dd | |||
885df9156f | |||
c319233ddc | |||
958b5c0780 | |||
880c0a5da8 | |||
237c6dc856 | |||
ccf6e32bf9 | |||
a1874f6f00 | |||
95e4490a8a | |||
31c132c2eb | |||
00b0ec58b4 | |||
a1d0e5bb65 | |||
03e0d4b2e8 | |||
6afdd4e6fd | |||
b500a0d477 | |||
dd2463a440 | |||
23a8bebd9e | |||
3caf9108ad | |||
bde4be8231 | |||
0bbbb12ed2 | |||
b570bdaed7 | |||
8c0843cc87 | |||
31458ffd81 | |||
c15c10a94e | |||
9fca978725 | |||
b125901717 | |||
eb018ae660 | |||
7e5a9474fe | |||
525a9b5036 | |||
c3fbdf34ca | |||
48bd51e1a5 | |||
10d0b03a90 | |||
e1b3582f08 | |||
95be1c9e22 | |||
1ce8fe06d5 | |||
15c649024e | |||
e97303c226 | |||
3b786c819d | |||
04959dbd8b | |||
5cd4b874ea | |||
f14ea1b3de | |||
9cc0cda0fb | |||
09a7a4bbe5 | |||
cfea8b3745 | |||
28bf0b61ce | |||
2dc2429735 | |||
83d4592526 | |||
2d528c26ae | |||
66b3dce794 | |||
93f77a1045 | |||
aa4d23a3d5 | |||
2d7ebff8e9 | |||
bad9dd3b3b | |||
2f4e517857 | |||
ff35ba3696 | |||
72768e7fad | |||
77f3852cdc | |||
66857ca477 | |||
75514fc7af | |||
be06d871b6 | |||
f98ee326b4 | |||
bc8126eb16 | |||
4c8beefdcb | |||
bbb6c53457 | |||
d8991894e3 | |||
c7b7dcfd03 | |||
2c9e50873c | |||
923367296d | |||
151a206617 | |||
e403c4cf99 | |||
e3fbe37f9f | |||
dc870cd5ea | |||
584be44743 | |||
5fffd35ec1 | |||
b92e22e4a6 | |||
3e6d16a7a8 | |||
ecbcc277b8 | |||
dff1d9e4dd | |||
7c0bde7310 | |||
a82d21ac05 | |||
0bf8378fcb | |||
017ef8a837 | |||
0d63cdcb96 | |||
68a6f99c9f | |||
60781bcfc4 | |||
77fa2e2722 | |||
c36afd872e | |||
7e58a4c130 | |||
19a4bf1088 | |||
9678bbae4b | |||
a4d093afa1 | |||
ba788bcf0f | |||
f2c62bee7e | |||
548721e306 | |||
1ae950a638 | |||
c9385e93fe | |||
9bb16e293c | |||
c223702ea0 | |||
9167ba499d | |||
2d7e95e1b6 | |||
0cba736446 | |||
0816a57032 | |||
a0ab0bd3e2 | |||
b89ad4b328 | |||
6cda76a116 | |||
c112b327ab | |||
46c12a8899 | |||
c5219dfb3f | |||
4a8ee6815a | |||
e1b6bb154a | |||
b19c282269 | |||
e520921746 | |||
970642244b | |||
3b90be2d9e | |||
2f756f1e3a | |||
78e84182f0 | |||
65a7a8caf8 | |||
4c6a2f5df9 | |||
fea297e409 | |||
7cf6aba625 | |||
3bbc00cc8c | |||
70ed2b4203 | |||
0adce9b9c6 | |||
0e781d18fa | |||
4575a8fffe | |||
10d0ff252b | |||
c7d54570cc | |||
7136b33f2e | |||
70a78e74f6 | |||
d5707b7bf3 | |||
9f247901d4 | |||
5659742d97 | |||
450eaf7c4a | |||
47485e4b49 | |||
64254e758d | |||
c1aa5d4e47 | |||
ab8173637a | |||
3841cef497 | |||
b717f1c7eb | |||
da57f76de3 | |||
4784f1c65a | |||
41af63b333 | |||
e2bb0de24d | |||
b791fae9ce | |||
6033a9e20c | |||
9e8c8973d8 | |||
3933bf5c1a | |||
708e296774 | |||
84925ab69c | |||
b3cb9b7fe2 | |||
9cb61fa34d | |||
7c219d235c | |||
6938c79f88 | |||
b8284a147d | |||
15ee90e99c | |||
795f80b4ec | |||
6b6427492d | |||
6055b8c3dc | |||
a98cb50d55 | |||
e98bbc1c52 | |||
7245aece4f | |||
60cbb02822 | |||
4e863ecdac | |||
5037033fcf | |||
e6b158bc97 | |||
4cc0dfa10b | |||
4ced8889d3 | |||
d26967a87d | |||
fc8955941b | |||
071a80360f | |||
d2154f5f2e | |||
334d382bfa | |||
90c4b00f74 | |||
71261525e8 | |||
3126959576 | |||
02e51d8282 | |||
ffb2027a19 | |||
70c9ab9074 | |||
6d1fdf1ba6 | |||
1f7180d9a8 | |||
b4e94ae4dd | |||
07c606bfc9 | |||
e705a8bd89 | |||
b3bdfb7f1f | |||
5af1aeb092 | |||
be64fa674a | |||
204f5591a9 | |||
ee3e3a3a40 | |||
f9200a2b75 | |||
f570b70827 | |||
0db141eeac | |||
acb2ee53bb | |||
c544b7f5ba | |||
c0024e97e5 | |||
bdf8aa9168 | |||
de5ce0f515 | |||
bb95484c8a | |||
cad18b8a3a | |||
0f6a98751a | |||
aac5a4c27f | |||
d3f6415387 | |||
04da44eb98 | |||
7649be97b1 | |||
c9ef777e0f | |||
c0cb2438d5 | |||
30c531b39e | |||
bf703a8a66 | |||
e7b631b087 | |||
a9f5dc036c | |||
0a83b51e00 | |||
eab63ecc6c | |||
b0794cf35e | |||
5b9e71a27d | |||
eae41de27d | |||
e9163aa3a7 | |||
8c617515ba | |||
04e4e71f2e | |||
a587482edf | |||
0aac9350d5 | |||
f56c12ee4e | |||
4bb9ae61f2 | |||
ff7f3484e4 | |||
5da3abe6b4 | |||
c0b398e0ce | |||
3de10adac2 | |||
1b573d6552 | |||
2a96f93919 | |||
c6b2639ca4 | |||
b9abf37a7e | |||
373cbb4144 | |||
a521982576 | |||
a77fde577c | |||
ea6926e57d | |||
ba25b7fee6 | |||
7ee162d98b | |||
380f557c45 | |||
1bdae53f4e | |||
9314c346da | |||
bfaad1388c | |||
0b580ad05d | |||
bb35a80177 | |||
24fc95ac81 | |||
8f864417c4 | |||
bb9d29b061 | |||
b9d8ec1463 | |||
1842a7660d | |||
5caa2f5536 | |||
d6078be8b7 | |||
cf60723f14 | |||
f7ff0a2b1d | |||
cc49664b2f | |||
99fe74f026 | |||
b021869eeb | |||
b8806d163b | |||
1116aae1de | |||
5e5f60253b | |||
bbc02752c9 | |||
9896bc110e | |||
ca60f8ecdd | |||
544acd1e35 | |||
6e07602d77 | |||
82898f7bba | |||
d61283a8bc | |||
1ee3f826cc | |||
4a00a5ba9e | |||
39eda67867 | |||
a99d38fdaa | |||
0eb2d437e2 | |||
3ac9036c79 | |||
c94e292176 | |||
91d87c2d9b | |||
ff472f69c0 | |||
e18119e24c | |||
4a592dc64c | |||
d9e13201dd | |||
5c75b19c5d | |||
52a77db60f | |||
0513c250fb | |||
48864ad6cf | |||
cdbccad21e | |||
e15bc68c9b | |||
8bffd7672d | |||
61df5b3060 | |||
b5255444cd | |||
0c94e377fc | |||
8e5c67b4b2 | |||
b24f2f1756 | |||
c69c17de42 | |||
061617122a | |||
125ce3240f | |||
7215efe167 | |||
06d1570142 | |||
093c370faa | |||
aec9574737 | |||
7ceb76cff5 | |||
300e2fe9f8 | |||
91e1643627 | |||
91421b0c62 | |||
40f611664f | |||
dcba4f4098 | |||
c098ad2b3b | |||
b43223cb7a | |||
e243531dab | |||
1af38e62bc | |||
f37f062cdc | |||
7e734214dc | |||
05d152746f | |||
dea7f37553 | |||
415c599310 | |||
70cd4fedbe | |||
1e6d7673bc | |||
b4963b725b | |||
0371ffa4ce | |||
6a664a7e15 | |||
88ce9300bc | |||
85cf0e311c | |||
0e3d75cfeb | |||
630c8a5faa | |||
905921a684 | |||
1e469b3b0f | |||
bff3c4f95c | |||
bd2bcb6994 | |||
4c8898a639 | |||
97df33ab1a | |||
ef46fb2685 | |||
d5d6dd3614 | |||
6c233c6a0a | |||
6db715d879 | |||
ab02e8a546 | |||
8cbfe64f19 | |||
fd1e9971e4 | |||
68336a76c5 | |||
393e914a86 | |||
ffb54110e9 | |||
533d825f1a | |||
c65279b672 | |||
f9926beeef | |||
add8a777d8 | |||
21bc505d85 | |||
3fc49c001e | |||
3d69a95c49 | |||
d81fdf6d6b | |||
87d3109ffb | |||
180dbbb521 | |||
24aac7cee5 | |||
53e18a5387 | |||
92062d056d | |||
06368ab0a1 | |||
38efe25c68 | |||
319079de7a | |||
025bf900a5 | |||
2885f4f7b1 | |||
c07eda15b1 | |||
4274296cf3 | |||
76a203d4df | |||
24f37e2062 | |||
f465b2e2a0 | |||
ce00e49a89 | |||
d494f9d66b | |||
c35a183a64 | |||
9cdd5fe7f2 | |||
c21428215e | |||
64d5af46f5 | |||
25846ea18a | |||
798383596d | |||
9ca71bc937 | |||
5407429ec0 | |||
ee5c94f6db | |||
91045afbee | |||
3f64782023 | |||
f8d35f9502 | |||
ea78d3ec9a | |||
e056a28316 | |||
0bea721c2e | |||
e1b89494d0 | |||
cd8e7f3912 | |||
50604c25c2 | |||
aa6b2357d8 | |||
5b2d29bef6 | |||
a296d26328 | |||
d01a26ec61 | |||
efd7d6f0c0 | |||
b55be093be | |||
7c1d5cadd7 | |||
dd1592b03b | |||
9b37ac483f | |||
090820958e | |||
ac21e1be5c | |||
5196443b26 | |||
c8531cbeb1 | |||
c560abedba | |||
9b952fbc44 | |||
ccdf05e922 | |||
c3d74f2ae9 | |||
f47498888c | |||
5665a7f0cb | |||
b8178c6c8d | |||
4a0f15eb88 | |||
c4f53fe525 | |||
8c93ec52de | |||
befe0fff2a | |||
b6a837cbea | |||
4861973899 | |||
c593e4b500 | |||
5bf78c20d4 | |||
5c672130e6 | |||
d8214d4f12 | |||
64d1f09ce0 | |||
47d0f0ea40 | |||
2d85fd093e | |||
d936568b76 | |||
4598a83e8e | |||
f4bf00ad31 | |||
07fde7f6cc | |||
729209574e | |||
f28206d989 | |||
0c81b32cac | |||
11216017cb | |||
a7b9f53967 | |||
1fa2e2e37d | |||
f67d5faeb7 | |||
5cbf859458 | |||
629ed74d09 | |||
ca2af2ca63 | |||
52ab089615 | |||
01461a196d | |||
04832f052a | |||
c8b2c8ae50 | |||
1b81c7fb22 | |||
9ccda0247e | |||
a7df4dcf25 | |||
d91f47c791 | |||
a9ac4e7f44 | |||
fc3ec57437 | |||
266f6ab919 | |||
6218c1c00b | |||
cc81d6fe82 | |||
69f9102f2d | |||
beb9275982 | |||
abe48713f2 | |||
82cfaf2fbb | |||
3d3bc4738f | |||
2d0746f5a4 | |||
9c71e2f1c8 | |||
134fd62da8 | |||
2afd283582 | |||
c66734bab0 | |||
8e56a61f95 | |||
d265271148 | |||
b40e397b28 | |||
35ff1d996a | |||
deea0b05cb | |||
c50c9ca545 | |||
a819b4a5a5 | |||
df2d7d4734 | |||
79ce4098cf | |||
374464a1f8 | |||
c8d0bf27af | |||
6e4ae034b2 | |||
52b560e72d | |||
9b971ad222 | |||
3613162d09 | |||
3a272e998d | |||
d4c750beb4 | |||
84b31e65e1 | |||
7b802bfd3d | |||
f9c4632b8d | |||
e4764cd8a6 | |||
dd78a3a686 | |||
94c06e13f4 | |||
e8bebe5a75 | |||
5b0e1b4f9e | |||
8c0a93779b | |||
9241479da4 | |||
8ffca93cd5 | |||
7fea0c124a | |||
20dbdb20d2 | |||
e6b8e2e8be | |||
7c5b7f77cc | |||
de84547a21 | |||
44676756ae | |||
b399b0f182 | |||
1152191f48 | |||
af1b07ad44 | |||
b8113fff1e | |||
ff6948cf2d | |||
fd25e85d59 | |||
c07cd72e85 | |||
e2c101206c | |||
92276b5769 | |||
a2133f61a8 | |||
199adbbcf0 | |||
dc316fd7b4 | |||
025183602f | |||
db4619a9d9 | |||
451e527b7c | |||
54dd3a00df | |||
03c5dab79d | |||
1fdee861e8 | |||
c12bf991b3 | |||
78a097585d | |||
39132327cc | |||
dc32318cec | |||
592f74124c | |||
e5e63cc5ac | |||
f40e0f786d | |||
ebd9f1471b | |||
d76547ead4 | |||
4600772e05 | |||
ed597423cd | |||
f20ca06f85 | |||
a636d3f394 | |||
043df18daa | |||
96996bf18e | |||
f350137a14 | |||
b7a6f3ec75 | |||
6c34672549 | |||
e779a07bce | |||
9a36e8ba3b | |||
c968bacb01 | |||
25199dfb43 | |||
48fed4e6fb | |||
fc253237c9 | |||
589948c7f4 | |||
7e69690605 | |||
95f498ba9b | |||
fd07ae5225 | |||
8acd94fc89 | |||
1436480eab | |||
448d176c24 | |||
fd269453a4 | |||
b3b380964c | |||
6e9025ebf2 | |||
3922691b3c | |||
0545b77cf4 | |||
6b3f39fa1a | |||
3114ab87dc | |||
00bc99cc7b | |||
540b3ae2f4 | |||
dbfe4140e1 | |||
d3675ec254 | |||
ded2483fc0 | |||
e62ea388e0 | |||
f20356e9be | |||
d282a2d846 | |||
4641ac46e7 | |||
ba9268a09e | |||
fb9902c536 | |||
5318ba6c6e | |||
fd5ebef488 | |||
d9e4f39ddc | |||
435b9d8973 | |||
0ea70ba656 | |||
92a07b87d2 | |||
c3c82282ba | |||
adc15c24ef | |||
dddf9a9396 | |||
9ca6860ffa | |||
f7dd388954 | |||
6012839f0e | |||
8e9cbab053 | |||
aaf375a57b | |||
3cce985f03 | |||
c59df6ec20 | |||
5c3f41f64d | |||
cf3523f49f | |||
db794752cb | |||
bceaebe856 | |||
3916de2921 | |||
9e0f8c1a97 | |||
0cbc56b82e | |||
b95608f68a | |||
b6e5dbd06c | |||
914f19be86 | |||
f09bcf3fcf | |||
d0b18dec8e | |||
75d486b124 | |||
4914609485 | |||
75bd66326a | |||
8f904f75bb | |||
549c598f51 | |||
ed68d604d6 | |||
f83752f43b | |||
86c22636eb | |||
30d20a453b | |||
fe29d8a23f | |||
694d088160 | |||
6aabbffc62 | |||
7b59bc8d12 | |||
79d0fb0b52 | |||
edf56d34f8 | |||
623329fb33 | |||
9f0074eef9 | |||
6733253826 | |||
f117805129 | |||
c75b1581d2 | |||
109e118aba | |||
201b77d5b6 | |||
a5ca08f33d | |||
86210c4513 | |||
988a3e4446 | |||
0f5cd22bb7 | |||
2f5bed36b3 | |||
5b6534bb28 | |||
e31e5b2477 | |||
07d5fafe2e | |||
e08da659e5 | |||
8a4979f44c | |||
e67464325f | |||
94c9b0d23b | |||
e9ec310d8a | |||
c78d1e3c39 | |||
e94319145f | |||
3f3b01b5f6 | |||
19a2791c65 | |||
4e8ccf0ef3 | |||
f1a7d5ecf7 | |||
8b05abb80d | |||
48c9349ce9 | |||
117d848466 | |||
9a2df072cc | |||
99c62aab36 | |||
224278e07a | |||
74b69e191e | |||
8cda8a727c | |||
a3c0c7c96f | |||
4403e4ed62 | |||
9b209823f6 | |||
b2cb125bd4 | |||
5e8f767642 | |||
6ee270d9d8 | |||
44fa309d20 | |||
58d88f3dd4 | |||
e980c23177 | |||
75224321bb | |||
801af05b20 | |||
7611dbbddc | |||
6d40ca15bc | |||
32c1c19224 | |||
bbf6357222 | |||
dc16629c24 | |||
3718b9d768 | |||
c25eb088ec | |||
3feb3e52f8 | |||
8e730ef93d | |||
e0913a39ab | |||
7a27fbc001 | |||
ee0dbdad35 | |||
9225f88f89 | |||
a04839dd6b | |||
002006517a | |||
f5b202d438 | |||
a7df094ff4 | |||
1e6fa77633 | |||
eb4cff202c | |||
7ee777f405 | |||
81bd5c784e | |||
b526e132a7 | |||
1860f66de5 | |||
ded9ada9bc | |||
d0e6a2eb8b | |||
4e103a1963 | |||
475e927178 | |||
ca7932c4f0 | |||
8ab47d3321 | |||
def7e87151 | |||
27568c2bef | |||
0694a187d7 | |||
832601b36b | |||
578969c34c | |||
d1d0115aed | |||
c89e6ebfab | |||
ca1089b881 | |||
a1d04f2aad | |||
bf0604133c | |||
a82b2da16e | |||
f2273c0acc | |||
17bedac96c | |||
4831fad27a | |||
5e896cf582 | |||
add3491c57 | |||
f470576822 | |||
10760a53a8 | |||
eee805183c | |||
b8fb391022 | |||
3c698f1584 | |||
2fad52d684 | |||
ec64a68a71 | |||
db55562f6a | |||
d8409a9d2b | |||
0d0ce6eec1 | |||
483f313eda | |||
7b6c742178 | |||
d4a35ba6ff | |||
68b112837a | |||
e2f20ebf94 | |||
f870e4965a | |||
7ebcb219d6 | |||
c21913a66b | |||
77e956a29f | |||
08275c406a | |||
2931e1b87b | |||
153b422496 | |||
0f6a6d6fea | |||
91fdb3e2d4 | |||
d8e87bd881 | |||
922033c1b2 | |||
df1793efbf | |||
836a2700f2 | |||
8f3aaf77a1 | |||
00c059e5b1 | |||
f4f355c74a | |||
b465fc5aaf | |||
2d78eaa48d | |||
d08451bccc | |||
d8e785aed0 | |||
267b6f49b5 | |||
e6688f4b9d | |||
9d7b9771c2 | |||
136a9a39de | |||
3dcf628fdb | |||
e614e9787a | |||
e426fc0922 | |||
5d4bfffc7e | |||
207cdaf7a4 | |||
7315b581ce | |||
38efaae7b2 | |||
469e042216 | |||
0f1a4b9d8f | |||
7303c00296 | |||
fc55b34d84 | |||
6f67fc0e02 | |||
562d722ad5 | |||
144c1ba3a6 | |||
06b032af91 | |||
3603140114 | |||
e094785cbd | |||
e7408224ac | |||
e67c05c274 | |||
b22804efaf | |||
890f55f91a | |||
cc5fc0b892 | |||
5efe2b027a | |||
5b6569d0f9 | |||
0eda7ac498 | |||
a5ef353484 | |||
67a36d8d31 | |||
7cc3cc3990 | |||
dc0edc4c2b | |||
71d2f091e5 | |||
c2f062a391 | |||
224f490455 | |||
5b35232ab4 | |||
6d6db70e42 | |||
6830e15b4e | |||
3f07cad35d | |||
e951340033 | |||
db8912a735 | |||
0e297731a3 | |||
f20c4f98ac | |||
05e60cc7c0 | |||
55b4469767 | |||
f15516e478 | |||
17ceadbadf | |||
8c25b2b316 | |||
8b1ae404a3 | |||
13534cd4a9 | |||
abfb345503 | |||
42ae935496 | |||
434515d957 | |||
094f7803b7 | |||
b0c7bad391 | |||
e9a4a905ef | |||
7b6cd0cfbe | |||
b718b12083 | |||
cfa7258ff4 | |||
b70e0a0870 | |||
da8eb464b8 | |||
8f9d1cfa30 | |||
585009ac5c | |||
30ee65fd14 | |||
76428b16f0 | |||
0d7b14e2d8 | |||
a9d19d02b3 | |||
adcbe55307 | |||
aa99a7df64 | |||
00afa1ce52 | |||
e94bf4c63c | |||
ec5adffdc2 | |||
733c17ad3a | |||
53b0b562e6 | |||
fabae6e970 | |||
a9f9c40d8a | |||
6fc89607d3 | |||
2340760f53 | |||
39d6d2857e | |||
7b722a0001 | |||
e7682119e0 | |||
af6be44676 | |||
5a8f97a0b6 | |||
0d4dd385b8 | |||
94f0f3e966 | |||
43e31765e5 | |||
7c1bdfe713 | |||
9f09784b55 | |||
e7a3a89bfb | |||
7ea7e63f44 | |||
1d2ce2cbeb | |||
06cf2e0bd7 | |||
9d219ae4b9 | |||
71f5a6c50e | |||
90b2be2bf4 | |||
db1aa8fcbd | |||
11c000f764 | |||
4d6dcbd173 | |||
0da117efd2 | |||
533c368e32 | |||
8883513b0e | |||
dcc9a71455 | |||
1a56743bb1 | |||
387a4b7c35 | |||
1d65d63bd9 | |||
dda19c29fe | |||
ca41669f4f | |||
0e1886e6bd | |||
c26e116f0e | |||
5c9c7f2c5e | |||
ca2fb6cef3 | |||
46dac909ef | |||
b1e4347e10 | |||
97aa91c75e | |||
4f8fb32136 | |||
e0fbce0087 | |||
fb22f78fb3 | |||
d6393cdbe5 | |||
5167fdb3f0 | |||
ab00822764 | |||
b4352ad38b | |||
d07d00fa41 | |||
11d87e4725 | |||
627ed51a1b | |||
c8f3bfa726 | |||
3091e3a1c8 | |||
2f3e7d1c27 | |||
0e831d4b92 | |||
7294ec9a3c | |||
e34bab9585 | |||
7dd14955c1 | |||
6428ced157 | |||
30a42ec1bd | |||
aacea3e9db | |||
6886b61186 | |||
0744c9fa29 | |||
502a665ffc | |||
3c315703c0 | |||
12ed07a607 | |||
101b33c381 | |||
97f4316653 | |||
b0704e86f0 | |||
a182b13e5a | |||
80b630a1e4 | |||
475efbe007 | |||
3ab5e5ac48 | |||
c6c5ff2089 | |||
176ec8ac7d | |||
dcdd4b3255 | |||
fc0a0105b3 | |||
f3960d21a8 | |||
a44d853c1b | |||
6b41734d6a | |||
c33dc0f3be | |||
bb5ffb24a8 | |||
a878c9a61d | |||
6454bf8ec4 | |||
40aa733ea7 | |||
f37a822725 | |||
f249ccd414 | |||
7ef4ddf0f3 | |||
d8e18df3a1 | |||
78d3d9d27d | |||
0aa0ec5abd | |||
b6eef3612f | |||
666d62dd7a | |||
44ee4b989f | |||
18790d867c | |||
d6b8936376 | |||
4d840c7db8 | |||
4d2b21816d | |||
2d34fdd28f | |||
68abda1219 | |||
f778f08f76 | |||
ac1bd2fb7b | |||
4b7b1379d9 | |||
e560e2ab3f | |||
1e441c2ddf | |||
93ce74eeb1 | |||
f718f4251b | |||
4644c9b621 | |||
197081f10d | |||
00b717cde8 | |||
34aa917ca4 | |||
a38ddcb364 | |||
5b9576df4e | |||
310219e5d7 | |||
a0deb463c9 | |||
90ddec2ad8 | |||
f6b03d5a78 | |||
f531daa872 | |||
046dceb5c2 | |||
dcc1f00048 | |||
05f935b598 | |||
f2d27403c5 | |||
473efbe67a | |||
aeabf0f324 | |||
80ab552ad8 | |||
7d4695c5b2 | |||
5189eaca36 | |||
cfb31377fc | |||
a07c52e112 | |||
8e1071aa89 | |||
7cb9a6ba60 | |||
350dc731f1 | |||
f690f58bd4 | |||
4bc65e9ef7 | |||
2d600da8b6 | |||
35af53828a | |||
10ddd5b127 | |||
f46e131f18 | |||
feb5c8be95 | |||
edf12bec71 | |||
ff1fc28287 | |||
314398ba4c | |||
840331347b | |||
6181b12ab8 | |||
68da661edc | |||
88cbb6913d | |||
7a26646e1b | |||
92eb3b0bf6 | |||
fb63434eee | |||
97f90d9684 | |||
f91786367f | |||
6a57337a68 | |||
211e2bb37a | |||
d2d08bf143 | |||
8acb37b6c2 | |||
81b3d2db4f | |||
9633c0b07a | |||
1dfa8ee7d8 | |||
1163543a98 | |||
bdb7de34be | |||
9500fc11ac | |||
65daf29acd | |||
298b25cf7d | |||
41f4e22a17 | |||
288c57c144 | |||
7ff8923569 | |||
b41779bd02 | |||
beea6bc794 | |||
fee58e98c5 | |||
c51c1da618 | |||
ea2812f50f | |||
3ec05709d5 | |||
4bdac7404a | |||
cc41218d37 | |||
4b336b1853 | |||
e1c77ce236 | |||
064d412ec8 | |||
7fff4f249d | |||
7a3745f642 | |||
f8658f6afa | |||
223b725a10 | |||
25aad8d7be | |||
b2c9b7635d | |||
24d13dd120 | |||
965340ff90 | |||
8e36fe6bef | |||
2eb41a8caf | |||
fb989ae62f | |||
7901ec2a64 | |||
f675dbc726 | |||
2ad4fdbbb9 | |||
97cb0cbd08 | |||
4ca0805de1 | |||
4b358abbb7 | |||
dc82a0fc16 | |||
435d6f6f3f | |||
ef92451d1a | |||
06184bdcb1 | |||
af98d01053 | |||
bb1cda0916 | |||
a6d0ea347c | |||
0fcd57192b | |||
a6ffa5738b | |||
c75bd97537 | |||
eea09f4de5 | |||
5656ec11d3 | |||
eb53e44cb0 | |||
69f3106062 | |||
8ab99f6129 | |||
53a3c59a91 | |||
df36983049 | |||
bda016bb3b | |||
cc174b7b85 | |||
bf9d120081 | |||
775c85fc18 | |||
5a756aaed9 | |||
dca092fd7c | |||
c6e92ecac4 | |||
93008ff605 | |||
43c7b935df | |||
8f9a0a244a | |||
fd13bd864e | |||
710f27afa9 | |||
f537793b0b | |||
f7183e38ee | |||
0a65dfdd10 | |||
3075578245 | |||
b042b7705e | |||
d56eb397f9 | |||
3054a1d32d | |||
0a3cd652b0 | |||
f70b914779 | |||
46ca0ac10d | |||
031f647952 | |||
8f1c86f550 | |||
926fdecd13 | |||
af2ca7a67e | |||
9e3e2ff81a | |||
a9fe6472d9 | |||
a862a81480 | |||
dbb92881a1 | |||
10bf7f5d07 | |||
1e61d84fd1 | |||
8618ba1b60 | |||
3c8c44155d | |||
2002412026 | |||
7f69517fd4 | |||
851f8645b5 | |||
c40cfaa388 | |||
0349d1d57c | |||
53049c02ee | |||
73a3a61729 | |||
5fe6aa2800 | |||
c7eafd7c79 | |||
10b5fb5d72 | |||
c4eaa944e2 | |||
a735939d1e | |||
6ed5f04970 | |||
b459b09b2f | |||
3f5877dbcc | |||
e659b91c4d | |||
e09f054058 | |||
b646f50265 | |||
0a48ef3030 | |||
ba614801ee | |||
fd6eb47e68 | |||
e69aeb8b98 | |||
26ea1da146 | |||
c9e8c7a290 | |||
5e4eb92443 | |||
461b6499ef | |||
c769920b6e | |||
181b98ef9e | |||
4e1184a400 | |||
e52d9e3210 | |||
dc6475c91b | |||
52f9956e92 | |||
0bf00d1ca4 | |||
d1a707df57 | |||
4dc9b45297 | |||
6e31eebfb5 | |||
a7df828932 | |||
517cf61d11 | |||
4be7bc8323 | |||
74c05d00a9 | |||
677613d30a | |||
bacba629a5 | |||
14e36f1362 | |||
d43ad849d1 | |||
627aa61184 | |||
dad5b17ac8 | |||
fef52c0112 | |||
8c4765b386 | |||
7c121bfc01 | |||
942c5cc04b | |||
348b3036ff | |||
09d3451d9d | |||
b1a49e5f29 | |||
da01a5b4dc | |||
3f9cdd9b56 | |||
0f9e87d7bb | |||
0869789214 | |||
10c8cc35c5 | |||
30c2e3e8ff | |||
86cc2f1075 | |||
fa357a450b | |||
b32641db87 | |||
0ee790969d | |||
7844ace934 | |||
f4993d6e5d | |||
0fab806f36 | |||
be2113d291 | |||
625d5b2313 | |||
6471c0c536 | |||
47c53fa60a | |||
cf50e4f6ec | |||
7eea97d741 | |||
88b55ab93e | |||
ee36d47c27 | |||
6f2fdbe447 | |||
0f36be0001 | |||
0f4a197e34 | |||
7dbff5b9e6 | |||
220246278a | |||
349e5a15e9 | |||
bf7f4bba7b | |||
ab1766a559 | |||
51bf33040a | |||
a2c7273801 | |||
ec6ac5bf24 | |||
ec7501782d | |||
890b1c2d52 | |||
c25d07259a | |||
c960246eee | |||
a01aee3111 | |||
e2e951efdf | |||
3f6393f732 | |||
b6eb343234 | |||
207a7e5160 | |||
a0face4a28 | |||
a8cf9f5cc4 | |||
461b38e653 | |||
8e4c0f7c22 | |||
d78bfcc35c | |||
2b7c09e6ee | |||
036d9dbe59 | |||
1d342cc6af | |||
62b32b2211 | |||
ae45ce517e | |||
5b3ccab7dc | |||
95f16c38a9 | |||
d616cb283b | |||
9874fe2c23 | |||
520a142992 | |||
6ff56dc0bb | |||
1e63615592 | |||
3e62ffed0a | |||
b133d51a83 | |||
037b89f018 | |||
20d06d9f9d | |||
156cf7315c | |||
e2886e5303 | |||
c6cf330e70 | |||
6be3b62d78 | |||
c57af5e81b | |||
f7431f809e | |||
ea43c34de8 | |||
fb6e9fa58f | |||
b2ce1e8029 | |||
d90c51220f | |||
d1b14b68fa | |||
d911728611 | |||
86a7200012 | |||
6ddb7453e1 | |||
ad2355f8d3 | |||
582c498fe3 | |||
0a0c58d450 | |||
0dc592b819 | |||
f46300016d | |||
3e1a7c6102 | |||
f07065bf84 | |||
6d79903eb3 | |||
e166329f34 | |||
bb1bf6a88c | |||
30cbb6c9a8 | |||
4e33ab1e89 | |||
5494f309c0 | |||
3b6e7eccdd | |||
e41d6787bb | |||
ed30108961 | |||
12712ef812 | |||
0307f6b42c | |||
3e44620966 | |||
7424f1f768 | |||
b5331d821c | |||
27f6d47efa | |||
dbc7ad2ec4 | |||
7b27d270a2 | |||
97b3a0b093 | |||
06b38506d1 | |||
fd581ffc37 | |||
ff57c5e9d3 | |||
9b16d7c786 | |||
4c1bb18956 | |||
7d2bf892b1 | |||
a99e77093f | |||
92737bb695 | |||
9b81955544 | |||
4a0031080a | |||
40e9fba312 | |||
e227cc92ff | |||
73dbdbcbe6 | |||
3961f26635 | |||
e51c274a18 | |||
e75d0c58a9 | |||
9a798360f4 | |||
844ad09464 | |||
1e1d1efd90 | |||
240e6835c2 | |||
61398ee8f8 | |||
e6e84859b7 | |||
abcdd331db | |||
775d136b91 | |||
dc93691fd9 | |||
48d782c69c | |||
0a04e626d7 | |||
e7c4bf5ebf | |||
546a416f7e | |||
179a7a2792 | |||
251b6fcf70 | |||
ab1fffb721 | |||
da352a322c | |||
7d20458e82 | |||
5a54066f81 | |||
a58e5a3399 | |||
9872f43cbf | |||
1078cc4642 | |||
db7ae028b2 | |||
2b6f5dbd59 | |||
f7aa0c45df | |||
a72d58cdf9 | |||
067283834a | |||
cf362c4a61 | |||
496245c801 | |||
859ab36347 | |||
1d740c7c36 | |||
a03c4c3659 | |||
094ecceaac | |||
2812736ae5 | |||
6f87f8706c | |||
38beebe720 | |||
fc1c3c6808 | |||
96ba895b84 | |||
df35dfe3bf | |||
c5504c6657 | |||
530e109433 | |||
6cce47b2f1 | |||
6185d5eca1 | |||
685ad1746e | |||
891f870ec0 | |||
ad9933f0f6 | |||
1b86117754 | |||
eeb3c968d6 | |||
406658a10f | |||
6a0551cea1 | |||
553f3b45d2 | |||
064a8e785c | |||
21e9723bb2 | |||
60b2c44a44 | |||
c4fe3ecc0a | |||
2f18a8f6d0 | |||
5ac784e18a | |||
7a2164b4d0 | |||
0a43eae184 | |||
3117e2b2a3 | |||
41fece4643 | |||
7aa807ec7f | |||
4d16e1e14a | |||
73fc18099e | |||
e34dac8dbb | |||
af0e7f7187 | |||
a3a6812608 | |||
2725c4ad4d | |||
c8cd6e9460 | |||
0cd27d6129 | |||
b47fc1c020 | |||
de6ef7ef5e | |||
f95fe8f1da | |||
bd0dee5db5 | |||
c13b7fd883 | |||
f7e74b3088 | |||
343f01d5e1 | |||
08bacdd090 | |||
41b1c80492 | |||
e5d7316e5d | |||
b043c3a6da | |||
98b2855b9c | |||
f3c52c409f | |||
1307bdc612 | |||
8c2e6971fc | |||
1903990f30 | |||
7d67005709 | |||
9acc2f92d1 | |||
72dfb0bda3 | |||
1635612430 | |||
abda837d2f | |||
101fb0b8aa | |||
10de7dc1f9 | |||
d2309b8114 | |||
6bdd81623f | |||
f538c9f0c3 | |||
8ae3bad6f7 | |||
77de99b383 | |||
312949f336 | |||
1ab635bd7e | |||
b35abd548c | |||
30e1c3307c | |||
08e052380a | |||
0e824c35cc | |||
548374ac2d | |||
9ad79fefc9 | |||
49d37c016e | |||
7c70c79a84 | |||
6916b8bff7 | |||
73dfb5f443 | |||
69b9dfa468 | |||
ab61b8ba0a | |||
5c8c64242f | |||
ddf96943f0 | |||
e773be2f58 | |||
f965804e6d | |||
ec078eba72 | |||
1815cb1bc3 | |||
7b3cd71085 | |||
06128b5d07 | |||
990c8e1f18 | |||
a170506356 | |||
5ecf2a3357 | |||
fa48746ba9 | |||
e2b8c069d7 | |||
14407bd1aa | |||
08db72903c | |||
46f9fab140 | |||
b7d06f2c0a | |||
118196a0bf | |||
586ce1fc80 | |||
adb979df38 | |||
3401cb5b4a | |||
ebf1f12e97 | |||
5766208207 | |||
4bf4771f08 | |||
0e87db9eb7 | |||
1e053783f3 | |||
7afc96112b | |||
7bb41a30ed | |||
3d1b0eb843 | |||
5b9af0b5ae | |||
9219ec539d | |||
c8bd57cd4d | |||
53bf8c09fd | |||
651c383668 | |||
9ed7587e3e | |||
674295e800 | |||
6b02f2eea0 | |||
5237e55326 | |||
3b59592110 | |||
72640ae058 | |||
d916027e75 | |||
8966d2aa06 | |||
de7ea04f54 | |||
bf71fabe0e | |||
b3368acb33 | |||
87220c6697 | |||
a3b5c2ad71 | |||
fb4c1473c5 | |||
2bb2502d20 | |||
fe51698579 | |||
0f0f40bff3 | |||
a798fe72d3 | |||
fba98d03a5 | |||
7dd2517f67 | |||
641477d6f6 | |||
8e56656c8d | |||
564a6a1f62 | |||
69f0c80cd7 | |||
6fcb51cea2 | |||
c58b8a4973 | |||
c8f4ab4f06 | |||
e425c4cca8 | |||
056ec986c2 | |||
de3b2fb95b | |||
789e39c719 | |||
b29c3152db | |||
3831679772 | |||
596f9566d8 | |||
124befe9d6 | |||
895534f32b | |||
50c16fe6de | |||
b092d1a5d3 | |||
a9b45630d7 | |||
c1a39c269e | |||
6fa3f0b6cd | |||
9e5e3d1559 | |||
7135205299 | |||
d99d977d2b | |||
7dd7e562bc | |||
75d857027e | |||
17694c1d01 | |||
749ad700d8 | |||
8f3df3039a | |||
02c315c194 | |||
b697375573 | |||
c57ef7725e | |||
3ae07503f2 | |||
9a0341adde | |||
96225efd96 | |||
c3bd904f41 | |||
74257163b1 | |||
7bc75fd220 | |||
a23281afab | |||
9e90dbdde6 | |||
1e8d8e40a2 | |||
583e208c1e | |||
9b91c427a1 | |||
196c5e9c24 | |||
d8f7feb672 | |||
7c889f17b9 | |||
c15a75556d | |||
5275c2e35f | |||
5267e06969 | |||
b62183adcb | |||
5d2dec1803 | |||
4a98dab948 | |||
9f8c70b326 | |||
a65404e63a | |||
05a1ddad05 | |||
4be3d63c0e | |||
de6ce4a46e | |||
7a9e5afb93 | |||
b2876b0a03 | |||
b66f66fe6a | |||
30f04962d4 | |||
0feeb88024 | |||
b799f2e05b | |||
56d21de001 | |||
7b54aa0c7d | |||
6e11b8ada1 | |||
98d25fc4e9 | |||
79405f47f6 | |||
1c7c4fc3b0 | |||
97e84d0977 | |||
9906b58818 | |||
371f084884 | |||
1c10839c14 | |||
c55fdd9834 | |||
67b0890a6e | |||
4da4f96669 | |||
60a64c2558 | |||
d4153da8b9 | |||
fc33ab8905 | |||
a123c64f59 | |||
a090fe3834 | |||
8fa84de28e | |||
3e3da38de1 | |||
a3be8ccc87 | |||
cdfef30c22 | |||
cabf1e82e8 | |||
608dc5e284 | |||
836d40072f | |||
431401d90e | |||
6da83e2bd7 | |||
7bccfc0006 | |||
e051e09c1d | |||
1462c57d0c | |||
77c2b2b326 | |||
3cf9b9d9a5 | |||
629117e594 | |||
08f87c321f | |||
1ff13723fe | |||
510bda1b28 | |||
890327b381 | |||
b21f7411dd | |||
5df623bd2e | |||
1e9d249f71 | |||
a7b5949e6a | |||
02010170ce | |||
35998142fe | |||
75ea453bf4 | |||
33061aaa0d | |||
e342311bef | |||
3d743a1ba1 | |||
abca618008 | |||
0d2c3901a3 | |||
d901a1531f | |||
d8d56b195f | |||
a52699717c | |||
98315de723 | |||
68d2f7d4c0 | |||
c812b5ee09 | |||
dcf487bdc1 | |||
547b1d3720 | |||
84f75f4156 | |||
ff69da3fa2 | |||
edffe92a24 | |||
b6fe40ada4 | |||
837804b231 | |||
81deed143b | |||
900cdd3fa1 | |||
0018dc6ce7 | |||
c92f914081 | |||
0498444ef2 | |||
ce3c34e458 | |||
20401b99d8 | |||
397f98513b | |||
e545ea9504 | |||
b867d8f731 | |||
9a68864b67 | |||
72d7178762 | |||
fbcd9a0c1d | |||
c3144a20db | |||
5b56e0462d | |||
b7fffbb6df | |||
1f346230e3 | |||
a2860a7c8c | |||
df997e5d3b | |||
a67a82c921 | |||
ea0fe8d3d2 | |||
2560042ac7 | |||
3d1d0696b9 | |||
83f893f50b | |||
9ecf95b075 | |||
7748c261da | |||
a2db44f80c | |||
b438d8aec0 | |||
4ac169b210 | |||
56dc6d7f1e | |||
45b8762188 | |||
cafab98d10 | |||
9256f910f0 | |||
32068a832a | |||
47c2c0376a | |||
f0dadc4a43 | |||
960b60cd2d | |||
d6abd72e55 | |||
0a568f2530 | |||
c52aa648c0 | |||
3d23b39f4c | |||
f3a4048ebf | |||
1b07637cc4 | |||
68b75fd558 | |||
7c5ec1853d | |||
e8f4686430 | |||
02348924d0 | |||
69dcb4dbda | |||
c838821615 | |||
8b4ac7801f | |||
64a411628d | |||
e8e25c6fd6 | |||
62485b6851 | |||
54025d2bf5 | |||
f5ebf79e71 | |||
66d5490702 | |||
42fe052f9f | |||
58d9c46a9b | |||
e4648e2138 | |||
110e047681 | |||
17d403d812 | |||
0a53bd4956 | |||
e52d05c7db | |||
b00db4f8a2 | |||
0c2f30fd45 | |||
e08871c637 | |||
ff715881bc | |||
0e2e5ffa52 | |||
8095c4c155 | |||
e86246a985 | |||
625aaa02eb | |||
787e35c9f3 | |||
8887e6af91 | |||
dde4c751da | |||
3c39baf1d6 | |||
b292124f3c | |||
c0035ba1a2 | |||
2491509c6a | |||
107935ed31 | |||
31491c62c5 | |||
eacf8b896a | |||
7936fc5bd8 | |||
adfaddbcf4 | |||
74db5c6be7 | |||
f9399bcce7 | |||
87600b23db | |||
cedfb17b18 | |||
fa4c83df6b | |||
42c8720e8b | |||
b334d89715 | |||
4f5d36a84d | |||
8f379e2262 | |||
fa11a6e18b | |||
52bedce8f4 | |||
4c82af36e6 | |||
dafa0d9138 | |||
2e0450d7ed | |||
6af3209d4d | |||
5d362047e2 | |||
f48d6ca9f8 | |||
964e8e0a17 | |||
1f60a2d8b9 | |||
5fd83f2757 | |||
c80df4140b | |||
53e1729e2f | |||
ab2d1122a9 | |||
5190594c8a | |||
c858ceeb58 | |||
f0f52b9166 | |||
00c6f74481 | |||
2177ba0ed2 | |||
3483515346 | |||
75a06d2a40 | |||
53ac11983b | |||
69f4a4d4f8 | |||
222bcb808f | |||
686483f51a | |||
8df3da11e3 | |||
84dafda0e4 | |||
b909facfe5 | |||
7780d94de1 | |||
f2c440e466 | |||
4937e004b5 | |||
4cb383dccb | |||
c8a4b6f23c | |||
857724c7e6 | |||
a9b0400d13 | |||
2d1e5bbc7e | |||
60627ce756 | |||
7961a09d16 | |||
613efcacc7 | |||
7e8db16e18 | |||
1fbbed7e23 | |||
984272beb4 | |||
b9ce94bb68 | |||
f4c4ee78d9 | |||
793596614e | |||
136280100c | |||
29f1e4d2c9 | |||
72a7e61fd0 | |||
381cfca67f | |||
f40620aa25 | |||
57a9fed42b | |||
18d820da94 | |||
26e66f046f | |||
4270c04856 | |||
74456d1135 | |||
62dc824bc0 | |||
1605791f1b | |||
37a46aa2cf | |||
1d2d217b94 | |||
23961f695d | |||
730b208617 | |||
f09c04eeac | |||
be73739c62 | |||
eea3fb48a8 | |||
b4fa72c058 | |||
b0a865b0f1 | |||
7f49731618 | |||
3410aea788 | |||
bc0a133bb1 | |||
7e287a5359 | |||
1110bd0851 | |||
1b576f826d | |||
fe17566370 | |||
e3c00669c1 | |||
33d17afc32 | |||
2388359a99 | |||
2df0c9503c | |||
61fa3bc77c | |||
03ac9b6956 | |||
dfbef8495d | |||
7b17c49d8f | |||
4b3f31c2ee | |||
9ccc65bf8f | |||
f9e22add03 | |||
846951cda7 | |||
97836e18b2 | |||
7b69df4db2 | |||
3767b4bbe7 | |||
d7d2eefa4f | |||
6737f28d1e | |||
3da9404c2d | |||
4d5bd0fa32 | |||
1137da37c3 | |||
495a18805c | |||
a226b82d0b | |||
0b5ddcdc9b | |||
82da8f4946 | |||
5ff481ce3c | |||
f21dcaa6fb | |||
2c940de598 | |||
ce75b776bb | |||
7d22b9b9f9 | |||
6cb8b3b5cd | |||
2bf4017f2b | |||
08d2f8568b | |||
ac5f45d2d4 | |||
3cc7ad7d20 | |||
d4513364fb | |||
9684f4e42a | |||
f4186981fd | |||
141689e697 | |||
743c8b44a2 | |||
5e1459564a | |||
69a8813a3d | |||
17175df835 | |||
6b32535cb6 | |||
7f8fe75ab2 | |||
2815a14bb5 | |||
f4dfa60790 | |||
35e88dd529 | |||
4d5094a517 | |||
dd5abae721 | |||
8f2fb20934 | |||
44143f481a | |||
440abf4998 | |||
3c10427e04 | |||
74555a32ed | |||
85956b5828 | |||
41e40cad03 | |||
df2d5c6585 | |||
1a111b706e | |||
f696fce187 | |||
82d3d81bb2 | |||
4668932bac | |||
e6c41eac93 | |||
f0cff661df | |||
82d20dea39 | |||
804bb06859 | |||
5afa7e53f8 | |||
7f15b7b716 | |||
552e0c2248 | |||
e5b9e1f5e7 | |||
502bf90007 | |||
40bf117497 | |||
4011dce31b | |||
9e881e32f8 | |||
14aad2358f | |||
637a8899c5 | |||
cf0e395921 | |||
6ef438ce50 | |||
46e4b977a4 | |||
9626c5dead | |||
aea364e43d | |||
06defd0cb0 | |||
0f80897c50 | |||
57bb1c2c0d | |||
7b35b414e8 | |||
761aac7a23 | |||
15a02d7664 | |||
16ed68c1ec | |||
e63cf660c6 | |||
aaff484306 | |||
3281d9a215 | |||
0fcd61e00f | |||
c4523ea470 | |||
0447b3e4cc | |||
4d27c2901b | |||
855e18b31c | |||
d790878af6 | |||
85b244df2f | |||
6070afa6b6 | |||
975594703d | |||
6b8c3ef614 | |||
9b22f05381 | |||
ca3a990f9e | |||
557f4f689f | |||
66574d058a | |||
1c7c67060d | |||
9827ee97ad | |||
71a9a84211 | |||
367a2a4cee | |||
4f7465ba44 | |||
f891fc698c | |||
36bec62c9a | |||
dd5a2c8315 | |||
56bff46481 | |||
b83a0adb19 | |||
92ffefe656 | |||
51b2e41879 | |||
ef43bc9208 | |||
33733a4001 | |||
e5a1b37981 | |||
30aa72dc8e | |||
2c2d474059 | |||
c55ac0450f | |||
2d26b9c994 | |||
f38fe092ee | |||
7a33eb163b | |||
5db0408b9f | |||
3557d38ce0 | |||
7de4e9e66a | |||
73838ccb8b | |||
0509de76d5 | |||
f4b3d19059 | |||
f37fb82d53 | |||
dbe98f3fa5 | |||
371d4768e6 | |||
562d8386ec | |||
1625e4eb85 | |||
2365a076ac | |||
9898791771 | |||
a1c658274d | |||
be9998b48b | |||
e8f308f654 | |||
07132a2c42 | |||
9c4582e283 | |||
0204002d9b | |||
b3107cfad0 | |||
91ae68c07e | |||
06b3bf27b5 | |||
fbef63e150 | |||
bb8ee9bb3e | |||
25677a4126 | |||
3aeca0a770 | |||
4bd4733e52 | |||
9acec4d952 | |||
8388adcd1d | |||
5988ba76b5 | |||
1a06e7a16e | |||
7241cef7a5 | |||
5145296486 | |||
2cbf2d2226 | |||
754664aefa | |||
af99173cd7 | |||
fd1f30f92b | |||
d9ab2f8b90 | |||
bd6c60cf8a | |||
f0c150d93b | |||
c2986eaf47 | |||
ef0c4797bb | |||
ac02a99934 | |||
fb67d1155f | |||
eb46852bb9 | |||
007d8d2811 | |||
ebe04fc114 | |||
d7dd7f70c0 | |||
f2cb89a128 | |||
b8fade23de | |||
3b97a17648 | |||
0d06e3ff22 | |||
c914f7bbcf | |||
1b451180c1 | |||
ed061b362b | |||
e1026584c8 | |||
4c615e4fac | |||
7c9d48833b | |||
b60b195aec | |||
db76c8d7f4 | |||
de92740e87 | |||
522bf91c30 | |||
48d3abc1fe | |||
3f6f25e06f | |||
34ba07ee3b | |||
ac37319d20 | |||
b2c6274f74 | |||
402884b5ce | |||
23c99002c0 | |||
ee115b3337 | |||
82f5a141ed | |||
0567168ea9 | |||
c80a15846d | |||
5e194536a8 | |||
43c5ab8ecc | |||
cd295228ef | |||
6c42221620 | |||
0d73a7cd07 | |||
39d5b7edb0 | |||
6fa50a699f | |||
ddaef3e5d5 | |||
c3e9d4a9f8 | |||
7530fb67c8 | |||
19bb56df47 | |||
b0073ac933 | |||
137a89da15 | |||
44da7a302f | |||
4096aae8d4 | |||
d3e026d82a | |||
fa5ecd6495 | |||
af209ad50e | |||
7b89228fa7 | |||
d31a88206c | |||
cd4ed8765b | |||
b6f780d70d | |||
b071a58ca7 | |||
ce554f7718 | |||
99b1cec2e1 | |||
46911a8905 | |||
4eb61529f6 | |||
81abf29bec | |||
85897ef8cd | |||
b824c0b125 | |||
6367c6d116 | |||
a7736d88a9 | |||
049dbf5a78 | |||
4ac92caeb5 | |||
7af3da2a97 | |||
95a62fcdd1 | |||
7872d20554 | |||
a598eb7e98 | |||
c786acc39b | |||
07d8052a57 | |||
db9edb477e | |||
9bd3a6758a | |||
2cb1560bbd | |||
006059438f | |||
84ea3b9788 | |||
b667abde10 | |||
aa10997171 | |||
7880ac1909 | |||
f53848b4b9 | |||
82f2f38680 | |||
dcc2549574 | |||
cfe4753913 | |||
fcb1a7e4d4 | |||
ce76a7dfa5 | |||
7c1de81861 | |||
eddad20acc | |||
7daad57862 | |||
1468049fe9 | |||
3b91e59a79 | |||
3496a30528 | |||
32bad5df15 | |||
3f58eca1be | |||
2350843d1d | |||
a2588a178c | |||
e5292696c4 | |||
34b2a65ccb | |||
3aa3659bc7 | |||
b8117394c0 | |||
fd2bbd2b59 | |||
127c470746 | |||
f2844bdf1a | |||
c5bfef4264 | |||
73863acc12 | |||
19e99204b9 | |||
13f5b94c3e | |||
3a2498401d | |||
53b20ba625 | |||
e7f6f0950f | |||
9fbe1b38a5 | |||
078485134d | |||
67b1766e32 | |||
d4b69ac79c | |||
e61a2d7083 | |||
c03f6604af | |||
572bb38ddb | |||
42c5c0cb9f | |||
e145d2255e | |||
442fa07dd4 | |||
31ae9e1243 | |||
d7f83f8df2 | |||
29e2d4e0c8 | |||
2732d2c844 | |||
c4a037b277 | |||
0e614ad6fc | |||
ca1a8cd617 | |||
ba96a637be | |||
c2cac772e3 | |||
6b7216f4ec | |||
e4fb5946dd | |||
ca61248861 | |||
68d7b4649e | |||
0416aacbbd | |||
bc731e6f8e | |||
ae5d7705bb | |||
b9bd541532 | |||
83639c2535 | |||
25d80f4df1 | |||
74f918d911 | |||
a20efa56eb | |||
f4d83075be | |||
254592c383 | |||
ee23ac0537 | |||
a48cf0bb24 | |||
dae59238cd | |||
8736da1a21 | |||
09a1de69e7 | |||
63d67bc6cb | |||
7099245204 | |||
4d097d2139 | |||
6485bf9ad9 | |||
b7c5b1bfc7 | |||
2b7546e827 | |||
3549ccf4b3 | |||
e2f5752d9a | |||
1a59019fc8 | |||
7bac7bdc3e | |||
19fe58dbac | |||
0a5b30e21c | |||
664818fd29 | |||
d5214e2505 | |||
d906fcea0e | |||
29c8e8b740 | |||
71fec4c555 | |||
5ee36c897d | |||
4aba0c7405 | |||
ed7479c854 | |||
8d3d5f726a | |||
a9a7068818 | |||
1bde7c7718 | |||
17068130bb | |||
81a91d62cb | |||
2575263438 | |||
7f0e25cb50 | |||
a1e4e9c50f | |||
98eff2701b | |||
8b84f87217 | |||
306a1b7bc2 | |||
481214c46e | |||
a5961cbeab | |||
3bf335e0a0 | |||
68f696d165 | |||
1170aed026 | |||
bf1b2066b6 | |||
4c080afb76 | |||
ee1c43ca91 | |||
1c2e6f9e4c | |||
dd379430d9 | |||
42033ebd35 | |||
a086d6e009 | |||
c70bbdab26 | |||
3d956ef554 | |||
329f491c30 | |||
e93701f50e | |||
e680de05ea | |||
56fec674c5 | |||
54d92a027a | |||
319ac3a641 | |||
0a03c46351 | |||
ae1b62e147 | |||
8d567f6b06 | |||
b1ef09675b | |||
2b7b925090 | |||
e0454e95db | |||
91e421d961 | |||
c853afe769 | |||
1a64cb38d5 | |||
ccebd22856 | |||
a1f3b82333 | |||
3dda29781e | |||
a9d297ee31 | |||
e5ff61f201 | |||
d116eb7655 | |||
bc726c6334 | |||
123473dfc8 | |||
d9eccd4fba | |||
5b890847e5 | |||
64c85b9617 | |||
3e3b0bcd8b | |||
4c1eb1b12a | |||
530d03d284 | |||
619fa9b65e | |||
0032235933 | |||
61d1f1ea87 | |||
238d27acdc | |||
2f62271453 | |||
75d5117a2d | |||
b4700af2f5 | |||
374e2b311d | |||
49036abbaf | |||
38ccbac97c | |||
6b4896b8f5 | |||
d582d1cc42 | |||
9e2b8a2aa9 | |||
6fdc733941 | |||
422b390c48 | |||
67a9d1285c | |||
8e26e38ecc | |||
02e12d8575 | |||
fe2954ce08 | |||
1fe4439395 | |||
2ff04d2abd | |||
3f30d3aa89 | |||
129e17b33a | |||
bf2d8c3f4b | |||
b29f04ce01 | |||
d185ebad48 | |||
605df7c91c | |||
ec60cad8bb | |||
6aa0f5a392 |
13
.github/FUNDING.yml
vendored
Normal file
13
.github/FUNDING.yml
vendored
Normal file
@ -0,0 +1,13 @@
|
||||
# These are supported funding model platforms
|
||||
|
||||
#github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
|
||||
#patreon: # Replace with a single Patreon username
|
||||
open_collective: # Replace with a single Open Collective username
|
||||
ko_fi: irmen
|
||||
#tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
|
||||
#community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
|
||||
#liberapay: # Replace with a single Liberapay username
|
||||
#issuehunt: # Replace with a single IssueHunt username
|
||||
#otechie: # Replace with a single Otechie username
|
||||
#lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry
|
||||
#custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
|
41
.github/workflows/all-ci.yml
vendored
Normal file
41
.github/workflows/all-ci.yml
vendored
Normal file
@ -0,0 +1,41 @@
|
||||
name: Build and Test the Prog8 compiler
|
||||
|
||||
on:
|
||||
push:
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: build and install recent 64tass
|
||||
run: |
|
||||
sudo apt-get install -y make build-essential
|
||||
git clone --depth=1 https://github.com/irmen/64tass
|
||||
cd 64tass
|
||||
make -j4
|
||||
sudo make install
|
||||
|
||||
- name: Set up JDK 11
|
||||
uses: actions/setup-java@v4
|
||||
with:
|
||||
java-version: 11
|
||||
distribution: temurin
|
||||
|
||||
- name: Build and test with Gradle
|
||||
run: |
|
||||
./gradlew build shadowJar --no-daemon
|
||||
sha256sum -b compiler/build/libs/*-all.jar > compiler/build/libs/hash.txt
|
||||
|
||||
- name: Create compiler shadowJar artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: prog8-compiler-jar-zipped
|
||||
path: |
|
||||
compiler/build/libs/*-all.jar
|
||||
compiler/build/libs/hash.txt
|
||||
|
10
.gitignore
vendored
10
.gitignore
vendored
@ -1,8 +1,12 @@
|
||||
.idea/workspace.xml
|
||||
.idea/discord.xml
|
||||
.idea/developer-tools.xml
|
||||
.idea/usage.statistics.xml
|
||||
.idea/shelf/
|
||||
build/
|
||||
dist/
|
||||
output/
|
||||
out/
|
||||
.*cache/
|
||||
*.directory
|
||||
*.prg
|
||||
@ -11,23 +15,25 @@ output/
|
||||
*.vm.txt
|
||||
*.vice-mon-list
|
||||
docs/build
|
||||
out/
|
||||
parser/**/*.interp
|
||||
parser/**/*.tokens
|
||||
parser/**/*.java
|
||||
compiler/src/prog8/buildversion/*
|
||||
*.py[cod]
|
||||
*.egg
|
||||
*.egg-info
|
||||
.eggs/
|
||||
/MANIFEST
|
||||
.tox/
|
||||
.kotlin/
|
||||
__pycache__/
|
||||
parser.out
|
||||
parsetab.py
|
||||
.pytest_cache/
|
||||
.attach_pid*
|
||||
compiler/lib/
|
||||
|
||||
.gradle
|
||||
/prog8compiler.jar
|
||||
sd*.img
|
||||
*.d64
|
||||
|
||||
|
8
.idea/codeInsightSettings.xml
generated
Normal file
8
.idea/codeInsightSettings.xml
generated
Normal file
@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="JavaProjectCodeInsightSettings">
|
||||
<excluded-names>
|
||||
<name>kotlin.Result</name>
|
||||
</excluded-names>
|
||||
</component>
|
||||
</project>
|
10
.idea/codeStyles/Project.xml
generated
Normal file
10
.idea/codeStyles/Project.xml
generated
Normal file
@ -0,0 +1,10 @@
|
||||
<component name="ProjectCodeStyleConfiguration">
|
||||
<code_scheme name="Project" version="173">
|
||||
<JetCodeStyleSettings>
|
||||
<option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" />
|
||||
</JetCodeStyleSettings>
|
||||
<codeStyleSettings language="kotlin">
|
||||
<option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" />
|
||||
</codeStyleSettings>
|
||||
</code_scheme>
|
||||
</component>
|
5
.idea/codeStyles/codeStyleConfig.xml
generated
Normal file
5
.idea/codeStyles/codeStyleConfig.xml
generated
Normal file
@ -0,0 +1,5 @@
|
||||
<component name="ProjectCodeStyleConfiguration">
|
||||
<state>
|
||||
<option name="USE_PER_PROJECT_SETTINGS" value="true" />
|
||||
</state>
|
||||
</component>
|
7
.idea/compiler.xml
generated
Normal file
7
.idea/compiler.xml
generated
Normal file
@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="CompilerConfiguration">
|
||||
<option name="BUILD_PROCESS_HEAP_SIZE" value="3000" />
|
||||
<bytecodeTargetLevel target="11" />
|
||||
</component>
|
||||
</project>
|
10
.idea/inspectionProfiles/Project_Default.xml
generated
10
.idea/inspectionProfiles/Project_Default.xml
generated
@ -7,7 +7,17 @@
|
||||
<language isEnabled="false" name="Groovy" />
|
||||
</Languages>
|
||||
</inspection_tool>
|
||||
<inspection_tool class="IncompleteDestructuring" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="PyInterpreterInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="PyPackageRequirementsInspection" enabled="true" level="WARNING" enabled_by_default="true">
|
||||
<option name="ignoredPackages">
|
||||
<value>
|
||||
<list size="1">
|
||||
<item index="0" class="java.lang.String" itemvalue="sphinx_rtd_theme" />
|
||||
</list>
|
||||
</value>
|
||||
</option>
|
||||
</inspection_tool>
|
||||
<inspection_tool class="SpellCheckingInspection" enabled="true" level="TYPO" enabled_by_default="true">
|
||||
<option name="processCode" value="false" />
|
||||
<option name="processLiterals" value="true" />
|
||||
|
13
.idea/kotlinc.xml
generated
13
.idea/kotlinc.xml
generated
@ -1,6 +1,19 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="Kotlin2JsCompilerArguments">
|
||||
<option name="moduleKind" value="plain" />
|
||||
</component>
|
||||
<component name="Kotlin2JvmCompilerArguments">
|
||||
<option name="jvmTarget" value="11" />
|
||||
</component>
|
||||
<component name="KotlinCommonCompilerArguments">
|
||||
<option name="apiVersion" value="2.1" />
|
||||
<option name="languageVersion" value="2.1" />
|
||||
</component>
|
||||
<component name="KotlinCompilerSettings">
|
||||
<option name="additionalArguments" value="-Xwhen-guards" />
|
||||
</component>
|
||||
<component name="KotlinJpsPluginSettings">
|
||||
<option name="version" value="2.1.0" />
|
||||
</component>
|
||||
</project>
|
28
.idea/libraries/KotlinJavaRuntime.xml
generated
28
.idea/libraries/KotlinJavaRuntime.xml
generated
@ -1,19 +1,23 @@
|
||||
<component name="libraryTable">
|
||||
<library name="KotlinJavaRuntime">
|
||||
<library name="KotlinJavaRuntime" type="repository">
|
||||
<properties maven-id="org.jetbrains.kotlin:kotlin-stdlib-jdk8:2.1.0" />
|
||||
<CLASSES>
|
||||
<root url="jar://$KOTLIN_BUNDLED$/lib/kotlin-stdlib.jar!/" />
|
||||
<root url="jar://$KOTLIN_BUNDLED$/lib/kotlin-reflect.jar!/" />
|
||||
<root url="jar://$KOTLIN_BUNDLED$/lib/kotlin-test.jar!/" />
|
||||
<root url="jar://$KOTLIN_BUNDLED$/lib/kotlin-stdlib-jdk7.jar!/" />
|
||||
<root url="jar://$KOTLIN_BUNDLED$/lib/kotlin-stdlib-jdk8.jar!/" />
|
||||
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib-jdk8/2.1.0/kotlin-stdlib-jdk8-2.1.0.jar!/" />
|
||||
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib/2.1.0/kotlin-stdlib-2.1.0.jar!/" />
|
||||
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/annotations/13.0/annotations-13.0.jar!/" />
|
||||
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib-jdk7/2.1.0/kotlin-stdlib-jdk7-2.1.0.jar!/" />
|
||||
</CLASSES>
|
||||
<JAVADOC />
|
||||
<JAVADOC>
|
||||
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib-jdk8/2.1.0/kotlin-stdlib-jdk8-2.1.0-javadoc.jar!/" />
|
||||
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib/2.1.0/kotlin-stdlib-2.1.0-javadoc.jar!/" />
|
||||
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/annotations/13.0/annotations-13.0-javadoc.jar!/" />
|
||||
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib-jdk7/2.1.0/kotlin-stdlib-jdk7-2.1.0-javadoc.jar!/" />
|
||||
</JAVADOC>
|
||||
<SOURCES>
|
||||
<root url="jar://$KOTLIN_BUNDLED$/lib/kotlin-stdlib-sources.jar!/" />
|
||||
<root url="jar://$KOTLIN_BUNDLED$/lib/kotlin-reflect-sources.jar!/" />
|
||||
<root url="jar://$KOTLIN_BUNDLED$/lib/kotlin-test-sources.jar!/" />
|
||||
<root url="jar://$KOTLIN_BUNDLED$/lib/kotlin-stdlib-jdk7-sources.jar!/" />
|
||||
<root url="jar://$KOTLIN_BUNDLED$/lib/kotlin-stdlib-jdk8-sources.jar!/" />
|
||||
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib-jdk8/2.1.0/kotlin-stdlib-jdk8-2.1.0-sources.jar!/" />
|
||||
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib/2.1.0/kotlin-stdlib-2.1.0-sources.jar!/" />
|
||||
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/annotations/13.0/annotations-13.0-sources.jar!/" />
|
||||
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib-jdk7/2.1.0/kotlin-stdlib-jdk7-2.1.0-sources.jar!/" />
|
||||
</SOURCES>
|
||||
</library>
|
||||
</component>
|
9
.idea/libraries/antlr_4_9_complete.xml
generated
9
.idea/libraries/antlr_4_9_complete.xml
generated
@ -1,9 +0,0 @@
|
||||
<component name="libraryTable">
|
||||
<library name="antlr-4.9-complete">
|
||||
<CLASSES>
|
||||
<root url="jar://$PROJECT_DIR$/parser/antlr/lib/antlr-4.9-complete.jar!/" />
|
||||
</CLASSES>
|
||||
<JAVADOC />
|
||||
<SOURCES />
|
||||
</library>
|
||||
</component>
|
18
.idea/libraries/antlr_antlr4.xml
generated
Normal file
18
.idea/libraries/antlr_antlr4.xml
generated
Normal file
@ -0,0 +1,18 @@
|
||||
<component name="libraryTable">
|
||||
<library name="antlr.antlr4" type="repository">
|
||||
<properties maven-id="org.antlr:antlr4:4.13.2">
|
||||
<exclude>
|
||||
<dependency maven-id="com.ibm.icu:icu4j" />
|
||||
</exclude>
|
||||
</properties>
|
||||
<CLASSES>
|
||||
<root url="jar://$MAVEN_REPOSITORY$/org/antlr/antlr4/4.13.2/antlr4-4.13.2.jar!/" />
|
||||
<root url="jar://$MAVEN_REPOSITORY$/org/antlr/antlr4-runtime/4.13.2/antlr4-runtime-4.13.2.jar!/" />
|
||||
<root url="jar://$MAVEN_REPOSITORY$/org/antlr/antlr-runtime/3.5.3/antlr-runtime-3.5.3.jar!/" />
|
||||
<root url="jar://$MAVEN_REPOSITORY$/org/antlr/ST4/4.3.4/ST4-4.3.4.jar!/" />
|
||||
<root url="jar://$MAVEN_REPOSITORY$/org/abego/treelayout/org.abego.treelayout.core/1.0.3/org.abego.treelayout.core-1.0.3.jar!/" />
|
||||
</CLASSES>
|
||||
<JAVADOC />
|
||||
<SOURCES />
|
||||
</library>
|
||||
</component>
|
9
.idea/libraries/antlr_runtime_4_9.xml
generated
9
.idea/libraries/antlr_runtime_4_9.xml
generated
@ -1,9 +0,0 @@
|
||||
<component name="libraryTable">
|
||||
<library name="antlr-runtime-4.9">
|
||||
<CLASSES>
|
||||
<root url="jar://$PROJECT_DIR$/parser/antlr/lib/antlr-runtime-4.9.jar!/" />
|
||||
</CLASSES>
|
||||
<JAVADOC />
|
||||
<SOURCES />
|
||||
</library>
|
||||
</component>
|
9
.idea/libraries/dbus_java_3_2_4.xml
generated
9
.idea/libraries/dbus_java_3_2_4.xml
generated
@ -1,9 +0,0 @@
|
||||
<component name="libraryTable">
|
||||
<library name="dbus-java-3.2.4">
|
||||
<CLASSES>
|
||||
<root url="jar://$PROJECT_DIR$/dbusCompilerService/lib/dbus-java-3.2.4.jar!/" />
|
||||
</CLASSES>
|
||||
<JAVADOC />
|
||||
<SOURCES />
|
||||
</library>
|
||||
</component>
|
13
.idea/libraries/eclipse_lsp4j.xml
generated
Normal file
13
.idea/libraries/eclipse_lsp4j.xml
generated
Normal file
@ -0,0 +1,13 @@
|
||||
<component name="libraryTable">
|
||||
<library name="eclipse.lsp4j" type="repository">
|
||||
<properties maven-id="org.eclipse.lsp4j:org.eclipse.lsp4j:0.23.1" />
|
||||
<CLASSES>
|
||||
<root url="jar://$MAVEN_REPOSITORY$/org/eclipse/lsp4j/org.eclipse.lsp4j/0.23.1/org.eclipse.lsp4j-0.23.1.jar!/" />
|
||||
<root url="jar://$MAVEN_REPOSITORY$/org/eclipse/lsp4j/org.eclipse.lsp4j.jsonrpc/0.23.1/org.eclipse.lsp4j.jsonrpc-0.23.1.jar!/" />
|
||||
<root url="jar://$MAVEN_REPOSITORY$/com/google/code/gson/gson/2.11.0/gson-2.11.0.jar!/" />
|
||||
<root url="jar://$MAVEN_REPOSITORY$/com/google/errorprone/error_prone_annotations/2.27.0/error_prone_annotations-2.27.0.jar!/" />
|
||||
</CLASSES>
|
||||
<JAVADOC />
|
||||
<SOURCES />
|
||||
</library>
|
||||
</component>
|
20
.idea/libraries/io_kotest_assertions_core_jvm.xml
generated
Normal file
20
.idea/libraries/io_kotest_assertions_core_jvm.xml
generated
Normal file
@ -0,0 +1,20 @@
|
||||
<component name="libraryTable">
|
||||
<library name="io.kotest.assertions.core.jvm" type="repository">
|
||||
<properties maven-id="io.kotest:kotest-assertions-core-jvm:5.9.1" />
|
||||
<CLASSES>
|
||||
<root url="jar://$MAVEN_REPOSITORY$/io/kotest/kotest-assertions-core-jvm/5.9.1/kotest-assertions-core-jvm-5.9.1.jar!/" />
|
||||
<root url="jar://$MAVEN_REPOSITORY$/io/kotest/kotest-assertions-shared-jvm/5.9.1/kotest-assertions-shared-jvm-5.9.1.jar!/" />
|
||||
<root url="jar://$MAVEN_REPOSITORY$/io/github/java-diff-utils/java-diff-utils/4.12/java-diff-utils-4.12.jar!/" />
|
||||
<root url="jar://$MAVEN_REPOSITORY$/org/opentest4j/opentest4j/1.3.0/opentest4j-1.3.0.jar!/" />
|
||||
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib/1.9.23/kotlin-stdlib-1.9.23.jar!/" />
|
||||
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/annotations/13.0/annotations-13.0.jar!/" />
|
||||
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlinx/kotlinx-coroutines-jdk8/1.8.0/kotlinx-coroutines-jdk8-1.8.0.jar!/" />
|
||||
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-reflect/1.9.23/kotlin-reflect-1.9.23.jar!/" />
|
||||
<root url="jar://$MAVEN_REPOSITORY$/io/kotest/kotest-common-jvm/5.9.1/kotest-common-jvm-5.9.1.jar!/" />
|
||||
<root url="jar://$MAVEN_REPOSITORY$/io/kotest/kotest-assertions-api-jvm/5.9.1/kotest-assertions-api-jvm-5.9.1.jar!/" />
|
||||
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlinx/kotlinx-coroutines-core-jvm/1.8.0/kotlinx-coroutines-core-jvm-1.8.0.jar!/" />
|
||||
</CLASSES>
|
||||
<JAVADOC />
|
||||
<SOURCES />
|
||||
</library>
|
||||
</component>
|
23
.idea/libraries/io_kotest_framework_datatest.xml
generated
Normal file
23
.idea/libraries/io_kotest_framework_datatest.xml
generated
Normal file
@ -0,0 +1,23 @@
|
||||
<component name="libraryTable">
|
||||
<library name="io.kotest.framework.datatest" type="repository">
|
||||
<properties maven-id="io.kotest:kotest-framework-datatest:5.9.1" />
|
||||
<CLASSES>
|
||||
<root url="jar://$MAVEN_REPOSITORY$/io/kotest/kotest-framework-datatest/5.9.1/kotest-framework-datatest-5.9.1.jar!/" />
|
||||
<root url="jar://$MAVEN_REPOSITORY$/io/kotest/kotest-framework-datatest-jvm/5.9.1/kotest-framework-datatest-jvm-5.9.1.jar!/" />
|
||||
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib/1.9.23/kotlin-stdlib-1.9.23.jar!/" />
|
||||
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/annotations/13.0/annotations-13.0.jar!/" />
|
||||
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlinx/kotlinx-coroutines-core-jvm/1.8.0/kotlinx-coroutines-core-jvm-1.8.0.jar!/" />
|
||||
<root url="jar://$MAVEN_REPOSITORY$/io/kotest/kotest-common-jvm/5.9.1/kotest-common-jvm-5.9.1.jar!/" />
|
||||
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-reflect/1.9.23/kotlin-reflect-1.9.23.jar!/" />
|
||||
<root url="jar://$MAVEN_REPOSITORY$/io/kotest/kotest-framework-api-jvm/5.9.1/kotest-framework-api-jvm-5.9.1.jar!/" />
|
||||
<root url="jar://$MAVEN_REPOSITORY$/io/kotest/kotest-assertions-shared-jvm/5.9.1/kotest-assertions-shared-jvm-5.9.1.jar!/" />
|
||||
<root url="jar://$MAVEN_REPOSITORY$/io/kotest/kotest-assertions-api-jvm/5.9.1/kotest-assertions-api-jvm-5.9.1.jar!/" />
|
||||
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlinx/kotlinx-coroutines-jdk8/1.8.0/kotlinx-coroutines-jdk8-1.8.0.jar!/" />
|
||||
<root url="jar://$MAVEN_REPOSITORY$/io/github/java-diff-utils/java-diff-utils/4.12/java-diff-utils-4.12.jar!/" />
|
||||
<root url="jar://$MAVEN_REPOSITORY$/org/opentest4j/opentest4j/1.3.0/opentest4j-1.3.0.jar!/" />
|
||||
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlinx/kotlinx-coroutines-test-jvm/1.8.0/kotlinx-coroutines-test-jvm-1.8.0.jar!/" />
|
||||
</CLASSES>
|
||||
<JAVADOC />
|
||||
<SOURCES />
|
||||
</library>
|
||||
</component>
|
41
.idea/libraries/io_kotest_runner_junit5_jvm.xml
generated
Normal file
41
.idea/libraries/io_kotest_runner_junit5_jvm.xml
generated
Normal file
@ -0,0 +1,41 @@
|
||||
<component name="libraryTable">
|
||||
<library name="io.kotest.runner.junit5.jvm" type="repository">
|
||||
<properties maven-id="io.kotest:kotest-runner-junit5-jvm:5.9.1" />
|
||||
<CLASSES>
|
||||
<root url="jar://$MAVEN_REPOSITORY$/io/kotest/kotest-runner-junit5-jvm/5.9.1/kotest-runner-junit5-jvm-5.9.1.jar!/" />
|
||||
<root url="jar://$MAVEN_REPOSITORY$/io/kotest/kotest-framework-api-jvm/5.9.1/kotest-framework-api-jvm-5.9.1.jar!/" />
|
||||
<root url="jar://$MAVEN_REPOSITORY$/io/kotest/kotest-assertions-shared-jvm/5.9.1/kotest-assertions-shared-jvm-5.9.1.jar!/" />
|
||||
<root url="jar://$MAVEN_REPOSITORY$/io/github/java-diff-utils/java-diff-utils/4.12/java-diff-utils-4.12.jar!/" />
|
||||
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlinx/kotlinx-coroutines-test-jvm/1.8.0/kotlinx-coroutines-test-jvm-1.8.0.jar!/" />
|
||||
<root url="jar://$MAVEN_REPOSITORY$/io/kotest/kotest-common-jvm/5.9.1/kotest-common-jvm-5.9.1.jar!/" />
|
||||
<root url="jar://$MAVEN_REPOSITORY$/io/kotest/kotest-framework-engine-jvm/5.9.1/kotest-framework-engine-jvm-5.9.1.jar!/" />
|
||||
<root url="jar://$MAVEN_REPOSITORY$/io/github/classgraph/classgraph/4.8.172/classgraph-4.8.172.jar!/" />
|
||||
<root url="jar://$MAVEN_REPOSITORY$/com/github/ajalt/mordant/1.2.1/mordant-1.2.1.jar!/" />
|
||||
<root url="jar://$MAVEN_REPOSITORY$/com/github/ajalt/colormath/1.2.0/colormath-1.2.0.jar!/" />
|
||||
<root url="jar://$MAVEN_REPOSITORY$/org/opentest4j/opentest4j/1.3.0/opentest4j-1.3.0.jar!/" />
|
||||
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlinx/kotlinx-coroutines-debug/1.8.0/kotlinx-coroutines-debug-1.8.0.jar!/" />
|
||||
<root url="jar://$MAVEN_REPOSITORY$/net/java/dev/jna/jna/5.9.0/jna-5.9.0.jar!/" />
|
||||
<root url="jar://$MAVEN_REPOSITORY$/net/java/dev/jna/jna-platform/5.9.0/jna-platform-5.9.0.jar!/" />
|
||||
<root url="jar://$MAVEN_REPOSITORY$/net/bytebuddy/byte-buddy/1.10.9/byte-buddy-1.10.9.jar!/" />
|
||||
<root url="jar://$MAVEN_REPOSITORY$/net/bytebuddy/byte-buddy-agent/1.10.9/byte-buddy-agent-1.10.9.jar!/" />
|
||||
<root url="jar://$MAVEN_REPOSITORY$/io/kotest/kotest-framework-discovery-jvm/5.9.1/kotest-framework-discovery-jvm-5.9.1.jar!/" />
|
||||
<root url="jar://$MAVEN_REPOSITORY$/io/kotest/kotest-assertions-core-jvm/5.9.1/kotest-assertions-core-jvm-5.9.1.jar!/" />
|
||||
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlinx/kotlinx-coroutines-jdk8/1.8.0/kotlinx-coroutines-jdk8-1.8.0.jar!/" />
|
||||
<root url="jar://$MAVEN_REPOSITORY$/io/kotest/kotest-assertions-api-jvm/5.9.1/kotest-assertions-api-jvm-5.9.1.jar!/" />
|
||||
<root url="jar://$MAVEN_REPOSITORY$/io/kotest/kotest-extensions-jvm/5.9.1/kotest-extensions-jvm-5.9.1.jar!/" />
|
||||
<root url="jar://$MAVEN_REPOSITORY$/io/kotest/kotest-framework-concurrency-jvm/5.9.1/kotest-framework-concurrency-jvm-5.9.1.jar!/" />
|
||||
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlinx/kotlinx-coroutines-core-jvm/1.8.0/kotlinx-coroutines-core-jvm-1.8.0.jar!/" />
|
||||
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/annotations/23.0.0/annotations-23.0.0.jar!/" />
|
||||
<root url="jar://$MAVEN_REPOSITORY$/org/junit/platform/junit-platform-engine/1.8.2/junit-platform-engine-1.8.2.jar!/" />
|
||||
<root url="jar://$MAVEN_REPOSITORY$/org/junit/platform/junit-platform-commons/1.8.2/junit-platform-commons-1.8.2.jar!/" />
|
||||
<root url="jar://$MAVEN_REPOSITORY$/org/apiguardian/apiguardian-api/1.1.2/apiguardian-api-1.1.2.jar!/" />
|
||||
<root url="jar://$MAVEN_REPOSITORY$/org/junit/platform/junit-platform-suite-api/1.8.2/junit-platform-suite-api-1.8.2.jar!/" />
|
||||
<root url="jar://$MAVEN_REPOSITORY$/org/junit/platform/junit-platform-launcher/1.8.2/junit-platform-launcher-1.8.2.jar!/" />
|
||||
<root url="jar://$MAVEN_REPOSITORY$/org/junit/jupiter/junit-jupiter-api/5.8.2/junit-jupiter-api-5.8.2.jar!/" />
|
||||
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib/1.9.23/kotlin-stdlib-1.9.23.jar!/" />
|
||||
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-reflect/1.9.23/kotlin-reflect-1.9.23.jar!/" />
|
||||
</CLASSES>
|
||||
<JAVADOC />
|
||||
<SOURCES />
|
||||
</library>
|
||||
</component>
|
10
.idea/libraries/javax_json_api_1_1_4.xml
generated
10
.idea/libraries/javax_json_api_1_1_4.xml
generated
@ -1,10 +0,0 @@
|
||||
<component name="libraryTable">
|
||||
<library name="javax.json-api-1.1.4">
|
||||
<CLASSES>
|
||||
<root url="jar://$PROJECT_DIR$/httpCompilerService/lib/javax.json-api-1.1.4.jar!/" />
|
||||
<root url="jar://$PROJECT_DIR$/httpCompilerService/lib/javax.json-1.1.4.jar!/" />
|
||||
</CLASSES>
|
||||
<JAVADOC />
|
||||
<SOURCES />
|
||||
</library>
|
||||
</component>
|
10
.idea/libraries/jetbrains_kotlinx_cli_jvm.xml
generated
Normal file
10
.idea/libraries/jetbrains_kotlinx_cli_jvm.xml
generated
Normal file
@ -0,0 +1,10 @@
|
||||
<component name="libraryTable">
|
||||
<library name="jetbrains.kotlinx.cli.jvm" type="repository">
|
||||
<properties include-transitive-deps="false" maven-id="org.jetbrains.kotlinx:kotlinx-cli-jvm:0.3.6" />
|
||||
<CLASSES>
|
||||
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlinx/kotlinx-cli-jvm/0.3.6/kotlinx-cli-jvm-0.3.6.jar!/" />
|
||||
</CLASSES>
|
||||
<JAVADOC />
|
||||
<SOURCES />
|
||||
</library>
|
||||
</component>
|
9
.idea/libraries/kotlinx_cli_jvm.xml
generated
9
.idea/libraries/kotlinx_cli_jvm.xml
generated
@ -1,9 +0,0 @@
|
||||
<component name="libraryTable">
|
||||
<library name="kotlinx-cli-jvm">
|
||||
<CLASSES>
|
||||
<root url="jar://$PROJECT_DIR$/compiler/lib/kotlinx-cli-jvm-0.3.1.jar!/" />
|
||||
</CLASSES>
|
||||
<JAVADOC />
|
||||
<SOURCES />
|
||||
</library>
|
||||
</component>
|
20
.idea/libraries/michael_bull_kotlin_result_jvm.xml
generated
Normal file
20
.idea/libraries/michael_bull_kotlin_result_jvm.xml
generated
Normal file
@ -0,0 +1,20 @@
|
||||
<component name="libraryTable">
|
||||
<library name="michael.bull.kotlin.result.jvm" type="repository">
|
||||
<properties maven-id="com.michael-bull.kotlin-result:kotlin-result-jvm:2.0.0" />
|
||||
<CLASSES>
|
||||
<root url="jar://$MAVEN_REPOSITORY$/com/michael-bull/kotlin-result/kotlin-result-jvm/2.0.0/kotlin-result-jvm-2.0.0.jar!/" />
|
||||
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib/1.9.22/kotlin-stdlib-1.9.22.jar!/" />
|
||||
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/annotations/13.0/annotations-13.0.jar!/" />
|
||||
</CLASSES>
|
||||
<JAVADOC>
|
||||
<root url="jar://$MAVEN_REPOSITORY$/com/michael-bull/kotlin-result/kotlin-result-jvm/2.0.0/kotlin-result-jvm-2.0.0-javadoc.jar!/" />
|
||||
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib/1.9.22/kotlin-stdlib-1.9.22-javadoc.jar!/" />
|
||||
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/annotations/13.0/annotations-13.0-javadoc.jar!/" />
|
||||
</JAVADOC>
|
||||
<SOURCES>
|
||||
<root url="jar://$MAVEN_REPOSITORY$/com/michael-bull/kotlin-result/kotlin-result-jvm/2.0.0/kotlin-result-jvm-2.0.0-sources.jar!/" />
|
||||
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib/1.9.22/kotlin-stdlib-1.9.22-sources.jar!/" />
|
||||
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/annotations/13.0/annotations-13.0-sources.jar!/" />
|
||||
</SOURCES>
|
||||
</library>
|
||||
</component>
|
10
.idea/libraries/slf4j_api_1_7_30.xml
generated
10
.idea/libraries/slf4j_api_1_7_30.xml
generated
@ -1,10 +0,0 @@
|
||||
<component name="libraryTable">
|
||||
<library name="slf4j-api-1.7.30">
|
||||
<CLASSES>
|
||||
<root url="jar://$PROJECT_DIR$/httpCompilerService/lib/slf4j-api-1.7.30.jar!/" />
|
||||
<root url="jar://$PROJECT_DIR$/httpCompilerService/lib/slf4j-simple-1.7.30.jar!/" />
|
||||
</CLASSES>
|
||||
<JAVADOC />
|
||||
<SOURCES />
|
||||
</library>
|
||||
</component>
|
12
.idea/libraries/takes_http.xml
generated
12
.idea/libraries/takes_http.xml
generated
@ -1,12 +0,0 @@
|
||||
<component name="libraryTable">
|
||||
<library name="takes-http">
|
||||
<CLASSES>
|
||||
<root url="jar://$PROJECT_DIR$/httpCompilerService/lib/cactoos-0.42.jar!/" />
|
||||
<root url="jar://$PROJECT_DIR$/httpCompilerService/lib/commons-lang3-3.7.jar!/" />
|
||||
<root url="jar://$PROJECT_DIR$/httpCompilerService/lib/commons-text-1.4.jar!/" />
|
||||
<root url="jar://$PROJECT_DIR$/httpCompilerService/lib/takes-1.19.jar!/" />
|
||||
</CLASSES>
|
||||
<JAVADOC />
|
||||
<SOURCES />
|
||||
</library>
|
||||
</component>
|
10
.idea/libraries/unittest_libs.xml
generated
10
.idea/libraries/unittest_libs.xml
generated
@ -1,10 +0,0 @@
|
||||
<component name="libraryTable">
|
||||
<library name="unittest-libs">
|
||||
<CLASSES>
|
||||
<root url="file://$PROJECT_DIR$/compiler/lib" />
|
||||
</CLASSES>
|
||||
<JAVADOC />
|
||||
<SOURCES />
|
||||
<jarDirectory url="file://$PROJECT_DIR$/compiler/lib" recursive="false" />
|
||||
</library>
|
||||
</component>
|
12
.idea/misc.xml
generated
12
.idea/misc.xml
generated
@ -4,19 +4,25 @@
|
||||
<option name="perGrammarGenerationSettings">
|
||||
<list>
|
||||
<PerGrammarGenerationSettings>
|
||||
<option name="fileName" value="$PROJECT_DIR$/parser/antlr/prog8.g4" />
|
||||
<option name="fileName" value="$PROJECT_DIR$/parser/src/main/antlr/Prog8ANTLR.g4" />
|
||||
<option name="autoGen" value="true" />
|
||||
<option name="outputDir" value="$PROJECT_DIR$/parser/src/prog8/parser" />
|
||||
<option name="libDir" value="" />
|
||||
<option name="encoding" value="" />
|
||||
<option name="pkg" value="" />
|
||||
<option name="language" value="" />
|
||||
<option name="language" value="Java" />
|
||||
<option name="generateListener" value="false" />
|
||||
</PerGrammarGenerationSettings>
|
||||
</list>
|
||||
</option>
|
||||
</component>
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_11" default="false" project-jdk-name="Kotlin SDK" project-jdk-type="KotlinSDK">
|
||||
<component name="Black">
|
||||
<option name="sdkName" value="Python 3.11" />
|
||||
</component>
|
||||
<component name="FrameworkDetectionExcludesConfiguration">
|
||||
<type id="Python" />
|
||||
</component>
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_17" default="true" project-jdk-name="openjdk-17" project-jdk-type="JavaSDK">
|
||||
<output url="file://$PROJECT_DIR$/out" />
|
||||
</component>
|
||||
</project>
|
13
.idea/modules.xml
generated
13
.idea/modules.xml
generated
@ -2,13 +2,22 @@
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/beanshell/beanshell.iml" filepath="$PROJECT_DIR$/beanshell/beanshell.iml" />
|
||||
<module fileurl="file://$PROJECT_DIR$/benchmark-program/benchmark-program.iml" filepath="$PROJECT_DIR$/benchmark-program/benchmark-program.iml" />
|
||||
<module fileurl="file://$PROJECT_DIR$/codeCore/codeCore.iml" filepath="$PROJECT_DIR$/codeCore/codeCore.iml" />
|
||||
<module fileurl="file://$PROJECT_DIR$/codeGenCpu6502/codeGenCpu6502.iml" filepath="$PROJECT_DIR$/codeGenCpu6502/codeGenCpu6502.iml" />
|
||||
<module fileurl="file://$PROJECT_DIR$/codeGenExperimental/codeGenExperimental.iml" filepath="$PROJECT_DIR$/codeGenExperimental/codeGenExperimental.iml" />
|
||||
<module fileurl="file://$PROJECT_DIR$/codeGenIntermediate/codeGenIntermediate.iml" filepath="$PROJECT_DIR$/codeGenIntermediate/codeGenIntermediate.iml" />
|
||||
<module fileurl="file://$PROJECT_DIR$/codeGenVirtual/codeGenVirtual.iml" filepath="$PROJECT_DIR$/codeGenVirtual/codeGenVirtual.iml" />
|
||||
<module fileurl="file://$PROJECT_DIR$/codeOptimizers/codeOptimizers.iml" filepath="$PROJECT_DIR$/codeOptimizers/codeOptimizers.iml" />
|
||||
<module fileurl="file://$PROJECT_DIR$/compiler/compiler.iml" filepath="$PROJECT_DIR$/compiler/compiler.iml" />
|
||||
<module fileurl="file://$PROJECT_DIR$/compilerAst/compilerAst.iml" filepath="$PROJECT_DIR$/compilerAst/compilerAst.iml" />
|
||||
<module fileurl="file://$PROJECT_DIR$/dbusCompilerService/dbusCompilerService.iml" filepath="$PROJECT_DIR$/dbusCompilerService/dbusCompilerService.iml" />
|
||||
<module fileurl="file://$PROJECT_DIR$/docs/docs.iml" filepath="$PROJECT_DIR$/docs/docs.iml" />
|
||||
<module fileurl="file://$PROJECT_DIR$/examples/examples.iml" filepath="$PROJECT_DIR$/examples/examples.iml" />
|
||||
<module fileurl="file://$PROJECT_DIR$/httpCompilerService/httpCompilerService.iml" filepath="$PROJECT_DIR$/httpCompilerService/httpCompilerService.iml" />
|
||||
<module fileurl="file://$PROJECT_DIR$/intermediate/intermediate.iml" filepath="$PROJECT_DIR$/intermediate/intermediate.iml" />
|
||||
<module fileurl="file://$PROJECT_DIR$/parser/parser.iml" filepath="$PROJECT_DIR$/parser/parser.iml" />
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/modules/prog8.iml" filepath="$PROJECT_DIR$/.idea/modules/prog8.iml" />
|
||||
<module fileurl="file://$PROJECT_DIR$/virtualmachine/virtualmachine.iml" filepath="$PROJECT_DIR$/virtualmachine/virtualmachine.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
2
.idea/vcs.xml
generated
2
.idea/vcs.xml
generated
@ -3,4 +3,4 @@
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
||||
</project>
|
27
.readthedocs.yaml
Normal file
27
.readthedocs.yaml
Normal file
@ -0,0 +1,27 @@
|
||||
# .readthedocs.yaml
|
||||
# Read the Docs configuration file
|
||||
# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details
|
||||
|
||||
# Required
|
||||
version: 2
|
||||
|
||||
# Set the version of Python and other tools you might need
|
||||
build:
|
||||
os: ubuntu-22.04
|
||||
tools:
|
||||
python: "3.12"
|
||||
|
||||
# Optionally declare the Python requirements required to build your docs
|
||||
python:
|
||||
install:
|
||||
- requirements: docs/requirements.txt
|
||||
|
||||
# Build documentation in the docs/ directory with Sphinx
|
||||
sphinx:
|
||||
configuration: docs/source/conf.py
|
||||
fail_on_warning: true
|
||||
|
||||
# If using Sphinx, optionally build your docs in additional formats such as PDF
|
||||
formats:
|
||||
- pdf
|
||||
- epub
|
11
.travis.yml
11
.travis.yml
@ -1,11 +0,0 @@
|
||||
language: java
|
||||
sudo: false
|
||||
# jdk: openjdk8
|
||||
# dist: xenial
|
||||
|
||||
before_install:
|
||||
- chmod +x ./gradlew
|
||||
|
||||
script:
|
||||
- ./gradlew test
|
||||
|
10
LICENSE
10
LICENSE
@ -1,3 +1,13 @@
|
||||
|
||||
This sofware license is for Prog8 the compiler + associated library files.
|
||||
|
||||
Exception: All output files generated by the compiler (intermediary files
|
||||
and compiled binary programs) are excluded from this; you can do with those
|
||||
whatever you want.
|
||||
|
||||
|
||||
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
|
12
Makefile
Normal file
12
Makefile
Normal file
@ -0,0 +1,12 @@
|
||||
# super simple Makefile to lauch the main gradle targets to build and/or test the prog8 compiler
|
||||
|
||||
.PHONY: all test
|
||||
|
||||
all:
|
||||
gradle installdist installshadowdist
|
||||
@echo "compiler launch script can be found here: compiler/build/install/compiler-shadow/bin/prog8c"
|
||||
|
||||
test:
|
||||
gradle build
|
||||
@echo "compiler launch script can be found here: compiler/build/install/compiler-shadow/bin/prog8c"
|
||||
|
101
README.md
101
README.md
@ -1,5 +1,4 @@
|
||||
[](https://saythanks.io/to/irmen)
|
||||
[](https://travis-ci.org/irmen/prog8)
|
||||
[](https://ko-fi.com/H2H6S0FFF)
|
||||
[](https://prog8.readthedocs.io/)
|
||||
|
||||
Prog8 - Structured Programming Language for 8-bit 6502/65c02 microprocessors
|
||||
@ -7,42 +6,75 @@ Prog8 - Structured Programming Language for 8-bit 6502/65c02 microprocessors
|
||||
|
||||
*Written by Irmen de Jong (irmen@razorvine.net)*
|
||||
|
||||
*Software license: GNU GPL 3.0, see file LICENSE*
|
||||
|
||||
|
||||
This is a structured programming language for the 8-bit 6502/6510/65c02 microprocessor from the late 1970's and 1980's
|
||||
as used in many home computers from that era. It is a medium to low level programming language,
|
||||
which aims to provide many conveniences over raw assembly code (even when using a macro assembler).
|
||||
|
||||
**Want to buy me a coffee or a pizza perhaps?**
|
||||
|
||||
This project was created over the last couple of years by dedicating thousands of hours of my free time to it, to make it the best I possibly can.
|
||||
If you like Prog8, and think it's worth a nice cup of hot coffee or a delicious pizza,
|
||||
you can help me out a little bit over at [ko-fi.com/irmen](https://ko-fi.com/irmen).
|
||||
|
||||
|
||||
Documentation
|
||||
-------------
|
||||
Full documentation (syntax reference, how to use the language and the compiler, etc.) can be found at:
|
||||
https://prog8.readthedocs.io/
|
||||
|
||||
How to get it/build it
|
||||
----------------------
|
||||
|
||||
- Download the latest [official release](https://github.com/irmen/prog8/releases) from github.
|
||||
- Or, if you want/need a bleeding edge development version, you can:
|
||||
- download a build artifact zipfile from a recent [github action build](https://github.com/irmen/prog8/actions).
|
||||
- you can also compile it yourself from source. [Instructions here](https://prog8.readthedocs.io/en/latest/compiling.html).
|
||||
Note that if you are not using *gradle* to build it, you might have to perform some manual
|
||||
tasks once to make it compile fully. These are explained in the linked instructions.
|
||||
- Alternatively, you can also install the compiler as a package on some linux distros:
|
||||
- Arch (via AUR): [`prog8`](https://aur.archlinux.org/packages/prog8)
|
||||
|
||||
Community
|
||||
---------
|
||||
Most of the development on Prog8 and the use of it is currently centered around
|
||||
the [Commander X16](https://www.commanderx16.com/) retro computer. Their [discord server](https://discord.gg/nS2PqEC) contains a small channel
|
||||
dedicated to Prog8. Other than that, use the issue tracker on github.
|
||||
|
||||
|
||||
Software license
|
||||
----------------
|
||||
GNU GPL 3.0 (see file LICENSE), with exception for generated code:
|
||||
|
||||
- The compiler and its libraries are free to use according to the terms of the GNU GPL 3.0
|
||||
- *exception:* the resulting files (intermediate source codes and resulting binary program) created by the compiler
|
||||
are excluded from the GPL and are free to use in whatever way desired, commercially or not.
|
||||
|
||||
|
||||
What does Prog8 provide?
|
||||
------------------------
|
||||
|
||||
- reduction of source code length over raw assembly
|
||||
- modularity, symbol scoping, subroutines
|
||||
- all advantages of a higher level language over having to write assembly code manually
|
||||
- programs run very fast because it's compiled to native machine code
|
||||
- code often is smaller and faster than equivalent C code compiled with CC65 or even LLVM-MOS
|
||||
- modularity, symbol scoping, subroutines. No need for forward declarations.
|
||||
- various data types other than just bytes (16-bit words, floats, strings)
|
||||
- automatic variable allocations, automatic string and array variables and string sharing
|
||||
- subroutines with input parameters and result values
|
||||
- floating point math is supported on certain targets
|
||||
- access to most Kernal ROM routines as external subroutine definitions you can call normally
|
||||
- strings can contain escaped characters but also many symbols directly if they have a petscii equivalent, such as "♠♥♣♦π▚●○╳". Characters like ^, _, \, {, } and | are also accepted and converted to the closest petscii equivalents.
|
||||
- automatic static variable allocations, automatic string and array variables and string sharing
|
||||
- high-level program optimizations
|
||||
- small program boilerplate/compilersupport overhead
|
||||
- sane variable initialization, programs can be restarted again just fine after exiting to basic
|
||||
- conditional branches
|
||||
- floating point operations (requires the C64 Basic ROM routines for this)
|
||||
- 'when' statement to provide a concise jump table alternative to if/elseif chains
|
||||
- structs to group together sets of variables and manipulate them at once
|
||||
- many built-in functions such as ``sin``, ``cos``, ``rnd``, ``abs``, ``min``, ``max``, ``sqrt``, ``msb``, ``rol``, ``ror``, ``swap``, ``sort`` and ``reverse``
|
||||
- programs can be run multiple times without reloading because of automatic variable (re)initializations.
|
||||
- conditional branches that map 1:1 to cpu status flags
|
||||
- ``when`` statement to provide a concise jump table alternative to if/elseif chains
|
||||
- ``in`` expression for concise and efficient multi-value/containment check
|
||||
- ``defer`` statement to help write concise and robust subroutine cleanup logic
|
||||
- several specialized built-in functions such as ``lsb``, ``msb``, ``min``, ``max``, ``rol``, ``ror``
|
||||
- various powerful built-in libraries to do I/O, number conversions, graphics and more
|
||||
- convenience abstractions for low level aspects such as ZeroPage handling, program startup, explicit memory addresses
|
||||
- fast execution speed due to compilation to native assembly code
|
||||
- variables are allocated statically
|
||||
- inline assembly allows you to have full control when every cycle or byte matters
|
||||
- supports the sixteen 'virtual' 16-bit registers R0 .. R15 from the Commander X16, and provides them also on the C64.
|
||||
- encode strings and characters into petscii or screencodes as desired (C64/Cx16)
|
||||
- supports the sixteen 'virtual' 16-bit registers R0 - R15 from the Commander X16 (also available on other targets)
|
||||
- encode strings and characters into petscii or screencodes or even other encodings
|
||||
- Automatic ROM/RAM bank switching on certain compiler targets when calling routines in other banks
|
||||
- 50 Kb of available program RAM size on the C64 by default; because Basic ROM is banked out altogether
|
||||
|
||||
*Rapid edit-compile-run-debug cycle:*
|
||||
|
||||
@ -51,11 +83,15 @@ What does Prog8 provide?
|
||||
- breakpoints, that let the Vice emulator drop into the monitor if execution hits them
|
||||
- source code labels automatically loaded in Vice emulator so it can show them in disassembly
|
||||
|
||||
*Two supported compiler targets* (contributions to improve these or to add support for other machines are welcome!):
|
||||
*Multiple supported compiler targets* (contributions to improve these or to add support for other machines are welcome!):
|
||||
|
||||
- "c64": Commodore-64 (6510 CPU = almost a 6502)
|
||||
- "cx16": [CommanderX16](https://www.commanderx16.com) (65c02 CPU)
|
||||
- If you only use standard kernal and prog8 library routines, it is possible to compile the *exact same program* for both machines (just change the compiler target flag)!
|
||||
- "c64": Commodore-64 (6502 like CPU)
|
||||
- "c128": Commodore-128 (6502 like CPU - the Z80 cpu mode is not supported)
|
||||
- "pet32": Commodore PET (limited support)
|
||||
- "atari": Atari 8 bit such as 800XL (experimental)
|
||||
- "neo": Neo6502 (experimental)
|
||||
- If you only use standard kernal and prog8 library routines, it is possible to compile the *exact same program* for different machines (just change the compiler target flag)
|
||||
|
||||
|
||||
|
||||
@ -72,7 +108,12 @@ IntelliJ IDEA with the Kotlin plugin).
|
||||
|
||||
It's handy to have an emulator (or a real machine perhaps!) to run the programs on. The compiler assumes the presence
|
||||
of the [Vice emulator](http://vice-emu.sourceforge.net/) for the C64 target,
|
||||
and the [x16emu emulator](https://github.com/commanderx16/x16-emulator) for the CommanderX16 target.
|
||||
and a recent emulator version (R42 or newer) for the CommanderX16, such as [x16emu](https://cx16forum.com/forum/viewforum.php?f=30)
|
||||
(preferred, this is the official emulator. If required, source code is [here](https://github.com/X16Community/x16-emulator/)).
|
||||
There is also [Box16](https://github.com/indigodarkwolf/box16) which has powerful debugging features.
|
||||
|
||||
**Syntax highlighting:** for a few different editors, syntax highlighting definition files are provided.
|
||||
Look in the [syntax-files](https://github.com/irmen/prog8/tree/master/syntax-files) directory in the github repository to find them.
|
||||
|
||||
|
||||
Example code
|
||||
@ -82,14 +123,13 @@ This code calculates prime numbers using the Sieve of Eratosthenes algorithm::
|
||||
|
||||
%import textio
|
||||
%zeropage basicsafe
|
||||
|
||||
|
||||
main {
|
||||
|
||||
ubyte[256] sieve
|
||||
bool[256] sieve
|
||||
ubyte candidate_prime = 2 ; is increased in the loop
|
||||
|
||||
sub start() {
|
||||
sys.memset(sieve, 256, false) ; clear the sieve
|
||||
sys.memset(sieve, 256, 0) ; clear the sieve
|
||||
txt.print("prime numbers up to 255:\n\n")
|
||||
ubyte amount=0
|
||||
repeat {
|
||||
@ -125,9 +165,6 @@ This code calculates prime numbers using the Sieve of Eratosthenes algorithm::
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
when compiled an ran on a C-64 you'll get:
|
||||
|
||||

|
||||
|
24
beanshell/beanshell.iml
Normal file
24
beanshell/beanshell.iml
Normal file
@ -0,0 +1,24 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="JAVA_MODULE" version="4">
|
||||
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
||||
<exclude-output />
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build" />
|
||||
</content>
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
<orderEntry type="library" name="KotlinJavaRuntime" level="project" />
|
||||
<orderEntry type="library" name="jetbrains.kotlinx.cli.jvm" level="project" />
|
||||
<orderEntry type="library" name="michael.bull.kotlin.result.jvm" level="project" />
|
||||
<orderEntry type="module-library">
|
||||
<library>
|
||||
<CLASSES>
|
||||
<root url="jar://$MODULE_DIR$/lib/bsh-3.0.0-SNAPSHOT.jar!/" />
|
||||
</CLASSES>
|
||||
<JAVADOC />
|
||||
<SOURCES />
|
||||
</library>
|
||||
</orderEntry>
|
||||
</component>
|
||||
</module>
|
65
beanshell/build.gradle.kts
Normal file
65
beanshell/build.gradle.kts
Normal file
@ -0,0 +1,65 @@
|
||||
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
|
||||
|
||||
plugins {
|
||||
id("application")
|
||||
kotlin("jvm")
|
||||
}
|
||||
|
||||
val serverMainClassName = "prog8lsp.MainKt"
|
||||
val applicationName = "prog8-beanshell"
|
||||
|
||||
application {
|
||||
mainClass.set(serverMainClassName)
|
||||
description = "Code completions, diagnostics and more for Prog8"
|
||||
// applicationDefaultJvmArgs = listOf("-DkotlinLanguageServer.version=$version")
|
||||
applicationDistribution.into("bin") {
|
||||
filePermissions {
|
||||
user {
|
||||
read=true
|
||||
execute=true
|
||||
write=true
|
||||
}
|
||||
other.execute = true
|
||||
group.execute = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation(files("lib/bsh-3.0.0-SNAPSHOT.jar"))
|
||||
}
|
||||
|
||||
configurations.forEach { config ->
|
||||
config.resolutionStrategy {
|
||||
preferProjectModules()
|
||||
}
|
||||
}
|
||||
|
||||
sourceSets.main {
|
||||
java.srcDir("src")
|
||||
resources.srcDir("resources")
|
||||
}
|
||||
|
||||
tasks.startScripts {
|
||||
applicationName = "prog8-beanshell"
|
||||
}
|
||||
|
||||
tasks.register<Exec>("fixFilePermissions") {
|
||||
// When running on macOS or Linux the start script
|
||||
// needs executable permissions to run.
|
||||
|
||||
onlyIf { !System.getProperty("os.name").lowercase().contains("windows") }
|
||||
commandLine("chmod", "+x", "${tasks.installDist.get().destinationDir}/bin/prog8-beanshell")
|
||||
}
|
||||
|
||||
tasks.installDist {
|
||||
finalizedBy("fixFilePermissions")
|
||||
}
|
||||
|
||||
tasks.build {
|
||||
finalizedBy("installDist")
|
||||
}
|
BIN
beanshell/lib/bsh-3.0.0-SNAPSHOT.jar
Normal file
BIN
beanshell/lib/bsh-3.0.0-SNAPSHOT.jar
Normal file
Binary file not shown.
48
beanshell/src/prog8beanshell/CommandLineReader.kt
Normal file
48
beanshell/src/prog8beanshell/CommandLineReader.kt
Normal file
@ -0,0 +1,48 @@
|
||||
package prog8beanshell
|
||||
|
||||
import java.io.FilterReader
|
||||
import java.io.Reader
|
||||
|
||||
|
||||
class CommandLineReader(val input: Reader): FilterReader(input) {
|
||||
private val normal = 0
|
||||
private val lastCharNL = 1
|
||||
private val sentSemi = 2
|
||||
private var state = lastCharNL
|
||||
|
||||
override fun read(): Int {
|
||||
if (state == sentSemi) {
|
||||
this.state = lastCharNL
|
||||
return 10
|
||||
} else {
|
||||
var b = input.read()
|
||||
while(b==13) b = input.read()
|
||||
|
||||
if (b == 10) {
|
||||
if (this.state == lastCharNL) {
|
||||
b = 59
|
||||
this.state = sentSemi
|
||||
} else {
|
||||
this.state = lastCharNL
|
||||
}
|
||||
} else {
|
||||
this.state = normal
|
||||
}
|
||||
|
||||
return b
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
override fun read(buff: CharArray, off: Int, len: Int): Int {
|
||||
val b = read()
|
||||
if (b == -1) {
|
||||
return -1
|
||||
} else {
|
||||
buff[off] = b.toChar()
|
||||
return 1
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
23
beanshell/src/prog8beanshell/Main.kt
Normal file
23
beanshell/src/prog8beanshell/Main.kt
Normal file
@ -0,0 +1,23 @@
|
||||
package prog8beanshell
|
||||
|
||||
import bsh.FileReader
|
||||
import bsh.Interpreter
|
||||
|
||||
|
||||
class BeanshellInterpreter {
|
||||
|
||||
fun run(symbols: Map<String, Any>) {
|
||||
val interpreter = Interpreter(CommandLineReader(FileReader(System.`in`)), System.out, System.err, true)
|
||||
interpreter.setExitOnEOF(false)
|
||||
symbols.forEach { (name, value) -> interpreter.set(name, value) }
|
||||
interpreter.run()
|
||||
}
|
||||
}
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
val i = BeanshellInterpreter()
|
||||
i.run(mapOf(
|
||||
"env" to System.getenv(),
|
||||
"args" to args
|
||||
))
|
||||
}
|
10
benchmark-program/Makefile
Normal file
10
benchmark-program/Makefile
Normal file
@ -0,0 +1,10 @@
|
||||
.PHONY: clean run
|
||||
|
||||
run:
|
||||
prog8c -target cx16 benchmark.p8
|
||||
x16emu -run -prg benchmark.prg -warp
|
||||
|
||||
clean:
|
||||
rm -f *.prg *.PRG *.asm *.vice-* *.BIN *.PAL *.zip *.7z
|
||||
|
||||
|
109
benchmark-program/b_3d.p8
Normal file
109
benchmark-program/b_3d.p8
Normal file
@ -0,0 +1,109 @@
|
||||
%import textio
|
||||
%import math
|
||||
|
||||
rotate3d {
|
||||
const ubyte WIDTH = 40
|
||||
const ubyte HEIGHT = 30
|
||||
|
||||
sub benchmark(uword max_time) -> uword {
|
||||
|
||||
uword anglex
|
||||
uword angley
|
||||
uword anglez
|
||||
uword frames
|
||||
|
||||
txt.nl()
|
||||
cbm.SETTIM(0,0,0)
|
||||
|
||||
while cbm.RDTIM16()<max_time {
|
||||
matrix_math.rotate_vertices(msb(anglex), msb(angley), msb(anglez))
|
||||
draw_edges() ; doesn't really draw anything in the benchmark, but does do the screen calculations
|
||||
anglex+=500
|
||||
angley+=215
|
||||
anglez+=453
|
||||
frames++
|
||||
}
|
||||
|
||||
return frames
|
||||
}
|
||||
|
||||
sub draw_edges() {
|
||||
|
||||
; plot the points of the 3d cube
|
||||
; first the points on the back, then the points on the front (painter algorithm)
|
||||
|
||||
ubyte @zp i
|
||||
word @zp rz
|
||||
word @zp persp
|
||||
byte @shared sx
|
||||
byte @shared sy
|
||||
|
||||
for i in 0 to len(matrix_math.xcoor)-1 {
|
||||
rz = matrix_math.rotatedz[i]
|
||||
if rz >= 10 {
|
||||
persp = 600 + rz/64
|
||||
sx = matrix_math.rotatedx[i] / persp as byte + WIDTH/2
|
||||
sy = matrix_math.rotatedy[i] / persp as byte + HEIGHT/2
|
||||
;; txt.setcc(sx as ubyte, sy as ubyte, 46, 7)
|
||||
}
|
||||
}
|
||||
|
||||
for i in 0 to len(matrix_math.xcoor)-1 {
|
||||
rz = matrix_math.rotatedz[i]
|
||||
if rz < 10 {
|
||||
persp = 600 + rz/64
|
||||
sx = matrix_math.rotatedx[i] / persp as byte + WIDTH/2
|
||||
sy = matrix_math.rotatedy[i] / persp as byte + HEIGHT/2
|
||||
;; txt.setcc(sx as ubyte, sy as ubyte, 81, 7)
|
||||
}
|
||||
}
|
||||
|
||||
txt.chrout('.')
|
||||
}
|
||||
}
|
||||
|
||||
matrix_math {
|
||||
; vertices
|
||||
word[] xcoor = [ -40, -40, -40, -40, 40, 40, 40, 40 ]
|
||||
word[] ycoor = [ -40, -40, 40, 40, -40, -40, 40, 40 ]
|
||||
word[] zcoor = [ -40, 40, -40, 40, -40, 40, -40, 40 ]
|
||||
|
||||
; storage for rotated coordinates
|
||||
word[len(xcoor)] rotatedx
|
||||
word[len(ycoor)] rotatedy
|
||||
word[len(zcoor)] rotatedz
|
||||
|
||||
sub rotate_vertices(ubyte ax, ubyte ay, ubyte az) {
|
||||
; rotate around origin (0,0,0)
|
||||
|
||||
; set up the 3d rotation matrix values
|
||||
word wcosa = math.cos8(ax)
|
||||
word wsina = math.sin8(ax)
|
||||
word wcosb = math.cos8(ay)
|
||||
word wsinb = math.sin8(ay)
|
||||
word wcosc = math.cos8(az)
|
||||
word wsinc = math.sin8(az)
|
||||
|
||||
word wcosa_sinb = wcosa*wsinb / 128
|
||||
word wsina_sinb = wsina*wsinb / 128
|
||||
|
||||
word Axx = wcosa*wcosb / 128
|
||||
word Axy = (wcosa_sinb*wsinc - wsina*wcosc) / 128
|
||||
word Axz = (wcosa_sinb*wcosc + wsina*wsinc) / 128
|
||||
word Ayx = wsina*wcosb / 128
|
||||
word Ayy = (wsina_sinb*wsinc + wcosa*wcosc) / 128
|
||||
word Ayz = (wsina_sinb*wcosc - wcosa*wsinc) / 128
|
||||
word Azx = -wsinb
|
||||
word Azy = wcosb*wsinc / 128
|
||||
word Azz = wcosb*wcosc / 128
|
||||
|
||||
ubyte @zp i
|
||||
for i in 0 to len(xcoor)-1 {
|
||||
; don't normalize by dividing by 128, instead keep some precision for perspective calc later
|
||||
rotatedx[i] = Axx*xcoor[i] + Axy*ycoor[i] + Axz*zcoor[i]
|
||||
rotatedy[i] = Ayx*xcoor[i] + Ayy*ycoor[i] + Ayz*zcoor[i]
|
||||
rotatedz[i] = Azx*xcoor[i] + Azy*ycoor[i] + Azz*zcoor[i]
|
||||
}
|
||||
}
|
||||
|
||||
}
|
89
benchmark-program/b_adpcm.p8
Normal file
89
benchmark-program/b_adpcm.p8
Normal file
@ -0,0 +1,89 @@
|
||||
adpcm {
|
||||
|
||||
sub decode_benchmark(uword max_time) -> uword {
|
||||
uword num_blocks
|
||||
txt.nl()
|
||||
cbm.SETTIM(0,0,0)
|
||||
|
||||
while cbm.RDTIM16()<max_time {
|
||||
adpcm.init(0,0)
|
||||
uword @requirezp nibbles_ptr = $a000 ; for benchmark purposes, the exact nibbles don't really matter, so we just take the basic ROM as input
|
||||
repeat 252/2 {
|
||||
unroll 2 {
|
||||
ubyte @zp nibble = @(nibbles_ptr)
|
||||
adpcm.decode_nibble(nibble & 15) ; first word (note: upper nibble needs to be zero!)
|
||||
adpcm.decode_nibble(nibble>>4) ; second word (note: upper nibble is zero, after the shifts.)
|
||||
nibbles_ptr++
|
||||
}
|
||||
}
|
||||
num_blocks++
|
||||
txt.chrout('.')
|
||||
}
|
||||
|
||||
return num_blocks
|
||||
}
|
||||
|
||||
; IMA ADPCM decoder. Supports mono and stereo streams.
|
||||
|
||||
byte[] t_index = [ -1, -1, -1, -1, 2, 4, 6, 8, -1, -1, -1, -1, 2, 4, 6, 8]
|
||||
uword[] t_step = [
|
||||
7, 8, 9, 10, 11, 12, 13, 14,
|
||||
16, 17, 19, 21, 23, 25, 28, 31,
|
||||
34, 37, 41, 45, 50, 55, 60, 66,
|
||||
73, 80, 88, 97, 107, 118, 130, 143,
|
||||
157, 173, 190, 209, 230, 253, 279, 307,
|
||||
337, 371, 408, 449, 494, 544, 598, 658,
|
||||
724, 796, 876, 963, 1060, 1166, 1282, 1411,
|
||||
1552, 1707, 1878, 2066, 2272, 2499, 2749, 3024,
|
||||
3327, 3660, 4026, 4428, 4871, 5358, 5894, 6484,
|
||||
7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899,
|
||||
15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794,
|
||||
32767]
|
||||
|
||||
uword @requirezp predict ; decoded 16 bit pcm sample for first channel.
|
||||
ubyte @requirezp index
|
||||
uword @requirezp pstep
|
||||
|
||||
sub init(uword startPredict, ubyte startIndex) {
|
||||
; initialize first decoding channel.
|
||||
predict = startPredict
|
||||
index = startIndex
|
||||
pstep = t_step[index]
|
||||
}
|
||||
|
||||
sub decode_nibble(ubyte @zp nibble) {
|
||||
; Decoder for a single nibble for the first channel. (value of 'nibble' needs to be strictly 0-15 !)
|
||||
; This is the hotspot of the decoder algorithm!
|
||||
; Note that the generated assembly from this is pretty efficient,
|
||||
; rewriting it by hand in asm seems to improve it only ~10%.
|
||||
cx16.r0s = 0 ; difference
|
||||
if nibble & %0100 !=0
|
||||
cx16.r0s += pstep
|
||||
pstep >>= 1
|
||||
if nibble & %0010 !=0
|
||||
cx16.r0s += pstep
|
||||
pstep >>= 1
|
||||
if nibble & %0001 !=0
|
||||
cx16.r0s += pstep
|
||||
pstep >>= 1
|
||||
cx16.r0s += pstep
|
||||
if nibble & %1000 !=0
|
||||
predict -= cx16.r0
|
||||
else
|
||||
predict += cx16.r0
|
||||
|
||||
; NOTE: the original C/Python code uses a 32 bits prediction value and clips it to a 16 bit word
|
||||
; but for speed reasons we only work with 16 bit words here all the time (with possible clipping error)
|
||||
; if predicted > 32767:
|
||||
; predicted = 32767
|
||||
; elif predicted < -32767:
|
||||
; predicted = - 32767
|
||||
|
||||
index += t_index[nibble] as ubyte
|
||||
if_neg
|
||||
index = 0
|
||||
else if index >= len(t_step)-1
|
||||
index = len(t_step)-1
|
||||
pstep = t_step[index]
|
||||
}
|
||||
}
|
111
benchmark-program/b_circles.p8
Normal file
111
benchmark-program/b_circles.p8
Normal file
@ -0,0 +1,111 @@
|
||||
%import gfx_lores
|
||||
%import math
|
||||
|
||||
circles {
|
||||
const ubyte MAX_NUM_CIRCLES = 80
|
||||
const ubyte GROWTH_RATE = 4
|
||||
uword[MAX_NUM_CIRCLES] circle_x
|
||||
uword[MAX_NUM_CIRCLES] circle_y
|
||||
ubyte[MAX_NUM_CIRCLES] circle_radius
|
||||
ubyte color
|
||||
uword total_num_circles
|
||||
|
||||
sub draw(bool use_kernal, uword max_time) -> uword {
|
||||
if use_kernal
|
||||
void cx16.set_screen_mode(128)
|
||||
else
|
||||
gfx_lores.graphics_mode()
|
||||
|
||||
math.rndseed(12345,6789)
|
||||
cbm.SETTIM(0,0,0)
|
||||
|
||||
total_num_circles = 0
|
||||
color = 16
|
||||
|
||||
while cbm.RDTIM16()<max_time {
|
||||
if use_kernal {
|
||||
cx16.GRAPH_set_colors(0,0,0)
|
||||
cx16.GRAPH_clear()
|
||||
}
|
||||
else
|
||||
gfx_lores.clear_screen(0)
|
||||
total_num_circles += draw_circles(use_kernal, max_time)
|
||||
}
|
||||
|
||||
if use_kernal
|
||||
void cx16.set_screen_mode(3)
|
||||
else {
|
||||
gfx_lores.text_mode()
|
||||
}
|
||||
|
||||
return total_num_circles
|
||||
}
|
||||
|
||||
sub draw_circles(bool use_kernal, uword max_time) -> uword {
|
||||
uword @zp x
|
||||
uword @zp y
|
||||
ubyte @zp radius
|
||||
|
||||
ubyte num_circles
|
||||
|
||||
while num_circles<MAX_NUM_CIRCLES and cbm.RDTIM16()<max_time {
|
||||
x = math.rndw() % 320
|
||||
y = math.rndw() % 240
|
||||
radius = GROWTH_RATE
|
||||
if not_colliding() {
|
||||
while not_edge() and not_colliding() {
|
||||
radius += GROWTH_RATE
|
||||
}
|
||||
radius -= GROWTH_RATE
|
||||
if radius>0 {
|
||||
color++
|
||||
if color==0
|
||||
color=16
|
||||
if use_kernal {
|
||||
cx16.GRAPH_set_colors(color, 255-color, 0)
|
||||
cx16.GRAPH_draw_oval(x-radius, y-radius, radius*2, radius*2, true)
|
||||
}
|
||||
else
|
||||
gfx_lores.disc(x, y as ubyte, radius, color)
|
||||
circle_x[num_circles] = x
|
||||
circle_y[num_circles] = y
|
||||
circle_radius[num_circles] = radius
|
||||
num_circles++
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return num_circles
|
||||
|
||||
sub not_colliding() -> bool {
|
||||
if num_circles==0
|
||||
return true
|
||||
ubyte @zp c
|
||||
for c in 0 to num_circles-1 {
|
||||
if distance(c) < (radius as uword) + circle_radius[c]
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
sub distance(ubyte cix) -> uword {
|
||||
word dx = x as word - circle_x[cix]
|
||||
word dy = y as word - circle_y[cix]
|
||||
uword sqx = dx*dx as uword
|
||||
uword sqy = dy*dy as uword
|
||||
return sqrt(sqx + sqy)
|
||||
}
|
||||
|
||||
sub not_edge() -> bool {
|
||||
if x as word - radius < 0
|
||||
return false
|
||||
if x + radius >= 320
|
||||
return false
|
||||
if y as word - radius < 0
|
||||
return false
|
||||
if y + radius >= 240
|
||||
return false
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
123
benchmark-program/b_life.p8
Normal file
123
benchmark-program/b_life.p8
Normal file
@ -0,0 +1,123 @@
|
||||
; conway's game of life.
|
||||
|
||||
%import math
|
||||
%import textio
|
||||
|
||||
life {
|
||||
const ubyte WIDTH = 40
|
||||
const ubyte HEIGHT = 30
|
||||
const uword STRIDE = $0002+WIDTH
|
||||
uword world1 = memory("world1", (WIDTH+2)*(HEIGHT+2), 0)
|
||||
uword world2 = memory("world2", (WIDTH+2)*(HEIGHT+2), 0)
|
||||
uword @requirezp active_world = world1
|
||||
|
||||
sub benchmark(uword max_time) -> uword {
|
||||
txt.clear_screen()
|
||||
sys.memset(world1, (WIDTH+2)*(HEIGHT+2), 0)
|
||||
sys.memset(world2, (WIDTH+2)*(HEIGHT+2), 0)
|
||||
|
||||
set_start_gen()
|
||||
|
||||
uword gen
|
||||
cbm.SETTIM(0,0,0)
|
||||
|
||||
while cbm.RDTIM16()<max_time {
|
||||
next_gen()
|
||||
gen++
|
||||
}
|
||||
|
||||
return gen
|
||||
}
|
||||
|
||||
sub set_start_gen() {
|
||||
|
||||
; some way to set a custom start generation:
|
||||
; str start_gen = " " +
|
||||
; " " +
|
||||
; " " +
|
||||
; " ** " +
|
||||
; " * * " +
|
||||
; " * " +
|
||||
; " * * " +
|
||||
; " ****** " +
|
||||
; " " +
|
||||
; " " +
|
||||
; " " +
|
||||
; " " +
|
||||
; " " +
|
||||
; " " +
|
||||
; " " +
|
||||
; " "
|
||||
;
|
||||
; for y in 0 to 15 {
|
||||
; for x in 0 to 15 {
|
||||
; if start_gen[y*16 + x]=='*'
|
||||
; active_world[offset + x] = 1
|
||||
; }
|
||||
; offset += STRIDE
|
||||
; }
|
||||
|
||||
; randomize whole world
|
||||
math.rndseed(12345,9999)
|
||||
uword offset = STRIDE+1
|
||||
ubyte x
|
||||
ubyte y
|
||||
for y in 0 to HEIGHT-1 {
|
||||
for x in 0 to WIDTH-1 {
|
||||
active_world[offset+x] = math.rnd() & 1
|
||||
}
|
||||
offset += STRIDE
|
||||
}
|
||||
}
|
||||
|
||||
sub next_gen() {
|
||||
const ubyte DXOFFSET = 0
|
||||
const ubyte DYOFFSET = 0
|
||||
ubyte[2] cell_chars = [sc:' ', sc:'●']
|
||||
|
||||
uword @requirezp new_world = world1
|
||||
if active_world == world1
|
||||
new_world = world2
|
||||
|
||||
; To avoid re-calculating word index lookups into the new- and active world arrays,
|
||||
; we calculate the required pointer values upfront.
|
||||
; Inside the loop we can use ptr+x just fine (results in efficient LDA (ptr),Y instruction because x is a byte type),
|
||||
; and for each row we simply add the stride to the pointer.
|
||||
; It's more readable to use active_world[offset] etc, but offset is a word value, and this produces
|
||||
; inefficient assembly code because we can't use a register indexed mode in this case. Costly inside a loop.
|
||||
|
||||
uword @requirezp new_world_ptr = new_world + STRIDE+1-DXOFFSET
|
||||
uword @requirezp active_world_ptr = active_world + STRIDE+1-DXOFFSET
|
||||
|
||||
ubyte x
|
||||
ubyte y
|
||||
for y in DYOFFSET to HEIGHT+DYOFFSET-1 {
|
||||
|
||||
cx16.vaddr_autoincr(1, $b000 + 256*y, 0, 2) ; allows us to use simple Vera data byte assigns later instead of setchr() calls
|
||||
|
||||
for x in DXOFFSET to WIDTH+DXOFFSET-1 {
|
||||
; count the living neighbors
|
||||
ubyte cell = @(active_world_ptr + x)
|
||||
uword @requirezp ptr = active_world_ptr + x - STRIDE - 1
|
||||
ubyte neighbors = @(ptr) + @(ptr+1) + @(ptr+2) +
|
||||
@(ptr+STRIDE) + cell + @(ptr+STRIDE+2) +
|
||||
@(ptr+STRIDE*2) + @(ptr+STRIDE*2+1) + @(ptr+STRIDE*2+2)
|
||||
|
||||
; apply game of life rules
|
||||
if neighbors==3
|
||||
cell=1
|
||||
else if neighbors!=4
|
||||
cell=0
|
||||
@(new_world_ptr + x) = cell
|
||||
|
||||
; draw new cell
|
||||
; txt.setchr(x,y,cell_chars[cell])
|
||||
cx16.VERA_DATA0 = cell_chars[cell]
|
||||
}
|
||||
active_world_ptr += STRIDE
|
||||
new_world_ptr += STRIDE
|
||||
}
|
||||
|
||||
active_world = new_world
|
||||
}
|
||||
}
|
54
benchmark-program/b_mandelbrot.p8
Normal file
54
benchmark-program/b_mandelbrot.p8
Normal file
@ -0,0 +1,54 @@
|
||||
%import textio
|
||||
%import floats
|
||||
|
||||
mandelbrot {
|
||||
const ubyte width = 39
|
||||
const ubyte height = 29
|
||||
const ubyte max_iter = 15
|
||||
|
||||
sub calc(uword max_time) -> uword {
|
||||
uword num_pixels
|
||||
ubyte pixelx
|
||||
ubyte pixely
|
||||
|
||||
txt.home()
|
||||
cbm.SETTIM(0,0,0)
|
||||
|
||||
while cbm.RDTIM16() < max_time {
|
||||
for pixely in 0 to height-1 {
|
||||
float yy = (pixely as float)/0.40/height - 1.3
|
||||
|
||||
for pixelx in 0 to width-1 {
|
||||
float xx = (pixelx as float)/0.32/width - 2.2
|
||||
|
||||
float xsquared = 0.0
|
||||
float ysquared = 0.0
|
||||
float x = 0.0
|
||||
float y = 0.0
|
||||
ubyte iter = 0
|
||||
|
||||
while iter<max_iter and xsquared+ysquared<4.0 {
|
||||
y = x*y*2.0 + yy
|
||||
x = xsquared - ysquared + xx
|
||||
xsquared = x*x
|
||||
ysquared = y*y
|
||||
iter++
|
||||
}
|
||||
txt.color2(1, max_iter-iter)
|
||||
txt.spc()
|
||||
num_pixels++
|
||||
|
||||
if cbm.RDTIM16()>=max_time
|
||||
goto finished
|
||||
}
|
||||
txt.nl()
|
||||
}
|
||||
|
||||
txt.clear_screen()
|
||||
}
|
||||
|
||||
finished:
|
||||
txt.color2(1, 6)
|
||||
return num_pixels
|
||||
}
|
||||
}
|
343
benchmark-program/b_maze.p8
Normal file
343
benchmark-program/b_maze.p8
Normal file
@ -0,0 +1,343 @@
|
||||
%import textio
|
||||
%import math
|
||||
|
||||
; Even though prog8 only has support for extremely limited recursion,
|
||||
; you can write recursive algorithms with a bit of extra work by building your own explicit stack structure.
|
||||
; This program shows a depth-first maze generation algorithm (1 possible path from start to finish),
|
||||
; and a depth-first maze solver algorithm, both using a stack to store the path taken.
|
||||
|
||||
; Note: this program can be compiled for multiple target systems.
|
||||
|
||||
maze {
|
||||
uword score
|
||||
|
||||
sub bench(uword max_time) -> uword {
|
||||
txt.nl()
|
||||
score=0
|
||||
math.rndseed(2345,44332)
|
||||
cbm.SETTIM(0,0,0)
|
||||
while cbm.RDTIM16()<max_time {
|
||||
maze.initialize()
|
||||
maze.drawStartFinish()
|
||||
if maze.generate(max_time) {
|
||||
maze.openpassages()
|
||||
maze.drawStartFinish()
|
||||
if maze.solve(max_time) {
|
||||
maze.drawStartFinish()
|
||||
} else break
|
||||
} else break
|
||||
}
|
||||
|
||||
return score
|
||||
}
|
||||
|
||||
const uword screenwidth = 40
|
||||
const uword screenheight = 30
|
||||
|
||||
const ubyte numCellsHoriz = (screenwidth-1) / 2
|
||||
const ubyte numCellsVert = (screenheight-1) / 2
|
||||
|
||||
; maze start and finish cells
|
||||
const ubyte startCx = 0
|
||||
const ubyte startCy = 0
|
||||
const ubyte finishCx = numCellsHoriz-1
|
||||
const ubyte finishCy = numCellsVert-1
|
||||
|
||||
; cell properties
|
||||
const ubyte STONE = 128
|
||||
const ubyte WALKED = 64
|
||||
const ubyte BACKTRACKED = 32
|
||||
const ubyte UP = 1
|
||||
const ubyte RIGHT = 2
|
||||
const ubyte DOWN = 4
|
||||
const ubyte LEFT = 8
|
||||
const ubyte WALLCOLOR = 12
|
||||
const ubyte EMPTYCOLOR = 0
|
||||
|
||||
; unfortunately on larger screens (cx16), the number of cells exceeds 256 and doesn't fit in a regular array anymore.
|
||||
uword cells = memory("cells", numCellsHoriz*numCellsVert, 0)
|
||||
|
||||
ubyte[256] cx_stack
|
||||
ubyte[256] cy_stack
|
||||
ubyte stackptr
|
||||
|
||||
ubyte[4] directionflags = [LEFT,RIGHT,UP,DOWN]
|
||||
|
||||
sub generate(uword max_time) -> bool {
|
||||
ubyte cx = startCx
|
||||
ubyte cy = startCy
|
||||
|
||||
stackptr = 0
|
||||
@(celladdr(cx,cy)) &= ~STONE
|
||||
drawCell(cx, cy)
|
||||
uword cells_to_carve = numCellsHoriz * numCellsVert - 1
|
||||
|
||||
while cbm.RDTIM16()<max_time {
|
||||
carve_restart_after_repath:
|
||||
ubyte direction = choose_uncarved_direction()
|
||||
if direction==0 {
|
||||
;backtrack
|
||||
stackptr--
|
||||
if stackptr==255 {
|
||||
; stack empty.
|
||||
; repath if we are not done yet. (this is a workaround for the prog8 256 array lenght limit)
|
||||
if cells_to_carve!=0 {
|
||||
if repath()
|
||||
goto carve_restart_after_repath
|
||||
}
|
||||
return true
|
||||
}
|
||||
cx = cx_stack[stackptr]
|
||||
cy = cy_stack[stackptr]
|
||||
} else {
|
||||
cx_stack[stackptr] = cx
|
||||
cy_stack[stackptr] = cy
|
||||
stackptr++
|
||||
if stackptr==0 {
|
||||
; stack overflow, we can't track our path any longer.
|
||||
; repath if we are not done yet. (this is a workaround for the prog8 256 array lenght limit)
|
||||
if cells_to_carve!=0 {
|
||||
if repath()
|
||||
goto carve_restart_after_repath
|
||||
}
|
||||
return true
|
||||
}
|
||||
@(celladdr(cx,cy)) |= direction
|
||||
when direction {
|
||||
UP -> {
|
||||
cy--
|
||||
@(celladdr(cx,cy)) |= DOWN
|
||||
}
|
||||
RIGHT -> {
|
||||
cx++
|
||||
@(celladdr(cx,cy)) |= LEFT
|
||||
|
||||
score++
|
||||
}
|
||||
DOWN -> {
|
||||
cy++
|
||||
@(celladdr(cx,cy)) |= UP
|
||||
}
|
||||
LEFT -> {
|
||||
cx--
|
||||
@(celladdr(cx,cy)) |= RIGHT
|
||||
}
|
||||
}
|
||||
@(celladdr(cx,cy)) &= ~STONE
|
||||
cells_to_carve--
|
||||
drawCell(cx, cy)
|
||||
}
|
||||
}
|
||||
return false
|
||||
|
||||
sub repath() -> bool {
|
||||
; repath: try to find a new start cell with possible directions.
|
||||
; we limit our number of searches so that the algorith doesn't get stuck
|
||||
; for too long on bad rng... just accept a few unused cells in that case.
|
||||
repeat 255 {
|
||||
do {
|
||||
cx = math.rnd() % numCellsHoriz
|
||||
cy = math.rnd() % numCellsVert
|
||||
} until @(celladdr(cx, cy)) & STONE ==0
|
||||
if available_uncarved()!=0
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
sub available_uncarved() -> ubyte {
|
||||
ubyte candidates = 0
|
||||
if cx>0 and @(celladdr(cx-1, cy)) & STONE !=0
|
||||
candidates |= LEFT
|
||||
if cx<numCellsHoriz-1 and @(celladdr(cx+1, cy)) & STONE !=0
|
||||
candidates |= RIGHT
|
||||
if cy>0 and @(celladdr(cx, cy-1)) & STONE !=0
|
||||
candidates |= UP
|
||||
if cy<numCellsVert-1 and @(celladdr(cx, cy+1)) & STONE !=0
|
||||
candidates |= DOWN
|
||||
return candidates
|
||||
}
|
||||
|
||||
sub choose_uncarved_direction() -> ubyte {
|
||||
ubyte candidates = available_uncarved()
|
||||
if candidates==0
|
||||
return 0
|
||||
|
||||
repeat {
|
||||
ubyte choice = candidates & directionflags[math.rnd() & 3]
|
||||
if choice!=0
|
||||
return choice
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sub openpassages() {
|
||||
; open just a few extra passages, so that multiple routes are possible in theory.
|
||||
ubyte numpassages
|
||||
ubyte cx
|
||||
ubyte cy
|
||||
do {
|
||||
do {
|
||||
cx = math.rnd() % (numCellsHoriz-2) + 1
|
||||
cy = math.rnd() % (numCellsVert-2) + 1
|
||||
} until @(celladdr(cx, cy)) & STONE ==0
|
||||
ubyte direction = directionflags[math.rnd() & 3]
|
||||
if @(celladdr(cx, cy)) & direction == 0 {
|
||||
when direction {
|
||||
LEFT -> {
|
||||
if @(celladdr(cx-1,cy)) & STONE == 0 {
|
||||
@(celladdr(cx,cy)) |= LEFT
|
||||
drawCell(cx,cy)
|
||||
numpassages++
|
||||
}
|
||||
}
|
||||
RIGHT -> {
|
||||
if @(celladdr(cx+1,cy)) & STONE == 0 {
|
||||
@(celladdr(cx,cy)) |= RIGHT
|
||||
drawCell(cx,cy)
|
||||
numpassages++
|
||||
}
|
||||
}
|
||||
UP -> {
|
||||
if @(celladdr(cx,cy-1)) & STONE == 0 {
|
||||
@(celladdr(cx,cy)) |= UP
|
||||
drawCell(cx,cy)
|
||||
numpassages++
|
||||
}
|
||||
}
|
||||
DOWN -> {
|
||||
if @(celladdr(cx,cy+1)) & STONE == 0 {
|
||||
@(celladdr(cx,cy)) |= DOWN
|
||||
drawCell(cx,cy)
|
||||
numpassages++
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} until numpassages==10
|
||||
}
|
||||
|
||||
sub solve(uword max_time) -> bool {
|
||||
ubyte cx = startCx
|
||||
ubyte cy = startCy
|
||||
const uword max_path_length = 1024
|
||||
|
||||
; the path through the maze can be longer than 256 so doesn't fit in a regular array.... :(
|
||||
uword pathstack = memory("pathstack", max_path_length, 0)
|
||||
uword pathstackptr = 0
|
||||
|
||||
@(celladdr(cx,cy)) |= WALKED
|
||||
; txt.setcc(cx*2+1, cy*2+1, 81, 1)
|
||||
|
||||
while cbm.RDTIM16()<max_time {
|
||||
solve_loop:
|
||||
if cx==finishCx and cy==finishCy {
|
||||
;txt.home()
|
||||
txt.print("found! path length: ")
|
||||
txt.print_uw(pathstackptr)
|
||||
txt.nl()
|
||||
return true
|
||||
}
|
||||
|
||||
ubyte cell = @(celladdr(cx,cy))
|
||||
if cell & UP!=0 and @(celladdr(cx,cy-1)) & (WALKED|BACKTRACKED) ==0 {
|
||||
@(pathstack + pathstackptr) = UP
|
||||
;txt.setcc(cx*2+1, cy*2, 81, 3)
|
||||
cy--
|
||||
}
|
||||
else if cell & DOWN !=0 and @(celladdr(cx,cy+1)) & (WALKED|BACKTRACKED) ==0 {
|
||||
@(pathstack + pathstackptr) = DOWN
|
||||
;txt.setcc(cx*2+1, cy*2+2, 81, 3)
|
||||
cy++
|
||||
}
|
||||
else if cell & LEFT !=0 and @(celladdr(cx-1,cy)) & (WALKED|BACKTRACKED) ==0 {
|
||||
@(pathstack + pathstackptr) = LEFT
|
||||
;txt.setcc(cx*2, cy*2+1, 81, 3)
|
||||
cx--
|
||||
}
|
||||
else if cell & RIGHT !=0 and @(celladdr(cx+1,cy)) & (WALKED|BACKTRACKED) ==0 {
|
||||
@(pathstack + pathstackptr) = RIGHT
|
||||
;txt.setcc(cx*2+2, cy*2+1, 81, 3)
|
||||
cx++
|
||||
}
|
||||
else {
|
||||
; dead end, pop stack
|
||||
pathstackptr--
|
||||
if pathstackptr==65535 {
|
||||
txt.print("no solution?!\n")
|
||||
return true
|
||||
}
|
||||
@(celladdr(cx,cy)) |= BACKTRACKED
|
||||
;txt.setcc(cx*2+1, cy*2+1, 81, 2)
|
||||
when @(pathstack + pathstackptr) {
|
||||
UP -> {
|
||||
;txt.setcc(cx*2+1, cy*2+2, 81, 9)
|
||||
cy++
|
||||
}
|
||||
DOWN -> {
|
||||
;txt.setcc(cx*2+1, cy*2, 81, 9)
|
||||
cy--
|
||||
}
|
||||
LEFT -> {
|
||||
;txt.setcc(cx*2+2, cy*2+1, 81, 9)
|
||||
cx++
|
||||
}
|
||||
RIGHT -> {
|
||||
;txt.setcc(cx*2, cy*2+1, 81, 9)
|
||||
cx--
|
||||
|
||||
score++
|
||||
}
|
||||
}
|
||||
goto solve_loop
|
||||
}
|
||||
pathstackptr++
|
||||
if pathstackptr==max_path_length {
|
||||
txt.print("stack overflow, path too long\n")
|
||||
return true
|
||||
}
|
||||
@(celladdr(cx,cy)) |= WALKED
|
||||
;txt.setcc(cx*2+1, cy*2+1, 81, 1)
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
sub celladdr(ubyte cx, ubyte cy) -> uword {
|
||||
return cells+(numCellsHoriz as uword)*cy+cx
|
||||
}
|
||||
|
||||
sub drawCell(ubyte cx, ubyte cy) {
|
||||
return
|
||||
; ubyte x = cx * 2 + 1
|
||||
; ubyte y = cy * 2 + 1
|
||||
; ubyte doors = @(celladdr(cx,cy))
|
||||
; if doors & UP !=0
|
||||
; txt.setcc(x, y-1, ' ', EMPTYCOLOR)
|
||||
; if doors & RIGHT !=0
|
||||
; txt.setcc(x+1, y, ' ', EMPTYCOLOR)
|
||||
; if doors & DOWN !=0
|
||||
; txt.setcc(x, y+1, ' ', EMPTYCOLOR)
|
||||
; if doors & LEFT !=0
|
||||
; txt.setcc(x-1, y, ' ', EMPTYCOLOR)
|
||||
; if doors & STONE !=0
|
||||
; txt.setcc(x, y, 160, WALLCOLOR)
|
||||
; else
|
||||
; txt.setcc(x, y, 32, EMPTYCOLOR)
|
||||
;
|
||||
; if doors & WALKED !=0
|
||||
; txt.setcc(x, y, 81, 1)
|
||||
; if doors & BACKTRACKED !=0
|
||||
; txt.setcc(x, y, 81, 2)
|
||||
}
|
||||
|
||||
sub initialize() {
|
||||
sys.memset(cells, numCellsHoriz*numCellsVert, STONE)
|
||||
; txt.fill_screen(160, WALLCOLOR)
|
||||
drawStartFinish()
|
||||
}
|
||||
|
||||
sub drawStartFinish() {
|
||||
; txt.setcc(startCx*2+1,startCy*2+1,sc:'s',5)
|
||||
; txt.setcc(finishCx*2+1, finishCy*2+1, sc:'f', 13)
|
||||
}
|
||||
}
|
63
benchmark-program/b_queens.p8
Normal file
63
benchmark-program/b_queens.p8
Normal file
@ -0,0 +1,63 @@
|
||||
%import textio
|
||||
|
||||
; Recursive N-Queens solver.
|
||||
; The problem is: find all possible ways to place 8 Queen chess pieces on a chess board, so that none of them attacks any other.
|
||||
; (this program prints all solutions without taking mirroring and flipping the chess board into account)
|
||||
; Note: this program can be compiled for multiple target systems.
|
||||
|
||||
queens {
|
||||
const ubyte NUMQUEENS=8
|
||||
ubyte[NUMQUEENS] board
|
||||
|
||||
sub could_place(ubyte row, ubyte col) -> bool {
|
||||
if row==0
|
||||
return true
|
||||
ubyte i
|
||||
for i in 0 to row-1 {
|
||||
if board[i]==col or board[i]-i==col-row or board[i]+i==col+row
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
uword solution_count
|
||||
uword maximum_duration
|
||||
|
||||
sub place_queen(ubyte row) -> bool {
|
||||
if row == NUMQUEENS {
|
||||
solution_count++
|
||||
txt.chrout('.')
|
||||
return cbm.RDTIM16()<maximum_duration
|
||||
}
|
||||
bool continue_running=true
|
||||
ubyte col
|
||||
for col in 0 to NUMQUEENS-1 {
|
||||
if could_place(row, col) {
|
||||
board[row] = col
|
||||
; we need to save the local variables row and col.
|
||||
sys.push(row)
|
||||
sys.push(col)
|
||||
continue_running = place_queen(row + 1)
|
||||
; restore the local variables after the recursive call.
|
||||
col = sys.pop()
|
||||
row = sys.pop()
|
||||
board[row] = 0
|
||||
|
||||
if not continue_running
|
||||
break
|
||||
}
|
||||
}
|
||||
return continue_running
|
||||
}
|
||||
|
||||
sub bench(uword max_time) -> uword {
|
||||
solution_count = 0
|
||||
maximum_duration = max_time
|
||||
txt.nl()
|
||||
cbm.SETTIM(0,0,0)
|
||||
while cbm.RDTIM16() < maximum_duration {
|
||||
void place_queen(0)
|
||||
}
|
||||
return solution_count
|
||||
}
|
||||
}
|
989
benchmark-program/b_textelite.p8
Normal file
989
benchmark-program/b_textelite.p8
Normal file
@ -0,0 +1,989 @@
|
||||
%import textio
|
||||
%import conv
|
||||
%import strings
|
||||
|
||||
|
||||
textelite {
|
||||
|
||||
const ubyte numforLave = 7 ; Lave is 7th generated planet in galaxy one
|
||||
const ubyte numforZaonce = 129
|
||||
const ubyte numforDiso = 147
|
||||
const ubyte numforRiedquat = 46
|
||||
uword num_commands
|
||||
|
||||
sub bench(uword max_time) -> uword {
|
||||
num_commands = 0
|
||||
txt.lowercase()
|
||||
cbm.SETTIM(0,0,0)
|
||||
while cbm.RDTIM16()<max_time {
|
||||
reinit()
|
||||
run_commands(max_time)
|
||||
}
|
||||
return num_commands
|
||||
}
|
||||
|
||||
sub reinit() {
|
||||
;txt.clear_screen()
|
||||
;txt.print("\n --- TextElite v1.3 ---\n")
|
||||
txt.print("\nnew game\n")
|
||||
elite_planet.set_seed(0, 0)
|
||||
elite_galaxy.travel_to(1, numforLave)
|
||||
elite_market.init(0) ; Lave's market is seeded with 0
|
||||
elite_ship.init()
|
||||
elite_planet.display(false, 0)
|
||||
input_index = 0
|
||||
}
|
||||
|
||||
sub run_commands(uword max_time) {
|
||||
while cbm.RDTIM16() < max_time {
|
||||
str input = "????????"
|
||||
;txt.print("\nCash: ")
|
||||
;elite_util.print_10s(elite_ship.cash)
|
||||
;txt.print("\nCommand (?=help): ")
|
||||
ubyte num_chars = next_input(input)
|
||||
;txt.nl()
|
||||
if num_chars!=0 {
|
||||
when input[0] {
|
||||
'q' -> {
|
||||
bool has_error = false
|
||||
if elite_galaxy.number != 2 {
|
||||
txt.print("\nERROR: galaxy is not 2: ")
|
||||
txt.print_ub(elite_galaxy.number)
|
||||
txt.nl()
|
||||
has_error=true
|
||||
}
|
||||
if elite_planet.number != 164 {
|
||||
txt.print("\nERROR: planet is not 164: ")
|
||||
txt.print_ub(elite_planet.number)
|
||||
txt.nl()
|
||||
has_error=true
|
||||
}
|
||||
if elite_planet.x != 116 {
|
||||
txt.print("\nERROR: planet.x is not 116: ")
|
||||
txt.print_ub(elite_planet.x)
|
||||
txt.nl()
|
||||
has_error=true
|
||||
}
|
||||
if elite_planet.y != 201 {
|
||||
txt.print("\nERROR: planet.y is not 201: ")
|
||||
txt.print_ub(elite_planet.y)
|
||||
txt.nl()
|
||||
has_error=true
|
||||
}
|
||||
if "ribeen" != elite_planet.name {
|
||||
txt.print("\nERROR: planet.name is not 'ribeen': ")
|
||||
txt.print(elite_planet.name)
|
||||
txt.nl()
|
||||
has_error=true
|
||||
}
|
||||
if elite_ship.cash != 1212 {
|
||||
txt.print("\nERROR: cash is not 1212: ")
|
||||
txt.print_uw(elite_ship.cash)
|
||||
txt.nl()
|
||||
has_error=true
|
||||
}
|
||||
if elite_ship.fuel != 50 {
|
||||
txt.print("\nERROR: fuel is not 50:")
|
||||
txt.print_ub(elite_ship.fuel)
|
||||
txt.nl()
|
||||
has_error=true
|
||||
}
|
||||
if elite_ship.cargohold[0] != 3 {
|
||||
txt.print("\nERROR: food is not 3:")
|
||||
txt.print_ub(elite_ship.cargohold[0])
|
||||
txt.nl()
|
||||
has_error=true
|
||||
}
|
||||
if elite_ship.cargohold[1] != 0 {
|
||||
txt.print("\nERROR: textiles is not 0:")
|
||||
txt.print_ub(elite_ship.cargohold[1])
|
||||
txt.nl()
|
||||
has_error=true
|
||||
}
|
||||
if has_error
|
||||
sys.exit(1)
|
||||
return
|
||||
}
|
||||
'b' -> elite_trader.do_buy()
|
||||
's' -> elite_trader.do_sell()
|
||||
'f' -> elite_trader.do_fuel()
|
||||
'j' -> elite_trader.do_jump()
|
||||
't' -> elite_trader.do_teleport()
|
||||
'g' -> elite_trader.do_next_galaxy()
|
||||
'i' -> elite_trader.do_info()
|
||||
'm' -> {
|
||||
if input[1]=='a' and input[2]=='p'
|
||||
elite_trader.do_map()
|
||||
else
|
||||
elite_trader.do_show_market()
|
||||
}
|
||||
'l' -> elite_trader.do_local()
|
||||
'c' -> elite_trader.do_cash()
|
||||
'h' -> elite_trader.do_hold()
|
||||
}
|
||||
num_commands++
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
str[] inputs = [
|
||||
"i",
|
||||
"diso",
|
||||
"i",
|
||||
"lave",
|
||||
"m",
|
||||
"b",
|
||||
"food",
|
||||
"15",
|
||||
"map",
|
||||
"g",
|
||||
"map",
|
||||
"l",
|
||||
"j",
|
||||
"zao",
|
||||
"s",
|
||||
"food",
|
||||
"12",
|
||||
"tele",
|
||||
"quti",
|
||||
"tele",
|
||||
"aro",
|
||||
"i",
|
||||
"diso",
|
||||
"i",
|
||||
"lave",
|
||||
"i",
|
||||
"zao",
|
||||
"galhyp",
|
||||
"fuel",
|
||||
"20",
|
||||
"j",
|
||||
"rib",
|
||||
"i",
|
||||
"rib",
|
||||
"i",
|
||||
"tiri",
|
||||
"q",
|
||||
0
|
||||
]
|
||||
|
||||
ubyte input_index
|
||||
|
||||
sub next_input(str buffer) -> ubyte {
|
||||
input_index++
|
||||
return strings.copy(inputs[input_index], buffer)
|
||||
}
|
||||
}
|
||||
|
||||
elite_trader {
|
||||
str input = "??????????"
|
||||
ubyte num_chars
|
||||
|
||||
sub do_jump() {
|
||||
;txt.print("\nJump to what system? ")
|
||||
jump_to_system()
|
||||
}
|
||||
|
||||
sub do_teleport() {
|
||||
;txt.print("\nCheat! Teleport to what system? ")
|
||||
ubyte fuel = elite_ship.fuel
|
||||
elite_ship.fuel = 255
|
||||
jump_to_system()
|
||||
elite_ship.fuel = fuel
|
||||
}
|
||||
|
||||
sub jump_to_system() {
|
||||
void textelite.next_input(input)
|
||||
ubyte current_planet = elite_planet.number
|
||||
ubyte x = elite_planet.x
|
||||
ubyte y = elite_planet.y
|
||||
if elite_galaxy.search_closest_planet(input) {
|
||||
ubyte distance = elite_planet.distance(x, y)
|
||||
if distance <= elite_ship.fuel {
|
||||
elite_galaxy.init_market_for_planet()
|
||||
elite_ship.fuel -= distance
|
||||
;txt.print("\n\nHyperspace jump! Arrived at:\n")
|
||||
elite_planet.display(true,0 )
|
||||
return
|
||||
}
|
||||
;txt.print("\nInsufficient fuel\n")
|
||||
} else {
|
||||
;txt.print(" Not found!\n")
|
||||
}
|
||||
elite_galaxy.travel_to(elite_galaxy.number, current_planet)
|
||||
}
|
||||
|
||||
sub do_buy() {
|
||||
;txt.print("\nBuy what commodity? ")
|
||||
str commodity = "???????????????"
|
||||
void textelite.next_input(commodity)
|
||||
ubyte ci = elite_market.match(commodity)
|
||||
if ci & 128 !=0 {
|
||||
txt.print("Unknown\n")
|
||||
} else {
|
||||
;txt.print("\nHow much? ")
|
||||
void textelite.next_input(input)
|
||||
ubyte amount = conv.str2ubyte(input)
|
||||
if elite_market.current_quantity[ci] < amount {
|
||||
txt.print(" Insufficient supply!\n")
|
||||
} else {
|
||||
uword price = elite_market.current_price[ci] * amount
|
||||
;txt.print(" Total price: ")
|
||||
;elite_util.print_10s(price)
|
||||
if price > elite_ship.cash {
|
||||
txt.print(" Not enough cash!\n")
|
||||
} else {
|
||||
elite_ship.cash -= price
|
||||
elite_ship.cargohold[ci] += amount
|
||||
elite_market.current_quantity[ci] -= amount
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sub do_sell() {
|
||||
;txt.print("\nSell what commodity? ")
|
||||
str commodity = "???????????????"
|
||||
void textelite.next_input(commodity)
|
||||
ubyte ci = elite_market.match(commodity)
|
||||
if ci & 128 !=0 {
|
||||
txt.print("Unknown\n")
|
||||
} else {
|
||||
;txt.print("\nHow much? ")
|
||||
void textelite.next_input(input)
|
||||
ubyte amount = conv.str2ubyte(input)
|
||||
if elite_ship.cargohold[ci] < amount {
|
||||
txt.print(" Insufficient supply!\n")
|
||||
} else {
|
||||
uword price = elite_market.current_price[ci] * amount
|
||||
;txt.print(" Total price: ")
|
||||
;elite_util.print_10s(price)
|
||||
elite_ship.cash += price
|
||||
elite_ship.cargohold[ci] -= amount
|
||||
elite_market.current_quantity[ci] += amount
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sub do_fuel() {
|
||||
;txt.print("\nBuy fuel. Amount? ")
|
||||
void textelite.next_input(input)
|
||||
ubyte buy_fuel = 10*conv.str2ubyte(input)
|
||||
ubyte max_fuel = elite_ship.Max_fuel - elite_ship.fuel
|
||||
if buy_fuel > max_fuel
|
||||
buy_fuel = max_fuel
|
||||
uword price = buy_fuel as uword * elite_ship.Fuel_cost
|
||||
if price > elite_ship.cash {
|
||||
txt.print("Not enough cash!\n")
|
||||
} else {
|
||||
elite_ship.cash -= price
|
||||
elite_ship.fuel += buy_fuel
|
||||
}
|
||||
}
|
||||
|
||||
sub do_cash() {
|
||||
;txt.print("\nCheat! Set cash amount: ")
|
||||
void textelite.next_input(input)
|
||||
elite_ship.cash = conv.str2uword(input)
|
||||
}
|
||||
|
||||
sub do_hold() {
|
||||
;txt.print("\nCheat! Set cargohold size: ")
|
||||
void textelite.next_input(input)
|
||||
elite_ship.Max_cargo = conv.str2ubyte(input)
|
||||
}
|
||||
|
||||
sub do_next_galaxy() {
|
||||
txt.print("\n>>>>> Galaxy Hyperjump!\n")
|
||||
elite_galaxy.travel_to(elite_galaxy.number+1, elite_planet.number)
|
||||
elite_planet.display(false, 0)
|
||||
}
|
||||
|
||||
sub do_info() {
|
||||
;txt.print("\nSystem name (empty=current): ")
|
||||
num_chars = textelite.next_input(input)
|
||||
if num_chars!=0 {
|
||||
ubyte current_planet = elite_planet.number
|
||||
ubyte x = elite_planet.x
|
||||
ubyte y = elite_planet.y
|
||||
if elite_galaxy.search_closest_planet(input) {
|
||||
ubyte distance = elite_planet.distance(x, y)
|
||||
elite_planet.display(false, distance)
|
||||
} else {
|
||||
;txt.print(" Not found!")
|
||||
}
|
||||
elite_galaxy.travel_to(elite_galaxy.number, current_planet)
|
||||
} else {
|
||||
elite_planet.display(false, 0)
|
||||
}
|
||||
}
|
||||
|
||||
sub do_local() {
|
||||
elite_galaxy.local_area()
|
||||
}
|
||||
|
||||
sub do_map() {
|
||||
;txt.print("\n(l)ocal or (g)alaxy starmap? ")
|
||||
num_chars = textelite.next_input(input)
|
||||
if num_chars!=0 {
|
||||
elite_galaxy.starmap(input[0]=='l')
|
||||
}
|
||||
}
|
||||
|
||||
sub do_show_market() {
|
||||
elite_market.display()
|
||||
;txt.print("\nFuel: ")
|
||||
;elite_util.print_10s(elite_ship.fuel)
|
||||
;txt.print(" Cargohold space: ")
|
||||
;txt.print_ub(elite_ship.cargo_free())
|
||||
;txt.print("t\n")
|
||||
}
|
||||
}
|
||||
|
||||
elite_ship {
|
||||
const ubyte Max_fuel = 70
|
||||
const ubyte Fuel_cost = 2
|
||||
ubyte Max_cargo = 20
|
||||
|
||||
ubyte fuel
|
||||
uword cash
|
||||
ubyte[17] cargohold
|
||||
|
||||
sub init() {
|
||||
sys.memset(cargohold, len(cargohold), 0)
|
||||
fuel = Max_fuel
|
||||
cash = 1000
|
||||
}
|
||||
}
|
||||
|
||||
elite_market {
|
||||
ubyte[17] baseprices = [$13, $14, $41, $28, $53, $C4, $EB, $9A, $75, $4E, $7C, $B0, $20, $61, $AB, $2D, $35]
|
||||
byte[17] gradients = [-$02, -$01, -$03, -$05, -$05, $08, $1D, $0E, $06, $01, $0d, -$09, -$01, -$01, -$02, -$01, $0F]
|
||||
ubyte[17] basequants = [$06, $0A, $02, $E2, $FB, $36, $08, $38, $28, $11, $1D, $DC, $35, $42, $37, $FA, $C0]
|
||||
ubyte[17] maskbytes = [$01, $03, $07, $1F, $0F, $03, $78, $03, $07, $1F, $07, $3F, $03, $07, $1F, $0F, $07]
|
||||
str[17] names = ["Food", "Textiles", "Radioactives", "Slaves", "Liquor/Wines", "Luxuries", "Narcotics", "Computers",
|
||||
"Machinery", "Alloys", "Firearms", "Furs", "Minerals", "Gold", "Platinum", "Gem-Stones", "Alien Items"]
|
||||
|
||||
ubyte[17] current_quantity
|
||||
uword[17] current_price
|
||||
|
||||
sub init(ubyte fluct) {
|
||||
; Prices and availabilities are influenced by the planet's economy type
|
||||
; (0-7) and a random "fluctuation" byte that was kept within the saved
|
||||
; commander position to keep the market prices constant over gamesaves.
|
||||
; Availabilities must be saved with the game since the player alters them
|
||||
; by buying (and selling(?))
|
||||
;
|
||||
; Almost all commands are one byte only and overflow "errors" are
|
||||
; extremely frequent and exploited.
|
||||
;
|
||||
; Trade Item prices are held internally in a single byte=true value/4.
|
||||
; The decimal point in prices is introduced only when printing them.
|
||||
; Internally, all prices are integers.
|
||||
; The player's cash is held in four bytes.
|
||||
ubyte ci
|
||||
for ci in 0 to len(names)-1 {
|
||||
word product
|
||||
byte changing
|
||||
product = elite_planet.economy as word * gradients[ci]
|
||||
changing = fluct & maskbytes[ci] as byte
|
||||
ubyte q = (basequants[ci] as word + changing - product) as ubyte
|
||||
if q & $80 !=0
|
||||
q = 0 ; clip to positive 8-bit
|
||||
current_quantity[ci] = q & $3f
|
||||
q = (baseprices[ci] + changing + product) as ubyte
|
||||
current_price[ci] = q * $0004
|
||||
}
|
||||
current_quantity[16] = 0 ; force nonavailability of Alien Items
|
||||
}
|
||||
|
||||
sub display() {
|
||||
return
|
||||
; ubyte ci
|
||||
; txt.nl()
|
||||
; elite_planet.print_name_uppercase()
|
||||
; txt.print(" trade market:\n COMMODITY / PRICE / AVAIL / IN HOLD\n")
|
||||
; for ci in 0 to len(names)-1 {
|
||||
; elite_util.print_right(13, names[ci])
|
||||
; txt.print(" ")
|
||||
; elite_util.print_10s(current_price[ci])
|
||||
; txt.column(24)
|
||||
; txt.print_ub(current_quantity[ci])
|
||||
; txt.chrout(' ')
|
||||
; when units[ci] {
|
||||
; 0 -> txt.chrout('t')
|
||||
; 1 -> txt.print("kg")
|
||||
; 2 -> txt.chrout('g')
|
||||
; }
|
||||
; txt.column(32)
|
||||
; txt.print_ub(elite_ship.cargohold[ci])
|
||||
; txt.nl()
|
||||
; }
|
||||
}
|
||||
|
||||
sub match(uword nameptr) -> ubyte {
|
||||
ubyte ci
|
||||
for ci in 0 to len(names)-1 {
|
||||
if elite_util.prefix_matches(nameptr, names[ci])
|
||||
return ci
|
||||
}
|
||||
return 255
|
||||
}
|
||||
}
|
||||
|
||||
elite_galaxy {
|
||||
const uword GALSIZE = 256
|
||||
const uword base0 = $5A4A ; seeds for the first galaxy
|
||||
const uword base1 = $0248
|
||||
const uword base2 = $B753
|
||||
|
||||
str pn_pairs = "..lexegezacebisousesarmaindirea.eratenberalavetiedorquanteisrion"
|
||||
|
||||
ubyte number
|
||||
|
||||
uword[3] seed
|
||||
|
||||
sub init(ubyte galaxynum) {
|
||||
number = 1
|
||||
elite_planet.number = 255
|
||||
seed[0] = base0
|
||||
seed[1] = base1
|
||||
seed[2] = base2
|
||||
repeat galaxynum-1 {
|
||||
nextgalaxy()
|
||||
}
|
||||
}
|
||||
|
||||
sub nextgalaxy() {
|
||||
textelite.num_commands++
|
||||
|
||||
seed[0] = twist(seed[0])
|
||||
seed[1] = twist(seed[1])
|
||||
seed[2] = twist(seed[2])
|
||||
number++
|
||||
if number==9
|
||||
number = 1
|
||||
}
|
||||
|
||||
sub travel_to(ubyte galaxynum, ubyte system) {
|
||||
init(galaxynum)
|
||||
generate_next_planet() ; always at least planet 0 (separate to avoid repeat ubyte overflow)
|
||||
repeat system {
|
||||
generate_next_planet()
|
||||
textelite.num_commands++
|
||||
}
|
||||
elite_planet.name = make_current_planet_name()
|
||||
init_market_for_planet()
|
||||
}
|
||||
|
||||
sub init_market_for_planet() {
|
||||
elite_market.init(lsb(seed[0])+msb(seed[2]))
|
||||
}
|
||||
|
||||
sub search_closest_planet(uword nameptr) -> bool {
|
||||
textelite.num_commands++
|
||||
|
||||
ubyte x = elite_planet.x
|
||||
ubyte y = elite_planet.y
|
||||
ubyte current_planet_num = elite_planet.number
|
||||
|
||||
init(number)
|
||||
bool found = false
|
||||
ubyte current_closest_pi
|
||||
ubyte current_distance = 127
|
||||
ubyte pi
|
||||
for pi in 0 to 255 {
|
||||
generate_next_planet()
|
||||
elite_planet.name = make_current_planet_name()
|
||||
if elite_util.prefix_matches(nameptr, elite_planet.name) {
|
||||
ubyte distance = elite_planet.distance(x, y)
|
||||
if distance < current_distance {
|
||||
current_distance = distance
|
||||
current_closest_pi = pi
|
||||
found = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if found
|
||||
travel_to(number, current_closest_pi)
|
||||
else
|
||||
travel_to(number, current_planet_num)
|
||||
|
||||
return found
|
||||
}
|
||||
|
||||
sub local_area() {
|
||||
ubyte current_planet = elite_planet.number
|
||||
ubyte px = elite_planet.x
|
||||
ubyte py = elite_planet.y
|
||||
ubyte pn = 0
|
||||
|
||||
init(number)
|
||||
; txt.print("\nGalaxy #")
|
||||
; txt.print_ub(number)
|
||||
; txt.print(" - systems in vicinity:\n")
|
||||
do {
|
||||
generate_next_planet()
|
||||
ubyte distance = elite_planet.distance(px, py)
|
||||
if distance <= elite_ship.Max_fuel {
|
||||
; if distance <= elite_ship.fuel
|
||||
; txt.chrout('*')
|
||||
; else
|
||||
; txt.chrout('-')
|
||||
; txt.spc()
|
||||
elite_planet.name = make_current_planet_name()
|
||||
elite_planet.display(true, distance)
|
||||
}
|
||||
pn++
|
||||
} until pn==0
|
||||
|
||||
travel_to(number, current_planet)
|
||||
}
|
||||
|
||||
sub starmap(bool local) {
|
||||
ubyte current_planet = elite_planet.number
|
||||
ubyte px = elite_planet.x
|
||||
ubyte py = elite_planet.y
|
||||
str current_name = " " ; 8 max
|
||||
ubyte pn = 0
|
||||
|
||||
current_name = elite_planet.name
|
||||
init(number)
|
||||
; txt.clear_screen()
|
||||
; txt.print("Galaxy #")
|
||||
; txt.print_ub(number)
|
||||
; if local
|
||||
; txt.print(" - local systems")
|
||||
; else
|
||||
; txt.print(" - galaxy")
|
||||
; txt.print(" starmap:\n")
|
||||
ubyte max_distance = 255
|
||||
if local
|
||||
max_distance = elite_ship.Max_fuel
|
||||
ubyte home_sx
|
||||
ubyte home_sy
|
||||
ubyte home_distance
|
||||
|
||||
do {
|
||||
generate_next_planet()
|
||||
ubyte distance = elite_planet.distance(px, py)
|
||||
if distance <= max_distance {
|
||||
elite_planet.name = make_current_planet_name()
|
||||
elite_planet.name[0] = strings.upperchar(elite_planet.name[0])
|
||||
uword tx = elite_planet.x
|
||||
uword ty = elite_planet.y
|
||||
if local {
|
||||
tx = tx + 24 - px
|
||||
ty = ty + 24 - py
|
||||
}
|
||||
ubyte sx = display_scale_x(tx)
|
||||
ubyte sy = display_scale_y(ty)
|
||||
ubyte char = '*'
|
||||
if elite_planet.number==current_planet
|
||||
char = '%'
|
||||
if local {
|
||||
print_planet_details(elite_planet.name, sx, sy, distance)
|
||||
} else if elite_planet.number==current_planet {
|
||||
home_distance = distance
|
||||
home_sx = sx
|
||||
home_sy = sy
|
||||
}
|
||||
; txt.setchr(2+sx, 2+sy, char)
|
||||
}
|
||||
pn++
|
||||
} until pn==0
|
||||
|
||||
if not local
|
||||
print_planet_details(current_name, home_sx, home_sy, home_distance)
|
||||
|
||||
; if local
|
||||
; txt.plot(0, display_scale_y(64) + 4)
|
||||
; else
|
||||
; txt.plot(0, display_scale_y(256) + 4 as ubyte)
|
||||
travel_to(number, current_planet)
|
||||
|
||||
sub print_planet_details(str name, ubyte screenx, ubyte screeny, ubyte d) {
|
||||
return
|
||||
; txt.plot(2+screenx-2, 2+screeny+1)
|
||||
; txt.print(name)
|
||||
; if d!=0 {
|
||||
; txt.plot(2+screenx-2, 2+screeny+2)
|
||||
; elite_util.print_10s(d)
|
||||
; txt.print(" LY")
|
||||
; }
|
||||
}
|
||||
|
||||
sub display_scale_x(uword x) -> ubyte {
|
||||
if local
|
||||
return x/2 as ubyte
|
||||
return x/8 as ubyte
|
||||
}
|
||||
|
||||
sub display_scale_y(uword y) -> ubyte {
|
||||
if local
|
||||
return y/4 as ubyte
|
||||
return y/16 as ubyte
|
||||
}
|
||||
}
|
||||
|
||||
ubyte pn_pair1
|
||||
ubyte pn_pair2
|
||||
ubyte pn_pair3
|
||||
ubyte pn_pair4
|
||||
bool longname
|
||||
|
||||
sub generate_next_planet() {
|
||||
determine_planet_properties()
|
||||
longname = lsb(seed[0]) & 64 !=0
|
||||
|
||||
; Always four iterations of random number
|
||||
pn_pair1 = (msb(seed[2]) & 31) * 2
|
||||
tweakseed()
|
||||
pn_pair2 = (msb(seed[2]) & 31) * 2
|
||||
tweakseed()
|
||||
pn_pair3 = (msb(seed[2]) & 31) * 2
|
||||
tweakseed()
|
||||
pn_pair4 = (msb(seed[2]) & 31) * 2
|
||||
tweakseed()
|
||||
}
|
||||
|
||||
sub make_current_planet_name() -> str {
|
||||
ubyte ni = 0
|
||||
str name = " " ; max 8
|
||||
|
||||
if pn_pairs[pn_pair1] != '.' {
|
||||
name[ni] = pn_pairs[pn_pair1]
|
||||
ni++
|
||||
}
|
||||
if pn_pairs[pn_pair1+1] != '.' {
|
||||
name[ni] = pn_pairs[pn_pair1+1]
|
||||
ni++
|
||||
}
|
||||
if pn_pairs[pn_pair2] != '.' {
|
||||
name[ni] = pn_pairs[pn_pair2]
|
||||
ni++
|
||||
}
|
||||
if pn_pairs[pn_pair2+1] != '.' {
|
||||
name[ni] = pn_pairs[pn_pair2+1]
|
||||
ni++
|
||||
}
|
||||
if pn_pairs[pn_pair3] != '.' {
|
||||
name[ni] = pn_pairs[pn_pair3]
|
||||
ni++
|
||||
}
|
||||
if pn_pairs[pn_pair3+1] != '.' {
|
||||
name[ni] = pn_pairs[pn_pair3+1]
|
||||
ni++
|
||||
}
|
||||
|
||||
if longname {
|
||||
if pn_pairs[pn_pair4] != '.' {
|
||||
name[ni] = pn_pairs[pn_pair4]
|
||||
ni++
|
||||
}
|
||||
if pn_pairs[pn_pair4+1] != '.' {
|
||||
name[ni] = pn_pairs[pn_pair4+1]
|
||||
ni++
|
||||
}
|
||||
}
|
||||
|
||||
name[ni] = 0
|
||||
return name
|
||||
}
|
||||
|
||||
sub determine_planet_properties() {
|
||||
; create the planet's characteristics
|
||||
elite_planet.number++
|
||||
elite_planet.x = msb(seed[1])
|
||||
elite_planet.y = msb(seed[0])
|
||||
elite_planet.govtype = lsb(seed[1]) >> 3 & 7 ; bits 3,4 &5 of w1
|
||||
elite_planet.economy = msb(seed[0]) & 7 ; bits 8,9 &A of w0
|
||||
if elite_planet.govtype <= 1
|
||||
elite_planet.economy = (elite_planet.economy | 2)
|
||||
elite_planet.techlevel = (msb(seed[1]) & 3) + (elite_planet.economy ^ 7)
|
||||
elite_planet.techlevel += elite_planet.govtype >> 1
|
||||
if elite_planet.govtype & 1 !=0
|
||||
elite_planet.techlevel++
|
||||
elite_planet.population = 4 * elite_planet.techlevel + elite_planet.economy
|
||||
elite_planet.population += elite_planet.govtype + 1
|
||||
elite_planet.productivity = ((elite_planet.economy ^ 7) + 3) * (elite_planet.govtype + 4)
|
||||
elite_planet.productivity *= elite_planet.population * 8
|
||||
ubyte seed2_msb = msb(seed[2])
|
||||
elite_planet.radius = mkword((seed2_msb & 15) + 11, elite_planet.x)
|
||||
elite_planet.species_is_alien = lsb(seed[2]) & 128 !=0 ; bit 7 of w2_lo
|
||||
if elite_planet.species_is_alien {
|
||||
elite_planet.species_size = (seed2_msb >> 2) & 7 ; bits 2-4 of w2_hi
|
||||
elite_planet.species_color = seed2_msb >> 5 ; bits 5-7 of w2_hi
|
||||
elite_planet.species_look = (seed2_msb ^ msb(seed[1])) & 7 ;bits 0-2 of (w0_hi EOR w1_hi)
|
||||
elite_planet.species_kind = (elite_planet.species_look + (seed2_msb & 3)) & 7 ;Add bits 0-1 of w2_hi to A from previous step, and take bits 0-2 of the result
|
||||
}
|
||||
|
||||
elite_planet.goatsoup_seed[0] = lsb(seed[1])
|
||||
elite_planet.goatsoup_seed[1] = msb(seed[1])
|
||||
elite_planet.goatsoup_seed[2] = lsb(seed[2])
|
||||
elite_planet.goatsoup_seed[3] = seed2_msb
|
||||
}
|
||||
|
||||
sub tweakseed() {
|
||||
uword temp = seed[0] + seed[1] + seed[2]
|
||||
seed[0] = seed[1]
|
||||
seed[1] = seed[2]
|
||||
seed[2] = temp
|
||||
}
|
||||
|
||||
sub twist(uword x) -> uword {
|
||||
ubyte xh = msb(x)
|
||||
ubyte xl = lsb(x)
|
||||
xh <<= 1 ; make sure carry flag is not used on first shift!
|
||||
rol(xl)
|
||||
return mkword(xh, xl)
|
||||
}
|
||||
}
|
||||
|
||||
elite_planet {
|
||||
str[] @nosplit words81 = ["fabled", "notable", "well known", "famous", "noted"]
|
||||
str[] @nosplit words82 = ["very", "mildly", "most", "reasonably", ""]
|
||||
str[] @nosplit words83 = ["ancient", "\x95", "great", "vast", "pink"]
|
||||
str[] @nosplit words84 = ["\x9E \x9D plantations", "mountains", "\x9C", "\x94 forests", "oceans"]
|
||||
str[] @nosplit words85 = ["shyness", "silliness", "mating traditions", "loathing of \x86", "love for \x86"]
|
||||
str[] @nosplit words86 = ["food blenders", "tourists", "poetry", "discos", "\x8E"]
|
||||
str[] @nosplit words87 = ["talking tree", "crab", "bat", "lobst", "\xB2"]
|
||||
str[] @nosplit words88 = ["beset", "plagued", "ravaged", "cursed", "scourged"]
|
||||
str[] @nosplit words89 = ["\x96 civil war", "\x9B \x98 \x99s", "a \x9B disease", "\x96 earthquakes", "\x96 solar activity"]
|
||||
str[] @nosplit words8A = ["its \x83 \x84", "the \xB1 \x98 \x99", "its inhabitants' \x9A \x85", "\xA1", "its \x8D \x8E"]
|
||||
str[] @nosplit words8B = ["juice", "brandy", "water", "brew", "gargle blasters"]
|
||||
str[] @nosplit words8C = ["\xB2", "\xB1 \x99", "\xB1 \xB2", "\xB1 \x9B", "\x9B \xB2"]
|
||||
str[] @nosplit words8D = ["fabulous", "exotic", "hoopy", "unusual", "exciting"]
|
||||
str[] @nosplit words8E = ["cuisine", "night life", "casinos", "sit coms", " \xA1 "]
|
||||
str[] @nosplit words8F = ["\xB0", "The planet \xB0", "The world \xB0", "This planet", "This world"]
|
||||
str[] @nosplit words90 = ["n unremarkable", " boring", " dull", " tedious", " revolting"]
|
||||
str[] @nosplit words91 = ["planet", "world", "place", "little planet", "dump"]
|
||||
str[] @nosplit words92 = ["wasp", "moth", "grub", "ant", "\xB2"]
|
||||
str[] @nosplit words93 = ["poet", "arts graduate", "yak", "snail", "slug"]
|
||||
str[] @nosplit words94 = ["tropical", "dense", "rain", "impenetrable", "exuberant"]
|
||||
str[] @nosplit words95 = ["funny", "wierd", "unusual", "strange", "peculiar"]
|
||||
str[] @nosplit words96 = ["frequent", "occasional", "unpredictable", "dreadful", "deadly"]
|
||||
str[] @nosplit words97 = ["\x82 \x81 for \x8A", "\x82 \x81 for \x8A and \x8A", "\x88 by \x89", "\x82 \x81 for \x8A but \x88 by \x89", "a\x90 \x91"]
|
||||
str[] @nosplit words98 = ["\x9B", "mountain", "edible", "tree", "spotted"]
|
||||
str[] @nosplit words99 = ["\x9F", "\xA0", "\x87oid", "\x93", "\x92"]
|
||||
str[] @nosplit words9A = ["ancient", "exceptional", "eccentric", "ingrained", "\x95"]
|
||||
str[] @nosplit words9B = ["killer", "deadly", "evil", "lethal", "vicious"]
|
||||
str[] @nosplit words9C = ["parking meters", "dust clouds", "ice bergs", "rock formations", "volcanoes"]
|
||||
str[] @nosplit words9D = ["plant", "tulip", "banana", "corn", "\xB2weed"]
|
||||
str[] @nosplit words9E = ["\xB2", "\xB1 \xB2", "\xB1 \x9B", "inhabitant", "\xB1 \xB2"]
|
||||
str[] @nosplit words9F = ["shrew", "beast", "bison", "snake", "wolf"]
|
||||
str[] @nosplit wordsA0 = ["leopard", "cat", "monkey", "goat", "fish"]
|
||||
str[] @nosplit wordsA1 = ["\x8C \x8B", "\xB1 \x9F \xA2", "its \x8D \xA0 \xA2", "\xA3 \xA4", "\x8C \x8B"]
|
||||
str[] @nosplit wordsA2 = ["meat", "cutlet", "steak", "burgers", "soup"]
|
||||
str[] @nosplit wordsA3 = ["ice", "mud", "Zero-G", "vacuum", "\xB1 ultra"]
|
||||
str[] @nosplit wordsA4 = ["hockey", "cricket", "karate", "polo", "tennis"]
|
||||
|
||||
uword[] @shared wordlists = [
|
||||
words81, words82, words83, words84, words85, words86, words87, words88,
|
||||
words89, words8A, words8B, words8C, words8D, words8E, words8F, words90,
|
||||
words91, words92, words93, words94, words95, words96, words97, words98,
|
||||
words99, words9A, words9B, words9C, words9D, words9E, words9F, wordsA0,
|
||||
wordsA1, wordsA2, wordsA3, wordsA4]
|
||||
|
||||
str pairs0 = "abouseitiletstonlonuthnoallexegezacebisousesarmaindirea.eratenbe"
|
||||
|
||||
ubyte[4] goatsoup_rnd = [0, 0, 0, 0]
|
||||
ubyte[4] goatsoup_seed = [0, 0, 0, 0]
|
||||
|
||||
str name = " " ; 8 max
|
||||
ubyte number ; starts at 0 in new galaxy, then increases by 1 for each generated planet
|
||||
ubyte x
|
||||
ubyte y
|
||||
ubyte economy
|
||||
ubyte govtype
|
||||
ubyte techlevel
|
||||
ubyte population
|
||||
uword productivity
|
||||
uword radius
|
||||
bool species_is_alien ; otherwise "Human Colonials"
|
||||
ubyte species_size
|
||||
ubyte species_color
|
||||
ubyte species_look
|
||||
ubyte species_kind
|
||||
|
||||
sub set_seed(uword s1, uword s2) {
|
||||
goatsoup_seed[0] = lsb(s1)
|
||||
goatsoup_seed[1] = msb(s1)
|
||||
goatsoup_seed[2] = lsb(s2)
|
||||
goatsoup_seed[3] = msb(s2)
|
||||
reset_rnd()
|
||||
}
|
||||
|
||||
sub reset_rnd() {
|
||||
goatsoup_rnd[0] = goatsoup_seed[0]
|
||||
goatsoup_rnd[1] = goatsoup_seed[1]
|
||||
goatsoup_rnd[2] = goatsoup_seed[2]
|
||||
goatsoup_rnd[3] = goatsoup_seed[3]
|
||||
}
|
||||
|
||||
sub random_name() -> str {
|
||||
ubyte ii
|
||||
str randname = " " ; 8 chars max
|
||||
ubyte nx = 0
|
||||
for ii in 0 to goatsoup_rnd_number() & 3 {
|
||||
ubyte xx = goatsoup_rnd_number() & $3e
|
||||
if pairs0[xx] != '.' {
|
||||
randname[nx] = pairs0[xx]
|
||||
nx++
|
||||
}
|
||||
xx++
|
||||
if pairs0[xx] != '.' {
|
||||
randname[nx] = pairs0[xx]
|
||||
nx++
|
||||
}
|
||||
}
|
||||
randname[nx] = 0
|
||||
randname[0] = strings.upperchar(randname[0])
|
||||
return randname
|
||||
}
|
||||
|
||||
sub goatsoup_rnd_number() -> ubyte {
|
||||
ubyte xx = goatsoup_rnd[0] * 2
|
||||
uword a = xx as uword + goatsoup_rnd[2]
|
||||
if goatsoup_rnd[0] > 127
|
||||
a ++
|
||||
goatsoup_rnd[0] = lsb(a)
|
||||
goatsoup_rnd[2] = xx
|
||||
xx = goatsoup_rnd[1]
|
||||
ubyte ac = xx + goatsoup_rnd[3] + msb(a)
|
||||
goatsoup_rnd[1] = ac
|
||||
goatsoup_rnd[3] = xx
|
||||
return ac
|
||||
}
|
||||
|
||||
sub distance(ubyte px, ubyte py) -> ubyte {
|
||||
uword ax
|
||||
uword ay
|
||||
if px>x
|
||||
ax=px-x
|
||||
else
|
||||
ax=x-px
|
||||
if py>y
|
||||
ay=py-y
|
||||
else
|
||||
ay=y-py
|
||||
ay /= 2
|
||||
ubyte d = sqrt(ax*ax + ay*ay)
|
||||
if d>63
|
||||
return 255
|
||||
return d*4
|
||||
}
|
||||
|
||||
sub soup() -> str {
|
||||
str planet_result = " " * 160
|
||||
uword[6] source_stack
|
||||
ubyte stack_ptr = 0
|
||||
str start_source = "\x8F is \x97."
|
||||
uword source_ptr = &start_source
|
||||
uword result_ptr = &planet_result
|
||||
|
||||
reset_rnd()
|
||||
recursive_soup()
|
||||
return planet_result
|
||||
|
||||
sub recursive_soup() {
|
||||
repeat {
|
||||
ubyte c = @(source_ptr)
|
||||
source_ptr++
|
||||
if c == $00 {
|
||||
@(result_ptr) = 0
|
||||
return
|
||||
}
|
||||
else if c <= $80 {
|
||||
@(result_ptr) = c
|
||||
result_ptr++
|
||||
}
|
||||
else {
|
||||
if c <= $a4 {
|
||||
ubyte rnr = goatsoup_rnd_number()
|
||||
ubyte wordNr = ((rnr >= $33) as ubyte) + ((rnr >= $66) as ubyte) + ((rnr >= $99) as ubyte) + ((rnr >= $CC) as ubyte)
|
||||
source_stack[stack_ptr] = source_ptr
|
||||
stack_ptr++
|
||||
source_ptr = getword(c, wordNr)
|
||||
recursive_soup() ; RECURSIVE CALL - ignore the warning message from the compiler; we don't use local variables or parameters so we're safe in this case
|
||||
stack_ptr--
|
||||
source_ptr = source_stack[stack_ptr]
|
||||
} else {
|
||||
if c == $b0 {
|
||||
@(result_ptr) = strings.upperchar(name[0])
|
||||
result_ptr++
|
||||
concat_string(&name + 1)
|
||||
}
|
||||
else if c == $b1 {
|
||||
@(result_ptr) = strings.upperchar(name[0])
|
||||
result_ptr++
|
||||
ubyte ni
|
||||
for ni in 1 to len(name) {
|
||||
ubyte cc = name[ni]
|
||||
if cc in ['e', 'o', 0]
|
||||
break
|
||||
else {
|
||||
@(result_ptr) = cc
|
||||
result_ptr++
|
||||
}
|
||||
}
|
||||
@(result_ptr) = 'i'
|
||||
result_ptr++
|
||||
@(result_ptr) = 'a'
|
||||
result_ptr++
|
||||
@(result_ptr) = 'n'
|
||||
result_ptr++
|
||||
}
|
||||
else if c == $b2 {
|
||||
concat_string(random_name())
|
||||
}
|
||||
else {
|
||||
@(result_ptr) = c
|
||||
result_ptr++
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sub concat_string(uword str_ptr) {
|
||||
repeat {
|
||||
ubyte c = @(str_ptr)
|
||||
if c==0
|
||||
break
|
||||
else {
|
||||
@(result_ptr) = c
|
||||
str_ptr++
|
||||
result_ptr++
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sub display(bool compressed, ubyte distance) {
|
||||
txt.print(soup())
|
||||
txt.nl()
|
||||
}
|
||||
|
||||
sub getword(ubyte listnum, ubyte wordidx) -> uword {
|
||||
uword list = wordlists[listnum-$81]
|
||||
return peekw(list + wordidx*2)
|
||||
}
|
||||
}
|
||||
|
||||
elite_util {
|
||||
sub prefix_matches(uword prefixptr, uword stringptr) -> bool {
|
||||
repeat {
|
||||
ubyte pc = @(prefixptr)
|
||||
ubyte sc = @(stringptr)
|
||||
if pc == 0
|
||||
return true
|
||||
; to lowercase for case insensitive compare:
|
||||
if strings.lowerchar(pc)!=strings.lowerchar(sc)
|
||||
return false
|
||||
prefixptr++
|
||||
stringptr++
|
||||
}
|
||||
}
|
||||
}
|
112
benchmark-program/benchmark.p8
Normal file
112
benchmark-program/benchmark.p8
Normal file
@ -0,0 +1,112 @@
|
||||
|
||||
; This benchmark program is meant to check for regressions in the
|
||||
; Prog8 compiler's code-generator (performance wise).
|
||||
;
|
||||
; As the X16 computer is a more or less fixed system, it's not very useful
|
||||
; to benchmark the computer itself with.
|
||||
|
||||
|
||||
%import textio
|
||||
%import b_adpcm
|
||||
%import b_circles
|
||||
%import b_3d
|
||||
%import b_life
|
||||
%import b_mandelbrot
|
||||
%import b_queens
|
||||
%import b_textelite
|
||||
%import b_maze
|
||||
|
||||
%zeropage basicsafe
|
||||
%option no_sysinit
|
||||
|
||||
|
||||
main {
|
||||
|
||||
str[20] benchmark_names
|
||||
uword[20] benchmark_score
|
||||
|
||||
|
||||
sub start() {
|
||||
ubyte benchmark_number
|
||||
|
||||
void cx16.set_screen_mode(3)
|
||||
txt.color2(1, 6)
|
||||
txt.clear_screen()
|
||||
|
||||
txt.print("\n\n\n prog8 compiler benchmark tests.\n")
|
||||
sys.wait(60)
|
||||
|
||||
benchmark_number = 0
|
||||
|
||||
announce_benchmark("maze solver")
|
||||
benchmark_score[benchmark_number] = maze.bench(300)
|
||||
benchmark_number++
|
||||
|
||||
announce_benchmark("n-queens")
|
||||
benchmark_score[benchmark_number] = queens.bench(300)
|
||||
benchmark_number++
|
||||
|
||||
announce_benchmark("mandelbrot (floating point)")
|
||||
benchmark_score[benchmark_number] = mandelbrot.calc(400)
|
||||
benchmark_number++
|
||||
|
||||
announce_benchmark("game of life")
|
||||
benchmark_score[benchmark_number] = life.benchmark(300)
|
||||
benchmark_number++
|
||||
|
||||
announce_benchmark("3d model rotation")
|
||||
benchmark_score[benchmark_number] = rotate3d.benchmark(300)
|
||||
benchmark_number++
|
||||
|
||||
announce_benchmark("adpcm audio decoding")
|
||||
benchmark_score[benchmark_number] = adpcm.decode_benchmark(300)
|
||||
benchmark_number++
|
||||
|
||||
announce_benchmark("circles with gfx_lores")
|
||||
benchmark_score[benchmark_number] = circles.draw(false, 300)
|
||||
benchmark_number++
|
||||
|
||||
; announce_benchmark("circles with kernal")
|
||||
; benchmark_score[benchmark_number] = circles.draw(true, 300)
|
||||
; benchmark_number++
|
||||
|
||||
announce_benchmark("text-elite")
|
||||
benchmark_score[benchmark_number] = textelite.bench(120)
|
||||
benchmark_number++
|
||||
|
||||
benchmark_names[benchmark_number] = 0
|
||||
benchmark_score[benchmark_number] = 0
|
||||
|
||||
void cx16.set_screen_mode(3)
|
||||
txt.uppercase()
|
||||
txt.color2(1, 6)
|
||||
uword final_score
|
||||
benchmark_number = 0
|
||||
txt.print("\nscore benchmark\n\n")
|
||||
do {
|
||||
txt.spc()
|
||||
txt.print_uw(benchmark_score[benchmark_number])
|
||||
txt.column(6)
|
||||
txt.print(benchmark_names[benchmark_number])
|
||||
final_score += benchmark_score[benchmark_number]
|
||||
txt.nl()
|
||||
benchmark_number++
|
||||
} until benchmark_names[benchmark_number]==0
|
||||
|
||||
txt.print("\n\nfinal score : ")
|
||||
txt.print_uw(final_score)
|
||||
txt.nl()
|
||||
|
||||
sub announce_benchmark(str name) {
|
||||
benchmark_names[benchmark_number] = name
|
||||
void cx16.set_screen_mode(3)
|
||||
txt.uppercase()
|
||||
txt.color2(1, 6)
|
||||
txt.clear_screen()
|
||||
txt.plot(4, 6)
|
||||
txt.print(benchmark_names[benchmark_number])
|
||||
txt.nl()
|
||||
sys.wait(60)
|
||||
}
|
||||
}
|
||||
}
|
26
build.gradle.kts
Normal file
26
build.gradle.kts
Normal file
@ -0,0 +1,26 @@
|
||||
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
|
||||
|
||||
plugins {
|
||||
kotlin("jvm") version "2.1.0"
|
||||
}
|
||||
|
||||
allprojects {
|
||||
apply(plugin="kotlin")
|
||||
|
||||
repositories {
|
||||
mavenLocal()
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
kotlin {
|
||||
compilerOptions {
|
||||
freeCompilerArgs = listOf("-Xwhen-guards")
|
||||
jvmTarget = JvmTarget.JVM_11
|
||||
}
|
||||
}
|
||||
|
||||
java {
|
||||
targetCompatibility = JavaVersion.VERSION_11
|
||||
sourceCompatibility = JavaVersion.VERSION_11
|
||||
}
|
||||
}
|
24
codeCore/build.gradle.kts
Normal file
24
codeCore/build.gradle.kts
Normal file
@ -0,0 +1,24 @@
|
||||
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
|
||||
|
||||
plugins {
|
||||
kotlin("jvm")
|
||||
}
|
||||
|
||||
dependencies {
|
||||
// should have no dependencies to other modules
|
||||
// implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
|
||||
implementation("com.michael-bull.kotlin-result:kotlin-result-jvm:2.0.0")
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
main {
|
||||
java {
|
||||
srcDir("${project.projectDir}/src")
|
||||
}
|
||||
resources {
|
||||
srcDir("${project.projectDir}/res")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// note: there are no unit tests in this module!
|
@ -4,13 +4,11 @@
|
||||
<exclude-output />
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build" />
|
||||
</content>
|
||||
<orderEntry type="jdk" jdkName="11" jdkType="JavaSDK" />
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
<orderEntry type="library" name="KotlinJavaRuntime" level="project" />
|
||||
<orderEntry type="library" name="takes-http" level="project" />
|
||||
<orderEntry type="library" name="javax.json-api-1.1.4" level="project" />
|
||||
<orderEntry type="module" module-name="compiler" />
|
||||
<orderEntry type="library" name="slf4j-api-1.7.30" level="project" />
|
||||
<orderEntry type="library" name="michael.bull.kotlin.result.jvm" level="project" />
|
||||
</component>
|
||||
</module>
|
24
codeCore/src/prog8/code/Either.kt
Normal file
24
codeCore/src/prog8/code/Either.kt
Normal file
@ -0,0 +1,24 @@
|
||||
package prog8.code
|
||||
|
||||
/**
|
||||
* By convention, the right side of an `Either` is used to hold successful values.
|
||||
*/
|
||||
sealed class Either<out L, out R> {
|
||||
|
||||
data class Left<out L>(val value: L) : Either<L, Nothing>()
|
||||
|
||||
data class Right<out R>(val value: R) : Either<Nothing, R>()
|
||||
|
||||
fun isRight() = this is Right<R>
|
||||
|
||||
fun isLeft() = this is Left<L>
|
||||
|
||||
inline fun <C> fold(ifLeft: (L) -> C, ifRight: (R) -> C): C = when (this) {
|
||||
is Right -> ifRight(value)
|
||||
is Left -> ifLeft(value)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fun <L> left(a: L) = Either.Left(a)
|
||||
fun <R> right(b: R) = Either.Right(b)
|
286
codeCore/src/prog8/code/SymbolTable.kt
Normal file
286
codeCore/src/prog8/code/SymbolTable.kt
Normal file
@ -0,0 +1,286 @@
|
||||
package prog8.code
|
||||
|
||||
import prog8.code.ast.PtAsmSub
|
||||
import prog8.code.ast.PtNode
|
||||
import prog8.code.ast.PtProgram
|
||||
import prog8.code.core.*
|
||||
|
||||
|
||||
const val internedStringsModuleName = "prog8_interned_strings"
|
||||
|
||||
|
||||
/**
|
||||
* Tree structure containing all symbol definitions in the program
|
||||
* (blocks, subroutines, variables (all types), memoryslabs, and labels).
|
||||
*/
|
||||
class SymbolTable(astProgram: PtProgram) : StNode(astProgram.name, StNodeType.GLOBAL, astProgram) {
|
||||
/**
|
||||
* The table as a flat mapping of scoped names to the StNode.
|
||||
* This gives the fastest lookup possible (no need to traverse tree nodes)
|
||||
*/
|
||||
|
||||
private var cachedFlat: Map<String, StNode>? = null
|
||||
|
||||
val flat: Map<String, StNode> get() {
|
||||
if(cachedFlat!=null)
|
||||
return cachedFlat!!
|
||||
|
||||
val result = mutableMapOf<String, StNode>()
|
||||
fun collect(node: StNode) {
|
||||
for(child in node.children) {
|
||||
result[child.value.scopedName] = child.value
|
||||
collect(child.value)
|
||||
}
|
||||
}
|
||||
collect(this)
|
||||
cachedFlat = result
|
||||
return result
|
||||
}
|
||||
|
||||
fun resetCachedFlat() {
|
||||
cachedFlat = null
|
||||
}
|
||||
|
||||
val allVariables: Collection<StStaticVariable> by lazy {
|
||||
// can't be done with a generic function because those don't support local recursive functions yet
|
||||
val vars = mutableListOf<StStaticVariable>()
|
||||
fun collect(node: StNode) {
|
||||
for(child in node.children) {
|
||||
if(child.value.type== StNodeType.STATICVAR)
|
||||
vars.add(child.value as StStaticVariable)
|
||||
else
|
||||
collect(child.value)
|
||||
}
|
||||
}
|
||||
collect(this)
|
||||
vars
|
||||
}
|
||||
|
||||
val allMemMappedVariables: Collection<StMemVar> by lazy {
|
||||
// can't be done with a generic function because those don't support local recursive functions yet
|
||||
val vars = mutableListOf<StMemVar>()
|
||||
fun collect(node: StNode) {
|
||||
for(child in node.children) {
|
||||
if(child.value.type== StNodeType.MEMVAR)
|
||||
vars.add(child.value as StMemVar)
|
||||
else
|
||||
collect(child.value)
|
||||
}
|
||||
}
|
||||
collect(this)
|
||||
vars
|
||||
}
|
||||
|
||||
val allMemorySlabs: Collection<StMemorySlab> by lazy {
|
||||
// can't be done with a generic function because those don't support local recursive functions yet
|
||||
val vars = mutableListOf<StMemorySlab>()
|
||||
fun collect(node: StNode) {
|
||||
for(child in node.children) {
|
||||
if(child.value.type== StNodeType.MEMORYSLAB)
|
||||
vars.add(child.value as StMemorySlab)
|
||||
else
|
||||
collect(child.value)
|
||||
}
|
||||
}
|
||||
collect(this)
|
||||
vars
|
||||
}
|
||||
|
||||
override fun lookup(scopedName: String) = flat[scopedName]
|
||||
|
||||
fun getLength(name: String): Int? {
|
||||
return when(val node = flat[name]) {
|
||||
is StMemVar -> node.length
|
||||
is StMemorySlab -> node.size.toInt()
|
||||
is StStaticVariable -> node.length
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
enum class StNodeType {
|
||||
GLOBAL,
|
||||
// MODULE, // not used with current scoping rules
|
||||
BLOCK,
|
||||
SUBROUTINE,
|
||||
EXTSUB,
|
||||
LABEL,
|
||||
STATICVAR,
|
||||
MEMVAR,
|
||||
CONSTANT,
|
||||
BUILTINFUNC,
|
||||
MEMORYSLAB
|
||||
}
|
||||
|
||||
|
||||
open class StNode(val name: String,
|
||||
val type: StNodeType,
|
||||
val astNode: PtNode?,
|
||||
val children: MutableMap<String, StNode> = mutableMapOf()
|
||||
) {
|
||||
|
||||
lateinit var parent: StNode
|
||||
|
||||
val scopedName: String by lazy { scopedNameList.joinToString(".") }
|
||||
|
||||
open fun lookup(scopedName: String) =
|
||||
lookup(scopedName.split('.'))
|
||||
|
||||
fun lookupUnscopedOrElse(name: String, default: () -> StNode) =
|
||||
lookupUnscoped(name) ?: default()
|
||||
|
||||
fun lookupOrElse(scopedName: String, default: () -> StNode): StNode =
|
||||
lookup(scopedName.split('.')) ?: default()
|
||||
|
||||
fun lookupUnscoped(name: String): StNode? {
|
||||
// first consider the builtin functions
|
||||
var globalscope = this
|
||||
while(globalscope.type!= StNodeType.GLOBAL)
|
||||
globalscope = globalscope.parent
|
||||
val globalNode = globalscope.children[name]
|
||||
if(globalNode!=null && globalNode.type== StNodeType.BUILTINFUNC)
|
||||
return globalNode
|
||||
|
||||
// search for the unqualified name in the current scope or its parent scopes
|
||||
var scope=this
|
||||
while(true) {
|
||||
val node = scope.children[name]
|
||||
if(node!=null)
|
||||
return node
|
||||
if(scope.type== StNodeType.GLOBAL)
|
||||
return null
|
||||
else
|
||||
scope = scope.parent
|
||||
}
|
||||
}
|
||||
|
||||
fun add(child: StNode) {
|
||||
children[child.name] = child
|
||||
child.parent = this
|
||||
}
|
||||
|
||||
private val scopedNameList: List<String> by lazy {
|
||||
if(type==StNodeType.GLOBAL)
|
||||
emptyList()
|
||||
else
|
||||
parent.scopedNameList + name
|
||||
}
|
||||
|
||||
private fun lookup(scopedName: List<String>): StNode? {
|
||||
// a scoped name refers to a name in another namespace, and always stars from the root.
|
||||
var node = this
|
||||
while(node.type!=StNodeType.GLOBAL)
|
||||
node = node.parent
|
||||
|
||||
for(name in scopedName) {
|
||||
if(name in node.children)
|
||||
node = node.children.getValue(name)
|
||||
else
|
||||
return null
|
||||
}
|
||||
return node
|
||||
}
|
||||
}
|
||||
|
||||
class StStaticVariable(name: String,
|
||||
val dt: DataType,
|
||||
val initializationStringValue: StString?,
|
||||
val initializationArrayValue: StArray?,
|
||||
val length: Int?, // for arrays: the number of elements, for strings: number of characters *including* the terminating 0-byte
|
||||
val zpwish: ZeropageWish, // used in the variable allocator
|
||||
val align: Int,
|
||||
astNode: PtNode?) : StNode(name, StNodeType.STATICVAR, astNode) {
|
||||
|
||||
var initializationNumericValue: Double? = null
|
||||
private set
|
||||
|
||||
fun setOnetimeInitNumeric(number: Double) {
|
||||
// In certain cases the init value of an existing var should be updated,
|
||||
// so we can't ask this as a constructor parameter.
|
||||
// This has to do with the way Prog8 does the (re)initialization of such variables: via code assignment statements.
|
||||
// Certain codegens might want to put them back into the variable directly.
|
||||
// For strings and arrays this doesn't occur - these are always already specced at creation time.
|
||||
initializationNumericValue = number
|
||||
}
|
||||
|
||||
val uninitialized: Boolean
|
||||
get() = initializationArrayValue==null && initializationStringValue==null && initializationNumericValue==null
|
||||
|
||||
init {
|
||||
if(length!=null) {
|
||||
require(initializationNumericValue == null)
|
||||
if(initializationArrayValue!=null)
|
||||
require(initializationArrayValue.isEmpty() ||initializationArrayValue.size==length)
|
||||
}
|
||||
if(initializationNumericValue!=null) {
|
||||
require(dt.isNumericOrBool)
|
||||
}
|
||||
if(initializationArrayValue!=null) {
|
||||
require(dt.isArray)
|
||||
require(length == initializationArrayValue.size)
|
||||
}
|
||||
if(initializationStringValue!=null) {
|
||||
require(dt.isString)
|
||||
require(length == initializationStringValue.first.length + 1)
|
||||
}
|
||||
if(align > 0) {
|
||||
require(dt.isString || dt.isArray)
|
||||
require(zpwish != ZeropageWish.REQUIRE_ZEROPAGE && zpwish != ZeropageWish.PREFER_ZEROPAGE)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class StConstant(name: String, val dt: BaseDataType, val value: Double, astNode: PtNode?) :
|
||||
StNode(name, StNodeType.CONSTANT, astNode)
|
||||
|
||||
|
||||
class StMemVar(name: String,
|
||||
val dt: DataType,
|
||||
val address: UInt,
|
||||
val length: Int?, // for arrays: the number of elements, for strings: number of characters *including* the terminating 0-byte
|
||||
astNode: PtNode?) :
|
||||
StNode(name, StNodeType.MEMVAR, astNode) {
|
||||
|
||||
init{
|
||||
require(!dt.isString)
|
||||
if(dt.isStringly && !dt.isWord)
|
||||
requireNotNull(length)
|
||||
}
|
||||
}
|
||||
|
||||
class StMemorySlab(
|
||||
name: String,
|
||||
val size: UInt,
|
||||
val align: UInt,
|
||||
astNode: PtNode?
|
||||
):
|
||||
StNode(name, StNodeType.MEMORYSLAB, astNode)
|
||||
|
||||
|
||||
class StSub(name: String, val parameters: List<StSubroutineParameter>, val returnType: DataType?, astNode: PtNode) :
|
||||
StNode(name, StNodeType.SUBROUTINE, astNode)
|
||||
|
||||
|
||||
class StExtSub(name: String,
|
||||
val address: PtAsmSub.Address?, // null in case of asmsub, specified in case of extsub.
|
||||
val parameters: List<StExtSubParameter>,
|
||||
val returns: List<StExtSubParameter>,
|
||||
astNode: PtNode) :
|
||||
StNode(name, StNodeType.EXTSUB, astNode)
|
||||
|
||||
|
||||
|
||||
class StSubroutineParameter(val name: String, val type: DataType, val register: RegisterOrPair?)
|
||||
class StExtSubParameter(val register: RegisterOrStatusflag, val type: DataType)
|
||||
class StArrayElement(val number: Double?, val addressOfSymbol: String?, val boolean: Boolean?) {
|
||||
init {
|
||||
if(number!=null) require(addressOfSymbol==null && boolean==null)
|
||||
if(addressOfSymbol!=null) require(number==null && boolean==null)
|
||||
if(boolean!=null) require(addressOfSymbol==null && number==null)
|
||||
}
|
||||
}
|
||||
|
||||
typealias StString = Pair<String, Encoding>
|
||||
typealias StArray = List<StArrayElement>
|
214
codeCore/src/prog8/code/SymbolTableMaker.kt
Normal file
214
codeCore/src/prog8/code/SymbolTableMaker.kt
Normal file
@ -0,0 +1,214 @@
|
||||
package prog8.code
|
||||
|
||||
import prog8.code.ast.*
|
||||
import prog8.code.core.*
|
||||
import prog8.code.target.VMTarget
|
||||
|
||||
|
||||
class SymbolTableMaker(private val program: PtProgram, private val options: CompilationOptions) {
|
||||
fun make(): SymbolTable {
|
||||
val st = SymbolTable(program)
|
||||
|
||||
BuiltinFunctions.forEach {
|
||||
val dt = DataType.forDt(it.value.returnType ?: BaseDataType.UNDEFINED)
|
||||
st.add(StNode(it.key, StNodeType.BUILTINFUNC, PtIdentifier(it.key, dt, Position.DUMMY)))
|
||||
}
|
||||
|
||||
val scopestack = ArrayDeque<StNode>()
|
||||
scopestack.add(st)
|
||||
program.children.forEach {
|
||||
addToSt(it, scopestack)
|
||||
}
|
||||
require(scopestack.size==1)
|
||||
|
||||
if(options.compTarget.name != VMTarget.NAME) {
|
||||
listOf(
|
||||
PtMemMapped("P8ZP_SCRATCH_B1", DataType.forDt(BaseDataType.UBYTE), options.compTarget.machine.zeropage.SCRATCH_B1, null, Position.DUMMY),
|
||||
PtMemMapped("P8ZP_SCRATCH_REG", DataType.forDt(BaseDataType.UBYTE), options.compTarget.machine.zeropage.SCRATCH_REG, null, Position.DUMMY),
|
||||
PtMemMapped("P8ZP_SCRATCH_W1", DataType.forDt(BaseDataType.UWORD), options.compTarget.machine.zeropage.SCRATCH_W1, null, Position.DUMMY),
|
||||
PtMemMapped("P8ZP_SCRATCH_W2", DataType.forDt(BaseDataType.UWORD), options.compTarget.machine.zeropage.SCRATCH_W2, null, Position.DUMMY),
|
||||
).forEach {
|
||||
it.parent = program
|
||||
st.add(StMemVar(it.name, it.type, it.address, it.arraySize?.toInt(), it))
|
||||
}
|
||||
}
|
||||
|
||||
return st
|
||||
}
|
||||
|
||||
private fun addToSt(node: PtNode, scope: ArrayDeque<StNode>) {
|
||||
val stNode = when(node) {
|
||||
is PtAsmSub -> {
|
||||
val parameters = node.parameters.map { StExtSubParameter(it.first, it.second.type) }
|
||||
val returns = node.returns.map { StExtSubParameter(it.first, it.second) }
|
||||
StExtSub(node.name, node.address, parameters, returns, node)
|
||||
}
|
||||
is PtBlock -> {
|
||||
StNode(node.name, StNodeType.BLOCK, node)
|
||||
}
|
||||
is PtConstant -> {
|
||||
require(node.type.isNumericOrBool)
|
||||
StConstant(node.name, node.type.base, node.value, node)
|
||||
}
|
||||
is PtLabel -> {
|
||||
StNode(node.name, StNodeType.LABEL, node)
|
||||
}
|
||||
is PtMemMapped -> {
|
||||
StMemVar(node.name, node.type, node.address, node.arraySize?.toInt(), node)
|
||||
}
|
||||
is PtSub -> {
|
||||
val params = node.parameters.map {StSubroutineParameter(it.name, it.type, it.register) }
|
||||
StSub(node.name, params, node.returntype, node)
|
||||
}
|
||||
is PtVariable -> {
|
||||
val initialNumeric: Double?
|
||||
val initialString: StString?
|
||||
val initialArray: StArray?
|
||||
val numElements: Int?
|
||||
val value = node.value
|
||||
if(value!=null) {
|
||||
when (value) {
|
||||
is PtString -> {
|
||||
initialString = StString(value.value, value.encoding)
|
||||
initialArray = null
|
||||
initialNumeric = null
|
||||
numElements = value.value.length + 1 // include the terminating 0-byte
|
||||
}
|
||||
is PtArray -> {
|
||||
initialArray = makeInitialArray(value)
|
||||
initialString = null
|
||||
initialNumeric = null
|
||||
numElements = initialArray.size
|
||||
require(node.arraySize?.toInt()==numElements)
|
||||
}
|
||||
else -> {
|
||||
require(value is PtNumber)
|
||||
initialString = null
|
||||
initialArray = null
|
||||
val number = value.number
|
||||
initialNumeric = number
|
||||
numElements = node.arraySize?.toInt()
|
||||
}
|
||||
}
|
||||
} else {
|
||||
initialNumeric = null
|
||||
initialArray = null
|
||||
initialString = null
|
||||
numElements = node.arraySize?.toInt()
|
||||
}
|
||||
// if(node.type in SplitWordArrayTypes) {
|
||||
// ... split array also add _lsb and _msb to symboltable?
|
||||
// }
|
||||
val stVar = StStaticVariable(node.name, node.type, initialString, initialArray, numElements, node.zeropage, node.align.toInt(), node)
|
||||
if(initialNumeric!=null)
|
||||
stVar.setOnetimeInitNumeric(initialNumeric)
|
||||
stVar
|
||||
}
|
||||
is PtBuiltinFunctionCall -> {
|
||||
if(node.name=="memory") {
|
||||
// memory slab allocations are a builtin functioncall in the program, but end up named as well in the symboltable
|
||||
require(node.name.all { it.isLetterOrDigit() || it=='_' }) {"memory name should be a valid symbol name"}
|
||||
val slabname = (node.args[0] as PtString).value
|
||||
val size = (node.args[1] as PtNumber).number.toUInt()
|
||||
val align = (node.args[2] as PtNumber).number.toUInt()
|
||||
// don't add memory slabs in nested scope, just put them in the top level of the ST
|
||||
scope.first().add(StMemorySlab("prog8_memoryslab_$slabname", size, align, node))
|
||||
}
|
||||
null
|
||||
}
|
||||
else -> null // node is not present in the ST
|
||||
}
|
||||
|
||||
if(stNode!=null) {
|
||||
scope.last().add(stNode)
|
||||
scope.add(stNode)
|
||||
}
|
||||
node.children.forEach {
|
||||
addToSt(it, scope)
|
||||
}
|
||||
if(stNode!=null)
|
||||
scope.removeLast()
|
||||
}
|
||||
|
||||
private fun makeInitialArray(value: PtArray): List<StArrayElement> {
|
||||
return value.children.map {
|
||||
when(it) {
|
||||
is PtAddressOf -> {
|
||||
if(it.isFromArrayElement)
|
||||
TODO("address-of array element $it in initial array value")
|
||||
StArrayElement(null, it.identifier.name, null)
|
||||
}
|
||||
is PtNumber -> StArrayElement(it.number, null, null)
|
||||
is PtBool -> StArrayElement(null, null, it.value)
|
||||
else -> throw AssemblyError("invalid array element $it")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// override fun visit(decl: VarDecl) {
|
||||
// val node =
|
||||
// when(decl.type) {
|
||||
// VarDeclType.VAR -> {
|
||||
// var initialNumeric = (decl.value as? NumericLiteral)?.number
|
||||
// if(initialNumeric==0.0)
|
||||
// initialNumeric=null // variable will go into BSS and this will be set to 0
|
||||
// val initialStringLit = decl.value as? StringLiteral
|
||||
// val initialString = if(initialStringLit==null) null else Pair(initialStringLit.value, initialStringLit.encoding)
|
||||
// val initialArrayLit = decl.value as? ArrayLiteral
|
||||
// val initialArray = makeInitialArray(initialArrayLit)
|
||||
// if(decl.isArray && decl.datatype !in ArrayDatatypes)
|
||||
// throw FatalAstException("array vardecl has mismatched dt ${decl.datatype}")
|
||||
// val numElements =
|
||||
// if(decl.isArray)
|
||||
// decl.arraysize!!.constIndex()
|
||||
// else if(initialStringLit!=null)
|
||||
// initialStringLit.value.length+1 // include the terminating 0-byte
|
||||
// else
|
||||
// null
|
||||
// val bss = if(decl.datatype==DataType.STR)
|
||||
// false
|
||||
// else if(decl.isArray)
|
||||
// initialArray.isNullOrEmpty()
|
||||
// else
|
||||
// initialNumeric == null
|
||||
// val astNode = PtVariable(decl.name, decl.datatype, null, null, decl.position)
|
||||
// StStaticVariable(decl.name, decl.datatype, bss, initialNumeric, initialString, initialArray, numElements, decl.zeropage, astNode, decl.position)
|
||||
// }
|
||||
// VarDeclType.CONST -> {
|
||||
// val astNode = PtVariable(decl.name, decl.datatype, null, null, decl.position)
|
||||
// StConstant(decl.name, decl.datatype, (decl.value as NumericLiteral).number, astNode, decl.position)
|
||||
// }
|
||||
// VarDeclType.MEMORY -> {
|
||||
// val numElements =
|
||||
// if(decl.isArray)
|
||||
// decl.arraysize!!.constIndex()
|
||||
// else null
|
||||
// val astNode = PtVariable(decl.name, decl.datatype, null, null, decl.position)
|
||||
// StMemVar(decl.name, decl.datatype, (decl.value as NumericLiteral).number.toUInt(), numElements, astNode, decl.position)
|
||||
// }
|
||||
// }
|
||||
// scopestack.peek().add(node)
|
||||
// // st.origAstLinks[decl] = node
|
||||
// }
|
||||
//
|
||||
// private fun makeInitialArray(arrayLit: ArrayLiteral?): StArray? {
|
||||
// if(arrayLit==null)
|
||||
// return null
|
||||
// return arrayLit.value.map {
|
||||
// when(it){
|
||||
// is AddressOf -> {
|
||||
// val scopedName = it.identifier.targetNameAndType(program).first
|
||||
// StArrayElement(null, scopedName)
|
||||
// }
|
||||
// is IdentifierReference -> {
|
||||
// val scopedName = it.targetNameAndType(program).first
|
||||
// StArrayElement(null, scopedName)
|
||||
// }
|
||||
// is NumericLiteral -> StArrayElement(it.number, null)
|
||||
// else -> throw FatalAstException("weird element dt in array literal")
|
||||
// }
|
||||
// }.toList()
|
||||
// }
|
||||
//
|
129
codeCore/src/prog8/code/ast/AstBase.kt
Normal file
129
codeCore/src/prog8/code/ast/AstBase.kt
Normal file
@ -0,0 +1,129 @@
|
||||
package prog8.code.ast
|
||||
|
||||
import prog8.code.core.IMemSizer
|
||||
import prog8.code.core.IStringEncoding
|
||||
import prog8.code.core.Position
|
||||
import prog8.code.source.SourceCode
|
||||
import java.nio.file.Path
|
||||
|
||||
// New simplified AST for the code generator.
|
||||
|
||||
|
||||
sealed class PtNode(val position: Position) {
|
||||
|
||||
val children = mutableListOf<PtNode>()
|
||||
lateinit var parent: PtNode
|
||||
|
||||
fun add(child: PtNode) {
|
||||
children.add(child)
|
||||
child.parent = this
|
||||
}
|
||||
|
||||
fun add(index: Int, child: PtNode) {
|
||||
children.add(index, child)
|
||||
child.parent = this
|
||||
}
|
||||
|
||||
fun definingBlock() = findParentNode<PtBlock>(this)
|
||||
fun definingSub() = findParentNode<PtSub>(this)
|
||||
fun definingAsmSub() = findParentNode<PtAsmSub>(this)
|
||||
fun definingISub() = findParentNode<IPtSubroutine>(this)
|
||||
}
|
||||
|
||||
|
||||
sealed interface IPtStatementContainer
|
||||
|
||||
|
||||
class PtNodeGroup : PtNode(Position.DUMMY), IPtStatementContainer
|
||||
|
||||
|
||||
sealed class PtNamedNode(var name: String, position: Position): PtNode(position) {
|
||||
// Note that as an exception, the 'name' is not read-only
|
||||
// but a var. This is to allow for cheap node renames.
|
||||
val scopedName: String
|
||||
get() {
|
||||
var namedParent: PtNode = this.parent
|
||||
return if(namedParent is PtProgram)
|
||||
name
|
||||
else {
|
||||
while (namedParent !is PtNamedNode)
|
||||
namedParent = namedParent.parent
|
||||
namedParent.scopedName + "." + name
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class PtProgram(
|
||||
val name: String,
|
||||
val memsizer: IMemSizer,
|
||||
val encoding: IStringEncoding
|
||||
) : PtNode(Position.DUMMY) {
|
||||
|
||||
// fun allModuleDirectives(): Sequence<PtDirective> =
|
||||
// children.asSequence().flatMap { it.children }.filterIsInstance<PtDirective>().distinct()
|
||||
|
||||
fun allBlocks(): Sequence<PtBlock> =
|
||||
children.asSequence().filterIsInstance<PtBlock>()
|
||||
|
||||
fun entrypoint(): PtSub? =
|
||||
// returns the main.start subroutine if it exists
|
||||
allBlocks().firstOrNull { it.name == "main" || it.name=="p8b_main" }
|
||||
?.children
|
||||
?.firstOrNull { it is PtSub && (it.name == "start" || it.name=="main.start" || it.name=="p8s_start" || it.name=="p8b_main.p8s_start") } as PtSub?
|
||||
}
|
||||
|
||||
|
||||
class PtBlock(name: String,
|
||||
val library: Boolean,
|
||||
val source: SourceCode, // taken from the module the block is defined in.
|
||||
val options: Options,
|
||||
position: Position
|
||||
) : PtNamedNode(name, position), IPtStatementContainer {
|
||||
class Options(val address: UInt? = null,
|
||||
val forceOutput: Boolean = false,
|
||||
val noSymbolPrefixing: Boolean = false,
|
||||
val veraFxMuls: Boolean = false,
|
||||
val ignoreUnused: Boolean = false)
|
||||
}
|
||||
|
||||
|
||||
class PtInlineAssembly(val assembly: String, val isIR: Boolean, position: Position) : PtNode(position) {
|
||||
init {
|
||||
require(!assembly.startsWith('\n') && !assembly.startsWith('\r')) { "inline assembly should be trimmed" }
|
||||
require(!assembly.endsWith('\n') && !assembly.endsWith('\r')) { "inline assembly should be trimmed" }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class PtLabel(name: String, position: Position) : PtNamedNode(name, position) {
|
||||
companion object {
|
||||
// all automatically generated labels everywhere need to have the same label name prefix:
|
||||
const val GENERATED_LABEL_PREFIX = "p8_label_gen_"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class PtBreakpoint(position: Position): PtNode(position)
|
||||
|
||||
|
||||
class PtAlign(val align: UInt, position: Position): PtNode(position)
|
||||
|
||||
|
||||
class PtIncludeBinary(val file: Path, val offset: UInt?, val length: UInt?, position: Position) : PtNode(position)
|
||||
|
||||
|
||||
class PtNop(position: Position): PtNode(position)
|
||||
|
||||
|
||||
// find the parent node of a specific type or interface
|
||||
// (useful to figure out in what namespace/block something is defined, etc.)
|
||||
inline fun <reified T> findParentNode(node: PtNode): T? {
|
||||
var candidate = node.parent
|
||||
while(candidate !is T && candidate !is PtProgram)
|
||||
candidate = candidate.parent
|
||||
return if(candidate is PtProgram)
|
||||
null
|
||||
else
|
||||
candidate as T
|
||||
}
|
386
codeCore/src/prog8/code/ast/AstExpressions.kt
Normal file
386
codeCore/src/prog8/code/ast/AstExpressions.kt
Normal file
@ -0,0 +1,386 @@
|
||||
package prog8.code.ast
|
||||
|
||||
import prog8.code.core.*
|
||||
import java.util.*
|
||||
import kotlin.math.abs
|
||||
import kotlin.math.truncate
|
||||
|
||||
|
||||
sealed class PtExpression(val type: DataType, position: Position) : PtNode(position) {
|
||||
|
||||
init {
|
||||
if(type.isUndefined) {
|
||||
@Suppress("LeakingThis")
|
||||
when(this) {
|
||||
is PtBuiltinFunctionCall -> { /* void function call */ }
|
||||
is PtFunctionCall -> { /* void function call */ }
|
||||
is PtIdentifier -> { /* non-variable identifier */ }
|
||||
else -> throw IllegalArgumentException("type should be known @$position")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
infix fun isSameAs(other: PtExpression): Boolean {
|
||||
return when(this) {
|
||||
is PtAddressOf -> {
|
||||
if(other !is PtAddressOf)
|
||||
return false
|
||||
if (other.type!==type || !(other.identifier isSameAs identifier))
|
||||
return false
|
||||
if(other.children.size!=children.size)
|
||||
return false
|
||||
if(children.size==1)
|
||||
return true
|
||||
return arrayIndexExpr!! isSameAs other.arrayIndexExpr!!
|
||||
}
|
||||
is PtArrayIndexer -> other is PtArrayIndexer && other.type==type && other.variable isSameAs variable && other.index isSameAs index && other.splitWords==splitWords
|
||||
is PtBinaryExpression -> {
|
||||
if(other !is PtBinaryExpression || other.operator!=operator)
|
||||
false
|
||||
else if(operator in AssociativeOperators)
|
||||
(other.left isSameAs left && other.right isSameAs right) || (other.left isSameAs right && other.right isSameAs left)
|
||||
else
|
||||
other.left isSameAs left && other.right isSameAs right
|
||||
}
|
||||
is PtContainmentCheck -> {
|
||||
if(other !is PtContainmentCheck || other.type != type || !(other.needle isSameAs needle))
|
||||
false
|
||||
else {
|
||||
if(haystackHeapVar!=null)
|
||||
other.haystackHeapVar!=null && other.haystackHeapVar!! isSameAs haystackHeapVar!!
|
||||
else if(haystackValues!=null)
|
||||
other.haystackValues!=null && other.haystackValues!! isSameAs haystackValues!!
|
||||
else
|
||||
false
|
||||
}
|
||||
}
|
||||
is PtIdentifier -> other is PtIdentifier && other.type==type && other.name==name
|
||||
is PtIrRegister -> other is PtIrRegister && other.type==type && other.register==register
|
||||
is PtMemoryByte -> other is PtMemoryByte && other.address isSameAs address
|
||||
is PtNumber -> other is PtNumber && other.type==type && other.number==number
|
||||
is PtBool -> other is PtBool && other.value==value
|
||||
is PtPrefix -> other is PtPrefix && other.type==type && other.operator==operator && other.value isSameAs value
|
||||
is PtRange -> other is PtRange && other.type==type && other.from==from && other.to==to && other.step==step
|
||||
is PtTypeCast -> other is PtTypeCast && other.type==type && other.value isSameAs value
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
|
||||
infix fun isSameAs(target: PtAssignTarget): Boolean = when {
|
||||
target.memory != null && this is PtMemoryByte -> {
|
||||
target.memory!!.address isSameAs this.address
|
||||
}
|
||||
target.identifier != null && this is PtIdentifier -> {
|
||||
this.name == target.identifier!!.name
|
||||
}
|
||||
target.array != null && this is PtArrayIndexer -> {
|
||||
this.variable.name == target.array!!.variable.name && this.index isSameAs target.array!!.index && this.splitWords==target.array!!.splitWords
|
||||
}
|
||||
else -> false
|
||||
}
|
||||
|
||||
fun asConstInteger(): Int? = (this as? PtNumber)?.number?.toInt() ?: (this as? PtBool)?.asInt()
|
||||
fun asConstValue(): Double? = (this as? PtNumber)?.number ?: (this as? PtBool)?.asInt()?.toDouble()
|
||||
|
||||
fun isSimple(): Boolean {
|
||||
return when(this) {
|
||||
is PtAddressOf -> this.arrayIndexExpr==null || this.arrayIndexExpr?.isSimple()==true
|
||||
is PtArray -> true
|
||||
is PtArrayIndexer -> index is PtNumber || index is PtIdentifier
|
||||
is PtBinaryExpression -> false
|
||||
is PtBuiltinFunctionCall -> {
|
||||
when (name) {
|
||||
in arrayOf("msb", "lsb", "msw", "lsw", "mkword", "set_carry", "set_irqd", "clear_carry", "clear_irqd") -> this.args.all { it.isSimple() }
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
is PtContainmentCheck -> false
|
||||
is PtFunctionCall -> false
|
||||
is PtIdentifier -> true
|
||||
is PtIrRegister -> true
|
||||
is PtMemoryByte -> address is PtNumber || address is PtIdentifier
|
||||
is PtBool -> true
|
||||
is PtNumber -> true
|
||||
is PtPrefix -> value.isSimple()
|
||||
is PtRange -> true
|
||||
is PtString -> true
|
||||
is PtTypeCast -> value.isSimple()
|
||||
is PtIfExpression -> condition.isSimple() && truevalue.isSimple() && falsevalue.isSimple()
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
fun clone(): PtExpression {
|
||||
fun withClonedChildrenFrom(orig: PtExpression, clone: PtExpression): PtExpression {
|
||||
orig.children.forEach { clone.add((it as PtExpression).clone()) }
|
||||
return clone
|
||||
}
|
||||
when(this) {
|
||||
is PtAddressOf -> return withClonedChildrenFrom(this, PtAddressOf(position))
|
||||
is PtArray -> return withClonedChildrenFrom(this, PtArray(type, position))
|
||||
is PtArrayIndexer -> return withClonedChildrenFrom(this, PtArrayIndexer(type, position))
|
||||
is PtBinaryExpression -> return withClonedChildrenFrom(this, PtBinaryExpression(operator, type, position))
|
||||
is PtBuiltinFunctionCall -> return withClonedChildrenFrom(this, PtBuiltinFunctionCall(name, void, hasNoSideEffects, type, position))
|
||||
is PtContainmentCheck -> return withClonedChildrenFrom(this, PtContainmentCheck(position))
|
||||
is PtFunctionCall -> return withClonedChildrenFrom(this, PtFunctionCall(name, void, type, position))
|
||||
is PtIdentifier -> return withClonedChildrenFrom(this, PtIdentifier(name, type, position))
|
||||
is PtMachineRegister -> return withClonedChildrenFrom(this, PtMachineRegister(register, type, position))
|
||||
is PtMemoryByte -> return withClonedChildrenFrom(this, PtMemoryByte(position))
|
||||
is PtNumber -> return withClonedChildrenFrom(this, PtNumber(type, number, position))
|
||||
is PtBool -> return withClonedChildrenFrom(this, PtBool(value, position))
|
||||
is PtPrefix -> return withClonedChildrenFrom(this, PtPrefix(operator, type, position))
|
||||
is PtRange -> return withClonedChildrenFrom(this, PtRange(type, position))
|
||||
is PtString -> return withClonedChildrenFrom(this, PtString(value, encoding, position))
|
||||
is PtTypeCast -> return withClonedChildrenFrom(this, PtTypeCast(type, position))
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
class PtAddressOf(position: Position, val isMsbForSplitArray: Boolean=false) : PtExpression(DataType.forDt(BaseDataType.UWORD), position) {
|
||||
val identifier: PtIdentifier
|
||||
get() = children[0] as PtIdentifier
|
||||
val arrayIndexExpr: PtExpression?
|
||||
get() = if(children.size==2) children[1] as PtExpression else null
|
||||
|
||||
val isFromArrayElement: Boolean
|
||||
get() = children.size==2
|
||||
}
|
||||
|
||||
|
||||
class PtArrayIndexer(elementType: DataType, position: Position): PtExpression(elementType, position) {
|
||||
val variable: PtIdentifier
|
||||
get() = children[0] as PtIdentifier
|
||||
val index: PtExpression
|
||||
get() = children[1] as PtExpression
|
||||
val splitWords: Boolean
|
||||
get() = variable.type.isSplitWordArray
|
||||
|
||||
init {
|
||||
require(elementType.isNumericOrBool)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class PtArray(type: DataType, position: Position): PtExpression(type, position) {
|
||||
// children are always one of 3 types: PtBool, PtNumber or PtAddressOf.
|
||||
override fun hashCode(): Int = Objects.hash(children, type)
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if(other==null || other !is PtArray)
|
||||
return false
|
||||
return type==other.type && children == other.children
|
||||
}
|
||||
|
||||
val size: Int
|
||||
get() = children.size
|
||||
}
|
||||
|
||||
|
||||
class PtBuiltinFunctionCall(val name: String,
|
||||
val void: Boolean,
|
||||
val hasNoSideEffects: Boolean,
|
||||
type: DataType,
|
||||
position: Position) : PtExpression(type, position) {
|
||||
init {
|
||||
if(!void)
|
||||
require(!type.isUndefined)
|
||||
}
|
||||
|
||||
val args: List<PtExpression>
|
||||
get() = children.map { it as PtExpression }
|
||||
}
|
||||
|
||||
|
||||
class PtBinaryExpression(val operator: String, type: DataType, position: Position): PtExpression(type, position) {
|
||||
val left: PtExpression
|
||||
get() = children[0] as PtExpression
|
||||
val right: PtExpression
|
||||
get() = children[1] as PtExpression
|
||||
|
||||
init {
|
||||
if(operator in ComparisonOperators + LogicalOperators)
|
||||
require(type.isBool)
|
||||
else
|
||||
require(!type.isBool) { "no bool allowed for this operator $operator"}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class PtIfExpression(type: DataType, position: Position): PtExpression(type, position) {
|
||||
val condition: PtExpression
|
||||
get() = children[0] as PtExpression
|
||||
val truevalue: PtExpression
|
||||
get() = children[1] as PtExpression
|
||||
val falsevalue: PtExpression
|
||||
get() = children[2] as PtExpression
|
||||
}
|
||||
|
||||
|
||||
class PtContainmentCheck(position: Position): PtExpression(DataType.forDt(BaseDataType.BOOL), position) {
|
||||
val needle: PtExpression
|
||||
get() = children[0] as PtExpression
|
||||
val haystackHeapVar: PtIdentifier?
|
||||
get() = children[1] as? PtIdentifier
|
||||
val haystackValues: PtArray?
|
||||
get() = children[1] as? PtArray
|
||||
|
||||
companion object {
|
||||
const val MAX_SIZE_FOR_INLINE_CHECKS_BYTE = 5
|
||||
const val MAX_SIZE_FOR_INLINE_CHECKS_WORD = 4
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class PtFunctionCall(val name: String,
|
||||
val void: Boolean,
|
||||
type: DataType,
|
||||
position: Position) : PtExpression(type, position) {
|
||||
val args: List<PtExpression>
|
||||
get() = children.map { it as PtExpression }
|
||||
|
||||
init {
|
||||
if(void) require(type.isUndefined) {
|
||||
"void fcall should have undefined datatype"
|
||||
}
|
||||
// note: non-void calls can have UNDEFINED type: is if they return more than 1 value
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class PtIdentifier(val name: String, type: DataType, position: Position) : PtExpression(type, position) {
|
||||
override fun toString(): String {
|
||||
return "[PtIdentifier:$name $type $position]"
|
||||
}
|
||||
|
||||
fun copy() = PtIdentifier(name, type, position)
|
||||
}
|
||||
|
||||
|
||||
class PtMemoryByte(position: Position) : PtExpression(DataType.forDt(BaseDataType.UBYTE), position) {
|
||||
val address: PtExpression
|
||||
get() = children.single() as PtExpression
|
||||
}
|
||||
|
||||
|
||||
class PtBool(val value: Boolean, position: Position) : PtExpression(DataType.forDt(BaseDataType.BOOL), position) {
|
||||
override fun hashCode(): Int = Objects.hash(type, value)
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if(other==null || other !is PtBool)
|
||||
return false
|
||||
return value==other.value
|
||||
}
|
||||
|
||||
override fun toString() = "PtBool:$value"
|
||||
|
||||
fun asInt(): Int = if(value) 1 else 0
|
||||
}
|
||||
|
||||
|
||||
class PtNumber(type: BaseDataType, val number: Double, position: Position) : PtExpression(DataType.forDt(type), position) {
|
||||
|
||||
companion object {
|
||||
fun fromBoolean(bool: Boolean, position: Position): PtNumber =
|
||||
PtNumber(BaseDataType.UBYTE, if(bool) 1.0 else 0.0, position)
|
||||
}
|
||||
|
||||
init {
|
||||
if(type==BaseDataType.BOOL)
|
||||
throw IllegalArgumentException("use PtBool instead")
|
||||
if(type!=BaseDataType.FLOAT) {
|
||||
val trunc = truncate(number)
|
||||
if (trunc != number)
|
||||
throw IllegalArgumentException("refused truncating of float to avoid loss of precision @$position")
|
||||
}
|
||||
when(type) {
|
||||
BaseDataType.UBYTE -> require(number in 0.0..255.0)
|
||||
BaseDataType.BYTE -> require(number in -128.0..127.0)
|
||||
BaseDataType.UWORD -> require(number in 0.0..65535.0)
|
||||
BaseDataType.WORD -> require(number in -32728.0..32767.0)
|
||||
BaseDataType.LONG -> require(number in -2147483647.0..2147483647.0)
|
||||
else -> require(type.isNumeric) { "numeric literal type should be numeric: $type" }
|
||||
}
|
||||
}
|
||||
|
||||
override fun hashCode(): Int = Objects.hash(type, number)
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
return if(other==null || other !is PtNumber)
|
||||
false
|
||||
else if(!type.isBool && !other.type.isBool)
|
||||
number==other.number
|
||||
else
|
||||
type==other.type && number==other.number
|
||||
}
|
||||
|
||||
operator fun compareTo(other: PtNumber): Int = number.compareTo(other.number)
|
||||
|
||||
override fun toString() = "PtNumber:$type:$number"
|
||||
}
|
||||
|
||||
|
||||
class PtPrefix(val operator: String, type: DataType, position: Position): PtExpression(type, position) {
|
||||
val value: PtExpression
|
||||
get() = children.single() as PtExpression
|
||||
|
||||
init {
|
||||
require(operator in PrefixOperators) { "invalid prefix operator: $operator" }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class PtRange(type: DataType, position: Position) : PtExpression(type, position) {
|
||||
val from: PtExpression
|
||||
get() = children[0] as PtExpression
|
||||
val to: PtExpression
|
||||
get() = children[1] as PtExpression
|
||||
val step: PtNumber
|
||||
get() = children[2] as PtNumber
|
||||
|
||||
fun toConstantIntegerRange(): IntProgression? {
|
||||
fun makeRange(fromVal: Int, toVal: Int, stepVal: Int): IntProgression {
|
||||
return when {
|
||||
fromVal == toVal -> fromVal .. toVal
|
||||
fromVal <= toVal -> when {
|
||||
stepVal <= 0 -> IntRange.EMPTY
|
||||
stepVal == 1 -> fromVal..toVal
|
||||
else -> fromVal..toVal step stepVal
|
||||
}
|
||||
else -> when {
|
||||
stepVal >= 0 -> IntRange.EMPTY
|
||||
stepVal == -1 -> fromVal downTo toVal
|
||||
else -> fromVal downTo toVal step abs(stepVal)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val fromLv = from as? PtNumber
|
||||
val toLv = to as? PtNumber
|
||||
if(fromLv==null || toLv==null)
|
||||
return null
|
||||
val fromVal = fromLv.number.toInt()
|
||||
val toVal = toLv.number.toInt()
|
||||
val stepVal = step.number.toInt()
|
||||
return makeRange(fromVal, toVal, stepVal)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class PtString(val value: String, val encoding: Encoding, position: Position) : PtExpression(DataType.forDt(BaseDataType.STR), position) {
|
||||
override fun hashCode(): Int = Objects.hash(value, encoding)
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if(other==null || other !is PtString)
|
||||
return false
|
||||
return value==other.value && encoding == other.encoding
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class PtTypeCast(type: BaseDataType, position: Position) : PtExpression(DataType.forDt(type), position) {
|
||||
val value: PtExpression
|
||||
get() = children.single() as PtExpression
|
||||
}
|
||||
|
||||
|
||||
// special node that isn't created from compiling user code, but used internally in the Intermediate Code
|
||||
class PtIrRegister(val register: Int, type: DataType, position: Position) : PtExpression(type, position)
|
208
codeCore/src/prog8/code/ast/AstPrinter.kt
Normal file
208
codeCore/src/prog8/code/ast/AstPrinter.kt
Normal file
@ -0,0 +1,208 @@
|
||||
package prog8.code.ast
|
||||
|
||||
import prog8.code.core.DataType
|
||||
import prog8.code.core.escape
|
||||
import prog8.code.core.toHex
|
||||
|
||||
/**
|
||||
* Produces readable text from a [PtNode] (AST node, usually starting with PtProgram as root),
|
||||
* passing it as a String to the specified receiver function.
|
||||
*/
|
||||
fun printAst(root: PtNode, skipLibraries: Boolean, output: (text: String) -> Unit) {
|
||||
fun type(dt: DataType) = "!${dt}!"
|
||||
fun txt(node: PtNode): String {
|
||||
return when(node) {
|
||||
is PtAlign -> "%align ${node.align}"
|
||||
is PtAssignTarget -> if(node.void) "<void>" else "<target>"
|
||||
is PtAssignment -> "<assign>"
|
||||
is PtAugmentedAssign -> "<inplace-assign> ${node.operator}"
|
||||
is PtBreakpoint -> "%breakpoint"
|
||||
is PtConditionalBranch -> "if_${node.condition.name.lowercase()}"
|
||||
is PtAddressOf -> {
|
||||
if(node.isMsbForSplitArray)
|
||||
"&>"
|
||||
else if(node.isFromArrayElement)
|
||||
"& array-element"
|
||||
else
|
||||
"&"
|
||||
}
|
||||
is PtArray -> {
|
||||
val valuelist = node.children.joinToString(", ") {
|
||||
when (it) {
|
||||
is PtBool -> it.toString()
|
||||
is PtNumber -> it.number.toString()
|
||||
is PtIdentifier -> it.name
|
||||
is PtAddressOf -> "& ${it.identifier.name}"
|
||||
else -> "invalid array element $it"
|
||||
}
|
||||
}
|
||||
"array len=${node.children.size} ${type(node.type)} [ $valuelist ]"
|
||||
}
|
||||
is PtArrayIndexer -> "<arrayindexer> ${type(node.type)} ${if(node.splitWords) "[splitwords]" else ""}"
|
||||
is PtBinaryExpression -> "<expr> ${node.operator} ${type(node.type)}"
|
||||
is PtBuiltinFunctionCall -> {
|
||||
val str = if(node.void) "void " else ""
|
||||
str + node.name + "()"
|
||||
}
|
||||
is PtContainmentCheck -> "in"
|
||||
is PtFunctionCall -> {
|
||||
val str = if(node.void) "void " else ""
|
||||
str + node.name + "()"
|
||||
}
|
||||
is PtIdentifier -> "${node.name} ${type(node.type)}"
|
||||
is PtIrRegister -> "IRREG#${node.register} ${type(node.type)}"
|
||||
is PtMemoryByte -> "@()"
|
||||
is PtNumber -> {
|
||||
val numstr = if(node.type.isFloat) node.number.toString() else node.number.toHex()
|
||||
"$numstr ${type(node.type)}"
|
||||
}
|
||||
is PtBool -> node.value.toString()
|
||||
is PtPrefix -> node.operator
|
||||
is PtRange -> "<range>"
|
||||
is PtString -> "\"${node.value.escape()}\""
|
||||
is PtTypeCast -> "as ${node.type}"
|
||||
is PtForLoop -> "for"
|
||||
is PtIfElse -> "ifelse"
|
||||
is PtIncludeBinary -> "%incbin '${node.file}', ${node.offset}, ${node.length}"
|
||||
is PtInlineAssembly -> {
|
||||
if(node.isIR)
|
||||
"%ir {{ ...${node.assembly.length} characters... }}"
|
||||
else
|
||||
"%asm {{ ...${node.assembly.length} characters... }}"
|
||||
}
|
||||
is PtJump -> {
|
||||
"goto ${txt(node.target)}"
|
||||
}
|
||||
is PtAsmSub -> {
|
||||
val params = node.parameters.joinToString(", ") {
|
||||
val register = it.first.registerOrPair
|
||||
val statusflag = it.first.statusflag
|
||||
"${it.second.type} ${it.second.name} @${register ?: statusflag}"
|
||||
}
|
||||
val clobbers = if (node.clobbers.isEmpty()) "" else "clobbers ${node.clobbers}"
|
||||
val returns = if (node.returns.isEmpty()) "" else {
|
||||
"-> ${node.returns.joinToString(", ") {
|
||||
val register = it.first.registerOrPair
|
||||
val statusflag = it.first.statusflag
|
||||
"${it.second} @${register ?: statusflag}"
|
||||
}
|
||||
}"
|
||||
}
|
||||
val str = if (node.inline) "inline " else ""
|
||||
if(node.address == null) {
|
||||
str + "asmsub ${node.name}($params) $clobbers $returns"
|
||||
} else {
|
||||
val bank = if(node.address.constbank!=null) "@bank ${node.address.constbank}"
|
||||
else if(node.address.varbank!=null) "@bank ${node.address.varbank?.name}"
|
||||
else ""
|
||||
str + "extsub $bank ${node.address.address.toHex()} = ${node.name}($params) $clobbers $returns"
|
||||
}
|
||||
}
|
||||
is PtBlock -> {
|
||||
val addr = if(node.options.address==null) "" else "@${node.options.address.toHex()}"
|
||||
"\nblock '${node.name}' $addr"
|
||||
}
|
||||
is PtConstant -> {
|
||||
val value = when {
|
||||
node.type.isBool -> if(node.value==0.0) "false" else "true"
|
||||
node.type.isInteger -> node.value.toInt().toString()
|
||||
else -> node.value.toString()
|
||||
}
|
||||
"const ${node.type} ${node.name} = $value"
|
||||
}
|
||||
is PtLabel -> "${node.name}:"
|
||||
is PtMemMapped -> {
|
||||
if(node.type.isArray) {
|
||||
val arraysize = if(node.arraySize==null) "" else node.arraySize.toString()
|
||||
"&${node.type.elementType()}[$arraysize] ${node.name} = ${node.address.toHex()}"
|
||||
} else {
|
||||
"&${node.type} ${node.name} = ${node.address.toHex()}"
|
||||
}
|
||||
}
|
||||
is PtSub -> {
|
||||
val params = node.parameters.joinToString(", ") {
|
||||
val reg = if(it.register!=null) "@${it.register}" else ""
|
||||
"${it.type} ${it.name} $reg"
|
||||
}
|
||||
var str = "sub ${node.name}($params) "
|
||||
if(node.returntype!=null)
|
||||
str += "-> ${node.returntype}"
|
||||
str
|
||||
}
|
||||
is PtVariable -> {
|
||||
val split = if(node.type.isSplitWordArray) "" else "@nosplit"
|
||||
val align = when(node.align) {
|
||||
0u -> ""
|
||||
2u -> "@alignword"
|
||||
64u -> "@align64"
|
||||
256u -> "@alignpage"
|
||||
else -> throw IllegalArgumentException("invalid alignment size")
|
||||
}
|
||||
val str = if(node.arraySize!=null) {
|
||||
val eltType = node.type.elementType()
|
||||
"${eltType}[${node.arraySize}] $split $align ${node.name}"
|
||||
}
|
||||
else if(node.type.isArray) {
|
||||
val eltType = node.type.elementType()
|
||||
"${eltType}[] $split $align ${node.name}"
|
||||
}
|
||||
else
|
||||
"${node.type} ${node.name}"
|
||||
if(node.value!=null)
|
||||
str + " = " + txt(node.value)
|
||||
else
|
||||
str
|
||||
}
|
||||
is PtNodeGroup -> if(node.children.isNotEmpty()) "<group>" else ""
|
||||
is PtNop -> "nop"
|
||||
is PtProgram -> "PROGRAM ${node.name}"
|
||||
is PtRepeatLoop -> "repeat"
|
||||
is PtReturn -> "return"
|
||||
is PtSubroutineParameter -> {
|
||||
val reg = if(node.register!=null) "@${node.register}" else ""
|
||||
"${node.type} ${node.name} $reg"
|
||||
}
|
||||
is PtWhen -> "when"
|
||||
is PtWhenChoice -> {
|
||||
if(node.isElse)
|
||||
"else"
|
||||
else
|
||||
"->"
|
||||
}
|
||||
is PtDefer -> "<defer>"
|
||||
is PtIfExpression -> "<ifexpr>"
|
||||
}
|
||||
}
|
||||
|
||||
if(root is PtProgram) {
|
||||
output(txt(root))
|
||||
root.children.forEach {
|
||||
walkAst(it) { node, depth ->
|
||||
val txt = txt(node)
|
||||
val library = if(node is PtBlock) node.library else node.definingBlock()?.library==true
|
||||
if(!library || !skipLibraries) {
|
||||
if (txt.isNotEmpty())
|
||||
output(" ".repeat(depth) + txt(node))
|
||||
}
|
||||
}
|
||||
}
|
||||
println()
|
||||
} else {
|
||||
walkAst(root) { node, depth ->
|
||||
val txt = txt(node)
|
||||
val library = if(node is PtBlock) node.library else node.definingBlock()?.library==true
|
||||
if(!library || !skipLibraries) {
|
||||
if (txt.isNotEmpty())
|
||||
output(" ".repeat(depth) + txt(node))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun walkAst(root: PtNode, act: (node: PtNode, depth: Int) -> Unit) {
|
||||
fun recurse(node: PtNode, depth: Int) {
|
||||
act(node, depth)
|
||||
node.children.forEach { recurse(it, depth+1) }
|
||||
}
|
||||
recurse(root, 0)
|
||||
}
|
193
codeCore/src/prog8/code/ast/AstStatements.kt
Normal file
193
codeCore/src/prog8/code/ast/AstStatements.kt
Normal file
@ -0,0 +1,193 @@
|
||||
package prog8.code.ast
|
||||
|
||||
import prog8.code.core.*
|
||||
|
||||
|
||||
sealed interface IPtSubroutine {
|
||||
val name: String
|
||||
val scopedName: String
|
||||
}
|
||||
|
||||
class PtAsmSub(
|
||||
name: String,
|
||||
val address: Address?,
|
||||
val clobbers: Set<CpuRegister>,
|
||||
val parameters: List<Pair<RegisterOrStatusflag, PtSubroutineParameter>>,
|
||||
val returns: List<Pair<RegisterOrStatusflag, DataType>>,
|
||||
val inline: Boolean,
|
||||
position: Position
|
||||
) : PtNamedNode(name, position), IPtSubroutine {
|
||||
|
||||
class Address(val constbank: UByte?, var varbank: PtIdentifier?, val address: UInt)
|
||||
}
|
||||
|
||||
|
||||
class PtSub(
|
||||
name: String,
|
||||
val parameters: List<PtSubroutineParameter>,
|
||||
val returntype: DataType?,
|
||||
position: Position
|
||||
) : PtNamedNode(name, position), IPtSubroutine, IPtStatementContainer {
|
||||
init {
|
||||
// params and return value should not be str
|
||||
if(parameters.any{ !it.type.isNumericOrBool })
|
||||
throw AssemblyError("non-numeric/non-bool parameter")
|
||||
if(returntype!=null && !returntype.isNumericOrBool)
|
||||
throw AssemblyError("non-numeric/non-bool returntype $returntype")
|
||||
parameters.forEach { it.parent=this }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class PtSubroutineParameter(name: String, val type: DataType, val register: RegisterOrPair?, position: Position): PtNamedNode(name, position)
|
||||
|
||||
|
||||
sealed interface IPtAssignment {
|
||||
val children: MutableList<PtNode>
|
||||
val target: PtAssignTarget
|
||||
get() {
|
||||
if(children.size==2)
|
||||
return children[0] as PtAssignTarget
|
||||
else if(children.size<2)
|
||||
throw AssemblyError("incomplete node")
|
||||
else
|
||||
throw AssemblyError("no singular target")
|
||||
}
|
||||
val value: PtExpression
|
||||
get() = children.last() as PtExpression
|
||||
val multiTarget: Boolean
|
||||
get() = children.size>2
|
||||
}
|
||||
|
||||
class PtAssignment(position: Position) : PtNode(position), IPtAssignment
|
||||
|
||||
class PtAugmentedAssign(val operator: String, position: Position) : PtNode(position), IPtAssignment
|
||||
|
||||
|
||||
class PtAssignTarget(val void: Boolean, position: Position) : PtNode(position) {
|
||||
val identifier: PtIdentifier?
|
||||
get() = children.single() as? PtIdentifier
|
||||
val array: PtArrayIndexer?
|
||||
get() = children.single() as? PtArrayIndexer
|
||||
val memory: PtMemoryByte?
|
||||
get() = children.single() as? PtMemoryByte
|
||||
|
||||
val type: DataType
|
||||
get() {
|
||||
return when(val tgt = children.single()) {
|
||||
is PtIdentifier -> tgt.type
|
||||
is PtArrayIndexer -> tgt.type
|
||||
is PtMemoryByte -> tgt.type
|
||||
else -> throw AssemblyError("weird target $tgt")
|
||||
}
|
||||
}
|
||||
|
||||
infix fun isSameAs(expression: PtExpression): Boolean = !void && expression.isSameAs(this)
|
||||
}
|
||||
|
||||
|
||||
class PtConditionalBranch(val condition: BranchCondition, position: Position) : PtNode(position) {
|
||||
val trueScope: PtNodeGroup
|
||||
get() = children[0] as PtNodeGroup
|
||||
val falseScope: PtNodeGroup
|
||||
get() = children[1] as PtNodeGroup
|
||||
}
|
||||
|
||||
|
||||
class PtForLoop(position: Position) : PtNode(position) {
|
||||
val variable: PtIdentifier
|
||||
get() = children[0] as PtIdentifier
|
||||
val iterable: PtExpression
|
||||
get() = children[1] as PtExpression
|
||||
val statements: PtNodeGroup
|
||||
get() = children[2] as PtNodeGroup
|
||||
}
|
||||
|
||||
|
||||
class PtIfElse(position: Position) : PtNode(position) {
|
||||
val condition: PtExpression
|
||||
get() = children[0] as PtExpression
|
||||
val ifScope: PtNodeGroup
|
||||
get() = children[1] as PtNodeGroup
|
||||
val elseScope: PtNodeGroup
|
||||
get() = children[2] as PtNodeGroup
|
||||
|
||||
fun hasElse(): Boolean = children.size==3 && elseScope.children.isNotEmpty()
|
||||
}
|
||||
|
||||
|
||||
class PtJump(position: Position) : PtNode(position) {
|
||||
val target: PtExpression
|
||||
get() = children.single() as PtExpression
|
||||
}
|
||||
|
||||
|
||||
class PtRepeatLoop(position: Position) : PtNode(position) {
|
||||
val count: PtExpression
|
||||
get() = children[0] as PtExpression
|
||||
val statements: PtNodeGroup
|
||||
get() = children[1] as PtNodeGroup
|
||||
}
|
||||
|
||||
|
||||
class PtReturn(position: Position) : PtNode(position) {
|
||||
val hasValue: Boolean
|
||||
get() = children.any()
|
||||
val value: PtExpression?
|
||||
get() {
|
||||
return if(children.any())
|
||||
children.single() as PtExpression
|
||||
else
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
sealed interface IPtVariable {
|
||||
val name: String
|
||||
val type: DataType
|
||||
}
|
||||
|
||||
|
||||
class PtVariable(
|
||||
name: String,
|
||||
override val type: DataType,
|
||||
val zeropage: ZeropageWish,
|
||||
val align: UInt,
|
||||
val value: PtExpression?,
|
||||
val arraySize: UInt?,
|
||||
position: Position
|
||||
) : PtNamedNode(name, position), IPtVariable {
|
||||
init {
|
||||
value?.let {it.parent=this}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class PtConstant(name: String, override val type: DataType, val value: Double, position: Position) : PtNamedNode(name, position), IPtVariable
|
||||
|
||||
|
||||
class PtMemMapped(name: String, override val type: DataType, val address: UInt, val arraySize: UInt?, position: Position) : PtNamedNode(name, position), IPtVariable {
|
||||
init {
|
||||
require(!type.isString)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class PtWhen(position: Position) : PtNode(position) {
|
||||
val value: PtExpression
|
||||
get() = children[0] as PtExpression
|
||||
val choices: PtNodeGroup
|
||||
get() = children[1] as PtNodeGroup
|
||||
}
|
||||
|
||||
|
||||
class PtWhenChoice(val isElse: Boolean, position: Position) : PtNode(position) {
|
||||
val values: PtNodeGroup
|
||||
get() = children[0] as PtNodeGroup
|
||||
val statements: PtNodeGroup
|
||||
get() = children[1] as PtNodeGroup
|
||||
}
|
||||
|
||||
|
||||
class PtDefer(position: Position): PtNode(position), IPtStatementContainer
|
16
codeCore/src/prog8/code/ast/Verify.kt
Normal file
16
codeCore/src/prog8/code/ast/Verify.kt
Normal file
@ -0,0 +1,16 @@
|
||||
package prog8.code.ast
|
||||
|
||||
import prog8.code.SymbolTable
|
||||
import prog8.code.core.*
|
||||
|
||||
fun verifyFinalAstBeforeAsmGen(program: PtProgram, options: CompilationOptions, st: SymbolTable, errors: IErrorReporter) {
|
||||
/*
|
||||
walkAst(program) { node, _ ->
|
||||
if(node is PtVariable) {
|
||||
if(node.value!=null) {
|
||||
// require(node.type in ArrayDatatypes || node.type==DataType.STR) { "final check before asmgen: only string and array variables can still have an init value ${node.name} ${node.type} ${node.position}"}
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
156
codeCore/src/prog8/code/core/BuiltinFunctions.kt
Normal file
156
codeCore/src/prog8/code/core/BuiltinFunctions.kt
Normal file
@ -0,0 +1,156 @@
|
||||
package prog8.code.core
|
||||
|
||||
class ReturnConvention(val dt: BaseDataType?, val reg: RegisterOrPair?)
|
||||
class ParamConvention(val dt: BaseDataType, val reg: RegisterOrPair?, val variable: Boolean)
|
||||
class CallConvention(val params: List<ParamConvention>, val returns: ReturnConvention) {
|
||||
override fun toString(): String {
|
||||
val paramConvs = params.mapIndexed { index, it ->
|
||||
when {
|
||||
it.reg!=null -> "$index:${it.reg}"
|
||||
it.variable -> "$index:variable"
|
||||
else -> "$index:???"
|
||||
}
|
||||
}
|
||||
val returnConv =
|
||||
when {
|
||||
returns.reg == RegisterOrPair.FAC1 -> "floatFAC1"
|
||||
returns.reg != null -> returns.reg.toString()
|
||||
else -> "<no returnvalue>"
|
||||
}
|
||||
return "CallConvention[" + paramConvs.joinToString() + " ; returns: $returnConv]"
|
||||
}
|
||||
}
|
||||
|
||||
class FParam(val name: String, vararg val possibleDatatypes: BaseDataType)
|
||||
|
||||
|
||||
private val IterableDatatypes = arrayOf(BaseDataType.STR, BaseDataType.ARRAY, BaseDataType.ARRAY_SPLITW)
|
||||
private val IntegerDatatypes = arrayOf(BaseDataType.UBYTE, BaseDataType.BYTE, BaseDataType.UWORD, BaseDataType.WORD, BaseDataType.LONG)
|
||||
private val NumericDatatypes = arrayOf(BaseDataType.UBYTE, BaseDataType.BYTE, BaseDataType.UWORD, BaseDataType.WORD, BaseDataType.LONG, BaseDataType.FLOAT)
|
||||
private val ByteDatatypes = arrayOf(BaseDataType.UBYTE, BaseDataType.BYTE)
|
||||
private val ArrayDatatypes = arrayOf(BaseDataType.ARRAY, BaseDataType.ARRAY_SPLITW)
|
||||
|
||||
|
||||
class FSignature(val pure: Boolean, // does it have side effects?
|
||||
val returnType: BaseDataType?,
|
||||
vararg val parameters: FParam) {
|
||||
|
||||
fun callConvention(actualParamTypes: List<BaseDataType>): CallConvention {
|
||||
val returns: ReturnConvention = when (returnType) {
|
||||
BaseDataType.UBYTE, BaseDataType.BYTE -> ReturnConvention(returnType, RegisterOrPair.A)
|
||||
BaseDataType.UWORD, BaseDataType.WORD -> ReturnConvention(returnType, RegisterOrPair.AY)
|
||||
BaseDataType.FLOAT -> ReturnConvention(returnType, RegisterOrPair.FAC1)
|
||||
in IterableDatatypes -> ReturnConvention(returnType!!, RegisterOrPair.AY)
|
||||
null -> ReturnConvention(null, null)
|
||||
else -> {
|
||||
// return type depends on arg type
|
||||
when (val paramType = actualParamTypes.first()) {
|
||||
BaseDataType.UBYTE, BaseDataType.BYTE -> ReturnConvention(paramType, RegisterOrPair.A)
|
||||
BaseDataType.UWORD, BaseDataType.WORD -> ReturnConvention(paramType, RegisterOrPair.AY)
|
||||
BaseDataType.FLOAT -> ReturnConvention(paramType, RegisterOrPair.FAC1)
|
||||
in IterableDatatypes -> ReturnConvention(paramType, RegisterOrPair.AY)
|
||||
else -> ReturnConvention(paramType, null)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return when {
|
||||
actualParamTypes.isEmpty() -> CallConvention(emptyList(), returns)
|
||||
actualParamTypes.size==1 -> {
|
||||
// One parameter goes via register/registerpair.
|
||||
// this avoids repeated code for every caller to store the value in the subroutine's argument variable.
|
||||
// (that store is still done, but only coded once at the start at the subroutine itself rather than at every call site).
|
||||
val paramConv = when(val paramType = actualParamTypes[0]) {
|
||||
BaseDataType.UBYTE, BaseDataType.BYTE -> ParamConvention(paramType, RegisterOrPair.A, false)
|
||||
BaseDataType.UWORD, BaseDataType.WORD -> ParamConvention(paramType, RegisterOrPair.AY, false)
|
||||
BaseDataType.FLOAT -> ParamConvention(paramType, RegisterOrPair.AY, false) // NOTE: for builtin functions, floating point arguments are passed by reference (so you get a pointer in AY)
|
||||
in IterableDatatypes -> ParamConvention(paramType, RegisterOrPair.AY, false)
|
||||
else -> ParamConvention(paramType, null, false)
|
||||
}
|
||||
CallConvention(listOf(paramConv), returns)
|
||||
}
|
||||
actualParamTypes.size==2 && (actualParamTypes[0] in ByteDatatypes && actualParamTypes[1].isWord) -> {
|
||||
TODO("opportunity to pass word+byte arguments in A,Y and X registers but not implemented yet")
|
||||
}
|
||||
actualParamTypes.size==2 && (actualParamTypes[0].isWord && actualParamTypes[1].isByte) -> {
|
||||
TODO("opportunity to pass word+byte arguments in A,Y and X registers but not implemented yet")
|
||||
}
|
||||
actualParamTypes.size==3 && actualParamTypes.all { it.isByte } -> {
|
||||
TODO("opportunity to pass 3 byte arguments in A,Y and X registers but not implemented yet")
|
||||
}
|
||||
else -> {
|
||||
// multiple parameters go via variables
|
||||
val paramConvs = actualParamTypes.map { ParamConvention(it, null, true) }
|
||||
CallConvention(paramConvs, returns)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val BuiltinFunctions: Map<String, FSignature> = mapOf(
|
||||
"setlsb" to FSignature(false, null, FParam("variable", BaseDataType.WORD, BaseDataType.UWORD), FParam("value", BaseDataType.BYTE, BaseDataType.UBYTE)),
|
||||
"setmsb" to FSignature(false, null, FParam("variable", BaseDataType.WORD, BaseDataType.UWORD), FParam("value", BaseDataType.BYTE, BaseDataType.UBYTE)),
|
||||
"rol" to FSignature(false, null, FParam("item", BaseDataType.UBYTE, BaseDataType.UWORD)),
|
||||
"ror" to FSignature(false, null, FParam("item", BaseDataType.UBYTE, BaseDataType.UWORD)),
|
||||
"rol2" to FSignature(false, null, FParam("item", BaseDataType.UBYTE, BaseDataType.UWORD)),
|
||||
"ror2" to FSignature(false, null, FParam("item", BaseDataType.UBYTE, BaseDataType.UWORD)),
|
||||
"cmp" to FSignature(false, null, FParam("value1", *IntegerDatatypes), FParam("value2", *NumericDatatypes)), // cmp returns a status in the carry flag, but not a proper return value
|
||||
"prog8_lib_stringcompare" to FSignature(true, BaseDataType.BYTE, FParam("str1", BaseDataType.STR), FParam("str2", BaseDataType.STR)),
|
||||
"prog8_lib_square_byte" to FSignature(true, BaseDataType.UBYTE, FParam("value", BaseDataType.BYTE, BaseDataType.UBYTE)),
|
||||
"prog8_lib_square_word" to FSignature(true, BaseDataType.UWORD, FParam("value", BaseDataType.WORD, BaseDataType.UWORD)),
|
||||
"prog8_ifelse_bittest_set" to FSignature(true, BaseDataType.BOOL, FParam("variable", *ByteDatatypes), FParam("bitnumber", BaseDataType.UBYTE)),
|
||||
"prog8_ifelse_bittest_notset" to FSignature(true, BaseDataType.BOOL, FParam("variable", *ByteDatatypes), FParam("bitnumber", BaseDataType.UBYTE)),
|
||||
"abs" to FSignature(true, null, FParam("value", *NumericDatatypes)),
|
||||
"abs__byte" to FSignature(true, BaseDataType.BYTE, FParam("value", BaseDataType.BYTE)),
|
||||
"abs__word" to FSignature(true, BaseDataType.WORD, FParam("value", BaseDataType.WORD)),
|
||||
"abs__float" to FSignature(true, BaseDataType.FLOAT, FParam("value", BaseDataType.FLOAT)),
|
||||
"len" to FSignature(true, BaseDataType.UWORD, FParam("values", *IterableDatatypes)),
|
||||
"sizeof" to FSignature(true, BaseDataType.UBYTE, FParam("object", *BaseDataType.entries.toTypedArray())),
|
||||
"sgn" to FSignature(true, BaseDataType.BYTE, FParam("value", *NumericDatatypes)),
|
||||
"sqrt" to FSignature(true, null, FParam("value", *NumericDatatypes)),
|
||||
"sqrt__ubyte" to FSignature(true, BaseDataType.UBYTE, FParam("value", BaseDataType.UBYTE)),
|
||||
"sqrt__uword" to FSignature(true, BaseDataType.UBYTE, FParam("value", BaseDataType.UWORD)),
|
||||
"sqrt__float" to FSignature(true, BaseDataType.FLOAT, FParam("value", BaseDataType.FLOAT)),
|
||||
"divmod" to FSignature(false, null, FParam("dividend", BaseDataType.UBYTE, BaseDataType.UWORD), FParam("divisor", BaseDataType.UBYTE, BaseDataType.UWORD), FParam("quotient", BaseDataType.UBYTE, BaseDataType.UWORD), FParam("remainder", BaseDataType.UBYTE, BaseDataType.UWORD)),
|
||||
"divmod__ubyte" to FSignature(false, null, FParam("dividend", BaseDataType.UBYTE), FParam("divisor", BaseDataType.UBYTE), FParam("quotient", BaseDataType.UBYTE), FParam("remainder", BaseDataType.UBYTE)),
|
||||
"divmod__uword" to FSignature(false, null, FParam("dividend", BaseDataType.UWORD), FParam("divisor", BaseDataType.UWORD), FParam("quotient", BaseDataType.UWORD), FParam("remainder", BaseDataType.UWORD)),
|
||||
"lsb" to FSignature(true, BaseDataType.UBYTE, FParam("value", BaseDataType.UWORD, BaseDataType.WORD, BaseDataType.LONG)),
|
||||
"lsw" to FSignature(true, BaseDataType.UWORD, FParam("value", BaseDataType.UWORD, BaseDataType.WORD, BaseDataType.LONG)),
|
||||
"msb" to FSignature(true, BaseDataType.UBYTE, FParam("value", BaseDataType.UWORD, BaseDataType.WORD, BaseDataType.LONG)),
|
||||
"msw" to FSignature(true, BaseDataType.UWORD, FParam("value", BaseDataType.UWORD, BaseDataType.WORD, BaseDataType.LONG)),
|
||||
"mkword" to FSignature(true, BaseDataType.UWORD, FParam("msb", BaseDataType.UBYTE), FParam("lsb", BaseDataType.UBYTE)),
|
||||
"clamp" to FSignature(true, null, FParam("value", BaseDataType.BYTE), FParam("minimum", BaseDataType.BYTE), FParam("maximum", BaseDataType.BYTE)),
|
||||
"clamp__byte" to FSignature(true, BaseDataType.BYTE, FParam("value", BaseDataType.BYTE), FParam("minimum", BaseDataType.BYTE), FParam("maximum", BaseDataType.BYTE)),
|
||||
"clamp__ubyte" to FSignature(true, BaseDataType.UBYTE, FParam("value", BaseDataType.UBYTE), FParam("minimum", BaseDataType.UBYTE), FParam("maximum", BaseDataType.UBYTE)),
|
||||
"clamp__word" to FSignature(true, BaseDataType.WORD, FParam("value", BaseDataType.WORD), FParam("minimum", BaseDataType.WORD), FParam("maximum", BaseDataType.WORD)),
|
||||
"clamp__uword" to FSignature(true, BaseDataType.UWORD, FParam("value", BaseDataType.UWORD), FParam("minimum", BaseDataType.UWORD), FParam("maximum", BaseDataType.UWORD)),
|
||||
"min" to FSignature(true, null, FParam("val1", BaseDataType.BYTE), FParam("val2", BaseDataType.BYTE)),
|
||||
"min__byte" to FSignature(true, BaseDataType.BYTE, FParam("val1", BaseDataType.BYTE), FParam("val2", BaseDataType.BYTE)),
|
||||
"min__ubyte" to FSignature(true, BaseDataType.UBYTE, FParam("val1", BaseDataType.UBYTE), FParam("val2", BaseDataType.UBYTE)),
|
||||
"min__word" to FSignature(true, BaseDataType.WORD, FParam("val1", BaseDataType.WORD), FParam("val2", BaseDataType.WORD)),
|
||||
"min__uword" to FSignature(true, BaseDataType.UWORD, FParam("val1", BaseDataType.UWORD), FParam("val2", BaseDataType.UWORD)),
|
||||
"max" to FSignature(true, null, FParam("val1", BaseDataType.BYTE), FParam("val2", BaseDataType.BYTE)),
|
||||
"max__byte" to FSignature(true, BaseDataType.BYTE, FParam("val1", BaseDataType.BYTE), FParam("val2", BaseDataType.BYTE)),
|
||||
"max__ubyte" to FSignature(true, BaseDataType.UBYTE, FParam("val1", BaseDataType.UBYTE), FParam("val2", BaseDataType.UBYTE)),
|
||||
"max__word" to FSignature(true, BaseDataType.WORD, FParam("val1", BaseDataType.WORD), FParam("val2", BaseDataType.WORD)),
|
||||
"max__uword" to FSignature(true, BaseDataType.UWORD, FParam("val1", BaseDataType.UWORD), FParam("val2", BaseDataType.UWORD)),
|
||||
"peek" to FSignature(true, BaseDataType.UBYTE, FParam("address", BaseDataType.UWORD)),
|
||||
"peekw" to FSignature(true, BaseDataType.UWORD, FParam("address", BaseDataType.UWORD)),
|
||||
"peekf" to FSignature(true, BaseDataType.FLOAT, FParam("address", BaseDataType.UWORD)),
|
||||
"poke" to FSignature(false, null, FParam("address", BaseDataType.UWORD), FParam("value", BaseDataType.UBYTE)),
|
||||
"pokew" to FSignature(false, null, FParam("address", BaseDataType.UWORD), FParam("value", BaseDataType.UWORD)),
|
||||
"pokef" to FSignature(false, null, FParam("address", BaseDataType.UWORD), FParam("value", BaseDataType.FLOAT)),
|
||||
"pokemon" to FSignature(false, BaseDataType.UBYTE, FParam("address", BaseDataType.UWORD), FParam("value", BaseDataType.UBYTE)),
|
||||
"rsave" to FSignature(false, null),
|
||||
"rrestore" to FSignature(false, null),
|
||||
"memory" to FSignature(true, BaseDataType.UWORD, FParam("name", BaseDataType.STR), FParam("size", BaseDataType.UWORD), FParam("alignment", BaseDataType.UWORD)),
|
||||
"callfar" to FSignature(false, BaseDataType.UWORD, FParam("bank", BaseDataType.UBYTE), FParam("address", BaseDataType.UWORD), FParam("arg", BaseDataType.UWORD)),
|
||||
"callfar2" to FSignature(false, BaseDataType.UWORD, FParam("bank", BaseDataType.UBYTE), FParam("address", BaseDataType.UWORD), FParam("argA", BaseDataType.UBYTE), FParam("argX", BaseDataType.UBYTE), FParam("argY", BaseDataType.UBYTE), FParam("argC", BaseDataType.BOOL)),
|
||||
"call" to FSignature(false, BaseDataType.UWORD, FParam("address", BaseDataType.UWORD)),
|
||||
)
|
||||
|
||||
val InplaceModifyingBuiltinFunctions = setOf(
|
||||
"setlsb", "setmsb",
|
||||
"rol", "ror", "rol2", "ror2",
|
||||
"divmod", "divmod__ubyte", "divmod__uword"
|
||||
)
|
43
codeCore/src/prog8/code/core/CompilationOptions.kt
Normal file
43
codeCore/src/prog8/code/core/CompilationOptions.kt
Normal file
@ -0,0 +1,43 @@
|
||||
package prog8.code.core
|
||||
|
||||
import java.nio.file.Path
|
||||
import kotlin.io.path.Path
|
||||
|
||||
|
||||
class CompilationOptions(val output: OutputType,
|
||||
val launcher: CbmPrgLauncherType,
|
||||
val zeropage: ZeropageType,
|
||||
val zpReserved: List<UIntRange>,
|
||||
val zpAllowed: List<UIntRange>,
|
||||
val floats: Boolean,
|
||||
val noSysInit: Boolean,
|
||||
val compTarget: ICompilationTarget,
|
||||
// these are set later, based on command line arguments or options in the source code:
|
||||
var loadAddress: UInt,
|
||||
var memtopAddress: UInt,
|
||||
var warnSymbolShadowing: Boolean = false,
|
||||
var optimize: Boolean = false,
|
||||
var asmQuiet: Boolean = false,
|
||||
var asmListfile: Boolean = false,
|
||||
var includeSourcelines: Boolean = false,
|
||||
var dumpVariables: Boolean = false,
|
||||
var dumpSymbols: Boolean = false,
|
||||
var experimentalCodegen: Boolean = false,
|
||||
var varsHighBank: Int? = null,
|
||||
var varsGolden: Boolean = false,
|
||||
var slabsHighBank: Int? = null,
|
||||
var slabsGolden: Boolean = false,
|
||||
var dontSplitWordArrays: Boolean = false,
|
||||
var breakpointCpuInstruction: String? = null,
|
||||
var ignoreFootguns: Boolean = false,
|
||||
var outputDir: Path = Path(""),
|
||||
var symbolDefs: Map<String, String> = emptyMap()
|
||||
) {
|
||||
init {
|
||||
compTarget.machine.initializeMemoryAreas(this)
|
||||
}
|
||||
|
||||
companion object {
|
||||
val AllZeropageAllowed: List<UIntRange> = listOf(0u..255u)
|
||||
}
|
||||
}
|
97
codeCore/src/prog8/code/core/Conversions.kt
Normal file
97
codeCore/src/prog8/code/core/Conversions.kt
Normal file
@ -0,0 +1,97 @@
|
||||
package prog8.code.core
|
||||
|
||||
import kotlin.math.abs
|
||||
import kotlin.math.pow
|
||||
|
||||
val powersOfTwoFloat = (0..16).map { (2.0).pow(it) }.toTypedArray()
|
||||
val negativePowersOfTwoFloat = powersOfTwoFloat.map { -it }.toTypedArray()
|
||||
val powersOfTwoInt = (0..16).map { 2.0.pow(it).toInt() }.toTypedArray()
|
||||
|
||||
fun Number.toHex(): String {
|
||||
// 0..15 -> "0".."15"
|
||||
// 16..255 -> "$10".."$ff"
|
||||
// 256..65536 -> "$0100".."$ffff"
|
||||
// larger -> "$12345678"
|
||||
// negative values are prefixed with '-'.
|
||||
val integer = this.toInt()
|
||||
if(integer<0)
|
||||
return '-' + abs(integer).toHex()
|
||||
return when (integer) {
|
||||
in 0 until 16 -> integer.toString()
|
||||
in 0 until 0x100 -> "$"+integer.toString(16).padStart(2,'0')
|
||||
in 0 until 0x10000 -> "$"+integer.toString(16).padStart(4,'0')
|
||||
else -> "$"+integer.toString(16).padStart(8,'0')
|
||||
}
|
||||
}
|
||||
|
||||
fun UInt.toHex(): String {
|
||||
// 0..15 -> "0".."15"
|
||||
// 16..255 -> "$10".."$ff"
|
||||
// 256..65536 -> "$0100".."$ffff"
|
||||
// larger -> "$12345678"
|
||||
return when (this) {
|
||||
in 0u until 16u -> this.toString()
|
||||
in 0u until 0x100u -> "$"+this.toString(16).padStart(2,'0')
|
||||
in 0u until 0x10000u -> "$"+this.toString(16).padStart(4,'0')
|
||||
else -> "$"+this.toString(16).padStart(8,'0')
|
||||
}
|
||||
}
|
||||
|
||||
fun Char.escape(): Char = this.toString().escape()[0]
|
||||
|
||||
fun String.escape(): String {
|
||||
val es = this.map {
|
||||
when(it) {
|
||||
'\t' -> "\\t"
|
||||
'\n' -> "\\n"
|
||||
'\r' -> "\\r"
|
||||
'"' -> "\\\""
|
||||
in '\u8000'..'\u80ff' -> "\\x" + (it.code - 0x8000).toString(16).padStart(2, '0') // 'ugly' passthrough hack
|
||||
in '\u0000'..'\u00ff' -> it.toString()
|
||||
else -> "\\u" + it.code.toString(16).padStart(4, '0')
|
||||
}
|
||||
}
|
||||
return es.joinToString("")
|
||||
}
|
||||
|
||||
fun String.unescape(): String {
|
||||
val result = mutableListOf<Char>()
|
||||
val iter = this.iterator()
|
||||
while(iter.hasNext()) {
|
||||
val c = iter.nextChar()
|
||||
if(c=='\\') {
|
||||
val ec = iter.nextChar()
|
||||
result.add(when(ec) {
|
||||
'\\' -> '\\'
|
||||
'n' -> '\n'
|
||||
'r' -> '\r'
|
||||
't' -> '\t'
|
||||
'"' -> '"'
|
||||
'\'' -> '\''
|
||||
'u' -> {
|
||||
try {
|
||||
"${iter.nextChar()}${iter.nextChar()}${iter.nextChar()}${iter.nextChar()}".toInt(16).toChar()
|
||||
} catch (sb: StringIndexOutOfBoundsException) {
|
||||
throw IllegalArgumentException("invalid \\u escape sequence")
|
||||
} catch (nf: NumberFormatException) {
|
||||
throw IllegalArgumentException("invalid \\u escape sequence")
|
||||
}
|
||||
}
|
||||
'x' -> {
|
||||
try {
|
||||
val hex = ("" + iter.nextChar() + iter.nextChar()).toInt(16)
|
||||
(0x8000 + hex).toChar() // 'ugly' pass-through hack
|
||||
} catch (sb: StringIndexOutOfBoundsException) {
|
||||
throw IllegalArgumentException("invalid \\x escape sequence")
|
||||
} catch (nf: NumberFormatException) {
|
||||
throw IllegalArgumentException("invalid \\x escape sequence")
|
||||
}
|
||||
}
|
||||
else -> throw IllegalArgumentException("invalid escape char in string: \\$ec")
|
||||
})
|
||||
} else {
|
||||
result.add(c)
|
||||
}
|
||||
}
|
||||
return result.joinToString("")
|
||||
}
|
351
codeCore/src/prog8/code/core/Enumerations.kt
Normal file
351
codeCore/src/prog8/code/core/Enumerations.kt
Normal file
@ -0,0 +1,351 @@
|
||||
package prog8.code.core
|
||||
|
||||
import java.util.Objects
|
||||
|
||||
enum class BaseDataType {
|
||||
UBYTE, // pass by value 8 bits unsigned
|
||||
BYTE, // pass by value 8 bits signed
|
||||
UWORD, // pass by value 16 bits unsigned
|
||||
WORD, // pass by value 16 bits signed
|
||||
LONG, // pass by value 32 bits signed
|
||||
FLOAT, // pass by value machine dependent
|
||||
BOOL, // pass by value bit 0 of an 8-bit byte
|
||||
STR, // pass by reference
|
||||
ARRAY, // pass by reference, subtype is the element type
|
||||
ARRAY_SPLITW, // pass by reference, split word layout, subtype is the element type (restricted to word types)
|
||||
UNDEFINED;
|
||||
|
||||
|
||||
fun largerSizeThan(other: BaseDataType) =
|
||||
when {
|
||||
this == other -> false
|
||||
this.isByteOrBool -> false
|
||||
this.isWord -> other.isByteOrBool
|
||||
this == LONG -> other.isByteOrBool || other.isWord
|
||||
this == STR && other == UWORD || this == UWORD && other == STR -> false
|
||||
this.isArray -> other != FLOAT
|
||||
this == STR -> other != FLOAT
|
||||
else -> true
|
||||
}
|
||||
|
||||
fun equalsSize(other: BaseDataType) =
|
||||
when {
|
||||
this == other -> true
|
||||
this.isByteOrBool -> other.isByteOrBool
|
||||
this.isWord -> other.isWord
|
||||
this == STR && other== UWORD || this== UWORD && other== STR -> true
|
||||
this == STR && other.isArray -> true
|
||||
this.isArray && other == STR -> true
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
|
||||
val BaseDataType.isByte get() = this in arrayOf(BaseDataType.UBYTE, BaseDataType.BYTE)
|
||||
val BaseDataType.isByteOrBool get() = this in arrayOf(BaseDataType.UBYTE, BaseDataType.BYTE, BaseDataType.BOOL)
|
||||
val BaseDataType.isWord get() = this in arrayOf(BaseDataType.UWORD, BaseDataType.WORD)
|
||||
val BaseDataType.isInteger get() = this in arrayOf(BaseDataType.UBYTE, BaseDataType.BYTE, BaseDataType.UWORD, BaseDataType.WORD, BaseDataType.LONG)
|
||||
val BaseDataType.isIntegerOrBool get() = this in arrayOf(BaseDataType.UBYTE, BaseDataType.BYTE, BaseDataType.UWORD, BaseDataType.WORD, BaseDataType.LONG, BaseDataType.BOOL)
|
||||
val BaseDataType.isNumeric get() = this == BaseDataType.FLOAT || this.isInteger
|
||||
val BaseDataType.isNumericOrBool get() = this == BaseDataType.BOOL || this.isNumeric
|
||||
val BaseDataType.isSigned get() = this in arrayOf(BaseDataType.BYTE, BaseDataType.WORD, BaseDataType.LONG, BaseDataType.FLOAT)
|
||||
val BaseDataType.isArray get() = this == BaseDataType.ARRAY || this == BaseDataType.ARRAY_SPLITW
|
||||
val BaseDataType.isSplitWordArray get() = this == BaseDataType.ARRAY_SPLITW
|
||||
val BaseDataType.isIterable get() = this in arrayOf(BaseDataType.STR, BaseDataType.ARRAY, BaseDataType.ARRAY_SPLITW)
|
||||
val BaseDataType.isPassByRef get() = this.isIterable
|
||||
val BaseDataType.isPassByValue get() = !this.isIterable
|
||||
|
||||
|
||||
class DataType private constructor(val base: BaseDataType, val sub: BaseDataType?) {
|
||||
|
||||
init {
|
||||
if(base.isArray) {
|
||||
require(sub != null)
|
||||
if(base.isSplitWordArray)
|
||||
require(sub == BaseDataType.UWORD || sub == BaseDataType.WORD)
|
||||
}
|
||||
else if(base==BaseDataType.STR)
|
||||
require(sub==BaseDataType.UBYTE) { "string subtype should be ubyte" }
|
||||
else
|
||||
require(sub == null) { "only string and array base types can have a subtype"}
|
||||
}
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
if (other !is DataType) return false
|
||||
return base == other.base && sub == other.sub
|
||||
}
|
||||
|
||||
override fun hashCode(): Int = Objects.hash(base, sub)
|
||||
|
||||
companion object {
|
||||
private val simpletypes = mapOf(
|
||||
BaseDataType.UBYTE to DataType(BaseDataType.UBYTE, null),
|
||||
BaseDataType.BYTE to DataType(BaseDataType.BYTE, null),
|
||||
BaseDataType.UWORD to DataType(BaseDataType.UWORD, null),
|
||||
BaseDataType.WORD to DataType(BaseDataType.WORD, null),
|
||||
BaseDataType.LONG to DataType(BaseDataType.LONG, null),
|
||||
BaseDataType.FLOAT to DataType(BaseDataType.FLOAT, null),
|
||||
BaseDataType.BOOL to DataType(BaseDataType.BOOL, null),
|
||||
BaseDataType.STR to DataType(BaseDataType.STR, BaseDataType.UBYTE),
|
||||
BaseDataType.UNDEFINED to DataType(BaseDataType.UNDEFINED, null)
|
||||
)
|
||||
|
||||
fun forDt(dt: BaseDataType) = simpletypes.getValue(dt)
|
||||
|
||||
fun arrayFor(elementDt: BaseDataType, splitwordarray: Boolean=true): DataType {
|
||||
val actualElementDt = if(elementDt==BaseDataType.STR) BaseDataType.UWORD else elementDt // array of strings is actually just an array of UWORD pointers
|
||||
return if(splitwordarray && actualElementDt.isWord)
|
||||
DataType(BaseDataType.ARRAY_SPLITW, actualElementDt)
|
||||
else {
|
||||
if(actualElementDt.isNumericOrBool && actualElementDt != BaseDataType.LONG)
|
||||
DataType(BaseDataType.ARRAY, actualElementDt)
|
||||
else
|
||||
throw NoSuchElementException("invalid element dt "+elementDt)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun elementToArray(splitwords: Boolean = true): DataType {
|
||||
return if (base == BaseDataType.UWORD || base == BaseDataType.WORD || base == BaseDataType.STR) arrayFor(base, splitwords)
|
||||
else arrayFor(base, false)
|
||||
}
|
||||
|
||||
fun elementType(): DataType =
|
||||
if(base.isArray || base==BaseDataType.STR)
|
||||
forDt(sub!!)
|
||||
else
|
||||
throw IllegalArgumentException("not an array")
|
||||
|
||||
override fun toString(): String = when(base) {
|
||||
BaseDataType.ARRAY -> {
|
||||
when(sub) {
|
||||
BaseDataType.BOOL -> "bool[]"
|
||||
BaseDataType.FLOAT -> "float[]"
|
||||
BaseDataType.BYTE -> "byte[]"
|
||||
BaseDataType.WORD -> "word[]"
|
||||
BaseDataType.UBYTE -> "ubyte[]"
|
||||
BaseDataType.UWORD -> "uword[]"
|
||||
else -> throw IllegalArgumentException("invalid sub type")
|
||||
}
|
||||
}
|
||||
BaseDataType.ARRAY_SPLITW -> {
|
||||
when(sub) {
|
||||
BaseDataType.WORD -> "word[] (split)"
|
||||
BaseDataType.UWORD -> "uword[] (split)"
|
||||
else -> throw IllegalArgumentException("invalid sub type")
|
||||
}
|
||||
}
|
||||
else -> base.name.lowercase()
|
||||
}
|
||||
|
||||
fun sourceString(): String = when (base) {
|
||||
BaseDataType.BOOL -> "bool"
|
||||
BaseDataType.UBYTE -> "ubyte"
|
||||
BaseDataType.BYTE -> "byte"
|
||||
BaseDataType.UWORD -> "uword"
|
||||
BaseDataType.WORD -> "word"
|
||||
BaseDataType.LONG -> "long"
|
||||
BaseDataType.FLOAT -> "float"
|
||||
BaseDataType.STR -> "str"
|
||||
BaseDataType.ARRAY -> {
|
||||
when(sub) {
|
||||
BaseDataType.UBYTE -> "ubyte["
|
||||
BaseDataType.UWORD -> "@nosplit uword["
|
||||
BaseDataType.BOOL -> "bool["
|
||||
BaseDataType.BYTE -> "byte["
|
||||
BaseDataType.WORD -> "@nosplit word["
|
||||
BaseDataType.FLOAT -> "float["
|
||||
else -> throw IllegalArgumentException("invalid sub type")
|
||||
}
|
||||
}
|
||||
BaseDataType.ARRAY_SPLITW -> {
|
||||
when(sub) {
|
||||
BaseDataType.UWORD -> "uword["
|
||||
BaseDataType.WORD -> "word["
|
||||
else -> throw IllegalArgumentException("invalid sub type")
|
||||
}
|
||||
}
|
||||
BaseDataType.UNDEFINED -> throw IllegalArgumentException("wrong dt")
|
||||
}
|
||||
|
||||
// is the type assignable to the given other type (perhaps via a typecast) without loss of precision?
|
||||
infix fun isAssignableTo(targetType: DataType) =
|
||||
when(base) {
|
||||
BaseDataType.BOOL -> targetType.base == BaseDataType.BOOL
|
||||
BaseDataType.UBYTE -> targetType.base in arrayOf(BaseDataType.UBYTE, BaseDataType.WORD, BaseDataType.UWORD, BaseDataType.LONG, BaseDataType.FLOAT)
|
||||
BaseDataType.BYTE -> targetType.base in arrayOf(BaseDataType.BYTE, BaseDataType.WORD, BaseDataType.LONG, BaseDataType.FLOAT)
|
||||
BaseDataType.UWORD -> targetType.base in arrayOf(BaseDataType.UWORD, BaseDataType.LONG, BaseDataType.FLOAT)
|
||||
BaseDataType.WORD -> targetType.base in arrayOf(BaseDataType.WORD, BaseDataType.LONG, BaseDataType.FLOAT)
|
||||
BaseDataType.LONG -> targetType.base in arrayOf(BaseDataType.LONG, BaseDataType.FLOAT)
|
||||
BaseDataType.FLOAT -> targetType.base in arrayOf(BaseDataType.FLOAT)
|
||||
BaseDataType.STR -> targetType.base in arrayOf(BaseDataType.STR, BaseDataType.UWORD)
|
||||
BaseDataType.ARRAY, BaseDataType.ARRAY_SPLITW -> targetType.base in arrayOf(BaseDataType.ARRAY, BaseDataType.ARRAY_SPLITW) && targetType.sub == sub
|
||||
BaseDataType.UNDEFINED -> false
|
||||
}
|
||||
|
||||
fun largerSizeThan(other: DataType): Boolean {
|
||||
if(isArray) throw IllegalArgumentException("cannot compare size of array types")
|
||||
return base.largerSizeThan(other.base)
|
||||
}
|
||||
fun equalsSize(other: DataType): Boolean {
|
||||
if(isArray) throw IllegalArgumentException("cannot compare size of array types")
|
||||
return base.equalsSize(other.base)
|
||||
}
|
||||
|
||||
val isUndefined = base == BaseDataType.UNDEFINED
|
||||
val isByte = base.isByte
|
||||
val isUnsignedByte = base == BaseDataType.UBYTE
|
||||
val isSignedByte = base == BaseDataType.BYTE
|
||||
val isByteOrBool = base.isByteOrBool
|
||||
val isWord = base.isWord
|
||||
val isUnsignedWord = base == BaseDataType.UWORD
|
||||
val isSignedWord = base == BaseDataType.WORD
|
||||
val isInteger = base.isInteger
|
||||
val isIntegerOrBool = base.isIntegerOrBool
|
||||
val isNumeric = base.isNumeric
|
||||
val isNumericOrBool = base.isNumericOrBool
|
||||
val isSigned = base.isSigned
|
||||
val isUnsigned = !base.isSigned
|
||||
val isArray = base.isArray
|
||||
val isBoolArray = base.isArray && sub == BaseDataType.BOOL
|
||||
val isByteArray = base.isArray && (sub == BaseDataType.UBYTE || sub == BaseDataType.BYTE)
|
||||
val isUnsignedByteArray = base.isArray && sub == BaseDataType.UBYTE
|
||||
val isSignedByteArray = base.isArray && sub == BaseDataType.BYTE
|
||||
val isWordArray = base.isArray && (sub == BaseDataType.UWORD || sub == BaseDataType.WORD)
|
||||
val isUnsignedWordArray = base.isArray && sub == BaseDataType.UWORD
|
||||
val isSignedWordArray = base.isArray && sub == BaseDataType.WORD
|
||||
val isFloatArray = base.isArray && sub == BaseDataType.FLOAT
|
||||
val isString = base == BaseDataType.STR
|
||||
val isBool = base == BaseDataType.BOOL
|
||||
val isFloat = base == BaseDataType.FLOAT
|
||||
val isLong = base == BaseDataType.LONG
|
||||
val isStringly = base == BaseDataType.STR || base == BaseDataType.UWORD || (base == BaseDataType.ARRAY && (sub == BaseDataType.UBYTE || sub == BaseDataType.BYTE))
|
||||
val isSplitWordArray = base.isSplitWordArray
|
||||
val isSplitUnsignedWordArray = base.isSplitWordArray && sub == BaseDataType.UWORD
|
||||
val isSplitSignedWordArray = base.isSplitWordArray && sub == BaseDataType.WORD
|
||||
val isIterable = base.isIterable
|
||||
val isPassByRef = base.isPassByRef
|
||||
val isPassByValue = base.isPassByValue
|
||||
}
|
||||
|
||||
|
||||
enum class CpuRegister {
|
||||
A,
|
||||
X,
|
||||
Y
|
||||
}
|
||||
|
||||
enum class RegisterOrPair {
|
||||
A,
|
||||
X,
|
||||
Y,
|
||||
AX,
|
||||
AY,
|
||||
XY,
|
||||
FAC1,
|
||||
FAC2,
|
||||
// cx16 virtual registers:
|
||||
R0, R1, R2, R3, R4, R5, R6, R7,
|
||||
R8, R9, R10, R11, R12, R13, R14, R15;
|
||||
|
||||
companion object {
|
||||
val names by lazy { entries.map { it.toString()} }
|
||||
fun fromCpuRegister(cpu: CpuRegister): RegisterOrPair {
|
||||
return when(cpu) {
|
||||
CpuRegister.A -> A
|
||||
CpuRegister.X -> X
|
||||
CpuRegister.Y -> Y
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun asCpuRegister(): CpuRegister = when(this) {
|
||||
A -> CpuRegister.A
|
||||
X -> CpuRegister.X
|
||||
Y -> CpuRegister.Y
|
||||
else -> throw IllegalArgumentException("no cpu hardware register for $this")
|
||||
}
|
||||
|
||||
fun asScopedNameVirtualReg(type: DataType?): List<String> {
|
||||
require(this in Cx16VirtualRegisters)
|
||||
val suffix = when(type?.base) {
|
||||
BaseDataType.UBYTE, BaseDataType.BOOL -> "L"
|
||||
BaseDataType.BYTE -> "sL"
|
||||
BaseDataType.WORD -> "s"
|
||||
BaseDataType.UWORD, null -> ""
|
||||
else -> throw kotlin.IllegalArgumentException("invalid register param type")
|
||||
}
|
||||
return listOf("cx16", name.lowercase()+suffix)
|
||||
}
|
||||
} // only used in parameter and return value specs in asm subroutines
|
||||
|
||||
enum class Statusflag {
|
||||
Pc,
|
||||
Pz, // don't use
|
||||
Pv,
|
||||
Pn; // don't use
|
||||
|
||||
companion object {
|
||||
val names by lazy { entries.map { it.toString()} }
|
||||
}
|
||||
}
|
||||
|
||||
enum class BranchCondition {
|
||||
CS,
|
||||
CC,
|
||||
EQ, // EQ == Z
|
||||
Z,
|
||||
NE, // NE == NZ
|
||||
NZ,
|
||||
MI, // MI == NEG
|
||||
NEG,
|
||||
PL, // PL == POS
|
||||
POS,
|
||||
VS,
|
||||
VC
|
||||
}
|
||||
|
||||
val Cx16VirtualRegisters = arrayOf(
|
||||
RegisterOrPair.R0, RegisterOrPair.R1, RegisterOrPair.R2, RegisterOrPair.R3,
|
||||
RegisterOrPair.R4, RegisterOrPair.R5, RegisterOrPair.R6, RegisterOrPair.R7,
|
||||
RegisterOrPair.R8, RegisterOrPair.R9, RegisterOrPair.R10, RegisterOrPair.R11,
|
||||
RegisterOrPair.R12, RegisterOrPair.R13, RegisterOrPair.R14, RegisterOrPair.R15
|
||||
)
|
||||
|
||||
val CpuRegisters = arrayOf(
|
||||
RegisterOrPair.A, RegisterOrPair.X, RegisterOrPair.Y,
|
||||
RegisterOrPair.AX, RegisterOrPair.AY, RegisterOrPair.XY
|
||||
)
|
||||
|
||||
|
||||
enum class OutputType {
|
||||
RAW,
|
||||
PRG,
|
||||
XEX
|
||||
}
|
||||
|
||||
enum class CbmPrgLauncherType {
|
||||
BASIC,
|
||||
NONE
|
||||
}
|
||||
|
||||
enum class ZeropageType {
|
||||
BASICSAFE,
|
||||
FLOATSAFE,
|
||||
KERNALSAFE,
|
||||
FULL,
|
||||
DONTUSE
|
||||
}
|
||||
|
||||
enum class ZeropageWish {
|
||||
REQUIRE_ZEROPAGE,
|
||||
PREFER_ZEROPAGE,
|
||||
DONTCARE,
|
||||
NOT_IN_ZEROPAGE
|
||||
}
|
||||
|
||||
enum class SplitWish {
|
||||
DONTCARE,
|
||||
SPLIT,
|
||||
NOSPLIT
|
||||
}
|
7
codeCore/src/prog8/code/core/Exceptions.kt
Normal file
7
codeCore/src/prog8/code/core/Exceptions.kt
Normal file
@ -0,0 +1,7 @@
|
||||
package prog8.code.core
|
||||
|
||||
class InternalCompilerException(message: String?) : Exception(message)
|
||||
|
||||
class AssemblyError(msg: String) : RuntimeException(msg)
|
||||
|
||||
class ErrorsReportedException(message: String?) : Exception(message)
|
17
codeCore/src/prog8/code/core/ICodeGeneratorBackend.kt
Normal file
17
codeCore/src/prog8/code/core/ICodeGeneratorBackend.kt
Normal file
@ -0,0 +1,17 @@
|
||||
package prog8.code.core
|
||||
|
||||
import prog8.code.SymbolTable
|
||||
import prog8.code.ast.PtProgram
|
||||
|
||||
interface ICodeGeneratorBackend {
|
||||
fun generate(program: PtProgram,
|
||||
symbolTable: SymbolTable,
|
||||
options: CompilationOptions,
|
||||
errors: IErrorReporter): IAssemblyProgram?
|
||||
}
|
||||
|
||||
|
||||
interface IAssemblyProgram {
|
||||
val name: String
|
||||
fun assemble(options: CompilationOptions, errors: IErrorReporter): Boolean
|
||||
}
|
9
codeCore/src/prog8/code/core/ICompilationTarget.kt
Normal file
9
codeCore/src/prog8/code/core/ICompilationTarget.kt
Normal file
@ -0,0 +1,9 @@
|
||||
package prog8.code.core
|
||||
|
||||
interface ICompilationTarget: IStringEncoding, IMemSizer {
|
||||
val name: String
|
||||
val machine: IMachineDefinition
|
||||
|
||||
override fun encodeString(str: String, encoding: Encoding): List<UByte>
|
||||
override fun decodeString(bytes: Iterable<UByte>, encoding: Encoding): String
|
||||
}
|
16
codeCore/src/prog8/code/core/IErrorReporter.kt
Normal file
16
codeCore/src/prog8/code/core/IErrorReporter.kt
Normal file
@ -0,0 +1,16 @@
|
||||
package prog8.code.core
|
||||
|
||||
interface IErrorReporter {
|
||||
fun err(msg: String, position: Position)
|
||||
fun warn(msg: String, position: Position)
|
||||
fun info(msg: String, position: Position)
|
||||
fun undefined(symbol: List<String>, position: Position)
|
||||
fun noErrors(): Boolean
|
||||
fun report()
|
||||
fun finalizeNumErrors(numErrors: Int, numWarnings: Int, numInfos: Int) {
|
||||
if(numErrors>0)
|
||||
throw ErrorsReportedException("There are $numErrors errors, $numWarnings warnings, and $numInfos infos.")
|
||||
}
|
||||
|
||||
fun noErrorForLine(position: Position): Boolean
|
||||
}
|
36
codeCore/src/prog8/code/core/IMachineDefinition.kt
Normal file
36
codeCore/src/prog8/code/core/IMachineDefinition.kt
Normal file
@ -0,0 +1,36 @@
|
||||
package prog8.code.core
|
||||
|
||||
import java.nio.file.Path
|
||||
|
||||
|
||||
enum class CpuType {
|
||||
CPU6502,
|
||||
CPU65c02,
|
||||
VIRTUAL
|
||||
}
|
||||
|
||||
interface IMachineDefinition {
|
||||
val FLOAT_MAX_NEGATIVE: Double
|
||||
val FLOAT_MAX_POSITIVE: Double
|
||||
val FLOAT_MEM_SIZE: Int
|
||||
val STARTUP_CODE_RESERVED_SIZE: UInt // this is here, so that certain compiler targets are able to tune this
|
||||
val PROGRAM_LOAD_ADDRESS : UInt
|
||||
val PROGRAM_MEMTOP_ADDRESS: UInt
|
||||
val BSSHIGHRAM_START: UInt
|
||||
val BSSHIGHRAM_END: UInt
|
||||
val BSSGOLDENRAM_START: UInt
|
||||
val BSSGOLDENRAM_END: UInt
|
||||
|
||||
val cpu: CpuType
|
||||
var zeropage: Zeropage
|
||||
var golden: GoldenRam
|
||||
|
||||
fun initializeMemoryAreas(compilerOptions: CompilationOptions)
|
||||
fun getFloatAsmBytes(num: Number): String
|
||||
|
||||
fun convertFloatToBytes(num: Double): List<UByte>
|
||||
fun convertBytesToFloat(bytes: List<UByte>): Double
|
||||
|
||||
fun launchEmulator(selectedEmulator: Int, programNameWithPath: Path)
|
||||
fun isIOAddress(address: UInt): Boolean
|
||||
}
|
15
codeCore/src/prog8/code/core/IMemSizer.kt
Normal file
15
codeCore/src/prog8/code/core/IMemSizer.kt
Normal file
@ -0,0 +1,15 @@
|
||||
package prog8.code.core
|
||||
|
||||
interface IMemSizer {
|
||||
fun memorySize(dt: DataType, numElements: Int?): Int
|
||||
|
||||
fun memorySize(dt: BaseDataType): Int {
|
||||
if(dt.isPassByRef)
|
||||
return memorySize(DataType.forDt(BaseDataType.UWORD), null) // a pointer size
|
||||
try {
|
||||
return memorySize(DataType.forDt(dt), null)
|
||||
} catch (x: NoSuchElementException) {
|
||||
throw IllegalArgumentException(x.message)
|
||||
}
|
||||
}
|
||||
}
|
20
codeCore/src/prog8/code/core/IStringEncoding.kt
Normal file
20
codeCore/src/prog8/code/core/IStringEncoding.kt
Normal file
@ -0,0 +1,20 @@
|
||||
package prog8.code.core
|
||||
|
||||
enum class Encoding(val prefix: String) {
|
||||
DEFAULT("default"), // depends on compilation target
|
||||
PETSCII("petscii"), // c64/c128/cx16
|
||||
SCREENCODES("sc"), // c64/c128/cx16
|
||||
ATASCII("atascii"), // atari
|
||||
ISO("iso"), // cx16 (iso-8859-15)
|
||||
ISO5("iso5"), // cx16 (iso-8859-5, cyrillic)
|
||||
ISO16("iso16"), // cx16 (iso-8859-16, eastern european)
|
||||
CP437("cp437"), // cx16 (ibm pc, codepage 437)
|
||||
KATAKANA("kata") // cx16 (katakana)
|
||||
}
|
||||
|
||||
interface IStringEncoding {
|
||||
val defaultEncoding: Encoding
|
||||
|
||||
fun encodeString(str: String, encoding: Encoding): List<UByte>
|
||||
fun decodeString(bytes: Iterable<UByte>, encoding: Encoding): String
|
||||
}
|
172
codeCore/src/prog8/code/core/MemoryRegions.kt
Normal file
172
codeCore/src/prog8/code/core/MemoryRegions.kt
Normal file
@ -0,0 +1,172 @@
|
||||
package prog8.code.core
|
||||
|
||||
import com.github.michaelbull.result.Err
|
||||
import com.github.michaelbull.result.Ok
|
||||
import com.github.michaelbull.result.Result
|
||||
|
||||
|
||||
class MemAllocationError(message: String) : Exception(message)
|
||||
|
||||
|
||||
abstract class MemoryAllocator(protected val options: CompilationOptions) {
|
||||
data class VarAllocation(val address: UInt, val dt: DataType, val size: Int)
|
||||
|
||||
abstract fun allocate(name: String,
|
||||
datatype: DataType,
|
||||
numElements: Int?,
|
||||
position: Position?,
|
||||
errors: IErrorReporter): Result<VarAllocation, MemAllocationError>
|
||||
}
|
||||
|
||||
|
||||
abstract class Zeropage(options: CompilationOptions): MemoryAllocator(options) {
|
||||
|
||||
abstract val SCRATCH_B1 : UInt // temp storage for a single byte
|
||||
abstract val SCRATCH_REG : UInt // temp storage for a register, must be B1+1
|
||||
abstract val SCRATCH_W1 : UInt // temp storage 1 for a word $fb+$fc
|
||||
abstract val SCRATCH_W2 : UInt // temp storage 2 for a word $fb+$fc
|
||||
|
||||
|
||||
// the variables allocated into Zeropage.
|
||||
// name (scoped) ==> pair of address to (Datatype + bytesize)
|
||||
val allocatedVariables = mutableMapOf<String, VarAllocation>()
|
||||
|
||||
val free = mutableListOf<UInt>() // subclasses must set this to the appropriate free locations.
|
||||
|
||||
fun removeReservedFromFreePool() {
|
||||
synchronized(this) {
|
||||
for (reserved in options.zpReserved)
|
||||
reserve(reserved)
|
||||
|
||||
free.removeAll(arrayOf(SCRATCH_B1, SCRATCH_REG, SCRATCH_W1, SCRATCH_W1 + 1u, SCRATCH_W2, SCRATCH_W2 + 1u))
|
||||
}
|
||||
}
|
||||
|
||||
fun retainAllowed() {
|
||||
synchronized(this) {
|
||||
for(allowed in options.zpAllowed)
|
||||
free.retainAll { it in allowed }
|
||||
}
|
||||
}
|
||||
|
||||
fun availableBytes() = if(options.zeropage== ZeropageType.DONTUSE) 0 else free.size
|
||||
fun hasByteAvailable() = if(options.zeropage== ZeropageType.DONTUSE) false else free.isNotEmpty()
|
||||
fun hasWordAvailable(): Boolean {
|
||||
if(options.zeropage== ZeropageType.DONTUSE)
|
||||
return false
|
||||
|
||||
return free.windowed(2).any { it[0] == it[1] - 1u }
|
||||
}
|
||||
|
||||
override fun allocate(name: String,
|
||||
datatype: DataType,
|
||||
numElements: Int?,
|
||||
position: Position?,
|
||||
errors: IErrorReporter): Result<VarAllocation, MemAllocationError> {
|
||||
|
||||
require(name.isEmpty() || name !in allocatedVariables) {"name can't be allocated twice"}
|
||||
|
||||
if(options.zeropage== ZeropageType.DONTUSE)
|
||||
return Err(MemAllocationError("zero page usage has been disabled"))
|
||||
|
||||
val size: Int =
|
||||
when {
|
||||
datatype.isIntegerOrBool -> options.compTarget.memorySize(datatype, null)
|
||||
datatype.isString || datatype.isArray -> {
|
||||
val memsize = options.compTarget.memorySize(datatype, numElements!!)
|
||||
if(position!=null)
|
||||
errors.warn("allocating a large value in zeropage; str/array $memsize bytes", position)
|
||||
else
|
||||
errors.warn("$name: allocating a large value in zeropage; str/array $memsize bytes", Position.DUMMY)
|
||||
memsize
|
||||
}
|
||||
datatype.isFloat -> {
|
||||
if (options.floats) {
|
||||
val memsize = options.compTarget.memorySize(DataType.forDt(BaseDataType.FLOAT), null)
|
||||
if(position!=null)
|
||||
errors.warn("allocating a large value in zeropage; float $memsize bytes", position)
|
||||
else
|
||||
errors.warn("$name: allocating a large value in zeropage; float $memsize bytes", Position.DUMMY)
|
||||
memsize
|
||||
} else return Err(MemAllocationError("floating point option not enabled"))
|
||||
}
|
||||
else -> throw MemAllocationError("weird dt")
|
||||
}
|
||||
|
||||
synchronized(this) {
|
||||
if(free.isNotEmpty()) {
|
||||
if(size==1) {
|
||||
for(candidate in free.minOrNull()!! .. free.maxOrNull()!!+1u) {
|
||||
if(oneSeparateByteFree(candidate))
|
||||
return Ok(VarAllocation(makeAllocation(candidate, 1, datatype, name), datatype,1))
|
||||
}
|
||||
return Ok(VarAllocation(makeAllocation(free[0], 1, datatype, name), datatype,1))
|
||||
}
|
||||
for(candidate in free.minOrNull()!! .. free.maxOrNull()!!+1u) {
|
||||
if (sequentialFree(candidate, size))
|
||||
return Ok(VarAllocation(makeAllocation(candidate, size, datatype, name), datatype, size))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Err(MemAllocationError("no more free space in ZP to allocate $size sequential bytes"))
|
||||
}
|
||||
|
||||
private fun reserve(range: UIntRange) = free.removeAll(range)
|
||||
|
||||
private fun makeAllocation(address: UInt, size: Int, datatype: DataType, name: String): UInt {
|
||||
require(size>=0)
|
||||
free.removeAll(address until address+size.toUInt())
|
||||
if(name.isNotEmpty()) {
|
||||
allocatedVariables[name] = when {
|
||||
datatype.isNumericOrBool -> VarAllocation(address, datatype, size) // numerical variables in zeropage never have an initial value here because they are set in separate initializer assignments
|
||||
datatype.isString -> VarAllocation(address, datatype, size)
|
||||
datatype.isArray -> VarAllocation(address, datatype, size)
|
||||
else -> throw AssemblyError("invalid dt")
|
||||
}
|
||||
}
|
||||
return address
|
||||
}
|
||||
|
||||
private fun oneSeparateByteFree(address: UInt) = address in free && address-1u !in free && address+1u !in free
|
||||
private fun sequentialFree(address: UInt, size: Int): Boolean {
|
||||
require(size>0)
|
||||
return free.containsAll((address until address+size.toUInt()).toList())
|
||||
}
|
||||
|
||||
abstract fun allocateCx16VirtualRegisters()
|
||||
}
|
||||
|
||||
|
||||
// TODO: this class is not yet used
|
||||
class GoldenRam(options: CompilationOptions, val region: UIntRange): MemoryAllocator(options) {
|
||||
private var nextLocation: UInt = region.first
|
||||
|
||||
override fun allocate(
|
||||
name: String,
|
||||
datatype: DataType,
|
||||
numElements: Int?,
|
||||
position: Position?,
|
||||
errors: IErrorReporter): Result<VarAllocation, MemAllocationError> {
|
||||
|
||||
val size: Int =
|
||||
when {
|
||||
datatype.isIntegerOrBool -> options.compTarget.memorySize(datatype, null)
|
||||
datatype.isString -> numElements!!
|
||||
datatype.isArray -> options.compTarget.memorySize(datatype, numElements!!)
|
||||
datatype.isFloat -> {
|
||||
if (options.floats) {
|
||||
options.compTarget.memorySize(DataType.forDt(BaseDataType.FLOAT), null)
|
||||
} else return Err(MemAllocationError("floating point option not enabled"))
|
||||
}
|
||||
else -> throw MemAllocationError("weird dt")
|
||||
}
|
||||
|
||||
return if(nextLocation<=region.last && (region.last + 1u - nextLocation) >= size.toUInt()) {
|
||||
val result = Ok(VarAllocation(nextLocation, datatype, size))
|
||||
nextLocation += size.toUInt()
|
||||
result
|
||||
} else
|
||||
Err(MemAllocationError("no more free space in Golden RAM to allocate $size sequential bytes"))
|
||||
}
|
||||
}
|
18
codeCore/src/prog8/code/core/Operators.kt
Normal file
18
codeCore/src/prog8/code/core/Operators.kt
Normal file
@ -0,0 +1,18 @@
|
||||
package prog8.code.core
|
||||
|
||||
val AssociativeOperators = arrayOf("+", "*", "&", "|", "^", "==", "!=", "xor") // note: and,or are not associative because of Shortcircuit/McCarthy evaluation
|
||||
val ComparisonOperators = arrayOf("==", "!=", "<", ">", "<=", ">=")
|
||||
val LogicalOperators = arrayOf("and", "or", "xor", "not", "in")
|
||||
val BitwiseOperators = arrayOf("&", "|", "^", "~")
|
||||
val PrefixOperators = arrayOf("+", "-", "~", "not")
|
||||
|
||||
fun invertedComparisonOperator(operator: String) =
|
||||
when (operator) {
|
||||
"==" -> "!="
|
||||
"!=" -> "=="
|
||||
"<" -> ">="
|
||||
">" -> "<="
|
||||
"<=" -> ">"
|
||||
">=" -> "<"
|
||||
else -> null
|
||||
}
|
27
codeCore/src/prog8/code/core/Position.kt
Normal file
27
codeCore/src/prog8/code/core/Position.kt
Normal file
@ -0,0 +1,27 @@
|
||||
package prog8.code.core
|
||||
|
||||
import prog8.code.source.SourceCode
|
||||
import java.nio.file.InvalidPathException
|
||||
import kotlin.io.path.Path
|
||||
import kotlin.io.path.absolute
|
||||
|
||||
data class Position(val file: String, val line: Int, val startCol: Int, val endCol: Int) {
|
||||
override fun toString(): String = "[$file: line $line col ${startCol+1}-${endCol+1}]"
|
||||
fun toClickableStr(): String {
|
||||
if(this===DUMMY)
|
||||
return ""
|
||||
if(SourceCode.isLibraryResource(file))
|
||||
return "$file:$line:$startCol:"
|
||||
return try {
|
||||
val path = Path(file).absolute().normalize().toString()
|
||||
"file://$path:$line:$startCol:"
|
||||
} catch(_: InvalidPathException) {
|
||||
// this can occur on Windows when the source origin contains "invalid" characters such as ':'
|
||||
"file://$file:$line:$startCol:"
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
val DUMMY = Position("~dummy~", 0, 0, 0)
|
||||
}
|
||||
}
|
3
codeCore/src/prog8/code/core/RegisterOrStatusflag.kt
Normal file
3
codeCore/src/prog8/code/core/RegisterOrStatusflag.kt
Normal file
@ -0,0 +1,3 @@
|
||||
package prog8.code.core
|
||||
|
||||
data class RegisterOrStatusflag(val registerOrPair: RegisterOrPair?, val statusflag: Statusflag?)
|
180
codeCore/src/prog8/code/optimize/Optimizer.kt
Normal file
180
codeCore/src/prog8/code/optimize/Optimizer.kt
Normal file
@ -0,0 +1,180 @@
|
||||
package prog8.code.optimize
|
||||
|
||||
import prog8.code.StExtSub
|
||||
import prog8.code.SymbolTable
|
||||
import prog8.code.ast.*
|
||||
import prog8.code.core.*
|
||||
|
||||
|
||||
fun optimizeIntermediateAst(program: PtProgram, options: CompilationOptions, st: SymbolTable, errors: IErrorReporter) {
|
||||
if (!options.optimize)
|
||||
return
|
||||
while (errors.noErrors() &&
|
||||
(optimizeBitTest(program, options)
|
||||
+ optimizeAssignTargets(program, st)) > 0
|
||||
) {
|
||||
// keep rolling
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private fun walkAst(root: PtNode, act: (node: PtNode, depth: Int) -> Boolean) {
|
||||
fun recurse(node: PtNode, depth: Int) {
|
||||
if(act(node, depth))
|
||||
node.children.forEach { recurse(it, depth+1) }
|
||||
}
|
||||
recurse(root, 0)
|
||||
}
|
||||
|
||||
|
||||
private fun optimizeAssignTargets(program: PtProgram, st: SymbolTable): Int {
|
||||
var changes = 0
|
||||
walkAst(program) { node: PtNode, depth: Int ->
|
||||
if(node is PtAssignment) {
|
||||
val value = node.value
|
||||
val functionName = when(value) {
|
||||
is PtBuiltinFunctionCall -> value.name
|
||||
is PtFunctionCall -> value.name
|
||||
else -> null
|
||||
}
|
||||
if(functionName!=null) {
|
||||
val stNode = st.lookup(functionName)
|
||||
if (stNode is StExtSub) {
|
||||
require(node.children.size==stNode.returns.size+1) {
|
||||
"number of targets must match return values"
|
||||
}
|
||||
node.children.zip(stNode.returns).withIndex().forEach { (index, xx) ->
|
||||
val target = xx.first as PtAssignTarget
|
||||
val returnedRegister = xx.second.register.registerOrPair
|
||||
if(returnedRegister!=null && !target.void && target.identifier!=null) {
|
||||
if(isSame(target.identifier!!, xx.second.type, returnedRegister)) {
|
||||
// output register is already identical to target register, so it can become void
|
||||
val voidTarget = PtAssignTarget(true, target.position)
|
||||
node.children[index] = voidTarget
|
||||
voidTarget.parent = node
|
||||
changes++
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if(node.children.dropLast(1).all { (it as PtAssignTarget).void }) {
|
||||
// all targets are now void, the whole assignment can be discarded and replaced by just a (void) call to the subroutine
|
||||
val index = node.parent.children.indexOf(node)
|
||||
val voidCall = PtFunctionCall(functionName, true, DataType.forDt(BaseDataType.UNDEFINED), value.position)
|
||||
value.children.forEach { voidCall.add(it) }
|
||||
node.parent.children[index] = voidCall
|
||||
voidCall.parent = node.parent
|
||||
changes++
|
||||
}
|
||||
}
|
||||
}
|
||||
true
|
||||
}
|
||||
return changes
|
||||
}
|
||||
|
||||
|
||||
private fun optimizeBitTest(program: PtProgram, options: CompilationOptions): Int {
|
||||
if(options.compTarget.machine.cpu == CpuType.VIRTUAL)
|
||||
return 0 // the special bittest optimization is not yet valid for the IR
|
||||
|
||||
fun makeBittestCall(condition: PtBinaryExpression, and: PtBinaryExpression, variable: PtIdentifier, bitmask: Int): PtBuiltinFunctionCall {
|
||||
require(bitmask==128 || bitmask==64)
|
||||
val setOrNot = if(condition.operator=="!=") "set" else "notset"
|
||||
val bittestCall = PtBuiltinFunctionCall("prog8_ifelse_bittest_$setOrNot", false, true, DataType.forDt(BaseDataType.BOOL), condition.position)
|
||||
bittestCall.add(variable)
|
||||
if(bitmask==128)
|
||||
bittestCall.add(PtNumber(BaseDataType.UBYTE, 7.0, and.right.position))
|
||||
else
|
||||
bittestCall.add(PtNumber(BaseDataType.UBYTE, 6.0, and.right.position))
|
||||
return bittestCall
|
||||
}
|
||||
|
||||
fun isAndByteConditionForBRK(condition: PtBinaryExpression?): Triple<PtBinaryExpression, PtIdentifier, Int>? {
|
||||
if(condition!=null && (condition.operator=="==" || condition.operator=="!=")) {
|
||||
if (condition.right.asConstInteger() == 0) {
|
||||
val and = condition.left as? PtBinaryExpression
|
||||
if (and != null && and.operator == "&" && and.type.isUnsignedByte) {
|
||||
val bitmask = and.right.asConstInteger()
|
||||
if(bitmask==128 || bitmask==64) {
|
||||
val variable = and.left as? PtIdentifier
|
||||
if (variable != null && variable.type.isByte) {
|
||||
return Triple(and, variable, bitmask)
|
||||
}
|
||||
val typecast = and.left as? PtTypeCast
|
||||
if (typecast != null && typecast.type.isUnsignedByte) {
|
||||
val castedVariable = typecast.value as? PtIdentifier
|
||||
if(castedVariable!=null && castedVariable.type.isByte)
|
||||
return Triple(and, castedVariable, bitmask)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
var changes = 0
|
||||
var recurse = true
|
||||
walkAst(program) { node: PtNode, depth: Int ->
|
||||
if(node is PtIfElse) {
|
||||
val condition = node.condition as? PtBinaryExpression
|
||||
val check = isAndByteConditionForBRK(condition)
|
||||
if(check!=null) {
|
||||
val (and, variable, bitmask) = check
|
||||
val bittestCall = makeBittestCall(condition!!, and, variable, bitmask)
|
||||
val ifElse = PtIfElse(node.position)
|
||||
ifElse.add(bittestCall)
|
||||
ifElse.add(node.ifScope)
|
||||
if (node.hasElse())
|
||||
ifElse.add(node.elseScope)
|
||||
val index = node.parent.children.indexOf(node)
|
||||
node.parent.children[index] = ifElse
|
||||
ifElse.parent = node.parent
|
||||
changes++
|
||||
recurse = false
|
||||
}
|
||||
}
|
||||
if (node is PtIfExpression) {
|
||||
val condition = node.condition as? PtBinaryExpression
|
||||
val check = isAndByteConditionForBRK(condition)
|
||||
if(check!=null) {
|
||||
val (and, variable, bitmask) = check
|
||||
val bittestCall = makeBittestCall(condition!!, and, variable, bitmask)
|
||||
node.children[0] = bittestCall
|
||||
bittestCall.parent = node
|
||||
changes++
|
||||
recurse = false
|
||||
}
|
||||
}
|
||||
recurse
|
||||
}
|
||||
return changes
|
||||
}
|
||||
|
||||
|
||||
internal fun isSame(identifier: PtIdentifier, type: DataType, returnedRegister: RegisterOrPair): Boolean {
|
||||
if(returnedRegister in Cx16VirtualRegisters) {
|
||||
val regname = returnedRegister.name.lowercase()
|
||||
val identifierRegName = identifier.name.substringAfterLast('.')
|
||||
/*
|
||||
cx16.r? UWORD
|
||||
cx16.r?s WORD
|
||||
cx16.r?L UBYTE
|
||||
cx16.r?H UBYTE
|
||||
cx16.r?sL BYTE
|
||||
cx16.r?sH BYTE
|
||||
*/
|
||||
if(identifier.type.isByte && type.isByte) {
|
||||
if(identifier.name.startsWith("cx16.$regname") && identifierRegName.startsWith(regname)) {
|
||||
return identifierRegName.substring(2) in arrayOf("", "L", "sL") // note: not the -H (msb) variants!
|
||||
}
|
||||
}
|
||||
else if(identifier.type.isWord && type.isWord) {
|
||||
if(identifier.name.startsWith("cx16.$regname") && identifierRegName.startsWith(regname)) {
|
||||
return identifierRegName.substring(2) in arrayOf("", "s")
|
||||
}
|
||||
}
|
||||
}
|
||||
return false // there are no identifiers directly corresponding to cpu registers
|
||||
}
|
74
codeCore/src/prog8/code/source/ImportFileSystem.kt
Normal file
74
codeCore/src/prog8/code/source/ImportFileSystem.kt
Normal file
@ -0,0 +1,74 @@
|
||||
package prog8.code.source
|
||||
|
||||
import prog8.code.core.Position
|
||||
import java.nio.file.Path
|
||||
import java.util.TreeMap
|
||||
import kotlin.io.path.Path
|
||||
import kotlin.io.path.absolute
|
||||
|
||||
|
||||
// Resource caching "filesystem".
|
||||
// Note that it leaves the decision to load a resource or an actual disk file to the caller.
|
||||
|
||||
object ImportFileSystem {
|
||||
|
||||
fun expandTilde(path: String): String = if (path.startsWith("~")) {
|
||||
val userHome = System.getProperty("user.home")
|
||||
userHome + path.drop(1)
|
||||
} else {
|
||||
path
|
||||
}
|
||||
|
||||
fun expandTilde(path: Path): Path = Path(expandTilde(path.toString()))
|
||||
|
||||
fun getFile(path: Path): SourceCode {
|
||||
val normalized = path.absolute().normalize()
|
||||
val cached = cache[normalized.toString()]
|
||||
if (cached != null)
|
||||
return cached
|
||||
val file = SourceCode.File(normalized)
|
||||
cache[normalized.toString()] = file
|
||||
return file
|
||||
}
|
||||
|
||||
fun getResource(name: String): SourceCode {
|
||||
val cached = cache[name]
|
||||
if (cached != null) return cached
|
||||
val resource = SourceCode.Resource(name)
|
||||
cache[name] = resource
|
||||
return resource
|
||||
}
|
||||
|
||||
fun retrieveSourceLine(position: Position): String {
|
||||
if(SourceCode.isLibraryResource(position.file)) {
|
||||
val cached = cache[SourceCode.withoutPrefix(position.file)]
|
||||
if(cached != null)
|
||||
return getLine(cached, position.line)
|
||||
}
|
||||
val cached = cache[position.file]
|
||||
if(cached != null)
|
||||
return getLine(cached, position.line)
|
||||
val path = Path(position.file).absolute().normalize()
|
||||
val cached2 = cache[path.toString()]
|
||||
if(cached2 != null)
|
||||
return getLine(cached2, position.line)
|
||||
throw NoSuchElementException("cannot get source line $position, with path $path")
|
||||
}
|
||||
|
||||
private fun getLine(code: SourceCode, lineIndex: Int): String {
|
||||
var spans = lineSpanCache[code]
|
||||
if(spans==null) {
|
||||
val lineSpans = Regex("^", RegexOption.MULTILINE).findAll(code.text).map { it.range.first }
|
||||
val ends = lineSpans.drop(1) + code.text.length
|
||||
spans = lineSpans.zip(ends).map { (start, end) -> LineSpan(start, end) }.toList().toTypedArray()
|
||||
lineSpanCache[code] = spans
|
||||
}
|
||||
val span = spans[lineIndex - 1]
|
||||
return code.text.substring(span.start, span.end).trim()
|
||||
}
|
||||
|
||||
private class LineSpan(val start: Int, val end: Int)
|
||||
|
||||
private val cache = TreeMap<String, SourceCode>(String.CASE_INSENSITIVE_ORDER)
|
||||
private val lineSpanCache = mutableMapOf<SourceCode, Array<LineSpan>>()
|
||||
}
|
152
codeCore/src/prog8/code/source/SourceCode.kt
Normal file
152
codeCore/src/prog8/code/source/SourceCode.kt
Normal file
@ -0,0 +1,152 @@
|
||||
package prog8.code.source
|
||||
|
||||
import java.io.IOException
|
||||
import java.nio.file.Path
|
||||
import java.text.Normalizer
|
||||
import kotlin.io.path.Path
|
||||
import kotlin.io.path.absolute
|
||||
import kotlin.io.path.readText
|
||||
|
||||
/**
|
||||
* Encapsulates - and ties together - actual source code (=text) and its [origin].
|
||||
*/
|
||||
sealed class SourceCode {
|
||||
|
||||
/**
|
||||
* Whether this [SourceCode] instance was created as a [Resource]
|
||||
*/
|
||||
abstract val isFromResources: Boolean
|
||||
|
||||
/**
|
||||
* Whether this [SourceCode] instance was created as a [File]
|
||||
*/
|
||||
abstract val isFromFilesystem: Boolean
|
||||
|
||||
/**
|
||||
* The logical name of the source code unit. Usually the module's name.
|
||||
*/
|
||||
abstract val name: String
|
||||
|
||||
/**
|
||||
* Where this [SourceCode] instance came from.
|
||||
* This can be one of the following:
|
||||
* * a normal string representation of a [java.nio.file.Path], if it originates from a file (see [File])
|
||||
* * `string:44c56085` if was created via [String]
|
||||
* * `library:/x/y/z.ext` if it is a library file that was loaded from resources (see [Resource])
|
||||
*/
|
||||
abstract val origin: String
|
||||
|
||||
/**
|
||||
* The source code as plain string.
|
||||
*/
|
||||
abstract val text: String
|
||||
|
||||
/**
|
||||
* Printable representation, deliberately does NOT return the actual text.
|
||||
*/
|
||||
final override fun toString() = "${this.javaClass.name}[${this.origin}]"
|
||||
|
||||
companion object {
|
||||
|
||||
/**
|
||||
* filename prefix to designate library files that will be retreived from internal resources rather than disk
|
||||
*/
|
||||
private const val LIBRARYFILEPREFIX = "library:"
|
||||
private const val STRINGSOURCEPREFIX = "string:"
|
||||
val curdir: Path = Path(".").absolute()
|
||||
fun relative(path: Path): Path = curdir.relativize(path.absolute())
|
||||
fun isRegularFilesystemPath(pathString: String) = !isLibraryResource(pathString) && !isStringResource(pathString)
|
||||
fun isLibraryResource(path: String) = path.startsWith(LIBRARYFILEPREFIX)
|
||||
fun isStringResource(path: String) = path.startsWith(STRINGSOURCEPREFIX)
|
||||
fun withoutPrefix(path: String): String {
|
||||
return if(isLibraryResource(path))
|
||||
path.removePrefix(LIBRARYFILEPREFIX)
|
||||
else if(isStringResource(path))
|
||||
path.removePrefix(STRINGSOURCEPREFIX)
|
||||
else
|
||||
path
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Turn a plain String into a [SourceCode] object.
|
||||
* [origin] will be something like `string:44c56085`.
|
||||
*/
|
||||
class Text(origText: String): SourceCode() {
|
||||
override val text = origText.replace("\\R".toRegex(), "\n") // normalize line endings
|
||||
override val isFromResources = false
|
||||
override val isFromFilesystem = false
|
||||
override val origin = "$STRINGSOURCEPREFIX${System.identityHashCode(text).toString(16)}"
|
||||
override val name = "<unnamed-text>"
|
||||
}
|
||||
|
||||
/**
|
||||
* Get [SourceCode] from the file represented by the specified Path.
|
||||
* This immediately reads the file fully into memory.
|
||||
* You can only get an instance of this via the ImportFileSystem object.
|
||||
*
|
||||
* [origin] will be the given path in absolute and normalized form.
|
||||
* @throws NoSuchFileException if the file does not exist
|
||||
* @throws FileSystemException if the file cannot be read
|
||||
*/
|
||||
internal class File(path: Path): SourceCode() {
|
||||
override val text: String
|
||||
override val origin: String
|
||||
override val name: String
|
||||
override val isFromResources = false
|
||||
override val isFromFilesystem = true
|
||||
|
||||
init {
|
||||
val normalized = path.normalize()
|
||||
origin = relative(normalized).toString()
|
||||
try {
|
||||
val contents = Normalizer.normalize(normalized.readText(), Normalizer.Form.NFC)
|
||||
text = contents.replace("\\R".toRegex(), "\n") // normalize line endings
|
||||
name = normalized.toFile().nameWithoutExtension
|
||||
} catch (nfx: java.nio.file.NoSuchFileException) {
|
||||
throw NoSuchFileException(normalized.toFile()).also { it.initCause(nfx) }
|
||||
} catch (iox: IOException) {
|
||||
throw FileSystemException(normalized.toFile()).also { it.initCause(iox) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* [origin]: `library:/x/y/z.p8` for a given `pathString` of "x/y/z.p8"
|
||||
* You can only get an instance of this via the ImportFileSystem object.
|
||||
*/
|
||||
internal class Resource(pathString: String): SourceCode() {
|
||||
private val normalized = "/" + Path(pathString).normalize().toMutableList().joinToString("/")
|
||||
|
||||
override val isFromResources = true
|
||||
override val isFromFilesystem = false
|
||||
override val origin = "$LIBRARYFILEPREFIX$normalized"
|
||||
override val text: String
|
||||
override val name: String
|
||||
|
||||
init {
|
||||
val rscURL = object {}.javaClass.getResource(normalized)
|
||||
if (rscURL == null) {
|
||||
val rscRoot = object {}.javaClass.getResource("/")
|
||||
throw NoSuchFileException(
|
||||
java.io.File(normalized),
|
||||
reason = "looked in resources rooted at $rscRoot"
|
||||
)
|
||||
}
|
||||
val stream = object {}.javaClass.getResourceAsStream(normalized)
|
||||
val contents = stream!!.reader().use { Normalizer.normalize(it.readText(), Normalizer.Form.NFC) }
|
||||
text = contents.replace("\\R".toRegex(), "\n") // normalize line endings
|
||||
name = Path(pathString).toFile().nameWithoutExtension
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* SourceCode for internally generated nodes (usually Modules)
|
||||
*/
|
||||
class Generated(override val name: String) : SourceCode() {
|
||||
override val isFromResources: Boolean = false
|
||||
override val isFromFilesystem: Boolean = false
|
||||
override val origin: String = name
|
||||
override val text: String = "<generated code node, no text representation>"
|
||||
}
|
||||
}
|
40
codeCore/src/prog8/code/target/AtariTarget.kt
Normal file
40
codeCore/src/prog8/code/target/AtariTarget.kt
Normal file
@ -0,0 +1,40 @@
|
||||
package prog8.code.target
|
||||
|
||||
import prog8.code.core.*
|
||||
import prog8.code.target.atari.AtariMachineDefinition
|
||||
|
||||
|
||||
class AtariTarget: ICompilationTarget, IStringEncoding by Encoder, IMemSizer {
|
||||
override val name = NAME
|
||||
override val machine = AtariMachineDefinition()
|
||||
override val defaultEncoding = Encoding.ATASCII
|
||||
|
||||
companion object {
|
||||
const val NAME = "atari"
|
||||
}
|
||||
|
||||
override fun memorySize(dt: DataType, numElements: Int?): Int {
|
||||
if(dt.isArray) {
|
||||
if(numElements==null) return 2 // treat it as a pointer size
|
||||
return when(dt.sub) {
|
||||
BaseDataType.BOOL, BaseDataType.UBYTE, BaseDataType.BYTE -> numElements
|
||||
BaseDataType.UWORD, BaseDataType.WORD, BaseDataType.STR -> numElements * 2
|
||||
BaseDataType.FLOAT-> numElements * machine.FLOAT_MEM_SIZE
|
||||
BaseDataType.UNDEFINED -> throw IllegalArgumentException("undefined has no memory size")
|
||||
else -> throw IllegalArgumentException("invalid sub type")
|
||||
}
|
||||
}
|
||||
else if (dt.isString) {
|
||||
if(numElements!=null) return numElements // treat it as the size of the given string with the length
|
||||
else return 2 // treat it as the size to store a string pointer
|
||||
}
|
||||
|
||||
return when {
|
||||
dt.isByteOrBool -> 1 * (numElements ?: 1)
|
||||
dt.isFloat -> machine.FLOAT_MEM_SIZE * (numElements ?: 1)
|
||||
dt.isLong -> throw IllegalArgumentException("long can not yet be put into memory")
|
||||
dt.isUndefined -> throw IllegalArgumentException("undefined has no memory size")
|
||||
else -> 2 * (numElements ?: 1)
|
||||
}
|
||||
}
|
||||
}
|
19
codeCore/src/prog8/code/target/C128Target.kt
Normal file
19
codeCore/src/prog8/code/target/C128Target.kt
Normal file
@ -0,0 +1,19 @@
|
||||
package prog8.code.target
|
||||
|
||||
import prog8.code.core.Encoding
|
||||
import prog8.code.core.ICompilationTarget
|
||||
import prog8.code.core.IMemSizer
|
||||
import prog8.code.core.IStringEncoding
|
||||
import prog8.code.target.c128.C128MachineDefinition
|
||||
import prog8.code.target.cbm.CbmMemorySizer
|
||||
|
||||
|
||||
class C128Target: ICompilationTarget, IStringEncoding by Encoder, IMemSizer by CbmMemorySizer {
|
||||
override val name = NAME
|
||||
override val machine = C128MachineDefinition()
|
||||
override val defaultEncoding = Encoding.PETSCII
|
||||
|
||||
companion object {
|
||||
const val NAME = "c128"
|
||||
}
|
||||
}
|
43
codeCore/src/prog8/code/target/C64Target.kt
Normal file
43
codeCore/src/prog8/code/target/C64Target.kt
Normal file
@ -0,0 +1,43 @@
|
||||
package prog8.code.target
|
||||
|
||||
import prog8.code.core.Encoding
|
||||
import prog8.code.core.ICompilationTarget
|
||||
import prog8.code.core.IMemSizer
|
||||
import prog8.code.core.IStringEncoding
|
||||
import prog8.code.target.c64.C64MachineDefinition
|
||||
import prog8.code.target.cbm.CbmMemorySizer
|
||||
|
||||
|
||||
class C64Target: ICompilationTarget, IStringEncoding by Encoder, IMemSizer by CbmMemorySizer {
|
||||
override val name = NAME
|
||||
override val machine = C64MachineDefinition()
|
||||
override val defaultEncoding = Encoding.PETSCII
|
||||
|
||||
companion object {
|
||||
const val NAME = "c64"
|
||||
|
||||
fun viceMonListName(baseFilename: String) = "$baseFilename.vice-mon-list"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
val CompilationTargets = listOf(
|
||||
C64Target.NAME,
|
||||
C128Target.NAME,
|
||||
Cx16Target.NAME,
|
||||
PETTarget.NAME,
|
||||
AtariTarget.NAME,
|
||||
Neo6502Target.NAME,
|
||||
VMTarget.NAME
|
||||
)
|
||||
|
||||
fun getCompilationTargetByName(name: String) = when(name.lowercase()) {
|
||||
C64Target.NAME -> C64Target()
|
||||
C128Target.NAME -> C128Target()
|
||||
Cx16Target.NAME -> Cx16Target()
|
||||
PETTarget.NAME -> PETTarget()
|
||||
AtariTarget.NAME -> AtariTarget()
|
||||
VMTarget.NAME -> VMTarget()
|
||||
Neo6502Target.NAME -> Neo6502Target()
|
||||
else -> throw IllegalArgumentException("invalid compilation target")
|
||||
}
|
19
codeCore/src/prog8/code/target/Cx16Target.kt
Normal file
19
codeCore/src/prog8/code/target/Cx16Target.kt
Normal file
@ -0,0 +1,19 @@
|
||||
package prog8.code.target
|
||||
|
||||
import prog8.code.core.Encoding
|
||||
import prog8.code.core.ICompilationTarget
|
||||
import prog8.code.core.IMemSizer
|
||||
import prog8.code.core.IStringEncoding
|
||||
import prog8.code.target.cbm.CbmMemorySizer
|
||||
import prog8.code.target.cx16.CX16MachineDefinition
|
||||
|
||||
|
||||
class Cx16Target: ICompilationTarget, IStringEncoding by Encoder, IMemSizer by CbmMemorySizer {
|
||||
override val name = NAME
|
||||
override val machine = CX16MachineDefinition()
|
||||
override val defaultEncoding = Encoding.PETSCII
|
||||
|
||||
companion object {
|
||||
const val NAME = "cx16"
|
||||
}
|
||||
}
|
47
codeCore/src/prog8/code/target/Encoder.kt
Normal file
47
codeCore/src/prog8/code/target/Encoder.kt
Normal file
@ -0,0 +1,47 @@
|
||||
package prog8.code.target
|
||||
|
||||
import com.github.michaelbull.result.fold
|
||||
import prog8.code.core.Encoding
|
||||
import prog8.code.core.IStringEncoding
|
||||
import prog8.code.core.InternalCompilerException
|
||||
import prog8.code.target.encodings.*
|
||||
|
||||
|
||||
object Encoder: IStringEncoding {
|
||||
override val defaultEncoding: Encoding = Encoding.ISO
|
||||
|
||||
override fun encodeString(str: String, encoding: Encoding): List<UByte> {
|
||||
val coded = when(encoding) {
|
||||
Encoding.PETSCII -> PetsciiEncoding.encodePetscii(str, true)
|
||||
Encoding.SCREENCODES -> PetsciiEncoding.encodeScreencode(str, true)
|
||||
Encoding.ISO -> IsoEncoding.encode(str)
|
||||
Encoding.ATASCII -> AtasciiEncoding.encode(str)
|
||||
Encoding.ISO5 -> IsoCyrillicEncoding.encode(str)
|
||||
Encoding.ISO16 -> IsoEasternEncoding.encode(str)
|
||||
Encoding.CP437 -> Cp437Encoding.encode(str)
|
||||
Encoding.KATAKANA -> KatakanaEncoding.encode(str)
|
||||
else -> throw InternalCompilerException("unsupported encoding $encoding")
|
||||
}
|
||||
return coded.fold(
|
||||
failure = { throw it },
|
||||
success = { it }
|
||||
)
|
||||
}
|
||||
override fun decodeString(bytes: Iterable<UByte>, encoding: Encoding): String {
|
||||
val decoded = when(encoding) {
|
||||
Encoding.PETSCII -> PetsciiEncoding.decodePetscii(bytes, true)
|
||||
Encoding.SCREENCODES -> PetsciiEncoding.decodeScreencode(bytes, true)
|
||||
Encoding.ISO -> IsoEncoding.decode(bytes)
|
||||
Encoding.ATASCII -> AtasciiEncoding.decode(bytes)
|
||||
Encoding.ISO5 -> IsoCyrillicEncoding.decode(bytes)
|
||||
Encoding.ISO16 -> IsoEasternEncoding.decode(bytes)
|
||||
Encoding.CP437 -> Cp437Encoding.decode(bytes)
|
||||
Encoding.KATAKANA -> KatakanaEncoding.decode(bytes)
|
||||
else -> throw InternalCompilerException("unsupported encoding $encoding")
|
||||
}
|
||||
return decoded.fold(
|
||||
failure = { throw it },
|
||||
success = { it }
|
||||
)
|
||||
}
|
||||
}
|
40
codeCore/src/prog8/code/target/Neo6502Target.kt
Normal file
40
codeCore/src/prog8/code/target/Neo6502Target.kt
Normal file
@ -0,0 +1,40 @@
|
||||
package prog8.code.target
|
||||
|
||||
import prog8.code.core.*
|
||||
import prog8.code.target.neo6502.Neo6502MachineDefinition
|
||||
|
||||
|
||||
class Neo6502Target: ICompilationTarget, IStringEncoding by Encoder, IMemSizer {
|
||||
override val name = NAME
|
||||
override val machine = Neo6502MachineDefinition()
|
||||
override val defaultEncoding = Encoding.ISO
|
||||
|
||||
companion object {
|
||||
const val NAME = "neo"
|
||||
}
|
||||
|
||||
override fun memorySize(dt: DataType, numElements: Int?): Int {
|
||||
if(dt.isArray) {
|
||||
if(numElements==null) return 2 // treat it as a pointer size
|
||||
return when(dt.sub) {
|
||||
BaseDataType.BOOL, BaseDataType.UBYTE, BaseDataType.BYTE -> numElements
|
||||
BaseDataType.UWORD, BaseDataType.WORD, BaseDataType.STR -> numElements * 2
|
||||
BaseDataType.FLOAT-> numElements * machine.FLOAT_MEM_SIZE
|
||||
BaseDataType.UNDEFINED -> throw IllegalArgumentException("undefined has no memory size")
|
||||
else -> throw IllegalArgumentException("invalid sub type")
|
||||
}
|
||||
}
|
||||
else if (dt.isString) {
|
||||
if(numElements!=null) return numElements // treat it as the size of the given string with the length
|
||||
else return 2 // treat it as the size to store a string pointer
|
||||
}
|
||||
|
||||
return when {
|
||||
dt.isByteOrBool -> 1 * (numElements ?: 1)
|
||||
dt.isFloat -> machine.FLOAT_MEM_SIZE * (numElements ?: 1)
|
||||
dt.isLong -> throw IllegalArgumentException("long can not yet be put into memory")
|
||||
dt.isUndefined -> throw IllegalArgumentException("undefined has no memory size")
|
||||
else -> 2 * (numElements ?: 1)
|
||||
}
|
||||
}
|
||||
}
|
19
codeCore/src/prog8/code/target/PETTarget.kt
Normal file
19
codeCore/src/prog8/code/target/PETTarget.kt
Normal file
@ -0,0 +1,19 @@
|
||||
package prog8.code.target
|
||||
|
||||
import prog8.code.core.Encoding
|
||||
import prog8.code.core.ICompilationTarget
|
||||
import prog8.code.core.IMemSizer
|
||||
import prog8.code.core.IStringEncoding
|
||||
import prog8.code.target.cbm.CbmMemorySizer
|
||||
import prog8.code.target.pet.PETMachineDefinition
|
||||
|
||||
|
||||
class PETTarget: ICompilationTarget, IStringEncoding by Encoder, IMemSizer by CbmMemorySizer {
|
||||
override val name = NAME
|
||||
override val machine = PETMachineDefinition()
|
||||
override val defaultEncoding = Encoding.PETSCII
|
||||
|
||||
companion object {
|
||||
const val NAME = "pet32"
|
||||
}
|
||||
}
|
39
codeCore/src/prog8/code/target/VMTarget.kt
Normal file
39
codeCore/src/prog8/code/target/VMTarget.kt
Normal file
@ -0,0 +1,39 @@
|
||||
package prog8.code.target
|
||||
|
||||
import prog8.code.core.*
|
||||
import prog8.code.target.virtual.VirtualMachineDefinition
|
||||
|
||||
class VMTarget: ICompilationTarget, IStringEncoding by Encoder, IMemSizer {
|
||||
override val name = NAME
|
||||
override val machine = VirtualMachineDefinition()
|
||||
override val defaultEncoding = Encoding.ISO
|
||||
|
||||
companion object {
|
||||
const val NAME = "virtual"
|
||||
}
|
||||
|
||||
override fun memorySize(dt: DataType, numElements: Int?): Int {
|
||||
if(dt.isArray) {
|
||||
if(numElements==null) return 2 // treat it as a pointer size
|
||||
return when(dt.sub) {
|
||||
BaseDataType.BOOL, BaseDataType.UBYTE, BaseDataType.BYTE -> numElements
|
||||
BaseDataType.UWORD, BaseDataType.WORD, BaseDataType.STR -> numElements * 2
|
||||
BaseDataType.FLOAT-> numElements * machine.FLOAT_MEM_SIZE
|
||||
BaseDataType.UNDEFINED -> throw IllegalArgumentException("undefined has no memory size")
|
||||
else -> throw IllegalArgumentException("invalid sub type")
|
||||
}
|
||||
}
|
||||
else if (dt.isString) {
|
||||
if(numElements!=null) return numElements // treat it as the size of the given string with the length
|
||||
else return 2 // treat it as the size to store a string pointer
|
||||
}
|
||||
|
||||
return when {
|
||||
dt.isByteOrBool -> 1 * (numElements ?: 1)
|
||||
dt.isFloat -> machine.FLOAT_MEM_SIZE * (numElements ?: 1)
|
||||
dt.isLong -> throw IllegalArgumentException("long can not yet be put into memory")
|
||||
dt.isUndefined -> throw IllegalArgumentException("undefined has no memory size")
|
||||
else -> 2 * (numElements ?: 1)
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,62 @@
|
||||
package prog8.code.target.atari
|
||||
|
||||
import prog8.code.core.*
|
||||
import java.nio.file.Path
|
||||
|
||||
|
||||
class AtariMachineDefinition: IMachineDefinition {
|
||||
|
||||
override val cpu = CpuType.CPU6502
|
||||
|
||||
override val FLOAT_MAX_POSITIVE = 9.999999999e97
|
||||
override val FLOAT_MAX_NEGATIVE = -9.999999999e97
|
||||
override val FLOAT_MEM_SIZE = 6
|
||||
override val STARTUP_CODE_RESERVED_SIZE = 20u
|
||||
override val PROGRAM_LOAD_ADDRESS = 0x2000u
|
||||
override val PROGRAM_MEMTOP_ADDRESS = 0xffffu // TODO what's memtop?
|
||||
|
||||
override val BSSHIGHRAM_START = 0u // TODO
|
||||
override val BSSHIGHRAM_END = 0u // TODO
|
||||
override val BSSGOLDENRAM_START = 0u // TODO
|
||||
override val BSSGOLDENRAM_END = 0u // TODO
|
||||
|
||||
override lateinit var zeropage: Zeropage
|
||||
override lateinit var golden: GoldenRam
|
||||
|
||||
override fun getFloatAsmBytes(num: Number) = TODO("atari float asm bytes from number")
|
||||
override fun convertFloatToBytes(num: Double): List<UByte> = TODO("atari float to bytes")
|
||||
override fun convertBytesToFloat(bytes: List<UByte>): Double = TODO("atari bytes to float")
|
||||
|
||||
override fun launchEmulator(selectedEmulator: Int, programNameWithPath: Path) {
|
||||
val emulatorName: String
|
||||
val cmdline: List<String>
|
||||
when(selectedEmulator) {
|
||||
1 -> {
|
||||
emulatorName = "atari800"
|
||||
cmdline = listOf(emulatorName, "-xl", "-xl-rev", "2", "-nobasic", "-run", "${programNameWithPath}.xex")
|
||||
}
|
||||
2 -> {
|
||||
emulatorName = "altirra"
|
||||
cmdline = listOf("Altirra64.exe", "${programNameWithPath.normalize()}.xex")
|
||||
}
|
||||
else -> {
|
||||
System.err.println("Atari target only supports atari800 and altirra emulators.")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// TODO monlist?
|
||||
|
||||
println("\nStarting Atari800XL emulator $emulatorName...")
|
||||
val processb = ProcessBuilder(cmdline).inheritIO()
|
||||
val process: Process = processb.start()
|
||||
process.waitFor()
|
||||
}
|
||||
|
||||
override fun isIOAddress(address: UInt): Boolean = address==0u || address==1u || address in 0xd000u..0xdfffu // TODO
|
||||
|
||||
override fun initializeMemoryAreas(compilerOptions: CompilationOptions) {
|
||||
zeropage = AtariZeropage(compilerOptions)
|
||||
golden = GoldenRam(compilerOptions, UIntRange.EMPTY)
|
||||
}
|
||||
}
|
57
codeCore/src/prog8/code/target/atari/AtariZeropage.kt
Normal file
57
codeCore/src/prog8/code/target/atari/AtariZeropage.kt
Normal file
@ -0,0 +1,57 @@
|
||||
package prog8.code.target.atari
|
||||
|
||||
import prog8.code.core.CompilationOptions
|
||||
import prog8.code.core.InternalCompilerException
|
||||
import prog8.code.core.Zeropage
|
||||
import prog8.code.core.ZeropageType
|
||||
|
||||
class AtariZeropage(options: CompilationOptions) : Zeropage(options) {
|
||||
|
||||
override val SCRATCH_B1 = 0xcbu // temp storage for a single byte
|
||||
override val SCRATCH_REG = 0xccu // temp storage for a register, must be B1+1
|
||||
override val SCRATCH_W1 = 0xcdu // temp storage 1 for a word $cd+$ce
|
||||
override val SCRATCH_W2 = 0xcfu // temp storage 2 for a word $cf+$d0 TODO is $d0 okay to use?
|
||||
|
||||
init {
|
||||
if (options.floats) {
|
||||
throw InternalCompilerException("Atari target doesn't yet support floating point routines")
|
||||
}
|
||||
|
||||
if (options.floats && options.zeropage !in arrayOf(
|
||||
ZeropageType.FLOATSAFE,
|
||||
ZeropageType.BASICSAFE,
|
||||
ZeropageType.DONTUSE
|
||||
))
|
||||
throw InternalCompilerException("when floats are enabled, zero page type should be 'floatsafe' or 'basicsafe' or 'dontuse'")
|
||||
|
||||
when (options.zeropage) {
|
||||
ZeropageType.FULL -> {
|
||||
// TODO all atari usable zero page locations, except the ones used by the system's IRQ routine
|
||||
free.addAll(0x00u..0xffu)
|
||||
// TODO atari free.removeAll(arrayOf(0xa0u, 0xa1u, 0xa2u, 0x91u, 0xc0u, 0xc5u, 0xcbu, 0xf5u, 0xf6u)) // these are updated by IRQ
|
||||
}
|
||||
ZeropageType.KERNALSAFE -> {
|
||||
free.addAll(0x80u..0xffu) // TODO
|
||||
}
|
||||
ZeropageType.BASICSAFE,
|
||||
ZeropageType.FLOATSAFE -> {
|
||||
free.addAll(0x80u..0xffu) // TODO
|
||||
free.removeAll(0xd4u .. 0xefu) // floating point storage
|
||||
}
|
||||
ZeropageType.DONTUSE -> {
|
||||
free.clear() // don't use zeropage at all
|
||||
}
|
||||
}
|
||||
|
||||
val distinctFree = free.distinct()
|
||||
free.clear()
|
||||
free.addAll(distinctFree)
|
||||
|
||||
removeReservedFromFreePool()
|
||||
retainAllowed()
|
||||
}
|
||||
|
||||
override fun allocateCx16VirtualRegisters() {
|
||||
TODO("Not known if atari can put the virtual regs in ZP")
|
||||
}
|
||||
}
|
62
codeCore/src/prog8/code/target/c128/C128MachineDefinition.kt
Normal file
62
codeCore/src/prog8/code/target/c128/C128MachineDefinition.kt
Normal file
@ -0,0 +1,62 @@
|
||||
package prog8.code.target.c128
|
||||
|
||||
import prog8.code.core.*
|
||||
import prog8.code.target.C64Target
|
||||
import prog8.code.target.cbm.Mflpt5
|
||||
import java.nio.file.Path
|
||||
|
||||
|
||||
class C128MachineDefinition: IMachineDefinition {
|
||||
|
||||
override val cpu = CpuType.CPU6502
|
||||
|
||||
override val FLOAT_MAX_POSITIVE = Mflpt5.FLOAT_MAX_POSITIVE
|
||||
override val FLOAT_MAX_NEGATIVE = Mflpt5.FLOAT_MAX_NEGATIVE
|
||||
override val FLOAT_MEM_SIZE = Mflpt5.FLOAT_MEM_SIZE
|
||||
override val STARTUP_CODE_RESERVED_SIZE = 20u
|
||||
override val PROGRAM_LOAD_ADDRESS = 0x1c01u
|
||||
override val PROGRAM_MEMTOP_ADDRESS = 0xc000u
|
||||
|
||||
override val BSSHIGHRAM_START = 0u // TODO
|
||||
override val BSSHIGHRAM_END = 0u // TODO
|
||||
override val BSSGOLDENRAM_START = 0u // TODO
|
||||
override val BSSGOLDENRAM_END = 0u // TODO
|
||||
|
||||
override lateinit var zeropage: Zeropage
|
||||
override lateinit var golden: GoldenRam
|
||||
|
||||
override fun getFloatAsmBytes(num: Number) = Mflpt5.fromNumber(num).makeFloatFillAsm()
|
||||
|
||||
override fun convertFloatToBytes(num: Double): List<UByte> {
|
||||
val m5 = Mflpt5.fromNumber(num)
|
||||
return listOf(m5.b0, m5.b1, m5.b2, m5.b3, m5.b4)
|
||||
}
|
||||
|
||||
override fun convertBytesToFloat(bytes: List<UByte>): Double {
|
||||
require(bytes.size==5) { "need 5 bytes" }
|
||||
val m5 = Mflpt5(bytes[0], bytes[1], bytes[2], bytes[3], bytes[4])
|
||||
return m5.toDouble()
|
||||
}
|
||||
|
||||
override fun launchEmulator(selectedEmulator: Int, programNameWithPath: Path) {
|
||||
if(selectedEmulator!=1) {
|
||||
System.err.println("The c128 target only supports the main emulator (Vice).")
|
||||
return
|
||||
}
|
||||
|
||||
println("\nStarting C-128 emulator x128...")
|
||||
val viceMonlist = C64Target.viceMonListName(programNameWithPath.toString())
|
||||
val cmdline = listOf("x128", "-silent", "-moncommands", viceMonlist,
|
||||
"-autostartprgmode", "1", "-autostart-warp", "-autostart", "${programNameWithPath}.prg")
|
||||
val processb = ProcessBuilder(cmdline).inheritIO()
|
||||
val process: Process = processb.start()
|
||||
process.waitFor()
|
||||
}
|
||||
|
||||
override fun isIOAddress(address: UInt): Boolean = address==0u || address==1u || address in 0xd000u..0xdfffu
|
||||
|
||||
override fun initializeMemoryAreas(compilerOptions: CompilationOptions) {
|
||||
zeropage = C128Zeropage(compilerOptions)
|
||||
golden = GoldenRam(compilerOptions, UIntRange.EMPTY) // TODO does the c128 have some of this somewhere?
|
||||
}
|
||||
}
|
78
codeCore/src/prog8/code/target/c128/C128Zeropage.kt
Normal file
78
codeCore/src/prog8/code/target/c128/C128Zeropage.kt
Normal file
@ -0,0 +1,78 @@
|
||||
package prog8.code.target.c128
|
||||
|
||||
import prog8.code.core.CompilationOptions
|
||||
import prog8.code.core.InternalCompilerException
|
||||
import prog8.code.core.Zeropage
|
||||
import prog8.code.core.ZeropageType
|
||||
|
||||
|
||||
// reference: "Mapping the C128" zeropage chapter.
|
||||
|
||||
class C128Zeropage(options: CompilationOptions) : Zeropage(options) {
|
||||
|
||||
override val SCRATCH_B1 = 0x74u // temp storage for a single byte
|
||||
override val SCRATCH_REG = 0x75u // temp storage for a register, must be B1+1
|
||||
override val SCRATCH_W1 = 0xfbu // temp storage 1 for a word $fb+$fc
|
||||
override val SCRATCH_W2 = 0xfdu // temp storage 2 for a word $fd+$fe
|
||||
|
||||
init {
|
||||
if (options.floats) {
|
||||
throw InternalCompilerException("C128 target doesn't yet support floating point routines")
|
||||
// note: in git commit labeled 'c128: remove floats module' the floats.p8 and floats.asm files are removed,
|
||||
// they could be retrieved again at a later time if the compiler somehow *does* store the fp variables in bank1.
|
||||
}
|
||||
|
||||
if (options.floats && options.zeropage !in arrayOf(
|
||||
ZeropageType.FLOATSAFE,
|
||||
ZeropageType.BASICSAFE,
|
||||
ZeropageType.DONTUSE
|
||||
))
|
||||
throw InternalCompilerException("when floats are enabled, zero page type should be 'floatsafe' or 'basicsafe' or 'dontuse'")
|
||||
|
||||
when (options.zeropage) {
|
||||
ZeropageType.FULL -> {
|
||||
// $00/$01 are data port IO registers, // $02-$09 are storage locations for JSRFAR and such
|
||||
free.addAll(0x0au..0xffu)
|
||||
free.removeAll(arrayOf(0x90u, 0x91u, 0xa0u, 0xa1u, 0xa2u, 0xc0u, 0xccu, 0xcdu, 0xd0u, 0xd1u, 0xd2u, 0xd3u, 0xd4u, 0xd5u, 0xf7u)) // these are updated/used by IRQ
|
||||
}
|
||||
ZeropageType.KERNALSAFE -> {
|
||||
free.addAll(0x0au..0x8fu) // BASIC variables
|
||||
free.addAll(arrayOf(0x92u, 0x96u, 0x9bu, 0x9cu, 0x9eu, 0x9fu, 0xa4u, 0xa7u, 0xa8u, 0xa9u, 0xaau, 0xabu,
|
||||
0xb0u, 0xb1u, 0xb4u, 0xb5u, 0xb6u))
|
||||
}
|
||||
ZeropageType.FLOATSAFE,
|
||||
ZeropageType.BASICSAFE -> {
|
||||
free.addAll(arrayOf(0x0bu, 0x0cu, 0x0du, 0x0eu, 0x0fu, 0x10u, 0x11u, 0x12u, 0x16u, 0x17u, 0x18u, 0x19u, 0x1au))
|
||||
free.addAll(0x1bu..0x23u)
|
||||
free.addAll(arrayOf(0x3fu, 0x40u, 0x41u, 0x42u, 0x43u, 0x44u, 0x47u, 0x48u, 0x49u, 0x4au, 0x4bu, 0x4cu, 0x4fu,
|
||||
0x55u, 0x56u, 0x57u, 0x58u,
|
||||
0x74u, 0x75u, 0x78u, 0x80u, 0x83u, 0x87u, 0x88u, 0x89u, 0x8au, 0x8bu, 0x8cu, 0x8du, 0x8eu, 0x8fu,
|
||||
0x92u, 0x96u, 0x9bu, 0x9cu, 0x9eu, 0x9fu, 0xa4u, 0xa7u, 0xa8u, 0xa9u, 0xaau, 0xabu,
|
||||
0xb0u, 0xb1u, 0xb4u, 0xb5u, 0xb6u
|
||||
))
|
||||
|
||||
// if(options.zeropage==ZeropageType.BASICSAFE) {
|
||||
// can also clobber the FP locations (unconditionally, because the C128 target doesn't support floating point calculations in prog8 at this time0
|
||||
free.addAll(arrayOf(0x14u, 0x28u, 0x29u, 0x2au, 0x2bu, 0x2cu,
|
||||
0x50u, 0x51u, 0x52u, 0x53u, 0x54u, 0x59u, 0x5au, 0x5bu, 0x5cu, 0x5du, 0x5eu, 0x5fu, 0x60u, 0x61u, 0x62u,
|
||||
0x63u, 0x64u, 0x65u, 0x66u, 0x67u, 0x68u,
|
||||
0x6au, 0x6bu, 0x6cu, 0x6du, 0x6eu, 0x6fu, 0x71u))
|
||||
// }
|
||||
}
|
||||
ZeropageType.DONTUSE -> {
|
||||
free.clear() // don't use zeropage at all
|
||||
}
|
||||
}
|
||||
|
||||
val distinctFree = free.distinct()
|
||||
free.clear()
|
||||
free.addAll(distinctFree)
|
||||
|
||||
removeReservedFromFreePool()
|
||||
retainAllowed()
|
||||
}
|
||||
|
||||
override fun allocateCx16VirtualRegisters() {
|
||||
TODO("Not known if C128 can put the virtual regs in ZP")
|
||||
}
|
||||
}
|
73
codeCore/src/prog8/code/target/c64/C64MachineDefinition.kt
Normal file
73
codeCore/src/prog8/code/target/c64/C64MachineDefinition.kt
Normal file
@ -0,0 +1,73 @@
|
||||
package prog8.code.target.c64
|
||||
|
||||
import prog8.code.core.*
|
||||
import prog8.code.target.C64Target
|
||||
import prog8.code.target.cbm.Mflpt5
|
||||
import java.io.IOException
|
||||
import java.nio.file.Path
|
||||
|
||||
|
||||
class C64MachineDefinition: IMachineDefinition {
|
||||
|
||||
override val cpu = CpuType.CPU6502
|
||||
|
||||
override val FLOAT_MAX_POSITIVE = Mflpt5.FLOAT_MAX_POSITIVE
|
||||
override val FLOAT_MAX_NEGATIVE = Mflpt5.FLOAT_MAX_NEGATIVE
|
||||
override val FLOAT_MEM_SIZE = Mflpt5.FLOAT_MEM_SIZE
|
||||
override val STARTUP_CODE_RESERVED_SIZE = 20u
|
||||
override val PROGRAM_LOAD_ADDRESS = 0x0801u
|
||||
override val PROGRAM_MEMTOP_ADDRESS = 0xcfe0u // $a000 if floats are used
|
||||
// note that at $cfe0-$cfff are the 16 'virtual registers' R0-R15
|
||||
|
||||
override val BSSHIGHRAM_START = 0xc000u
|
||||
override val BSSHIGHRAM_END = 0xcfdfu
|
||||
override val BSSGOLDENRAM_START = 0u
|
||||
override val BSSGOLDENRAM_END = 0u
|
||||
|
||||
override lateinit var zeropage: Zeropage
|
||||
override lateinit var golden: GoldenRam
|
||||
|
||||
override fun getFloatAsmBytes(num: Number) = Mflpt5.fromNumber(num).makeFloatFillAsm()
|
||||
|
||||
override fun convertFloatToBytes(num: Double): List<UByte> {
|
||||
val m5 = Mflpt5.fromNumber(num)
|
||||
return listOf(m5.b0, m5.b1, m5.b2, m5.b3, m5.b4)
|
||||
}
|
||||
|
||||
override fun convertBytesToFloat(bytes: List<UByte>): Double {
|
||||
require(bytes.size==5) { "need 5 bytes" }
|
||||
val m5 = Mflpt5(bytes[0], bytes[1], bytes[2], bytes[3], bytes[4])
|
||||
return m5.toDouble()
|
||||
}
|
||||
|
||||
override fun launchEmulator(selectedEmulator: Int, programNameWithPath: Path) {
|
||||
if(selectedEmulator!=1) {
|
||||
System.err.println("The c64 target only supports the main emulator (Vice).")
|
||||
return
|
||||
}
|
||||
|
||||
for(emulator in listOf("x64sc", "x64")) {
|
||||
println("\nStarting C-64 emulator $emulator...")
|
||||
val viceMonlist = C64Target.viceMonListName(programNameWithPath.toString())
|
||||
val cmdline = listOf(emulator, "-silent", "-moncommands", viceMonlist,
|
||||
"-autostartprgmode", "1", "-autostart-warp", "-autostart", "${programNameWithPath}.prg")
|
||||
val processb = ProcessBuilder(cmdline).inheritIO()
|
||||
val process: Process
|
||||
try {
|
||||
process=processb.start()
|
||||
} catch(_: IOException) {
|
||||
continue // try the next emulator executable
|
||||
}
|
||||
process.waitFor()
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
override fun isIOAddress(address: UInt): Boolean = address==0u || address==1u || address in 0xd000u..0xdfffu
|
||||
|
||||
override fun initializeMemoryAreas(compilerOptions: CompilationOptions) {
|
||||
zeropage = C64Zeropage(compilerOptions)
|
||||
golden = GoldenRam(compilerOptions, 0xc000u until 0xd000u)
|
||||
}
|
||||
|
||||
}
|
98
codeCore/src/prog8/code/target/c64/C64Zeropage.kt
Normal file
98
codeCore/src/prog8/code/target/c64/C64Zeropage.kt
Normal file
@ -0,0 +1,98 @@
|
||||
package prog8.code.target.c64
|
||||
|
||||
import prog8.code.core.*
|
||||
|
||||
|
||||
class C64Zeropage(options: CompilationOptions) : Zeropage(options) {
|
||||
|
||||
override val SCRATCH_B1 = 0x02u // temp storage for a single byte
|
||||
override val SCRATCH_REG = 0x03u // temp storage for a register, must be B1+1
|
||||
override val SCRATCH_W1 = 0xfbu // temp storage 1 for a word $fb+$fc
|
||||
override val SCRATCH_W2 = 0xfdu // temp storage 2 for a word $fd+$fe
|
||||
|
||||
|
||||
init {
|
||||
if (options.floats && options.zeropage !in arrayOf(
|
||||
ZeropageType.FLOATSAFE,
|
||||
ZeropageType.BASICSAFE,
|
||||
ZeropageType.DONTUSE
|
||||
))
|
||||
throw InternalCompilerException("when floats are enabled, zero page type should be 'floatsafe' or 'basicsafe' or 'dontuse'")
|
||||
|
||||
if (options.zeropage == ZeropageType.FULL) {
|
||||
free.addAll(0x02u..0xffu)
|
||||
free.removeAll(arrayOf(SCRATCH_B1, SCRATCH_REG, SCRATCH_W1, SCRATCH_W1+1u, SCRATCH_W2, SCRATCH_W2+1u))
|
||||
free.removeAll(arrayOf(0xa0u, 0xa1u, 0xa2u, 0x91u, 0xc0u, 0xc5u, 0xcbu, 0xf5u, 0xf6u)) // these are updated by IRQ
|
||||
} else {
|
||||
if (options.zeropage == ZeropageType.KERNALSAFE || options.zeropage == ZeropageType.FLOATSAFE) {
|
||||
free.addAll(arrayOf(
|
||||
0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
|
||||
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
|
||||
0x20, 0x21, 0x22, 0x23, 0x24, 0x25,
|
||||
0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46,
|
||||
0x47, 0x48, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x51, 0x52, 0x53,
|
||||
0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, 0x60,
|
||||
0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68,
|
||||
0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72,
|
||||
0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c,
|
||||
0x7d, 0x7e, 0x7f, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a,
|
||||
0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 0xff
|
||||
// 0x90-0xfa is 'kernal work storage area'
|
||||
).map{it.toUInt()})
|
||||
}
|
||||
|
||||
if (options.zeropage == ZeropageType.FLOATSAFE) {
|
||||
// remove the zeropage locations used for floating point operations from the free list
|
||||
free.removeAll(arrayOf(
|
||||
0x03, 0x04, 0x05, 0x06, 0x10, 0x11, 0x12,
|
||||
0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a,
|
||||
0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, 0x60,
|
||||
0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68,
|
||||
0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72,
|
||||
0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 0xff
|
||||
).map{it.toUInt()})
|
||||
}
|
||||
|
||||
if(options.zeropage != ZeropageType.DONTUSE) {
|
||||
// add the free Zp addresses
|
||||
// these are valid for the C-64 but allow BASIC to keep running fully *as long as you don't use tape I/O*
|
||||
free.addAll(arrayOf(0x02, 0x03, 0x04, 0x05, 0x06, 0x0a, 0x0e,
|
||||
0x92, 0x96, 0x9b, 0x9c, 0x9e, 0x9f, 0xa6,
|
||||
0xb0, 0xb1, 0xbe, 0xbf, 0xf9).map{it.toUInt()})
|
||||
} else {
|
||||
// don't use the zeropage at all
|
||||
free.clear()
|
||||
}
|
||||
}
|
||||
|
||||
val distinctFree = free.distinct()
|
||||
free.clear()
|
||||
free.addAll(distinctFree)
|
||||
|
||||
removeReservedFromFreePool()
|
||||
|
||||
if(options.zeropage==ZeropageType.FULL || options.zeropage==ZeropageType.KERNALSAFE) {
|
||||
// in these cases there is enough space on the zero page to stick the cx16 virtual registers in there as well.
|
||||
allocateCx16VirtualRegisters()
|
||||
}
|
||||
|
||||
retainAllowed()
|
||||
}
|
||||
|
||||
override fun allocateCx16VirtualRegisters() {
|
||||
// Note: the 16 virtual registers R0-R15 are not regular allocated variables, they're *memory mapped* elsewhere to fixed addresses.
|
||||
// However, to be able for the compiler to "see" them as zeropage variables, we have to register them here as well.
|
||||
// This is important because the compiler sometimes treats ZP variables more efficiently (for example if it's a pointer)
|
||||
// The base addres is $04. Unfortunately it cannot be the same as on the Commander X16 ($02).
|
||||
for(reg in 0..15) {
|
||||
allocatedVariables["cx16.r${reg}"] = VarAllocation((4+reg*2).toUInt(), DataType.forDt(BaseDataType.UWORD), 2) // cx16.r0 .. cx16.r15
|
||||
allocatedVariables["cx16.r${reg}s"] = VarAllocation((4+reg*2).toUInt(), DataType.forDt(BaseDataType.WORD), 2) // cx16.r0s .. cx16.r15s
|
||||
allocatedVariables["cx16.r${reg}L"] = VarAllocation((4+reg*2).toUInt(), DataType.forDt(BaseDataType.UBYTE), 1) // cx16.r0L .. cx16.r15L
|
||||
allocatedVariables["cx16.r${reg}H"] = VarAllocation((5+reg*2).toUInt(), DataType.forDt(BaseDataType.UBYTE), 1) // cx16.r0H .. cx16.r15H
|
||||
allocatedVariables["cx16.r${reg}sL"] = VarAllocation((4+reg*2).toUInt(), DataType.forDt(BaseDataType.BYTE), 1) // cx16.r0sL .. cx16.r15sL
|
||||
allocatedVariables["cx16.r${reg}sH"] = VarAllocation((5+reg*2).toUInt(), DataType.forDt(BaseDataType.BYTE), 1) // cx16.r0sH .. cx16.r15sH
|
||||
free.remove((4+reg*2).toUInt())
|
||||
free.remove((5+reg*2).toUInt())
|
||||
}
|
||||
}
|
||||
}
|
33
codeCore/src/prog8/code/target/cbm/CbmMemorySizer.kt
Normal file
33
codeCore/src/prog8/code/target/cbm/CbmMemorySizer.kt
Normal file
@ -0,0 +1,33 @@
|
||||
package prog8.code.target.cbm
|
||||
|
||||
import prog8.code.core.BaseDataType
|
||||
import prog8.code.core.DataType
|
||||
import prog8.code.core.IMemSizer
|
||||
|
||||
|
||||
internal object CbmMemorySizer: IMemSizer {
|
||||
override fun memorySize(dt: DataType, numElements: Int?): Int {
|
||||
if(dt.isArray) {
|
||||
if(numElements==null) return 2 // treat it as a pointer size
|
||||
return when(dt.sub) {
|
||||
BaseDataType.BOOL, BaseDataType.UBYTE, BaseDataType.BYTE -> numElements
|
||||
BaseDataType.UWORD, BaseDataType.WORD, BaseDataType.STR -> numElements * 2
|
||||
BaseDataType.FLOAT-> numElements * Mflpt5.FLOAT_MEM_SIZE
|
||||
BaseDataType.UNDEFINED -> throw IllegalArgumentException("undefined has no memory size")
|
||||
else -> throw IllegalArgumentException("invalid sub type")
|
||||
}
|
||||
}
|
||||
else if (dt.isString) {
|
||||
if(numElements!=null) return numElements // treat it as the size of the given string with the length
|
||||
else return 2 // treat it as the size to store a string pointer
|
||||
}
|
||||
|
||||
return when {
|
||||
dt.isByteOrBool -> 1 * (numElements ?: 1)
|
||||
dt.isFloat -> Mflpt5.FLOAT_MEM_SIZE * (numElements ?: 1)
|
||||
dt.isLong -> throw IllegalArgumentException("long can not yet be put into memory")
|
||||
dt.isUndefined -> throw IllegalArgumentException("undefined has no memory size")
|
||||
else -> 2 * (numElements ?: 1)
|
||||
}
|
||||
}
|
||||
}
|
77
codeCore/src/prog8/code/target/cbm/Mflpt5.kt
Normal file
77
codeCore/src/prog8/code/target/cbm/Mflpt5.kt
Normal file
@ -0,0 +1,77 @@
|
||||
package prog8.code.target.cbm
|
||||
|
||||
import prog8.code.core.InternalCompilerException
|
||||
import kotlin.math.absoluteValue
|
||||
import kotlin.math.pow
|
||||
|
||||
|
||||
data class Mflpt5(val b0: UByte, val b1: UByte, val b2: UByte, val b3: UByte, val b4: UByte) {
|
||||
|
||||
companion object {
|
||||
const val FLOAT_MAX_POSITIVE = 1.7014118345e+38 // bytes: 255,127,255,255,255
|
||||
const val FLOAT_MAX_NEGATIVE = -1.7014118345e+38 // bytes: 255,255,255,255,255
|
||||
const val FLOAT_MEM_SIZE = 5
|
||||
|
||||
val zero = Mflpt5(0u, 0u, 0u, 0u, 0u)
|
||||
fun fromNumber(num: Number): Mflpt5 {
|
||||
// see https://en.wikipedia.org/wiki/Microsoft_Binary_Format
|
||||
// and https://sourceforge.net/p/acme-crossass/code-0/62/tree/trunk/ACME_Lib/cbm/mflpt.a
|
||||
// and https://en.wikipedia.org/wiki/IEEE_754-1985
|
||||
|
||||
val flt = num.toDouble()
|
||||
if (flt < FLOAT_MAX_NEGATIVE || flt > FLOAT_MAX_POSITIVE)
|
||||
throw InternalCompilerException("floating point number out of 5-byte mflpt range: $this")
|
||||
if (flt == 0.0)
|
||||
return zero
|
||||
|
||||
val sign = if (flt < 0.0) 0x80L else 0x00L
|
||||
var exponent = 128 + 32 // 128 is cbm's bias, 32 is this algo's bias
|
||||
var mantissa = flt.absoluteValue
|
||||
|
||||
// if mantissa is too large, shift right and adjust exponent
|
||||
while (mantissa >= 0x100000000) {
|
||||
mantissa /= 2.0
|
||||
exponent++
|
||||
}
|
||||
// if mantissa is too small, shift left and adjust exponent
|
||||
while (mantissa < 0x80000000) {
|
||||
mantissa *= 2.0
|
||||
exponent--
|
||||
}
|
||||
|
||||
return when {
|
||||
exponent < 0 -> zero // underflow, use zero instead
|
||||
exponent > 255 -> throw InternalCompilerException("floating point overflow: $this")
|
||||
exponent == 0 -> zero
|
||||
else -> {
|
||||
val mantLong = mantissa.toLong()
|
||||
Mflpt5(
|
||||
exponent.toUByte(),
|
||||
(mantLong.and(0x7f000000L) ushr 24).or(sign).toUByte(),
|
||||
(mantLong.and(0x00ff0000L) ushr 16).toUByte(),
|
||||
(mantLong.and(0x0000ff00L) ushr 8).toUByte(),
|
||||
(mantLong.and(0x000000ffL)).toUByte()
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun toDouble(): Double {
|
||||
if (this == zero) return 0.0
|
||||
val exp = b0.toInt() - 128
|
||||
val sign = (b1.toInt() and 0x80) > 0
|
||||
val number = 0x80000000L.or(b1.toLong() shl 24).or(b2.toLong() shl 16).or(b3.toLong() shl 8).or(b4.toLong())
|
||||
val result = number.toDouble() * (2.0).pow(exp) / 0x100000000
|
||||
return if (sign) -result else result
|
||||
}
|
||||
|
||||
fun makeFloatFillAsm(): String {
|
||||
val b0 = "$" + b0.toString(16).padStart(2, '0')
|
||||
val b1 = "$" + b1.toString(16).padStart(2, '0')
|
||||
val b2 = "$" + b2.toString(16).padStart(2, '0')
|
||||
val b3 = "$" + b3.toString(16).padStart(2, '0')
|
||||
val b4 = "$" + b4.toString(16).padStart(2, '0')
|
||||
return "$b0, $b1, $b2, $b3, $b4"
|
||||
}
|
||||
}
|
75
codeCore/src/prog8/code/target/cx16/CX16MachineDefinition.kt
Normal file
75
codeCore/src/prog8/code/target/cx16/CX16MachineDefinition.kt
Normal file
@ -0,0 +1,75 @@
|
||||
package prog8.code.target.cx16
|
||||
|
||||
import prog8.code.core.*
|
||||
import prog8.code.target.C64Target
|
||||
import prog8.code.target.cbm.Mflpt5
|
||||
import java.nio.file.Path
|
||||
|
||||
|
||||
class CX16MachineDefinition: IMachineDefinition {
|
||||
|
||||
override val cpu = CpuType.CPU65c02
|
||||
|
||||
override val FLOAT_MAX_POSITIVE = Mflpt5.FLOAT_MAX_POSITIVE
|
||||
override val FLOAT_MAX_NEGATIVE = Mflpt5.FLOAT_MAX_NEGATIVE
|
||||
override val FLOAT_MEM_SIZE = Mflpt5.FLOAT_MEM_SIZE
|
||||
override val STARTUP_CODE_RESERVED_SIZE = 20u
|
||||
override val PROGRAM_LOAD_ADDRESS = 0x0801u
|
||||
override val PROGRAM_MEMTOP_ADDRESS = 0x9f00u
|
||||
|
||||
override val BSSHIGHRAM_START = 0xa000u // hiram bank 1, 8Kb, assumed to be active
|
||||
override val BSSHIGHRAM_END = 0xbfffu // Rom starts at $c000
|
||||
override val BSSGOLDENRAM_START = 0x0400u
|
||||
override val BSSGOLDENRAM_END = 0x07ffu
|
||||
|
||||
override lateinit var zeropage: Zeropage
|
||||
override lateinit var golden: GoldenRam
|
||||
|
||||
override fun getFloatAsmBytes(num: Number) = Mflpt5.fromNumber(num).makeFloatFillAsm()
|
||||
|
||||
override fun convertFloatToBytes(num: Double): List<UByte> {
|
||||
val m5 = Mflpt5.fromNumber(num)
|
||||
return listOf(m5.b0, m5.b1, m5.b2, m5.b3, m5.b4)
|
||||
}
|
||||
|
||||
override fun convertBytesToFloat(bytes: List<UByte>): Double {
|
||||
require(bytes.size==5) { "need 5 bytes" }
|
||||
val m5 = Mflpt5(bytes[0], bytes[1], bytes[2], bytes[3], bytes[4])
|
||||
return m5.toDouble()
|
||||
}
|
||||
|
||||
override fun launchEmulator(selectedEmulator: Int, programNameWithPath: Path) {
|
||||
val emulator: String
|
||||
val extraArgs: List<String>
|
||||
|
||||
when(selectedEmulator) {
|
||||
1 -> {
|
||||
emulator = "x16emu"
|
||||
extraArgs = listOf("-debug")
|
||||
}
|
||||
2 -> {
|
||||
emulator = "box16"
|
||||
extraArgs = listOf("-sym", C64Target.viceMonListName(programNameWithPath.toString()))
|
||||
}
|
||||
else -> {
|
||||
System.err.println("Cx16 target only supports x16emu and box16 emulators.")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
println("\nStarting Commander X16 emulator $emulator...")
|
||||
val cmdline = listOf(emulator, "-scale", "2", "-rtc", "-run", "-prg", "${programNameWithPath}.prg") + extraArgs
|
||||
val processb = ProcessBuilder(cmdline).inheritIO()
|
||||
processb.environment()["PULSE_LATENCY_MSEC"] = "10"
|
||||
val process: Process = processb.start()
|
||||
process.waitFor()
|
||||
}
|
||||
|
||||
override fun isIOAddress(address: UInt): Boolean = address==0u || address==1u || address in 0x9f00u..0x9fffu
|
||||
|
||||
override fun initializeMemoryAreas(compilerOptions: CompilationOptions) {
|
||||
zeropage = CX16Zeropage(compilerOptions)
|
||||
golden = GoldenRam(compilerOptions, 0x0400u until 0x0800u)
|
||||
}
|
||||
|
||||
}
|
68
codeCore/src/prog8/code/target/cx16/CX16Zeropage.kt
Normal file
68
codeCore/src/prog8/code/target/cx16/CX16Zeropage.kt
Normal file
@ -0,0 +1,68 @@
|
||||
package prog8.code.target.cx16
|
||||
|
||||
import prog8.code.core.*
|
||||
|
||||
|
||||
class CX16Zeropage(options: CompilationOptions) : Zeropage(options) {
|
||||
|
||||
override val SCRATCH_B1 = 0x7au // temp storage for a single byte
|
||||
override val SCRATCH_REG = 0x7bu // temp storage for a register, must be B1+1
|
||||
override val SCRATCH_W1 = 0x7cu // temp storage 1 for a word $7c+$7d
|
||||
override val SCRATCH_W2 = 0x7eu // temp storage 2 for a word $7e+$7f
|
||||
|
||||
|
||||
init {
|
||||
if (options.floats && options.zeropage !in arrayOf(
|
||||
ZeropageType.FLOATSAFE,
|
||||
ZeropageType.BASICSAFE,
|
||||
ZeropageType.DONTUSE
|
||||
))
|
||||
throw InternalCompilerException("when floats are enabled, zero page type should be 'floatsafe' or 'basicsafe' or 'dontuse'")
|
||||
|
||||
// the addresses 0x02 to 0x21 (inclusive) are taken for sixteen virtual 16-bit api registers.
|
||||
|
||||
synchronized(this) {
|
||||
when (options.zeropage) {
|
||||
ZeropageType.FULL -> {
|
||||
free.addAll(0x22u..0xffu)
|
||||
}
|
||||
ZeropageType.KERNALSAFE -> {
|
||||
free.addAll(0x22u..0x7fu)
|
||||
free.addAll(0xa9u..0xffu)
|
||||
}
|
||||
ZeropageType.FLOATSAFE -> {
|
||||
free.addAll(0x22u..0x7fu)
|
||||
free.addAll(0xd4u..0xffu)
|
||||
}
|
||||
ZeropageType.BASICSAFE -> {
|
||||
free.addAll(0x22u..0x7fu)
|
||||
}
|
||||
ZeropageType.DONTUSE -> {
|
||||
free.clear() // don't use zeropage at all
|
||||
}
|
||||
}
|
||||
|
||||
val distinctFree = free.distinct()
|
||||
free.clear()
|
||||
free.addAll(distinctFree)
|
||||
|
||||
removeReservedFromFreePool()
|
||||
allocateCx16VirtualRegisters()
|
||||
retainAllowed()
|
||||
}
|
||||
}
|
||||
|
||||
override fun allocateCx16VirtualRegisters() {
|
||||
// Note: the 16 virtual registers R0-R15 are not regular allocated variables, they're *memory mapped* elsewhere to fixed addresses.
|
||||
// However, to be able for the compiler to "see" them as zeropage variables, we have to register them here as well.
|
||||
// This is important because the compiler sometimes treats ZP variables more efficiently (for example if it's a pointer)
|
||||
for(reg in 0..15) {
|
||||
allocatedVariables["cx16.r${reg}"] = VarAllocation((2+reg*2).toUInt(), DataType.forDt(BaseDataType.UWORD), 2) // cx16.r0 .. cx16.r15
|
||||
allocatedVariables["cx16.r${reg}s"] = VarAllocation((2+reg*2).toUInt(), DataType.forDt(BaseDataType.WORD), 2) // cx16.r0s .. cx16.r15s
|
||||
allocatedVariables["cx16.r${reg}L"] = VarAllocation((2+reg*2).toUInt(), DataType.forDt(BaseDataType.UBYTE), 1) // cx16.r0L .. cx16.r15L
|
||||
allocatedVariables["cx16.r${reg}H"] = VarAllocation((3+reg*2).toUInt(), DataType.forDt(BaseDataType.UBYTE), 1) // cx16.r0H .. cx16.r15H
|
||||
allocatedVariables["cx16.r${reg}sL"] = VarAllocation((2+reg*2).toUInt(), DataType.forDt(BaseDataType.BYTE), 1) // cx16.r0sL .. cx16.r15sL
|
||||
allocatedVariables["cx16.r${reg}sH"] = VarAllocation((3+reg*2).toUInt(), DataType.forDt(BaseDataType.BYTE), 1) // cx16.r0sH .. cx16.r15sH
|
||||
}
|
||||
}
|
||||
}
|
214
codeCore/src/prog8/code/target/encodings/AtasciiEncoding.kt
Normal file
214
codeCore/src/prog8/code/target/encodings/AtasciiEncoding.kt
Normal file
@ -0,0 +1,214 @@
|
||||
package prog8.code.target.encodings
|
||||
|
||||
import com.github.michaelbull.result.Ok
|
||||
import com.github.michaelbull.result.Result
|
||||
import java.io.CharConversionException
|
||||
|
||||
object AtasciiEncoding {
|
||||
|
||||
private val decodeTable: CharArray = charArrayOf(
|
||||
// $00
|
||||
'♥',
|
||||
'├',
|
||||
'\uf130', // 🮇 0x02 -> RIGHT ONE QUARTER BLOCK (CUS)
|
||||
'┘',
|
||||
'┤',
|
||||
'┐',
|
||||
'╱',
|
||||
'╲',
|
||||
'◢',
|
||||
'▗',
|
||||
'◣',
|
||||
'▝',
|
||||
'▘',
|
||||
'\uf132', // 🮂 0x1d -> UPPER ONE QUARTER BLOCK (CUS)
|
||||
'▂',
|
||||
'▖',
|
||||
|
||||
// $10
|
||||
'♣',
|
||||
'┌',
|
||||
'─',
|
||||
'┼',
|
||||
'•',
|
||||
'▄',
|
||||
'▎',
|
||||
'┬',
|
||||
'┴',
|
||||
'▌',
|
||||
'└',
|
||||
'\u001b', // $1b = escape
|
||||
'\ufffe', // UNDEFINED CHAR. $1c = cursor up
|
||||
'\ufffe', // UNDEFINED CHAR. $1d = cursor down
|
||||
'\ufffe', // UNDEFINED CHAR. $1e = cursor left
|
||||
'\ufffe', // UNDEFINED CHAR. $1f = cursor right
|
||||
|
||||
// $20
|
||||
' ',
|
||||
'!',
|
||||
'"',
|
||||
'#',
|
||||
'$',
|
||||
'%',
|
||||
'&',
|
||||
'\'',
|
||||
'(',
|
||||
')',
|
||||
'*',
|
||||
'+',
|
||||
',',
|
||||
'-',
|
||||
'.',
|
||||
'/',
|
||||
|
||||
// $30
|
||||
'0',
|
||||
'1',
|
||||
'2',
|
||||
'3',
|
||||
'4',
|
||||
'5',
|
||||
'6',
|
||||
'7',
|
||||
'8',
|
||||
'9',
|
||||
':',
|
||||
';',
|
||||
'<',
|
||||
'=',
|
||||
'>',
|
||||
'?',
|
||||
|
||||
// $40
|
||||
'@',
|
||||
'A',
|
||||
'B',
|
||||
'C',
|
||||
'D',
|
||||
'E',
|
||||
'F',
|
||||
'G',
|
||||
'H',
|
||||
'I',
|
||||
'J',
|
||||
'K',
|
||||
'L',
|
||||
'M',
|
||||
'N',
|
||||
'O',
|
||||
|
||||
// $50
|
||||
'P',
|
||||
'Q',
|
||||
'R',
|
||||
'S',
|
||||
'T',
|
||||
'U',
|
||||
'V',
|
||||
'W',
|
||||
'X',
|
||||
'Y',
|
||||
'Z',
|
||||
'[',
|
||||
'\\',
|
||||
']',
|
||||
'^',
|
||||
'_',
|
||||
|
||||
// $60
|
||||
'♦',
|
||||
'a',
|
||||
'b',
|
||||
'c',
|
||||
'd',
|
||||
'e',
|
||||
'f',
|
||||
'g',
|
||||
'h',
|
||||
'i',
|
||||
'j',
|
||||
'k',
|
||||
'l',
|
||||
'm',
|
||||
'n',
|
||||
'o',
|
||||
|
||||
// $70
|
||||
'p',
|
||||
'q',
|
||||
'r',
|
||||
's',
|
||||
't',
|
||||
'u',
|
||||
'v',
|
||||
'w',
|
||||
'x',
|
||||
'y',
|
||||
'z',
|
||||
'♠',
|
||||
'|',
|
||||
'\u000c', // $7d -> FORM FEED (CLEAR SCREEN)
|
||||
'\u0008', // $7e -> BACKSPACE
|
||||
'\u0009', // $7f -> TAB
|
||||
|
||||
// $80-$ff are reversed video characters + various special characters.
|
||||
'\ufffe', '\ufffe', '\ufffe', '\ufffe', '\ufffe', '\ufffe', '\ufffe', '\ufffe',
|
||||
'\ufffe', '\ufffe', '\ufffe', '\ufffe', '\ufffe', '\ufffe', '\ufffe', '\ufffe',
|
||||
// $90
|
||||
'\ufffe', '\ufffe', '\ufffe', '\ufffe', '\ufffe', '\ufffe', '\ufffe', '\ufffe',
|
||||
'\ufffe',
|
||||
'\ufffe',
|
||||
'\ufffe',
|
||||
'\n', // $9b -> EOL/RETURN
|
||||
'\ufffe', // UNDEFINED $9c = DELETE LINE
|
||||
'\ufffe', // UNDEFINED $9d = INSERT LINE
|
||||
'\ufffe', // UNDEFINED $9e = CLEAR TAB STOP
|
||||
'\ufffe', // UNDEFINED $9f = SET TAB STOP
|
||||
// $a0
|
||||
'\ufffe', '\ufffe', '\ufffe', '\ufffe', '\ufffe', '\ufffe', '\ufffe', '\ufffe',
|
||||
'\ufffe', '\ufffe', '\ufffe', '\ufffe', '\ufffe', '\ufffe', '\ufffe', '\ufffe',
|
||||
// $b0
|
||||
'\ufffe', '\ufffe', '\ufffe', '\ufffe', '\ufffe', '\ufffe', '\ufffe', '\ufffe',
|
||||
'\ufffe', '\ufffe', '\ufffe', '\ufffe', '\ufffe', '\ufffe', '\ufffe', '\ufffe',
|
||||
// $c0
|
||||
'\ufffe', '\ufffe', '\ufffe', '\ufffe', '\ufffe', '\ufffe', '\ufffe', '\ufffe',
|
||||
'\ufffe', '\ufffe', '\ufffe', '\ufffe', '\ufffe', '\ufffe', '\ufffe', '\ufffe',
|
||||
// $d0
|
||||
'\ufffe', '\ufffe', '\ufffe', '\ufffe', '\ufffe', '\ufffe', '\ufffe', '\ufffe',
|
||||
'\ufffe', '\ufffe', '\ufffe', '\ufffe', '\ufffe', '\ufffe', '\ufffe', '\ufffe',
|
||||
// $e0
|
||||
'\ufffe', '\ufffe', '\ufffe', '\ufffe', '\ufffe', '\ufffe', '\ufffe', '\ufffe',
|
||||
'\ufffe', '\ufffe', '\ufffe', '\ufffe', '\ufffe', '\ufffe', '\ufffe', '\ufffe',
|
||||
// $f0
|
||||
'\ufffe', '\ufffe', '\ufffe', '\ufffe', '\ufffe', '\ufffe', '\ufffe', '\ufffe',
|
||||
'\ufffe',
|
||||
'\ufffe',
|
||||
'\ufffe',
|
||||
'\ufffe',
|
||||
'\ufffe',
|
||||
'\u0007', // $fd = bell/beep
|
||||
'\u007f', // $fe = DELETE
|
||||
'\ufffe' // UNDEFINED $ff = INSERT
|
||||
)
|
||||
|
||||
private val encodeTable = decodeTable.withIndex().associate{it.value to it.index}
|
||||
|
||||
|
||||
fun encode(str: String): Result<List<UByte>, CharConversionException> {
|
||||
val mapped = str.map { chr ->
|
||||
when (chr) {
|
||||
'\u0000' -> 0u
|
||||
in '\u8000'..'\u80ff' -> {
|
||||
// special case: take the lower 8 bit hex value directly
|
||||
(chr.code - 0x8000).toUByte()
|
||||
}
|
||||
else -> encodeTable.getValue(chr).toUByte()
|
||||
}
|
||||
}
|
||||
return Ok(mapped)
|
||||
}
|
||||
|
||||
fun decode(bytes: Iterable<UByte>): Result<String, CharConversionException> {
|
||||
return Ok(bytes.map { decodeTable[it.toInt()] }.joinToString(""))
|
||||
}
|
||||
}
|
69
codeCore/src/prog8/code/target/encodings/Cp437Encoding.kt
Normal file
69
codeCore/src/prog8/code/target/encodings/Cp437Encoding.kt
Normal file
@ -0,0 +1,69 @@
|
||||
package prog8.code.target.encodings
|
||||
|
||||
import com.github.michaelbull.result.Err
|
||||
import com.github.michaelbull.result.Ok
|
||||
import com.github.michaelbull.result.Result
|
||||
import java.io.CharConversionException
|
||||
import java.nio.charset.Charset
|
||||
|
||||
object Cp437Encoding {
|
||||
val charset: Charset = Charset.forName("IBM437")
|
||||
|
||||
fun encode(str: String): Result<List<UByte>, CharConversionException> {
|
||||
return try {
|
||||
val mapped = str.map { chr ->
|
||||
when (chr) {
|
||||
'\u0000' -> 0u
|
||||
'\u00a0' -> 255u
|
||||
'☺' -> 1u
|
||||
'☻' -> 2u
|
||||
'♥' -> 3u
|
||||
'♦' -> 4u
|
||||
'♣' -> 5u
|
||||
'♠' -> 6u
|
||||
'•' -> 7u
|
||||
'◘' -> 8u
|
||||
'○' -> 9u
|
||||
'◙' -> 10u
|
||||
'♂' -> 11u
|
||||
'♀' -> 12u
|
||||
'♪' -> 13u
|
||||
'♫' -> 14u
|
||||
'☼' -> 15u
|
||||
'►' -> 16u
|
||||
'◄' -> 17u
|
||||
'↕' -> 18u
|
||||
'‼' -> 19u
|
||||
'¶' -> 20u
|
||||
'§' -> 21u
|
||||
'▬' -> 22u
|
||||
'↨' -> 23u
|
||||
'↑' -> 24u
|
||||
'↓' -> 25u
|
||||
'→' -> 26u
|
||||
'←' -> 27u
|
||||
'∟' -> 28u
|
||||
'↔' -> 29u
|
||||
'▲' -> 30u
|
||||
'▼' -> 31u
|
||||
in '\u8000'..'\u80ff' -> {
|
||||
// special case: take the lower 8 bit hex value directly
|
||||
(chr.code - 0x8000).toUByte()
|
||||
}
|
||||
else -> charset.encode(chr.toString())[0].toUByte()
|
||||
}
|
||||
}
|
||||
Ok(mapped)
|
||||
} catch (ce: CharConversionException) {
|
||||
Err(ce)
|
||||
}
|
||||
}
|
||||
|
||||
fun decode(bytes: Iterable<UByte>): Result<String, CharConversionException> {
|
||||
return try {
|
||||
Ok(String(bytes.map { it.toByte() }.toByteArray(), charset))
|
||||
} catch (ce: CharConversionException) {
|
||||
Err(ce)
|
||||
}
|
||||
}
|
||||
}
|
42
codeCore/src/prog8/code/target/encodings/IsoEncoding.kt
Normal file
42
codeCore/src/prog8/code/target/encodings/IsoEncoding.kt
Normal file
@ -0,0 +1,42 @@
|
||||
package prog8.code.target.encodings
|
||||
|
||||
import com.github.michaelbull.result.Err
|
||||
import com.github.michaelbull.result.Ok
|
||||
import com.github.michaelbull.result.Result
|
||||
import java.io.CharConversionException
|
||||
import java.nio.charset.Charset
|
||||
|
||||
open class IsoEncodingBase(charsetName: String) {
|
||||
val charset: Charset = Charset.forName(charsetName)
|
||||
|
||||
fun encode(str: String): Result<List<UByte>, CharConversionException> {
|
||||
return try {
|
||||
val mapped = str.map { chr ->
|
||||
when (chr) {
|
||||
'\u0000' -> 0u
|
||||
in '\u8000'..'\u80ff' -> {
|
||||
// special case: take the lower 8 bit hex value directly
|
||||
(chr.code - 0x8000).toUByte()
|
||||
}
|
||||
else -> charset.encode(chr.toString())[0].toUByte()
|
||||
}
|
||||
}
|
||||
Ok(mapped)
|
||||
} catch (ce: CharConversionException) {
|
||||
Err(ce)
|
||||
}
|
||||
}
|
||||
|
||||
fun decode(bytes: Iterable<UByte>): Result<String, CharConversionException> {
|
||||
return try {
|
||||
Ok(String(bytes.map { it.toByte() }.toByteArray(), charset))
|
||||
} catch (ce: CharConversionException) {
|
||||
Err(ce)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
object IsoEncoding: IsoEncodingBase("ISO-8859-15")
|
||||
object IsoCyrillicEncoding: IsoEncodingBase("ISO-8859-5")
|
||||
object IsoEasternEncoding: IsoEncodingBase("ISO-8859-16")
|
122
codeCore/src/prog8/code/target/encodings/KatakanaEncoding.kt
Normal file
122
codeCore/src/prog8/code/target/encodings/KatakanaEncoding.kt
Normal file
@ -0,0 +1,122 @@
|
||||
package prog8.code.target.encodings
|
||||
|
||||
import com.github.michaelbull.result.Err
|
||||
import com.github.michaelbull.result.Ok
|
||||
import com.github.michaelbull.result.Result
|
||||
import java.io.CharConversionException
|
||||
import java.nio.charset.Charset
|
||||
|
||||
|
||||
object JapaneseCharacterConverter {
|
||||
// adapted from https://github.com/raminduw/Japanese-Character-Converter
|
||||
|
||||
private val ZENKAKU_KATAKANA = charArrayOf(
|
||||
'ァ', 'ア', 'ィ', 'イ', 'ゥ',
|
||||
'ウ', 'ェ', 'エ', 'ォ', 'オ', 'カ', 'ガ', 'キ', 'ギ', 'ク', 'グ', 'ケ', 'ゲ',
|
||||
'コ', 'ゴ', 'サ', 'ザ', 'シ', 'ジ', 'ス', 'ズ', 'セ', 'ゼ', 'ソ', 'ゾ', 'タ',
|
||||
'ダ', 'チ', 'ヂ', 'ッ', 'ツ', 'ヅ', 'テ', 'デ', 'ト', 'ド', 'ナ', 'ニ', 'ヌ',
|
||||
'ネ', 'ノ', 'ハ', 'バ', 'パ', 'ヒ', 'ビ', 'ピ', 'フ', 'ブ', 'プ', 'ヘ', 'ベ',
|
||||
'ペ', 'ホ', 'ボ', 'ポ', 'マ', 'ミ', 'ム', 'メ', 'モ', 'ャ', 'ヤ', 'ュ', 'ユ',
|
||||
'ョ', 'ヨ', 'ラ', 'リ', 'ル', 'レ', 'ロ', 'ヮ', 'ワ', 'ヰ', 'ヱ', 'ヲ', 'ン',
|
||||
'ヴ', 'ヵ', 'ヶ'
|
||||
)
|
||||
|
||||
private val HANKAKU_HIRAGANA = charArrayOf(
|
||||
'ぁ', 'あ', 'ぃ', 'い', 'ぅ', 'う', 'ぇ', 'え',
|
||||
'ぉ', 'お', 'か', 'が', 'き', 'ぎ', 'く', 'ぐ',
|
||||
'け', 'げ', 'こ', 'ご', 'さ', 'ざ', 'し', 'じ',
|
||||
'す', 'ず', 'せ', 'ぜ', 'そ', 'ぞ', 'た', 'だ',
|
||||
'ち', 'ぢ', 'っ', 'つ', 'づ', 'て', 'で', 'と',
|
||||
'ど', 'な', 'に', 'ぬ', 'ね', 'の', 'は', 'ば',
|
||||
'ぱ', 'ひ', 'び', 'ぴ', 'ふ', 'ぶ', 'ぷ', 'へ',
|
||||
'べ', 'ぺ', 'ほ', 'ぼ', 'ぽ', 'ま', 'み', 'む',
|
||||
'め', 'も', 'ゃ', 'や', 'ゅ', 'ゆ', 'ょ', 'よ',
|
||||
'ら', 'り', 'る', 'れ', 'ろ', 'ゎ', 'わ', 'ゐ',
|
||||
'ゑ', 'を', 'ん', 'ゔ', 'ゕ', 'ゖ'
|
||||
)
|
||||
|
||||
private val HANKAKU_KATAKANA = arrayOf(
|
||||
"ァ", "ア", "ィ", "イ", "ゥ",
|
||||
"ウ", "ェ", "エ", "ォ", "オ", "カ", "ガ", "キ", "ギ", "ク", "グ", "ケ",
|
||||
"ゲ", "コ", "ゴ", "サ", "ザ", "シ", "ジ", "ス", "ズ", "セ", "ゼ", "ソ",
|
||||
"ゾ", "タ", "ダ", "チ", "ヂ", "ッ", "ツ", "ヅ", "テ", "デ", "ト", "ド",
|
||||
"ナ", "ニ", "ヌ", "ネ", "ノ", "ハ", "バ", "パ", "ヒ", "ビ", "ピ", "フ",
|
||||
"ブ", "プ", "ヘ", "ベ", "ペ", "ホ", "ボ", "ポ", "マ", "ミ", "ム", "メ",
|
||||
"モ", "ャ", "ヤ", "ュ", "ユ", "ョ", "ヨ", "ラ", "リ", "ル", "レ", "ロ", "ワ",
|
||||
"ワ", "イ", "エ", "ヲ", "ン", "ヴ", "カ", "ケ"
|
||||
)
|
||||
|
||||
private val ZENKAKU_KATAKANA_FIRST_CHAR_CODE = ZENKAKU_KATAKANA.first().code
|
||||
private val HANKAKU_HIRAGANA_FIRST_CHAR_CODE = HANKAKU_HIRAGANA.first().code
|
||||
|
||||
private fun zenkakuKatakanaToHankakuKatakana(c: Char): String = if (c in ZENKAKU_KATAKANA) HANKAKU_KATAKANA[c.code - ZENKAKU_KATAKANA_FIRST_CHAR_CODE] else c.toString()
|
||||
private fun hankakuKatakanaToZenkakuKatakana(c: Char): Char = if (c in HANKAKU_HIRAGANA) ZENKAKU_KATAKANA[c.code - HANKAKU_HIRAGANA_FIRST_CHAR_CODE] else c
|
||||
|
||||
fun zenkakuKatakanaToHankakuKatakana(s: String): String = buildString {
|
||||
for (element in s) {
|
||||
val converted = hankakuKatakanaToZenkakuKatakana(element)
|
||||
val convertedChar = zenkakuKatakanaToHankakuKatakana(converted)
|
||||
append(convertedChar)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
object KatakanaEncoding {
|
||||
val charset: Charset = Charset.forName("JIS_X0201")
|
||||
|
||||
fun encode(str: String): Result<List<UByte>, CharConversionException> {
|
||||
return try {
|
||||
val mapped = str.map { chr ->
|
||||
when (chr) {
|
||||
|
||||
'\u0000' -> 0u
|
||||
'\u00a0' -> 0xa0u // $a0 isn't technically a part of JIS X 0201 spec, and so we need to handle this ourselves
|
||||
|
||||
'♥' -> 0xe3u
|
||||
'♦' -> 0xe4u
|
||||
'♣' -> 0xe5u
|
||||
'♠' -> 0xe6u
|
||||
|
||||
'大' -> 0xeau
|
||||
'中' -> 0xebu
|
||||
'小' -> 0xecu
|
||||
'百' -> 0xedu
|
||||
'千' -> 0xeeu
|
||||
'万' -> 0xefu
|
||||
'♪' -> 0xf0u
|
||||
'土' -> 0xf1u
|
||||
'金' -> 0xf2u
|
||||
'木' -> 0xf3u
|
||||
'水' -> 0xf4u
|
||||
'火' -> 0xf5u
|
||||
'月' -> 0xf6u
|
||||
'日' -> 0xf7u
|
||||
'時' -> 0xf8u
|
||||
'分' -> 0xf9u
|
||||
'秒' -> 0xfau
|
||||
'年' -> 0xfbu
|
||||
'円' -> 0xfcu
|
||||
'人' -> 0xfdu
|
||||
'生' -> 0xfeu
|
||||
'〒' -> 0xffu
|
||||
in '\u8000'..'\u80ff' -> {
|
||||
// special case: take the lower 8 bit hex value directly
|
||||
(chr.code - 0x8000).toUByte()
|
||||
}
|
||||
else -> charset.encode(chr.toString())[0].toUByte()
|
||||
}
|
||||
}
|
||||
Ok(mapped)
|
||||
} catch (ce: CharConversionException) {
|
||||
Err(ce)
|
||||
}
|
||||
}
|
||||
|
||||
fun decode(bytes: Iterable<UByte>): Result<String, CharConversionException> {
|
||||
return try {
|
||||
Ok(String(bytes.map { it.toByte() }.toByteArray(), charset))
|
||||
} catch (ce: CharConversionException) {
|
||||
Err(ce)
|
||||
}
|
||||
}
|
||||
}
|
1193
codeCore/src/prog8/code/target/encodings/PetsciiEncoding.kt
Normal file
1193
codeCore/src/prog8/code/target/encodings/PetsciiEncoding.kt
Normal file
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user