mirror of
https://github.com/vlang/v.git
synced 2023-08-10 21:13:21 +03:00
Compare commits
814 Commits
weekly.202
...
weekly.202
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ed2d1286da | ||
|
|
460f7c6637 | ||
|
|
9f7d71d338 | ||
|
|
68ada041e6 | ||
|
|
5f0160bf11 | ||
|
|
f81654e3a7 | ||
|
|
7c85c2ab1f | ||
|
|
d07975335d | ||
|
|
840a92c14e | ||
|
|
cd0b581445 | ||
|
|
c957f59071 | ||
|
|
41176c4967 | ||
|
|
a7019ac86c | ||
|
|
2ab861ef89 | ||
|
|
5e5c78ed37 | ||
|
|
de92f819f0 | ||
|
|
3a504480d9 | ||
|
|
80995f3a2d | ||
|
|
927eecf7c0 | ||
|
|
7c255f0ff2 | ||
|
|
50d988ebc7 | ||
|
|
75830f1fe3 | ||
|
|
08766da7e8 | ||
|
|
4ecdb28f5a | ||
|
|
130d189fce | ||
|
|
b482da74e9 | ||
|
|
66070ec63e | ||
|
|
c9f6a96936 | ||
|
|
d80dd77adf | ||
|
|
e5e3979e45 | ||
|
|
2f7ac7e407 | ||
|
|
f87f8ec3f7 | ||
|
|
5f1eaaf3b1 | ||
|
|
c6b902d2b7 | ||
|
|
8a34fb7857 | ||
|
|
6ff953d936 | ||
|
|
caac89d6ca | ||
|
|
674f99a658 | ||
|
|
d8a333058d | ||
|
|
1261468d8e | ||
|
|
d90ef1f29f | ||
|
|
c44115c67d | ||
|
|
2b981b011e | ||
|
|
65f12f3217 | ||
|
|
11d2b8b354 | ||
|
|
df7f2aa8a3 | ||
|
|
1a6899e85e | ||
|
|
2ce1647ea0 | ||
|
|
fa1a7a85f0 | ||
|
|
1d41d9daf9 | ||
|
|
5b5d0bbb9c | ||
|
|
d13fe7843c | ||
|
|
1c629f4a93 | ||
|
|
6079448f35 | ||
|
|
c900dc1053 | ||
|
|
96e9cc62b0 | ||
|
|
70564ae8b2 | ||
|
|
73e097c1cb | ||
|
|
a1efde8b10 | ||
|
|
d7abdd314d | ||
|
|
eeb7d4a7fd | ||
|
|
99f14a7ead | ||
|
|
5365984ef5 | ||
|
|
2f99022f0f | ||
|
|
eed882950c | ||
|
|
731015cd9b | ||
|
|
b4b2a21453 | ||
|
|
2a5356670b | ||
|
|
76f6f99bce | ||
|
|
b1a9bf29db | ||
|
|
cb4c67588c | ||
|
|
d5c0bdf954 | ||
|
|
be5823069a | ||
|
|
b303588491 | ||
|
|
3afbb9e90a | ||
|
|
57c1faadbe | ||
|
|
f407d6de02 | ||
|
|
ab6e93394f | ||
|
|
8c1c70db04 | ||
|
|
bf835d47d8 | ||
|
|
79de408ef0 | ||
|
|
9b7a50b1a2 | ||
|
|
adf353702e | ||
|
|
23be53e2de | ||
|
|
d3b769d1bc | ||
|
|
f0969698e2 | ||
|
|
2ced182816 | ||
|
|
0d0d7323bb | ||
|
|
fe14e2fceb | ||
|
|
9e68a03f94 | ||
|
|
24bc2ae406 | ||
|
|
cde0cbd5ad | ||
|
|
b3287f8159 | ||
|
|
b18cd37e59 | ||
|
|
ba06eba39c | ||
|
|
9bf777c1ee | ||
|
|
7c7cdf8ce7 | ||
|
|
a58c539ee6 | ||
|
|
19a47abcca | ||
|
|
ee6c0a0691 | ||
|
|
ea1f398f90 | ||
|
|
feb12b62dc | ||
|
|
ade2a4cd01 | ||
|
|
eaf0f9b4c1 | ||
|
|
ed4ecae57d | ||
|
|
9b4329d2f6 | ||
|
|
b116170735 | ||
|
|
7fc9e614a3 | ||
|
|
dbe67c688f | ||
|
|
4c95127cbc | ||
|
|
8f9f681e81 | ||
|
|
0021fbbaa9 | ||
|
|
85f3372a32 | ||
|
|
7379488cee | ||
|
|
d88e67a5ec | ||
|
|
cd96f980cc | ||
|
|
b1622c74b9 | ||
|
|
e433badcb8 | ||
|
|
2fbf7fea75 | ||
|
|
525791fa3a | ||
|
|
7a0b63e795 | ||
|
|
a19dd36473 | ||
|
|
fd4e071621 | ||
|
|
7bbc70820a | ||
|
|
c29a3cf6e8 | ||
|
|
f60cf65284 | ||
|
|
1cb06a2de4 | ||
|
|
c23ebec944 | ||
|
|
f86af7237f | ||
|
|
6d14275106 | ||
|
|
36fbd3c4fa | ||
|
|
ef16a8ec54 | ||
|
|
047f059fb8 | ||
|
|
1cd703d96b | ||
|
|
325e116b7a | ||
|
|
09955b7ce8 | ||
|
|
d85111e3dd | ||
|
|
3ab82a23c5 | ||
|
|
89eb5425cd | ||
|
|
6f5d952d8f | ||
|
|
3b7e7c9c46 | ||
|
|
7d1dec5b44 | ||
|
|
ae2ae6e6fd | ||
|
|
0c713f6edc | ||
|
|
105d7fcf75 | ||
|
|
e4850a007c | ||
|
|
229d2fb667 | ||
|
|
2754368873 | ||
|
|
4b21d3e364 | ||
|
|
81a1490e31 | ||
|
|
ace63594bf | ||
|
|
0f50ac3260 | ||
|
|
0cb4557a8d | ||
|
|
d59aa14b26 | ||
|
|
89c08c6292 | ||
|
|
2d43fdb42a | ||
|
|
7e6d4ebfe1 | ||
|
|
33163238e7 | ||
|
|
365b46cad3 | ||
|
|
4624de6cb5 | ||
|
|
1d6cc57d9c | ||
|
|
0da7e2f8ab | ||
|
|
be5446bfa4 | ||
|
|
209747d03e | ||
|
|
eca78a2906 | ||
|
|
c4363bc78b | ||
|
|
66a67de8c0 | ||
|
|
7d0a36dd08 | ||
|
|
adddac4807 | ||
|
|
63b0798771 | ||
|
|
5ab91dd471 | ||
|
|
ebfacca252 | ||
|
|
799d7b843c | ||
|
|
9cf7af0c75 | ||
|
|
f7926ec9a4 | ||
|
|
2144471ce1 | ||
|
|
988779846f | ||
|
|
8494e387ec | ||
|
|
d7bc2a88f7 | ||
|
|
b3aedff3f8 | ||
|
|
6f297cdfaa | ||
|
|
f5d283721e | ||
|
|
79cb303a6c | ||
|
|
47aa2b1f93 | ||
|
|
519ca90cfa | ||
|
|
f86710dcc7 | ||
|
|
6f193c4300 | ||
|
|
547f326f33 | ||
|
|
5e1cd13e39 | ||
|
|
758ba76d2b | ||
|
|
5c8e626912 | ||
|
|
d1b0ce9e0c | ||
|
|
7d9028db56 | ||
|
|
f50f409ad7 | ||
|
|
1b691e7612 | ||
|
|
05db3533d3 | ||
|
|
8ac7739db8 | ||
|
|
6749979534 | ||
|
|
bbc47562b3 | ||
|
|
14424100e8 | ||
|
|
83260e5074 | ||
|
|
0f59d88ba6 | ||
|
|
ddec89f9ee | ||
|
|
9825c7e06c | ||
|
|
65e9503556 | ||
|
|
c14c324125 | ||
|
|
6d97b0a407 | ||
|
|
fe37da31a8 | ||
|
|
6d6a23a1c9 | ||
|
|
87029e5707 | ||
|
|
31fe02de8c | ||
|
|
b4c52b72cf | ||
|
|
9c88317ca6 | ||
|
|
5786dd84e6 | ||
|
|
1913de0187 | ||
|
|
5deb56fc79 | ||
|
|
969e0dce20 | ||
|
|
dc610a9a80 | ||
|
|
0fc47b50a2 | ||
|
|
783aba4552 | ||
|
|
f72d001db5 | ||
|
|
1d8ece7ac0 | ||
|
|
22043f2df1 | ||
|
|
d52b62a4f4 | ||
|
|
8315e82188 | ||
|
|
deaeffc4db | ||
|
|
12585e88e1 | ||
|
|
4383cf7de5 | ||
|
|
89bab98833 | ||
|
|
04b030b7ab | ||
|
|
253e38d9d7 | ||
|
|
6299a73e90 | ||
|
|
85633fe546 | ||
|
|
cf274f262c | ||
|
|
a59eabc4ab | ||
|
|
f584e70cf2 | ||
|
|
ac3910b8c2 | ||
|
|
9a2c563735 | ||
|
|
fb3a793a27 | ||
|
|
11d70624af | ||
|
|
f825306cff | ||
|
|
b0bc112168 | ||
|
|
ff95cf18d4 | ||
|
|
6f46fc2170 | ||
|
|
cbf4a5b58c | ||
|
|
43a1d2cfea | ||
|
|
70ff00efbb | ||
|
|
ff911986e7 | ||
|
|
8e0de2036d | ||
|
|
e42db5bee2 | ||
|
|
87f7a6d99f | ||
|
|
1be6aed16e | ||
|
|
0779b5fd8e | ||
|
|
49cd1b3d59 | ||
|
|
12ffe04212 | ||
|
|
e9efed02f0 | ||
|
|
3f0e532660 | ||
|
|
13a2d547b4 | ||
|
|
93bdff5589 | ||
|
|
fbe2b5cb58 | ||
|
|
bf7074cad4 | ||
|
|
83fee01f6e | ||
|
|
d431145a39 | ||
|
|
bd9564e38b | ||
|
|
42b97ef888 | ||
|
|
278be77c11 | ||
|
|
f37eb6a932 | ||
|
|
6914763493 | ||
|
|
1bbbba5813 | ||
|
|
759f3d28b7 | ||
|
|
5e8288528a | ||
|
|
6a252ed015 | ||
|
|
7a0dc60d04 | ||
|
|
5e1782bf9c | ||
|
|
c3b8e5e181 | ||
|
|
84aa05f8fb | ||
|
|
fe48380e85 | ||
|
|
e77a11001e | ||
|
|
c7bd74e0f8 | ||
|
|
1aaac13a60 | ||
|
|
117c99d938 | ||
|
|
480f3876ee | ||
|
|
243e66a106 | ||
|
|
258d0d6df7 | ||
|
|
f1dd0e3355 | ||
|
|
4b9e8e243c | ||
|
|
82010e729d | ||
|
|
90ba856107 | ||
|
|
24ffc1ffb2 | ||
|
|
1bbc73384c | ||
|
|
a894a6cf36 | ||
|
|
eec8788333 | ||
|
|
2794aa623a | ||
|
|
b576181a66 | ||
|
|
e275220f05 | ||
|
|
762a7fde2a | ||
|
|
c2eb909c9b | ||
|
|
80a4ff9900 | ||
|
|
fa995ca537 | ||
|
|
9eac656e55 | ||
|
|
76cf11e6b5 | ||
|
|
b367ed9ba3 | ||
|
|
d498c365c2 | ||
|
|
24ba660367 | ||
|
|
96554fad71 | ||
|
|
3caeadfa0d | ||
|
|
7fba3e65e9 | ||
|
|
24ea15c8f0 | ||
|
|
0ec02e3247 | ||
|
|
7ec70d5477 | ||
|
|
5bf28c5287 | ||
|
|
1edb3e559e | ||
|
|
409321327b | ||
|
|
b5e410e408 | ||
|
|
ae54cd78f5 | ||
|
|
26fbf1885d | ||
|
|
3b612899bf | ||
|
|
81455acd29 | ||
|
|
2f5fae06ee | ||
|
|
2733319879 | ||
|
|
dbf469e000 | ||
|
|
7cdc906683 | ||
|
|
3e1fb22a04 | ||
|
|
1370516f53 | ||
|
|
2eb02ff5a7 | ||
|
|
6ac109a7c3 | ||
|
|
bd9ac598f7 | ||
|
|
5a89c0a480 | ||
|
|
927df948ae | ||
|
|
11ce26b3f6 | ||
|
|
49a36515dc | ||
|
|
2984751a57 | ||
|
|
3fab0a5d05 | ||
|
|
045579fd8a | ||
|
|
f0f5f97e9f | ||
|
|
3f37ab2ef2 | ||
|
|
bede0587ad | ||
|
|
9565adf597 | ||
|
|
2f75ce0d4c | ||
|
|
7b9cca7524 | ||
|
|
c28041cecc | ||
|
|
1d003228cb | ||
|
|
cbdb270d2f | ||
|
|
78662c800c | ||
|
|
a8a1e9381f | ||
|
|
1d2b16dde2 | ||
|
|
7b723262e4 | ||
|
|
5e75c89b71 | ||
|
|
d8479f107f | ||
|
|
e3d98b1b28 | ||
|
|
460f4523aa | ||
|
|
fb997eb5fe | ||
|
|
61b99e1915 | ||
|
|
9c508237bd | ||
|
|
6c32c544e1 | ||
|
|
3bb1c3f930 | ||
|
|
50a608aab3 | ||
|
|
c6b8b0bb0a | ||
|
|
1c17ba82ac | ||
|
|
fcecf527ec | ||
|
|
20d63de136 | ||
|
|
4b42dcad8e | ||
|
|
6c5dfc5c2f | ||
|
|
4728b975e3 | ||
|
|
9cb378bb6b | ||
|
|
c8cb1bf6b4 | ||
|
|
35f00c9f91 | ||
|
|
6f55439930 | ||
|
|
a4c57ba56e | ||
|
|
015cfdb49f | ||
|
|
dbd5acd5ba | ||
|
|
69fa87ad24 | ||
|
|
823a3ab838 | ||
|
|
72a7d5a559 | ||
|
|
8a971c3bf7 | ||
|
|
637ebe5d42 | ||
|
|
3c6356ba36 | ||
|
|
466ced2876 | ||
|
|
66e53279c2 | ||
|
|
d5e767f389 | ||
|
|
194b3647e2 | ||
|
|
6c244d3065 | ||
|
|
8f4180ea09 | ||
|
|
3f841edec1 | ||
|
|
08667c5645 | ||
|
|
15242d8082 | ||
|
|
758c18a906 | ||
|
|
1211029926 | ||
|
|
c8ff9e39b5 | ||
|
|
bc98da9111 | ||
|
|
9ec1262734 | ||
|
|
1c12186701 | ||
|
|
80242c8041 | ||
|
|
d8f971ffb5 | ||
|
|
852d85b3a9 | ||
|
|
32b74dd348 | ||
|
|
8be64ef80e | ||
|
|
5f3dcde358 | ||
|
|
7a9ba9f41f | ||
|
|
d2d67e9f4d | ||
|
|
9b00564d98 | ||
|
|
24cd619ff8 | ||
|
|
db65b65f3c | ||
|
|
c3b389cde9 | ||
|
|
b963aff8e8 | ||
|
|
7ea57bfa1e | ||
|
|
ace9444108 | ||
|
|
1999fb9a95 | ||
|
|
fc7f4c5b1f | ||
|
|
59e21c2068 | ||
|
|
73e25ccb3c | ||
|
|
a27833ed0d | ||
|
|
1a54817c81 | ||
|
|
2b4154910c | ||
|
|
c4e282a0c8 | ||
|
|
4bafc5042b | ||
|
|
45c938bdec | ||
|
|
bd5e2db460 | ||
|
|
99fd84dfe4 | ||
|
|
3fdbfca202 | ||
|
|
639cbfa0d1 | ||
|
|
0952af606c | ||
|
|
4ed6fb0e9b | ||
|
|
1d1793ec34 | ||
|
|
9aba00cd08 | ||
|
|
dcf230ca24 | ||
|
|
0ab133a563 | ||
|
|
da65680acf | ||
|
|
51f5841b6e | ||
|
|
28cada3fd5 | ||
|
|
6937074e7a | ||
|
|
ce9f26c589 | ||
|
|
81b95ece51 | ||
|
|
579d5ae649 | ||
|
|
612e742c1f | ||
|
|
a7d4236337 | ||
|
|
7e0f2fcda9 | ||
|
|
1785b184b9 | ||
|
|
d1acca3e52 | ||
|
|
d5642b6134 | ||
|
|
71392111f8 | ||
|
|
4c67c01e72 | ||
|
|
3d800b12e8 | ||
|
|
b86c79329b | ||
|
|
f801ef5e17 | ||
|
|
a32dae335a | ||
|
|
d33f7d12f7 | ||
|
|
5e4594a121 | ||
|
|
fa02418a55 | ||
|
|
0e95e4d7b4 | ||
|
|
475a2f9b43 | ||
|
|
4d0f6767b1 | ||
|
|
2c3e44eb20 | ||
|
|
a987440e2f | ||
|
|
99e71d0868 | ||
|
|
5ecaa160a7 | ||
|
|
8014235e0e | ||
|
|
b1bb1d361a | ||
|
|
1b6cccaf6d | ||
|
|
8cd01e0eac | ||
|
|
8fd66994c7 | ||
|
|
cfecb62299 | ||
|
|
0ff23eeb74 | ||
|
|
f79bc8619a | ||
|
|
bc3827ae15 | ||
|
|
43fbc68f1e | ||
|
|
159a9c3070 | ||
|
|
462d097bf5 | ||
|
|
943a807d30 | ||
|
|
e5c759eb91 | ||
|
|
d53bb54c0a | ||
|
|
ea6d2d53db | ||
|
|
6eaacd3391 | ||
|
|
d7fd4a563b | ||
|
|
1b9eef74aa | ||
|
|
c526752419 | ||
|
|
9a3967bd7d | ||
|
|
52df19ef61 | ||
|
|
f14dabc6bd | ||
|
|
f62b2dcfa7 | ||
|
|
508f29c101 | ||
|
|
655b5c563a | ||
|
|
06796a6119 | ||
|
|
5b325b99e8 | ||
|
|
ac99007cab | ||
|
|
77a1e3dedb | ||
|
|
18da724a9f | ||
|
|
cc2847f6ff | ||
|
|
45c1c1ab41 | ||
|
|
49ebba535e | ||
|
|
bb71089b70 | ||
|
|
e99b699ac6 | ||
|
|
f34daf9ff4 | ||
|
|
e34046a0e1 | ||
|
|
d1c4b470bc | ||
|
|
d9c6c9a7df | ||
|
|
2eae4cf63e | ||
|
|
c340906280 | ||
|
|
242b99340d | ||
|
|
47a2301139 | ||
|
|
e45cd02029 | ||
|
|
008d15dcb5 | ||
|
|
aa22751d26 | ||
|
|
864d6eae6b | ||
|
|
8a4756819a | ||
|
|
506924b01c | ||
|
|
8273c0582b | ||
|
|
eb364f0301 | ||
|
|
eed94c727c | ||
|
|
0401b5ece0 | ||
|
|
76ff708cf8 | ||
|
|
0d7057dd44 | ||
|
|
cc2ef4188d | ||
|
|
47313cbf27 | ||
|
|
5b69593766 | ||
|
|
da7dad07a3 | ||
|
|
909ed76b8f | ||
|
|
a85707246f | ||
|
|
1ba839dc3b | ||
|
|
a84b1a53ec | ||
|
|
5607224be6 | ||
|
|
ff02c19827 | ||
|
|
57c79770b3 | ||
|
|
7c1fff3495 | ||
|
|
3e52d54586 | ||
|
|
ef0eaeee08 | ||
|
|
a8ced46564 | ||
|
|
ab350d52ec | ||
|
|
d8ea9e4969 | ||
|
|
45534b512b | ||
|
|
f2cda1a529 | ||
|
|
6aca360507 | ||
|
|
c1aa782a6c | ||
|
|
39c3817ce4 | ||
|
|
a84a6d1fb1 | ||
|
|
108644d260 | ||
|
|
e9aa18fcc8 | ||
|
|
3af53e29c9 | ||
|
|
b23984a211 | ||
|
|
53c2e262f1 | ||
|
|
a3de67de28 | ||
|
|
2070839722 | ||
|
|
5dd3864617 | ||
|
|
735c961682 | ||
|
|
6e4bda3741 | ||
|
|
1313dcf601 | ||
|
|
98b2bdb410 | ||
|
|
3a073329ff | ||
|
|
a006090b08 | ||
|
|
29f068997b | ||
|
|
fd3a10ab43 | ||
|
|
e6b7ab8b9d | ||
|
|
678e3a210d | ||
|
|
bff7cc5f20 | ||
|
|
dee4ffbc99 | ||
|
|
c108e01917 | ||
|
|
27cd21e459 | ||
|
|
814b4ebb4c | ||
|
|
d3887c1568 | ||
|
|
c29a5cdedb | ||
|
|
4d1307f29b | ||
|
|
6d62574e7f | ||
|
|
c9b2f878b3 | ||
|
|
4490d5ed29 | ||
|
|
4c2cb1b6df | ||
|
|
05885059bd | ||
|
|
6f629d1a6a | ||
|
|
5b9553d5c4 | ||
|
|
5bfa3d5530 | ||
|
|
97e999768a | ||
|
|
d373eba79b | ||
|
|
ade5774313 | ||
|
|
6c728cf389 | ||
|
|
1d2b56d71d | ||
|
|
347ebe5fd3 | ||
|
|
a0a0ae85eb | ||
|
|
22962dd2d2 | ||
|
|
cfc56b24fb | ||
|
|
555e8cada6 | ||
|
|
da58ba0d5c | ||
|
|
4d7bb95c2f | ||
|
|
5eba02ea94 | ||
|
|
0fafefc078 | ||
|
|
3c8be0db72 | ||
|
|
9fabf9f20c | ||
|
|
6c6bb08547 | ||
|
|
0386f2bbea | ||
|
|
d0c961ebc0 | ||
|
|
35b301f73c | ||
|
|
3e02cfd528 | ||
|
|
ceb24bc32e | ||
|
|
1831eccd5e | ||
|
|
e69df54a36 | ||
|
|
0f7dfb984a | ||
|
|
83bc9b35b1 | ||
|
|
8d5931c96c | ||
|
|
3647fc6633 | ||
|
|
093cab6f56 | ||
|
|
7a6491b9b0 | ||
|
|
d14b5d0c11 | ||
|
|
32ea53960e | ||
|
|
e267106220 | ||
|
|
23e679475c | ||
|
|
3c7c11e55b | ||
|
|
43931be451 | ||
|
|
cd5b304cbf | ||
|
|
a8ace2c41c | ||
|
|
60add6cc28 | ||
|
|
c356e347f5 | ||
|
|
33a1006cc5 | ||
|
|
42359d8915 | ||
|
|
fbe54e49f5 | ||
|
|
09cc0c7247 | ||
|
|
d2d70450a5 | ||
|
|
53aa4eba0d | ||
|
|
f454d30318 | ||
|
|
42c088896a | ||
|
|
32259af2c9 | ||
|
|
e53682320c | ||
|
|
0d53705776 | ||
|
|
5f736dd768 | ||
|
|
963233687e | ||
|
|
f1742a6f62 | ||
|
|
77c18f4435 | ||
|
|
b2945e916f | ||
|
|
115493781b | ||
|
|
5bc8b4dadb | ||
|
|
2526aca75f | ||
|
|
efa1092199 | ||
|
|
aa8915bdf6 | ||
|
|
443fa50244 | ||
|
|
6d2c1f7e2c | ||
|
|
7cf9c198fe | ||
|
|
514443a019 | ||
|
|
eef8017281 | ||
|
|
ccb5f1d563 | ||
|
|
e23d61d99e | ||
|
|
92f2e5bad2 | ||
|
|
b4d1429ef0 | ||
|
|
7bc3e67e24 | ||
|
|
7555b337b9 | ||
|
|
8d1ba52d0c | ||
|
|
e94e08475d | ||
|
|
03269f9854 | ||
|
|
a8c2c419cd | ||
|
|
bfb8116623 | ||
|
|
82e6d6e51d | ||
|
|
b62520af9e | ||
|
|
895daf297f | ||
|
|
9be16eba63 | ||
|
|
9b6e07e2a6 | ||
|
|
10caf4a84a | ||
|
|
9145cd66ec | ||
|
|
129c81f34d | ||
|
|
f282e64fe3 | ||
|
|
117091452b | ||
|
|
86a5e72c74 | ||
|
|
02e4aa0f0e | ||
|
|
0916806350 | ||
|
|
9a4dbc25ca | ||
|
|
4c8094d0d9 | ||
|
|
600880660a | ||
|
|
c86935309e | ||
|
|
cc4af235f3 | ||
|
|
552daea04f | ||
|
|
d1d4877348 | ||
|
|
82f187e5e0 | ||
|
|
60ecbec8ea | ||
|
|
cb149bfa00 | ||
|
|
ce0867f40c | ||
|
|
41de0c3c6a | ||
|
|
6f7c3a7cdf | ||
|
|
2bdba5ed73 | ||
|
|
149517ced4 | ||
|
|
4a6d161c08 | ||
|
|
8705db5844 | ||
|
|
d4b3c65c45 | ||
|
|
6cffcf515a | ||
|
|
e3d379a1eb | ||
|
|
f9ceb12e22 | ||
|
|
d374c347e5 | ||
|
|
e3d3727c0c | ||
|
|
c2f535fee1 | ||
|
|
4333a53f28 | ||
|
|
4ff061927b | ||
|
|
f2c710d306 | ||
|
|
8789cc422c | ||
|
|
d39fec3479 | ||
|
|
24c1d552d7 | ||
|
|
8dde9d4a7b | ||
|
|
5d3795e876 | ||
|
|
86694ddc85 | ||
|
|
bc4aad5fb4 | ||
|
|
a03693e881 | ||
|
|
85c38bac34 | ||
|
|
87fe15e39f | ||
|
|
3467ab1551 | ||
|
|
9bf6d57032 | ||
|
|
c8f1e6b5b6 | ||
|
|
d07a96ede8 | ||
|
|
8f4fe61381 | ||
|
|
975550f912 | ||
|
|
d31c9250d3 | ||
|
|
97eb0fc74f | ||
|
|
9e2607db57 | ||
|
|
858161bbc4 | ||
|
|
6b40ead54d | ||
|
|
bf0b86774a | ||
|
|
85b58b03a3 | ||
|
|
a17b943e87 | ||
|
|
c151e075e1 | ||
|
|
d6a4bce2ef | ||
|
|
2ee873d6ca | ||
|
|
4e1ebca0cb | ||
|
|
105e76f321 | ||
|
|
07d65b2aab | ||
|
|
6967a47e07 | ||
|
|
6a2ef733de | ||
|
|
09dfc3f301 | ||
|
|
4c01627e00 | ||
|
|
d93737dd34 | ||
|
|
6391f3d2da | ||
|
|
e09860731f | ||
|
|
da47638f42 | ||
|
|
863dd0b23e | ||
|
|
f3757a7cd1 | ||
|
|
d329e1decd | ||
|
|
13b2aa701c | ||
|
|
80c15607da | ||
|
|
970768288d | ||
|
|
956fdffd96 | ||
|
|
4fbf3fdf03 | ||
|
|
5541ec8670 | ||
|
|
834cf40ab2 | ||
|
|
400ab7876b | ||
|
|
c75271fcb7 | ||
|
|
430677a0c0 | ||
|
|
ad58fe8249 | ||
|
|
b354f9ae9a | ||
|
|
4a0d00fb30 | ||
|
|
afc3531945 | ||
|
|
ece5fa183c | ||
|
|
930b95f76c | ||
|
|
8837712f2b | ||
|
|
79e33d92f1 | ||
|
|
b52f79e137 | ||
|
|
4d0f835548 | ||
|
|
27f5c35bde | ||
|
|
b8935551f1 | ||
|
|
7b60367512 | ||
|
|
52b53f17b2 | ||
|
|
bf2569a9a8 | ||
|
|
76e360ce86 | ||
|
|
e5fb4e4845 | ||
|
|
b9720f5d9e | ||
|
|
2f3925a0cf | ||
|
|
de4c0c237b | ||
|
|
108a01d65f | ||
|
|
d6fa6a459c | ||
|
|
95136cbfc7 | ||
|
|
e4bd2306da | ||
|
|
49886b8c40 | ||
|
|
f6bdc6b87e | ||
|
|
b2ecca3966 | ||
|
|
4aa99e4303 | ||
|
|
1430ebc5e3 | ||
|
|
d51f8ed878 | ||
|
|
077c55d0c8 | ||
|
|
5cf0ee46b3 | ||
|
|
9c4507d115 | ||
|
|
1de4f1af2e | ||
|
|
f9f4867c25 | ||
|
|
2534946ead | ||
|
|
7bd145d88a | ||
|
|
b343f19bec | ||
|
|
76f70d51f3 | ||
|
|
b5d8c53a0c | ||
|
|
6799f3ac5c | ||
|
|
e76be4ba37 | ||
|
|
0b4e03ad5c | ||
|
|
6b2cc9c5cf | ||
|
|
8501217a4e | ||
|
|
f5efa93570 | ||
|
|
0a7fb34613 | ||
|
|
396eede4db | ||
|
|
740af306c0 | ||
|
|
df8a4a03a0 | ||
|
|
eec930b86a | ||
|
|
209b159554 | ||
|
|
39ad6da506 | ||
|
|
2eeba4758a | ||
|
|
219a764a83 | ||
|
|
6d47dd22df | ||
|
|
44ec8a8cd4 | ||
|
|
bd65ceb463 | ||
|
|
9180647f99 | ||
|
|
30e53c95c7 | ||
|
|
fb75d528eb | ||
|
|
816c6c62b5 | ||
|
|
92bb292113 | ||
|
|
273154c1ae | ||
|
|
467afad065 | ||
|
|
1688148828 | ||
|
|
0a18690a4f | ||
|
|
c175b4fd48 | ||
|
|
ead5e66afd | ||
|
|
f295469fac | ||
|
|
d5e00b0920 | ||
|
|
09ded16e3d | ||
|
|
7d1776b84d | ||
|
|
d00808660f | ||
|
|
5bc6cc9512 | ||
|
|
7145461cc5 | ||
|
|
ef690dc06b |
76
.cirrus.yml
76
.cirrus.yml
@@ -1,7 +1,8 @@
|
||||
freebsd_instance:
|
||||
image_family: freebsd-13-0
|
||||
|
||||
task:
|
||||
freebsd_task:
|
||||
name: Code CI / freebsd
|
||||
install_script: pkg install -y git
|
||||
script: |
|
||||
echo 'Building V'
|
||||
@@ -12,3 +13,76 @@ task:
|
||||
##tcc -v -v
|
||||
echo 'Build cmd/tools/fast'
|
||||
cd cmd/tools/fast && ../../../v fast.v && ./fast -clang
|
||||
|
||||
|
||||
arm64_task:
|
||||
name: Code CI / arm64-ubuntu-tcc
|
||||
arm_container:
|
||||
image: ubuntu:latest
|
||||
install_script: apt-get update -y && apt-get install --quiet -y build-essential pkg-config wget git valgrind libsqlite3-dev libssl-dev libxi-dev libxcursor-dev libfreetype6-dev libxi-dev libxcursor-dev libgl-dev xfonts-75dpi xfonts-base libmysqlclient-dev libpq-dev gcc-10-arm-linux-gnueabihf libc6-dev-armhf-cross qemu-user
|
||||
env:
|
||||
DEBIAN_FRONTEND: noninteractive
|
||||
VFLAGS: -cc tcc -no-retry-compilation
|
||||
VJOBS: 2
|
||||
script: |
|
||||
set -e
|
||||
|
||||
wget https://github.com/wkhtmltopdf/packaging/releases/download/0.12.6-1/wkhtmltox_0.12.6-1.focal_arm64.deb
|
||||
apt install --fix-missing -y ./wkhtmltox_0.12.6-1.focal_arm64.deb
|
||||
|
||||
# ensure that a V binary can be built, even if tcc has broken for some reason
|
||||
VFLAGS='-cc gcc' make
|
||||
|
||||
./v -g self
|
||||
./v -g self
|
||||
|
||||
./v -d debug_malloc -d debug_realloc -o v cmd/v
|
||||
./v -cg -cstrict -o v cmd/v
|
||||
#Test v->c
|
||||
thirdparty/tcc/tcc.exe -version
|
||||
./v -cg -o v cmd/v # Make sure vtcc can build itself twice
|
||||
|
||||
# - name: v self compilation
|
||||
./v -o v2 cmd/v && ./v2 -o v3 cmd/v && ./v3 -o v4 cmd/v
|
||||
|
||||
# - name: v self compilation with -skip-unused
|
||||
./v -skip-unused -o v2 cmd/v && ./v2 -skip-unused -o v3 cmd/v && ./v3 -skip-unused -o v4 cmd/v
|
||||
|
||||
# - name: v doctor
|
||||
./v doctor
|
||||
|
||||
# - name: Verify `v test` works
|
||||
./v cmd/tools/test_if_v_test_system_works.v
|
||||
./cmd/tools/test_if_v_test_system_works
|
||||
|
||||
# - name: Self tests
|
||||
./v -silent test-self
|
||||
|
||||
## - name: Self tests (-cstrict)
|
||||
## ./v -cstrict test-self
|
||||
|
||||
# - name: Test time functions in a timezone UTC-12
|
||||
TZ=Etc/GMT+12 ./v test vlib/time/
|
||||
# - name: Test time functions in a timezone UTC-3
|
||||
TZ=Etc/GMT+3 ./v test vlib/time/
|
||||
# - name: Test time functions in a timezone UTC+3
|
||||
TZ=Etc/GMT-3 ./v test vlib/time/
|
||||
# - name: Test time functions in a timezone UTC+12
|
||||
TZ=Etc/GMT-12 ./v test vlib/time/
|
||||
# - name: Test time functions in a timezone using daylight saving (Europe/Paris)
|
||||
TZ=Europe/Paris ./v test vlib/time/
|
||||
# - name: Build examples
|
||||
./v -W build-examples
|
||||
# - name: Test building v tools
|
||||
./v -W build-tools
|
||||
# - name: Test v binaries
|
||||
./v build-vbinaries
|
||||
# - name: Run a VSH script
|
||||
./v run examples/v_script.vsh
|
||||
# - name: Test v tutorials
|
||||
./v tutorials/building_a_simple_web_blog_with_vweb/code/blog
|
||||
|
||||
# test the arm32 version of tcc
|
||||
# TODO: support something like `V_EMULATOR=qemu-arm v run file.v` so that V automatically runs all binaries under qemu
|
||||
./v -arch arm32 -cc arm-linux-gnueabihf-gcc-10 -o av cmd/v && qemu-arm -L /usr/arm-linux-gnueabihf ./av -arch arm32 -cc arm-linux-gnueabihf-gcc-10 -o av2 cmd/v && qemu-arm -L /usr/arm-linux-gnueabihf ./av2 -arch arm32 -cc arm-linux-gnueabihf-gcc-10 -o av3 cmd/v && qemu-arm -L /usr/arm-linux-gnueabihf ./av3 -arch arm32 -cc arm-linux-gnueabihf-gcc-10 -o av4 cmd/v
|
||||
./v -arch arm32 -o closure_test.c vlib/v/tests/closure_test.v && arm-linux-gnueabihf-gcc-10 -o closure_test closure_test.c && qemu-arm -L /usr/arm-linux-gnueabihf ./closure_test
|
||||
|
||||
1
.gitattributes
vendored
1
.gitattributes
vendored
@@ -2,3 +2,4 @@
|
||||
*.vv linguist-language=V text=auto eol=lf
|
||||
*.bat text=auto eol=crlf
|
||||
Dockerfile.* linguist-language=Dockerfile
|
||||
*.toml text eol=lf
|
||||
|
||||
121
.github/workflows/binary_artifact.yml
vendored
121
.github/workflows/binary_artifact.yml
vendored
@@ -12,86 +12,96 @@ jobs:
|
||||
runs-on: ubuntu-20.04
|
||||
env:
|
||||
CC: gcc
|
||||
ZIPNAME: v_linux.zip
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- name: Compile
|
||||
run: |
|
||||
make -j4
|
||||
./v -cc $CC -o v -prod cmd/v
|
||||
./v -prod cmd/tools/vup.v
|
||||
./v -prod cmd/tools/vdoctor.v
|
||||
make -j4
|
||||
./v -cc $CC -prod -o v cmd/v
|
||||
./v -cc $CC -prod cmd/tools/vup.v
|
||||
./v -cc $CC -prod cmd/tools/vdoctor.v
|
||||
- name: Remove excluded
|
||||
run: |
|
||||
rm -rf .git
|
||||
rm -rf vc/
|
||||
rm -rf v_old
|
||||
- name: Create ZIP archive
|
||||
run: |
|
||||
cd ..
|
||||
zip -r9 --symlinks $ZIPNAME v/
|
||||
mv $ZIPNAME v/
|
||||
cd v/
|
||||
- name: Create artifact
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: linux
|
||||
path: |
|
||||
.
|
||||
./cmd/tools/vup
|
||||
./cmd/tools/vdoctor
|
||||
!./.git
|
||||
!./vc
|
||||
!./v_old
|
||||
- name: Create binary only artifact
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: linux-binary
|
||||
path: ./v
|
||||
path: v_linux.zip
|
||||
|
||||
build-macos:
|
||||
runs-on: macos-latest
|
||||
env:
|
||||
CC: clang
|
||||
ZIPNAME: v_macos.zip
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- name: Compile
|
||||
env:
|
||||
CC: clang
|
||||
run: |
|
||||
make -j4
|
||||
./v -cc $CC -o v -prod cmd/v
|
||||
./v -prod cmd/tools/vup.v
|
||||
./v -prod cmd/tools/vdoctor.v
|
||||
./v -cc $CC -prod -o v cmd/v
|
||||
./v -cc $CC -prod cmd/tools/vup.v
|
||||
./v -cc $CC -prod cmd/tools/vdoctor.v
|
||||
- name: Remove excluded
|
||||
run: |
|
||||
rm -rf .git
|
||||
rm -rf vc/
|
||||
rm -rf v_old
|
||||
- name: Create ZIP archive
|
||||
run: |
|
||||
cd ..
|
||||
zip -r9 --symlinks $ZIPNAME v/
|
||||
mv $ZIPNAME v/
|
||||
cd v/
|
||||
- name: Create artifact
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: macos
|
||||
path: |
|
||||
.
|
||||
./cmd/tools/vup
|
||||
./cmd/tools/vdoctor
|
||||
!./.git
|
||||
!./vc
|
||||
!./v_old
|
||||
- name: Create binary only artifact
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: macos-binary
|
||||
path: ./v
|
||||
path: v_macos.zip
|
||||
|
||||
build-windows:
|
||||
runs-on: windows-latest
|
||||
env:
|
||||
CC: msvc
|
||||
ZIPNAME: v_windows.zip
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- uses: msys2/setup-msys2@v2
|
||||
- name: Compile
|
||||
run: |
|
||||
.\make.bat
|
||||
.\make.bat -tcc
|
||||
.\v.exe cmd\tools\vup.v
|
||||
.\v.exe cmd\tools\vdoctor.v
|
||||
- name: Remove excluded
|
||||
shell: msys2 {0}
|
||||
run: |
|
||||
rm -rf .git
|
||||
rm -rf vc/
|
||||
rm -rf v_old.exe
|
||||
- name: Create archive
|
||||
shell: msys2 {0}
|
||||
run: |
|
||||
cd ..
|
||||
powershell Compress-Archive v $ZIPNAME
|
||||
mv $ZIPNAME v/
|
||||
cd v/
|
||||
# NB: the powershell Compress-Archive line is from:
|
||||
# https://superuser.com/a/1336434/194881
|
||||
# It is needed, because `zip` is not installed by default :-|
|
||||
- name: Create artifact
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: windows
|
||||
path: |
|
||||
.
|
||||
./cmd/tools/vup.exe
|
||||
./cmd/tools/vdoctor.exe
|
||||
!./.git
|
||||
!./vc
|
||||
!./v_old.exe
|
||||
- name: Create binary only artifact
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: windows-binary
|
||||
path: ./v.exe
|
||||
path: v_windows.zip
|
||||
|
||||
release:
|
||||
name: Create Github Release
|
||||
@@ -128,23 +138,6 @@ jobs:
|
||||
with:
|
||||
name: ${{ matrix.version }}
|
||||
path: ./${{ matrix.version }}
|
||||
- name: Build Zip Archives
|
||||
run: |
|
||||
mkdir -p workdir/
|
||||
mv ${{ matrix.version }}/ workdir/v/
|
||||
cd workdir/v/
|
||||
chmod 755 v || true
|
||||
chmod 755 v.exe || true
|
||||
chmod 755 thirdparty/tcc/tcc.exe || true
|
||||
chmod 755 cmd/tools/vup || true
|
||||
chmod 755 cmd/tools/vup.exe || true
|
||||
chmod 755 cmd/tools/vdoctor || true
|
||||
chmod 755 cmd/tools/vdoctor.exe || true
|
||||
rm -rf v_old v_old.exe
|
||||
cd ..
|
||||
zip -r9 --symlinks ../v_${{ matrix.version }}.zip v/*
|
||||
cd ..
|
||||
rm -rf workdir/
|
||||
- name: Get short tag name
|
||||
uses: jungwinter/split@v1
|
||||
id: split
|
||||
@@ -165,6 +158,6 @@ jobs:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
upload_url: ${{ steps.get_release_info.outputs.upload_url }}
|
||||
asset_path: ./v_${{ matrix.version }}.zip
|
||||
asset_path: ${{ matrix.version }}/v_${{ matrix.version }}.zip
|
||||
asset_name: v_${{ matrix.version }}.zip
|
||||
asset_content_type: application/zip
|
||||
|
||||
185
.github/workflows/ci.yml
vendored
185
.github/workflows/ci.yml
vendored
@@ -42,9 +42,9 @@ jobs:
|
||||
- name: Build the repeat tool
|
||||
run: ./v cmd/tools/repeat.v
|
||||
- name: Repeat -o hw.c examples/hello_world.v
|
||||
run: cmd/tools/repeat --max_time 201 --series 3 --count 20 --nmins 2 --nmaxs 5 --warmup 3 --fail_percent 10 -t 'cd {T} ; ./v -show-timings -o hw.c examples/hello_world.v' . ./vmaster
|
||||
run: cmd/tools/repeat --max_time 251 --series 3 --count 20 --nmins 2 --nmaxs 5 --warmup 3 --fail_percent 10 -t 'cd {T} ; ./v -show-timings -o hw.c examples/hello_world.v' . ./vmaster
|
||||
- name: Repeat -o v.c cmd/v
|
||||
run: cmd/tools/repeat --max_time 1201 --series 3 --count 20 --nmins 2 --nmaxs 5 --warmup 3 --fail_percent 10 -t 'cd {T} ; ./v -show-timings -o v.c cmd/v' . ./vmaster
|
||||
run: cmd/tools/repeat --max_time 1501 --series 3 --count 20 --nmins 2 --nmaxs 5 --warmup 3 --fail_percent 10 -t 'cd {T} ; ./v -show-timings -o v.c cmd/v' . ./vmaster
|
||||
|
||||
ubuntu-tcc:
|
||||
needs: no-scheduling
|
||||
@@ -188,24 +188,6 @@ jobs:
|
||||
- name: Build v
|
||||
run: make
|
||||
|
||||
- name: v.c can be compiled and run with -os cross
|
||||
run: |
|
||||
./v -os cross -o /tmp/v.c cmd/v
|
||||
gcc -g -std=gnu11 -w -o v_from_vc /tmp/v.c -lm -lpthread
|
||||
ls -lart v_from_vc
|
||||
./v_from_vc version
|
||||
|
||||
- name: Ensure v up works
|
||||
run: |
|
||||
./v cmd/tools/oldv.v
|
||||
./cmd/tools/oldv -v HEAD^^^^^
|
||||
cd ~/.cache/oldv/v_at_HEAD_____/
|
||||
./v version
|
||||
./v -v up
|
||||
./v version
|
||||
./v -o v2 cmd/v
|
||||
./v2 -o v3 cmd/v
|
||||
|
||||
- name: Ensure V can be compiled with -autofree
|
||||
run: ./v -autofree -o v2 cmd/v ## NB: this does not mean it runs, but at least keeps it from regressing
|
||||
|
||||
@@ -235,7 +217,7 @@ jobs:
|
||||
- name: g++ version
|
||||
run: g++-9 --version
|
||||
- name: V self compilation with g++
|
||||
run: ./v -cc g++-9 -o v2 cmd/v && ./v2 -cc g++-9 -o v3 cmd/v
|
||||
run: ./v -cc g++-9 -no-std -cflags -std=c++11 -o v2 cmd/v && ./v2 -cc g++-9 -no-std -cflags -std=c++11 -o v3 cmd/v
|
||||
## - name: Running tests with g++
|
||||
## run: ./v -cc g++-9 -silent test-self
|
||||
|
||||
@@ -257,18 +239,20 @@ jobs:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Build V
|
||||
run: |
|
||||
make CC=clang
|
||||
- name: Show PWD and Environment
|
||||
- name: Show Environment
|
||||
run: |
|
||||
echo "PWD:"
|
||||
pwd
|
||||
echo "ENVIRONMENT"
|
||||
echo "ENVIRONMENT:"
|
||||
env
|
||||
echo "C Compiler:"
|
||||
gcc --version
|
||||
|
||||
- name: Build V
|
||||
run: CC=gcc make
|
||||
|
||||
- name: Test V fixed tests
|
||||
run: |
|
||||
./v -silent test-self
|
||||
run: ./v -silent test-self
|
||||
|
||||
macos:
|
||||
needs: no-scheduling
|
||||
@@ -276,6 +260,7 @@ jobs:
|
||||
timeout-minutes: 121
|
||||
env:
|
||||
VFLAGS: -cc clang
|
||||
PKG_CONFIG_PATH: /usr/local/opt/openssl@3/lib/pkgconfig
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-node@v1
|
||||
@@ -285,8 +270,9 @@ jobs:
|
||||
run: |
|
||||
##brew install libpq openssl freetype ### these are *already installed* on Catalina ...
|
||||
brew uninstall --ignore-dependencies libpq ## libpq is a dependency of PHP
|
||||
brew install postgresql
|
||||
brew install postgresql openssl
|
||||
export LIBRARY_PATH="$LIBRARY_PATH:/usr/local/opt/openssl/lib/"
|
||||
echo "PKG_CONFIG_PATH is '$PKG_CONFIG_PATH'"
|
||||
- name: Build V
|
||||
run: make -j4 && ./v -cg -cstrict -o v cmd/v
|
||||
- name: Run sanitizers
|
||||
@@ -320,13 +306,6 @@ jobs:
|
||||
./v cmd/tools/test_if_v_test_system_works.v
|
||||
./cmd/tools/test_if_v_test_system_works
|
||||
|
||||
- name: v.c can be compiled and run with -os cross
|
||||
run: |
|
||||
./v -os cross -o /tmp/v.c cmd/v
|
||||
cc -g -std=gnu11 -w -o v_from_vc /tmp/v.c -lm -lpthread
|
||||
ls -lart v_from_vc
|
||||
./v_from_vc version
|
||||
|
||||
- name: Self tests
|
||||
run: VJOBS=1 ./v -silent test-self
|
||||
|
||||
@@ -627,7 +606,7 @@ jobs:
|
||||
gcc --version
|
||||
.\make.bat -gcc
|
||||
- name: Test new v.c
|
||||
run: .\v.exe -o v.c cmd/v && gcc -Werror -municode -w v.c
|
||||
run: .\v.exe -o v.c cmd/v && gcc -Werror -I ./thirdparty/stdatomic/win -municode -w v.c
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
.\v.exe setup-freetype
|
||||
@@ -669,7 +648,7 @@ jobs:
|
||||
run: |
|
||||
echo %VFLAGS%
|
||||
echo $VFLAGS
|
||||
.\make.bat -msvc --verbose
|
||||
.\make.bat -msvc
|
||||
.\v.exe -cflags /WX self
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
@@ -713,9 +692,9 @@ jobs:
|
||||
node-version: 12.x
|
||||
- name: Build with make.bat -tcc
|
||||
run: |
|
||||
.\make.bat -tcc --verbose
|
||||
.\make.bat -tcc
|
||||
- name: Test new v.c
|
||||
run: .\v.exe -o v.c cmd/v && .\thirdparty\tcc\tcc.exe -Werror -w -ladvapi32 -bt10 v.c
|
||||
run: .\v.exe -o v.c cmd/v && .\thirdparty\tcc\tcc.exe -I ./thirdparty/stdatomic/win -Werror -w -ladvapi32 -bt10 v.c
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
.\v.exe setup-freetype
|
||||
@@ -757,45 +736,45 @@ jobs:
|
||||
- name: v2 self compilation
|
||||
run: .\v.exe -o v2.exe cmd/v && .\v2.exe -o v3.exe cmd/v
|
||||
|
||||
## tcc32
|
||||
- name: Build with make.bat -tcc32
|
||||
run: |
|
||||
Remove-Item -Recurse -Force .\thirdparty\tcc
|
||||
.\v.exe wipe-cache
|
||||
.\make.bat -tcc32 --verbose
|
||||
- name: Test new v.c
|
||||
run: .\v.exe -o v.c cmd/v && .\thirdparty\tcc\tcc.exe -Werror -w -ladvapi32 -bt10 v.c
|
||||
- name: v doctor
|
||||
run: ./v doctor
|
||||
|
||||
- name: Verify `v test` works
|
||||
run: |
|
||||
.\v.exe cmd/tools/test_if_v_test_system_works.v
|
||||
.\cmd\tools\test_if_v_test_system_works.exe
|
||||
|
||||
- name: Verify `v vlib/v/gen/c/coutput_test.v` works
|
||||
run: |
|
||||
.\v.exe vlib/v/gen/c/coutput_test.v
|
||||
|
||||
- name: Make sure running TCC32 instead of TCC64
|
||||
run: ./v -stats .github\workflows\make_sure_ci_run_with_32bit_compiler_test.v
|
||||
|
||||
- name: Test v build-tools
|
||||
run: ./v -W build-tools
|
||||
|
||||
- name: Test ./v doc clipboard
|
||||
run: ./v doc clipboard
|
||||
|
||||
- name: Self tests
|
||||
run: ./v test-self
|
||||
- name: Test v->js
|
||||
run: ./v -o hi.js examples/hello_v_js.v && node hi.js
|
||||
- name: Test v binaries
|
||||
run: ./v build-vbinaries
|
||||
- name: Build examples
|
||||
run: ./v build-examples
|
||||
- name: v2 self compilation
|
||||
run: .\v.exe -o v2.exe cmd/v && .\v2.exe -o v3.exe cmd/v
|
||||
## ## tcc32
|
||||
## - name: Build with make.bat -tcc32
|
||||
## run: |
|
||||
## Remove-Item -Recurse -Force .\thirdparty\tcc
|
||||
## .\v.exe wipe-cache
|
||||
## .\make.bat -tcc32
|
||||
## - name: Test new v.c
|
||||
## run: .\v.exe -o v.c cmd/v && .\thirdparty\tcc\tcc.exe -I ./thirdparty/stdatomic/win -Werror -g -w -ladvapi32 -bt10 v.c
|
||||
## - name: v doctor
|
||||
## run: ./v doctor
|
||||
##
|
||||
## - name: Verify `v test` works
|
||||
## run: |
|
||||
## .\v.exe cmd/tools/test_if_v_test_system_works.v
|
||||
## .\cmd\tools\test_if_v_test_system_works.exe
|
||||
##
|
||||
## - name: Verify `v vlib/v/gen/c/coutput_test.v` works
|
||||
## run: |
|
||||
## .\v.exe vlib/v/gen/c/coutput_test.v
|
||||
##
|
||||
## - name: Make sure running TCC32 instead of TCC64
|
||||
## run: ./v -stats .github\workflows\make_sure_ci_run_with_32bit_compiler_test.v
|
||||
##
|
||||
## - name: Test v build-tools
|
||||
## run: ./v -W build-tools
|
||||
##
|
||||
## - name: Test ./v doc clipboard
|
||||
## run: ./v doc clipboard
|
||||
##
|
||||
## - name: Self tests
|
||||
## run: ./v test-self
|
||||
## - name: Test v->js
|
||||
## run: ./v -o hi.js examples/hello_v_js.v && node hi.js
|
||||
## - name: Test v binaries
|
||||
## run: ./v build-vbinaries
|
||||
## - name: Build examples
|
||||
## run: ./v build-examples
|
||||
## - name: v2 self compilation
|
||||
## run: .\v.exe -o v2.exe cmd/v && .\v2.exe -o v3.exe cmd/v
|
||||
|
||||
parser-silent:
|
||||
needs: no-scheduling
|
||||
@@ -847,22 +826,40 @@ jobs:
|
||||
run: make && sudo ./v symlink
|
||||
|
||||
## vls
|
||||
- name: Clone tree-sitter-v to ~/.vmodules/tree_sitter_v
|
||||
run: git clone --depth 1 https://github.com/nedpals/tree-sitter-v ~/.vmodules/tree_sitter_v
|
||||
- name: Clone VLS tree-sitter
|
||||
run: git clone --depth 1 --no-single-branch https://github.com/vlang/vls
|
||||
- name: Checkout branch tree-sitter
|
||||
run: pushd vls; git checkout use-tree-sitter; popd
|
||||
- name: Build VLS tree-sitter
|
||||
- name: Clone VLS
|
||||
run: git clone --depth 1 https://github.com/vlang/vls
|
||||
- name: Build VLS
|
||||
run: pushd vls; v cmd/vls ; popd
|
||||
- name: Build VLS tree-sitter with -prod
|
||||
- name: Build VLS with -prod
|
||||
run: pushd vls; v -prod cmd/vls; popd
|
||||
- name: Checkout branch master
|
||||
run: pushd vls; git checkout master; popd
|
||||
- name: Build VLS master
|
||||
run: pushd vls; v cmd/vls ; popd
|
||||
- name: Build VLS master with -prod
|
||||
run: pushd vls; v -prod cmd/vls ; popd
|
||||
|
||||
## vsl
|
||||
- name: Clone VSL
|
||||
run: git clone --depth 1 https://github.com/vlang/vsl ~/.vmodules/vsl
|
||||
- name: Install dependencies
|
||||
run: sudo apt-get install --quiet -y --no-install-recommends gfortran liblapacke-dev libopenblas-dev libgc-dev
|
||||
- name: Execute Tests using Pure V Backend
|
||||
run: ~/.vmodules/vsl/bin/test
|
||||
- name: Execute Tests using Pure V Backend with Pure V Math
|
||||
run: ~/.vmodules/vsl/bin/test --use-cblas
|
||||
- name: Execute Tests using Pure V Backend and Garbage Collection enabled
|
||||
run: ~/.vmodules/vsl/bin/test --use-gc boehm
|
||||
- name: Execute Tests using Pure V Backend with Pure V Math and Garbage Collection enabled
|
||||
run: ~/.vmodules/vsl/bin/test --use-cblas --use-gc boehm
|
||||
|
||||
## vtl
|
||||
- name: Clone VTL
|
||||
run: git clone --depth 1 https://github.com/vlang/vtl ~/.vmodules/vtl
|
||||
- name: Install dependencies
|
||||
run: sudo apt-get install --quiet -y --no-install-recommends gfortran liblapacke-dev libopenblas-dev libgc-dev
|
||||
- name: Execute Tests using Pure V Backend
|
||||
run: ~/.vmodules/vtl/bin/test
|
||||
- name: Execute Tests using Pure V Backend with Pure V Math
|
||||
run: ~/.vmodules/vtl/bin/test --use-cblas
|
||||
- name: Execute Tests using Pure V Backend and Garbage Collection enabled
|
||||
run: ~/.vmodules/vtl/bin/test --use-gc boehm
|
||||
- name: Execute Tests using Pure V Backend with Pure V Math and Garbage Collection enabled
|
||||
run: ~/.vmodules/vtl/bin/test --use-cblas --use-gc boehm
|
||||
|
||||
## vab
|
||||
- name: Clone vab
|
||||
@@ -880,6 +877,8 @@ jobs:
|
||||
../v .
|
||||
# ./gitly -ci_run
|
||||
../v -autofree .
|
||||
../v -o x tests/first_run.v
|
||||
./x
|
||||
cd ..
|
||||
|
||||
## vex
|
||||
|
||||
77
.github/workflows/ci_bootstrapping_works.yml
vendored
Normal file
77
.github/workflows/ci_bootstrapping_works.yml
vendored
Normal file
@@ -0,0 +1,77 @@
|
||||
name: Bootstraping works
|
||||
|
||||
on:
|
||||
push:
|
||||
paths-ignore:
|
||||
- "**.md"
|
||||
pull_request:
|
||||
paths-ignore:
|
||||
- "**.md"
|
||||
|
||||
jobs:
|
||||
ubuntu:
|
||||
runs-on: ubuntu-20.04
|
||||
timeout-minutes: 15
|
||||
env:
|
||||
VFLAGS: -cc tcc -no-retry-compilation
|
||||
B_CFLAGS: -g -std=gnu11 -I ./thirdparty/stdatomic/nix -w
|
||||
B_LFLAGS: -lm -lpthread
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
fetch-depth: 10
|
||||
- name: Build v
|
||||
run: make
|
||||
|
||||
- name: v.c can be compiled and run with -os cross (bootstrapping works)
|
||||
run: |
|
||||
ls -la v vc/v.c
|
||||
./v -os cross -o vc/v.c cmd/v
|
||||
gcc $B_CFLAGS -o v_from_vc vc/v.c $B_LFLAGS
|
||||
ls -lart v_from_vc
|
||||
./v_from_vc version
|
||||
./v_from_vc run examples/hello_world.v
|
||||
./v_from_vc -o v_from_vc_produced_native_v cmd/v
|
||||
./v_from_vc_produced_native_v run examples/hello_world.v
|
||||
make local=1
|
||||
ls -la v vc/v.c v_from_vc v_from_vc_produced_native_v
|
||||
|
||||
- name: Ensure v up works
|
||||
run: |
|
||||
./v cmd/tools/oldv.v
|
||||
./cmd/tools/oldv -v HEAD^^^^^
|
||||
cd ~/.cache/oldv/v_at_HEAD_____/
|
||||
./v version
|
||||
./v -v up
|
||||
./v version
|
||||
./v -o v2 cmd/v
|
||||
./v2 -o v3 cmd/v
|
||||
|
||||
macos:
|
||||
runs-on: macos-11
|
||||
timeout-minutes: 15
|
||||
env:
|
||||
VFLAGS: -cc clang
|
||||
B_CFLAGS: -g -std=gnu11 -I ./thirdparty/stdatomic/nix -w
|
||||
B_LFLAGS: -lm -lpthread
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
fetch-depth: 10
|
||||
- name: Build V
|
||||
run: make && ./v -cg -cstrict -o v cmd/v
|
||||
|
||||
- name: v.c can be compiled and run with -os cross (bootstrapping works)
|
||||
run: |
|
||||
ls -la v vc/v.c
|
||||
./v -os cross -o vc/v.c cmd/v
|
||||
cc $B_CFLAGS -o v_from_vc vc/v.c $B_LFLAGS
|
||||
ls -lart v_from_vc
|
||||
./v_from_vc version
|
||||
./v_from_vc run examples/hello_world.v
|
||||
./v_from_vc -o v_from_vc_produced_native_v cmd/v
|
||||
./v_from_vc_produced_native_v run examples/hello_world.v
|
||||
### the next make invocation will simulate building V from scratch,
|
||||
### using this commit
|
||||
make local=1
|
||||
ls -la v vc/v.c v_from_vc v_from_vc_produced_native_v
|
||||
33
.github/workflows/ci_cross.yml
vendored
33
.github/workflows/ci_cross.yml
vendored
@@ -19,23 +19,23 @@ jobs:
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
fetch-depth: 10
|
||||
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
brew install mingw-w64
|
||||
export LIBRARY_PATH="$LIBRARY_PATH:/usr/local/opt/openssl/lib/"
|
||||
|
||||
|
||||
- name: Build V
|
||||
run: make
|
||||
|
||||
- name: Test symlink
|
||||
run: ./v symlink
|
||||
|
||||
|
||||
- name: Cross-compilation to Linux
|
||||
run: |
|
||||
./v -os linux cmd/v
|
||||
# TODO: fix this: ./v -os linux examples/2048/2048.v
|
||||
|
||||
|
||||
- name: Cross-compilation to Windows
|
||||
run: |
|
||||
./v -os windows cmd/v
|
||||
@@ -52,35 +52,37 @@ jobs:
|
||||
fetch-depth: 10
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
## sudo dpkg --add-architecture i386
|
||||
sudo apt update
|
||||
sudo apt-get install --quiet -y libssl-dev sqlite3 libsqlite3-dev valgrind
|
||||
sudo apt-get install --quiet -y libssl-dev sqlite3 libsqlite3-dev
|
||||
sudo apt-get install --quiet -y mingw-w64 wine-stable winetricks
|
||||
## sudo apt-get install --quiet -y wine32
|
||||
- name: Turn off the wine crash dialog
|
||||
run: winetricks nocrashdialog
|
||||
|
||||
|
||||
- name: Build v
|
||||
run: make
|
||||
|
||||
|
||||
- name: v.c can be compiled and run with -os cross
|
||||
run: |
|
||||
./v -os cross -o /tmp/v.c cmd/v
|
||||
gcc -g -std=gnu11 -w -o v_from_vc /tmp/v.c -lm -lpthread
|
||||
gcc -g -std=gnu11 -I ./thirdparty/stdatomic/nix -w -o v_from_vc /tmp/v.c -lm -lpthread
|
||||
ls -lart v_from_vc
|
||||
./v_from_vc version
|
||||
|
||||
|
||||
- name: v_win.c can be compiled and run with -os windows
|
||||
run: |
|
||||
./v -os windows -o /tmp/v_win.c cmd/v
|
||||
x86_64-w64-mingw32-gcc /tmp/v_win.c -std=c99 -w -municode -o v_from_vc.exe
|
||||
x86_64-w64-mingw32-gcc -I ./thirdparty/stdatomic/win /tmp/v_win.c -std=c99 -w -municode -o v_from_vc.exe
|
||||
ls -lart v_from_vc.exe
|
||||
wine v_from_vc.exe version
|
||||
|
||||
wine64 ./v_from_vc.exe version
|
||||
|
||||
- name: hello_world.v can be cross compiled to hello_world.exe
|
||||
run: |
|
||||
./v -os windows examples/hello_world.v
|
||||
ls -lart examples/hello_world.exe
|
||||
wine examples/hello_world.exe
|
||||
|
||||
wine64 examples/hello_world.exe
|
||||
|
||||
- name: 2048.v can be cross compiled to 2048.exe
|
||||
run: |
|
||||
./v -os windows examples/2048/2048.v
|
||||
@@ -97,10 +99,11 @@ jobs:
|
||||
run: |
|
||||
echo %VFLAGS%
|
||||
echo $VFLAGS
|
||||
.\make.bat --verbose -msvc
|
||||
.\make.bat -msvc
|
||||
- name: TODO v_win.c can be compiled and run with -os windows
|
||||
run: |
|
||||
.\v.exe -os windows -showcc -o v2.exe cmd\v
|
||||
.\v.exe -os windows -o v_win.c cmd\v
|
||||
dir v2.exe
|
||||
dir v_win.c
|
||||
.\v2.exe version
|
||||
|
||||
16
.github/workflows/ci_sanitized.yml
vendored
16
.github/workflows/ci_sanitized.yml
vendored
@@ -159,14 +159,14 @@ jobs:
|
||||
echo %VFLAGS%
|
||||
echo $VFLAGS
|
||||
.\make.bat -msvc
|
||||
.\v.exe -cflags /WX self
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
.\v.exe setup-freetype
|
||||
.\.github\workflows\windows-install-sqlite.bat
|
||||
- name: Self tests (-fsanitize=address)
|
||||
run: |
|
||||
.\v.exe -cflags -fsanitize=address test-self
|
||||
.\v.exe self
|
||||
## - name: Install dependencies
|
||||
## run: |
|
||||
## .\v.exe setup-freetype
|
||||
## .\.github\workflows\windows-install-sqlite.bat
|
||||
## - name: Self tests (TODO: /fsanitize=address)
|
||||
## run: |
|
||||
## .\v.exe -cflags "/fsanitize=address" test-self
|
||||
|
||||
tests-sanitize-address-gcc:
|
||||
needs: no-scheduling
|
||||
|
||||
2
.github/workflows/debug_ci.yml
vendored
2
.github/workflows/debug_ci.yml
vendored
@@ -18,7 +18,7 @@ jobs:
|
||||
run: |
|
||||
echo %VFLAGS%
|
||||
echo $VFLAGS
|
||||
.\make.bat --verbose -msvc
|
||||
.\make.bat -msvc
|
||||
.\v.exe -cflags /WX self
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
|
||||
53
.github/workflows/gfx_ci.yml
vendored
Normal file
53
.github/workflows/gfx_ci.yml
vendored
Normal file
@@ -0,0 +1,53 @@
|
||||
name: Graphics CI
|
||||
|
||||
on:
|
||||
push:
|
||||
paths-ignore:
|
||||
- "**.md"
|
||||
pull_request:
|
||||
paths-ignore:
|
||||
- "**.md"
|
||||
|
||||
jobs:
|
||||
gg-regressions:
|
||||
runs-on: ubuntu-18.04
|
||||
timeout-minutes: 10
|
||||
env:
|
||||
VFLAGS: -cc tcc
|
||||
DISPLAY: :99
|
||||
steps:
|
||||
- name: Checkout V
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Build local v
|
||||
run: make -j4
|
||||
|
||||
- name: Setup dependencies
|
||||
run: |
|
||||
# xvfb : xvfb (installed by openrndr/setup-opengl@v1.1)
|
||||
# openimageio-tools : idiff
|
||||
# libxcursor-dev libxi-dev : V gfx deps
|
||||
# mesa-common-dev : For headless rendering
|
||||
# freeglut3-dev : Fixes graphic apps compilation with tcc
|
||||
sudo apt-get install imagemagick openimageio-tools mesa-common-dev libxcursor-dev libxi-dev freeglut3-dev
|
||||
wget https://raw.githubusercontent.com/tremby/imgur.sh/c98345d/imgur.sh
|
||||
chmod +x ./imgur.sh
|
||||
|
||||
- uses: openrndr/setup-opengl@v1.1
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
repository: Larpon/gg-regression-images
|
||||
path: gg-regression-images
|
||||
|
||||
- name: Sample and compare
|
||||
id: compare
|
||||
continue-on-error: true
|
||||
run: |
|
||||
Xvfb $DISPLAY -screen 0 1280x1024x24 &
|
||||
./v gret -t ./gg-regression-images/vgret.v_examples.toml -v ./gg-sample_images ./gg-regression-images
|
||||
|
||||
- name: Upload regression to imgur
|
||||
if: steps.compare.outcome != 'success'
|
||||
run: |
|
||||
./imgur.sh /tmp/fail.png
|
||||
exit 1
|
||||
70
.github/workflows/toml_ci.yml
vendored
Normal file
70
.github/workflows/toml_ci.yml
vendored
Normal file
@@ -0,0 +1,70 @@
|
||||
name: toml CI
|
||||
|
||||
on:
|
||||
push:
|
||||
paths-ignore:
|
||||
- "**.md"
|
||||
pull_request:
|
||||
paths-ignore:
|
||||
- "**.md"
|
||||
|
||||
jobs:
|
||||
toml-module-pass-external-test-suites:
|
||||
runs-on: ubuntu-18.04
|
||||
timeout-minutes: 10
|
||||
env:
|
||||
TOML_BS_TESTS_PATH: vlib/toml/tests/testdata/burntsushi/toml-test
|
||||
TOML_BS_TESTS_PINNED_COMMIT: eb989e5
|
||||
TOML_IARNA_TESTS_PATH: vlib/toml/tests/testdata/iarna/toml-test
|
||||
TOML_IARNA_TESTS_PINNED_COMMIT: 1880b1a
|
||||
TOML_ALEXCRICHTON_TESTS_PATH: vlib/toml/tests/testdata/alexcrichton/toml-test
|
||||
TOML_ALEXCRICHTON_TESTS_PINNED_COMMIT: 499e8c4
|
||||
steps:
|
||||
|
||||
- uses: actions/checkout@v2
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install --quiet -y jq
|
||||
- name: Build V
|
||||
run: make -j2 && ./v -cc gcc -o v cmd/v
|
||||
|
||||
- name: Run local TOML tests
|
||||
run: ./v test vlib/toml
|
||||
|
||||
# Tests found at https://github.com/BurntSushi/toml-test
|
||||
- name: Clone BurntSushi/toml-test
|
||||
run: |
|
||||
git clone https://github.com/BurntSushi/toml-test.git $TOML_BS_TESTS_PATH
|
||||
## TODO: update/remove this pinning once all our skip lists are empty:
|
||||
git -C $TOML_BS_TESTS_PATH checkout $TOML_BS_TESTS_PINNED_COMMIT
|
||||
|
||||
- name: Run BurntSushi TOML tests
|
||||
run: ./v vlib/toml/tests/burntsushi.toml-test_test.v
|
||||
|
||||
# Tests found at gist
|
||||
- name: Get large_toml_file_test.toml
|
||||
run: wget https://gist.githubusercontent.com/Larpon/89b0e3d94c6903851ff15559e5df7a05/raw/62a1f87a4e37bf157f2e0bfb32d85d840c98e422/large_toml_file_test.toml -O vlib/toml/tests/testdata/large_toml_file_test.toml
|
||||
|
||||
- name: Run large TOML file tests
|
||||
run: ./v vlib/toml/tests/large_toml_file_test.v
|
||||
|
||||
# Tests found at https://github.com/iarna/toml-spec-tests
|
||||
- name: Clone iarna/toml-spec-tests
|
||||
run: |
|
||||
git clone https://github.com/iarna/toml-spec-tests.git $TOML_IARNA_TESTS_PATH
|
||||
## TODO: update/remove this pinning once all our skip lists are empty:
|
||||
git -C $TOML_IARNA_TESTS_PATH checkout $TOML_IARNA_TESTS_PINNED_COMMIT
|
||||
|
||||
- name: Run iarna TOML tests
|
||||
run: ./v vlib/toml/tests/iarna.toml-spec-tests_test.v
|
||||
|
||||
# Tests found at https://github.com/alexcrichton/toml-rs
|
||||
- name: Clone alexcrichton/toml-rs
|
||||
run: |
|
||||
git clone https://github.com/alexcrichton/toml-rs.git $TOML_ALEXCRICHTON_TESTS_PATH
|
||||
## TODO: update/remove this pinning once all our skip lists are empty:
|
||||
git -C $TOML_ALEXCRICHTON_TESTS_PATH checkout $TOML_ALEXCRICHTON_TESTS_PINNED_COMMIT
|
||||
|
||||
- name: Run alexcrichton TOML tests
|
||||
run: ./v vlib/toml/tests/alexcrichton.toml-rs-tests_test.v
|
||||
3
.github/workflows/vinix-kernel.yml
vendored
3
.github/workflows/vinix-kernel.yml
vendored
@@ -20,7 +20,8 @@ jobs:
|
||||
- name: Build V
|
||||
run: make
|
||||
- name: Clone current Vinix
|
||||
run: git clone https://github.com/vlang/vinix.git --depth=1
|
||||
run: |
|
||||
git clone https://github.com/vlang/vinix.git --depth 1
|
||||
- name: Clone current mlibc
|
||||
run: git clone https://github.com/managarm/mlibc.git --depth=1
|
||||
- name: Patch mlibc for Vinix
|
||||
|
||||
6
.gitignore
vendored
6
.gitignore
vendored
@@ -20,6 +20,7 @@ vdbg.exe
|
||||
*.dll
|
||||
*.lib
|
||||
*.bak
|
||||
*.dylib
|
||||
a.out
|
||||
.noprefix.vrepl_temp
|
||||
|
||||
@@ -99,3 +100,8 @@ shell.nix
|
||||
default.nix
|
||||
flake.nix
|
||||
.envrc
|
||||
|
||||
thirdparty/stdatomic/nix/cpp/*.h
|
||||
|
||||
# ignore VLS log
|
||||
vls.log
|
||||
|
||||
@@ -183,17 +183,19 @@ to create a copy of the compiler rather than replacing it with `v self`.
|
||||
|
||||
| Flag | Usage |
|
||||
|------|-------|
|
||||
| `debugautostr` | Prints informations about `.str()` method auto-generated by the compiler during C generation |
|
||||
| `debugscanner` | Prints debug information during the scanning phase |
|
||||
| `debug_codegen` | Prints automatically generated V code during the scanning phase |
|
||||
| `debug_interface_table` | Prints generated interfaces during C generation |
|
||||
| `debug_interface_type_implements` | Prints debug information when checking that a type implements in interface |
|
||||
| `debug_embed_file_in_prod` | Prints debug information about the embedded files with `$embed_file('somefile')` |
|
||||
| `print_vweb_template_expansions` | Prints vweb compiled HTML files |
|
||||
| `time_checking` | Prints the time spent checking files and other related informations |
|
||||
| `time_parsing` | Prints the time spent parsing files and other related informations |
|
||||
| `time_checking` | Prints the time spent checking files and other related information |
|
||||
| `time_parsing` | Prints the time spent parsing files and other related information |
|
||||
| `trace_autofree` | Prints details about how/when -autofree puts free() calls |
|
||||
| `trace_autostr` | Prints details about `.str()` method auto-generated by the compiler during C generation |
|
||||
| `trace_ccoptions` | Prints options passed down to the C compiler |
|
||||
| `trace_checker` | Prints informations about the statements being checked |
|
||||
| `trace_checker` | Prints details about the statements being checked |
|
||||
| `trace_gen` | Prints strings written to the generated C file. Beware, this flag is very verbose |
|
||||
| `trace_parser` | Prints informations about parsed statements and expressions |
|
||||
| `trace_thirdparty_obj_files` | Prints informations about built thirdparty obj files |
|
||||
| `trace_use_cache` | Prints informations about cache use |
|
||||
| `trace_parser` | Prints details about parsed statements and expressions |
|
||||
| `trace_thirdparty_obj_files` | Prints details about built thirdparty obj files |
|
||||
| `trace_usecache` | Prints details when -usecache is used |
|
||||
|
||||
@@ -4,7 +4,7 @@ LABEL maintainer="Vitaly Takmazov <vitalyster@gmail.com>"
|
||||
COPY . .
|
||||
RUN make
|
||||
RUN ./v -os windows -o v.c cmd/v
|
||||
RUN x86_64-w64-mingw32-gcc v.c -std=c99 -w -municode -o v.exe
|
||||
RUN x86_64-w64-mingw32-gcc v.c -std=c99 -I ./thirdparty/stdatomic/win -w -municode -o v.exe
|
||||
RUN file v.exe
|
||||
|
||||
CMD [ "bash" ]
|
||||
|
||||
15
GNUmakefile
15
GNUmakefile
@@ -84,13 +84,16 @@ endif
|
||||
|
||||
all: latest_vc latest_tcc
|
||||
ifdef WIN32
|
||||
$(CC) $(CFLAGS) -std=c99 -municode -w -o $(V) $(VC)/$(VCFILE) $(LDFLAGS)
|
||||
$(V) -o v2.exe $(VFLAGS) cmd/v
|
||||
move /y v2.exe v.exe
|
||||
$(CC) $(CFLAGS) -std=c99 -municode -w -I ./thirdparty/stdatomic/nix -o v1.exe $(VC)/$(VCFILE) $(LDFLAGS)
|
||||
v1.exe -no-parallel -o v2.exe $(VFLAGS) cmd/v
|
||||
v2.exe -o $(V) $(VFLAGS) cmd/v
|
||||
del v1.exe
|
||||
del v2.exe
|
||||
else
|
||||
$(CC) $(CFLAGS) -std=gnu99 -w -o $(V) $(VC)/$(VCFILE) -lm -lpthread $(LDFLAGS)
|
||||
$(V) -o v2.exe $(VFLAGS) cmd/v
|
||||
mv -f v2.exe v
|
||||
$(CC) $(CFLAGS) -std=gnu99 -w -I ./thirdparty/stdatomic/nix -o v1.exe $(VC)/$(VCFILE) -lm -lpthread $(LDFLAGS)
|
||||
./v1.exe -no-parallel -o v2.exe $(VFLAGS) cmd/v
|
||||
./v2.exe -o $(V) $(VFLAGS) cmd/v
|
||||
rm -rf v1.exe v2.exe
|
||||
endif
|
||||
@echo "V has been successfully built"
|
||||
@$(V) -version
|
||||
|
||||
7
Makefile
7
Makefile
@@ -1,8 +1,11 @@
|
||||
CC ?= cc
|
||||
VFLAGS ?=
|
||||
|
||||
all:
|
||||
rm -rf vc/
|
||||
git clone --depth 1 --quiet https://github.com/vlang/vc
|
||||
$(CC) -std=gnu11 -w -o v vc/v.c -lm -lexecinfo
|
||||
rm -rf vc/
|
||||
$(CC) -std=gnu11 -w -I ./thirdparty/stdatomic/nix -o v1 vc/v.c -lm -lexecinfo -lpthread
|
||||
./v1 -no-parallel -o v2 $(VFLAGS) cmd/v
|
||||
./v2 -o v $(VFLAGS) cmd/v
|
||||
rm -rf v1 v2 vc/
|
||||
@echo "V has been successfully built"
|
||||
|
||||
16
README.md
16
README.md
@@ -29,19 +29,19 @@
|
||||
- Fast compilation: ≈110k loc/s with a Clang backend,
|
||||
≈1 million loc/s with native and tcc backends *(Intel i5-7500, SSD, no optimization)* ([demo video](https://www.youtube.com/watch?v=pvP6wmcl_Sc))
|
||||
- Easy to develop: V compiles itself in less than a second
|
||||
- Performance: as fast as C (V's main backend compiles to human readable C)
|
||||
- Performance: as fast as C (V's main backend compiles to human-readable C)
|
||||
- Safety: no null, no globals, no undefined behavior, immutability by default
|
||||
- C to V translation
|
||||
- Hot code reloading
|
||||
- [Innovative memory management](https://vlang.io/#memory) ([demo video](https://www.youtube.com/watch?v=gmB8ea8uLsM))
|
||||
- [Cross-platform UI library](https://github.com/vlang/ui)
|
||||
- Built-in graphics library
|
||||
- Easy cross compilation
|
||||
- Easy cross-compilation
|
||||
- REPL
|
||||
- [Built-in ORM](https://github.com/vlang/v/blob/master/doc/docs.md#orm)
|
||||
- [Built-in web framework](https://github.com/vlang/v/blob/master/vlib/vweb/README.md)
|
||||
- C and JavaScript backends
|
||||
- Great for writing low level software ([Vinix OS](https://github.com/vlang/vinix))
|
||||
- Great for writing low-level software ([Vinix OS](https://github.com/vlang/vinix))
|
||||
|
||||
## Stability guarantee and future changes
|
||||
|
||||
@@ -112,7 +112,7 @@ sudo ./v symlink
|
||||
```
|
||||
|
||||
On Windows, start a new shell with administrative privileges, for
|
||||
example by <kbd>Windows Key</kbd>, then type `cmd.exe`, right click on its menu
|
||||
example by <kbd>Windows Key</kbd>, then type `cmd.exe`, right-click on its menu
|
||||
entry, and choose `Run as administrator`. In the new administrative
|
||||
shell, cd to the path, where you have compiled v.exe, then type:
|
||||
|
||||
@@ -125,7 +125,7 @@ Please restart your shell/editor after that, so that it can pick
|
||||
the new PATH variable.
|
||||
|
||||
NB: there is no need to run `v symlink` more than once - v will
|
||||
continue to be available, even after `v up`, restarts and so on.
|
||||
continue to be available, even after `v up`, restarts, and so on.
|
||||
You only need to run it again, if you decide to move the V repo
|
||||
folder somewhere else.
|
||||
|
||||
@@ -184,7 +184,9 @@ v run tetris/tetris.v
|
||||
NB: In order to build Tetris or 2048 (or anything else using `sokol` or `gg` graphics modules)
|
||||
on some Linux systems, you need to install `libxi-dev` and `libxcursor-dev` .
|
||||
|
||||
If you plan to use the http package, you also need to install OpenSSL on non-Windows systems.
|
||||
## V net.http, net.websocket, `v install`
|
||||
If you plan to use the net.http module, or the net.websocket module, you also need to install
|
||||
OpenSSL on non-Windows systems:
|
||||
|
||||
```bash
|
||||
macOS:
|
||||
@@ -266,7 +268,7 @@ https://github.com/vlang/gitly
|
||||
|
||||
## Vinix, an OS/kernel written in V
|
||||
|
||||
V is great for writing low level software like drivers and kernels.
|
||||
V is great for writing low-level software like drivers and kernels.
|
||||
Vinix is an OS/kernel that already runs bash, GCC, V, and nano.
|
||||
|
||||
https://github.com/vlang/vinix
|
||||
|
||||
@@ -15,11 +15,12 @@
|
||||
- [x] iOS/Android support
|
||||
- [ ] parallel parser
|
||||
- [ ] parallel checker
|
||||
- [ ] parallel cgen
|
||||
- [x] parallel cgen
|
||||
- [ ] parallel C compilation
|
||||
- [ ] `recover()` from panics
|
||||
- [x] IO streams
|
||||
- [x] struct embedding
|
||||
- [ ] interface embedding
|
||||
- [x] interface embedding
|
||||
- [x] interfaces: allow struct fields (not just methods)
|
||||
- [ ] vfmt: fix common errors automatically (make vars mutable and vice versa, add missing imports)
|
||||
- [ ] method expressions with an explicit receiver as the first argument
|
||||
|
||||
11
cmd/tools/builders/c_builder.v
Normal file
11
cmd/tools/builders/c_builder.v
Normal file
@@ -0,0 +1,11 @@
|
||||
module main
|
||||
|
||||
import v.builder.cbuilder
|
||||
|
||||
// TODO: change bootstrapping to use the C code generated from
|
||||
// `VEXE=v cmd/tools/builders/c_builder -os cross -o c.c cmd/tools/builders/c_builder.v`
|
||||
// See also `cmd/v/v.v`
|
||||
|
||||
fn main() {
|
||||
cbuilder.start()
|
||||
}
|
||||
7
cmd/tools/builders/interpret_builder.v
Normal file
7
cmd/tools/builders/interpret_builder.v
Normal file
@@ -0,0 +1,7 @@
|
||||
module main
|
||||
|
||||
import v.builder.interpreterbuilder
|
||||
|
||||
fn main() {
|
||||
interpreterbuilder.start()
|
||||
}
|
||||
7
cmd/tools/builders/js_builder.v
Normal file
7
cmd/tools/builders/js_builder.v
Normal file
@@ -0,0 +1,7 @@
|
||||
module main
|
||||
|
||||
import v.builder.jsbuilder
|
||||
|
||||
fn main() {
|
||||
jsbuilder.start()
|
||||
}
|
||||
7
cmd/tools/builders/native_builder.v
Normal file
7
cmd/tools/builders/native_builder.v
Normal file
@@ -0,0 +1,7 @@
|
||||
module main
|
||||
|
||||
import v.builder.nativebuilder
|
||||
|
||||
fn main() {
|
||||
nativebuilder.start()
|
||||
}
|
||||
@@ -5,6 +5,7 @@ import v.util
|
||||
import v.util.diff
|
||||
import v.pref
|
||||
import v.builder
|
||||
import v.builder.cbuilder
|
||||
import v.ast
|
||||
import rand
|
||||
import term
|
||||
@@ -98,7 +99,7 @@ fn (app App) gen_api_for_module_in_os(mod_name string, os_name string) string {
|
||||
tmpname := '/tmp/${mod_name}_${os_name}.c'
|
||||
prefs, _ := pref.parse_args([], ['-os', os_name, '-o', tmpname, '-shared', mpath])
|
||||
mut b := builder.new_builder(prefs)
|
||||
b.compile_c()
|
||||
cbuilder.compile_c(mut b)
|
||||
mut res := []string{}
|
||||
for f in b.parsed_files {
|
||||
for s in f.stmts {
|
||||
|
||||
@@ -21,11 +21,13 @@ fn main() {
|
||||
println('fast.html generator needs to be located in `v/cmd/tools/fast`')
|
||||
}
|
||||
println('fast.html generator\n')
|
||||
println('Fetching updates...')
|
||||
ret := os.system('$vdir/v up')
|
||||
if ret != 0 {
|
||||
println('failed to update V')
|
||||
return
|
||||
if !os.args.contains('-noupdate') {
|
||||
println('Fetching updates...')
|
||||
ret := os.system('$vdir/v up')
|
||||
if ret != 0 {
|
||||
println('failed to update V')
|
||||
return
|
||||
}
|
||||
}
|
||||
// Fetch the last commit's hash
|
||||
commit := exec('git rev-parse HEAD')[..8]
|
||||
@@ -55,7 +57,6 @@ fn main() {
|
||||
} else {
|
||||
exec('./v -o vprod -prod -prealloc cmd/v')
|
||||
}
|
||||
// println('cur vdir="$vdir"')
|
||||
// cache vlib modules
|
||||
exec('$vdir/v wipe-cache')
|
||||
exec('$vdir/v -o v2 -prod cmd/v')
|
||||
|
||||
@@ -7,14 +7,25 @@ import benchmark
|
||||
import sync.pool
|
||||
import v.pref
|
||||
import v.util.vtest
|
||||
import runtime
|
||||
|
||||
const github_job = os.getenv('GITHUB_JOB')
|
||||
pub const github_job = os.getenv('GITHUB_JOB')
|
||||
|
||||
const show_start = os.getenv('VTEST_SHOW_START') == '1'
|
||||
pub const show_start = os.getenv('VTEST_SHOW_START') == '1'
|
||||
|
||||
const hide_skips = os.getenv('VTEST_HIDE_SKIP') == '1'
|
||||
pub const hide_skips = os.getenv('VTEST_HIDE_SKIP') == '1'
|
||||
|
||||
const hide_oks = os.getenv('VTEST_HIDE_OK') == '1'
|
||||
pub const hide_oks = os.getenv('VTEST_HIDE_OK') == '1'
|
||||
|
||||
pub const fail_fast = os.getenv('VTEST_FAIL_FAST') == '1'
|
||||
|
||||
pub const test_only = os.getenv('VTEST_ONLY').split_any(',')
|
||||
|
||||
pub const test_only_fn = os.getenv('VTEST_ONLY_FN').split_any(',')
|
||||
|
||||
pub const is_node_present = os.execute('node --version').exit_code == 0
|
||||
|
||||
pub const all_processes = os.execute('ps ax').output.split_any('\r\n')
|
||||
|
||||
pub struct TestSession {
|
||||
pub mut:
|
||||
@@ -25,6 +36,7 @@ pub mut:
|
||||
vtmp_dir string
|
||||
vargs string
|
||||
failed bool
|
||||
fail_fast bool
|
||||
benchmark benchmark.Benchmark
|
||||
rm_binaries bool = true
|
||||
silent_mode bool
|
||||
@@ -185,6 +197,7 @@ pub fn new_test_session(_vargs string, will_compile bool) TestSession {
|
||||
vexe: vexe
|
||||
vroot: vroot
|
||||
skip_files: skip_files
|
||||
fail_fast: testing.fail_fast
|
||||
vargs: vargs
|
||||
vtmp_dir: new_vtmp_dir
|
||||
silent_mode: _vargs.contains('-silent')
|
||||
@@ -233,6 +246,7 @@ pub fn (mut ts TestSession) test() {
|
||||
remaining_files = vtest.filter_vtest_only(remaining_files, fix_slashes: false)
|
||||
ts.files = remaining_files
|
||||
ts.benchmark.set_total_expected_steps(remaining_files.len)
|
||||
ts.benchmark.njobs = runtime.nr_jobs()
|
||||
mut pool_of_test_runners := pool.new_pool_processor(callback: worker_trunner)
|
||||
// for handling messages across threads
|
||||
ts.nmessages = chan LogMessage{cap: 10000}
|
||||
@@ -248,7 +262,7 @@ pub fn (mut ts TestSession) test() {
|
||||
// cleanup generated .tmp.c files after successfull tests:
|
||||
if ts.benchmark.nfail == 0 {
|
||||
if ts.rm_binaries {
|
||||
os.rmdir_all(ts.vtmp_dir) or { panic(err) }
|
||||
os.rmdir_all(ts.vtmp_dir) or {}
|
||||
}
|
||||
}
|
||||
ts.show_list_of_failed_tests()
|
||||
@@ -256,6 +270,11 @@ pub fn (mut ts TestSession) test() {
|
||||
|
||||
fn worker_trunner(mut p pool.PoolProcessor, idx int, thread_id int) voidptr {
|
||||
mut ts := &TestSession(p.get_shared_context())
|
||||
if ts.fail_fast {
|
||||
if ts.failed {
|
||||
return pool.no_result
|
||||
}
|
||||
}
|
||||
tmpd := ts.vtmp_dir
|
||||
show_stats := '-stats' in ts.vargs.split(' ')
|
||||
// tls_bench is used to format the step messages/timings
|
||||
@@ -266,9 +285,21 @@ fn worker_trunner(mut p pool.PoolProcessor, idx int, thread_id int) voidptr {
|
||||
p.set_thread_context(idx, tls_bench)
|
||||
}
|
||||
tls_bench.no_cstep = true
|
||||
tls_bench.njobs = ts.benchmark.njobs
|
||||
mut relative_file := os.real_path(p.get_item<string>(idx))
|
||||
mut cmd_options := [ts.vargs]
|
||||
if relative_file.contains('global') && !ts.vargs.contains('fmt') {
|
||||
mut run_js := false
|
||||
|
||||
is_fmt := ts.vargs.contains('fmt')
|
||||
|
||||
if relative_file.ends_with('js.v') {
|
||||
if !is_fmt {
|
||||
cmd_options << ' -b js'
|
||||
}
|
||||
run_js = true
|
||||
}
|
||||
|
||||
if relative_file.contains('global') && !is_fmt {
|
||||
cmd_options << ' -enable-globals'
|
||||
}
|
||||
if ts.root_relative {
|
||||
@@ -279,17 +310,20 @@ fn worker_trunner(mut p pool.PoolProcessor, idx int, thread_id int) voidptr {
|
||||
// Ensure that the generated binaries will be stored in the temporary folder.
|
||||
// Remove them after a test passes/fails.
|
||||
fname := os.file_name(file)
|
||||
generated_binary_fname := if os.user_os() == 'windows' {
|
||||
generated_binary_fname := if os.user_os() == 'windows' && !run_js {
|
||||
fname.replace('.v', '.exe')
|
||||
} else if !run_js {
|
||||
fname.replace('.v', '')
|
||||
} else {
|
||||
fname.replace('.v', '')
|
||||
}
|
||||
generated_binary_fpath := os.join_path(tmpd, generated_binary_fname)
|
||||
generated_binary_fpath := os.join_path_single(tmpd, generated_binary_fname)
|
||||
if os.exists(generated_binary_fpath) {
|
||||
if ts.rm_binaries {
|
||||
os.rm(generated_binary_fpath) or { panic(err) }
|
||||
os.rm(generated_binary_fpath) or {}
|
||||
}
|
||||
}
|
||||
|
||||
if !ts.vargs.contains('fmt') {
|
||||
cmd_options << ' -o "$generated_binary_fpath"'
|
||||
}
|
||||
@@ -306,22 +340,35 @@ fn worker_trunner(mut p pool.PoolProcessor, idx int, thread_id int) voidptr {
|
||||
}
|
||||
if show_stats {
|
||||
ts.append_message(.ok, term.h_divider('-'))
|
||||
status := os.system(cmd)
|
||||
if status == 0 {
|
||||
ts.benchmark.ok()
|
||||
tls_bench.ok()
|
||||
} else {
|
||||
mut status := os.system(cmd)
|
||||
if status != 0 {
|
||||
details := get_test_details(file)
|
||||
os.setenv('VTEST_RETRY_MAX', '$details.retry', true)
|
||||
for retry := 1; retry <= details.retry; retry++ {
|
||||
ts.append_message(.info, ' retrying $retry/$details.retry of $relative_file ...')
|
||||
os.setenv('VTEST_RETRY', '$retry', true)
|
||||
status = os.system(cmd)
|
||||
if status == 0 {
|
||||
unsafe {
|
||||
goto test_passed_system
|
||||
}
|
||||
}
|
||||
}
|
||||
ts.failed = true
|
||||
ts.benchmark.fail()
|
||||
tls_bench.fail()
|
||||
ts.add_failed_cmd(cmd)
|
||||
return pool.no_result
|
||||
} else {
|
||||
test_passed_system:
|
||||
ts.benchmark.ok()
|
||||
tls_bench.ok()
|
||||
}
|
||||
} else {
|
||||
if testing.show_start {
|
||||
ts.append_message(.info, ' starting $relative_file ...')
|
||||
}
|
||||
r := os.execute(cmd)
|
||||
mut r := os.execute(cmd)
|
||||
if r.exit_code < 0 {
|
||||
ts.failed = true
|
||||
ts.benchmark.fail()
|
||||
@@ -331,6 +378,18 @@ fn worker_trunner(mut p pool.PoolProcessor, idx int, thread_id int) voidptr {
|
||||
return pool.no_result
|
||||
}
|
||||
if r.exit_code != 0 {
|
||||
details := get_test_details(file)
|
||||
os.setenv('VTEST_RETRY_MAX', '$details.retry', true)
|
||||
for retry := 1; retry <= details.retry; retry++ {
|
||||
ts.append_message(.info, ' retrying $retry/$details.retry of $relative_file ...')
|
||||
os.setenv('VTEST_RETRY', '$retry', true)
|
||||
r = os.execute(cmd)
|
||||
if r.exit_code == 0 {
|
||||
unsafe {
|
||||
goto test_passed_execute
|
||||
}
|
||||
}
|
||||
}
|
||||
ts.failed = true
|
||||
ts.benchmark.fail()
|
||||
tls_bench.fail()
|
||||
@@ -338,6 +397,7 @@ fn worker_trunner(mut p pool.PoolProcessor, idx int, thread_id int) voidptr {
|
||||
ts.append_message(.fail, tls_bench.step_message_fail('$normalised_relative_file\n$r.output.trim_space()$ending_newline'))
|
||||
ts.add_failed_cmd(cmd)
|
||||
} else {
|
||||
test_passed_execute:
|
||||
ts.benchmark.ok()
|
||||
tls_bench.ok()
|
||||
if !testing.hide_oks {
|
||||
@@ -347,24 +407,20 @@ fn worker_trunner(mut p pool.PoolProcessor, idx int, thread_id int) voidptr {
|
||||
}
|
||||
if os.exists(generated_binary_fpath) {
|
||||
if ts.rm_binaries {
|
||||
os.rm(generated_binary_fpath) or { panic(err) }
|
||||
os.rm(generated_binary_fpath) or {}
|
||||
}
|
||||
}
|
||||
return pool.no_result
|
||||
}
|
||||
|
||||
pub fn vlib_should_be_present(parent_dir string) {
|
||||
vlib_dir := os.join_path(parent_dir, 'vlib')
|
||||
vlib_dir := os.join_path_single(parent_dir, 'vlib')
|
||||
if !os.is_dir(vlib_dir) {
|
||||
eprintln('$vlib_dir is missing, it must be next to the V executable')
|
||||
exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn v_build_failing(zargs string, folder string) bool {
|
||||
return v_build_failing_skipped(zargs, folder, [])
|
||||
}
|
||||
|
||||
pub fn prepare_test_session(zargs string, folder string, oskipped []string, main_label string) TestSession {
|
||||
vexe := pref.vexe_path()
|
||||
parent_dir := os.dir(vexe)
|
||||
@@ -375,7 +431,7 @@ pub fn prepare_test_session(zargs string, folder string, oskipped []string, main
|
||||
eprintln('v compiler args: "$vargs"')
|
||||
}
|
||||
mut session := new_test_session(vargs, true)
|
||||
files := os.walk_ext(os.join_path(parent_dir, folder), '.v')
|
||||
files := os.walk_ext(os.join_path_single(parent_dir, folder), '.v')
|
||||
mut mains := []string{}
|
||||
mut skipped := oskipped.clone()
|
||||
next_file: for f in files {
|
||||
@@ -399,7 +455,7 @@ pub fn prepare_test_session(zargs string, folder string, oskipped []string, main
|
||||
maxc := if c.len > 300 { 300 } else { c.len }
|
||||
start := c[0..maxc]
|
||||
if start.contains('module ') && !start.contains('module main') {
|
||||
skipped_f := f.replace(os.join_path(parent_dir, ''), '')
|
||||
skipped_f := f.replace(os.join_path_single(parent_dir, ''), '')
|
||||
skipped << skipped_f
|
||||
}
|
||||
for skip_prefix in oskipped {
|
||||
@@ -414,10 +470,13 @@ pub fn prepare_test_session(zargs string, folder string, oskipped []string, main
|
||||
return session
|
||||
}
|
||||
|
||||
pub fn v_build_failing_skipped(zargs string, folder string, oskipped []string) bool {
|
||||
pub type FnTestSetupCb = fn (mut session TestSession)
|
||||
|
||||
pub fn v_build_failing_skipped(zargs string, folder string, oskipped []string, cb FnTestSetupCb) bool {
|
||||
main_label := 'Building $folder ...'
|
||||
finish_label := 'building $folder'
|
||||
mut session := prepare_test_session(zargs, folder, oskipped, main_label)
|
||||
cb(mut session)
|
||||
session.test()
|
||||
eprintln(session.benchmark.total_message(finish_label))
|
||||
return session.failed
|
||||
@@ -446,8 +505,7 @@ pub fn building_any_v_binaries_failed() bool {
|
||||
mut failed := false
|
||||
v_build_commands := ['$vexe -o v_g -g cmd/v', '$vexe -o v_prod_g -prod -g cmd/v',
|
||||
'$vexe -o v_cg -cg cmd/v', '$vexe -o v_prod_cg -prod -cg cmd/v',
|
||||
'$vexe -o v_prod -prod cmd/v',
|
||||
]
|
||||
'$vexe -o v_prod -prod cmd/v']
|
||||
mut bmark := benchmark.new_benchmark()
|
||||
for cmd in v_build_commands {
|
||||
bmark.step()
|
||||
@@ -484,3 +542,28 @@ pub fn setup_new_vtmp_folder() string {
|
||||
os.setenv('VTMP', new_vtmp_dir, true)
|
||||
return new_vtmp_dir
|
||||
}
|
||||
|
||||
pub struct TestDetails {
|
||||
pub mut:
|
||||
retry int
|
||||
}
|
||||
|
||||
pub fn get_test_details(file string) TestDetails {
|
||||
mut res := TestDetails{}
|
||||
lines := os.read_lines(file) or { [] }
|
||||
for line in lines {
|
||||
if line.starts_with('// vtest retry:') {
|
||||
res.retry = line.all_after(':').trim_space().int()
|
||||
}
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
pub fn find_started_process(pname string) ?string {
|
||||
for line in testing.all_processes {
|
||||
if line.contains(pname) {
|
||||
return line
|
||||
}
|
||||
}
|
||||
return error('could not find process matching $pname')
|
||||
}
|
||||
|
||||
@@ -76,7 +76,7 @@ pub fn prepare_vc_source(vcdir string, cdir string, commit string) (string, stri
|
||||
|
||||
pub fn clone_or_pull(remote_git_url string, local_worktree_path string) {
|
||||
// NB: after clone_or_pull, the current repo branch is === HEAD === master
|
||||
if os.is_dir(local_worktree_path) && os.is_dir(os.join_path(local_worktree_path, '.git')) {
|
||||
if os.is_dir(local_worktree_path) && os.is_dir(os.join_path_single(local_worktree_path, '.git')) {
|
||||
// Already existing ... Just pulling in this case is faster usually.
|
||||
scripting.run('git -C "$local_worktree_path" checkout --quiet master')
|
||||
scripting.run('git -C "$local_worktree_path" pull --quiet ')
|
||||
@@ -107,14 +107,14 @@ pub mut:
|
||||
|
||||
pub fn (mut vgit_context VGitContext) compile_oldv_if_needed() {
|
||||
vgit_context.vexename = if os.user_os() == 'windows' { 'v.exe' } else { 'v' }
|
||||
vgit_context.vexepath = os.real_path(os.join_path(vgit_context.path_v, vgit_context.vexename))
|
||||
vgit_context.vexepath = os.real_path(os.join_path_single(vgit_context.path_v, vgit_context.vexename))
|
||||
mut command_for_building_v_from_c_source := ''
|
||||
mut command_for_selfbuilding := ''
|
||||
if 'windows' == os.user_os() {
|
||||
command_for_building_v_from_c_source = '$vgit_context.cc -std=c99 -municode -w -o cv.exe "$vgit_context.path_vc/v_win.c" '
|
||||
command_for_building_v_from_c_source = '$vgit_context.cc -std=c99 -I ./thirdparty/stdatomic/win -municode -w -o cv.exe "$vgit_context.path_vc/v_win.c" '
|
||||
command_for_selfbuilding = './cv.exe -o $vgit_context.vexename {SOURCE}'
|
||||
} else {
|
||||
command_for_building_v_from_c_source = '$vgit_context.cc -std=gnu11 -w -o cv "$vgit_context.path_vc/v.c" -lm -lpthread'
|
||||
command_for_building_v_from_c_source = '$vgit_context.cc -std=gnu11 -I ./thirdparty/stdatomic/nix -w -o cv "$vgit_context.path_vc/v.c" -lm -lpthread'
|
||||
command_for_selfbuilding = './cv -o $vgit_context.vexename {SOURCE}'
|
||||
}
|
||||
scripting.chdir(vgit_context.workdir)
|
||||
|
||||
@@ -123,7 +123,7 @@ fn main() {
|
||||
}
|
||||
should_sync := fp.bool('cache-sync', `s`, false, 'Update the local cache')
|
||||
if !should_sync {
|
||||
fp.limit_free_args(1, 1)
|
||||
fp.limit_free_args(1, 1) ?
|
||||
}
|
||||
////
|
||||
context.cleanup = fp.bool('clean', 0, false, 'Clean before running (slower).')
|
||||
@@ -171,6 +171,9 @@ fn main() {
|
||||
}
|
||||
scripting.cprint_strong('# result: ')
|
||||
print(cmdres.output)
|
||||
if !cmdres.output.ends_with('\n') {
|
||||
println('')
|
||||
}
|
||||
exit(cmdres.exit_code)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,15 +56,18 @@ fn (c Context) compare_versions() {
|
||||
'v @DEBUG@ -o source.c examples/hello_world.v',
|
||||
'v -o source.c examples/hello_world.v',
|
||||
])
|
||||
perf_files << c.compare_v_performance('source_v', ['vprod @DEBUG@ -o source.c @COMPILER@',
|
||||
'vprod -o source.c @COMPILER@', 'v @DEBUG@ -o source.c @COMPILER@',
|
||||
perf_files << c.compare_v_performance('source_v', [
|
||||
'vprod @DEBUG@ -o source.c @COMPILER@',
|
||||
'vprod -o source.c @COMPILER@',
|
||||
'v @DEBUG@ -o source.c @COMPILER@',
|
||||
'v -o source.c @COMPILER@',
|
||||
])
|
||||
perf_files << c.compare_v_performance('binary_hello', [
|
||||
'vprod -o hello examples/hello_world.v',
|
||||
'v -o hello examples/hello_world.v',
|
||||
])
|
||||
perf_files << c.compare_v_performance('binary_v', ['vprod -o binary @COMPILER@',
|
||||
perf_files << c.compare_v_performance('binary_v', [
|
||||
'vprod -o binary @COMPILER@',
|
||||
'v -o binary @COMPILER@',
|
||||
])
|
||||
println('All performance files:')
|
||||
@@ -107,8 +110,7 @@ fn (c &Context) prepare_v(cdir string, commit string) {
|
||||
scripting.show_sizes_of_files(['$cdir/cv', '$cdir/cv_stripped', '$cdir/cv_stripped_upxed'])
|
||||
scripting.show_sizes_of_files(['$cdir/v', '$cdir/v_stripped', '$cdir/v_stripped_upxed'])
|
||||
scripting.show_sizes_of_files(['$cdir/vprod', '$cdir/vprod_stripped',
|
||||
'$cdir/vprod_stripped_upxed',
|
||||
])
|
||||
'$cdir/vprod_stripped_upxed'])
|
||||
vversion := scripting.run('$cdir/v -version')
|
||||
vcommit := scripting.run('git rev-parse --short --verify HEAD')
|
||||
println('V version is: $vversion , local source commit: $vcommit')
|
||||
@@ -192,7 +194,7 @@ fn main() {
|
||||
fp.description(tool_description)
|
||||
fp.arguments_description('COMMIT_BEFORE [COMMIT_AFTER]')
|
||||
fp.skip_executable()
|
||||
fp.limit_free_args(1, 2)
|
||||
fp.limit_free_args(1, 2) ?
|
||||
context.vflags = fp.string('vflags', 0, '', 'Additional options to pass to the v commands, for example "-cc tcc"')
|
||||
context.hyperfineopts = fp.string('hyperfine_options', 0, '', 'Additional options passed to hyperfine.
|
||||
${flag.space}For example on linux, you may want to pass:
|
||||
|
||||
@@ -143,19 +143,19 @@ const (
|
||||
|
||||
fn main() {
|
||||
mut context := Context{}
|
||||
context.parse_options()
|
||||
context.parse_options() ?
|
||||
context.run()
|
||||
context.show_diff_summary()
|
||||
}
|
||||
|
||||
fn (mut context Context) parse_options() {
|
||||
fn (mut context Context) parse_options() ? {
|
||||
mut fp := flag.new_flag_parser(os.args)
|
||||
fp.application(os.file_name(os.executable()))
|
||||
fp.version('0.0.1')
|
||||
fp.description('Repeat command(s) and collect statistics. NB: you have to quote each command, if it contains spaces.')
|
||||
fp.arguments_description('CMD1 CMD2 ...')
|
||||
fp.skip_executable()
|
||||
fp.limit_free_args_to_at_least(1)
|
||||
fp.limit_free_args_to_at_least(1) ?
|
||||
context.count = fp.int('count', `c`, 10, 'Repetition count.')
|
||||
context.series = fp.int('series', `s`, 2, 'Series count. `-s 2 -c 4 a b` => aaaabbbbaaaabbbb, while `-s 3 -c 2 a b` => aabbaabbaabb.')
|
||||
context.warmup = fp.int('warmup', `w`, 2, 'Warmup runs. These are done *only at the start*, and are ignored.')
|
||||
|
||||
@@ -40,24 +40,31 @@ fn cleanup_tdir() {
|
||||
os.rmdir_all(tdir) or { eprintln(err) }
|
||||
}
|
||||
|
||||
fn create_test(tname string, tcontent string) ?string {
|
||||
tpath := os.join_path(tdir, tname)
|
||||
os.write_file(tpath, tcontent) ?
|
||||
eprintln('>>>>>>>> tpath: $tpath | tcontent: $tcontent')
|
||||
return tpath
|
||||
}
|
||||
|
||||
fn main() {
|
||||
defer {
|
||||
os.chdir(os.wd_at_startup) or {}
|
||||
}
|
||||
println('> vroot: $vroot | vexe: $vexe | tdir: $tdir')
|
||||
ok_fpath := os.join_path(tdir, 'single_test.v')
|
||||
os.write_file(ok_fpath, 'fn test_ok(){ assert true }') ?
|
||||
check_ok('"$vexe" $ok_fpath')
|
||||
check_ok('"$vexe" test $ok_fpath')
|
||||
fail_fpath := os.join_path(tdir, 'failing_test.v')
|
||||
os.write_file(fail_fpath, 'fn test_fail(){ assert 1 == 2 }') ?
|
||||
check_fail('"$vexe" $fail_fpath')
|
||||
check_fail('"$vexe" test $fail_fpath')
|
||||
check_fail('"$vexe" test $tdir')
|
||||
ok_fpath := create_test('a_single_ok_test.v', 'fn test_ok(){ assert true }') ?
|
||||
check_ok('"$vexe" "$ok_fpath"')
|
||||
check_ok('"$vexe" test "$ok_fpath"')
|
||||
check_ok('"$vexe" test "$tdir"')
|
||||
fail_fpath := create_test('a_single_failing_test.v', 'fn test_fail(){ assert 1 == 2 }') ?
|
||||
check_fail('"$vexe" "$fail_fpath"')
|
||||
check_fail('"$vexe" test "$fail_fpath"')
|
||||
check_fail('"$vexe" test "$tdir"')
|
||||
rel_dir := os.join_path(tdir, rand.ulid())
|
||||
os.mkdir(rel_dir) ?
|
||||
os.chdir(rel_dir) ?
|
||||
check_ok('"$vexe" test ..${os.path_separator + os.base(ok_fpath)}')
|
||||
check_ok('"$vexe" test "..${os.path_separator + os.base(ok_fpath)}"')
|
||||
println('> all done')
|
||||
}
|
||||
|
||||
fn check_ok(cmd string) string {
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -105,6 +105,7 @@ fn main() {
|
||||
eprintln('v bug: no v file listed to report')
|
||||
exit(1)
|
||||
}
|
||||
os.unsetenv('VCOLORS')
|
||||
// collect error information
|
||||
// output from `v doctor`
|
||||
vdoctor_output := get_vdoctor_output(is_verbose)
|
||||
|
||||
@@ -3,13 +3,28 @@ module main
|
||||
import os
|
||||
import testing
|
||||
|
||||
const vroot = @VMODROOT
|
||||
|
||||
const efolders = [
|
||||
'examples/viewer',
|
||||
]
|
||||
|
||||
fn main() {
|
||||
args_string := os.args[1..].join(' ')
|
||||
params := args_string.all_before('build-examples')
|
||||
if testing.v_build_failing(params, 'examples') {
|
||||
skip_prefixes := efolders.map(os.real_path(os.join_path_single(vroot, it)))
|
||||
res := testing.v_build_failing_skipped(params, 'examples', skip_prefixes, fn (mut session testing.TestSession) {
|
||||
for x in efolders {
|
||||
pathsegments := x.split_any('/')
|
||||
session.add(os.real_path(os.join_path(vroot, ...pathsegments)))
|
||||
}
|
||||
})
|
||||
if res {
|
||||
exit(1)
|
||||
}
|
||||
if testing.v_build_failing(params + '-live', os.join_path('examples', 'hot_reload')) {
|
||||
if testing.v_build_failing_skipped(params + '-live', os.join_path_single('examples',
|
||||
'hot_reload'), skip_prefixes, fn (mut session testing.TestSession) {})
|
||||
{
|
||||
exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,6 +56,10 @@ fn main() {
|
||||
}
|
||||
//
|
||||
tpath := os.join_path(session.vtmp_dir, texe)
|
||||
if texe.ends_with('_builder') || texe.ends_with('_builder.exe') {
|
||||
os.mv_by_cp(tpath, os.join_path(tfolder, 'builders', texe)) or { panic(err) }
|
||||
continue
|
||||
}
|
||||
if tname in tools_in_subfolders {
|
||||
os.mv_by_cp(tpath, os.join_path(tfolder, tname, texe)) or { panic(err) }
|
||||
continue
|
||||
|
||||
188
cmd/tools/vbump.v
Normal file
188
cmd/tools/vbump.v
Normal file
@@ -0,0 +1,188 @@
|
||||
// Copyright (c) 2019-2021 Subhomoy Haldar. All rights reserved.
|
||||
// Use of this source code is governed by an MIT license that can be found in the LICENSE file.
|
||||
module main
|
||||
|
||||
import flag
|
||||
import os
|
||||
import regex
|
||||
import semver
|
||||
|
||||
const (
|
||||
tool_name = os.file_name(os.executable())
|
||||
tool_version = '0.0.1'
|
||||
tool_description = '\n Bump the semantic version of the v.mod and/or specified files.
|
||||
|
||||
The first instance of a version number is replaced with the new version.
|
||||
Additionally, the line affected must contain the word "version" in any
|
||||
form of capitalization. For instance, the following lines will be
|
||||
recognized by the heuristic:
|
||||
|
||||
tool_version = \'1.2.1\'
|
||||
version: \'0.2.42\'
|
||||
VERSION = "1.23.8"
|
||||
|
||||
Examples:
|
||||
Bump the patch version in v.mod if it exists
|
||||
v bump --patch
|
||||
Bump the major version in v.mod and vls.v
|
||||
v bump --major v.mod vls.v
|
||||
Upgrade the minor version in sample.v only
|
||||
v bump --minor sample.v
|
||||
'
|
||||
semver_query = r'((0)|([1-9]\d*)\.){2}(0)|([1-9]\d*)(\-[\w\d\.\-_]+)?(\+[\w\d\.\-_]+)?'
|
||||
)
|
||||
|
||||
struct Options {
|
||||
show_help bool
|
||||
major bool
|
||||
minor bool
|
||||
patch bool
|
||||
}
|
||||
|
||||
type ReplacementFunction = fn (re regex.RE, input string, start int, end int) string
|
||||
|
||||
fn replace_with_increased_patch_version(re regex.RE, input string, start int, end int) string {
|
||||
version := semver.from(input[start..end]) or { return input }
|
||||
return version.increment(.patch).str()
|
||||
}
|
||||
|
||||
fn replace_with_increased_minor_version(re regex.RE, input string, start int, end int) string {
|
||||
version := semver.from(input[start..end]) or { return input }
|
||||
return version.increment(.minor).str()
|
||||
}
|
||||
|
||||
fn replace_with_increased_major_version(re regex.RE, input string, start int, end int) string {
|
||||
version := semver.from(input[start..end]) or { return input }
|
||||
return version.increment(.major).str()
|
||||
}
|
||||
|
||||
fn get_replacement_function(options Options) ReplacementFunction {
|
||||
if options.patch {
|
||||
return replace_with_increased_patch_version
|
||||
} else if options.minor {
|
||||
return replace_with_increased_minor_version
|
||||
} else if options.major {
|
||||
return replace_with_increased_major_version
|
||||
}
|
||||
return replace_with_increased_patch_version
|
||||
}
|
||||
|
||||
fn process_file(input_file string, options Options) {
|
||||
lines := os.read_lines(input_file) or { panic('Failed to read file: $input_file') }
|
||||
|
||||
mut re := regex.regex_opt(semver_query) or { panic('Could not create a RegEx parser.') }
|
||||
|
||||
repl_fn := get_replacement_function(options)
|
||||
|
||||
mut new_lines := []string{cap: lines.len}
|
||||
mut replacement_complete := false
|
||||
|
||||
for line in lines {
|
||||
// Copy over the remaining lines normally if the replacement is complete
|
||||
if replacement_complete {
|
||||
new_lines << line
|
||||
continue
|
||||
}
|
||||
|
||||
// Check if replacement is necessary
|
||||
updated_line := if line.to_lower().contains('version') {
|
||||
replacement_complete = true
|
||||
re.replace_by_fn(line, repl_fn)
|
||||
} else {
|
||||
line
|
||||
}
|
||||
new_lines << updated_line
|
||||
}
|
||||
|
||||
// Add a trailing newline
|
||||
new_lines << ''
|
||||
|
||||
backup_file := input_file + '.cache'
|
||||
|
||||
// Remove the backup file if it exists.
|
||||
os.rm(backup_file) or {}
|
||||
|
||||
// Rename the original to the backup.
|
||||
os.mv(input_file, backup_file) or { panic('Failed to copy file: $input_file') }
|
||||
|
||||
// Process the old file and write it back to the original.
|
||||
os.write_file(input_file, new_lines.join_lines()) or {
|
||||
panic('Failed to write file: $input_file')
|
||||
}
|
||||
|
||||
// Remove the backup file.
|
||||
os.rm(backup_file) or {}
|
||||
|
||||
if replacement_complete {
|
||||
println('Bumped version in $input_file')
|
||||
} else {
|
||||
println('No changes made in $input_file')
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
if os.args.len < 2 {
|
||||
println('Usage: $tool_name [options] [file1 file2 ...]
|
||||
$tool_description
|
||||
Try $tool_name -h for more help...')
|
||||
exit(1)
|
||||
}
|
||||
|
||||
mut fp := flag.new_flag_parser(os.args)
|
||||
|
||||
fp.application(tool_name)
|
||||
fp.version(tool_version)
|
||||
fp.description(tool_description)
|
||||
fp.arguments_description('[file1 file2 ...]')
|
||||
fp.skip_executable()
|
||||
|
||||
options := Options{
|
||||
show_help: fp.bool('help', `h`, false, 'Show this help text.')
|
||||
patch: fp.bool('patch', `p`, false, 'Bump the patch version.')
|
||||
minor: fp.bool('minor', `n`, false, 'Bump the minor version.')
|
||||
major: fp.bool('major', `m`, false, 'Bump the major version.')
|
||||
}
|
||||
|
||||
if options.show_help {
|
||||
println(fp.usage())
|
||||
exit(0)
|
||||
}
|
||||
|
||||
validate_options(options) or { panic(err) }
|
||||
|
||||
files := os.args[3..]
|
||||
|
||||
if files.len == 0 {
|
||||
if !os.exists('v.mod') {
|
||||
println('v.mod does not exist. You can create one using "v init".')
|
||||
exit(1)
|
||||
}
|
||||
process_file('v.mod', options)
|
||||
}
|
||||
|
||||
for input_file in files {
|
||||
if !os.exists(input_file) {
|
||||
println('File not found: $input_file')
|
||||
exit(1)
|
||||
}
|
||||
process_file(input_file, options)
|
||||
}
|
||||
}
|
||||
|
||||
fn validate_options(options Options) ? {
|
||||
if options.patch && options.major {
|
||||
return error('Cannot specify both --patch and --major.')
|
||||
}
|
||||
|
||||
if options.patch && options.minor {
|
||||
return error('Cannot specify both --patch and --minor.')
|
||||
}
|
||||
|
||||
if options.major && options.minor {
|
||||
return error('Cannot specify both --major and --minor.')
|
||||
}
|
||||
|
||||
if !(options.patch || options.major || options.minor) {
|
||||
return error('Must specify one of --patch, --major, or --minor.')
|
||||
}
|
||||
}
|
||||
95
cmd/tools/vbump_test.v
Normal file
95
cmd/tools/vbump_test.v
Normal file
@@ -0,0 +1,95 @@
|
||||
import os
|
||||
|
||||
struct BumpTestCase {
|
||||
file_name string
|
||||
contents string
|
||||
line int
|
||||
expected_patch string
|
||||
expected_minor string
|
||||
expected_major string
|
||||
}
|
||||
|
||||
const test_cases = [
|
||||
BumpTestCase{
|
||||
file_name: 'v.mod'
|
||||
contents: "Module {
|
||||
name: 'Sample'
|
||||
description: 'Sample project'
|
||||
version: '1.2.6'
|
||||
license: 'MIT'
|
||||
dependencies: []
|
||||
}
|
||||
|
||||
"
|
||||
line: 3
|
||||
expected_patch: " version: '1.2.7'"
|
||||
expected_minor: " version: '1.3.0'"
|
||||
expected_major: " version: '2.0.0'"
|
||||
},
|
||||
BumpTestCase{
|
||||
file_name: 'random_versions.vv'
|
||||
contents: "
|
||||
1.1.2
|
||||
1.2.5
|
||||
3.21.73
|
||||
version = '1.5.1'
|
||||
|
||||
"
|
||||
line: 4
|
||||
expected_patch: "version = '1.5.2'"
|
||||
expected_minor: "version = '1.6.0'"
|
||||
expected_major: "version = '2.0.0'"
|
||||
},
|
||||
BumpTestCase{
|
||||
file_name: 'sample_tool.v'
|
||||
contents: "// Module comment and copyright information
|
||||
import os
|
||||
import flag
|
||||
|
||||
const (
|
||||
tool_name = os.file_name(os.executable())
|
||||
tool_version = '0.1.33'
|
||||
)
|
||||
fn main() {
|
||||
// stuff
|
||||
}
|
||||
"
|
||||
line: 6
|
||||
expected_patch: " tool_version = '0.1.34'"
|
||||
expected_minor: " tool_version = '0.2.0'"
|
||||
expected_major: " tool_version = '1.0.0'"
|
||||
},
|
||||
]
|
||||
|
||||
fn run_individual_test(case BumpTestCase) ? {
|
||||
vexe := @VEXE
|
||||
|
||||
temp_dir := os.temp_dir()
|
||||
test_file := os.join_path_single(temp_dir, case.file_name)
|
||||
|
||||
os.rm(test_file) or {}
|
||||
os.write_file(test_file, case.contents) ?
|
||||
|
||||
{
|
||||
os.execute_or_exit('$vexe bump --patch $test_file')
|
||||
patch_lines := os.read_lines(test_file) ?
|
||||
assert patch_lines[case.line] == case.expected_patch
|
||||
}
|
||||
{
|
||||
os.execute_or_exit('$vexe bump --minor $test_file')
|
||||
minor_lines := os.read_lines(test_file) ?
|
||||
assert minor_lines[case.line] == case.expected_minor
|
||||
}
|
||||
{
|
||||
os.execute_or_exit('$vexe bump --major $test_file')
|
||||
major_lines := os.read_lines(test_file) ?
|
||||
assert major_lines[case.line] == case.expected_major
|
||||
}
|
||||
os.rm(test_file) ?
|
||||
}
|
||||
|
||||
fn test_all_bump_cases() {
|
||||
for case in test_cases {
|
||||
run_individual_test(case) or { panic(err) }
|
||||
}
|
||||
}
|
||||
@@ -48,27 +48,40 @@ const (
|
||||
|
||||
// Snooped from cmd/v/v.v, vlib/v/pref/pref.v
|
||||
const (
|
||||
auto_complete_commands = [
|
||||
auto_complete_commands = [
|
||||
// simple_cmd
|
||||
'fmt',
|
||||
'up',
|
||||
'vet',
|
||||
'self',
|
||||
'tracev',
|
||||
'symlink',
|
||||
'bin2v',
|
||||
'test',
|
||||
'test-fmt',
|
||||
'test-self',
|
||||
'test-cleancode',
|
||||
'repl',
|
||||
'complete',
|
||||
'build-tools',
|
||||
'build-examples',
|
||||
'build-vbinaries',
|
||||
'setup-freetype',
|
||||
'ast',
|
||||
'doc',
|
||||
'vet',
|
||||
// tools in one .v file
|
||||
'bin2v',
|
||||
'bug',
|
||||
'build-examples',
|
||||
'build-tools',
|
||||
'build-vbinaries',
|
||||
'bump',
|
||||
'check-md',
|
||||
'complete',
|
||||
'compress',
|
||||
'create',
|
||||
'doctor',
|
||||
'fmt',
|
||||
'gret',
|
||||
'repl',
|
||||
'self',
|
||||
'setup-freetype',
|
||||
'shader',
|
||||
'symlink',
|
||||
'test-all',
|
||||
'test-cleancode',
|
||||
'test-fmt',
|
||||
'test-parser',
|
||||
'test-self',
|
||||
'test',
|
||||
'tracev',
|
||||
'up',
|
||||
'watch',
|
||||
'wipe-cache',
|
||||
// commands
|
||||
'help',
|
||||
'new',
|
||||
@@ -90,7 +103,7 @@ const (
|
||||
'build',
|
||||
'build-module',
|
||||
]
|
||||
auto_complete_flags = [
|
||||
auto_complete_flags = [
|
||||
'-apk',
|
||||
'-show-timings',
|
||||
'-check-syntax',
|
||||
@@ -149,7 +162,7 @@ const (
|
||||
'-version',
|
||||
'--version',
|
||||
]
|
||||
auto_complete_flags_doc = [
|
||||
auto_complete_flags_doc = [
|
||||
'-all',
|
||||
'-f',
|
||||
'-h',
|
||||
@@ -167,7 +180,7 @@ const (
|
||||
'-s',
|
||||
'-l',
|
||||
]
|
||||
auto_complete_flags_fmt = [
|
||||
auto_complete_flags_fmt = [
|
||||
'-c',
|
||||
'-diff',
|
||||
'-l',
|
||||
@@ -175,7 +188,7 @@ const (
|
||||
'-debug',
|
||||
'-verify',
|
||||
]
|
||||
auto_complete_flags_bin2v = [
|
||||
auto_complete_flags_bin2v = [
|
||||
'-h',
|
||||
'--help',
|
||||
'-m',
|
||||
@@ -185,10 +198,22 @@ const (
|
||||
'-w',
|
||||
'--write',
|
||||
]
|
||||
auto_complete_flags_self = [
|
||||
auto_complete_flags_shader = [
|
||||
'help',
|
||||
'h',
|
||||
'force-update',
|
||||
'u',
|
||||
'verbose',
|
||||
'v',
|
||||
'slang',
|
||||
'l',
|
||||
'output',
|
||||
'o',
|
||||
]
|
||||
auto_complete_flags_self = [
|
||||
'-prod',
|
||||
]
|
||||
auto_complete_compilers = [
|
||||
auto_complete_compilers = [
|
||||
'cc',
|
||||
'gcc',
|
||||
'tcc',
|
||||
@@ -368,6 +393,9 @@ fn auto_complete_request(args []string) []string {
|
||||
'self' { // 'v self -<tab>' -> flags.
|
||||
list = get_flags(auto_complete_flags_self, part)
|
||||
}
|
||||
'shader' { // 'v shader -<tab>' -> flags.
|
||||
list = get_flags(auto_complete_flags_shader, part)
|
||||
}
|
||||
else {
|
||||
for flag in auto_complete_flags {
|
||||
if flag == part {
|
||||
|
||||
44
cmd/tools/vcompress.v
Normal file
44
cmd/tools/vcompress.v
Normal file
@@ -0,0 +1,44 @@
|
||||
module main
|
||||
|
||||
import compress.zlib
|
||||
import os
|
||||
|
||||
enum CompressionType {
|
||||
zlib
|
||||
}
|
||||
|
||||
fn main() {
|
||||
if os.args.len != 5 {
|
||||
eprintln('v compress <type> <in> <out>')
|
||||
eprintln('supported types: zlib')
|
||||
exit(1)
|
||||
}
|
||||
compression_type := match os.args[2] {
|
||||
'zlib' {
|
||||
CompressionType.zlib
|
||||
}
|
||||
else {
|
||||
eprintln('unsupported type: ${os.args[1]}')
|
||||
exit(1)
|
||||
}
|
||||
}
|
||||
path := os.args[3]
|
||||
content := os.read_bytes(path) or {
|
||||
eprintln('unable to read "$path": $err')
|
||||
exit(1)
|
||||
}
|
||||
compressed := match compression_type {
|
||||
.zlib {
|
||||
zlib.compress(content) or {
|
||||
eprintln('compression error: $err')
|
||||
exit(1)
|
||||
}
|
||||
}
|
||||
}
|
||||
out_path := os.args[4]
|
||||
|
||||
os.write_file_array(out_path, compressed) or {
|
||||
eprintln('failed to write "$out_path": $err')
|
||||
exit(1)
|
||||
}
|
||||
}
|
||||
@@ -51,7 +51,7 @@ fn vmod_content(c Create) string {
|
||||
' dependencies: []',
|
||||
'}',
|
||||
'',
|
||||
].join('\n')
|
||||
].join_lines()
|
||||
}
|
||||
|
||||
fn main_content() string {
|
||||
@@ -61,7 +61,7 @@ fn main_content() string {
|
||||
" println('Hello World!')",
|
||||
'}',
|
||||
'',
|
||||
].join('\n')
|
||||
].join_lines()
|
||||
}
|
||||
|
||||
fn gen_gitignore(name string) string {
|
||||
@@ -74,18 +74,22 @@ fn gen_gitignore(name string) string {
|
||||
'*.so',
|
||||
'*.dylib',
|
||||
'*.dll',
|
||||
'vls.log',
|
||||
'',
|
||||
].join('\n')
|
||||
].join_lines()
|
||||
}
|
||||
|
||||
fn gitattributes_content() string {
|
||||
return [
|
||||
'*.v linguist-language=V text=auto eol=lf',
|
||||
'*.vv linguist-language=V text=auto eol=lf',
|
||||
'',
|
||||
].join_lines()
|
||||
}
|
||||
|
||||
fn (c &Create) write_vmod(new bool) {
|
||||
vmod_path := if new { '$c.name/v.mod' } else { 'v.mod' }
|
||||
mut vmod := os.create(vmod_path) or {
|
||||
cerror(err.msg)
|
||||
exit(1)
|
||||
}
|
||||
vmod.write_string(vmod_content(c)) or { panic(err) }
|
||||
vmod.close()
|
||||
os.write_file(vmod_path, vmod_content(c)) or { panic(err) }
|
||||
}
|
||||
|
||||
fn (c &Create) write_main(new bool) {
|
||||
@@ -93,12 +97,12 @@ fn (c &Create) write_main(new bool) {
|
||||
return
|
||||
}
|
||||
main_path := if new { '$c.name/${c.name}.v' } else { '${c.name}.v' }
|
||||
mut mainfile := os.create(main_path) or {
|
||||
cerror(err.msg)
|
||||
exit(2)
|
||||
}
|
||||
mainfile.write_string(main_content()) or { panic(err) }
|
||||
mainfile.close()
|
||||
os.write_file(main_path, main_content()) or { panic(err) }
|
||||
}
|
||||
|
||||
fn (c &Create) write_gitattributes(new bool) {
|
||||
gitattributes_path := if new { '$c.name/.gitattributes' } else { '.gitattributes' }
|
||||
os.write_file(gitattributes_path, gitattributes_content()) or { panic(err) }
|
||||
}
|
||||
|
||||
fn (c &Create) create_git_repo(dir string) {
|
||||
@@ -110,13 +114,9 @@ fn (c &Create) create_git_repo(dir string) {
|
||||
exit(4)
|
||||
}
|
||||
}
|
||||
if !os.exists('$dir/.gitignore') {
|
||||
mut fl := os.create('$dir/.gitignore') or {
|
||||
// We don't really need a .gitignore, it's just a nice-to-have
|
||||
return
|
||||
}
|
||||
fl.write_string(gen_gitignore(c.name)) or { panic(err) }
|
||||
fl.close()
|
||||
gitignore_path := '$dir/.gitignore'
|
||||
if !os.exists(gitignore_path) {
|
||||
os.write_file(gitignore_path, gen_gitignore(c.name)) or {}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -150,6 +150,7 @@ fn create(args []string) {
|
||||
os.mkdir(c.name) or { panic(err) }
|
||||
c.write_vmod(true)
|
||||
c.write_main(true)
|
||||
c.write_gitattributes(true)
|
||||
c.create_git_repo(c.name)
|
||||
}
|
||||
|
||||
@@ -163,6 +164,7 @@ fn init_project() {
|
||||
c.description = ''
|
||||
c.write_vmod(false)
|
||||
c.write_main(false)
|
||||
c.write_gitattributes(false)
|
||||
c.create_git_repo('.')
|
||||
|
||||
println('Change the description of your project in `v.mod`')
|
||||
|
||||
@@ -12,7 +12,7 @@ fn init_and_check() ? {
|
||||
" println('Hello World!')",
|
||||
'}',
|
||||
'',
|
||||
].join('\n')
|
||||
].join_lines()
|
||||
|
||||
assert os.read_file('v.mod') ? == [
|
||||
'Module {',
|
||||
@@ -23,7 +23,7 @@ fn init_and_check() ? {
|
||||
' dependencies: []',
|
||||
'}',
|
||||
'',
|
||||
].join('\n')
|
||||
].join_lines()
|
||||
|
||||
assert os.read_file('.gitignore') ? == [
|
||||
'# Binaries for programs and plugins',
|
||||
@@ -34,8 +34,15 @@ fn init_and_check() ? {
|
||||
'*.so',
|
||||
'*.dylib',
|
||||
'*.dll',
|
||||
'vls.log',
|
||||
'',
|
||||
].join('\n')
|
||||
].join_lines()
|
||||
|
||||
assert os.read_file('.gitattributes') ? == [
|
||||
'*.v linguist-language=V text=auto eol=lf',
|
||||
'*.vv linguist-language=V text=auto eol=lf',
|
||||
'',
|
||||
].join_lines()
|
||||
}
|
||||
|
||||
fn test_v_init() ? {
|
||||
|
||||
@@ -37,6 +37,7 @@ const (
|
||||
{{ head_assets }}
|
||||
</head>
|
||||
<body>
|
||||
<div><a id="skip-to-content-link" href="#main-content">Skip to content</a></div>
|
||||
<div id="page">
|
||||
<header class="doc-nav hidden">
|
||||
<div class="heading-container">
|
||||
@@ -59,7 +60,7 @@ const (
|
||||
</ul>
|
||||
</nav>
|
||||
</header>
|
||||
<div class="doc-scrollview">
|
||||
<div class="doc-scrollview" id="main-content">
|
||||
<div class="doc-container">
|
||||
<div class="doc-content">
|
||||
{{ contents }}
|
||||
|
||||
@@ -730,3 +730,19 @@ pre {
|
||||
top: 0;
|
||||
}
|
||||
}
|
||||
|
||||
#skip-to-content-link {
|
||||
height: 30px;
|
||||
left: 50%;
|
||||
padding: 8px;
|
||||
position: absolute;
|
||||
transform: translateY(-100%);
|
||||
transition: transform 0.3s;
|
||||
background: var(--links);
|
||||
color: var(--warn-text);
|
||||
border-radius: 1px;
|
||||
}
|
||||
#skip-to-content-link:focus {
|
||||
transform: translateY(0%);
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
@@ -149,8 +149,7 @@ fn color_highlight(code string, tb &ast.Table) string {
|
||||
.string {
|
||||
use_double_quote := tok.lit.contains("'") && !tok.lit.contains('"')
|
||||
unescaped_val := tok.lit.replace('\\\\', '\x01').replace_each(["\\'", "'", '\\"',
|
||||
'"',
|
||||
])
|
||||
'"'])
|
||||
if use_double_quote {
|
||||
s := unescaped_val.replace_each(['\x01', '\\\\', '"', '\\"'])
|
||||
lit = term.yellow('"$s"')
|
||||
|
||||
@@ -289,11 +289,9 @@ fn (mut vd VDoc) generate_docs_from_file() {
|
||||
}
|
||||
}
|
||||
}
|
||||
dirs := if cfg.is_multi {
|
||||
get_modules_list(cfg.input_path, []string{})
|
||||
} else {
|
||||
[cfg.input_path]
|
||||
}
|
||||
dirs := if cfg.is_multi { get_modules_list(cfg.input_path, []string{}) } else { [
|
||||
cfg.input_path,
|
||||
] }
|
||||
for dirpath in dirs {
|
||||
vd.vprintln('Generating $out.typ docs for "$dirpath"')
|
||||
mut dcs := doc.generate(dirpath, cfg.pub_only, true, cfg.platform, cfg.symbol_name) or {
|
||||
@@ -327,6 +325,10 @@ fn (mut vd VDoc) generate_docs_from_file() {
|
||||
docs << vd.docs.filter(it.head.name != 'builtin')
|
||||
vd.docs = docs
|
||||
}
|
||||
if dirs.len == 0 && cfg.is_multi {
|
||||
eprintln('vdoc: -m requires at least 1 module folder')
|
||||
exit(1)
|
||||
}
|
||||
vd.vprintln('Rendering docs...')
|
||||
if out.path.len == 0 || out.path == 'stdout' {
|
||||
if out.typ == .html {
|
||||
@@ -334,7 +336,11 @@ fn (mut vd VDoc) generate_docs_from_file() {
|
||||
}
|
||||
outputs := vd.render(out)
|
||||
if outputs.len == 0 {
|
||||
eprintln('vdoc: No documentation found for ${dirs[0]}')
|
||||
if dirs.len == 0 {
|
||||
eprintln('vdoc: No documentation found')
|
||||
} else {
|
||||
eprintln('vdoc: No documentation found for ${dirs[0]}')
|
||||
}
|
||||
exit(1)
|
||||
} else {
|
||||
first := outputs.keys()[0]
|
||||
|
||||
@@ -26,6 +26,7 @@ struct FormatOptions {
|
||||
is_noerror bool
|
||||
is_verify bool // exit(1) if the file is not vfmt'ed
|
||||
is_worker bool // true *only* in the worker processes. NB: workers can crash.
|
||||
is_backup bool // make a `file.v.bak` copy *before* overwriting a `file.v` in place with `-w`
|
||||
}
|
||||
|
||||
const (
|
||||
@@ -53,6 +54,7 @@ fn main() {
|
||||
is_debug: '-debug' in args
|
||||
is_noerror: '-noerror' in args
|
||||
is_verify: '-verify' in args
|
||||
is_backup: '-backup' in args
|
||||
}
|
||||
if term_colors {
|
||||
os.setenv('VCOLORS', 'always', true)
|
||||
@@ -249,6 +251,10 @@ fn (foptions &FormatOptions) post_process_file(file string, formatted_file_path
|
||||
}
|
||||
if foptions.is_w {
|
||||
if is_formatted_different {
|
||||
if foptions.is_backup {
|
||||
file_bak := '${file}.bak'
|
||||
os.cp(file, file_bak) or {}
|
||||
}
|
||||
os.mv_by_cp(formatted_file_path, file) or { panic(err) }
|
||||
eprintln('Reformatted file: $file')
|
||||
} else {
|
||||
|
||||
74
cmd/tools/vgret.defaults.toml
Normal file
74
cmd/tools/vgret.defaults.toml
Normal file
@@ -0,0 +1,74 @@
|
||||
# Defaults
|
||||
[compare]
|
||||
method = 'idiff'
|
||||
flags = ['-p','-fail 0.001','-failpercent 0.2']
|
||||
|
||||
[capture]
|
||||
method = 'gg_record'
|
||||
flags = [] # ['-prod','-d ...'] etc.
|
||||
|
||||
[capture.env]
|
||||
VGG_STOP_AT_FRAME = '8'
|
||||
VGG_SCREENSHOT_FOLDER = '$OUT_PATH'
|
||||
VGG_SCREENSHOT_FRAMES = '5'
|
||||
|
||||
# List of apps to run and capture
|
||||
[[apps]]
|
||||
path = 'examples/game_of_life/life_gg.v'
|
||||
|
||||
[[apps]]
|
||||
path = 'examples/gg/bezier.v'
|
||||
|
||||
[[apps]]
|
||||
path = 'examples/gg/mandelbrot.v'
|
||||
|
||||
[[apps]]
|
||||
path = 'examples/gg/rectangles.v'
|
||||
|
||||
[[apps]]
|
||||
path = 'examples/gg/raven_text_rendering.v'
|
||||
|
||||
[[apps]]
|
||||
path = 'examples/gg/worker_thread.v'
|
||||
|
||||
[[apps]]
|
||||
path = 'examples/gg/polygons.v'
|
||||
|
||||
[[apps]]
|
||||
path = 'examples/gg/bezier_anim.v'
|
||||
|
||||
[[apps]]
|
||||
path = 'examples/gg/drag_n_drop.v'
|
||||
|
||||
[[apps]]
|
||||
path = 'examples/ttf_font/example_ttf.v'
|
||||
|
||||
# Reasons for ex- or inclusion:
|
||||
#
|
||||
# 'examples/snek/snek.v' // Inacurrate captures
|
||||
# 'examples/game_of_life/life_gg.v' // OK
|
||||
# 'examples/tetris/tetris.v' // Uses random start block
|
||||
# 'examples/fireworks/fireworks.v' // Uses rand for placement
|
||||
# 'examples/gg/bezier.v', // OK
|
||||
# 'examples/gg/mandelbrot.v', // OK
|
||||
# 'examples/gg/rectangles.v', // OK
|
||||
# 'examples/gg/set_pixels.v' // Has problem in CI software render (blank, no pixels set)
|
||||
# 'examples/gg/random.v' // Always random
|
||||
# 'examples/gg/stars.v' // Uses rand for placement
|
||||
# 'examples/gg/raven_text_rendering.v', // OK
|
||||
# 'examples/gg/worker_thread.v', // OK
|
||||
# 'examples/gg/polygons.v', // OK
|
||||
# 'examples/gg/bezier_anim.v', // OK
|
||||
# 'examples/gg/drag_n_drop.v' // OK
|
||||
# 'examples/2048/2048.v' // Random start tiles
|
||||
# 'examples/clock/clock.v' // Can only be tested on exact points in time :)
|
||||
# 'examples/flappylearning/game.v' // Random movement
|
||||
# 'examples/hot_reload/bounce.v' // Inacurrate captures
|
||||
# 'examples/hot_reload/graph.v' // Inacurrate captures
|
||||
# 'examples/ttf_font/example_ttf.v', // OK
|
||||
# 'examples/sokol/01_cubes/cube.v', // Can pass with a warning and diff at around 1.2%
|
||||
# 'examples/sokol/02_cubes_glsl/cube_glsl.v', // Inacurrate captures
|
||||
# 'examples/sokol/03_march_tracing_glsl/rt_glsl.v', // Inacurrate captures
|
||||
# 'examples/sokol/04_multi_shader_glsl/rt_glsl.v', // Inacurrate captures
|
||||
# 'examples/sokol/05_instancing_glsl/rt_glsl.v', // Inacurrate captures
|
||||
# 'examples/sokol/06_obj_viewer/show_obj.v', // Inacurrate captures
|
||||
422
cmd/tools/vgret.v
Normal file
422
cmd/tools/vgret.v
Normal file
@@ -0,0 +1,422 @@
|
||||
// Copyright (c) 2021 Lars Pontoppidan. All rights reserved.
|
||||
// Use of this source code is governed by an MIT license
|
||||
// that can be found in the LICENSE file.
|
||||
//
|
||||
// vgret (V Graphics REgression Tool) aids in generating screenshots of various graphical `gg`
|
||||
// based V applications, in a structured directory hierarchy, with the intent of either:
|
||||
// * Generate a directory structure of screenshots/images to test against
|
||||
// (which, as an example, could later be pushed to a remote git repository)
|
||||
// * Test for *visual* differences between two, structurally equal, directories
|
||||
//
|
||||
// vgret uses features and applications that is currently only available on Linux based distros:
|
||||
// idiff : `sudo apt install openimageio-tools` to programmatically find *visual* differences between two images.
|
||||
//
|
||||
// For developers:
|
||||
// For a quick overview of the generated images you can use `montage` from imagemagick to generate a "Contact Sheet":
|
||||
// montage -verbose -label '%f' -font Helvetica -pointsize 10 -background '#000000' -fill 'gray' -define jpeg:size=200x200 -geometry 200x200+2+2 -auto-orient $(fd -t f . /path/to/vgret/out/dir) /tmp/montage.jpg
|
||||
//
|
||||
// To generate the reference images locally - or for uploading to a remote repo like `gg-regression-images`
|
||||
// You can do the following:
|
||||
// 1. `export DISPLAY=:99` # Start all graphical apps on DISPLAY 99
|
||||
// 2. `Xvfb $DISPLAY -screen 0 1280x1024x24 &` # Starts a virtual X11 screen buffer
|
||||
// 3. `v gret -v /tmp/gg-regression-images` # Generate reference images to /tmp/gg-regression-images
|
||||
// 4. `v gret -v /tmp/test /tmp/gg-regression-images` # Test if the tests can pass locally by comparing to a fresh imageset
|
||||
// 5. Visually check the images (you can get an overview by running the `montage` command above)
|
||||
// 6. Upload to GitHub or keep locally for more testing/tweaking
|
||||
//
|
||||
// It's a known factor that the images generated on a local machine won't match the images generated on a remote machine by 100%.
|
||||
// They will most likely differ by a small percentage - the comparison tool can be tweaked to accept these subtle changes,
|
||||
// at the expense of slightly more inaccurate test results. For non-animated apps the percentage should be > 0.01.
|
||||
// You can emulate or test these inaccuracies to some extend locally by simply running the test from a terminal using
|
||||
// your physical X11 session display (Usually DISPLAY=:0).
|
||||
//
|
||||
// Read more about the options of `idiff` here: https://openimageio.readthedocs.io/en/latest/idiff.html
|
||||
//
|
||||
import os
|
||||
import flag
|
||||
import toml
|
||||
|
||||
const (
|
||||
tool_name = os.file_name(os.executable())
|
||||
tool_version = '0.0.1'
|
||||
tool_description = '\n Dump and/or compare rendered frames of `gg` based apps
|
||||
|
||||
Examples:
|
||||
Generate screenshots to `/tmp/test`
|
||||
v gret /tmp/test
|
||||
Generate and compare screenshots in `/tmp/src` to existing screenshots in `/tmp/dst`
|
||||
v gret /tmp/src /tmp/dst
|
||||
Compare screenshots in `/tmp/src` to existing screenshots in `/tmp/dst`
|
||||
v gret --compare-only /tmp/src /tmp/dst
|
||||
'
|
||||
tmp_dir = os.join_path(os.temp_dir(), 'v', tool_name)
|
||||
runtime_os = os.user_os()
|
||||
v_root = os.real_path(@VMODROOT)
|
||||
)
|
||||
|
||||
const (
|
||||
supported_hosts = ['linux']
|
||||
// External tool executables
|
||||
v_exe = vexe()
|
||||
idiff_exe = os.find_abs_path_of_executable('idiff') or { '' }
|
||||
)
|
||||
|
||||
const (
|
||||
embedded_toml = $embed_file('vgret.defaults.toml', .zlib)
|
||||
default_toml = embedded_toml.to_string()
|
||||
empty_toml_array = []toml.Any{}
|
||||
empty_toml_map = map[string]toml.Any{}
|
||||
)
|
||||
|
||||
struct Config {
|
||||
path string
|
||||
mut:
|
||||
apps []AppConfig
|
||||
}
|
||||
|
||||
struct CompareOptions {
|
||||
mut:
|
||||
method string = 'idiff'
|
||||
flags []string
|
||||
}
|
||||
|
||||
struct CaptureOptions {
|
||||
mut:
|
||||
method string = 'gg_record'
|
||||
flags []string
|
||||
env map[string]string
|
||||
}
|
||||
|
||||
struct AppConfig {
|
||||
compare CompareOptions
|
||||
capture CaptureOptions
|
||||
path string
|
||||
abs_path string
|
||||
mut:
|
||||
screenshots_path string
|
||||
screenshots []string
|
||||
}
|
||||
|
||||
struct Options {
|
||||
verbose bool
|
||||
compare_only bool
|
||||
root_path string
|
||||
mut:
|
||||
config Config
|
||||
}
|
||||
|
||||
fn main() {
|
||||
if os.args.len == 1 {
|
||||
println('Usage: $tool_name PATH \n$tool_description\n$tool_name -h for more help...')
|
||||
exit(1)
|
||||
}
|
||||
mut fp := flag.new_flag_parser(os.args[1..])
|
||||
fp.application(tool_name)
|
||||
fp.version(tool_version)
|
||||
fp.description(tool_description)
|
||||
fp.arguments_description('PATH [PATH]')
|
||||
fp.skip_executable()
|
||||
|
||||
show_help := fp.bool('help', `h`, false, 'Show this help text.')
|
||||
if show_help {
|
||||
println(fp.usage())
|
||||
exit(0)
|
||||
}
|
||||
|
||||
// Collect tool options
|
||||
mut opt := Options{
|
||||
verbose: fp.bool('verbose', `v`, false, "Be verbose about the tool's progress.")
|
||||
compare_only: fp.bool('compare-only', `c`, false, "Don't generate screenshots - only compare input directories")
|
||||
root_path: fp.string('root-path', `r`, v_root, 'Root path of the comparison')
|
||||
}
|
||||
|
||||
toml_conf := fp.string('toml-config', `t`, default_toml, 'Path or string with TOML configuration')
|
||||
|
||||
ensure_env(opt) or { panic(err) }
|
||||
|
||||
arg_paths := fp.finalize() or { panic(err) }
|
||||
|
||||
if arg_paths.len == 0 {
|
||||
println(fp.usage())
|
||||
println('\nError missing arguments')
|
||||
exit(1)
|
||||
}
|
||||
|
||||
opt.config = new_config(opt.root_path, toml_conf) ?
|
||||
|
||||
gen_in_path := arg_paths[0]
|
||||
if arg_paths.len >= 1 {
|
||||
generate_screenshots(mut opt, gen_in_path) ?
|
||||
}
|
||||
if arg_paths.len > 1 {
|
||||
target_path := arg_paths[1]
|
||||
path := opt.config.path
|
||||
all_paths_in_use := [path, gen_in_path, target_path]
|
||||
for path_in_use in all_paths_in_use {
|
||||
if !os.is_dir(path_in_use) {
|
||||
panic('`$path_in_use` is not a directory')
|
||||
}
|
||||
}
|
||||
if path == target_path || gen_in_path == target_path || gen_in_path == path {
|
||||
panic('Compare paths can not be the same directory `$path`/`$target_path`/`$gen_in_path`')
|
||||
}
|
||||
compare_screenshots(opt, gen_in_path, target_path) or { panic(err) }
|
||||
}
|
||||
}
|
||||
|
||||
fn generate_screenshots(mut opt Options, output_path string) ? {
|
||||
path := opt.config.path
|
||||
|
||||
dst_path := output_path.trim_right('/')
|
||||
|
||||
if !os.is_dir(path) {
|
||||
return error('`$path` is not a directory')
|
||||
}
|
||||
|
||||
for mut app_config in opt.config.apps {
|
||||
file := app_config.path
|
||||
app_path := app_config.abs_path
|
||||
|
||||
mut rel_out_path := ''
|
||||
if os.is_file(app_path) {
|
||||
rel_out_path = os.dir(file)
|
||||
} else {
|
||||
rel_out_path = file
|
||||
}
|
||||
|
||||
if opt.verbose {
|
||||
eprintln('Compiling shaders (if needed) for `$file`')
|
||||
}
|
||||
sh_result := os.execute('$v_exe shader "$app_path"')
|
||||
if sh_result.exit_code != 0 {
|
||||
if opt.verbose {
|
||||
eprintln('Skipping shader compile for `$file` v shader failed with:\n$sh_result.output')
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
if !os.exists(dst_path) {
|
||||
if opt.verbose {
|
||||
eprintln('Creating output path `$dst_path`')
|
||||
}
|
||||
os.mkdir_all(dst_path) ?
|
||||
}
|
||||
|
||||
screenshot_path := os.join_path(dst_path, rel_out_path)
|
||||
if !os.exists(screenshot_path) {
|
||||
os.mkdir_all(screenshot_path) or {
|
||||
return error('Failed making screenshot path `$screenshot_path`')
|
||||
}
|
||||
}
|
||||
|
||||
app_config.screenshots_path = screenshot_path
|
||||
app_config.screenshots = take_screenshots(opt, app_config) or {
|
||||
return error('Failed taking screenshots of `$app_path`:\n$err.msg')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn compare_screenshots(opt Options, output_path string, target_path string) ? {
|
||||
mut fails := map[string]string{}
|
||||
mut warns := map[string]string{}
|
||||
for app_config in opt.config.apps {
|
||||
screenshots := app_config.screenshots
|
||||
if opt.verbose {
|
||||
eprintln('Comparing $screenshots.len screenshots in `$output_path` with `$target_path`')
|
||||
}
|
||||
for screenshot in screenshots {
|
||||
relative_screenshot := screenshot.all_after(output_path + os.path_separator)
|
||||
|
||||
src := screenshot
|
||||
target := os.join_path(target_path, relative_screenshot)
|
||||
|
||||
if opt.verbose {
|
||||
eprintln('Comparing `$src` with `$target` with $app_config.compare.method')
|
||||
}
|
||||
|
||||
if app_config.compare.method == 'idiff' {
|
||||
if idiff_exe == '' {
|
||||
return error('$tool_name need the `idiff` tool installed. It can be installed on Ubuntu with `sudo apt install openimageio-tools`')
|
||||
}
|
||||
diff_file := os.join_path(os.temp_dir(), os.file_name(src).all_before_last('.') +
|
||||
'.diff.tif')
|
||||
flags := app_config.compare.flags.join(' ')
|
||||
diff_cmd := '$idiff_exe $flags -od -o "$diff_file" -abs "$src" "$target"'
|
||||
result := os.execute(diff_cmd)
|
||||
if opt.verbose && result.exit_code == 0 {
|
||||
eprintln('Running: $diff_cmd')
|
||||
eprintln('$result.output')
|
||||
}
|
||||
if result.exit_code != 0 {
|
||||
eprintln('$result.output')
|
||||
if result.exit_code == 1 {
|
||||
warns[src] = target
|
||||
} else {
|
||||
fails[src] = target
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if warns.len > 0 {
|
||||
eprintln('--- WARNINGS ---')
|
||||
eprintln('The following files had warnings when compared to their targets')
|
||||
for warn_src, warn_target in warns {
|
||||
eprintln('$warn_src ~= $warn_target')
|
||||
}
|
||||
}
|
||||
if fails.len > 0 {
|
||||
eprintln('--- ERRORS ---')
|
||||
eprintln('The following files did not match their targets')
|
||||
for fail_src, fail_target in fails {
|
||||
eprintln('$fail_src != $fail_target')
|
||||
}
|
||||
first := fails.keys()[0]
|
||||
fail_copy := os.join_path(os.temp_dir(), 'fail.' + first.all_after_last('.'))
|
||||
os.cp(first, fail_copy) or { panic(err) }
|
||||
eprintln('First failed file `$first` is copied to `$fail_copy`')
|
||||
|
||||
diff_file := os.join_path(os.temp_dir(), os.file_name(first).all_before_last('.') +
|
||||
'.diff.tif')
|
||||
diff_copy := os.join_path(os.temp_dir(), 'diff.tif')
|
||||
if os.is_file(diff_file) {
|
||||
os.cp(diff_file, diff_copy) or { panic(err) }
|
||||
eprintln('First failed diff file `$diff_file` is copied to `$diff_copy`')
|
||||
}
|
||||
exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
fn take_screenshots(opt Options, app AppConfig) ?[]string {
|
||||
out_path := app.screenshots_path
|
||||
if !opt.compare_only {
|
||||
if opt.verbose {
|
||||
eprintln('Taking screenshot(s) of `$app.path` to `$out_path`')
|
||||
}
|
||||
|
||||
if app.capture.method == 'gg_record' {
|
||||
for k, v in app.capture.env {
|
||||
rv := v.replace('\$OUT_PATH', out_path)
|
||||
if opt.verbose {
|
||||
eprintln('Setting ENV `$k` = $rv ...')
|
||||
}
|
||||
os.setenv('$k', rv, true)
|
||||
}
|
||||
|
||||
mut flags := app.capture.flags.join(' ')
|
||||
v_cmd := '$v_exe $flags -d gg_record run "$app.abs_path"'
|
||||
if opt.verbose {
|
||||
eprintln('Running `$v_cmd`')
|
||||
}
|
||||
result := os.execute('$v_cmd')
|
||||
if result.exit_code != 0 {
|
||||
return error('Failed taking screenshot of `$app.abs_path`:\n$result.output')
|
||||
}
|
||||
}
|
||||
}
|
||||
mut screenshots := []string{}
|
||||
shots := os.ls(out_path) or { return error('Failed listing dir `$out_path`') }
|
||||
for shot in shots {
|
||||
if shot.starts_with(os.file_name(app.path).all_before_last('.')) {
|
||||
screenshots << os.join_path(out_path, shot)
|
||||
}
|
||||
}
|
||||
return screenshots
|
||||
}
|
||||
|
||||
// ensure_env returns nothing if everything is okay.
|
||||
fn ensure_env(opt Options) ? {
|
||||
if !os.exists(tmp_dir) {
|
||||
os.mkdir_all(tmp_dir) ?
|
||||
}
|
||||
|
||||
if runtime_os !in supported_hosts {
|
||||
return error('$tool_name is currently only supported on $supported_hosts hosts')
|
||||
}
|
||||
}
|
||||
|
||||
// vexe returns the absolute path to the V compiler.
|
||||
fn vexe() string {
|
||||
mut exe := os.getenv('VEXE')
|
||||
if os.is_executable(exe) {
|
||||
return os.real_path(exe)
|
||||
}
|
||||
possible_symlink := os.find_abs_path_of_executable('v') or { '' }
|
||||
if os.is_executable(possible_symlink) {
|
||||
exe = os.real_path(possible_symlink)
|
||||
}
|
||||
return exe
|
||||
}
|
||||
|
||||
fn new_config(root_path string, toml_config string) ?Config {
|
||||
doc := toml.parse(toml_config) ?
|
||||
|
||||
path := os.real_path(root_path).trim_right('/')
|
||||
|
||||
compare_method := doc.value('compare.method').default_to('idiff').string()
|
||||
compare_flags := doc.value('compare.flags').default_to(empty_toml_array).array().as_strings()
|
||||
default_compare := CompareOptions{
|
||||
method: compare_method
|
||||
flags: compare_flags
|
||||
}
|
||||
capture_method := doc.value('capture.method').default_to('gg_record').string()
|
||||
capture_flags := doc.value('capture.flags').default_to(empty_toml_array).array().as_strings()
|
||||
capture_env := doc.value('capture.env').default_to(empty_toml_map).as_map()
|
||||
mut env_map := map[string]string{}
|
||||
for k, v in capture_env {
|
||||
env_map[k] = v.string()
|
||||
}
|
||||
default_capture := CaptureOptions{
|
||||
method: capture_method
|
||||
flags: capture_flags
|
||||
env: env_map
|
||||
}
|
||||
|
||||
apps_any := doc.value('apps').default_to(empty_toml_array).array()
|
||||
mut apps := []AppConfig{cap: apps_any.len}
|
||||
for app_any in apps_any {
|
||||
rel_path := app_any.value('path').string().trim_right('/')
|
||||
|
||||
// Merge, per app, overwrites
|
||||
mut merged_compare := CompareOptions{}
|
||||
merged_compare.method = app_any.value('compare.method').default_to(default_compare.method).string()
|
||||
merged_compare_flags := app_any.value('compare.flags').default_to(empty_toml_array).array().as_strings()
|
||||
if merged_compare_flags.len > 0 {
|
||||
merged_compare.flags = merged_compare_flags
|
||||
} else {
|
||||
merged_compare.flags = default_compare.flags
|
||||
}
|
||||
|
||||
mut merged_capture := CaptureOptions{}
|
||||
merged_capture.method = app_any.value('capture.method').default_to(default_capture.method).string()
|
||||
merged_capture_flags := app_any.value('capture.flags').default_to(empty_toml_array).array().as_strings()
|
||||
if merged_capture_flags.len > 0 {
|
||||
merged_capture.flags = merged_capture_flags
|
||||
} else {
|
||||
merged_capture.flags = default_capture.flags
|
||||
}
|
||||
|
||||
merge_capture_env := app_any.value('capture.env').default_to(empty_toml_map).as_map()
|
||||
mut merge_env_map := default_capture.env.clone()
|
||||
for k, v in merge_capture_env {
|
||||
merge_env_map[k] = v.string()
|
||||
}
|
||||
for k, v in merge_env_map {
|
||||
merged_capture.env[k] = v
|
||||
}
|
||||
|
||||
app_config := AppConfig{
|
||||
compare: merged_compare
|
||||
capture: merged_capture
|
||||
path: rel_path
|
||||
abs_path: os.join_path(path, rel_path).trim_right('/')
|
||||
}
|
||||
apps << app_config
|
||||
}
|
||||
|
||||
return Config{
|
||||
apps: apps
|
||||
path: path
|
||||
}
|
||||
}
|
||||
299
cmd/tools/vshader.v
Normal file
299
cmd/tools/vshader.v
Normal file
@@ -0,0 +1,299 @@
|
||||
// Copyright (c) 2021 Lars Pontoppidan. All rights reserved.
|
||||
// Use of this source code is governed by an MIT license
|
||||
// that can be found in the LICENSE file.
|
||||
//
|
||||
// vshader aids in generating special shader code C headers via sokol-shdc's 'annotated GLSL' format to any
|
||||
// supported target formats that sokol_gfx supports internally.
|
||||
//
|
||||
// vshader bootstraps itself by downloading it's own dependencies to a system cache directory on first run.
|
||||
//
|
||||
// Please see https://github.com/floooh/sokol-tools/blob/master/docs/sokol-shdc.md#feature-overview
|
||||
// for a more in-depth overview of the specific tool in use.
|
||||
//
|
||||
// The shader language used is, as described on the overview page linked above, an 'annotated GLSL'
|
||||
// and 'modern GLSL' (v450) shader language format.
|
||||
import os
|
||||
import io.util
|
||||
import flag
|
||||
import net.http
|
||||
|
||||
const (
|
||||
tool_name = os.file_name(os.executable())
|
||||
tool_version = '0.0.1'
|
||||
tool_description = "Compile shaders in sokol's annotated GLSL format to C headers for use with sokol based apps"
|
||||
cache_dir = os.join_path(os.cache_dir(), 'v', tool_name)
|
||||
runtime_os = os.user_os()
|
||||
)
|
||||
|
||||
const (
|
||||
supported_hosts = ['linux', 'macos', 'windows']
|
||||
supported_slangs = [
|
||||
'glsl330', // desktop GL
|
||||
'glsl100', // GLES2 / WebGL
|
||||
'glsl300es', // GLES3 / WebGL2
|
||||
'hlsl4', // D3D11
|
||||
'hlsl5', // D3D11
|
||||
'metal_macos', // Metal on macOS
|
||||
'metal_ios', // Metal on iOS device
|
||||
'metal_sim', // Metal on iOS simulator
|
||||
'wgpu', // WebGPU
|
||||
]
|
||||
default_slangs = [
|
||||
'glsl330',
|
||||
'glsl100',
|
||||
'glsl300es',
|
||||
// 'hlsl4', and hlsl5 can't be used at the same time
|
||||
'hlsl5',
|
||||
'metal_macos',
|
||||
'metal_ios',
|
||||
'metal_sim',
|
||||
'wgpu',
|
||||
]
|
||||
|
||||
shdc_version = '33d2e4cc'
|
||||
shdc_urls = {
|
||||
'windows': 'https://github.com/floooh/sokol-tools-bin/raw/33d2e4cc26088c6c28eaef5467990f8940d15aab/bin/win32/sokol-shdc.exe'
|
||||
'macos': 'https://github.com/floooh/sokol-tools-bin/raw/33d2e4cc26088c6c28eaef5467990f8940d15aab/bin/osx/sokol-shdc'
|
||||
'linux': 'https://github.com/floooh/sokol-tools-bin/raw/33d2e4cc26088c6c28eaef5467990f8940d15aab/bin/linux/sokol-shdc'
|
||||
}
|
||||
shdc_version_file = os.join_path(cache_dir, 'sokol-shdc.version')
|
||||
shdc = shdc_exe()
|
||||
shdc_exe_name = 'sokol-shdc.exe'
|
||||
)
|
||||
|
||||
struct Options {
|
||||
show_help bool
|
||||
verbose bool
|
||||
force_update bool
|
||||
slangs []string
|
||||
}
|
||||
|
||||
struct CompileOptions {
|
||||
verbose bool
|
||||
slangs []string
|
||||
invoke_path string
|
||||
}
|
||||
|
||||
fn main() {
|
||||
if os.args.len == 1 {
|
||||
println('Usage: $tool_name PATH \n$tool_description\n$tool_name -h for more help...')
|
||||
exit(1)
|
||||
}
|
||||
mut fp := flag.new_flag_parser(os.args[1..])
|
||||
fp.application(tool_name)
|
||||
fp.version(tool_version)
|
||||
fp.description(tool_description)
|
||||
fp.arguments_description('PATH [PATH]...')
|
||||
fp.skip_executable()
|
||||
// Collect tool options
|
||||
opt := Options{
|
||||
show_help: fp.bool('help', `h`, false, 'Show this help text.')
|
||||
force_update: fp.bool('force-update', `u`, false, 'Force update of the sokol-shdc tool.')
|
||||
verbose: fp.bool('verbose', `v`, false, 'Be verbose about the tools progress.')
|
||||
slangs: fp.string_multi('slang', `l`, 'Shader dialects to generate code for. Default is all.\n Available dialects: $supported_slangs')
|
||||
}
|
||||
if opt.show_help {
|
||||
println(fp.usage())
|
||||
exit(0)
|
||||
}
|
||||
|
||||
ensure_external_tools(opt) or { panic(err) }
|
||||
|
||||
input_paths := fp.finalize() or { panic(err) }
|
||||
|
||||
for path in input_paths {
|
||||
if os.exists(path) {
|
||||
compile_shaders(opt, path) or { panic(err) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// shader_program_name returns the name of the program from `shader_file`.
|
||||
// shader_program_name returns a blank string if no @program entry could be found.
|
||||
fn shader_program_name(shader_file string) string {
|
||||
shader_program := os.read_lines(shader_file) or { return '' }
|
||||
for line in shader_program {
|
||||
if line.contains('@program ') {
|
||||
return line.all_after('@program ').all_before(' ')
|
||||
}
|
||||
}
|
||||
return ''
|
||||
}
|
||||
|
||||
// validate_shader_file returns an error if `shader_file` isn't valid.
|
||||
fn validate_shader_file(shader_file string) ? {
|
||||
shader_program := os.read_lines(shader_file) or {
|
||||
return error('shader program at "$shader_file" could not be opened for reading')
|
||||
}
|
||||
mut has_program_directive := false
|
||||
for line in shader_program {
|
||||
if line.contains('@program ') {
|
||||
has_program_directive = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !has_program_directive {
|
||||
return error('shader program at "$shader_file" is missing a "@program" directive.')
|
||||
}
|
||||
}
|
||||
|
||||
// compile_shaders compiles all `*.glsl` files found in `input_path`
|
||||
// to their C header file representatives.
|
||||
fn compile_shaders(opt Options, input_path string) ? {
|
||||
mut path := os.real_path(input_path)
|
||||
path = path.trim_right('/')
|
||||
if os.is_file(path) {
|
||||
path = os.dir(path)
|
||||
}
|
||||
|
||||
mut shader_files := []string{}
|
||||
collect(path, mut shader_files)
|
||||
|
||||
if shader_files.len == 0 {
|
||||
if opt.verbose {
|
||||
eprintln('$tool_name found no shader files to compile for "$path"')
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
for shader_file in shader_files {
|
||||
// It could be the user has WIP shader files lying around not used,
|
||||
// so we just report that there's something wrong
|
||||
validate_shader_file(shader_file) or {
|
||||
eprintln(err)
|
||||
continue
|
||||
}
|
||||
co := CompileOptions{
|
||||
verbose: opt.verbose
|
||||
slangs: opt.slangs
|
||||
invoke_path: path
|
||||
}
|
||||
// Currently sokol-shdc allows for multiple --input flags
|
||||
// - but it's only the last entry that's actually compiled/used
|
||||
// Given this fact - we can only compile one '.glsl' file to one C '.h' header
|
||||
compile_shader(co, shader_file) ?
|
||||
}
|
||||
}
|
||||
|
||||
// compile_shader compiles `shader_file` to a C header file.
|
||||
fn compile_shader(opt CompileOptions, shader_file string) ? {
|
||||
path := opt.invoke_path
|
||||
// The output convetion, for now, is to use the name of the .glsl file
|
||||
mut out_file := os.file_name(shader_file).all_before_last('.') + '.h'
|
||||
out_file = os.join_path(path, out_file)
|
||||
|
||||
mut slangs := opt.slangs.clone()
|
||||
if opt.slangs.len == 0 {
|
||||
slangs = default_slangs.clone()
|
||||
}
|
||||
|
||||
header_name := os.file_name(out_file)
|
||||
if opt.verbose {
|
||||
eprintln('$tool_name generating shader code for $slangs in header "$header_name" in "$path" from $shader_file')
|
||||
}
|
||||
|
||||
cmd := '$shdc --input "$shader_file" --output "$out_file" --slang "' + slangs.join(':') + '"'
|
||||
if opt.verbose {
|
||||
eprintln('$tool_name executing:\n$cmd')
|
||||
}
|
||||
res := os.execute(cmd)
|
||||
if res.exit_code != 0 {
|
||||
eprintln('$tool_name failed generating shader includes:\n $res.output\n $cmd')
|
||||
exit(1)
|
||||
}
|
||||
if opt.verbose {
|
||||
program_name := shader_program_name(shader_file)
|
||||
eprintln('$tool_name usage example in V:\n\nimport sokol.gfx\n\n#include "$header_name"\n\nfn C.${program_name}_shader_desc(gfx.Backend) &C.sg_shader_desc\n')
|
||||
}
|
||||
}
|
||||
|
||||
// collect recursively collects `.glsl` file entries from `path` in `list`.
|
||||
fn collect(path string, mut list []string) {
|
||||
if !os.is_dir(path) {
|
||||
return
|
||||
}
|
||||
mut files := os.ls(path) or { return }
|
||||
for file in files {
|
||||
p := os.join_path(path, file)
|
||||
if os.is_dir(p) && !os.is_link(p) {
|
||||
collect(p, mut list)
|
||||
} else if os.exists(p) {
|
||||
if os.file_ext(p) == '.glsl' {
|
||||
list << os.real_path(p)
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// ensure_external_tools returns nothing if the external
|
||||
// tools can be setup or is already in place.
|
||||
fn ensure_external_tools(opt Options) ? {
|
||||
if !os.exists(cache_dir) {
|
||||
os.mkdir_all(cache_dir) ?
|
||||
}
|
||||
if opt.force_update {
|
||||
download_shdc(opt) ?
|
||||
return
|
||||
}
|
||||
|
||||
is_shdc_available := os.is_file(shdc)
|
||||
is_shdc_executable := os.is_executable(shdc)
|
||||
if is_shdc_available && is_shdc_executable {
|
||||
if opt.verbose {
|
||||
version := os.read_file(shdc_version_file) or { 'unknown' }
|
||||
eprintln('$tool_name using sokol-shdc version $version at "$shdc"')
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
download_shdc(opt) ?
|
||||
}
|
||||
|
||||
// shdc_exe returns an absolute path to the `sokol-shdc` tool.
|
||||
// Please note that the tool isn't guaranteed to actually be present, nor is
|
||||
// it guaranteed that it can be invoked.
|
||||
fn shdc_exe() string {
|
||||
return os.join_path(cache_dir, shdc_exe_name)
|
||||
}
|
||||
|
||||
// download_shdc downloads the `sokol-shdc` tool to an OS specific cache directory.
|
||||
fn download_shdc(opt Options) ? {
|
||||
// We want to use the same, runtime, OS type as this tool is invoked on.
|
||||
download_url := shdc_urls[runtime_os] or { '' }
|
||||
if download_url == '' {
|
||||
return error('$tool_name failed to download an external dependency "sokol-shdc" for ${runtime_os}.\nThe supported host platforms for shader compilation is $supported_hosts')
|
||||
}
|
||||
update_to_shdc_version := os.read_file(shdc_version_file) or { shdc_version }
|
||||
file := shdc_exe()
|
||||
if opt.verbose {
|
||||
if shdc_version != update_to_shdc_version && os.exists(file) {
|
||||
eprintln('$tool_name updating sokol-shdc to version $update_to_shdc_version ...')
|
||||
} else {
|
||||
eprintln('$tool_name installing sokol-shdc version $update_to_shdc_version ...')
|
||||
}
|
||||
}
|
||||
if os.exists(file) {
|
||||
os.rm(file) ?
|
||||
}
|
||||
|
||||
mut dtmp_file, dtmp_path := util.temp_file(util.TempFileOptions{ path: os.dir(file) }) ?
|
||||
dtmp_file.close()
|
||||
if opt.verbose {
|
||||
eprintln('$tool_name downloading sokol-shdc from $download_url')
|
||||
}
|
||||
http.download_file(download_url, dtmp_path) or {
|
||||
os.rm(dtmp_path) ?
|
||||
return error('$tool_name failed to download sokol-shdc needed for shader compiling: $err')
|
||||
}
|
||||
// Make it executable
|
||||
os.chmod(dtmp_path, 0o775) ?
|
||||
// Move downloaded file in place
|
||||
os.mv(dtmp_path, file) ?
|
||||
if runtime_os in ['linux', 'macos'] {
|
||||
// Use the .exe file ending to minimize platform friction.
|
||||
os.mv(file, shdc) ?
|
||||
}
|
||||
// Update internal version file
|
||||
os.write_file(shdc_version_file, update_to_shdc_version) ?
|
||||
}
|
||||
@@ -70,7 +70,7 @@ fn setup_symlink_windows(vexe string) {
|
||||
if os.exists(vsymlink) {
|
||||
os.rm(vsymlink) or { panic(err) }
|
||||
}
|
||||
os.write_file(vsymlink, '@echo off\n$vexe %*') or { panic(err) }
|
||||
os.write_file(vsymlink, '@echo off\n"$vexe" %*') or { panic(err) }
|
||||
eprintln('$vsymlink file written.')
|
||||
}
|
||||
if !os.exists(vsymlink) {
|
||||
|
||||
@@ -67,10 +67,43 @@ fn get_all_commands() []Command {
|
||||
line: '$vexe -o - examples/hello_world.v | grep "#define V_COMMIT_HASH" > /dev/null'
|
||||
okmsg: 'V prints the generated source code to stdout with `-o -` .'
|
||||
}
|
||||
}
|
||||
res << Command{
|
||||
line: '$vexe run examples/v_script.vsh'
|
||||
okmsg: 'V can run the .VSH script file examples/v_script.vsh'
|
||||
res << Command{
|
||||
line: '$vexe run examples/v_script.vsh > /dev/null'
|
||||
okmsg: 'V can run the .VSH script file examples/v_script.vsh'
|
||||
}
|
||||
$if linux {
|
||||
res << Command{
|
||||
line: '$vexe -b native run examples/native/hello_world.v > /dev/null'
|
||||
okmsg: 'V compiles and runs examples/native/hello_world.v on the native backend for linux'
|
||||
}
|
||||
}
|
||||
// only compilation:
|
||||
res << Command{
|
||||
line: '$vexe -os linux -b native -o hw.linux examples/hello_world.v'
|
||||
okmsg: 'V compiles hello_world.v on the native backend for linux'
|
||||
rmfile: 'hw.linux'
|
||||
}
|
||||
res << Command{
|
||||
line: '$vexe -os macos -b native -o hw.macos examples/hello_world.v'
|
||||
okmsg: 'V compiles hello_world.v on the native backend for macos'
|
||||
rmfile: 'hw.macos'
|
||||
}
|
||||
res << Command{
|
||||
line: '$vexe -os windows -b native -o hw.exe examples/hello_world.v'
|
||||
okmsg: 'V compiles hello_world.v on the native backend for windows'
|
||||
rmfile: 'hw.exe'
|
||||
}
|
||||
//
|
||||
res << Command{
|
||||
line: '$vexe -b js -o hw.js examples/hello_world.v'
|
||||
okmsg: 'V compiles hello_world.v on the JS backend'
|
||||
rmfile: 'hw.js'
|
||||
}
|
||||
res << Command{
|
||||
line: '$vexe -skip-unused -b js -o hw_skip_unused.js examples/hello_world.v'
|
||||
okmsg: 'V compiles hello_world.v on the JS backend, with -skip-unused'
|
||||
rmfile: 'hw_skip_unused.js'
|
||||
}
|
||||
}
|
||||
res << Command{
|
||||
line: '$vexe -o vtmp cmd/v'
|
||||
@@ -148,7 +181,7 @@ fn get_all_commands() []Command {
|
||||
}
|
||||
$if macos || linux {
|
||||
res << Command{
|
||||
line: '$vexe -o v.c cmd/v && cc -Werror v.c && rm -rf a.out'
|
||||
line: '$vexe -o v.c cmd/v && cc -Werror -I "$vroot/thirdparty/stdatomic/nix" v.c -lpthread -lm && rm -rf a.out'
|
||||
label: 'v.c should be buildable with no warnings...'
|
||||
okmsg: 'v.c can be compiled without warnings. This is good :)'
|
||||
rmfile: 'v.c'
|
||||
|
||||
@@ -28,12 +28,8 @@ const (
|
||||
'vlib/gg/m4/graphic.v',
|
||||
'vlib/gg/m4/m4_test.v',
|
||||
'vlib/gg/m4/matrix.v',
|
||||
'vlib/sqlite/orm.v' /* mut c &int -> mut c int */,
|
||||
'vlib/builtin/int_test.v' /* special number formatting that should be tested */,
|
||||
// TODOs and unfixed vfmt bugs
|
||||
'vlib/builtin/int.v' /* TODO byteptr: vfmt converts `pub fn (nn byteptr) str() string {` to `nn &byte` and that conflicts with `nn byte` */,
|
||||
'vlib/builtin/string_charptr_byteptr_helpers.v' /* TODO byteptr: a temporary shim to ease the byteptr=>&byte transition */,
|
||||
'vlib/v/tests/interop_test.v', /* bad comment formatting */
|
||||
'vlib/v/gen/js/tests/js.v', /* local `hello` fn, gets replaced with module `hello` aliased as `hl` */
|
||||
]
|
||||
vfmt_verify_list = [
|
||||
@@ -44,8 +40,6 @@ const (
|
||||
]
|
||||
vfmt_known_failing_exceptions = arrays.merge(verify_known_failing_exceptions, [
|
||||
'vlib/regex/regex_test.v' /* contains meaningfull formatting of the test case data */,
|
||||
'vlib/readline/readline_test.v' /* vfmt eats `{ Readline }` from `import readline { Readline }` */,
|
||||
'vlib/glm/glm.v' /* `mut res &f32` => `mut res f32`, which then fails to compile */,
|
||||
'vlib/crypto/sha512/sha512block_generic.v' /* formatting of large constant arrays wraps to too many lines */,
|
||||
'vlib/crypto/aes/const.v' /* formatting of large constant arrays wraps to too many lines */,
|
||||
])
|
||||
|
||||
@@ -8,6 +8,7 @@ const github_job = os.getenv('GITHUB_JOB')
|
||||
|
||||
const (
|
||||
skip_test_files = [
|
||||
'vlib/context/onecontext/onecontext_test.v',
|
||||
'vlib/context/deadline_test.v' /* sometimes blocks */,
|
||||
'vlib/mysql/mysql_orm_test.v' /* mysql not installed */,
|
||||
'vlib/pg/pg_orm_test.v' /* pg not installed */,
|
||||
@@ -69,6 +70,7 @@ const (
|
||||
]
|
||||
skip_on_musl = [
|
||||
'vlib/v/tests/profile/profile_test.v',
|
||||
'vlib/gg/draw_fns_api_test.v',
|
||||
]
|
||||
skip_on_ubuntu_musl = [
|
||||
//'vlib/v/gen/js/jsgen_test.v',
|
||||
@@ -91,6 +93,7 @@ const (
|
||||
'vlib/net/http/header_test.v',
|
||||
'vlib/net/http/server_test.v',
|
||||
'vlib/net/http/response_test.v',
|
||||
'vlib/builtin/js/array_test.js.v',
|
||||
]
|
||||
skip_on_linux = [
|
||||
'do_not_remove',
|
||||
@@ -99,9 +102,14 @@ const (
|
||||
'do_not_remove',
|
||||
]
|
||||
skip_on_windows = [
|
||||
'vlib/context/cancel_test.v',
|
||||
'vlib/context/deadline_test.v',
|
||||
'vlib/context/empty_test.v',
|
||||
'vlib/context/value_test.v',
|
||||
'vlib/orm/orm_test.v',
|
||||
'vlib/v/tests/orm_sub_struct_test.v',
|
||||
'vlib/v/tests/closure_test.v',
|
||||
'vlib/v/tests/closure_generator_test.v',
|
||||
'vlib/net/websocket/ws_test.v',
|
||||
'vlib/net/unix/unix_test.v',
|
||||
'vlib/net/websocket/websocket_test.v',
|
||||
@@ -109,6 +117,8 @@ const (
|
||||
'vlib/vweb/request_test.v',
|
||||
'vlib/net/http/request_test.v',
|
||||
'vlib/vweb/route_test.v',
|
||||
'vlib/sync/many_times_test.v',
|
||||
'vlib/sync/once_test.v',
|
||||
]
|
||||
skip_on_non_windows = [
|
||||
'do_not_remove',
|
||||
@@ -122,8 +132,20 @@ const (
|
||||
skip_on_amd64 = [
|
||||
'do_not_remove',
|
||||
]
|
||||
skip_on_non_amd64 = [
|
||||
'vlib/v/tests/closure_test.v' /* not implemented yet */,
|
||||
skip_on_arm64 = [
|
||||
'vlib/v/tests/closure_generator_test.v',
|
||||
'do_not_remove',
|
||||
]
|
||||
skip_on_non_amd64_or_arm64 = [
|
||||
// closures aren't implemented yet:
|
||||
'vlib/v/tests/closure_test.v',
|
||||
'vlib/context/cancel_test.v',
|
||||
'vlib/context/deadline_test.v',
|
||||
'vlib/context/empty_test.v',
|
||||
'vlib/context/value_test.v',
|
||||
'vlib/context/onecontext/onecontext_test.v',
|
||||
'vlib/sync/once_test.v',
|
||||
'vlib/sync/many_times_test.v',
|
||||
'do_not_remove',
|
||||
]
|
||||
)
|
||||
@@ -138,12 +160,23 @@ fn main() {
|
||||
args_string := args[1..].join(' ')
|
||||
cmd_prefix := args_string.all_before('test-self')
|
||||
title := 'testing vlib'
|
||||
all_test_files := os.walk_ext(os.join_path(vroot, 'vlib'), '_test.v')
|
||||
mut all_test_files := os.walk_ext(os.join_path(vroot, 'vlib'), '_test.v')
|
||||
test_js_files := os.walk_ext(os.join_path(vroot, 'vlib'), '_test.js.v')
|
||||
all_test_files << test_js_files
|
||||
testing.eheader(title)
|
||||
mut tsession := testing.new_test_session(cmd_prefix, true)
|
||||
tsession.files << all_test_files.filter(!it.contains('testdata' + os.path_separator))
|
||||
tsession.skip_files << skip_test_files
|
||||
|
||||
if !testing.is_node_present {
|
||||
testroot := vroot + os.path_separator
|
||||
tsession.skip_files << test_js_files.map(it.replace(testroot, ''))
|
||||
}
|
||||
testing.find_started_process('mysqld') or {
|
||||
tsession.skip_files << 'vlib/mysql/mysql_orm_test.v'
|
||||
}
|
||||
testing.find_started_process('postgres') or { tsession.skip_files << 'vlib/pg/pg_orm_test.v' }
|
||||
|
||||
if github_job == 'windows-tcc' {
|
||||
// TODO: fix these ASAP
|
||||
tsession.skip_files << 'vlib/net/tcp_test.v'
|
||||
@@ -205,12 +238,15 @@ fn main() {
|
||||
if os.getenv('V_CI_UBUNTU_MUSL').len > 0 {
|
||||
tsession.skip_files << skip_on_ubuntu_musl
|
||||
}
|
||||
$if !amd64 {
|
||||
$if !amd64 && !arm64 {
|
||||
tsession.skip_files << skip_on_non_amd64
|
||||
}
|
||||
$if amd64 {
|
||||
tsession.skip_files << skip_on_amd64
|
||||
}
|
||||
$if arm64 {
|
||||
tsession.skip_files << skip_on_arm64
|
||||
}
|
||||
$if !linux {
|
||||
tsession.skip_files << skip_on_non_linux
|
||||
}
|
||||
|
||||
@@ -5,6 +5,13 @@ import os.cmdline
|
||||
import testing
|
||||
import v.pref
|
||||
|
||||
struct Context {
|
||||
mut:
|
||||
verbose bool
|
||||
fail_fast bool
|
||||
run_only []string
|
||||
}
|
||||
|
||||
fn main() {
|
||||
args := os.args.clone()
|
||||
if os.args.last() == 'test' {
|
||||
@@ -12,9 +19,14 @@ fn main() {
|
||||
return
|
||||
}
|
||||
args_to_executable := args[1..]
|
||||
args_before := cmdline.options_before(args_to_executable, ['test'])
|
||||
args_after := cmdline.options_after(args_to_executable, ['test'])
|
||||
if args_after.join(' ') == 'v' {
|
||||
mut args_before := cmdline.options_before(args_to_executable, ['test'])
|
||||
mut args_after := cmdline.options_after(args_to_executable, ['test'])
|
||||
mut ctx := Context{}
|
||||
ctx.fail_fast = extract_flag_bool('-fail-fast', mut args_after, testing.fail_fast)
|
||||
ctx.verbose = extract_flag_bool('-v', mut args_after, false)
|
||||
ctx.run_only = extract_flag_string_array('-run-only', mut args_after, testing.test_only_fn)
|
||||
os.setenv('VTEST_ONLY_FN', ctx.run_only.join(','), true)
|
||||
if args_after == ['v'] {
|
||||
eprintln('`v test v` has been deprecated.')
|
||||
eprintln('Use `v test-all` instead.')
|
||||
exit(1)
|
||||
@@ -23,20 +35,25 @@ fn main() {
|
||||
backend := if backend_pos == -1 { '.c' } else { args_before[backend_pos + 1] } // this giant mess because closures are not implemented
|
||||
|
||||
mut ts := testing.new_test_session(args_before.join(' '), true)
|
||||
ts.fail_fast = ctx.fail_fast
|
||||
for targ in args_after {
|
||||
if os.is_dir(targ) {
|
||||
// Fetch all tests from the directory
|
||||
files, skip_files := should_test_dir(targ.trim_right(os.path_separator), backend)
|
||||
files, skip_files := ctx.should_test_dir(targ.trim_right(os.path_separator),
|
||||
backend)
|
||||
ts.files << files
|
||||
ts.skip_files << skip_files
|
||||
continue
|
||||
} else if os.exists(targ) {
|
||||
match should_test(targ, backend) {
|
||||
match ctx.should_test(targ, backend) {
|
||||
.test {
|
||||
ts.files << targ
|
||||
continue
|
||||
}
|
||||
.skip {
|
||||
if ctx.run_only.len > 0 {
|
||||
continue
|
||||
}
|
||||
ts.files << targ
|
||||
ts.skip_files << targ
|
||||
continue
|
||||
@@ -69,7 +86,7 @@ fn show_usage() {
|
||||
println('')
|
||||
}
|
||||
|
||||
pub fn should_test_dir(path string, backend string) ([]string, []string) { // return is (files, skip_files)
|
||||
pub fn (mut ctx Context) should_test_dir(path string, backend string) ([]string, []string) { // return is (files, skip_files)
|
||||
mut files := os.ls(path) or { return []string{}, []string{} }
|
||||
mut local_path_separator := os.path_separator
|
||||
if path.ends_with(os.path_separator) {
|
||||
@@ -83,15 +100,18 @@ pub fn should_test_dir(path string, backend string) ([]string, []string) { // re
|
||||
if file == 'testdata' {
|
||||
continue
|
||||
}
|
||||
ret_files, ret_skip_files := should_test_dir(p, backend)
|
||||
ret_files, ret_skip_files := ctx.should_test_dir(p, backend)
|
||||
res_files << ret_files
|
||||
skip_files << ret_skip_files
|
||||
} else if os.exists(p) {
|
||||
match should_test(p, backend) {
|
||||
match ctx.should_test(p, backend) {
|
||||
.test {
|
||||
res_files << p
|
||||
}
|
||||
.skip {
|
||||
if ctx.run_only.len > 0 {
|
||||
continue
|
||||
}
|
||||
res_files << p
|
||||
skip_files << p
|
||||
}
|
||||
@@ -103,14 +123,34 @@ pub fn should_test_dir(path string, backend string) ([]string, []string) { // re
|
||||
}
|
||||
|
||||
enum ShouldTestStatus {
|
||||
test // do test
|
||||
skip
|
||||
ignore
|
||||
test // do test, print OK or FAIL, depending on if it passes
|
||||
skip // print SKIP for the test
|
||||
ignore // just ignore the file, so it will not be printed at all in the list of tests
|
||||
}
|
||||
|
||||
fn should_test(path string, backend string) ShouldTestStatus {
|
||||
fn (mut ctx Context) should_test(path string, backend string) ShouldTestStatus {
|
||||
if path.ends_with('mysql_orm_test.v') {
|
||||
testing.find_started_process('mysqld') or { return .skip }
|
||||
}
|
||||
if path.ends_with('pg_orm_test.v') {
|
||||
testing.find_started_process('postgres') or { return .skip }
|
||||
}
|
||||
if path.ends_with('onecontext_test.v') {
|
||||
return .skip
|
||||
}
|
||||
$if tinyc {
|
||||
if path.ends_with('naked_attr_test.amd64.v') {
|
||||
return .skip
|
||||
}
|
||||
}
|
||||
if path.ends_with('_test.v') {
|
||||
return .test
|
||||
return ctx.should_test_when_it_contains_matching_fns(path, backend)
|
||||
}
|
||||
if path.ends_with('_test.js.v') {
|
||||
if testing.is_node_present {
|
||||
return ctx.should_test_when_it_contains_matching_fns(path, backend)
|
||||
}
|
||||
return .skip
|
||||
}
|
||||
if path.ends_with('.v') && path.count('.') == 2 {
|
||||
if !path.all_before_last('.v').all_before_last('.').ends_with('_test') {
|
||||
@@ -119,13 +159,21 @@ fn should_test(path string, backend string) ShouldTestStatus {
|
||||
backend_arg := path.all_before_last('.v').all_after_last('.')
|
||||
arch := pref.arch_from_string(backend_arg) or { pref.Arch._auto }
|
||||
if arch == pref.get_host_arch() {
|
||||
return .test
|
||||
return ctx.should_test_when_it_contains_matching_fns(path, backend)
|
||||
} else if arch == ._auto {
|
||||
if backend_arg == 'c' { // .c.v
|
||||
return if backend == 'c' { ShouldTestStatus.test } else { ShouldTestStatus.skip }
|
||||
return if backend == 'c' {
|
||||
ctx.should_test_when_it_contains_matching_fns(path, backend)
|
||||
} else {
|
||||
ShouldTestStatus.skip
|
||||
}
|
||||
}
|
||||
if backend_arg == 'js' {
|
||||
return if backend == 'js' { ShouldTestStatus.test } else { ShouldTestStatus.skip }
|
||||
return if backend == 'js' {
|
||||
ctx.should_test_when_it_contains_matching_fns(path, backend)
|
||||
} else {
|
||||
ShouldTestStatus.skip
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return .skip
|
||||
@@ -133,3 +181,53 @@ fn should_test(path string, backend string) ShouldTestStatus {
|
||||
}
|
||||
return .ignore
|
||||
}
|
||||
|
||||
fn (mut ctx Context) should_test_when_it_contains_matching_fns(path string, backend string) ShouldTestStatus {
|
||||
if ctx.run_only.len == 0 {
|
||||
// no filters set, so just compile and test
|
||||
return .test
|
||||
}
|
||||
lines := os.read_lines(path) or { return .ignore }
|
||||
for line in lines {
|
||||
if line.match_glob('fn test_*') || line.match_glob('pub fn test_*') {
|
||||
tname := line.replace_each(['pub fn ', '', 'fn ', '']).all_before('(')
|
||||
for pattern in ctx.run_only {
|
||||
mut pat := pattern.clone()
|
||||
if pat.contains('.') {
|
||||
pat = pat.all_after_last('.')
|
||||
}
|
||||
if tname.match_glob(pat) {
|
||||
if ctx.verbose {
|
||||
println('> compiling path: $path, since test fn `$tname` matches glob pattern `$pat`')
|
||||
}
|
||||
return .test
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return .ignore
|
||||
}
|
||||
|
||||
fn extract_flag_bool(flag_name string, mut after []string, flag_default bool) bool {
|
||||
mut res := flag_default
|
||||
orig_after := after.clone() // workaround for after.filter() codegen bug, when `mut after []string`
|
||||
matches_after := orig_after.filter(it != flag_name)
|
||||
if matches_after.len < after.len {
|
||||
after = matches_after.clone()
|
||||
res = true
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
fn extract_flag_string_array(flag_name string, mut after []string, flag_default []string) []string {
|
||||
mut res := flag_default.clone()
|
||||
mut found := after.index(flag_name)
|
||||
if found > -1 {
|
||||
if found + 1 < after.len {
|
||||
res = after[found + 1].split_any(',')
|
||||
after.delete(found)
|
||||
}
|
||||
after.delete(found)
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
@@ -61,7 +61,7 @@ fn get_scan_timeout_seconds() int {
|
||||
|
||||
struct VFileStat {
|
||||
path string
|
||||
mtime int
|
||||
mtime i64
|
||||
}
|
||||
|
||||
[unsafe]
|
||||
@@ -300,7 +300,6 @@ const ccontext = Context{
|
||||
}
|
||||
|
||||
fn main() {
|
||||
dump(scan_timeout_s)
|
||||
mut context := unsafe { &Context(voidptr(&ccontext)) }
|
||||
context.pid = os.getpid()
|
||||
context.vexe = os.getenv('VEXE')
|
||||
@@ -314,7 +313,7 @@ fn main() {
|
||||
fp.description('Collect all .v files needed for a compilation, then re-run the compilation when any of the source changes.')
|
||||
fp.arguments_description('[--silent] [--clear] [--ignore .db] [--add /path/to/a/file.v] [run] program.v')
|
||||
fp.allow_unknown_args()
|
||||
fp.limit_free_args_to_at_least(1)
|
||||
fp.limit_free_args_to_at_least(1) ?
|
||||
context.is_worker = fp.bool('vwatchworker', 0, false, 'Internal flag. Used to distinguish vwatch manager and worker processes.')
|
||||
context.silent = fp.bool('silent', `s`, false, 'Be more silent; do not print the watch timestamp before each re-run.')
|
||||
context.clear_terminal = fp.bool('clear', `c`, false, 'Clears the terminal before each re-run.')
|
||||
|
||||
@@ -119,7 +119,12 @@ see also `v help build`.
|
||||
explicitly supported platforms without source changes.
|
||||
|
||||
-m32, -m64
|
||||
Specify whether 32-bit or 64-bit machine code is generated.
|
||||
Whether 32-bit or 64-bit machine code will be generated.
|
||||
NB: if you need to produce 32-bit code, *and* you are cross compiling
|
||||
to another OS, you may need to also set the environment variable
|
||||
VCROSS_COMPILER_NAME, in order to override the default cross compiler,
|
||||
that V will use (`x86_64-w64-mingw32-gcc` for targeting Windows, and
|
||||
`clang` for targeting Linux from other operating systems).
|
||||
|
||||
-sanitize
|
||||
Pass flags related to sanitization to the C compiler.
|
||||
@@ -153,6 +158,9 @@ see also `v help build`.
|
||||
|
||||
https://github.com/ivmai/bdwgc
|
||||
|
||||
On Mac OS, it can be installed using homebrew (https://homebrew.sh/) with
|
||||
`brew install libgc`.
|
||||
|
||||
Note, `-gc boehm` is complementary to -autofree. The Boehm garbage
|
||||
collector is conservative, and it may make your program significantly
|
||||
slower if it does many small allocations in a loop. This option
|
||||
@@ -238,7 +246,7 @@ see also `v help build`.
|
||||
compiler, on the command line, without writing an .rsp file first.
|
||||
|
||||
-no-std
|
||||
By default, V passes -std=c99 to the C backend, but some compilers do
|
||||
By default, V passes -std=gnu99(linux)/-std=c99 to the C backend, but some compilers do
|
||||
not support that, even though they may be able to compile the produced
|
||||
code, or have other options that can be tuned to allow it.
|
||||
Passing -no-std will remove that flag, and you can then use -cflags ''
|
||||
|
||||
@@ -2,9 +2,17 @@ Usage: v -b js [-options] ['run'] <target.v|target_directory> [run options]
|
||||
|
||||
This command compiles the given target, along with their dependencies, into an Javascript source file.
|
||||
|
||||
Note that `js` defaults to the `node` codegen backend but it's also possible to pick another:
|
||||
|
||||
* `js_browser` - V outputs JS source code ready for the browser.
|
||||
* `js_node` - V outputs JS source code to run with nodejs.
|
||||
* `js_freestanding` - V outputs JS source code with no hard runtime dependency.
|
||||
|
||||
For more general build help, see also `v help build`.
|
||||
|
||||
# Interfacing the Javascript Backend code generation, passing options to it:
|
||||
-es5
|
||||
Compile V to ES5 compatible code possibly shrinking output. Note that this flag might limit some types capabilities.
|
||||
-prod
|
||||
Do not create any JS Doc comments
|
||||
|
||||
@@ -19,4 +27,4 @@ For more general build help, see also `v help build`.
|
||||
Include the orginal V source files into the generated source map
|
||||
(default false, all files in the source map are currently referenced by their absolute system file path)
|
||||
|
||||
The supported targets for the JS backend are: ES5 strict
|
||||
The supported targets for the JS backend are: ES6 strict
|
||||
|
||||
@@ -90,9 +90,18 @@ NB: the build flags are shared with the run command too:
|
||||
The checker will abort prematurely once this limit has been reached.
|
||||
Setting this to 0 or a negative value, will disable the limit.
|
||||
|
||||
-no-parallel
|
||||
Do not run the compiler in parallel (currently only the cgen stage has parallelization).
|
||||
|
||||
-profile-no-inline
|
||||
Skip [inline] functions when profiling.
|
||||
|
||||
-skip-unused
|
||||
Skip generating C/JS code for functions, that are provably not used by your project.
|
||||
This speeds up compilation, and reduces the generated output size.
|
||||
It is still experimental, due to historical reasons, but please do try it,
|
||||
and report issues, if compilation breaks with that option for your program.
|
||||
|
||||
-stats
|
||||
Enable more detailed statistics reporting, while compiling test files.
|
||||
You can use that with `v test` too, for example:
|
||||
|
||||
28
cmd/v/help/bump.txt
Normal file
28
cmd/v/help/bump.txt
Normal file
@@ -0,0 +1,28 @@
|
||||
Usage: v bump [options] [file1 file2 ...]
|
||||
|
||||
Description:
|
||||
Bump the semantic version of the v.mod and/or specified files.
|
||||
|
||||
The first instance of a version number is replaced with the new version.
|
||||
Additionally, the line affected must contain the word "version" in any
|
||||
form of capitalization. For instance, the following lines will be
|
||||
recognized by the heuristic:
|
||||
|
||||
tool_version = '1.2.1'
|
||||
version: '0.2.42'
|
||||
VERSION = "1.23.8"
|
||||
|
||||
Examples:
|
||||
Bump the patch version in v.mod if it exists
|
||||
v bump --patch
|
||||
Bump the major version in v.mod and vls.v
|
||||
v bump --major v.mod vls.v
|
||||
Upgrade the minor version in sample.v only
|
||||
v bump --minor sample.v
|
||||
|
||||
|
||||
Options:
|
||||
-h, --help Show this help text.
|
||||
-m, --major Bump the major version.
|
||||
-n, --minor Bump the minor version.
|
||||
-p, --patch Bump the patch version.
|
||||
@@ -18,6 +18,9 @@ Options:
|
||||
-l List files whose formatting differs from vfmt.
|
||||
|
||||
-w Write result to (source) file(s) instead of to stdout.
|
||||
|
||||
-backup In combination with `-w`, copy the original `file.v` to a `file.v.bak` backup,
|
||||
before overwriting the original source file.
|
||||
|
||||
-debug Print the kinds of encountered AST statements/expressions on stderr.
|
||||
|
||||
|
||||
19
cmd/v/help/gret.txt
Normal file
19
cmd/v/help/gret.txt
Normal file
@@ -0,0 +1,19 @@
|
||||
Usage:
|
||||
v gret [options] PATH [PATH]
|
||||
|
||||
Description:
|
||||
Dump and/or compare rendered frames of `gg` based apps
|
||||
|
||||
Examples:
|
||||
Generate screenshots to `/tmp/test`
|
||||
v gret /tmp/test
|
||||
Generate and compare screenshots in `/tmp/src` to existing screenshots in `/tmp/dst`
|
||||
v gret /tmp/src /tmp/dst
|
||||
Compare screenshots in `/tmp/src` to existing screenshots in `/tmp/dst`
|
||||
v gret --compare-only /tmp/src /tmp/dst
|
||||
|
||||
|
||||
Options:
|
||||
-h, --help Show this help text.
|
||||
-v, --verbose Be verbose about the tool's progress.
|
||||
-c, --compare-only Don't generate screenshots - only compare input directories
|
||||
17
cmd/v/help/shader.txt
Normal file
17
cmd/v/help/shader.txt
Normal file
@@ -0,0 +1,17 @@
|
||||
Usage:
|
||||
v shader [options] [DIRECTORY / FILE]
|
||||
|
||||
Examples:
|
||||
v shader .
|
||||
v shader examples/sokol/02_cubes_glsl/cube_glsl.glsl
|
||||
|
||||
Compile shaders in sokol's annotated GLSL format to C headers for use with sokol based apps.
|
||||
Sokol based apps include all apps using V's gg module.
|
||||
|
||||
Options:
|
||||
-h, --help Show this help text.
|
||||
-v, --verbose Be verbose about the tools progress.
|
||||
-u, --force-update Force update of the sokol-shdc tool.
|
||||
-l, --slang <multiple strings> Shader dialects to generate code for. Default is all.
|
||||
Available: 'glsl330', 'glsl100', 'glsl300es', 'hlsl4', 'hlsl5', 'metal_macos', 'metal_ios', 'metal_sim', 'wgpu'
|
||||
|
||||
@@ -1,18 +1,62 @@
|
||||
Usage:
|
||||
v [-stats] test FILE|DIRECTORY[...]
|
||||
Runs test functions in the given FILEs and DIRECTORYs
|
||||
v [-stats] test FILE|DIRECTORY[...] [-run-only GPATTERN1[,...]]
|
||||
Runs test functions in the given FILEs and DIRECTORYs.
|
||||
|
||||
If '-stats' is given, more statistics about the tests are printed along
|
||||
with a report of passes/failures
|
||||
|
||||
If you give `-run-only GPATTERN`, then *only* test functions, that do
|
||||
match by name the given glob pattern `GPATTERN` will run. You can separate
|
||||
multiple glob patterns with `,`.
|
||||
If a _test.v file lacks matching functions for all of the glob patterns, it
|
||||
will be ignored completely, so you can do in effect:
|
||||
`v test . -run-only test_your_fn_name`
|
||||
... and V will run only that test function, no matter how many _test.v
|
||||
files you have, and how many other test_ functions exist in them.
|
||||
NB: glob patterns support `*` which matches anything, and `?`, that
|
||||
matches any single character. They are *NOT* regular expressions however.
|
||||
|
||||
NB 1: very frequently, when you work on a module you can cd into its folder,
|
||||
and then you can perform:
|
||||
v test .
|
||||
v test .
|
||||
... to run all the module's '_test.v' files.
|
||||
|
||||
NB 2: V builtin testing requires you to name your files with a _test.v
|
||||
suffix, and to name your test functions with test_ prefix. Each 'test_'
|
||||
function in a '_test.v' file will be called automatically by the test
|
||||
framework. You can use `assert condition` inside each 'test_' function.
|
||||
If the asserted condition fails, then v will record that and produce a
|
||||
more detailed error message about where the failure was.
|
||||
suffix, and to name your test functions with test_ prefix. Each function,
|
||||
that starts with 'fn test_', and that is in a '_test.v' file will be called
|
||||
automatically by the test framework.
|
||||
|
||||
NB 3: You can use `assert condition` inside each 'test_' function. If the
|
||||
asserted condition fails, then v will record that, and produce a more detailed
|
||||
error message, about where the failure was.
|
||||
|
||||
NB 4: Alternative test runners (for IDE integrations):
|
||||
You can use several alternative test result formats, using `-test-runner name`,
|
||||
or by setting VTEST_RUNNER (the command line option has higher priority).
|
||||
|
||||
The names of the available test runners are:
|
||||
`simple` Fastest, does not import additional modules, does no processing.
|
||||
`tap` Format the output as required by the Test Anything Protocol (TAP).
|
||||
`normal` Supports color output, nicest/most human readable, the default.
|
||||
|
||||
You can also implement your own custom test runner, by providing the path to
|
||||
your .v file, that implements it to this option. For example, see:
|
||||
vlib/v/preludes/test_runner_tap.v .
|
||||
|
||||
NB 5: Filtering only specific _test.v files by name:
|
||||
You can set the environment variable `VTEST_ONLY` to a list of strings, that
|
||||
will have to be contained in the paths of the _test.v files.
|
||||
|
||||
Example:
|
||||
`VTEST_ONLY=complex,stats v test . -run-only *sin*`
|
||||
|
||||
This will find all _test.v files that have either `complex` or `stats`
|
||||
in their path, then for these test files, V test will find all that contain
|
||||
`test_` functions that glob match `*sin*`, and run only them, so you
|
||||
should see something like this:
|
||||
```
|
||||
OK [1/2] 164.671 ms vlib/math/stats/stats_test.v
|
||||
OK [2/2] 184.842 ms vlib/math/complex/complex_test.v
|
||||
------------------------------------------------------------------------------------------
|
||||
Summary for all V _test.v files: 2 passed, 2 total. Runtime: 185 ms, on 2 parallel jobs.
|
||||
```
|
||||
|
||||
44
cmd/v/v.v
44
cmd/v/v.v
@@ -10,22 +10,28 @@ import v.pref
|
||||
import v.util
|
||||
import v.util.version
|
||||
import v.builder
|
||||
import v.builder.cbuilder
|
||||
|
||||
const (
|
||||
external_tools = [
|
||||
'ast',
|
||||
'bin2v',
|
||||
'bug',
|
||||
'build-examples',
|
||||
'build-tools',
|
||||
'build-vbinaries',
|
||||
'bump',
|
||||
'check-md',
|
||||
'complete',
|
||||
'compress',
|
||||
'doc',
|
||||
'doctor',
|
||||
'fmt',
|
||||
'gret',
|
||||
'repl',
|
||||
'self',
|
||||
'setup-freetype',
|
||||
'shader',
|
||||
'symlink',
|
||||
'test',
|
||||
'test-all', /* runs most of the tests and other checking tools, that will be run by the CI */
|
||||
@@ -38,7 +44,6 @@ const (
|
||||
'vet',
|
||||
'wipe-cache',
|
||||
'watch',
|
||||
'ast',
|
||||
]
|
||||
list_of_flags_that_allow_duplicates = ['cc', 'd', 'define', 'cf', 'cflags']
|
||||
)
|
||||
@@ -48,7 +53,7 @@ fn main() {
|
||||
$if time_v ? {
|
||||
timers_should_print = true
|
||||
}
|
||||
mut timers := util.new_timers(timers_should_print)
|
||||
mut timers := util.new_timers(should_print: timers_should_print, label: 'main')
|
||||
timers.start('v total')
|
||||
defer {
|
||||
timers.show('v total')
|
||||
@@ -57,10 +62,9 @@ fn main() {
|
||||
timers.show('v start')
|
||||
timers.start('parse_CLI_args')
|
||||
args := os.args[1..]
|
||||
// args = 123
|
||||
if args.len == 0 || args[0] in ['-', 'repl'] {
|
||||
// Running `./v` without args launches repl
|
||||
if args.len == 0 {
|
||||
// Running `./v` without args launches repl
|
||||
if os.is_atty(0) != 0 {
|
||||
cmd_exit := term.highlight_command('exit')
|
||||
cmd_help := term.highlight_command('v help')
|
||||
@@ -72,14 +76,15 @@ fn main() {
|
||||
} else {
|
||||
mut args_and_flags := util.join_env_vflags_and_os_args()[1..].clone()
|
||||
args_and_flags << ['run', '-']
|
||||
pref.parse_args(external_tools, args_and_flags)
|
||||
pref.parse_args_and_show_errors(external_tools, args_and_flags, true)
|
||||
}
|
||||
}
|
||||
util.launch_tool(false, 'vrepl', os.args[1..])
|
||||
return
|
||||
}
|
||||
args_and_flags := util.join_env_vflags_and_os_args()[1..]
|
||||
prefs, command := pref.parse_args(external_tools, args_and_flags)
|
||||
mut args_and_flags := util.join_env_vflags_and_os_args()[1..]
|
||||
prefs, command := pref.parse_args_and_show_errors(external_tools, args_and_flags,
|
||||
true)
|
||||
if prefs.use_cache && os.user_os() == 'windows' {
|
||||
eprintln('-usecache is currently disabled on windows')
|
||||
exit(1)
|
||||
@@ -111,6 +116,9 @@ fn main() {
|
||||
'vlib-docs' {
|
||||
util.launch_tool(prefs.is_verbose, 'vdoc', ['doc', 'vlib'])
|
||||
}
|
||||
'interpret' {
|
||||
util.launch_tool(prefs.is_verbose, 'builders/interpret_builder', os.args[1..])
|
||||
}
|
||||
'get' {
|
||||
eprintln('V Error: Use `v install` to install modules from vpm.vlang.io')
|
||||
exit(1)
|
||||
@@ -124,7 +132,27 @@ fn main() {
|
||||
if command in ['run', 'build', 'build-module'] || command.ends_with('.v') || os.exists(command) {
|
||||
// println('command')
|
||||
// println(prefs.path)
|
||||
builder.compile(command, prefs)
|
||||
match prefs.backend {
|
||||
.c {
|
||||
$if no_bootstrapv ? {
|
||||
// TODO: improve the bootstrapping with a split C backend here.
|
||||
// C code generated by `VEXE=v cmd/tools/builders/c_builder -os cross -o c.c cmd/tools/builders/c_builder.v`
|
||||
// is enough to bootstrap the C backend, and thus the rest, but currently bootstrapping relies on
|
||||
// `v -os cross -o v.c cmd/v` having a functional C codegen inside instead.
|
||||
util.launch_tool(prefs.is_verbose, 'builders/c_builder', os.args[1..])
|
||||
}
|
||||
builder.compile('build', prefs, cbuilder.compile_c)
|
||||
}
|
||||
.js_node, .js_freestanding, .js_browser {
|
||||
util.launch_tool(prefs.is_verbose, 'builders/js_builder', os.args[1..])
|
||||
}
|
||||
.native {
|
||||
util.launch_tool(prefs.is_verbose, 'builders/native_builder', os.args[1..])
|
||||
}
|
||||
.interpret {
|
||||
util.launch_tool(prefs.is_verbose, 'builders/interpret_builder', os.args[1..])
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
if prefs.is_help {
|
||||
|
||||
555
doc/docs.md
555
doc/docs.md
@@ -65,6 +65,7 @@ For more details and troubleshooting, please visit the [vab GitHub repository](h
|
||||
* [Comments](#comments)
|
||||
* [Functions](#functions)
|
||||
* [Returning multiple values](#returning-multiple-values)
|
||||
* [Hoistings](#hoistings)
|
||||
* [Symbol visibility](#symbol-visibility)
|
||||
* [Variables](#variables)
|
||||
* [V types](#v-types)
|
||||
@@ -95,13 +96,12 @@ For more details and troubleshooting, please visit the [vab GitHub repository](h
|
||||
* [Mutable arguments](#mutable-arguments)
|
||||
* [Variable number of arguments](#variable-number-of-arguments)
|
||||
* [Anonymous & higher-order functions](#anonymous--higher-order-functions)
|
||||
* [Closures](#closures)
|
||||
* [References](#references)
|
||||
* [Constants](#constants)
|
||||
* [Builtin functions](#builtin-functions)
|
||||
* [Printing custom types](#printing-custom-types)
|
||||
* [Modules](#modules)
|
||||
* [Manage Packages](#manage-packages)
|
||||
* [Publish package](#publish-package)
|
||||
* [Type Declarations](#type-declarations)
|
||||
* [Interfaces](#interfaces)
|
||||
* [Enums](#enums)
|
||||
@@ -124,7 +124,10 @@ For more details and troubleshooting, please visit the [vab GitHub repository](h
|
||||
* [Writing documentation](#writing-documentation)
|
||||
* [Tools](#tools)
|
||||
* [v fmt](#v-fmt)
|
||||
* [v shader](#v-shader)
|
||||
* [Profiling](#profiling)
|
||||
* [Package Management](#package-management)
|
||||
* [Publish package](#publish-package)
|
||||
* [Advanced Topics](#advanced-topics)
|
||||
* [Dumping expressions at runtime](#dumping-expressions-at-runtime)
|
||||
* [Memory-unsafe code](#memory-unsafe-code)
|
||||
@@ -264,6 +267,8 @@ Again, the type comes after the argument's name.
|
||||
Just like in Go and C, functions cannot be overloaded.
|
||||
This simplifies the code and improves maintainability and readability.
|
||||
|
||||
### Hoistings
|
||||
|
||||
Functions can be used before their declaration:
|
||||
`add` and `sub` are declared after `main`, but can still be called from `main`.
|
||||
This is true for all declarations in V and eliminates the need for header files
|
||||
@@ -475,7 +480,18 @@ windows_newline := '\r\n' // escape special characters like in C
|
||||
assert windows_newline.len == 2
|
||||
```
|
||||
|
||||
In V, a string is a read-only array of bytes. String data is encoded using UTF-8.
|
||||
In V, a string is a read-only array of bytes. String data is encoded using UTF-8:
|
||||
```v
|
||||
s := 'hello 🌎' // emoji takes 4 bytes
|
||||
assert s.len == 10
|
||||
|
||||
arr := s.bytes() // convert `string` to `[]byte`
|
||||
assert arr.len == 10
|
||||
|
||||
s2 := arr.bytestr() // convert `[]byte` to `string`
|
||||
assert s2 == s
|
||||
```
|
||||
|
||||
String values are immutable. You cannot mutate elements:
|
||||
|
||||
```v failcompile
|
||||
@@ -484,8 +500,8 @@ s[0] = `H` // not allowed
|
||||
```
|
||||
> error: cannot assign to `s[i]` since V strings are immutable
|
||||
|
||||
Note that indexing a string will produce a `byte`, not a `rune` nor another `string`.
|
||||
Indexes correspond to bytes in the string, not Unicode code points. If you want to
|
||||
Note that indexing a string will produce a `byte`, not a `rune` nor another `string`.
|
||||
Indexes correspond to bytes in the string, not Unicode code points. If you want to
|
||||
convert the `byte` to a `string`, use the `ascii_str()` method:
|
||||
|
||||
```v
|
||||
@@ -688,6 +704,7 @@ arrays there is a second initialization syntax:
|
||||
```v
|
||||
mut a := []int{len: 10000, cap: 30000, init: 3}
|
||||
```
|
||||
|
||||
This creates an array of 10000 `int` elements that are all initialized with `3`. Memory
|
||||
space is reserved for 30000 elements. The parameters `len`, `cap` and `init` are optional;
|
||||
`len` defaults to `0` and `init` to the default initialization of the element type (`0`
|
||||
@@ -717,6 +734,13 @@ for i in 0 .. 1000 {
|
||||
Note: The above code uses a [range `for`](#range-for) statement and a
|
||||
[push operator (`<<`)](#array-operations).
|
||||
|
||||
You can initialize the array by accessing the `it` variable as shown here:
|
||||
|
||||
```v
|
||||
mut square := []int{len: 6, init: it * it}
|
||||
// square == [0, 1, 4, 9, 16, 25]
|
||||
```
|
||||
|
||||
#### Array Types
|
||||
|
||||
An array can be of these types:
|
||||
@@ -1029,7 +1053,7 @@ println(typeof(fnums).name) // => [3]int
|
||||
|
||||
fnums2 := [1, 10, 100]! // short init syntax that does the same (the syntax will probably change)
|
||||
|
||||
anums := fnums[0..fnums.len]
|
||||
anums := fnums[..] // same as `anums := fnums[0..fnums.len]`
|
||||
println(anums) // => [1, 10, 100]
|
||||
println(typeof(anums).name) // => []int
|
||||
```
|
||||
@@ -1090,6 +1114,10 @@ The same optional check applies to arrays:
|
||||
arr := [1, 2, 3]
|
||||
large_index := 999
|
||||
val := arr[large_index] or { panic('out of bounds') }
|
||||
println(val)
|
||||
// you can also do this, if you want to *propagate* the access error:
|
||||
val2 := arr[333] ?
|
||||
println(val2)
|
||||
```
|
||||
|
||||
## Module imports
|
||||
@@ -1300,7 +1328,7 @@ if mut x is MyStruct {
|
||||
// same with match
|
||||
match mut x {
|
||||
MyStruct {
|
||||
// x is casted to MyStruct even it's mutable
|
||||
// x is casted to MyStruct even if it's mutable
|
||||
// without the mut keyword that wouldn't work
|
||||
println(x)
|
||||
}
|
||||
@@ -1816,7 +1844,6 @@ mut p := Point{
|
||||
x: 10
|
||||
y: 20
|
||||
}
|
||||
// you can omit the struct name when it's already known
|
||||
p = Point{
|
||||
x: 30
|
||||
y: 4
|
||||
@@ -1837,6 +1864,7 @@ V doesn't have default function arguments or named arguments, for that trailing
|
||||
literal syntax can be used instead:
|
||||
|
||||
```v
|
||||
[params]
|
||||
struct ButtonConfig {
|
||||
text string
|
||||
is_disabled bool
|
||||
@@ -1871,6 +1899,13 @@ new_button(ButtonConfig{text:'Click me', width:100})
|
||||
|
||||
This only works for functions that take a struct for the last argument.
|
||||
|
||||
NB: the `[params]` tag is used to tell V, that the trailing struct parameter
|
||||
can be omitted *entirely*, so that you can write `button := new_button()`.
|
||||
Without it, you have to specify *at least* one of the field names, even if it
|
||||
has its default value, otherwise the compiler will produce this error message,
|
||||
when you call the function with no parameters:
|
||||
`error: expected 1 arguments, but got 0`.
|
||||
|
||||
### Access modifiers
|
||||
|
||||
Struct fields are private and immutable by default (making structs immutable as well).
|
||||
@@ -2041,16 +2076,14 @@ println(nums)
|
||||
Note, that you have to add `mut` before `nums` when calling this function. This makes
|
||||
it clear that the function being called will modify the value.
|
||||
|
||||
It is preferable to return values instead of modifying arguments.
|
||||
It is preferable to return values instead of modifying arguments,
|
||||
e.g. `user = register(user)` (or `user.register()`) instead of `register(mut user)`.
|
||||
Modifying arguments should only be done in performance-critical parts of your application
|
||||
to reduce allocations and copying.
|
||||
|
||||
For this reason V doesn't allow the modification of arguments with primitive types (e.g. integers).
|
||||
Only more complex types such as arrays and maps may be modified.
|
||||
|
||||
Use `user.register()` or `user = register(user)`
|
||||
instead of `register(mut user)`.
|
||||
|
||||
#### Struct update syntax
|
||||
|
||||
V makes it easy to return a modified version of an object:
|
||||
@@ -2137,6 +2170,8 @@ fn main() {
|
||||
}
|
||||
```
|
||||
|
||||
### Closures
|
||||
|
||||
V supports closures too.
|
||||
This means that anonymous functions can inherit variables from the scope they were created in.
|
||||
They must do so explicitly by listing all variables that are inherited.
|
||||
@@ -2460,157 +2495,6 @@ fn init() {
|
||||
The `init` function cannot be public - it will be called automatically. This feature is
|
||||
particularly useful for initializing a C library.
|
||||
|
||||
### Manage Packages
|
||||
|
||||
Briefly:
|
||||
|
||||
```powershell
|
||||
v [module option] [param]
|
||||
```
|
||||
|
||||
###### module options:
|
||||
|
||||
```
|
||||
install Install a module from VPM.
|
||||
remove Remove a module that was installed from VPM.
|
||||
search Search for a module from VPM.
|
||||
update Update an installed module from VPM.
|
||||
upgrade Upgrade all the outdated modules.
|
||||
list List all installed modules.
|
||||
outdated Show installed modules that need updates.
|
||||
```
|
||||
|
||||
Read more:
|
||||
|
||||
You can also install modules already created by someone else with [VPM](https://vpm.vlang.io/):
|
||||
```powershell
|
||||
v install [module]
|
||||
```
|
||||
**Example:**
|
||||
```powershell
|
||||
v install ui
|
||||
```
|
||||
|
||||
Modules could install directly from git or mercurial repositories.
|
||||
```powershell
|
||||
v install [--git|--hg] [url]
|
||||
```
|
||||
**Example:**
|
||||
```powershell
|
||||
v install --git https://github.com/vlang/markdown
|
||||
```
|
||||
|
||||
Removing a module with v:
|
||||
|
||||
```powershell
|
||||
v remove [module]
|
||||
```
|
||||
**Example:**
|
||||
```powershell
|
||||
v remove ui
|
||||
```
|
||||
|
||||
Updating an installed module from [VPM](https://vpm.vlang.io/):
|
||||
|
||||
```powershell
|
||||
v update [module]
|
||||
```
|
||||
**Example:**
|
||||
```powershell
|
||||
v update ui
|
||||
```
|
||||
|
||||
Or you can update all your modules:
|
||||
```powershell
|
||||
v update
|
||||
```
|
||||
|
||||
To see all the modules you have installed, you can use:
|
||||
|
||||
```powershell
|
||||
v list
|
||||
```
|
||||
**Example:**
|
||||
```powershell
|
||||
> v list
|
||||
Installed modules:
|
||||
markdown
|
||||
ui
|
||||
```
|
||||
|
||||
To see all the modules you have installed, you can use:
|
||||
outdated Show installed modules that need updates.
|
||||
```powershell
|
||||
v outdated
|
||||
```
|
||||
**Example:**
|
||||
```powershell
|
||||
> v outdated
|
||||
Modules are up to date.
|
||||
```
|
||||
|
||||
### Publish package
|
||||
|
||||
1. Put a `v.mod` file inside the toplevel folder of your module (if you
|
||||
created your module with the command `v new mymodule` or `v init` you already have a v.mod file).
|
||||
|
||||
```sh
|
||||
v new mymodule
|
||||
Input your project description: My nice module.
|
||||
Input your project version: (0.0.0) 0.0.1
|
||||
Input your project license: (MIT)
|
||||
Initialising ...
|
||||
Complete!
|
||||
```
|
||||
|
||||
Example `v.mod`:
|
||||
```v ignore
|
||||
Module {
|
||||
name: 'mymodule'
|
||||
description: 'My nice module.'
|
||||
version: '0.0.1'
|
||||
license: 'MIT'
|
||||
dependencies: []
|
||||
}
|
||||
```
|
||||
|
||||
Minimal file structure:
|
||||
```
|
||||
v.mod
|
||||
mymodule.v
|
||||
```
|
||||
|
||||
Check that your module name is used in `mymodule.v`:
|
||||
```v
|
||||
module mymodule
|
||||
|
||||
pub fn hello_world() {
|
||||
println('Hello World!')
|
||||
}
|
||||
```
|
||||
|
||||
2. Create a git repository in the folder with the `v.mod` file
|
||||
(this is not required if you used `v new` or `v init`):
|
||||
```sh
|
||||
git init
|
||||
git add .
|
||||
git commit -m "INIT"
|
||||
````
|
||||
|
||||
3. Create a public repository on github.com.
|
||||
4. Connect your local repository to the remote repository and push the changes.
|
||||
5. Add your module to the public V module registry VPM:
|
||||
https://vpm.vlang.io/new
|
||||
|
||||
You will have to login with your Github account to register the module.
|
||||
**Warning:** _Currently it is not possibility to edit your entry after submiting.
|
||||
Check your module name and github url twice as this cannot be changed by you later._
|
||||
6. The final module name is a combination of your github account and
|
||||
the module name you provided e.g. `mygithubname.mymodule`.
|
||||
|
||||
**Optional:** tag your V module with `vlang` and `vlang-module` on github.com
|
||||
to allow a better search experiance.
|
||||
|
||||
## Type Declarations
|
||||
|
||||
### Interfaces
|
||||
@@ -2649,9 +2533,54 @@ for item in arr {
|
||||
}
|
||||
```
|
||||
|
||||
#### Implement an interface
|
||||
|
||||
A type implements an interface by implementing its methods and fields.
|
||||
There is no explicit declaration of intent, no "implements" keyword.
|
||||
|
||||
An interface can have a `mut:` section. Implementing types will need
|
||||
to have a `mut` receiver, for methods declared in the `mut:` section
|
||||
of an interface.
|
||||
```v
|
||||
module main
|
||||
|
||||
pub interface Foo {
|
||||
write(string) string
|
||||
}
|
||||
|
||||
// => the method signature of a type, implementing interface Foo should be:
|
||||
// `pub fn (s Type) write(a string) string`
|
||||
|
||||
pub interface Bar {
|
||||
mut:
|
||||
write(string) string
|
||||
}
|
||||
|
||||
// => the method signature of a type, implementing interface Bar should be:
|
||||
// `pub fn (mut s Type) write(a string) string`
|
||||
|
||||
struct MyStruct {}
|
||||
|
||||
// MyStruct implements the interface Foo, but *not* interface Bar
|
||||
pub fn (s MyStruct) write(a string) string {
|
||||
return a
|
||||
}
|
||||
|
||||
fn main() {
|
||||
s1 := MyStruct{}
|
||||
fn1(s1)
|
||||
// fn2(s1) -> compile error, since MyStruct does not implement Bar
|
||||
}
|
||||
|
||||
fn fn1(s Foo) {
|
||||
println(s.write('Foo'))
|
||||
}
|
||||
|
||||
// fn fn2(s Bar) { // does not match
|
||||
// println(s.write('Foo'))
|
||||
// }
|
||||
```
|
||||
|
||||
#### Casting an interface
|
||||
|
||||
We can test the underlying type of an interface using dynamic cast operators:
|
||||
@@ -2707,6 +2636,31 @@ fn main() {
|
||||
}
|
||||
```
|
||||
|
||||
#### Embedded interface
|
||||
|
||||
Interfaces support embedding, just like structs:
|
||||
|
||||
```v
|
||||
pub interface Reader {
|
||||
mut:
|
||||
read(mut buf []byte) ?int
|
||||
}
|
||||
|
||||
pub interface Writer {
|
||||
mut:
|
||||
write(buf []byte) ?int
|
||||
}
|
||||
|
||||
// ReaderWriter embeds both Reader and Writer.
|
||||
// The effect is the same as copy/pasting all of the
|
||||
// Reader and all of the Writer methods/fields into
|
||||
// ReaderWriter.
|
||||
pub interface ReaderWriter {
|
||||
Reader
|
||||
Writer
|
||||
}
|
||||
```
|
||||
|
||||
### Function Types
|
||||
|
||||
You can use type aliases for naming specific function signatures - for
|
||||
@@ -2830,7 +2784,7 @@ println('Grocery IDs: $g1, $g2, $g3')
|
||||
|
||||
Output: `Grocery IDs: 0, 5, 6`.
|
||||
|
||||
Operations are not allowed on enum variables; they must be explicity cast to `int`.
|
||||
Operations are not allowed on enum variables; they must be explicitly cast to `int`.
|
||||
|
||||
### Sum types
|
||||
|
||||
@@ -3452,7 +3406,7 @@ fn main() {
|
||||
go fn (the_channel chan f64) {
|
||||
_ := <-the_channel
|
||||
}(ch3)
|
||||
//
|
||||
|
||||
select {
|
||||
a := <-ch {
|
||||
// do something with `a`
|
||||
@@ -3478,7 +3432,7 @@ fn main() {
|
||||
|
||||
The timeout branch is optional. If it is absent `select` waits for an unlimited amount of time.
|
||||
It is also possible to proceed immediately if no channel is ready in the moment `select` is called
|
||||
by adding an `else { ... }` branch. `else` and `> timeout` are mutually exclusive.
|
||||
by adding an `else { ... }` branch. `else` and `<timeout>` are mutually exclusive.
|
||||
|
||||
The `select` command can be used as an *expression* of type `bool`
|
||||
that becomes `false` if all channels are closed:
|
||||
@@ -3535,7 +3489,7 @@ using `rlock` for read-only and `lock` for read/write access.
|
||||
```v
|
||||
struct St {
|
||||
mut:
|
||||
x int // data to shared
|
||||
x int // data to be shared
|
||||
}
|
||||
|
||||
fn (shared b St) g() {
|
||||
@@ -3639,9 +3593,9 @@ fn main() {
|
||||
```
|
||||
|
||||
```v failcompile
|
||||
// hello_test.v
|
||||
module main
|
||||
|
||||
// hello_test.v
|
||||
fn test_hello() {
|
||||
assert hello() == 'Hello world'
|
||||
}
|
||||
@@ -3667,7 +3621,7 @@ just like `hello.v`, i.e. both are part of the same module. Note also that
|
||||
since `module main` is a regular module like the others, internal tests can
|
||||
be used to test private functions in your main program .v files too.
|
||||
|
||||
You can also define special test functions in a test file:
|
||||
You can also define these special test functions in a test file:
|
||||
* `testsuite_begin` which will be run *before* all other test functions.
|
||||
* `testsuite_end` which will be run *after* all other test functions.
|
||||
|
||||
@@ -3692,7 +3646,7 @@ option to see more details about the individual tests run.
|
||||
|
||||
You can put additional test data, including .v source files in a folder, named
|
||||
`testdata`, right next to your _test.v files. V's test framework will *ignore*
|
||||
such folders, while scanning for tests to run. This is usefull, if you want to
|
||||
such folders, while scanning for tests to run. This is useful, if you want to
|
||||
put .v files with invalid V source code, or other tests, including known
|
||||
failing ones, that should be run in a specific way/options by a parent _test.v
|
||||
file.
|
||||
@@ -4056,8 +4010,9 @@ V's ORM provides a number of benefits:
|
||||
```v
|
||||
import sqlite
|
||||
|
||||
// sets a custom table name. Default is struct name (case-sensitive)
|
||||
[table: 'customers']
|
||||
struct Customer {
|
||||
// struct name has to be the same as the table name (for now)
|
||||
id int [primary; sql: serial] // a field named `id` of integer type must be the first field
|
||||
name string [nonull]
|
||||
nr_orders int
|
||||
@@ -4077,7 +4032,7 @@ sql db {
|
||||
create table Customer
|
||||
}
|
||||
|
||||
// select count(*) from Customer
|
||||
// select count(*) from customers
|
||||
nr_customers := sql db {
|
||||
select count from Customer
|
||||
}
|
||||
@@ -4146,7 +4101,7 @@ Comments spanning multiple lines are merged together using spaces, unless
|
||||
|
||||
- the line is empty
|
||||
- the line ends with a `.` (end of sentence)
|
||||
- the line is contains purely of at least 3 of `-`, `=`, `_`, `*`, `~` (horizontal rule)
|
||||
- the line is purely of at least 3 of `-`, `=`, `_`, `*`, `~` (horizontal rule)
|
||||
- the line starts with at least one `#` followed by a space (header)
|
||||
- the line starts and ends with a `|` (table)
|
||||
- the line starts with `- ` (list)
|
||||
@@ -4167,6 +4122,19 @@ A vfmt run is usually pretty cheap (takes <30ms).
|
||||
|
||||
Always run `v fmt -w file.v` before pushing your code.
|
||||
|
||||
### v shader
|
||||
|
||||
You can use GPU shaders with V graphical apps. You write your shaders in an
|
||||
[annotated GLSL dialect](https://github.com/vlang/v/blob/1d8ece7/examples/sokol/02_cubes_glsl/cube_glsl.glsl)
|
||||
and use `v shader` to compile them for all supported target platforms.
|
||||
|
||||
```shell
|
||||
v shader /path/to/project/dir/or/file.v
|
||||
```
|
||||
|
||||
Currently you need to [include a header and declare a glue function](https://github.com/vlang/v/blob/c14c324/examples/sokol/02_cubes_glsl/cube_glsl.v#L43-L46) before
|
||||
using the shader in your code.
|
||||
|
||||
### Profiling
|
||||
|
||||
V has good support for profiling your programs: `v -profile profile.txt run file.v`
|
||||
@@ -4192,6 +4160,153 @@ fn main() {
|
||||
}
|
||||
```
|
||||
|
||||
## Package management
|
||||
|
||||
```powershell
|
||||
v [module option] [param]
|
||||
```
|
||||
|
||||
###### module options:
|
||||
|
||||
```
|
||||
install Install a module from VPM.
|
||||
remove Remove a module that was installed from VPM.
|
||||
search Search for a module from VPM.
|
||||
update Update an installed module from VPM.
|
||||
upgrade Upgrade all the outdated modules.
|
||||
list List all installed modules.
|
||||
outdated Show installed modules that need updates.
|
||||
```
|
||||
|
||||
You can install modules already created by someone else with [VPM](https://vpm.vlang.io/):
|
||||
```powershell
|
||||
v install [module]
|
||||
```
|
||||
**Example:**
|
||||
```powershell
|
||||
v install ui
|
||||
```
|
||||
|
||||
Modules can be installed directly from git or mercurial repositories.
|
||||
```powershell
|
||||
v install [--git|--hg] [url]
|
||||
```
|
||||
**Example:**
|
||||
```powershell
|
||||
v install --git https://github.com/vlang/markdown
|
||||
```
|
||||
|
||||
Removing a module with v:
|
||||
|
||||
```powershell
|
||||
v remove [module]
|
||||
```
|
||||
**Example:**
|
||||
```powershell
|
||||
v remove ui
|
||||
```
|
||||
|
||||
Updating an installed module from [VPM](https://vpm.vlang.io/):
|
||||
|
||||
```powershell
|
||||
v update [module]
|
||||
```
|
||||
**Example:**
|
||||
```powershell
|
||||
v update ui
|
||||
```
|
||||
|
||||
Or you can update all your modules:
|
||||
```powershell
|
||||
v update
|
||||
```
|
||||
|
||||
To see all the modules you have installed, you can use:
|
||||
|
||||
```powershell
|
||||
v list
|
||||
```
|
||||
**Example:**
|
||||
```powershell
|
||||
> v list
|
||||
Installed modules:
|
||||
markdown
|
||||
ui
|
||||
```
|
||||
|
||||
To see all the modules that need updates:
|
||||
```powershell
|
||||
v outdated
|
||||
```
|
||||
**Example:**
|
||||
```powershell
|
||||
> v outdated
|
||||
Modules are up to date.
|
||||
```
|
||||
|
||||
### Publish package
|
||||
|
||||
1. Put a `v.mod` file inside the toplevel folder of your module (if you
|
||||
created your module with the command `v new mymodule` or `v init` you already have a v.mod file).
|
||||
|
||||
```sh
|
||||
v new mymodule
|
||||
Input your project description: My nice module.
|
||||
Input your project version: (0.0.0) 0.0.1
|
||||
Input your project license: (MIT)
|
||||
Initialising ...
|
||||
Complete!
|
||||
```
|
||||
|
||||
Example `v.mod`:
|
||||
```v ignore
|
||||
Module {
|
||||
name: 'mymodule'
|
||||
description: 'My nice module.'
|
||||
version: '0.0.1'
|
||||
license: 'MIT'
|
||||
dependencies: []
|
||||
}
|
||||
```
|
||||
|
||||
Minimal file structure:
|
||||
```
|
||||
v.mod
|
||||
mymodule.v
|
||||
```
|
||||
|
||||
The name of your module should be used with the `module` directive
|
||||
at the top of all files in your module. For `mymodule.v`:
|
||||
```v
|
||||
module mymodule
|
||||
|
||||
pub fn hello_world() {
|
||||
println('Hello World!')
|
||||
}
|
||||
```
|
||||
|
||||
2. Create a git repository in the folder with the `v.mod` file
|
||||
(this is not required if you used `v new` or `v init`):
|
||||
```sh
|
||||
git init
|
||||
git add .
|
||||
git commit -m "INIT"
|
||||
````
|
||||
|
||||
3. Create a public repository on github.com.
|
||||
4. Connect your local repository to the remote repository and push the changes.
|
||||
5. Add your module to the public V module registry VPM:
|
||||
https://vpm.vlang.io/new
|
||||
|
||||
You will have to login with your Github account to register the module.
|
||||
**Warning:** _Currently it is not possible to edit your entry after submitting.
|
||||
Check your module name and github url twice as this cannot be changed by you later._
|
||||
6. The final module name is a combination of your github account and
|
||||
the module name you provided e.g. `mygithubname.mymodule`.
|
||||
|
||||
**Optional:** tag your V module with `vlang` and `vlang-module` on github.com
|
||||
to allow for a better search experience.
|
||||
|
||||
# Advanced Topics
|
||||
|
||||
## Dumping expressions at runtime
|
||||
@@ -4591,7 +4706,7 @@ If no flags are passed it will add `--cflags` and `--libs`, both lines below do
|
||||
The `.pc` files are looked up into a hardcoded list of default pkg-config paths, the user can add
|
||||
extra paths by using the `PKG_CONFIG_PATH` environment variable. Multiple modules can be passed.
|
||||
|
||||
To check the existance of a pkg-config use `$pkgconfig('pkg')` as a compile time if condition to
|
||||
To check the existence of a pkg-config use `$pkgconfig('pkg')` as a compile time "if" condition to
|
||||
check if a pkg-config exists. If it exists the branch will be created. Use `$else` or `$else $if`
|
||||
to handle other cases.
|
||||
|
||||
@@ -4768,7 +4883,7 @@ use `v help`, `v help build` and `v help build-c`.
|
||||
1. compile your binary with debugging info `v -g hello.v`
|
||||
2. debug with [lldb](https://lldb.llvm.org) or [GDB](https://www.gnu.org/software/gdb/) e.g. `lldb hello`
|
||||
|
||||
Troubleshooting (debugging) executables [created with V in GDB](https://github.com/vlang/v/wiki/Troubleshooting-(debugging)-executables-created-with-V-in-GDB)
|
||||
[Troubleshooting (debugging) executables created with V in GDB](https://github.com/vlang/v/wiki/Troubleshooting-(debugging)-executables-created-with-V-in-GDB)
|
||||
|
||||
**Visual debugging Setup:**
|
||||
* [Visual Studio Code](vscode.md)
|
||||
@@ -4780,7 +4895,7 @@ native backend (flag: `-b native`).
|
||||
|
||||
### Javascript Backend
|
||||
|
||||
To debug the generated Javascript output you can active source maps:
|
||||
To debug the generated Javascript output you can activate source maps:
|
||||
`v -b js -sourcemap hello.v -o hello.js`
|
||||
|
||||
For all supported options check the latest help:
|
||||
@@ -4841,7 +4956,7 @@ Full list of builtin options:
|
||||
| `windows`, `linux`, `macos` | `gcc`, `tinyc` | `amd64`, `arm64` | `debug`, `prod`, `test` |
|
||||
| `mac`, `darwin`, `ios`, | `clang`, `mingw` | `x64`, `x32` | `js`, `glibc`, `prealloc` |
|
||||
| `android`,`mach`, `dragonfly` | `msvc` | `little_endian` | `no_bounds_checking`, `freestanding` |
|
||||
| `gnu`, `hpux`, `haiku`, `qnx` | `cplusplus` | `big_endian` |
|
||||
| `gnu`, `hpux`, `haiku`, `qnx` | `cplusplus` | `big_endian` | `no_segfault_handler`, `no_backtrace`, `no_main` |
|
||||
| `solaris` | | | |
|
||||
|
||||
#### `$embed_file`
|
||||
@@ -4858,15 +4973,26 @@ V can embed arbitrary files into the executable with the `$embed_file(<path>)`
|
||||
compile time call. Paths can be absolute or relative to the source file.
|
||||
|
||||
When you do not use `-prod`, the file will not be embedded. Instead, it will
|
||||
be loaded *the first time* your program calls `f.data()` at runtime, making
|
||||
be loaded *the first time* your program calls `embedded_file.data()` at runtime, making
|
||||
it easier to change in external editor programs, without needing to recompile
|
||||
your executable.
|
||||
|
||||
When you compile with `-prod`, the file *will be embedded inside* your
|
||||
executable, increasing your binary size, but making it more self contained
|
||||
and thus easier to distribute. In this case, `f.data()` will cause *no IO*,
|
||||
and thus easier to distribute. In this case, `embedded_file.data()` will cause *no IO*,
|
||||
and it will always return the same data.
|
||||
|
||||
`$embed_file` supports compression of the embedded file when compiling with `-prod`.
|
||||
Currently only one compression type is supported: `zlib`
|
||||
|
||||
```v ignore
|
||||
import os
|
||||
fn main() {
|
||||
embedded_file := $embed_file('v.png', .zlib) // compressed using zlib
|
||||
os.write_file('exported.png', embedded_file.to_string()) ?
|
||||
}
|
||||
```
|
||||
|
||||
#### `$tmpl` for embedding and parsing V template files
|
||||
|
||||
V has a simple template language for text and html templates, and they can easily
|
||||
@@ -5040,7 +5166,7 @@ but may impact the size of your executable.
|
||||
|
||||
`[direct_array_access]` - in functions tagged with `[direct_array_access]`
|
||||
the compiler will translate array operations directly into C array operations -
|
||||
omiting bounds checking. This may save a lot of time in a function that iterates
|
||||
omitting bounds checking. This may save a lot of time in a function that iterates
|
||||
over an array but at the cost of making the function unsafe - unless
|
||||
the boundaries will be checked by the user.
|
||||
|
||||
@@ -5059,39 +5185,27 @@ the boolean expression is highly improbable. In the JS backend, that does nothin
|
||||
Having built-in JSON support is nice, but V also allows you to create efficient
|
||||
serializers for any data format. V has compile-time `if` and `for` constructs:
|
||||
|
||||
```v wip
|
||||
// TODO: not fully implemented
|
||||
|
||||
```v
|
||||
struct User {
|
||||
name string
|
||||
age int
|
||||
name string
|
||||
age int
|
||||
}
|
||||
|
||||
// Note: T should be passed a struct name only
|
||||
fn decode<T>(data string) T {
|
||||
mut result := T{}
|
||||
// compile-time `for` loop
|
||||
// T.fields gives an array of a field metadata type
|
||||
$for field in T.fields {
|
||||
$if field.typ is string {
|
||||
// $(string_expr) produces an identifier
|
||||
result.$(field.name) = get_string(data, field.name)
|
||||
} $else $if field.typ is int {
|
||||
result.$(field.name) = get_int(data, field.name)
|
||||
}
|
||||
}
|
||||
return result
|
||||
fn main() {
|
||||
$for field in User.fields {
|
||||
$if field.typ is string {
|
||||
println('$field.name is of type string')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// `decode<User>` generates:
|
||||
fn decode_User(data string) User {
|
||||
mut result := User{}
|
||||
result.name = get_string(data, 'name')
|
||||
result.age = get_int(data, 'age')
|
||||
return result
|
||||
}
|
||||
// Output:
|
||||
// name is of type string
|
||||
```
|
||||
|
||||
See [`examples/compiletime/reflection.v`](/examples/compiletime/reflection.v)
|
||||
for a more complete example.
|
||||
|
||||
## Limited operator overloading
|
||||
|
||||
```v
|
||||
@@ -5132,14 +5246,14 @@ operator overloading is an important feature to have in order to improve readabi
|
||||
To improve safety and maintainability, operator overloading is limited:
|
||||
|
||||
- It's only possible to overload `+, -, *, /, %, <, >, ==, !=, <=, >=` operators.
|
||||
- `==` and `!=` are self generated by the compiler but can be overriden.
|
||||
- `==` and `!=` are self generated by the compiler but can be overridden.
|
||||
- Calling other functions inside operator functions is not allowed.
|
||||
- Operator functions can't modify their arguments.
|
||||
- When using `<` and `==` operators, the return type must be `bool`.
|
||||
- `!=`, `>`, `<=` and `>=` are auto generated when `==` and `<` are defined.
|
||||
- Both arguments must have the same type (just like with all operators in V).
|
||||
- Assignment operators (`*=`, `+=`, `/=`, etc)
|
||||
are auto generated when the operators are defined though they must return the same type.
|
||||
are auto generated when the corresponding operators are defined and operands are of the same type.
|
||||
|
||||
## Inline assembly
|
||||
<!-- ignore because it doesn't pass fmt test (why?) -->
|
||||
@@ -5202,7 +5316,7 @@ This will generate a directory `libsodium` with a V module.
|
||||
|
||||
Example of a C2V generated libsodium wrapper:
|
||||
|
||||
https://github.com/medvednikov/libsodium
|
||||
https://github.com/vlang/libsodium
|
||||
|
||||
<br>
|
||||
|
||||
@@ -5344,14 +5458,23 @@ enum BitField {
|
||||
other
|
||||
}
|
||||
|
||||
fn example_enum_as_bitfield_use() {
|
||||
fn main() {
|
||||
assert 1 == int(BitField.read)
|
||||
assert 2 == int(BitField.write)
|
||||
mut bf := BitField.read
|
||||
assert bf.has(.read | .other) // test if *at least one* of the flags is set
|
||||
assert !bf.all(.read | .other) // test if *all* of the flags is set
|
||||
bf.set(.write | .other)
|
||||
assert bf.has(.read | .write | .other)
|
||||
assert bf.all(.read | .write | .other)
|
||||
bf.toggle(.other)
|
||||
assert bf == BitField.read | .write
|
||||
assert bf.all(.read | .write)
|
||||
assert !bf.has(.other)
|
||||
}
|
||||
```
|
||||
|
||||
```v
|
||||
// Calling this function will result in a deprecation warning
|
||||
[deprecated]
|
||||
fn old_function() {
|
||||
@@ -5372,7 +5495,9 @@ fn legacy_function() {}
|
||||
[deprecated: 'use new_function2() instead']
|
||||
[deprecated_after: '2021-05-27']
|
||||
fn legacy_function2() {}
|
||||
```
|
||||
|
||||
```v nofmt
|
||||
// This function's calls will be inlined.
|
||||
[inline]
|
||||
fn inlined_function() {
|
||||
@@ -5418,7 +5543,7 @@ fn C.my_external_function(voidptr, int, voidptr) int
|
||||
// Calls to following function must be in unsafe{} blocks.
|
||||
// Note that the code in the body of `risky_business()` will still be
|
||||
// checked, unless you also wrap it in `unsafe {}` blocks.
|
||||
// This is usefull, when you want to have an `[unsafe]` function that
|
||||
// This is useful, when you want to have an `[unsafe]` function that
|
||||
// has checks before/after a certain unsafe operation, that will still
|
||||
// benefit from V's safety features.
|
||||
[unsafe]
|
||||
@@ -5453,7 +5578,7 @@ fn C.DefWindowProc(hwnd int, msg int, lparam int, wparam int)
|
||||
// Windows only:
|
||||
// If a default graphics library is imported (ex. gg, ui), then the graphical window takes
|
||||
// priority and no console window is created, effectively disabling println() statements.
|
||||
// Use to explicity create console window. Valid before main() only.
|
||||
// Use to explicitly create console window. Valid before main() only.
|
||||
[console]
|
||||
fn main() {
|
||||
}
|
||||
@@ -5530,6 +5655,7 @@ type
|
||||
typeof
|
||||
union
|
||||
unsafe
|
||||
volatile
|
||||
__offsetof
|
||||
```
|
||||
See also [V Types](#v-types).
|
||||
@@ -5557,10 +5683,11 @@ This lists operators for [primitive types](#primitive-types) only.
|
||||
|
||||
<< left shift integer << unsigned integer
|
||||
>> right shift integer >> unsigned integer
|
||||
>>> unsigned right shift integer >> unsigned integer
|
||||
|
||||
|
||||
Precedence Operator
|
||||
5 * / % << >> &
|
||||
5 * / % << >> >>> &
|
||||
4 + - | ^
|
||||
3 == != < <= > >=
|
||||
2 &&
|
||||
@@ -5570,5 +5697,5 @@ Precedence Operator
|
||||
Assignment Operators
|
||||
+= -= *= /= %=
|
||||
&= |= ^=
|
||||
>>= <<=
|
||||
>>= <<= >>>=
|
||||
```
|
||||
|
||||
@@ -19,19 +19,19 @@ provides V language support for Visual Studio Code.
|
||||
* Linter (Workspace files only).
|
||||
[more](https://marketplace.visualstudio.com/items?itemName=vlanguage.vscode-vlang)
|
||||
|
||||
**Hint:** This extention will not add the V compiler! Information on how to
|
||||
**Hint:** This extension will not add the V compiler! Information on how to
|
||||
[install V compiler](https://github.com/vlang/v/blob/master/doc/docs.md#install-from-source)
|
||||
on your operating system.
|
||||
|
||||
### Setup Extention
|
||||
### Setup Extension
|
||||
|
||||
Install [V VS Code Extention](https://marketplace.visualstudio.com/items?itemName=vlanguage.vscode-vlang).
|
||||
Install [V VS Code Extension](https://marketplace.visualstudio.com/items?itemName=vlanguage.vscode-vlang).
|
||||
|
||||
## Visual Debugging
|
||||
|
||||

|
||||
|
||||
The [C/C++ Extention](https://marketplace.visualstudio.com/items?itemName=ms-vscode.cpptools)
|
||||
The [C/C++ Extension](https://marketplace.visualstudio.com/items?itemName=ms-vscode.cpptools)
|
||||
for Visual Studio Code provides visual conditional debugging.
|
||||
|
||||
**Features:**
|
||||
@@ -47,13 +47,16 @@ edit the variable.
|
||||
|
||||
### Setup Debugging
|
||||
|
||||
1. Install the [C/C++ Extention](https://marketplace.visualstudio.com/items?itemName=ms-vscode.cpptools)
|
||||
#### Step1: Configure the launch.json file
|
||||
1. Install the [C/C++ Extension](https://marketplace.visualstudio.com/items?itemName=ms-vscode.cpptools)
|
||||
2. Open `RUN AND DEBUG` panel (Debug Icon in left panel).
|
||||
3. Click on `Show` all automatic debug configurations.
|
||||
4. Select `Add config`.
|
||||
5. Select environment `C++ (GDB/LLDB)`.
|
||||
6. Change the line `"program": "Enter the program name, e.g. \"${workspaceFolder}/a.out\"",`
|
||||
to point to your compiled application e.g. `"program": "${workspaceFolder}/hello",`.
|
||||
to point to your compiled application e.g. `"program": "${workspaceFolder}/hello",`
|
||||
or a more flexible one `"program": "${fileDirname}/${fileBasenameNoExtension}",`
|
||||
when you want to debug the current opened file.
|
||||
|
||||
This will add a block to your `.workspace` file,
|
||||
or create the file `.vscode/launch.json`:
|
||||
@@ -62,7 +65,7 @@ or create the file `.vscode/launch.json`:
|
||||
// Use IntelliSense to learn about possible attributes.
|
||||
// Hover to view descriptions of existing attributes.
|
||||
// For more information, visit:
|
||||
// https://go.microsoft.com/fwlink/?linkid=830387
|
||||
// https://go.microsoft.com/fwlink/?linkid=830387
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
@@ -75,7 +78,8 @@ or create the file `.vscode/launch.json`:
|
||||
"cwd": "${fileDirname}",
|
||||
"environment": [],
|
||||
"externalConsole": false,
|
||||
"MIMode": "lldb"
|
||||
"MIMode": "lldb",
|
||||
"preLaunchTask": "build"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -84,24 +88,55 @@ or create the file `.vscode/launch.json`:
|
||||
**Optional:** use `"program": "${fileDirname}/${fileBasenameNoExtension}"` to debug
|
||||
any current open source file with an existing binary with the same name but without any extension.
|
||||
|
||||
#### Step2: Configure the tasks.json file
|
||||
Generally, you can manually compile the application with: `v -b c -g hello.v -o hello`,
|
||||
or for short: `v -g hello.v`, and then call the debugger.
|
||||
|
||||
The `-g` option will add the needed debugging information.
|
||||
You can find more debugging options in the [docs](docs.md#debugging).
|
||||
|
||||
VS Code provides a hook called `preLaunchTask`, which can be used to compile
|
||||
the application automatially every time you call the debugger.
|
||||
[preLaunchTask](https://code.visualstudio.com/docs/editor/debugging#_launchjson-attributes) launches
|
||||
a task before the start of a debug session, set this attribute to the label of a task specified
|
||||
in [task.json](https://code.visualstudio.com/docs/editor/tasks) (in the workspace's .vscode folder).
|
||||
Or, this can be set to `${defaultBuildTask}`, to use your default build task.
|
||||
|
||||
As explained, the `"preLaunchTask": "build"` needs to work with a `.vscode/tasks.json`
|
||||
with a label named `build`.
|
||||
```json
|
||||
{
|
||||
// See https://go.microsoft.com/fwlink/?LinkId=733558
|
||||
// for the documentation about the tasks.json format
|
||||
"version": "2.0.0",
|
||||
"tasks": [
|
||||
{
|
||||
"label": "build",
|
||||
"type": "shell",
|
||||
"command": "v",
|
||||
"args": [
|
||||
"-g", // add more compiler options here if necessary
|
||||
"${relativeFile}" // or modify it according to your requirements
|
||||
],
|
||||
"group": "build",
|
||||
"presentation": {
|
||||
"reveal": "silent"
|
||||
},
|
||||
"problemMatcher": "$gcc"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### Usage
|
||||
|
||||
To allow your compiled application to be debugged.
|
||||
The application needs to include additional debugging information
|
||||
([DWARF](https://en.wikipedia.org/wiki/DWARF)).
|
||||
|
||||
**1. Compile with debugging information:**
|
||||
`v -b c -g hello.v -o hello` or short `v -g hello.v`
|
||||
|
||||
The `-g` option will add the needed debugging informations.
|
||||
More Options are explained in the [docs](docs.md#debugging).
|
||||
|
||||
|
||||
**2. Start Debugging**
|
||||
|
||||
1. Open your source code and set the required break points
|
||||
2. Click on the Debug Icon in the left Icon panel and click
|
||||
`> (lldb) Start`, or use `F5` to launch your application in debug mode.
|
||||
|
||||
For all options look at the official
|
||||
[C/C++ Extention documentation](https://code.visualstudio.com/docs/cpp/cpp-debug).
|
||||
[C/C++ Extension documentation](https://code.visualstudio.com/docs/cpp/cpp-debug).
|
||||
|
||||
3
examples/.gitignore
vendored
3
examples/.gitignore
vendored
@@ -1,2 +1,3 @@
|
||||
*.js
|
||||
*.log
|
||||
*.ppm
|
||||
*.js
|
||||
@@ -788,7 +788,7 @@ fn (mut app App) on_key_down(key gg.KeyCode) {
|
||||
// these keys are independent from the game state:
|
||||
match key {
|
||||
.a { app.is_ai_mode = !app.is_ai_mode }
|
||||
.escape { exit(0) }
|
||||
.escape { app.gg.quit() }
|
||||
.n, .r { app.new_game() }
|
||||
.backspace { app.undo() }
|
||||
.enter { app.next_tile_format() }
|
||||
@@ -910,7 +910,7 @@ fn (mut app App) showfps() {
|
||||
fn main() {
|
||||
mut app := &App{}
|
||||
app.new_game()
|
||||
mut font_path := os.resource_abs_path(os.join_path('../assets/fonts/', 'RobotoMono-Regular.ttf'))
|
||||
mut font_path := os.resource_abs_path(os.join_path('..', 'assets', 'fonts', 'RobotoMono-Regular.ttf'))
|
||||
$if android {
|
||||
font_path = 'fonts/RobotoMono-Regular.ttf'
|
||||
}
|
||||
|
||||
|
Before Width: | Height: | Size: 4.2 KiB After Width: | Height: | Size: 4.2 KiB |
@@ -1,42 +1,41 @@
|
||||
// Binary Search Tree example by @SleepyRoy
|
||||
|
||||
// TODO: make Node.value generic once it's robust enough
|
||||
struct Empty {}
|
||||
|
||||
struct Node {
|
||||
value f64
|
||||
left Tree
|
||||
right Tree
|
||||
struct Node<T> {
|
||||
value T
|
||||
left Tree<T>
|
||||
right Tree<T>
|
||||
}
|
||||
|
||||
type Tree = Empty | Node
|
||||
type Tree<T> = Empty | Node<T>
|
||||
|
||||
// return size(number of nodes) of BST
|
||||
fn size(tree Tree) int {
|
||||
fn (tree Tree<T>) size<T>() int {
|
||||
return match tree {
|
||||
Empty { 0 }
|
||||
Node { 1 + size(tree.left) + size(tree.right) }
|
||||
Node<T> { 1 + tree.left.size() + tree.right.size() }
|
||||
}
|
||||
}
|
||||
|
||||
// insert a value to BST
|
||||
fn insert(tree Tree, x f64) Tree {
|
||||
fn (tree Tree<T>) insert<T>(x T) Tree<T> {
|
||||
return match tree {
|
||||
Empty {
|
||||
Node{x, tree, tree}
|
||||
Node<T>{x, tree, tree}
|
||||
}
|
||||
Node {
|
||||
Node<T> {
|
||||
if x == tree.value {
|
||||
tree
|
||||
} else if x < tree.value {
|
||||
Node{
|
||||
Node<T>{
|
||||
...tree
|
||||
left: insert(tree.left, x)
|
||||
left: tree.left.insert(x)
|
||||
}
|
||||
} else {
|
||||
Node{
|
||||
Node<T>{
|
||||
...tree
|
||||
right: insert(tree.right, x)
|
||||
right: tree.right.insert(x)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -44,80 +43,80 @@ fn insert(tree Tree, x f64) Tree {
|
||||
}
|
||||
|
||||
// whether able to find a value in BST
|
||||
fn search(tree Tree, x f64) bool {
|
||||
fn (tree Tree<T>) search<T>(x T) bool {
|
||||
return match tree {
|
||||
Empty {
|
||||
false
|
||||
}
|
||||
Node {
|
||||
Node<T> {
|
||||
if x == tree.value {
|
||||
true
|
||||
} else if x < tree.value {
|
||||
search(tree.left, x)
|
||||
tree.left.search(x)
|
||||
} else {
|
||||
search(tree.right, x)
|
||||
tree.right.search(x)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// find the minimal value of a BST
|
||||
fn min(tree Tree) f64 {
|
||||
fn (tree Tree<T>) min<T>() T {
|
||||
return match tree {
|
||||
Empty {
|
||||
1e100
|
||||
T(1e9)
|
||||
}
|
||||
Node {
|
||||
if tree.value < min(tree.left) {
|
||||
Node<T> {
|
||||
if tree.value < tree.left.min() {
|
||||
tree.value
|
||||
} else {
|
||||
min(tree.left)
|
||||
tree.left.min()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// delete a value in BST (if nonexistant do nothing)
|
||||
fn delete(tree Tree, x f64) Tree {
|
||||
fn (tree Tree<T>) delete<T>(x T) Tree<T> {
|
||||
return match tree {
|
||||
Empty {
|
||||
tree
|
||||
}
|
||||
Node {
|
||||
if tree.left is Node && tree.right is Node {
|
||||
Node<T> {
|
||||
if tree.left !is Empty && tree.right !is Empty {
|
||||
if x < tree.value {
|
||||
Node{
|
||||
Node<T>{
|
||||
...tree
|
||||
left: delete(tree.left, x)
|
||||
left: tree.left.delete(x)
|
||||
}
|
||||
} else if x > tree.value {
|
||||
Node{
|
||||
Node<T>{
|
||||
...tree
|
||||
right: delete(tree.right, x)
|
||||
right: tree.right.delete(x)
|
||||
}
|
||||
} else {
|
||||
Node{
|
||||
Node<T>{
|
||||
...tree
|
||||
value: min(tree.right)
|
||||
right: delete(tree.right, min(tree.right))
|
||||
value: tree.right.min()
|
||||
right: tree.right.delete(tree.right.min())
|
||||
}
|
||||
}
|
||||
} else if tree.left is Node {
|
||||
} else if tree.left !is Empty {
|
||||
if x == tree.value {
|
||||
tree.left
|
||||
} else {
|
||||
Node{
|
||||
Node<T>{
|
||||
...tree
|
||||
left: delete(tree.left, x)
|
||||
left: tree.left.delete(x)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if x == tree.value {
|
||||
tree.right
|
||||
} else {
|
||||
Node{
|
||||
Node<T>{
|
||||
...tree
|
||||
right: delete(tree.right, x)
|
||||
right: tree.right.delete(x)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -126,46 +125,22 @@ fn delete(tree Tree, x f64) Tree {
|
||||
}
|
||||
|
||||
fn main() {
|
||||
$if !freestanding {
|
||||
mut tree := Tree(Empty{})
|
||||
input := [0.3, 0.2, 0.5, 0.0, 0.6, 0.8, 0.9, 1.0, 0.1, 0.4, 0.7]
|
||||
for i in input {
|
||||
tree = insert(tree, i)
|
||||
}
|
||||
println('[1] after insertion tree size is ${size(tree)}') // 11
|
||||
del := [-0.3, 0.0, 0.3, 0.6, 1.0, 1.5]
|
||||
for i in del {
|
||||
tree = delete(tree, i)
|
||||
}
|
||||
print('[2] after deletion tree size is ${size(tree)}, ') // 7
|
||||
print('and these elements were deleted: ') // 0.0 0.3 0.6 1.0
|
||||
for i in input {
|
||||
if !search(tree, i) {
|
||||
print('$i ')
|
||||
}
|
||||
}
|
||||
println('')
|
||||
} $else {
|
||||
mut tree := Tree(Empty{})
|
||||
input := [0.3, 0.2, 0.5, 0.0, 0.6, 0.8, 0.9, 1.0, 0.1, 0.4, 0.7]
|
||||
for i in input {
|
||||
tree = insert(tree, i)
|
||||
}
|
||||
print('[1] after insertion tree size is ') // 11
|
||||
println(size(tree))
|
||||
del := [-0.3, 0.0, 0.3, 0.6, 1.0, 1.5]
|
||||
for i in del {
|
||||
tree = delete(tree, i)
|
||||
}
|
||||
print('[2] after deletion tree size is ') // 7
|
||||
print(size(tree))
|
||||
print(', and these elements were deleted: ') // 0.0 0.3 0.6 1.0
|
||||
for i in input {
|
||||
if !search(tree, i) {
|
||||
print(i)
|
||||
print(' ')
|
||||
}
|
||||
}
|
||||
println('')
|
||||
mut tree := Tree<f64>(Empty{})
|
||||
vals := [0.2, 0.0, 0.5, 0.3, 0.6, 0.8, 0.9, 1.0, 0.1, 0.4, 0.7]
|
||||
for i in vals {
|
||||
tree = tree.insert(i)
|
||||
}
|
||||
println('[1] after insertion tree size is $tree.size()') // 11
|
||||
del_vals := [-0.3, 0.0, 0.3, 0.6, 1.0, 1.5]
|
||||
for i in del_vals {
|
||||
tree = tree.delete(i)
|
||||
}
|
||||
print('[2] after deletion tree size is $tree.size(), ') // 7
|
||||
print('and these elements were deleted: ') // 0.0 0.3 0.6 1.0
|
||||
for i in vals {
|
||||
if !tree.search(i) {
|
||||
print('$i ')
|
||||
}
|
||||
}
|
||||
println('')
|
||||
}
|
||||
|
||||
@@ -88,11 +88,12 @@ fn on_frame(mut app App) {
|
||||
}
|
||||
|
||||
// Rotate a polygon round the centerpoint
|
||||
[manualfree]
|
||||
fn draw_convex_poly_rotate(mut ctx gg.Context, dpi_scale f32, points []f32, c gx.Color, angle f32) {
|
||||
sa := math.sin(math.pi * angle / 180.0)
|
||||
ca := math.cos(math.pi * angle / 180.0)
|
||||
|
||||
mut rotated_points := []f32{}
|
||||
mut rotated_points := []f32{cap: points.len}
|
||||
for i := 0; i < points.len / 2; i++ {
|
||||
x := points[2 * i]
|
||||
y := points[2 * i + 1]
|
||||
@@ -102,6 +103,7 @@ fn draw_convex_poly_rotate(mut ctx gg.Context, dpi_scale f32, points []f32, c gx
|
||||
rotated_points << (yn + center) * dpi_scale
|
||||
}
|
||||
ctx.draw_convex_poly(rotated_points, c)
|
||||
unsafe { rotated_points.free() }
|
||||
}
|
||||
|
||||
fn (mut app App) resize() {
|
||||
@@ -133,7 +135,7 @@ fn on_event(e &gg.Event, mut app App) {
|
||||
.q {
|
||||
println('Good bye.')
|
||||
// do we need to free anything here?
|
||||
exit(0)
|
||||
app.gg.quit()
|
||||
}
|
||||
else {}
|
||||
}
|
||||
@@ -142,11 +144,15 @@ fn on_event(e &gg.Event, mut app App) {
|
||||
}
|
||||
}
|
||||
|
||||
fn on_init(mut app App) {
|
||||
app.resize()
|
||||
}
|
||||
|
||||
// is needed for easier diagnostics on windows
|
||||
[console]
|
||||
fn main() {
|
||||
println("Press 'q' to quit.")
|
||||
mut font_path := os.resource_abs_path(os.join_path('../assets/fonts/', 'RobotoMono-Regular.ttf'))
|
||||
mut font_path := os.resource_abs_path(os.join_path('..', 'assets', 'fonts', 'RobotoMono-Regular.ttf'))
|
||||
$if android {
|
||||
font_path = 'fonts/RobotoMono-Regular.ttf'
|
||||
}
|
||||
@@ -161,6 +167,7 @@ fn main() {
|
||||
user_data: app
|
||||
frame_fn: on_frame
|
||||
event_fn: on_event
|
||||
init_fn: on_init
|
||||
font_path: font_path
|
||||
)
|
||||
|
||||
|
||||
49
examples/compiletime/reflection.v
Normal file
49
examples/compiletime/reflection.v
Normal file
@@ -0,0 +1,49 @@
|
||||
// An example deserializer implementation
|
||||
|
||||
struct User {
|
||||
name string
|
||||
age int
|
||||
}
|
||||
|
||||
fn main() {
|
||||
data := 'name=Alice\nage=18'
|
||||
user := decode<User>(data)
|
||||
println(user)
|
||||
}
|
||||
|
||||
fn decode<T>(data string) T {
|
||||
mut result := T{}
|
||||
// compile-time `for` loop
|
||||
// T.fields gives an array of a field metadata type
|
||||
$for field in T.fields {
|
||||
$if field.typ is string {
|
||||
// $(string_expr) produces an identifier
|
||||
result.$(field.name) = get_string(data, field.name)
|
||||
} $else $if field.typ is int {
|
||||
result.$(field.name) = get_int(data, field.name)
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
fn get_string(data string, field_name string) string {
|
||||
for line in data.split_into_lines() {
|
||||
key_val := line.split('=')
|
||||
if key_val[0] == field_name {
|
||||
return key_val[1]
|
||||
}
|
||||
}
|
||||
return ''
|
||||
}
|
||||
|
||||
fn get_int(data string, field string) int {
|
||||
return get_string(data, field).int()
|
||||
}
|
||||
|
||||
// `decode<User>` generates:
|
||||
// fn decode_User(data string) User {
|
||||
// mut result := User{}
|
||||
// result.name = get_string(data, 'name')
|
||||
// result.age = get_int(data, 'age')
|
||||
// return result
|
||||
// }
|
||||
@@ -12,7 +12,7 @@ struct Module {
|
||||
|
||||
struct User {
|
||||
id int [primary; sql: serial]
|
||||
age int [unique: 'user']
|
||||
age u32 [unique: 'user']
|
||||
name string [sql: 'username'; unique]
|
||||
is_customer bool [sql: 'abc'; unique: 'user']
|
||||
skipped_string string [skip]
|
||||
|
||||
@@ -1,18 +1,17 @@
|
||||
// This program displays the fibonacci sequence
|
||||
// import os
|
||||
import os
|
||||
|
||||
fn main() {
|
||||
// Check for user input
|
||||
// if os.args.len != 2 {
|
||||
// println('usage: fibonacci [rank]')
|
||||
if os.args.len != 2 {
|
||||
println('usage: fibonacci [rank]')
|
||||
|
||||
// Exit
|
||||
// return
|
||||
// }
|
||||
return
|
||||
}
|
||||
|
||||
// Parse first argument and cast it to int
|
||||
// stop := os.args[1].int()
|
||||
stop := 23
|
||||
|
||||
stop := os.args[1].int()
|
||||
// Can only calculate correctly until rank 92
|
||||
if stop > 92 {
|
||||
println('rank must be 92 or less')
|
||||
@@ -20,9 +19,9 @@ fn main() {
|
||||
}
|
||||
|
||||
// Three consecutive terms of the sequence
|
||||
mut a := 0
|
||||
mut b := 0
|
||||
mut c := 1
|
||||
mut a := i64(0)
|
||||
mut b := i64(0)
|
||||
mut c := i64(1)
|
||||
println(a + c + c)
|
||||
for _ in 0 .. stop {
|
||||
// Set a and b to the next term
|
||||
|
||||
@@ -96,7 +96,7 @@ fn (mut app App) resize() {
|
||||
// is needed for easier diagnostics on windows
|
||||
[console]
|
||||
fn main() {
|
||||
mut font_path := os.resource_abs_path(os.join_path('../assets/fonts/', 'RobotoMono-Regular.ttf'))
|
||||
mut font_path := os.resource_abs_path(os.join_path('..', 'assets', 'fonts', 'RobotoMono-Regular.ttf'))
|
||||
$if android {
|
||||
font_path = 'fonts/RobotoMono-Regular.ttf'
|
||||
}
|
||||
|
||||
@@ -177,7 +177,7 @@ fn main() {
|
||||
mut app := &App{
|
||||
gg: 0
|
||||
}
|
||||
mut font_path := os.resource_abs_path(os.join_path('../assets/fonts/', 'RobotoMono-Regular.ttf'))
|
||||
mut font_path := os.resource_abs_path(os.join_path('..', 'assets', 'fonts', 'RobotoMono-Regular.ttf'))
|
||||
$if android {
|
||||
font_path = 'fonts/RobotoMono-Regular.ttf'
|
||||
}
|
||||
@@ -274,7 +274,7 @@ fn (mut app App) key_down(key gg.KeyCode) {
|
||||
// global keys
|
||||
match key {
|
||||
.escape {
|
||||
exit(0)
|
||||
app.gg.quit()
|
||||
}
|
||||
._0 {
|
||||
app.timer_period_ms = 0
|
||||
|
||||
@@ -1,25 +1,85 @@
|
||||
module main
|
||||
|
||||
import term
|
||||
import rand
|
||||
import time
|
||||
import automaton
|
||||
|
||||
fn print_automaton(a &automaton.Automaton) {
|
||||
for y := 1; y < a.field.maxy; y++ {
|
||||
mut s := ' '
|
||||
for x := 1; x < a.field.maxx; x++ {
|
||||
cell := a.field.get(x, y)
|
||||
s += if cell == 1 { '@' } else { '.' }
|
||||
}
|
||||
println(s)
|
||||
const (
|
||||
cell = '█'
|
||||
nothing = ' '
|
||||
switches = {
|
||||
cell: nothing
|
||||
nothing: cell
|
||||
}
|
||||
println('')
|
||||
transformers = [nothing, cell]
|
||||
)
|
||||
|
||||
struct Game {
|
||||
mut:
|
||||
grid [][]string
|
||||
}
|
||||
|
||||
fn (g Game) get_surrounding_alive_count(x int, y int) int {
|
||||
mut count := 0
|
||||
for i := x - 1; i <= x + 1; i++ {
|
||||
for j := y - 1; j <= y + 1; j++ {
|
||||
if (i != x || j != y) && i >= 0 && j >= 0 && i < g.grid.len && j < g.grid[x].len {
|
||||
if g.grid[i][j] == cell {
|
||||
count++
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return count
|
||||
}
|
||||
|
||||
fn (mut g Game) evolve() {
|
||||
mut temp_grid := [][]string{}
|
||||
for x in 0 .. g.grid.len {
|
||||
temp_grid << []string{}
|
||||
for y in 0 .. g.grid[x].len {
|
||||
count := g.get_surrounding_alive_count(x, y)
|
||||
if count == 3 || ((g.grid[x][y] == cell) && count == 2) {
|
||||
temp_grid[x] << cell
|
||||
} else {
|
||||
temp_grid[x] << nothing
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
g.grid = temp_grid
|
||||
}
|
||||
|
||||
fn (mut g Game) display() {
|
||||
for y in 0 .. g.grid[0].len {
|
||||
mut line := ''
|
||||
for x in 0 .. g.grid.len {
|
||||
line += g.grid[x][y]
|
||||
}
|
||||
println(line)
|
||||
}
|
||||
}
|
||||
|
||||
fn new_game() Game {
|
||||
w, h := term.get_terminal_size()
|
||||
mut grid := [][]string{}
|
||||
for x in 0 .. w {
|
||||
grid << []string{}
|
||||
for _ in 0 .. h {
|
||||
is_live := rand.f64() > 0.82
|
||||
icon := transformers[int(is_live)]
|
||||
grid[x] << icon
|
||||
}
|
||||
}
|
||||
return Game{grid}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
mut a := automaton.gun()
|
||||
mut g := new_game()
|
||||
|
||||
g.display()
|
||||
for {
|
||||
a.update()
|
||||
print_automaton(a)
|
||||
g.evolve()
|
||||
term.erase_clear()
|
||||
g.display()
|
||||
time.sleep(100 * time.millisecond)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,7 +23,6 @@ pub fn (a &A2D) set(x int, y int, newval int) {
|
||||
mut e := &int(0)
|
||||
e = a.data + y * a.maxx + x
|
||||
*e = newval
|
||||
_ = e // TODO compiler bug, this is not necessary
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ mut:
|
||||
}
|
||||
|
||||
fn main() {
|
||||
mut font_path := os.resource_abs_path(os.join_path('../assets/fonts/', 'RobotoMono-Regular.ttf'))
|
||||
mut font_path := os.resource_abs_path(os.join_path('..', 'assets', 'fonts', 'RobotoMono-Regular.ttf'))
|
||||
mut app := &App{
|
||||
gg: 0
|
||||
}
|
||||
|
||||
@@ -3,32 +3,22 @@ module main
|
||||
import gg
|
||||
import gx
|
||||
|
||||
struct App {
|
||||
mut:
|
||||
gg &gg.Context
|
||||
}
|
||||
|
||||
fn main() {
|
||||
mut app := &App{
|
||||
gg: 0
|
||||
}
|
||||
app.gg = gg.new_context(
|
||||
mut context := gg.new_context(
|
||||
bg_color: gx.rgb(174, 198, 255)
|
||||
width: 600
|
||||
height: 400
|
||||
window_title: 'Polygons'
|
||||
frame_fn: frame
|
||||
user_data: app
|
||||
)
|
||||
app.gg.run()
|
||||
context.run()
|
||||
}
|
||||
|
||||
fn frame(mut app App) {
|
||||
app.gg.begin()
|
||||
app.gg.draw_convex_poly([f32(100.0), 100.0, 200.0, 100.0, 300.0, 200.0, 200.0, 300.0, 100.0,
|
||||
300.0,
|
||||
], gx.blue)
|
||||
app.gg.draw_empty_poly([f32(50.0), 50.0, 70.0, 60.0, 90.0, 80.0, 70.0, 110.0], gx.black)
|
||||
app.gg.draw_triangle(450, 142, 530, 280, 370, 280, gx.red)
|
||||
app.gg.end()
|
||||
fn frame(mut ctx gg.Context) {
|
||||
ctx.begin()
|
||||
ctx.draw_convex_poly([f32(100.0), 100.0, 200.0, 100.0, 300.0, 200.0, 200.0, 300.0, 100.0, 300.0],
|
||||
gx.blue)
|
||||
ctx.draw_empty_poly([f32(50.0), 50.0, 70.0, 60.0, 90.0, 80.0, 70.0, 110.0], gx.black)
|
||||
ctx.draw_triangle(450, 142, 530, 280, 370, 280, gx.red)
|
||||
ctx.end()
|
||||
}
|
||||
|
||||
@@ -75,7 +75,7 @@ fn main() {
|
||||
width: win_width
|
||||
height: win_height
|
||||
create_window: true
|
||||
window_title: 'Empty window'
|
||||
window_title: 'Raven text'
|
||||
user_data: app
|
||||
bg_color: bg_color
|
||||
frame_fn: frame
|
||||
|
||||
@@ -29,7 +29,8 @@ fn main() {
|
||||
user_data: app
|
||||
init_fn: init_images
|
||||
)
|
||||
app.image = app.gg.create_image(os.resource_abs_path('logo.png'))
|
||||
mut logo_path := os.resource_abs_path(os.join_path('..', 'assets', 'logo.png'))
|
||||
app.image = app.gg.create_image(logo_path)
|
||||
app.gg.run()
|
||||
}
|
||||
|
||||
|
||||
@@ -5,12 +5,28 @@ import gx
|
||||
|
||||
struct App {
|
||||
mut:
|
||||
gg &gg.Context
|
||||
gg &gg.Context
|
||||
pixels []f32
|
||||
}
|
||||
|
||||
fn main() {
|
||||
mut pixels := []f32{}
|
||||
density := 4
|
||||
for x in 30 .. 60 {
|
||||
if x % density == 0 {
|
||||
continue
|
||||
}
|
||||
for y in 30 .. 60 {
|
||||
if y % density == 0 {
|
||||
continue
|
||||
}
|
||||
pixels << f32(x + density)
|
||||
pixels << f32(y + density)
|
||||
}
|
||||
}
|
||||
mut app := &App{
|
||||
gg: 0
|
||||
pixels: pixels
|
||||
}
|
||||
app.gg = gg.new_context(
|
||||
bg_color: gx.rgb(174, 198, 255)
|
||||
@@ -24,16 +40,13 @@ fn main() {
|
||||
}
|
||||
|
||||
fn frame(mut app App) {
|
||||
mut pixels := []f32{}
|
||||
|
||||
for x in 30 .. 60 {
|
||||
for y in 30 .. 60 {
|
||||
pixels << f32(x)
|
||||
pixels << f32(y)
|
||||
}
|
||||
}
|
||||
|
||||
app.gg.begin()
|
||||
app.gg.set_pixels(pixels, gx.red)
|
||||
// Set a blue pixel near each corner. (Find your magnifying glass)
|
||||
app.gg.set_pixel(2, 2, gx.blue)
|
||||
app.gg.set_pixel(app.gg.width - 2, 2, gx.blue)
|
||||
app.gg.set_pixel(app.gg.width - 2, app.gg.height - 2, gx.blue)
|
||||
app.gg.set_pixel(2, app.gg.height - 2, gx.blue)
|
||||
// Set pixels in a grid-like pattern.
|
||||
app.gg.set_pixels(app.pixels, gx.red)
|
||||
app.gg.end()
|
||||
}
|
||||
|
||||
@@ -81,7 +81,8 @@ fn main() {
|
||||
}
|
||||
|
||||
fn init_images(mut app App) {
|
||||
app.image = app.gg.create_image(os.resource_abs_path('logo.png'))
|
||||
mut logo_path := os.resource_abs_path(os.join_path('..', 'assets', 'logo.png'))
|
||||
app.image = app.gg.create_image(logo_path)
|
||||
}
|
||||
|
||||
fn frame(mut app App) {
|
||||
|
||||
7
examples/js_dom_cube/README.md
Normal file
7
examples/js_dom_cube/README.md
Normal file
@@ -0,0 +1,7 @@
|
||||
Interactive 3D cube using DOM & WebGL API.
|
||||
|
||||
# Compiling
|
||||
```
|
||||
v -b js_browser examples/js_dom_cube/cube.js.v
|
||||
```
|
||||
Then you can open `index.html` with your favourite browser.
|
||||
452
examples/js_dom_cube/cube.js.v
Normal file
452
examples/js_dom_cube/cube.js.v
Normal file
@@ -0,0 +1,452 @@
|
||||
import js.dom
|
||||
import math
|
||||
|
||||
const (
|
||||
vert_code = 'attribute vec3 position;uniform mat4 Pmatrix;uniform mat4 Vmatrix;uniform mat4 Mmatrix;attribute vec3 color;varying vec3 vColor;void main(void) {gl_Position = Pmatrix * Vmatrix * Mmatrix * vec4(position,1.);vColor = color;}
|
||||
'
|
||||
|
||||
frag_code = 'precision mediump float;varying vec3 vColor;void main(void) {gl_FragColor = vec4(vColor, 1.);}
|
||||
'
|
||||
|
||||
vertices = [
|
||||
f32(-1),
|
||||
-1,
|
||||
-1,
|
||||
1,
|
||||
-1,
|
||||
-1,
|
||||
1,
|
||||
1,
|
||||
-1,
|
||||
-1,
|
||||
1,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
1,
|
||||
1,
|
||||
-1,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
-1,
|
||||
1,
|
||||
1,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
1,
|
||||
-1,
|
||||
-1,
|
||||
1,
|
||||
1,
|
||||
-1,
|
||||
-1,
|
||||
1,
|
||||
1,
|
||||
-1,
|
||||
-1,
|
||||
1,
|
||||
1,
|
||||
-1,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
-1,
|
||||
1,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
1,
|
||||
1,
|
||||
-1,
|
||||
1,
|
||||
1,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
1,
|
||||
-1,
|
||||
-1,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
-1,
|
||||
]
|
||||
colors = [
|
||||
f32(5),
|
||||
3,
|
||||
7,
|
||||
5,
|
||||
3,
|
||||
7,
|
||||
5,
|
||||
3,
|
||||
7,
|
||||
5,
|
||||
3,
|
||||
7,
|
||||
1,
|
||||
1,
|
||||
3,
|
||||
1,
|
||||
1,
|
||||
3,
|
||||
1,
|
||||
1,
|
||||
3,
|
||||
1,
|
||||
1,
|
||||
3,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
1,
|
||||
0,
|
||||
1,
|
||||
1,
|
||||
0,
|
||||
1,
|
||||
1,
|
||||
0,
|
||||
1,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
]
|
||||
indices = [
|
||||
u16(0),
|
||||
1,
|
||||
2,
|
||||
0,
|
||||
2,
|
||||
3,
|
||||
4,
|
||||
5,
|
||||
6,
|
||||
4,
|
||||
6,
|
||||
7,
|
||||
8,
|
||||
9,
|
||||
10,
|
||||
8,
|
||||
10,
|
||||
11,
|
||||
12,
|
||||
13,
|
||||
14,
|
||||
12,
|
||||
14,
|
||||
15,
|
||||
16,
|
||||
17,
|
||||
18,
|
||||
16,
|
||||
18,
|
||||
19,
|
||||
20,
|
||||
21,
|
||||
22,
|
||||
20,
|
||||
22,
|
||||
23,
|
||||
]
|
||||
amortization = 0.95
|
||||
)
|
||||
|
||||
fn get_webgl() (&JS.HTMLCanvasElement, JS.WebGLRenderingContext) {
|
||||
JS.console.log(dom.document)
|
||||
elem := dom.document.getElementById('myCanvas'.str) or { panic('cannot get canvas') }
|
||||
match elem {
|
||||
JS.HTMLCanvasElement {
|
||||
webgl := elem.getContext('experimental-webgl'.str, js_undefined()) or {
|
||||
panic('context not found')
|
||||
}
|
||||
match webgl {
|
||||
JS.WebGLRenderingContext {
|
||||
return elem, webgl
|
||||
}
|
||||
else {
|
||||
panic('cannot get webgl')
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
panic('not an canvas')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn get_projection(angle f64, a f64, z_min f64, z_max f64) []f64 {
|
||||
ang := math.tan((angle * 0.5) * math.pi / 180)
|
||||
return [
|
||||
0.5 / ang,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0.5 * a / ang,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
-(z_max + z_min) / (z_max - z_min),
|
||||
-1,
|
||||
0,
|
||||
0,
|
||||
(-2 * z_max * z_min) / (z_max - z_min),
|
||||
0,
|
||||
]
|
||||
}
|
||||
|
||||
fn JS.Math.cos(JS.Number) JS.Number
|
||||
fn JS.Math.sin(JS.Number) JS.Number
|
||||
fn rotate_x(mut m []f64, angle f64) {
|
||||
c := math.cos(angle)
|
||||
s := math.sin(angle)
|
||||
mv1 := m[1]
|
||||
mv5 := m[5]
|
||||
mv9 := m[9]
|
||||
m[1] = m[1] * c - m[2] * s
|
||||
m[5] = m[5] * c - m[6] * s
|
||||
m[9] = m[9] * c - m[10] * s
|
||||
|
||||
m[2] = m[2] * c + mv1 * s
|
||||
m[6] = m[6] * c + mv5 * s
|
||||
m[10] = m[10] * c + mv9 * s
|
||||
}
|
||||
|
||||
fn rotate_y(mut m []f64, angle f64) {
|
||||
c := math.cos(angle)
|
||||
s := math.sin(angle)
|
||||
|
||||
mv0 := m[0]
|
||||
mv4 := m[4]
|
||||
mv8 := m[8]
|
||||
m[0] = c * m[0] + s * m[2]
|
||||
m[4] = c * m[4] + s * m[6]
|
||||
m[8] = c * m[8] + s * m[10]
|
||||
|
||||
m[2] = c * m[2] - s * mv0
|
||||
m[6] = c * m[6] - s * mv4
|
||||
m[10] = c * m[10] - s * mv8
|
||||
}
|
||||
|
||||
struct State {
|
||||
mut:
|
||||
drag bool
|
||||
gl JS.WebGLRenderingContext
|
||||
canvas JS.HTMLCanvasElement
|
||||
old_x f64
|
||||
old_y f64
|
||||
dx f64
|
||||
dy f64
|
||||
theta f64
|
||||
phi f64
|
||||
time_old f64
|
||||
mo_matrix []f64
|
||||
view_matrix []f64
|
||||
proj_matrix []f64
|
||||
pmatrix JS.WebGLUniformLocation
|
||||
vmatrix JS.WebGLUniformLocation
|
||||
mmatrix JS.WebGLUniformLocation
|
||||
index_buffer JS.WebGLBuffer
|
||||
}
|
||||
|
||||
fn animate(mut state State, time f64) {
|
||||
if !state.drag {
|
||||
state.dx = state.dx * amortization
|
||||
state.dy = state.dy * amortization
|
||||
state.theta += state.dx
|
||||
state.phi += state.dy
|
||||
}
|
||||
|
||||
state.mo_matrix[0] = 1
|
||||
state.mo_matrix[1] = 0
|
||||
state.mo_matrix[2] = 0
|
||||
state.mo_matrix[3] = 0
|
||||
|
||||
state.mo_matrix[4] = 0
|
||||
state.mo_matrix[5] = 1
|
||||
state.mo_matrix[6] = 0
|
||||
state.mo_matrix[7] = 0
|
||||
|
||||
state.mo_matrix[8] = 0
|
||||
state.mo_matrix[9] = 0
|
||||
state.mo_matrix[10] = 1
|
||||
state.mo_matrix[11] = 0
|
||||
|
||||
state.mo_matrix[12] = 0
|
||||
state.mo_matrix[13] = 0
|
||||
state.mo_matrix[14] = 0
|
||||
state.mo_matrix[15] = 1
|
||||
// println('${state.theta} ${state.phi}')
|
||||
rotate_x(mut state.mo_matrix, state.phi)
|
||||
rotate_y(mut state.mo_matrix, state.theta)
|
||||
state.time_old = time
|
||||
state.gl.enable(dom.gl_depth_test())
|
||||
state.gl.clearColor(0.5, 0.5, 0.5, 0.9)
|
||||
state.gl.clearDepth(1.0)
|
||||
state.gl.viewport(0.0, 0.0, state.canvas.width, state.canvas.height)
|
||||
state.gl.clear(JS.Number(int(dom.gl_color_buffer_bit()) | int(dom.gl_depth_buffer_bit())))
|
||||
|
||||
state.gl.uniformMatrix4fv(state.pmatrix, JS.Boolean(false), state.proj_matrix.to_number_array())
|
||||
state.gl.uniformMatrix4fv(state.vmatrix, JS.Boolean(false), state.view_matrix.to_number_array())
|
||||
state.gl.uniformMatrix4fv(state.mmatrix, JS.Boolean(false), state.mo_matrix.to_number_array())
|
||||
|
||||
state.gl.bindBuffer(dom.gl_element_array_buffer(), state.index_buffer)
|
||||
state.gl.drawElements(dom.gl_triangles(), indices.len, dom.gl_unsigned_short(), 0)
|
||||
|
||||
dom.window().requestAnimationFrame(fn [mut state] (time JS.Number) {
|
||||
animate(mut state, f64(time))
|
||||
})
|
||||
}
|
||||
|
||||
fn main() {
|
||||
canvas, gl := get_webgl()
|
||||
|
||||
vertex_buffer := gl.createBuffer() ?
|
||||
gl.bindBuffer(dom.gl_array_buffer(), vertex_buffer)
|
||||
gl.bufferData(dom.gl_array_buffer(), float32_array(vertices), dom.gl_static_draw())
|
||||
|
||||
color_buffer := gl.createBuffer() ?
|
||||
gl.bindBuffer(dom.gl_array_buffer(), color_buffer)
|
||||
gl.bufferData(dom.gl_array_buffer(), float32_array(colors), dom.gl_static_draw())
|
||||
|
||||
index_buffer := gl.createBuffer() ?
|
||||
gl.bindBuffer(dom.gl_element_array_buffer(), index_buffer)
|
||||
gl.bufferData(dom.gl_element_array_buffer(), uint16_array(indices), dom.gl_static_draw())
|
||||
|
||||
vert_shader := gl.createShader(dom.gl_vertex_shader()) ?
|
||||
gl.shaderSource(vert_shader, vert_code.str)
|
||||
gl.compileShader(vert_shader)
|
||||
|
||||
if !bool(JS.Boolean(gl.getShaderParameter(vert_shader, dom.gl_compile_status()))) {
|
||||
panic('An error occurred when compiling vertex shader: ${string(gl.getShaderInfoLog(vert_shader))}')
|
||||
}
|
||||
|
||||
frag_shader := gl.createShader(dom.gl_fragment_shader()) ?
|
||||
gl.shaderSource(frag_shader, frag_code.str)
|
||||
gl.compileShader(frag_shader)
|
||||
if !bool(JS.Boolean(gl.getShaderParameter(frag_shader, dom.gl_compile_status()))) {
|
||||
panic('An error occurred when compiling fragment shader: ${string(gl.getShaderInfoLog(frag_shader))}')
|
||||
}
|
||||
|
||||
shader_program := gl.createProgram() ?
|
||||
gl.attachShader(shader_program, vert_shader)
|
||||
gl.attachShader(shader_program, frag_shader)
|
||||
gl.linkProgram(shader_program)
|
||||
|
||||
if !bool(JS.Boolean(gl.getProgramParameter(shader_program, dom.gl_link_status()))) {
|
||||
panic('unable to initialize the shader program: ${string(gl.getProgramInfoLog(shader_program))}')
|
||||
}
|
||||
|
||||
pmatrix := gl.getUniformLocation(shader_program, 'Pmatrix'.str) ?
|
||||
vmatrix := gl.getUniformLocation(shader_program, 'Vmatrix'.str) ?
|
||||
mmatrix := gl.getUniformLocation(shader_program, 'Mmatrix'.str) ?
|
||||
|
||||
gl.bindBuffer(dom.gl_array_buffer(), vertex_buffer)
|
||||
position := gl.getAttribLocation(shader_program, 'position'.str)
|
||||
gl.vertexAttribPointer(position, JS.Number(3), dom.gl_float(), JS.Boolean(false),
|
||||
JS.Number(0), JS.Number(0))
|
||||
gl.enableVertexAttribArray(position)
|
||||
|
||||
gl.bindBuffer(dom.gl_array_buffer(), color_buffer)
|
||||
color := gl.getAttribLocation(shader_program, 'color'.str)
|
||||
gl.vertexAttribPointer(color, JS.Number(3), dom.gl_float(), JS.Boolean(false), JS.Number(0),
|
||||
JS.Number(0))
|
||||
gl.enableVertexAttribArray(color)
|
||||
gl.useProgram(shader_program)
|
||||
|
||||
mut proj_matrix := get_projection(40.0, f64(canvas.width) / f64(canvas.height), 1.0,
|
||||
100.0)
|
||||
mut mo_matrix := [f64(1), 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]
|
||||
mut view_matrix := [f64(1), 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]
|
||||
|
||||
view_matrix[14] = view_matrix[14] - 6
|
||||
|
||||
mut state := State{false, gl, canvas, 0, 0, 0, 0, 0, 0, 0, mo_matrix, view_matrix, proj_matrix, pmatrix, vmatrix, mmatrix, index_buffer}
|
||||
|
||||
canvas.addEventListener('mousedown'.str, fn [mut state] (e JS.Event) {
|
||||
state.drag = true
|
||||
match e {
|
||||
JS.MouseEvent {
|
||||
state.old_x = f64(e.pageX)
|
||||
state.old_y = f64(e.pageY)
|
||||
e.preventDefault()
|
||||
}
|
||||
else {}
|
||||
}
|
||||
}, JS.EventListenerOptions{})
|
||||
|
||||
canvas.addEventListener('mouseup'.str, fn [mut state] (e JS.Event) {
|
||||
state.drag = false
|
||||
}, JS.EventListenerOptions{})
|
||||
canvas.addEventListener('mouseout'.str, fn [mut state] (e JS.Event) {
|
||||
state.drag = false
|
||||
}, JS.EventListenerOptions{})
|
||||
canvas.addEventListener('mousemove'.str, fn [mut state] (e JS.Event) {
|
||||
if !state.drag {
|
||||
return
|
||||
}
|
||||
match e {
|
||||
JS.MouseEvent {
|
||||
state.dx = (f64(e.pageX) - state.old_x) * 2.0 * math.pi / f64(state.canvas.width)
|
||||
state.dy = (f64(e.pageY) - state.old_y) * 2.0 * math.pi / f64(state.canvas.height)
|
||||
state.theta += state.dx
|
||||
state.phi += state.dy
|
||||
state.old_x = f64(e.pageX)
|
||||
state.old_y = f64(e.pageY)
|
||||
e.preventDefault()
|
||||
}
|
||||
else {
|
||||
panic('not a mouse event??')
|
||||
}
|
||||
}
|
||||
}, JS.EventListenerOptions{})
|
||||
|
||||
animate(mut state, 0)
|
||||
}
|
||||
6
examples/js_dom_cube/index.html
Normal file
6
examples/js_dom_cube/index.html
Normal file
@@ -0,0 +1,6 @@
|
||||
<body>
|
||||
<canvas width="570" height="570" id="myCanvas"></canvas>
|
||||
<script src="cube.js">
|
||||
|
||||
</script>
|
||||
</body>
|
||||
7
examples/js_dom_draw/README.md
Normal file
7
examples/js_dom_draw/README.md
Normal file
@@ -0,0 +1,7 @@
|
||||
Drawing with mouse events using DOM API. Adopted from MDN examples.
|
||||
|
||||
# Compiling
|
||||
```
|
||||
v -b js_browser examples/js_dom_draw/draw.js.v
|
||||
```
|
||||
Then you can open `index.html` with your favourite browser.
|
||||
90
examples/js_dom_draw/draw.js.v
Normal file
90
examples/js_dom_draw/draw.js.v
Normal file
@@ -0,0 +1,90 @@
|
||||
import js.dom
|
||||
|
||||
fn get_canvas(elem JS.HTMLElement) &JS.HTMLCanvasElement {
|
||||
match elem {
|
||||
JS.HTMLCanvasElement {
|
||||
return elem
|
||||
}
|
||||
else {
|
||||
panic('Not a canvas')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn draw_line(mut context JS.CanvasRenderingContext2D, x1 int, y1 int, x2 int, y2 int) {
|
||||
context.beginPath()
|
||||
context.strokeStyle = 'black'.str
|
||||
context.lineWidth = JS.Number(1)
|
||||
context.moveTo(x1, y1)
|
||||
context.lineTo(x2, y2)
|
||||
context.stroke()
|
||||
context.closePath()
|
||||
}
|
||||
|
||||
struct DrawState {
|
||||
mut:
|
||||
context JS.CanvasRenderingContext2D
|
||||
drawing bool
|
||||
x int
|
||||
y int
|
||||
}
|
||||
|
||||
fn main() {
|
||||
window := dom.window()
|
||||
document := dom.document
|
||||
clear_btn := document.getElementById('clearButton'.str) ?
|
||||
canvas_elem := document.getElementById('canvas'.str) ?
|
||||
canvas := get_canvas(canvas_elem)
|
||||
ctx := canvas.getContext('2d'.str, js_undefined()) ?
|
||||
context := match ctx {
|
||||
JS.CanvasRenderingContext2D {
|
||||
ctx
|
||||
}
|
||||
else {
|
||||
panic('can not get 2d context')
|
||||
}
|
||||
}
|
||||
mut state := DrawState{context, false, 0, 0}
|
||||
|
||||
canvas.addEventListener('mousedown'.str, fn [mut state] (event JS.Event) {
|
||||
state.drawing = true
|
||||
match event {
|
||||
JS.MouseEvent {
|
||||
state.x = int(event.offsetX)
|
||||
state.y = int(event.offsetY)
|
||||
}
|
||||
else {}
|
||||
}
|
||||
}, JS.EventListenerOptions{})
|
||||
canvas.addEventListener('mousemove'.str, fn [mut state] (event JS.Event) {
|
||||
if state.drawing {
|
||||
match event {
|
||||
JS.MouseEvent {
|
||||
draw_line(mut state.context, state.x, state.y, int(event.offsetX),
|
||||
int(event.offsetY))
|
||||
state.x = int(event.offsetX)
|
||||
state.y = int(event.offsetY)
|
||||
}
|
||||
else {}
|
||||
}
|
||||
}
|
||||
}, JS.EventListenerOptions{})
|
||||
|
||||
window.addEventListener('mouseup'.str, fn [mut state] (event JS.Event) {
|
||||
if state.drawing {
|
||||
match event {
|
||||
JS.MouseEvent {
|
||||
draw_line(mut state.context, state.x, state.y, int(event.offsetX),
|
||||
int(event.offsetY))
|
||||
}
|
||||
else {}
|
||||
}
|
||||
state.x = 0
|
||||
state.y = 0
|
||||
state.drawing = false
|
||||
}
|
||||
}, JS.EventListenerOptions{})
|
||||
clear_btn.addEventListener('click'.str, fn [mut state, canvas] (_ JS.Event) {
|
||||
state.context.clearRect(0, 0, canvas.width, canvas.height)
|
||||
}, JS.EventListenerOptions{})
|
||||
}
|
||||
7
examples/js_dom_draw/index.html
Normal file
7
examples/js_dom_draw/index.html
Normal file
@@ -0,0 +1,7 @@
|
||||
<body class="main">
|
||||
<title>Drawing with mouse events</title>
|
||||
<input type="button" id="clearButton" value="Clear canvas">
|
||||
<canvas style="border: 1px solid black;" width="720" height="480" id="canvas"></canvas>
|
||||
<script type="text/javascript" src="draw.js"></script>
|
||||
|
||||
</body>
|
||||
@@ -11,8 +11,14 @@ fn main() {
|
||||
l.info('info')
|
||||
l.warn('warn')
|
||||
l.error('error')
|
||||
l.debug('no debug')
|
||||
l.debug('no output for debug')
|
||||
l.set_level(.debug)
|
||||
l.debug('debug')
|
||||
l.fatal('fatal')
|
||||
l.debug('debug now')
|
||||
l.set_level(log.level_from_tag('INFO') or { log.Level.disabled }) // set level from string, sample
|
||||
l.info('info again')
|
||||
l.set_level(log.level_from_tag('') or { log.Level.disabled }) // set level from string, sample
|
||||
l.error('no output anymore')
|
||||
l.fatal('fatal') // panic, next statements won't be executed
|
||||
l.set_level(.info)
|
||||
l.warn('warn')
|
||||
}
|
||||
|
||||
@@ -1,20 +1,18 @@
|
||||
// fn println(s string) { }
|
||||
|
||||
// fn test_fn() {
|
||||
// println('test fn')
|
||||
//}
|
||||
fn test_fn() {
|
||||
println('test fn')
|
||||
}
|
||||
|
||||
fn main() {
|
||||
println('native test')
|
||||
// i := 0
|
||||
// for i < 5 {
|
||||
for _ in 1 .. 5 {
|
||||
println('Hello world from V native machine code generator!')
|
||||
// i++
|
||||
mut i := 0
|
||||
for i < 5 {
|
||||
println('Hello world from V native machine code generator, in a while style for loop!')
|
||||
i++
|
||||
}
|
||||
for _ in 1 .. 5 {
|
||||
println('Hello world from V native machine code generator, in a range loop!')
|
||||
}
|
||||
/*
|
||||
println('Hello again!')
|
||||
//test_fn()
|
||||
test_fn()
|
||||
println('done')
|
||||
*/
|
||||
}
|
||||
|
||||
@@ -166,135 +166,159 @@ fn (sp Sphere) intersect(r Ray) f64 {
|
||||
const (
|
||||
cen = Vec{50, 40.8, -860} // used by scene 1
|
||||
spheres = [
|
||||
[/* scene 0 cornnel box */ Sphere{
|
||||
rad: 1e+5
|
||||
p: Vec{1e+5 + 1, 40.8, 81.6}
|
||||
e: Vec{}
|
||||
c: Vec{.75, .25, .25}
|
||||
refl: .diff
|
||||
}, /* Left */ Sphere{
|
||||
rad: 1e+5
|
||||
p: Vec{-1e+5 + 99, 40.8, 81.6}
|
||||
e: Vec{}
|
||||
c: Vec{.25, .25, .75}
|
||||
refl: .diff
|
||||
}, /* Rght */ Sphere{
|
||||
rad: 1e+5
|
||||
p: Vec{50, 40.8, 1e+5}
|
||||
e: Vec{}
|
||||
c: Vec{.75, .75, .75}
|
||||
refl: .diff
|
||||
}, /* Back */ Sphere{
|
||||
rad: 1e+5
|
||||
p: Vec{50, 40.8, -1e+5 + 170}
|
||||
e: Vec{}
|
||||
c: Vec{}
|
||||
refl: .diff
|
||||
}, /* Frnt */ Sphere{
|
||||
rad: 1e+5
|
||||
p: Vec{50, 1e+5, 81.6}
|
||||
e: Vec{}
|
||||
c: Vec{.75, .75, .75}
|
||||
refl: .diff
|
||||
}, /* Botm */ Sphere{
|
||||
rad: 1e+5
|
||||
p: Vec{50, -1e+5 + 81.6, 81.6}
|
||||
e: Vec{}
|
||||
c: Vec{.75, .75, .75}
|
||||
refl: .diff
|
||||
}, /* Top */ Sphere{
|
||||
rad: 16.5
|
||||
p: Vec{27, 16.5, 47}
|
||||
e: Vec{}
|
||||
c: Vec{1, 1, 1}.mult_s(.999)
|
||||
refl: .spec
|
||||
}, /* Mirr */ Sphere{
|
||||
rad: 16.5
|
||||
p: Vec{73, 16.5, 78}
|
||||
e: Vec{}
|
||||
c: Vec{1, 1, 1}.mult_s(.999)
|
||||
refl: .refr
|
||||
}, /* Glas */ Sphere{
|
||||
rad: 600
|
||||
p: Vec{50, 681.6 - .27, 81.6}
|
||||
e: Vec{12, 12, 12}
|
||||
c: Vec{}
|
||||
refl: .diff
|
||||
} /* Lite */],
|
||||
[/* scene 1 sunset */ Sphere{
|
||||
rad: 1600
|
||||
p: Vec{1.0, 0.0, 2.0}.mult_s(3000)
|
||||
e: Vec{1.0, .9, .8}.mult_s(1.2e+1 * 1.56 * 2)
|
||||
c: Vec{}
|
||||
refl: .diff
|
||||
}, /* sun */ Sphere{
|
||||
rad: 1560
|
||||
p: Vec{1, 0, 2}.mult_s(3500)
|
||||
e: Vec{1.0, .5, .05}.mult_s(4.8e+1 * 1.56 * 2)
|
||||
c: Vec{}
|
||||
refl: .diff
|
||||
}, /* horizon sun2 */ Sphere{
|
||||
rad: 10000
|
||||
p: cen + Vec{0, 0, -200}
|
||||
e: Vec{0.00063842, 0.02001478, 0.28923243}.mult_s(6e-2 * 8)
|
||||
c: Vec{.7, .7, 1}.mult_s(.25)
|
||||
refl: .diff
|
||||
}, /* sky */ Sphere{
|
||||
rad: 100000
|
||||
p: Vec{50, -100000, 0}
|
||||
e: Vec{}
|
||||
c: Vec{.3, .3, .3}
|
||||
refl: .diff
|
||||
}, /* grnd */ Sphere{
|
||||
rad: 110000
|
||||
p: Vec{50, -110048.5, 0}
|
||||
e: Vec{.9, .5, .05}.mult_s(4)
|
||||
c: Vec{}
|
||||
refl: .diff
|
||||
}, /* horizon brightener */ Sphere{
|
||||
rad: 4e+4
|
||||
p: Vec{50, -4e+4 - 30, -3000}
|
||||
e: Vec{}
|
||||
c: Vec{.2, .2, .2}
|
||||
refl: .diff
|
||||
}, /* mountains */ Sphere{
|
||||
rad: 26.5
|
||||
p: Vec{22, 26.5, 42}
|
||||
e: Vec{}
|
||||
c: Vec{1, 1, 1}.mult_s(.596)
|
||||
refl: .spec
|
||||
}, /* white Mirr */ Sphere{
|
||||
rad: 13
|
||||
p: Vec{75, 13, 82}
|
||||
e: Vec{}
|
||||
c: Vec{.96, .96, .96}.mult_s(.96)
|
||||
refl: .refr
|
||||
}, /* Glas */ Sphere{
|
||||
rad: 22
|
||||
p: Vec{87, 22, 24}
|
||||
e: Vec{}
|
||||
c: Vec{.6, .6, .6}.mult_s(.696)
|
||||
refl: .refr
|
||||
} /* Glas2 */],
|
||||
[/* scene 3 Psychedelic */ Sphere{
|
||||
rad: 150
|
||||
p: Vec{50 + 75, 28, 62}
|
||||
e: Vec{1, 1, 1}.mult_s(0e-3)
|
||||
c: Vec{1, .9, .8}.mult_s(.93)
|
||||
refl: .refr
|
||||
}, Sphere{
|
||||
rad: 28
|
||||
p: Vec{50 + 5, -28, 62}
|
||||
e: Vec{1, 1, 1}.mult_s(1e+1)
|
||||
c: Vec{1, 1, 1}.mult_s(0)
|
||||
refl: .diff
|
||||
}, Sphere{
|
||||
rad: 300
|
||||
p: Vec{50, 28, 62}
|
||||
e: Vec{1, 1, 1}.mult_s(0e-3)
|
||||
c: Vec{1, 1, 1}.mult_s(.93)
|
||||
refl: .spec
|
||||
}],
|
||||
[// scene 0 cornnel box
|
||||
Sphere{
|
||||
rad: 1e+5
|
||||
p: Vec{1e+5 + 1, 40.8, 81.6}
|
||||
e: Vec{}
|
||||
c: Vec{.75, .25, .25}
|
||||
refl: .diff
|
||||
}, /* Left */
|
||||
Sphere{
|
||||
rad: 1e+5
|
||||
p: Vec{-1e+5 + 99, 40.8, 81.6}
|
||||
e: Vec{}
|
||||
c: Vec{.25, .25, .75}
|
||||
refl: .diff
|
||||
}, /* Rght */
|
||||
Sphere{
|
||||
rad: 1e+5
|
||||
p: Vec{50, 40.8, 1e+5}
|
||||
e: Vec{}
|
||||
c: Vec{.75, .75, .75}
|
||||
refl: .diff
|
||||
}, /* Back */
|
||||
Sphere{
|
||||
rad: 1e+5
|
||||
p: Vec{50, 40.8, -1e+5 + 170}
|
||||
e: Vec{}
|
||||
c: Vec{}
|
||||
refl: .diff
|
||||
}, /* Frnt */
|
||||
Sphere{
|
||||
rad: 1e+5
|
||||
p: Vec{50, 1e+5, 81.6}
|
||||
e: Vec{}
|
||||
c: Vec{.75, .75, .75}
|
||||
refl: .diff
|
||||
}, /* Botm */
|
||||
Sphere{
|
||||
rad: 1e+5
|
||||
p: Vec{50, -1e+5 + 81.6, 81.6}
|
||||
e: Vec{}
|
||||
c: Vec{.75, .75, .75}
|
||||
refl: .diff
|
||||
}, /* Top */
|
||||
Sphere{
|
||||
rad: 16.5
|
||||
p: Vec{27, 16.5, 47}
|
||||
e: Vec{}
|
||||
c: Vec{1, 1, 1}.mult_s(.999)
|
||||
refl: .spec
|
||||
}, /* Mirr */
|
||||
Sphere{
|
||||
rad: 16.5
|
||||
p: Vec{73, 16.5, 78}
|
||||
e: Vec{}
|
||||
c: Vec{1, 1, 1}.mult_s(.999)
|
||||
refl: .refr
|
||||
}, /* Glas */
|
||||
Sphere{
|
||||
rad: 600
|
||||
p: Vec{50, 681.6 - .27, 81.6}
|
||||
e: Vec{12, 12, 12}
|
||||
c: Vec{}
|
||||
refl: .diff
|
||||
} /* Lite */,
|
||||
],
|
||||
[// scene 1 sunset
|
||||
Sphere{
|
||||
rad: 1600
|
||||
p: Vec{1.0, 0.0, 2.0}.mult_s(3000)
|
||||
e: Vec{1.0, .9, .8}.mult_s(1.2e+1 * 1.56 * 2)
|
||||
c: Vec{}
|
||||
refl: .diff
|
||||
}, /* sun */
|
||||
Sphere{
|
||||
rad: 1560
|
||||
p: Vec{1, 0, 2}.mult_s(3500)
|
||||
e: Vec{1.0, .5, .05}.mult_s(4.8e+1 * 1.56 * 2)
|
||||
c: Vec{}
|
||||
refl: .diff
|
||||
}, /* horizon sun2 */
|
||||
Sphere{
|
||||
rad: 10000
|
||||
p: cen + Vec{0, 0, -200}
|
||||
e: Vec{0.00063842, 0.02001478, 0.28923243}.mult_s(6e-2 * 8)
|
||||
c: Vec{.7, .7, 1}.mult_s(.25)
|
||||
refl: .diff
|
||||
}, /* sky */
|
||||
Sphere{
|
||||
rad: 100000
|
||||
p: Vec{50, -100000, 0}
|
||||
e: Vec{}
|
||||
c: Vec{.3, .3, .3}
|
||||
refl: .diff
|
||||
}, /* grnd */
|
||||
Sphere{
|
||||
rad: 110000
|
||||
p: Vec{50, -110048.5, 0}
|
||||
e: Vec{.9, .5, .05}.mult_s(4)
|
||||
c: Vec{}
|
||||
refl: .diff
|
||||
}, /* horizon brightener */
|
||||
Sphere{
|
||||
rad: 4e+4
|
||||
p: Vec{50, -4e+4 - 30, -3000}
|
||||
e: Vec{}
|
||||
c: Vec{.2, .2, .2}
|
||||
refl: .diff
|
||||
}, /* mountains */
|
||||
Sphere{
|
||||
rad: 26.5
|
||||
p: Vec{22, 26.5, 42}
|
||||
e: Vec{}
|
||||
c: Vec{1, 1, 1}.mult_s(.596)
|
||||
refl: .spec
|
||||
}, /* white Mirr */
|
||||
Sphere{
|
||||
rad: 13
|
||||
p: Vec{75, 13, 82}
|
||||
e: Vec{}
|
||||
c: Vec{.96, .96, .96}.mult_s(.96)
|
||||
refl: .refr
|
||||
}, /* Glas */
|
||||
Sphere{
|
||||
rad: 22
|
||||
p: Vec{87, 22, 24}
|
||||
e: Vec{}
|
||||
c: Vec{.6, .6, .6}.mult_s(.696)
|
||||
refl: .refr
|
||||
} /* Glas2 */,
|
||||
],
|
||||
[// scene 3 Psychedelic
|
||||
Sphere{
|
||||
rad: 150
|
||||
p: Vec{50 + 75, 28, 62}
|
||||
e: Vec{1, 1, 1}.mult_s(0e-3)
|
||||
c: Vec{1, .9, .8}.mult_s(.93)
|
||||
refl: .refr
|
||||
},
|
||||
Sphere{
|
||||
rad: 28
|
||||
p: Vec{50 + 5, -28, 62}
|
||||
e: Vec{1, 1, 1}.mult_s(1e+1)
|
||||
c: Vec{1, 1, 1}.mult_s(0)
|
||||
refl: .diff
|
||||
},
|
||||
Sphere{
|
||||
rad: 300
|
||||
p: Vec{50, 28, 62}
|
||||
e: Vec{1, 1, 1}.mult_s(0e-3)
|
||||
c: Vec{1, 1, 1}.mult_s(.93)
|
||||
refl: .spec
|
||||
},
|
||||
],
|
||||
] // end of scene array
|
||||
)
|
||||
|
||||
|
||||
100
examples/rule110.v
Normal file
100
examples/rule110.v
Normal file
@@ -0,0 +1,100 @@
|
||||
import os
|
||||
import rand
|
||||
|
||||
fn main() {
|
||||
mut arg := '31'
|
||||
if os.args.len != 2 {
|
||||
println('Usage: rule110 [<n>]')
|
||||
println('Using default `n` value: 31')
|
||||
} else {
|
||||
arg = os.args[1]
|
||||
}
|
||||
|
||||
mut n := arg.int()
|
||||
if n > 200 || n < 3 {
|
||||
eprintln('`n` must be between 3 and 200!')
|
||||
exit(1)
|
||||
}
|
||||
|
||||
print('\n')
|
||||
title := ' Rule 110 V Implementation '
|
||||
title_len := title.len
|
||||
if n > title_len {
|
||||
for _ in 0 .. (n - title_len) / 2 {
|
||||
print('=')
|
||||
}
|
||||
print(title)
|
||||
for _ in 0 .. (n - title_len) / 2 {
|
||||
print('=')
|
||||
}
|
||||
} else {
|
||||
println(title[1..(title_len - 1)])
|
||||
}
|
||||
|
||||
mut generation_bin := []int{len: n}
|
||||
for i in 0 .. n {
|
||||
generation_bin[i] = rand.intn(2)
|
||||
}
|
||||
print('\n')
|
||||
|
||||
// println('Random generated first automaton content: $generation_bin')
|
||||
for _ in 0 .. n {
|
||||
print_generation(generation_bin)
|
||||
next_generation(mut generation_bin)
|
||||
}
|
||||
}
|
||||
|
||||
fn print_generation(arr []int) {
|
||||
symbols := [' ', '*']!
|
||||
for i in 0 .. arr.len {
|
||||
print(symbols[arr[i]])
|
||||
}
|
||||
print('\n')
|
||||
}
|
||||
|
||||
fn next_generation(mut gen []int) {
|
||||
mut arr := gen.clone()
|
||||
mut prev := 0
|
||||
mut curr := 0
|
||||
mut next := 0
|
||||
for i in 0 .. arr.len {
|
||||
if (i - 1) % gen.len < 0 {
|
||||
prev = gen[gen.len - 1]
|
||||
} else {
|
||||
prev = gen[(i - 1) % gen.len]
|
||||
}
|
||||
curr = gen[i]
|
||||
next = gen[(i + 1) % gen.len]
|
||||
|
||||
if prev == 1 {
|
||||
if curr == 1 {
|
||||
if next == 1 { // 111
|
||||
arr[i] = 0
|
||||
} else { // 110
|
||||
arr[i] = 1
|
||||
}
|
||||
} else {
|
||||
if next == 1 { // 101
|
||||
arr[i] = 1
|
||||
} else { // 100
|
||||
arr[i] = 0
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if curr == 1 {
|
||||
if next == 1 { // 011
|
||||
arr[i] = 1
|
||||
} else { // 010
|
||||
arr[i] = 1
|
||||
}
|
||||
} else {
|
||||
if next == 1 { // 001
|
||||
arr[i] = 1
|
||||
} else { // 000
|
||||
arr[i] = 0
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
gen = arr.clone()
|
||||
}
|
||||
@@ -55,6 +55,7 @@ mut:
|
||||
best HighScore
|
||||
snake []Pos
|
||||
dir Direction
|
||||
last_dir Direction
|
||||
food Pos
|
||||
start_time i64
|
||||
last_tick i64
|
||||
@@ -70,6 +71,7 @@ fn (mut app App) reset_game() {
|
||||
Pos{0, 8},
|
||||
]
|
||||
app.dir = .right
|
||||
app.last_dir = app.dir
|
||||
app.food = Pos{10, 8}
|
||||
app.start_time = time.ticks()
|
||||
app.last_tick = time.ticks()
|
||||
@@ -91,22 +93,22 @@ fn (mut app App) move_food() {
|
||||
fn on_keydown(key gg.KeyCode, mod gg.Modifier, mut app App) {
|
||||
match key {
|
||||
.w, .up {
|
||||
if app.dir != .down {
|
||||
if app.last_dir != .down {
|
||||
app.dir = .up
|
||||
}
|
||||
}
|
||||
.s, .down {
|
||||
if app.dir != .up {
|
||||
if app.last_dir != .up {
|
||||
app.dir = .down
|
||||
}
|
||||
}
|
||||
.a, .left {
|
||||
if app.dir != .right {
|
||||
if app.last_dir != .right {
|
||||
app.dir = .left
|
||||
}
|
||||
}
|
||||
.d, .right {
|
||||
if app.dir != .left {
|
||||
if app.last_dir != .left {
|
||||
app.dir = .right
|
||||
}
|
||||
}
|
||||
@@ -150,6 +152,8 @@ fn on_frame(mut app App) {
|
||||
}
|
||||
app.snake << app.snake.last() + app.snake.last() - app.snake[app.snake.len - 2]
|
||||
}
|
||||
|
||||
app.last_dir = app.dir
|
||||
}
|
||||
// drawing snake
|
||||
for pos in app.snake {
|
||||
|
||||
@@ -7,25 +7,8 @@
|
||||
* that can be found in the LICENSE file.
|
||||
*
|
||||
* HOW TO COMPILE SHADERS:
|
||||
* - download the sokol shader convertor tool from https://github.com/floooh/sokol-tools-bin
|
||||
*
|
||||
* - compile the .glsl shader with:
|
||||
* linux : sokol-shdc --input cube_glsl.glsl --output cube_glsl.h --slang glsl330
|
||||
* windows: sokol-shdc.exe --input cube_glsl.glsl --output cube_glsl.h --slang glsl330
|
||||
*
|
||||
* --slang parameter can be:
|
||||
* - glsl330: desktop GL
|
||||
* - glsl100: GLES2 / WebGL
|
||||
* - glsl300es: GLES3 / WebGL2
|
||||
* - hlsl4: D3D11
|
||||
* - hlsl5: D3D11
|
||||
* - metal_macos: Metal on macOS
|
||||
* - metal_ios: Metal on iOS device
|
||||
* - metal_sim: Metal on iOS simulator
|
||||
* - wgpu: WebGPU
|
||||
*
|
||||
* you can have multiple platforms at the same time passing prameter like this: --slang glsl330:hlsl5:metal_macos
|
||||
* for further infos have a look at the sokol shader tool docs.
|
||||
* Run `v shader .` in this directory to compile the shaders.
|
||||
* For more info and help with shader compilation see `docs.md` and `v help shader`.
|
||||
*
|
||||
* TODO:
|
||||
* - add instancing
|
||||
@@ -41,7 +24,7 @@ import gg.m4
|
||||
|
||||
// GLSL Include and functions
|
||||
#flag -I @VMODROOT/.
|
||||
#include "cube_glsl.h" #Please use sokol-shdc to generate the necessary cube_glsl.h file from cube_glsl.glsl (see the instructions at the top of this file)
|
||||
#include "cube_glsl.h" # Should be generated with `v shader .` (see the instructions at the top of this file)
|
||||
|
||||
fn C.cube_shader_desc(gfx.Backend) &C.sg_shader_desc
|
||||
|
||||
|
||||
@@ -7,25 +7,8 @@
|
||||
* that can be found in the LICENSE file.
|
||||
*
|
||||
* HOW TO COMPILE SHADERS:
|
||||
* - download the sokol shader convertor tool from https://github.com/floooh/sokol-tools-bin
|
||||
*
|
||||
* - compile the .glsl shader with:
|
||||
* linux : sokol-shdc --input rt_glsl.glsl --output rt_glsl.h --slang glsl330
|
||||
* windows: sokol-shdc.exe --input rt_glsl.glsl --output rt_glsl.h --slang glsl330
|
||||
*
|
||||
* --slang parameter can be:
|
||||
* - glsl330: desktop GL
|
||||
* - glsl100: GLES2 / WebGL
|
||||
* - glsl300es: GLES3 / WebGL2
|
||||
* - hlsl4: D3D11
|
||||
* - hlsl5: D3D11
|
||||
* - metal_macos: Metal on macOS
|
||||
* - metal_ios: Metal on iOS device
|
||||
* - metal_sim: Metal on iOS simulator
|
||||
* - wgpu: WebGPU
|
||||
*
|
||||
* you can have multiple platforms at the same time passing parameters like this: --slang glsl330:hlsl5:metal_macos
|
||||
* for further infos have a look at the sokol shader tool docs.
|
||||
* Run `v shader .` in this directory to compile the shaders.
|
||||
* For more info and help with shader compilation see `docs.md` and `v help shader`.
|
||||
*
|
||||
* TODO:
|
||||
* - frame counter
|
||||
@@ -42,7 +25,7 @@ import time
|
||||
// GLSL Include and functions
|
||||
|
||||
#flag -I @VMODROOT/.
|
||||
#include "rt_glsl.h" #Please use sokol-shdc to generate the necessary rt_glsl.h file from rt_glsl.glsl (see the instructions at the top of this file)
|
||||
#include "rt_glsl.h" # Should be generated with `v shader .` (see the instructions at the top of this file)
|
||||
|
||||
fn C.rt_shader_desc(gfx.Backend) &C.sg_shader_desc
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user