Compare commits
323 Commits
12ec3b9d53
...
9a0f499506
Author | SHA1 | Date |
---|---|---|
Jef Roosens | 9a0f499506 | |
Jef Roosens | b21fa77baf | |
Delyan Angelov | da42f0d42b | |
Delyan Angelov | 3fc4459485 | |
yuyi | 020845f6c3 | |
yuyi | d7b1e57186 | |
yuyi | 60e817ff32 | |
yuyi | d6aa85d059 | |
playX | 7c6eaa8204 | |
Delyan Angelov | 78ab3296c9 | |
WoodyAtHome | 02c8a6057c | |
Alexander Medvednikov | d10f83ce15 | |
playX | bc397bb0e1 | |
Delyan Angelov | 32dd801201 | |
Delyan Angelov | 9cb8bb2968 | |
yuyi | c624de8523 | |
Delyan Angelov | e5c7fe3006 | |
Delyan Angelov | 39874ae168 | |
yuyi | d59f4e9479 | |
Larpon | ef6225c542 | |
yuyi | 0ab4133128 | |
spaceface | 36bec823c2 | |
WoodyAtHome | c2b763655d | |
Delyan Angelov | 1cf683d482 | |
Delyan Angelov | b4c529066a | |
Ben | cbb24d34c9 | |
yuyi | 7fe3ef9a6e | |
Larpon | 5068b8b293 | |
Jah-On | 02e026e298 | |
WoodyAtHome | eeff02a8ee | |
spaceface | c01a8a1737 | |
Delyan Angelov | c2bc9f4960 | |
crthpl | e4065bd57b | |
David 'Epper' Marshall | c28051020a | |
Delyan Angelov | b50f7fdc71 | |
Delyan Angelov | c70e18ea8f | |
Delyan Angelov | 3a09ccc80a | |
Larpon | dd6629e932 | |
David 'Epper' Marshall | 8d141878ce | |
Delyan Angelov | 67963e0ff2 | |
Delyan Angelov | 1225a865a3 | |
yuyi | fe9f97074b | |
Alexander Medvednikov | 3adad32355 | |
Alexander Medvednikov | b42c824cdb | |
Daniel Däschle | f0d46413d9 | |
JalonSolov | b3e80a3100 | |
j. redhead | 441637eeb4 | |
Delyan Angelov | cee7856c0f | |
Delyan Angelov | 714ce4e7fc | |
Delyan Angelov | c1bafe7a5a | |
playX | 6ec4185017 | |
Daniel Däschle | d407a6449d | |
Delyan Angelov | ed12a5c84c | |
yuyi | 3c95504a35 | |
Daniel Däschle | d679146a80 | |
Delyan Angelov | df029da942 | |
Daniel Däschle | 0972e67f72 | |
Delyan Angelov | 8ef9dc6247 | |
Delyan Angelov | 668d1b04d2 | |
Hunam | 20139ad756 | |
playX | 4952967366 | |
yuyi | f48f7014f0 | |
penguindark | e93a8766e5 | |
Delyan Angelov | b7ca4c1668 | |
yuyi | 8830af5c89 | |
yuyi | 5bc4fea9e0 | |
CC | 901b8f0c24 | |
spaceface | 49382f1f43 | |
Emily Hudson | c19b037880 | |
yuyi | cd4fa041ff | |
Larpon | 34a252ef84 | |
David 'Epper' Marshall | 26b81d68b5 | |
Larpon | 0ec1c8d9f0 | |
yuyi | 3afc7c4c6d | |
Delyan Angelov | cf536b848b | |
yuyi | 8f765ed5f1 | |
yuyi | 5697d4375b | |
yuyi | 606d8cfaca | |
Isaiah | 9e09b709e3 | |
yuyi | 940c78bdfd | |
Subhomoy Haldar | 79f8a3c796 | |
StunxFS | d24dce8eb3 | |
Dialga | 4400f9891e | |
yuyi | 8519996201 | |
Merlin Diavova | 106487d62f | |
David 'Epper' Marshall | 650fb493bd | |
Delyan Angelov | 084f2867b6 | |
WoodyAtHome | a0a3499bdc | |
Alexander Medvednikov | 0526499d5f | |
Merlin Diavova | f8747d05dc | |
StunxFS | d5e70552eb | |
David 'Epper' Marshall | aef95721a4 | |
yuyi | b04d46770b | |
yuyi | 724e7f037a | |
David 'Epper' Marshall | a91226c376 | |
Delyan Angelov | b53b1cc7cb | |
Delyan Angelov | 7ecd65221e | |
Delyan Angelov | 56cf0b0a2e | |
Delyan Angelov | 7f974a275a | |
Delyan Angelov | f956acd2f6 | |
Delyan Angelov | 9e8e364493 | |
Alexander Medvednikov | ca42ace367 | |
Alexander Medvednikov | 35cfa0da7c | |
playX | 6a6c005dc0 | |
Alexander Medvednikov | 9fb8de14dd | |
Alexander Medvednikov | 89c1e7f980 | |
yuyi | 70184ad1f8 | |
Alexander Medvednikov | 14f06ead1b | |
yuyi | 621574c12a | |
Hunam | 0699f324b5 | |
Lathanao | ce99a306c0 | |
StunxFS | 87de6df0e6 | |
Ekopalypse | 2027a1969b | |
Daniel Däschle | 76cdf75299 | |
yuyi | 45fe87c9e3 | |
yuyi | 3091f31019 | |
Claudio Cesar de Sá | 634796ae42 | |
Andréas Livet | 9fde5b067b | |
Daniel Däschle | 89fe82b732 | |
yuyi | b6058bfd6e | |
playX | 8afdb1c3ef | |
StunxFS | 7499506cf8 | |
Delyan Angelov | 785e9af8f1 | |
Delyan Angelov | 7170a09382 | |
Delyan Angelov | 01c1892995 | |
Delyan Angelov | a6b3e5d6a5 | |
Ned | 76a7354506 | |
yuyi | 4242e7610f | |
yuyi | e2aa5c9b3f | |
Ikko Ashimine | 223b96a59a | |
Delyan Angelov | 1a4d9017e2 | |
Alexander Medvednikov | af8be14639 | |
yuyi | ac90a2b53d | |
playX | 3bd6455178 | |
Alexander Medvednikov | 3d4b8dffdf | |
yuyi | f321422964 | |
Alexander Medvednikov | 1e9156fd71 | |
yuyi | 3732db2bcc | |
playX | 146051b231 | |
Delyan Angelov | 04a77c731e | |
yuyi | 63eacede95 | |
Hunam | 6da300428e | |
yuyi | 276bd8060c | |
Delyan Angelov | 0e5c1cee48 | |
Delyan Angelov | 4da2908d63 | |
StunxFS | cf92224248 | |
Delyan Angelov | ab1c265679 | |
spaceface | db185598d2 | |
yuyi | 990afe37e1 | |
yuyi | d72a25098a | |
yuyi | 25c1b174ca | |
yuyi | b9cf2db6a8 | |
playX | afbe6bf3a2 | |
Isaiah | a4fd349cf1 | |
yuyi | 968d2b4654 | |
spaceface | 332e821518 | |
Delyan Angelov | aed2d0caf2 | |
David 'Epper' Marshall | 91c1157810 | |
Daniel Däschle | ec92d467d1 | |
playX | 0b54196962 | |
Daniel Däschle | 9f8a34a528 | |
Delyan Angelov | 63d413f93c | |
Delyan Angelov | c0b37409d2 | |
Delyan Angelov | 8da42bfc85 | |
Delyan Angelov | 5277ce7dce | |
David 'Epper' Marshall | a2338dbb7c | |
Delyan Angelov | dcdfdf4dd8 | |
spaceface | dab649ec8a | |
Alexander Medvednikov | ce31a01a70 | |
yuyi | cd30b6ea82 | |
Daniel Däschle | 08fd0ce0de | |
StunxFS | db185e6580 | |
Benjamin Thomas | 48eb40cd2c | |
David 'Epper' Marshall | 881d0c04f1 | |
yuyi | ec865cfb37 | |
yuyi | 317acfda97 | |
Wertzui123 | 872f739396 | |
StunxFS | 995485c649 | |
StunxFS | 8b798acadd | |
Alexander Medvednikov | 77645fcf35 | |
spaceface | 14309594fe | |
David 'Epper' Marshall | 5a42350a78 | |
StunxFS | e24482a143 | |
playX | e56385d57d | |
yuyi | 7aca67fb60 | |
yuyi | dd94ab890a | |
yuyi | c802688690 | |
Atom | a225b25117 | |
Delyan Angelov | 4538efd8f4 | |
Delyan Angelov | e0ed8f8278 | |
Delyan Angelov | f72297c331 | |
Delyan Angelov | be04ec0620 | |
yuyi | 7dd5d9ee61 | |
yuyi | 09f8b6a380 | |
tzSharing | eb03fad934 | |
Delyan Angelov | f53b9b4f12 | |
Alexander Medvednikov | 7dbfa86f25 | |
yuyi | 82ac39eca6 | |
yuyi | 752e105f25 | |
tzSharing | 85f616877f | |
playX | b76095f28a | |
R cqls | c26b7666c7 | |
yuyi | be513b4c27 | |
Larpon | 1c48a8d760 | |
yuyi | 660201c188 | |
Brian Callahan | b9a0e2d285 | |
yuyi | 38afd74d26 | |
playX | 95880dfe5c | |
playX | dce2173ac9 | |
Alexander Medvednikov | 501b293e84 | |
Larpon | d799abd139 | |
yuyi | e42dc8e228 | |
yuyi | f89c81087b | |
yuyi | aeba110d01 | |
Larpon | 283d181047 | |
yuyi | 88f22b4367 | |
Delyan Angelov | 60e205a193 | |
Delyan Angelov | d35d67c2bd | |
Nick Treleaven | d8a5df9044 | |
Delyan Angelov | 147e6e669f | |
yuyi | 922cee9162 | |
Delyan Angelov | 1291b621f6 | |
fleur | ddbe812f1b | |
Haren S | 11ee2b6409 | |
stackotter | 563469ed9f | |
yuyi | c819f0f86f | |
Alexander Medvednikov | 9355048b6c | |
Delyan Angelov | 3388caa6c5 | |
Delyan Angelov | 365e7d6b34 | |
yuyi | d934472b17 | |
yuyi | b86320a669 | |
Claudio Cesar de Sá | a2db44bc38 | |
yuyi | 5dce091379 | |
Alexander Medvednikov | 9b565bf765 | |
tzSharing | 03d21a727e | |
Larpon | 506259adb6 | |
yuyi | 26b0e7fd34 | |
Delyan Angelov | 2080557f50 | |
yuyi | 8a18f9175a | |
yuyi | 448938be0d | |
yuyi | 99eb9fdaab | |
yuyi | f13583b04a | |
yuyi | 8013bd43b0 | |
Delyan Angelov | 5e8c4a3aff | |
StunxFS | 2a0b372d0d | |
ChAoS_UnItY | c5824c36f2 | |
Delyan Angelov | c789ea5a15 | |
sunnylcw | 4491b535ec | |
Delyan Angelov | 31b28af179 | |
lemon | 960225f7a7 | |
Nick Treleaven | 1533b77404 | |
yuyi | 0260c2a552 | |
Hunam | 0374f021c5 | |
mjh | 1546645f63 | |
Larpon | a1342e85c3 | |
yuyi | 52ea0b8cc3 | |
yuyi | ce4c2afc9c | |
yuyi | 44ba19716b | |
yuyi | 0c3b69eaef | |
Alexander Medvednikov | 364656b312 | |
Isaiah | 0887b59254 | |
yuyi | 8cc79e4299 | |
playX | 711e90cf99 | |
playX | f6a0c26a85 | |
Delyan Angelov | 9646e4b9d8 | |
Delyan Angelov | 006df58451 | |
JalonSolov | daf5d32327 | |
yuyi | a318a2e09e | |
yuyi | e16ce3af88 | |
yuyi | 6164654d11 | |
Nick Treleaven | 4400efeb9f | |
yuyi | 7ef64bde50 | |
yuyi | d0a11f50ca | |
Delyan Angelov | 379b638b57 | |
yuyi | fe371845da | |
spaceface | 775c4c34b5 | |
Ikko Ashimine | 56a3539ea9 | |
yuyi | 17c34b09a6 | |
yuyi | cb44f5981e | |
Vincenzo Palazzo | 4f14f7714f | |
Vincenzo Palazzo | 48486e1afb | |
Cameron Katri | 1fc54a1e5b | |
Delyan Angelov | 8a57f7ed2d | |
Julien de Carufel | 16ead4e63c | |
Alexander Medvednikov | 43931a8e77 | |
Delyan Angelov | 5b7e538119 | |
Delyan Angelov | 4a71b27c52 | |
Delyan Angelov | d75c408868 | |
Delyan Angelov | 82c5621621 | |
Delyan Angelov | 675f8b6300 | |
Delyan Angelov | ad231cec2f | |
Delyan Angelov | 87a373d82c | |
Delyan Angelov | c7aedb8e8d | |
Delyan Angelov | 375361b787 | |
Delyan Angelov | 840f474fb5 | |
Delyan Angelov | e802e0b9cb | |
Delyan Angelov | bb2a324d61 | |
Delyan Angelov | 868d3e1008 | |
Alexander Medvednikov | c03fe020bf | |
Delyan Angelov | 6f5a513d8b | |
Delyan Angelov | e18cb9748f | |
Delyan Angelov | 173e6a943b | |
Delyan Angelov | cc8803c602 | |
Alexander Medvednikov | 78cb6e2b41 | |
Alexander Medvednikov | 1c6f63ac0a | |
Alexander Medvednikov | fbb9e65c0f | |
Alexander Medvednikov | ae6a25f44e | |
Alexander Medvednikov | e97ebf8cfc | |
Alexander Medvednikov | 258d1f77dc | |
Alexander Medvednikov | af73e195da | |
Alexander Medvednikov | fb192d949b | |
Alexander Medvednikov | 0527ac633e | |
Alexander Medvednikov | dbcf6e9c33 | |
Alexander Medvednikov | c14984899b | |
Alexander Medvednikov | a1372e284c | |
Alexander Medvednikov | c3ad4e2069 | |
Alexander Medvednikov | d4a0d6f73c | |
Alexander Medvednikov | b49d873217 | |
Alexander Medvednikov | 014c3c97f0 | |
Alexander Medvednikov | 7f3b91e688 | |
Alexander Medvednikov | 1e7eb713fb | |
Alexander Medvednikov | ba7b329c73 | |
Alexander Medvednikov | e6ff1508d2 |
|
@ -15,6 +15,8 @@ ls -lat
|
|||
## try running the known failing tests first to get faster feedback
|
||||
./v test vlib/builtin/string_test.v vlib/strings/builder_test.v
|
||||
|
||||
./v test-cleancode
|
||||
|
||||
./v test-self
|
||||
|
||||
./v build-vbinaries
|
||||
|
|
|
@ -33,6 +33,7 @@ jobs:
|
|||
run: |
|
||||
echo $VFLAGS
|
||||
make
|
||||
./v test-cleancode
|
||||
./v -d debug_malloc -d debug_realloc -o v cmd/v
|
||||
./v -cg -cstrict -o v cmd/v
|
||||
# Test v -realloc arena allocation
|
||||
|
@ -54,6 +55,8 @@ jobs:
|
|||
echo $VFLAGS
|
||||
./v cmd/tools/test_if_v_test_system_works.v
|
||||
./cmd/tools/test_if_v_test_system_works
|
||||
- name: All code is formatted
|
||||
run: ./v test-cleancode
|
||||
- name: Self tests
|
||||
run: ./v test-self
|
||||
# - name: Self tests (-cstrict)
|
||||
|
@ -125,13 +128,15 @@ jobs:
|
|||
run: |
|
||||
./v -gc boehm cmd/tools/test_if_v_test_system_works.v
|
||||
./cmd/tools/test_if_v_test_system_works
|
||||
- name: All code is formatted
|
||||
run: ./v test-cleancode
|
||||
- name: Self tests with `-gc boehm` with V compiler using Boehm-GC itself
|
||||
run: ./v -gc boehm test-self
|
||||
- name: Test leak detector
|
||||
run: |
|
||||
./v -gc boehm_leak -o testcase_leak vlib/v/tests/testcase_leak.vv
|
||||
./testcase_leak 2>leaks.txt
|
||||
grep "Found 1 leaked object" leaks.txt && grep ", sz=1000," leaks.txt
|
||||
grep "Found 1 leaked object" leaks.txt && grep -P ", sz=\s?1000," leaks.txt
|
||||
- name: Test leak detector not being active for `-gc boehm`
|
||||
run: |
|
||||
./v -gc boehm -o testcase_leak vlib/v/tests/testcase_leak.vv
|
||||
|
@ -188,6 +193,8 @@ jobs:
|
|||
echo $VFLAGS
|
||||
./v cmd/tools/test_if_v_test_system_works.v
|
||||
./cmd/tools/test_if_v_test_system_works
|
||||
- name: All code is formatted
|
||||
run: ./v test-cleancode
|
||||
- name: Self tests
|
||||
run: VJOBS=1 ./v test-self
|
||||
- name: Build examples
|
||||
|
@ -280,6 +287,8 @@ jobs:
|
|||
echo $VFLAGS
|
||||
./v cmd/tools/test_if_v_test_system_works.v
|
||||
./cmd/tools/test_if_v_test_system_works
|
||||
- name: All code is formatted
|
||||
run: ./v test-cleancode
|
||||
- name: Self tests
|
||||
run: ./v test-self
|
||||
- name: Self tests (-prod)
|
||||
|
@ -372,6 +381,8 @@ jobs:
|
|||
echo $VFLAGS
|
||||
./v cmd/tools/test_if_v_test_system_works.v
|
||||
./cmd/tools/test_if_v_test_system_works
|
||||
- name: All code is formatted
|
||||
run: ./v test-cleancode
|
||||
- name: Self tests
|
||||
run: ./v test-self
|
||||
- name: Self tests (-prod)
|
||||
|
@ -429,7 +440,7 @@ jobs:
|
|||
- name: Test new v.c
|
||||
run: |
|
||||
.\v.exe -o v.c cmd/v
|
||||
gcc -Werror -I ./thirdparty/stdatomic/win -municode -w v.c
|
||||
gcc -Werror -municode -w v.c
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
.\v.exe setup-freetype
|
||||
|
@ -442,6 +453,8 @@ jobs:
|
|||
echo $VFLAGS
|
||||
./v cmd/tools/test_if_v_test_system_works.v
|
||||
./cmd/tools/test_if_v_test_system_works
|
||||
- name: All code is formatted
|
||||
run: ./v test-cleancode
|
||||
- name: Self tests
|
||||
run: .\v.exe test-self
|
||||
# - name: Test
|
||||
|
@ -500,6 +513,9 @@ jobs:
|
|||
echo $VFLAGS
|
||||
./v cmd/tools/test_if_v_test_system_works.v
|
||||
./cmd/tools/test_if_v_test_system_works
|
||||
### TODO: test-cleancode fails with msvc. Investigate why???
|
||||
## - name: All code is formatted
|
||||
## run: ./v test-cleancode
|
||||
- name: Self tests
|
||||
run: |
|
||||
./v -cg cmd\tools\vtest-self.v
|
||||
|
@ -534,7 +550,7 @@ jobs:
|
|||
- name: Test new v.c
|
||||
run: |
|
||||
.\v.exe -o v.c cmd/v
|
||||
.\thirdparty\tcc\tcc.exe -I ./thirdparty/stdatomic/win -Werror -w -ladvapi32 -bt10 v.c
|
||||
.\thirdparty\tcc\tcc.exe -Werror -w -ladvapi32 -bt10 v.c
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
.\v.exe setup-freetype
|
||||
|
@ -555,8 +571,8 @@ jobs:
|
|||
run: ./v doc -v clipboard
|
||||
- name: Test v build-tools
|
||||
run: ./v -W build-tools
|
||||
- name: Test ./v doc clipboard
|
||||
run: ./v doc clipboard
|
||||
- name: All code is formatted
|
||||
run: ./v test-cleancode
|
||||
- name: Self tests
|
||||
run: ./v test-self
|
||||
- name: Test v->js
|
||||
|
@ -575,7 +591,7 @@ jobs:
|
|||
## .\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
|
||||
## run: .\v.exe -o v.c cmd/v && .\thirdparty\tcc\tcc.exe -Werror -g -w -ladvapi32 -bt10 v.c
|
||||
## - name: v doctor
|
||||
## run: ./v doctor
|
||||
##
|
||||
|
|
|
@ -14,7 +14,7 @@ jobs:
|
|||
timeout-minutes: 30
|
||||
env:
|
||||
VFLAGS: -cc tcc -no-retry-compilation
|
||||
B_CFLAGS: -g -std=gnu11 -I ./thirdparty/stdatomic/nix -w
|
||||
B_CFLAGS: -g -std=gnu11 -w
|
||||
B_LFLAGS: -lm -lpthread
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
@ -52,7 +52,7 @@ jobs:
|
|||
timeout-minutes: 30
|
||||
env:
|
||||
VFLAGS: -cc clang
|
||||
B_CFLAGS: -g -std=gnu11 -I ./thirdparty/stdatomic/nix -w
|
||||
B_CFLAGS: -g -std=gnu11 -w
|
||||
B_LFLAGS: -lm -lpthread
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
|
|
@ -71,14 +71,14 @@ jobs:
|
|||
- 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 -I ./thirdparty/stdatomic/nix -w -o v_from_vc /tmp/v.c -lm -lpthread
|
||||
gcc -g -std=gnu11 -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 -cc msvc -os windows -o /tmp/v_win.c cmd/v
|
||||
x86_64-w64-mingw32-gcc -I ./thirdparty/stdatomic/win /tmp/v_win.c -std=c99 -w -municode -o v_from_vc.exe
|
||||
x86_64-w64-mingw32-gcc /tmp/v_win.c -std=c99 -w -municode -o v_from_vc.exe
|
||||
ls -lart v_from_vc.exe
|
||||
wine64 ./v_from_vc.exe version
|
||||
|
||||
|
|
|
@ -91,7 +91,9 @@ jobs:
|
|||
sudo apt-get install --quiet -y libfreetype6-dev libxi-dev libxcursor-dev libgl-dev
|
||||
sudo apt-get install clang
|
||||
- name: Build V
|
||||
run: make -j4 && ./v -cg -cstrict -o v cmd/v
|
||||
run: make && ./v -cg -cstrict -o v cmd/v
|
||||
- name: Ensure code is well formatted
|
||||
run: ./v test-cleancode
|
||||
- name: Self tests (-fsanitize=undefined)
|
||||
run: ./v -cflags "-fsanitize=undefined" -o v2 cmd/v && ./v2 -cflags -fsanitize=undefined test-self
|
||||
- name: Build examples (V compiled with -fsanitize=undefined)
|
||||
|
@ -115,7 +117,9 @@ jobs:
|
|||
sudo apt-get install --quiet -y postgresql libpq-dev libssl-dev sqlite3 libsqlite3-dev valgrind
|
||||
sudo apt-get install --quiet -y libfreetype6-dev libxi-dev libxcursor-dev libgl-dev
|
||||
- name: Build V
|
||||
run: make -j4 && ./v -cg -cstrict -o v cmd/v
|
||||
run: make && ./v -cg -cstrict -o v cmd/v
|
||||
- name: Ensure code is well formatted
|
||||
run: ./v test-cleancode
|
||||
- name: Self tests (-fsanitize=undefined)
|
||||
run: ./v -cflags "-fsanitize=undefined" -o v2 cmd/v && ./v2 -cflags -fsanitize=undefined test-self
|
||||
- name: Build examples (V compiled with -fsanitize=undefined)
|
||||
|
@ -140,7 +144,9 @@ jobs:
|
|||
sudo apt-get install --quiet -y libfreetype6-dev libxi-dev libxcursor-dev libgl-dev
|
||||
sudo apt-get install clang
|
||||
- name: Build V
|
||||
run: make -j4 && ./v -cg -cstrict -o v cmd/v
|
||||
run: make && ./v -cg -cstrict -o v cmd/v
|
||||
- name: Ensure code is well formatted
|
||||
run: ./v test-cleancode
|
||||
- name: Self tests (-fsanitize=address)
|
||||
run: ASAN_OPTIONS=detect_leaks=0 ./v -cflags "-fsanitize=address,pointer-compare,pointer-subtract" test-self
|
||||
- name: Self tests (V compiled with -fsanitize=address)
|
||||
|
@ -168,6 +174,11 @@ jobs:
|
|||
echo $VFLAGS
|
||||
.\make.bat -msvc
|
||||
.\v.exe self
|
||||
- name: Ensure code is well formatted
|
||||
run: |
|
||||
.\v.exe fmt -verify vlib/builtin/ vlib/v/scanner/ vlib/v/parser/ vlib/v/gen/
|
||||
## TODO: check to see why `v test-cleancode` does not work with msvc on windows
|
||||
|
||||
## - name: Install dependencies
|
||||
## run: |
|
||||
## .\v.exe setup-freetype
|
||||
|
@ -195,7 +206,9 @@ jobs:
|
|||
sudo apt-get install --quiet -y libfreetype6-dev libxi-dev libxcursor-dev libgl-dev
|
||||
sudo apt-get install clang
|
||||
- name: Build V
|
||||
run: make -j4 && ./v -cg -cstrict -o v cmd/v
|
||||
run: make && ./v -cg -cstrict -o v cmd/v
|
||||
- name: Ensure code is well formatted
|
||||
run: ./v test-cleancode
|
||||
- name: Self tests (-fsanitize=address)
|
||||
run: ASAN_OPTIONS=detect_leaks=0 ./v -cflags -fsanitize=address test-self
|
||||
- name: Self tests (V compiled with -fsanitize=address)
|
||||
|
@ -224,11 +237,14 @@ jobs:
|
|||
sudo apt-get install --quiet -y libfreetype6-dev libxi-dev libxcursor-dev libgl-dev
|
||||
sudo apt-get install clang
|
||||
- name: Build V
|
||||
run: make -j4 && ./v -cc clang -cg -cstrict -o v cmd/v
|
||||
run: make && ./v -cc clang -cg -cstrict -o v cmd/v
|
||||
- name: Ensure code is well formatted
|
||||
run: ./v test-cleancode
|
||||
- name: Self tests (-fsanitize=memory)
|
||||
run: ./v -cflags -fsanitize=memory test-self
|
||||
- name: Self tests (V compiled with -fsanitize=memory)
|
||||
run:
|
||||
./v -cflags -fsanitize=memory -o v cmd/v && ./v -cc tcc test-self -msan-compiler
|
||||
run: |
|
||||
./v -cflags -fsanitize=memory -o v cmd/v
|
||||
./v -cc tcc test-self -msan-compiler
|
||||
- name: Build examples (V compiled with -fsanitize=memory)
|
||||
run: ./v build-examples
|
||||
|
|
|
@ -42,6 +42,9 @@ jobs:
|
|||
- name: Build V
|
||||
run: CC=gcc make
|
||||
|
||||
- name: All code is formatted
|
||||
run: ./v test-cleancode
|
||||
|
||||
- name: Test V fixed tests
|
||||
run: ./v test-self
|
||||
|
||||
|
@ -69,5 +72,9 @@ jobs:
|
|||
echo $VFLAGS
|
||||
./v cmd/tools/test_if_v_test_system_works.v
|
||||
./cmd/tools/test_if_v_test_system_works
|
||||
|
||||
- name: All code is formatted
|
||||
run: ./v test-cleancode
|
||||
|
||||
- name: Test V fixed tests
|
||||
run: ./v test-self
|
||||
|
|
|
@ -25,12 +25,13 @@ jobs:
|
|||
.\v.exe setup-freetype
|
||||
.\.github\workflows\windows-install-sqlite.bat
|
||||
- name: v doctor
|
||||
run: |
|
||||
./v doctor
|
||||
run: ./v doctor
|
||||
- name: Verify `v test` works
|
||||
run: |
|
||||
./v cmd/tools/test_if_v_test_system_works.v
|
||||
./cmd/tools/test_if_v_test_system_works
|
||||
- name: All code is formatted
|
||||
run: ./v test-cleancode
|
||||
- name: Self tests
|
||||
run: |
|
||||
./v -cg cmd\tools\vtest-self.v
|
||||
|
|
|
@ -85,6 +85,7 @@ jobs:
|
|||
- name: g++ version
|
||||
run: g++-9 --version
|
||||
- name: V self compilation with g++
|
||||
continue-on-error: true
|
||||
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 test-self
|
||||
|
@ -93,6 +94,7 @@ jobs:
|
|||
run: ./v -autofree -o v2 cmd/v ## NB: this does not mean it runs, but at least keeps it from regressing
|
||||
|
||||
- name: Shader examples can be build
|
||||
continue-on-error: true
|
||||
run: |
|
||||
wget https://github.com/floooh/sokol-tools-bin/raw/33d2e4cc26088c6c28eaef5467990f8940d15aab/bin/linux/sokol-shdc
|
||||
chmod +x ./sokol-shdc
|
||||
|
@ -146,116 +148,3 @@ jobs:
|
|||
./v test-parser -S examples/regex_example_fuzz.v
|
||||
./v test-parser -S examples/2048/2048_fuzz.v
|
||||
|
||||
v-apps-compile:
|
||||
runs-on: ubuntu-20.04
|
||||
timeout-minutes: 121
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Build V
|
||||
run: make && sudo ./v symlink
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install --quiet -y libgc-dev
|
||||
sudo apt-get install --quiet -y libsodium-dev libssl-dev sqlite3 libsqlite3-dev valgrind
|
||||
sudo apt-get install --quiet -y libfreetype6-dev libxi-dev libxcursor-dev libgl-dev
|
||||
sudo apt-get install --quiet -y xfonts-75dpi xfonts-base
|
||||
|
||||
## vls
|
||||
- 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 with -prod
|
||||
run: pushd vls; v -prod cmd/vls; popd
|
||||
- name: Build VLS with -gc boehm -skip-unused
|
||||
run: pushd vls; v -gc boehm -skip-unused 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
|
||||
run: git clone --depth 1 https://github.com/vlang/vab
|
||||
- name: Build vab
|
||||
run: cd vab; ../v ./vab.v ; cd ..
|
||||
- name: Build vab with -gc boehm -skip-unused
|
||||
run: cd vab; ../v -gc boehm -skip-unused ./vab.v ; cd ..
|
||||
|
||||
## gitly
|
||||
- name: Install markdown
|
||||
run: ./v install markdown
|
||||
- name: Build Gitly
|
||||
run: |
|
||||
git clone --depth 1 https://github.com/vlang/gitly
|
||||
cd gitly
|
||||
../v .
|
||||
# ./gitly -ci_run
|
||||
../v -autofree .
|
||||
../v -o x tests/first_run.v
|
||||
./x
|
||||
cd ..
|
||||
|
||||
## vex
|
||||
- name: Install Vex dependencies
|
||||
run: sudo apt-get install --quiet -y libsodium-dev libssl-dev sqlite3 libsqlite3-dev
|
||||
- name: Install Vex
|
||||
run: mkdir -p ~/.vmodules/nedpals; git clone https://github.com/nedpals/vex ~/.vmodules/nedpals/vex
|
||||
- name: Compile all of the Vex examples
|
||||
run: ./v should-compile-all ~/.vmodules/nedpals/vex/examples
|
||||
- name: Compile the simple Vex example with -gc boehm -skip-unused
|
||||
run: ./v -gc boehm -skip-unused ~/.vmodules/nedpals/vex/examples/simple_example.v
|
||||
- name: Run Vex Tests
|
||||
run: ./v test ~/.vmodules/nedpals/vex
|
||||
|
||||
## vpm modules
|
||||
- name: Install UI through VPM
|
||||
run: ./v install ui
|
||||
|
||||
## libsodium
|
||||
- name: Install libsodium-dev package
|
||||
run: sudo apt-get install --quiet -y libsodium-dev
|
||||
- name: Installl the libsodium wrapper through VPM
|
||||
run: ./v install libsodium
|
||||
- name: Test libsodium
|
||||
run: VJOBS=1 ./v -stats test ~/.vmodules/libsodium
|
||||
|
||||
## Go2V
|
||||
- name: Clone & Build go2v
|
||||
run: git clone --depth=1 https://github.com/vlang/go2v go2v/
|
||||
- name: Build go2v
|
||||
run: ./v go2v/
|
||||
- name: Run tests for go2v
|
||||
run: VJOBS=1 ./v -stats test go2v/
|
||||
|
||||
## vlang/pdf
|
||||
- name: Clone & Build vlang/pdf
|
||||
run: git clone --depth=1 https://github.com/vlang/pdf ~/.vmodules/pdf/
|
||||
- name: PDF examples should compile
|
||||
run: ./v should-compile-all ~/.vmodules/pdf/examples
|
||||
|
|
|
@ -0,0 +1,145 @@
|
|||
name: V Apps and Modules
|
||||
|
||||
on:
|
||||
push:
|
||||
paths-ignore:
|
||||
- "**.md"
|
||||
pull_request:
|
||||
paths-ignore:
|
||||
- "**.md"
|
||||
|
||||
concurrency:
|
||||
group: build-other-${{ github.event.pull_request.number || github.sha }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
v-apps-compile:
|
||||
runs-on: ubuntu-20.04
|
||||
timeout-minutes: 121
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Build V
|
||||
run: make && sudo ./v symlink
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install --quiet -y libgc-dev
|
||||
sudo apt-get install --quiet -y libsodium-dev libssl-dev sqlite3 libsqlite3-dev valgrind
|
||||
sudo apt-get install --quiet -y libfreetype6-dev libxi-dev libxcursor-dev libgl-dev
|
||||
sudo apt-get install --quiet -y xfonts-75dpi xfonts-base
|
||||
|
||||
- name: Install UI through VPM
|
||||
continue-on-error: true
|
||||
run: |
|
||||
echo "Official VPM modules should be installable"
|
||||
./v install ui
|
||||
|
||||
- name: Build V Language Server (VLS)
|
||||
continue-on-error: true
|
||||
run: |
|
||||
echo "Clone VLS"
|
||||
git clone --depth 1 https://github.com/vlang/vls
|
||||
echo "Build VLS"
|
||||
pushd vls; v cmd/vls ; popd
|
||||
echo "Build VLS with -prod"
|
||||
pushd vls; v -prod cmd/vls; popd
|
||||
echo "Build VLS with -gc boehm -skip-unused"
|
||||
pushd vls; v -gc boehm -skip-unused cmd/vls; popd
|
||||
|
||||
- name: Build VSL
|
||||
continue-on-error: true
|
||||
run: |
|
||||
git clone --depth 1 https://github.com/vlang/vsl ~/.vmodules/vsl
|
||||
sudo apt-get install --quiet -y --no-install-recommends gfortran liblapacke-dev libopenblas-dev libgc-dev
|
||||
echo "Execute Tests using Pure V Backend"
|
||||
~/.vmodules/vsl/bin/test
|
||||
echo "Execute Tests using Pure V Backend with Pure V Math"
|
||||
~/.vmodules/vsl/bin/test --use-cblas
|
||||
echo "Execute Tests using Pure V Backend and Garbage Collection enabled"
|
||||
~/.vmodules/vsl/bin/test --use-gc boehm
|
||||
echo "Execute Tests using Pure V Backend with Pure V Math and Garbage Collection enabled"
|
||||
~/.vmodules/vsl/bin/test --use-cblas --use-gc boehm
|
||||
|
||||
- name: Build VTL
|
||||
continue-on-error: true
|
||||
run: |
|
||||
echo "Clone VTL"
|
||||
git clone --depth 1 https://github.com/vlang/vtl ~/.vmodules/vtl
|
||||
echo "Install dependencies"
|
||||
sudo apt-get install --quiet -y --no-install-recommends gfortran liblapacke-dev libopenblas-dev libgc-dev
|
||||
echo "Execute Tests using Pure V Backend"
|
||||
~/.vmodules/vtl/bin/test
|
||||
echo "Execute Tests using Pure V Backend with Pure V Math"
|
||||
~/.vmodules/vtl/bin/test --use-cblas
|
||||
echo "Execute Tests using Pure V Backend and Garbage Collection enabled"
|
||||
~/.vmodules/vtl/bin/test --use-gc boehm
|
||||
echo "Execute Tests using Pure V Backend with Pure V Math and Garbage Collection enabled"
|
||||
~/.vmodules/vtl/bin/test --use-cblas --use-gc boehm
|
||||
|
||||
- name: Build VAB
|
||||
continue-on-error: true
|
||||
run: |
|
||||
echo "Clone vab"
|
||||
git clone --depth 1 https://github.com/vlang/vab
|
||||
echo "Build vab"
|
||||
cd vab; ../v ./vab.v ; cd ..
|
||||
echo "Build vab with -gc boehm -skip-unused"
|
||||
cd vab; ../v -gc boehm -skip-unused ./vab.v ; cd ..
|
||||
|
||||
- name: Build Gitly
|
||||
continue-on-error: true
|
||||
run: |
|
||||
echo "Clone markdown"
|
||||
git clone https://github.com/vlang/markdown ~/.vmodules/markdown
|
||||
echo "Clone Gitly"
|
||||
git clone --depth 1 https://github.com/vlang/gitly
|
||||
cd gitly
|
||||
echo "Build Gitly"
|
||||
../v .
|
||||
echo "Build Gitly with -autofree"
|
||||
../v -autofree .
|
||||
echo "Run first_run.v"
|
||||
../v run tests/first_run.v
|
||||
# ./gitly -ci_run
|
||||
|
||||
- name: Build libsodium
|
||||
continue-on-error: true
|
||||
run: |
|
||||
echo "Install libsodium-dev package"
|
||||
sudo apt-get install --quiet -y libsodium-dev
|
||||
echo "Clone the libsodium wrapper"
|
||||
git clone https://github.com/vlang/libsodium ~/.vmodules/libsodium
|
||||
echo "Test libsodium"
|
||||
VJOBS=1 ./v -stats test ~/.vmodules/libsodium
|
||||
|
||||
- name: Build VEX
|
||||
continue-on-error: true
|
||||
run: |
|
||||
echo "Install Vex dependencies"
|
||||
sudo apt-get install --quiet -y libsodium-dev libssl-dev sqlite3 libsqlite3-dev
|
||||
echo "Clone Vex"
|
||||
mkdir -p ~/.vmodules/nedpals; git clone https://github.com/nedpals/vex ~/.vmodules/nedpals/vex
|
||||
echo "Compile all of the Vex examples"
|
||||
./v should-compile-all ~/.vmodules/nedpals/vex/examples
|
||||
echo "Compile the simple Vex example with -gc boehm -skip-unused"
|
||||
./v -gc boehm -skip-unused ~/.vmodules/nedpals/vex/examples/simple_example.v
|
||||
echo "Run Vex Tests"
|
||||
./v test ~/.vmodules/nedpals/vex
|
||||
|
||||
- name: Build go2v
|
||||
continue-on-error: true
|
||||
run: |
|
||||
echo "Clone go2v"
|
||||
clone --depth=1 https://github.com/vlang/go2v go2v/
|
||||
echo "Build go2v"
|
||||
./v go2v/
|
||||
## echo "Run tests for go2v"
|
||||
## VJOBS=1 ./v -stats test go2v/
|
||||
|
||||
- name: Build vlang/pdf
|
||||
continue-on-error: true
|
||||
run: |
|
||||
git clone --depth=1 https://github.com/vlang/pdf ~/.vmodules/pdf/
|
||||
echo "PDF examples should compile"
|
||||
./v should-compile-all ~/.vmodules/pdf/examples
|
|
@ -1,12 +1,11 @@
|
|||
@echo off
|
||||
|
||||
curl -L https://www.sqlite.org/2020/sqlite-amalgamation-3320300.zip -o sqlite-amalgamation-3320300.zip
|
||||
curl -L https://www.sqlite.org/2022/sqlite-amalgamation-3380200.zip -o sqlite-amalgamation-3380200.zip
|
||||
|
||||
unzip sqlite-amalgamation-3320300.zip -d thirdparty\
|
||||
unzip sqlite-amalgamation-3380200.zip -d thirdparty\
|
||||
|
||||
del thirdparty\sqlite-amalgamation-3320300\shell.c
|
||||
del thirdparty\sqlite-amalgamation-3380200\shell.c
|
||||
|
||||
move /y thirdparty\sqlite-amalgamation-3320300 thirdparty\sqlite
|
||||
move /y thirdparty\sqlite-amalgamation-3380200 thirdparty\sqlite
|
||||
|
||||
dir thirdparty\sqlite
|
||||
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
matrix:
|
||||
PLATFORM:
|
||||
- 'linux/amd64'
|
||||
- 'linux/arm64'
|
||||
|
||||
platform: ${PLATFORM}
|
||||
branches: ['master']
|
||||
depends_on:
|
||||
- 'vc'
|
||||
|
||||
pipeline:
|
||||
build:
|
||||
image: 'menci/archlinuxarm:base-devel'
|
||||
commands:
|
||||
# Update packages
|
||||
- pacman -Syu --noconfirm
|
||||
# Create non-root user to perform build & switch to their home
|
||||
- groupadd -g 1000 builder
|
||||
- useradd -mg builder builder
|
||||
- chown -R builder:builder "$PWD"
|
||||
- "echo 'builder ALL=(ALL) NOPASSWD: ALL' >> /etc/sudoers"
|
||||
- su builder
|
||||
# Build the package
|
||||
- makepkg -s --noconfirm --needed
|
||||
|
||||
publish:
|
||||
image: 'curlimages/curl'
|
||||
secrets:
|
||||
- 'vieter_api_key'
|
||||
commands:
|
||||
# Publish the package
|
||||
- 'for pkg in $(ls -1 *.pkg*); do curl -f -XPOST -T "$pkg" -H "X-API-KEY: $VIETER_API_KEY" https://arch.r8r.be/vieter/publish; done'
|
|
@ -0,0 +1,18 @@
|
|||
platform: 'linux/amd64'
|
||||
branches: ['master']
|
||||
depends_on:
|
||||
- 'vc'
|
||||
|
||||
pipeline:
|
||||
build-publish:
|
||||
image: 'woodpeckerci/plugin-docker-buildx'
|
||||
secrets: [ docker_username, docker_password ]
|
||||
settings:
|
||||
repo: chewingbever/vlang
|
||||
tag: latest
|
||||
dockerfile: Dockerfile.builder
|
||||
platforms: [ linux/arm64/v8, linux/amd64 ]
|
||||
# The build can run every time, because we should only push when there's
|
||||
# actual changes
|
||||
when:
|
||||
event: push
|
|
@ -0,0 +1,48 @@
|
|||
platform: 'linux/amd64'
|
||||
branches: ['master']
|
||||
|
||||
pipeline:
|
||||
gen-vc:
|
||||
# This is what the official CI uses as well
|
||||
image: 'ubuntu:latest'
|
||||
secrets:
|
||||
- deploy_key
|
||||
commands:
|
||||
# Install necessary dependencies
|
||||
- apt-get update -y && apt-get install openssh-client git build-essential -y
|
||||
# Build the compiler
|
||||
- make
|
||||
# Run ssh-agent
|
||||
- eval $(ssh-agent -s)
|
||||
# Add ssh key
|
||||
- echo "$DEPLOY_KEY" | tr -d '\r' | ssh-add -
|
||||
# Create ssh dir with proper permissions
|
||||
- mkdir -p ~/.ssh
|
||||
- chmod 700 ~/.ssh
|
||||
# Configure git credentials
|
||||
- git config --global user.email 'vbot@rustybever.be'
|
||||
- git config --global user.name 'vbot'
|
||||
# Verify SSH keys
|
||||
- ssh-keyscan git.rustybever.be > ~/.ssh/known_hosts
|
||||
|
||||
# The following is copied over from the official repo's CI
|
||||
# https://github.com/vlang/v/blob/master/.github/workflows/gen_vc.yml
|
||||
- export "COMMIT_HASH=$(git rev-parse --short HEAD)"
|
||||
- export "COMMIT_MSG=$(git log -1 --oneline --pretty='%s' HEAD)"
|
||||
- rm -rf vc
|
||||
- git clone --depth=1 'git@git.rustybever.be:vieter/vc.git'
|
||||
- rm -rf vc/v.c vc/v_win.c
|
||||
- ./v -o vc/v.c -os cross cmd/v
|
||||
- ./v -o vc/v_win.c -os windows -cc msvc cmd/v
|
||||
- sed -i "1s/^/#define V_COMMIT_HASH \"$COMMIT_HASH\"\n/" vc/v.c
|
||||
- sed -i "1s/^/#define V_COMMIT_HASH \"$COMMIT_HASH\"\n/" vc/v_win.c
|
||||
# ensure the C files are over 5000 lines long, as a safety measure
|
||||
- '[ $(wc -l < vc/v.c) -gt 5000 ]'
|
||||
- '[ $(wc -l < vc/v_win.c) -gt 5000 ]'
|
||||
- git -C vc add v.c v_win.c
|
||||
- 'git -C vc commit -m "[v:master] $COMMIT_HASH - $COMMIT_MSG"'
|
||||
# in case there are recent commits:
|
||||
- git -C vc pull --rebase origin main
|
||||
- git -C vc push
|
||||
when:
|
||||
event: push
|
|
@ -2,6 +2,7 @@
|
|||
-*Not yet released, changelog is not full*
|
||||
- Introduce `isize` and `usize` types, deprecate `size_t` in favor of `usize`.
|
||||
- Add `datatypes` and `datatypes.fsm` modules.
|
||||
- Add `compile_error` and `compile_warn` comptime functions.
|
||||
|
||||
-## V 0.2.4
|
||||
-*Not yet released, changelog is not full*
|
||||
|
|
|
@ -35,32 +35,35 @@ The main files are:
|
|||
- Creates a parser object for each file and runs `parse()` on them.
|
||||
- The correct backend is called (C, JS, native), and a binary is compiled.
|
||||
|
||||
2. `v/scanner` The scanner's job is to parse a list of characters and convert
|
||||
2. `vlib/v/scanner` The scanner's job is to parse a list of characters and convert
|
||||
them to tokens.
|
||||
|
||||
3. `v/token` This is simply a list of all tokens, their string values, and a
|
||||
3. `vlib/v/token` This is simply a list of all tokens, their string values, and a
|
||||
couple of helper functions.
|
||||
|
||||
4. `v/parser` The parser. It converts a list of tokens into an AST.
|
||||
4. `vlib/v/parser` The parser. It converts a list of tokens into an AST.
|
||||
In V, objects can be used before declaration, so unknown types are marked as
|
||||
unresolved. They are resolved later in the type checker.
|
||||
|
||||
5. `v/table` V creates one table object that is shared by all parsers. It
|
||||
5. `vlib/v/table` V creates one table object that is shared by all parsers. It
|
||||
contains all types, consts, and functions, as well as several helpers to search
|
||||
for objects by name, register new objects, modify types' fields, etc.
|
||||
|
||||
6. `v/checker` Type checker and resolver. It processes the AST and makes sure
|
||||
6. `vlib/v/checker` Type checker and resolver. It processes the AST and makes sure
|
||||
the types are correct. Unresolved types are resolved, type information is added
|
||||
to the AST.
|
||||
|
||||
7. `v/gen/c` C backend. It simply walks the AST and generates C code that can be
|
||||
7. `vlib/v/gen/c` C backend. It simply walks the AST and generates C code that can be
|
||||
compiled with Clang, GCC, Visual Studio, and TCC.
|
||||
|
||||
8. `json.v` defines the json code generation. This file will be removed once V
|
||||
8. `vlib/v/gen/js` JavaScript backend. It simply walks the AST and generates JS code that can be
|
||||
executed on the browser or in NodeJS/Deno.
|
||||
|
||||
9. `vlib/v/gen/c/json.v` defines the json code generation. This file will be removed once V
|
||||
supports comptime code generation, and it will be possible to do this using the
|
||||
language's tools.
|
||||
|
||||
9. `v/gen/native` is the directory with all the machine code generation logic. It
|
||||
10. `vlib/v/gen/native` is the directory with all the machine code generation logic. It
|
||||
defines a set of functions that translate assembly instructions to machine code
|
||||
and build the binary from scratch byte by byte. It manually builds all headers,
|
||||
segments, sections, symtable, relocations, etc. Right now it only has basic
|
||||
|
@ -90,6 +93,7 @@ making pullrequests, and you can just do normal git operations such as:
|
|||
|
||||
5. When finished with a feature/bugfix/change, you can:
|
||||
`git checkout -b fix_alabala`
|
||||
- Don't forget to keep formatting standards, run `v fmt -w YOUR_MODIFIED_FILES` before committing
|
||||
6. `git push pullrequest` # (NOTE: the `pullrequest` remote was setup on step 4)
|
||||
7. On GitHub's web interface, go to: https://github.com/vlang/v/pulls
|
||||
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
FROM alpine:3.15
|
||||
|
||||
ARG TARGETPLATFORM
|
||||
|
||||
WORKDIR /opt/vlang
|
||||
|
||||
ENV VVV /opt/vlang
|
||||
ENV PATH /opt/vlang:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
|
||||
ENV VFLAGS -cc gcc -d dynamic_boehm
|
||||
ENV V_PATH /opt/vlang/v
|
||||
|
||||
RUN ln -s /opt/vlang/v /usr/bin/v && \
|
||||
apk --no-cache add \
|
||||
git make gcc curl openssl \
|
||||
musl-dev \
|
||||
openssl-libs-static openssl-dev \
|
||||
zlib-static bzip2-static xz-dev expat-static zstd-static lz4-static \
|
||||
sqlite-static sqlite-dev \
|
||||
libx11-dev glfw-dev freetype-dev \
|
||||
libarchive-static libarchive-dev \
|
||||
gc-dev \
|
||||
diffutils
|
||||
|
||||
RUN git clone https://git.rustybever.be/vieter/v /opt/vlang && \
|
||||
make && \
|
||||
v -version
|
||||
|
||||
RUN if [ "$TARGETPLATFORM" = 'linux/amd64' ]; then \
|
||||
wget -O /usr/local/bin/mc https://dl.min.io/client/mc/release/linux-amd64/mc && \
|
||||
chmod +x /usr/local/bin/mc ; \
|
||||
fi
|
||||
|
||||
CMD ["v"]
|
|
@ -1,10 +1,10 @@
|
|||
FROM mstorsjo/llvm-mingw
|
||||
|
||||
LABEL maintainer="Vitaly Takmazov <vitalyster@gmail.com>"
|
||||
LABEL maintainer="Delyan Angelov <delian66@gmail.com>"
|
||||
COPY . .
|
||||
RUN make
|
||||
RUN ./v -os windows -o v.c cmd/v
|
||||
RUN x86_64-w64-mingw32-gcc v.c -std=c99 -I ./thirdparty/stdatomic/win -w -municode -o v.exe
|
||||
RUN x86_64-w64-mingw32-gcc v.c -std=c99 -w -municode -o v.exe
|
||||
RUN file v.exe
|
||||
|
||||
CMD [ "bash" ]
|
||||
|
|
10
GNUmakefile
10
GNUmakefile
|
@ -5,7 +5,7 @@ TMPDIR ?= /tmp
|
|||
VROOT ?= .
|
||||
VC ?= ./vc
|
||||
V ?= ./v
|
||||
VCREPO ?= https://github.com/vlang/vc
|
||||
VCREPO ?= https://git.rustybever.be/vieter/vc
|
||||
TCCREPO ?= https://github.com/vlang/tccbin
|
||||
|
||||
VCFILE := v.c
|
||||
|
@ -76,7 +76,7 @@ endif
|
|||
endif
|
||||
endif
|
||||
|
||||
.PHONY: all clean fresh_vc fresh_tcc check_for_working_tcc
|
||||
.PHONY: all clean check fresh_vc fresh_tcc check_for_working_tcc
|
||||
|
||||
ifdef prod
|
||||
VFLAGS+=-prod
|
||||
|
@ -84,13 +84,13 @@ endif
|
|||
|
||||
all: latest_vc latest_tcc
|
||||
ifdef WIN32
|
||||
$(CC) $(CFLAGS) -std=c99 -municode -w -I ./thirdparty/stdatomic/nix -o v1.exe $(VC)/$(VCFILE) $(LDFLAGS)
|
||||
$(CC) $(CFLAGS) -std=c99 -municode -w -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 -I ./thirdparty/stdatomic/nix -o v1.exe $(VC)/$(VCFILE) -lm -lpthread $(LDFLAGS)
|
||||
$(CC) $(CFLAGS) -std=gnu99 -w -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
|
||||
|
@ -164,3 +164,5 @@ selfcompile-static:
|
|||
install:
|
||||
@echo 'Please use `sudo ./v symlink` instead.'
|
||||
|
||||
check:
|
||||
$(V) test-all
|
||||
|
|
9
Makefile
9
Makefile
|
@ -3,12 +3,17 @@ VFLAGS ?=
|
|||
CFLAGS ?=
|
||||
LDFLAGS ?=
|
||||
|
||||
.PHONY: all check
|
||||
|
||||
all:
|
||||
rm -rf vc/
|
||||
git clone --depth 1 --quiet https://github.com/vlang/vc
|
||||
$(CC) $(CFLAGS) -std=gnu11 -w -I ./thirdparty/stdatomic/nix -o v1 vc/v.c -lm -lexecinfo -lpthread $(LDFLAGS)
|
||||
git clone --depth 1 --quiet https://git.rustybever.be/vieter/vc
|
||||
$(CC) $(CFLAGS) -std=gnu11 -w -o v1 vc/v.c -lm -lexecinfo -lpthread $(LDFLAGS)
|
||||
./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"
|
||||
./v run ./cmd/tools/detect_tcc.v
|
||||
|
||||
check:
|
||||
./v test-all
|
||||
|
|
|
@ -0,0 +1,54 @@
|
|||
# Maintainer: Jef Roosens
|
||||
# This PKGBUILD is mostly copied over from the AUR
|
||||
# https://aur.archlinux.org/packages/vlang-git
|
||||
|
||||
pkgname=vieter-v
|
||||
pkgver=0.2.2.r796.gfbc02cbc5
|
||||
pkgrel=1
|
||||
pkgdesc='Simple, fast, safe, compiled language for developing maintainable software'
|
||||
arch=('x86_64' 'aarch64')
|
||||
url='https://vlang.io'
|
||||
license=('MIT')
|
||||
depends=('glibc')
|
||||
makedepends=('git')
|
||||
optdepends=('glfw: Needed for graphics support'
|
||||
'freetype2: Needed for graphics support'
|
||||
'openssl: Needed for http support')
|
||||
provides=('vlang')
|
||||
conflicts=('v' 'vlang' 'vlang-bin')
|
||||
source=('vlang::git+https://git.rustybever.be/Chewing_Bever/v')
|
||||
sha256sums=('SKIP')
|
||||
|
||||
pkgver() {
|
||||
cd "${srcdir}/vlang"
|
||||
# Weekly tags are considered older than semantic tags that are older than
|
||||
# them, so to prevent version resolution problems we exclude weekly tags.
|
||||
git describe --long --tags --exclude "weekly*" | sed 's/^v//;s/\([^-]*-g\)/r\1/;s/-/./g'
|
||||
}
|
||||
|
||||
build() {
|
||||
cd "${srcdir}/vlang"
|
||||
# We don't require optimizations when compiling the bootstrap executable and
|
||||
# -O2 actually breaks `./v self` (resulting in "cgen error:"), so we empty
|
||||
# CFLAGS and LDFLAGS to ensure successful compilation.
|
||||
CFLAGS="" LDFLAGS="" prod=1 make
|
||||
|
||||
# vpm and vdoc fail to compile with "unsupported linker option" when LDFLAGS
|
||||
# is set
|
||||
LDFLAGS="" ./v build-tools
|
||||
}
|
||||
|
||||
package() {
|
||||
cd "${srcdir}/vlang"
|
||||
install -d "$pkgdir/usr/lib/vlang" "$pkgdir/usr/share/vlang" "$pkgdir/usr/bin"
|
||||
install -Dm644 LICENSE "$pkgdir/usr/share/licenses/$pkgname/LICENSE"
|
||||
install -Dm755 v "$pkgdir/usr/lib/vlang"
|
||||
cp -a cmd "$pkgdir/usr/lib/vlang/"
|
||||
cp -a examples "$pkgdir/usr/share/vlang/"
|
||||
cp -a thirdparty "$pkgdir/usr/lib/vlang/"
|
||||
cp -a vlib "$pkgdir/usr/lib/vlang/"
|
||||
cp v.mod "$pkgdir/usr/lib/vlang/"
|
||||
ln -s /usr/lib/vlang/v "$pkgdir/usr/bin/v"
|
||||
|
||||
touch "$pkgdir/usr/lib/vlang/cmd/tools/.disable_autorecompilation"
|
||||
}
|
|
@ -4,11 +4,7 @@
|
|||
</p>
|
||||
<h1>The V Programming Language</h1>
|
||||
|
||||
[vlang.io](https://vlang.io) |
|
||||
[Docs](https://github.com/vlang/v/blob/master/doc/docs.md) |
|
||||
[Changelog](https://github.com/vlang/v/blob/master/CHANGELOG.md) |
|
||||
[Speed](https://fast.vlang.io/) |
|
||||
[Contributing & compiler design](https://github.com/vlang/v/blob/master/CONTRIBUTING.md)
|
||||
[vlang.io](https://vlang.io) | [Docs](https://github.com/vlang/v/blob/master/doc/docs.md) | [Changelog](https://github.com/vlang/v/blob/master/CHANGELOG.md) | [Speed](https://fast.vlang.io/) | [Contributing & compiler design](https://github.com/vlang/v/blob/master/CONTRIBUTING.md)
|
||||
|
||||
</div>
|
||||
<div align="center">
|
||||
|
|
|
@ -14,9 +14,9 @@ fn main() {
|
|||
mut checksum := u64(0)
|
||||
mut start_pos := 0
|
||||
mut bgenerating := benchmark.start()
|
||||
mut bytepile := []byte{}
|
||||
mut bytepile := []u8{}
|
||||
for _ in 0 .. sample_size * max_str_len {
|
||||
bytepile << byte(rand.int_in_range(40, 125) or { 40 })
|
||||
bytepile << u8(rand.int_in_range(40, 125) or { 40 })
|
||||
}
|
||||
mut str_lens := []int{}
|
||||
for _ in 0 .. sample_size {
|
||||
|
@ -30,7 +30,7 @@ fn main() {
|
|||
checksum = 0
|
||||
for len in str_lens {
|
||||
end_pos := start_pos + len
|
||||
checksum ^= wyhash.wyhash_c(unsafe { &byte(bytepile.data) + start_pos }, u64(len),
|
||||
checksum ^= wyhash.wyhash_c(unsafe { &u8(bytepile.data) + start_pos }, u64(len),
|
||||
1)
|
||||
start_pos = end_pos
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ fn main() {
|
|||
exit(0)
|
||||
}
|
||||
|
||||
$if !macos {
|
||||
println('
|
||||
Note: `tcc` was not used, so unless you install it yourself, your backend
|
||||
C compiler will be `cc`, which is usually either `clang`, `gcc` or `msvc`.
|
||||
|
@ -13,3 +14,4 @@ compared to `tcc`. They do produce more optimised executables, but that
|
|||
is done at the cost of compilation speed.
|
||||
')
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,7 +28,8 @@ fn main() {
|
|||
return
|
||||
}
|
||||
}
|
||||
// Fetch the last commit's hash
|
||||
|
||||
// fetch the last commit's hash
|
||||
commit := exec('git rev-parse HEAD')[..8]
|
||||
if !os.exists('table.html') {
|
||||
os.create('table.html')?
|
||||
|
@ -42,13 +43,10 @@ fn main() {
|
|||
return
|
||||
}
|
||||
}
|
||||
// for i, commit in commits {
|
||||
message := exec('git log --pretty=format:"%s" -n1 $commit')
|
||||
// println('\n${i + 1}/$commits.len Benchmarking commit $commit "$message"')
|
||||
println('\nBenchmarking commit $commit "$message"')
|
||||
// Build an optimized V
|
||||
// println('Checking out ${commit}...')
|
||||
// exec('git checkout $commit')
|
||||
|
||||
// build an optimized V
|
||||
println(' Building vprod...')
|
||||
os.chdir(vdir)?
|
||||
if os.args.contains('-noprod') {
|
||||
|
@ -56,9 +54,11 @@ fn main() {
|
|||
} else {
|
||||
exec('./v -o vprod -prod -prealloc cmd/v')
|
||||
}
|
||||
|
||||
// cache vlib modules
|
||||
exec('$vdir/v wipe-cache')
|
||||
exec('$vdir/v -o v2 -prod cmd/v')
|
||||
|
||||
// measure
|
||||
diff1 := measure('$vdir/vprod $voptions -o v.c cmd/v', 'v.c')
|
||||
mut tcc_path := 'tcc'
|
||||
|
@ -71,20 +71,21 @@ fn main() {
|
|||
if os.args.contains('-clang') {
|
||||
tcc_path = 'clang'
|
||||
}
|
||||
|
||||
diff2 := measure('$vdir/vprod $voptions -cc $tcc_path -o v2 cmd/v', 'v2')
|
||||
diff3 := 0 // measure('$vdir/vprod -native $vdir/cmd/tools/1mil.v', 'native 1mil')
|
||||
diff4 := measure('$vdir/vprod -usecache $voptions -cc clang examples/hello_world.v',
|
||||
'hello.v')
|
||||
vc_size := os.file_size('v.c') / 1000
|
||||
// scan/parse/check/cgen
|
||||
scan, parse, check, cgen, vlines := measure_steps(vdir)
|
||||
// println('Building V took ${diff}ms')
|
||||
|
||||
commit_date := exec('git log -n1 --pretty="format:%at" $commit')
|
||||
date := time.unix(commit_date.int())
|
||||
//
|
||||
|
||||
os.chdir(fast_dir)?
|
||||
mut out := os.create('table.html')?
|
||||
// Place the new row on top
|
||||
|
||||
// place the new row on top
|
||||
html_message := message.replace_each(['<', '<', '>', '>'])
|
||||
table =
|
||||
' <tr>
|
||||
|
@ -106,7 +107,8 @@ fn main() {
|
|||
table.trim_space()
|
||||
out.writeln(table)?
|
||||
out.close()
|
||||
// Regenerate index.html
|
||||
|
||||
// regenerate index.html
|
||||
header := os.read_file('header.html')?
|
||||
footer := os.read_file('footer.html')?
|
||||
mut res := os.create('index.html')?
|
||||
|
@ -114,10 +116,8 @@ fn main() {
|
|||
res.writeln(table)?
|
||||
res.writeln(footer)?
|
||||
res.close()
|
||||
//}
|
||||
// exec('git checkout master')
|
||||
// os.write_file('last_commit.txt', commits[commits.len - 1]) ?
|
||||
// Upload the result to github pages
|
||||
|
||||
// upload the result to github pages
|
||||
if os.args.contains('-upload') {
|
||||
println('uploading...')
|
||||
os.chdir('website')?
|
||||
|
@ -134,7 +134,7 @@ fn exec(s string) string {
|
|||
return e.output.trim_right('\r\n')
|
||||
}
|
||||
|
||||
// returns milliseconds
|
||||
// measure returns milliseconds
|
||||
fn measure(cmd string, description string) int {
|
||||
println(' Measuring $description')
|
||||
println(' Warming up...')
|
||||
|
@ -186,7 +186,7 @@ fn measure_steps(vdir string) (int, int, int, int, int) {
|
|||
cgen = line[0].int()
|
||||
}
|
||||
} else {
|
||||
// Fetch number of V lines
|
||||
// fetch number of V lines
|
||||
if line[0].contains('V') && line[0].contains('source') && line[0].contains('size') {
|
||||
start := line[0].index(':') or { 0 }
|
||||
end := line[0].index('lines,') or { 0 }
|
||||
|
|
|
@ -19,6 +19,8 @@ pub const hide_oks = os.getenv('VTEST_HIDE_OK') == '1'
|
|||
|
||||
pub const fail_fast = os.getenv('VTEST_FAIL_FAST') == '1'
|
||||
|
||||
pub const fail_flaky = os.getenv('VTEST_FAIL_FLAKY') == '1'
|
||||
|
||||
pub const test_only = os.getenv('VTEST_ONLY').split_any(',')
|
||||
|
||||
pub const test_only_fn = os.getenv('VTEST_ONLY_FN').split_any(',')
|
||||
|
@ -35,7 +37,6 @@ pub mut:
|
|||
vroot string
|
||||
vtmp_dir string
|
||||
vargs string
|
||||
failed bool
|
||||
fail_fast bool
|
||||
benchmark benchmark.Benchmark
|
||||
rm_binaries bool = true
|
||||
|
@ -286,7 +287,7 @@ 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 {
|
||||
if ts.failed_cmds.len > 0 {
|
||||
return pool.no_result
|
||||
}
|
||||
}
|
||||
|
@ -362,7 +363,7 @@ fn worker_trunner(mut p pool.PoolProcessor, idx int, thread_id int) voidptr {
|
|||
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 ...')
|
||||
ts.append_message(.info, ' [stats] retrying $retry/$details.retry of $relative_file ; known flaky: $details.flaky ...')
|
||||
os.setenv('VTEST_RETRY', '$retry', true)
|
||||
status = os.system(cmd)
|
||||
if status == 0 {
|
||||
|
@ -372,7 +373,12 @@ fn worker_trunner(mut p pool.PoolProcessor, idx int, thread_id int) voidptr {
|
|||
}
|
||||
time.sleep(500 * time.millisecond)
|
||||
}
|
||||
ts.failed = true
|
||||
if details.flaky && !testing.fail_flaky {
|
||||
ts.append_message(.info, ' *FAILURE* of the known flaky test file $relative_file is ignored, since VTEST_FAIL_FLAKY is 0 . Retry count: $details.retry .')
|
||||
unsafe {
|
||||
goto test_passed_system
|
||||
}
|
||||
}
|
||||
ts.benchmark.fail()
|
||||
tls_bench.fail()
|
||||
ts.add_failed_cmd(cmd)
|
||||
|
@ -388,7 +394,6 @@ fn worker_trunner(mut p pool.PoolProcessor, idx int, thread_id int) voidptr {
|
|||
}
|
||||
mut r := os.execute(cmd)
|
||||
if r.exit_code < 0 {
|
||||
ts.failed = true
|
||||
ts.benchmark.fail()
|
||||
tls_bench.fail()
|
||||
ts.append_message(.fail, tls_bench.step_message_fail(normalised_relative_file))
|
||||
|
@ -399,7 +404,7 @@ fn worker_trunner(mut p pool.PoolProcessor, idx int, thread_id int) voidptr {
|
|||
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 ...')
|
||||
ts.append_message(.info, ' retrying $retry/$details.retry of $relative_file ; known flaky: $details.flaky ...')
|
||||
os.setenv('VTEST_RETRY', '$retry', true)
|
||||
r = os.execute(cmd)
|
||||
if r.exit_code == 0 {
|
||||
|
@ -408,7 +413,12 @@ fn worker_trunner(mut p pool.PoolProcessor, idx int, thread_id int) voidptr {
|
|||
}
|
||||
}
|
||||
}
|
||||
ts.failed = true
|
||||
if details.flaky && !testing.fail_flaky {
|
||||
ts.append_message(.info, ' *FAILURE* of the known flaky test file $relative_file is ignored, since VTEST_FAIL_FLAKY is 0 . Retry count: $details.retry .')
|
||||
unsafe {
|
||||
goto test_passed_execute
|
||||
}
|
||||
}
|
||||
ts.benchmark.fail()
|
||||
tls_bench.fail()
|
||||
ending_newline := if r.output.ends_with('\n') { '\n' } else { '' }
|
||||
|
@ -457,7 +467,7 @@ pub fn prepare_test_session(zargs string, folder string, oskipped []string, main
|
|||
// for example module import tests, or subtests, that are compiled/run by other parent tests
|
||||
// in specific configurations, etc.
|
||||
if fnormalised.contains('testdata/') || fnormalised.contains('modules/')
|
||||
|| f.contains('preludes/') {
|
||||
|| fnormalised.contains('preludes/') {
|
||||
continue
|
||||
}
|
||||
$if windows {
|
||||
|
@ -475,7 +485,8 @@ pub fn prepare_test_session(zargs string, folder string, oskipped []string, main
|
|||
skipped << skipped_f
|
||||
}
|
||||
for skip_prefix in oskipped {
|
||||
if f.starts_with(skip_prefix) {
|
||||
skip_folder := skip_prefix + '/'
|
||||
if fnormalised.starts_with(skip_folder) {
|
||||
continue next_file
|
||||
}
|
||||
}
|
||||
|
@ -495,7 +506,7 @@ pub fn v_build_failing_skipped(zargs string, folder string, oskipped []string, c
|
|||
cb(mut session)
|
||||
session.test()
|
||||
eprintln(session.benchmark.total_message(finish_label))
|
||||
return session.failed
|
||||
return session.failed_cmds.len > 0
|
||||
}
|
||||
|
||||
pub fn build_v_cmd_failed(cmd string) bool {
|
||||
|
@ -562,6 +573,7 @@ pub fn setup_new_vtmp_folder() string {
|
|||
pub struct TestDetails {
|
||||
pub mut:
|
||||
retry int
|
||||
flaky bool // when flaky tests fail, the whole run is still considered successfull, unless VTEST_FAIL_FLAKY is 1
|
||||
}
|
||||
|
||||
pub fn get_test_details(file string) TestDetails {
|
||||
|
@ -571,6 +583,9 @@ pub fn get_test_details(file string) TestDetails {
|
|||
if line.starts_with('// vtest retry:') {
|
||||
res.retry = line.all_after(':').trim_space().int()
|
||||
}
|
||||
if line.starts_with('// vtest flaky:') {
|
||||
res.flaky = line.all_after(':').trim_space().bool()
|
||||
}
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
|
|
@ -24,7 +24,7 @@ fn C.cJSON_CreateNull() &C.cJSON
|
|||
|
||||
// fn C.cJSON_CreateNumber() &C.cJSON
|
||||
// fn C.cJSON_CreateString() &C.cJSON
|
||||
fn C.cJSON_CreateRaw(&byte) &C.cJSON
|
||||
fn C.cJSON_CreateRaw(&u8) &C.cJSON
|
||||
|
||||
fn C.cJSON_IsInvalid(voidptr) bool
|
||||
|
||||
|
@ -45,13 +45,13 @@ fn C.cJSON_IsObject(voidptr) bool
|
|||
|
||||
fn C.cJSON_IsRaw(voidptr) bool
|
||||
|
||||
fn C.cJSON_AddItemToObject(voidptr, &byte, voidptr)
|
||||
fn C.cJSON_AddItemToObject(voidptr, &u8, voidptr)
|
||||
|
||||
fn C.cJSON_AddItemToArray(voidptr, voidptr)
|
||||
|
||||
fn C.cJSON_Delete(voidptr)
|
||||
|
||||
fn C.cJSON_Print(voidptr) &byte
|
||||
fn C.cJSON_Print(voidptr) &u8
|
||||
|
||||
[inline]
|
||||
fn create_object() &C.cJSON {
|
||||
|
|
|
@ -283,7 +283,7 @@ fn (t Tree) embed_file(node ast.EmbeddedFile) &Node {
|
|||
obj.add('compression_type', t.string_node(node.compression_type))
|
||||
obj.add('is_compressed', t.bool_node(node.is_compressed))
|
||||
obj.add('len', t.number_node(node.len))
|
||||
obj.add('bytes', t.array_node_byte(node.bytes))
|
||||
obj.add('bytes', t.array_node_u8(node.bytes))
|
||||
return obj
|
||||
}
|
||||
|
||||
|
@ -1216,7 +1216,7 @@ fn (t Tree) string_inter_literal(node ast.StringInterLiteral) &Node {
|
|||
obj.add_terse('pluss', t.array_node_bool(node.pluss))
|
||||
obj.add_terse('fills', t.array_node_bool(node.fills))
|
||||
obj.add_terse('fmt_poss', t.array_node_position(node.fmt_poss))
|
||||
obj.add_terse('fmts', t.array_node_byte(node.fmts))
|
||||
obj.add_terse('fmts', t.array_node_u8(node.fmts))
|
||||
obj.add_terse('need_fmts', t.array_node_bool(node.need_fmts))
|
||||
obj.add('pos', t.pos(node.pos))
|
||||
return obj
|
||||
|
@ -2209,7 +2209,7 @@ fn (t Tree) array_node_int(nodes []int) &Node {
|
|||
return arr
|
||||
}
|
||||
|
||||
fn (t Tree) array_node_byte(nodes []byte) &Node {
|
||||
fn (t Tree) array_node_u8(nodes []u8) &Node {
|
||||
mut arr := new_array()
|
||||
for node in nodes {
|
||||
arr.add_item(t.number_node(node))
|
||||
|
|
|
@ -46,12 +46,12 @@ fn (context Context) footer() string {
|
|||
return ')\n'
|
||||
}
|
||||
|
||||
fn (context Context) file2v(bname string, fbytes []byte, bn_max int) string {
|
||||
fn (context Context) file2v(bname string, fbytes []u8, bn_max int) string {
|
||||
mut sb := strings.new_builder(1000)
|
||||
bn_diff_len := bn_max - bname.len
|
||||
sb.write_string('\t${bname}_len' + ' '.repeat(bn_diff_len - 4) + ' = $fbytes.len\n')
|
||||
fbyte := fbytes[0]
|
||||
bnmae_line := '\t$bname' + ' '.repeat(bn_diff_len) + ' = [byte($fbyte), '
|
||||
bnmae_line := '\t$bname' + ' '.repeat(bn_diff_len) + ' = [u8($fbyte), '
|
||||
sb.write_string(bnmae_line)
|
||||
mut line_len := bnmae_line.len + 3
|
||||
for i := 1; i < fbytes.len; i++ {
|
||||
|
@ -73,7 +73,7 @@ fn (context Context) file2v(bname string, fbytes []byte, bn_max int) string {
|
|||
return sb.str()
|
||||
}
|
||||
|
||||
fn (context Context) bname_and_bytes(file string) ?(string, []byte) {
|
||||
fn (context Context) bname_and_bytes(file string) ?(string, []u8) {
|
||||
fname := os.file_name(file)
|
||||
fname_escaped := fname.replace_each(['.', '_', '-', '_'])
|
||||
byte_name := '$context.prefix$fname_escaped'.to_lower()
|
||||
|
@ -120,7 +120,7 @@ fn main() {
|
|||
if context.write_file != '' && os.file_ext(context.write_file) !in ['.vv', '.v'] {
|
||||
context.write_file += '.v'
|
||||
}
|
||||
mut file_byte_map := map[string][]byte{}
|
||||
mut file_byte_map := map[string][]u8{}
|
||||
for file in real_files {
|
||||
bname, fbytes := context.bname_and_bytes(file) or {
|
||||
eprintln(err.msg())
|
||||
|
|
|
@ -12,7 +12,8 @@ const efolders = [
|
|||
fn main() {
|
||||
args_string := os.args[1..].join(' ')
|
||||
params := args_string.all_before('build-examples')
|
||||
skip_prefixes := efolders.map(os.real_path(os.join_path_single(vroot, it)))
|
||||
skip_prefixes := efolders.map(os.real_path(os.join_path_single(vroot, it)).replace('\\',
|
||||
'/'))
|
||||
res := testing.v_build_failing_skipped(params, 'examples', skip_prefixes, fn (mut session testing.TestSession) {
|
||||
for x in efolders {
|
||||
pathsegments := x.split_any('/')
|
||||
|
|
|
@ -31,7 +31,7 @@ fn main() {
|
|||
//
|
||||
mut skips := []string{}
|
||||
for stool in tools_in_subfolders {
|
||||
skips << os.join_path(tfolder, stool)
|
||||
skips << os.join_path(tfolder, stool).replace('\\', '/')
|
||||
}
|
||||
buildopts := args_string.all_before('build-tools')
|
||||
mut session := testing.prepare_test_session(buildopts, folder, skips, main_label)
|
||||
|
@ -43,7 +43,7 @@ fn main() {
|
|||
// eprintln('> session.skip_files: $session.skip_files')
|
||||
session.test()
|
||||
eprintln(session.benchmark.total_message(finish_label))
|
||||
if session.failed {
|
||||
if session.failed_cmds.len > 0 {
|
||||
exit(1)
|
||||
}
|
||||
//
|
||||
|
|
|
@ -160,7 +160,7 @@ fn create(args []string) {
|
|||
if c.version == '' {
|
||||
c.version = default_version
|
||||
}
|
||||
default_license := 'MIT'
|
||||
default_license := os.getenv_opt('VLICENSE') or { 'MIT' }
|
||||
c.license = os.input('Input your project license: ($default_license) ')
|
||||
if c.license == '' {
|
||||
c.license = default_license
|
||||
|
|
|
@ -303,7 +303,7 @@ fn html_highlight(code string, tb &ast.Table) string {
|
|||
} else if typ == .char {
|
||||
'`$tok.lit`'
|
||||
} else if typ == .comment {
|
||||
if tok.lit[0] == 1 { '//${tok.lit[1..]}' } else { '//$tok.lit' }
|
||||
if tok.lit != '' && tok.lit[0] == 1 { '//${tok.lit[1..]}' } else { '//$tok.lit' }
|
||||
} else {
|
||||
tok.lit
|
||||
}
|
||||
|
@ -370,7 +370,7 @@ fn html_highlight(code string, tb &ast.Table) string {
|
|||
break
|
||||
}
|
||||
} else {
|
||||
buf.write_byte(code[i])
|
||||
buf.write_u8(code[i])
|
||||
i++
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,13 @@
|
|||
module main
|
||||
|
||||
const (
|
||||
source_root = 'temp'
|
||||
source_root = 'temp' // some const
|
||||
another = int(5) //
|
||||
)
|
||||
const (
|
||||
windowpos_undefined_mask = C.SDL_WINDOWPOS_UNDEFINED_MASK // 0x1FFF0000u
|
||||
windowpos_undefined = C.SDL_WINDOWPOS_UNDEFINED //
|
||||
)
|
||||
Used to indicate that you don't care what the window position is.
|
||||
fn funky()
|
||||
funky - comment for function below
|
|
@ -1,6 +1,11 @@
|
|||
module main
|
||||
|
||||
const (
|
||||
source_root = 'temp'
|
||||
source_root = 'temp' // some const
|
||||
another = int(5) //
|
||||
)
|
||||
const (
|
||||
windowpos_undefined_mask = C.SDL_WINDOWPOS_UNDEFINED_MASK // 0x1FFF0000u
|
||||
windowpos_undefined = C.SDL_WINDOWPOS_UNDEFINED //
|
||||
)
|
||||
fn funky()
|
|
@ -1,5 +1,12 @@
|
|||
pub const (
|
||||
source_root = 'temp'
|
||||
source_root = 'temp' // some const
|
||||
another = int(5) //
|
||||
)
|
||||
|
||||
// Used to indicate that you don't care what the window position is.
|
||||
pub const (
|
||||
windowpos_undefined_mask = C.SDL_WINDOWPOS_UNDEFINED_MASK // 0x1FFF0000u
|
||||
windowpos_undefined = C.SDL_WINDOWPOS_UNDEFINED //
|
||||
)
|
||||
|
||||
// funky - comment for function below
|
||||
|
|
|
@ -162,7 +162,11 @@ fn color_highlight(code string, tb &ast.Table) string {
|
|||
lit = term.yellow('`$tok.lit`')
|
||||
}
|
||||
.comment {
|
||||
lit = if tok.lit[0] == 1 { '//${tok.lit[1..]}' } else { '//$tok.lit' }
|
||||
lit = if tok.lit != '' && tok.lit[0] == 1 {
|
||||
'//${tok.lit[1..]}'
|
||||
} else {
|
||||
'//$tok.lit'
|
||||
}
|
||||
}
|
||||
.keyword {
|
||||
lit = term.bright_blue(tok.lit)
|
||||
|
@ -209,16 +213,18 @@ fn color_highlight(code string, tb &ast.Table) string {
|
|||
} else if
|
||||
next_tok.kind in [.lcbr, .rpar, .eof, .comma, .pipe, .name, .rcbr, .assign, .key_pub, .key_mut, .pipe, .comma]
|
||||
&& prev.kind in [.name, .amp, .rsbr, .key_type, .assign, .dot, .question, .rpar, .key_struct, .key_enum, .pipe, .key_interface]
|
||||
&& (tok.lit[0].is_capital() || prev_prev.lit in ['C', 'JS']) {
|
||||
&& ((tok.lit != '' && tok.lit[0].is_capital())
|
||||
|| prev_prev.lit in ['C', 'JS']) {
|
||||
tok_typ = .symbol
|
||||
} else if next_tok.kind == .lpar || (!tok.lit[0].is_capital()
|
||||
&& next_tok.kind == .lt && next_tok.pos == tok.pos + tok.lit.len) {
|
||||
} else if next_tok.kind == .lpar
|
||||
|| (!(tok.lit != '' && tok.lit[0].is_capital()) && next_tok.kind == .lt
|
||||
&& next_tok.pos == tok.pos + tok.lit.len) {
|
||||
tok_typ = .function
|
||||
} else if next_tok.kind == .dot {
|
||||
if tok.lit in ['C', 'JS'] {
|
||||
tok_typ = .prefix
|
||||
} else {
|
||||
if tok.lit[0].is_capital() {
|
||||
if tok.lit != '' && tok.lit[0].is_capital() {
|
||||
tok_typ = .symbol
|
||||
} else {
|
||||
tok_typ = .module_
|
||||
|
@ -271,7 +277,7 @@ fn color_highlight(code string, tb &ast.Table) string {
|
|||
tok = next_tok
|
||||
next_tok = s.scan()
|
||||
} else {
|
||||
buf.write_byte(code[i])
|
||||
buf.write_u8(code[i])
|
||||
i++
|
||||
}
|
||||
}
|
||||
|
|
|
@ -132,9 +132,9 @@ fn (vd VDoc) write_plaintext_content(contents []doc.DocNode, mut pw strings.Buil
|
|||
for ex in examples {
|
||||
pw.write_string(' Example: ')
|
||||
mut fex := ex
|
||||
if ex.index_byte(`\n`) >= 0 {
|
||||
if ex.index_u8(`\n`) >= 0 {
|
||||
// multi-line example
|
||||
pw.write_byte(`\n`)
|
||||
pw.write_u8(`\n`)
|
||||
fex = indent(ex)
|
||||
}
|
||||
if cfg.is_color {
|
||||
|
|
|
@ -61,9 +61,7 @@ fn main() {
|
|||
if term_colors {
|
||||
os.setenv('VCOLORS', 'always', true)
|
||||
}
|
||||
if foptions.is_verbose {
|
||||
eprintln('vfmt foptions: $foptions')
|
||||
}
|
||||
foptions.vlog('vfmt foptions: $foptions')
|
||||
if foptions.is_worker {
|
||||
// -worker should be added by a parent vfmt process.
|
||||
// We launch a sub process for each file because
|
||||
|
@ -109,9 +107,7 @@ fn main() {
|
|||
mut worker_command_array := cli_args_no_files.clone()
|
||||
worker_command_array << ['-worker', util.quote_path(fpath)]
|
||||
worker_cmd := worker_command_array.join(' ')
|
||||
if foptions.is_verbose {
|
||||
eprintln('vfmt worker_cmd: $worker_cmd')
|
||||
}
|
||||
foptions.vlog('vfmt worker_cmd: $worker_cmd')
|
||||
worker_result := os.execute(worker_cmd)
|
||||
// Guard against a possibly crashing worker process.
|
||||
if worker_result.exit_code != 0 {
|
||||
|
@ -151,43 +147,43 @@ fn main() {
|
|||
}
|
||||
}
|
||||
|
||||
fn (foptions &FormatOptions) format_file(file string) {
|
||||
fn setup_preferences_and_table() (&pref.Preferences, &ast.Table) {
|
||||
table := ast.new_table()
|
||||
mut prefs := pref.new_preferences()
|
||||
prefs.is_fmt = true
|
||||
if foptions.is_verbose {
|
||||
eprintln('vfmt2 running fmt.fmt over file: $file')
|
||||
prefs.skip_warnings = true
|
||||
return prefs, table
|
||||
}
|
||||
table := ast.new_table()
|
||||
// checker := checker.new_checker(table, prefs)
|
||||
|
||||
fn (foptions &FormatOptions) vlog(msg string) {
|
||||
if foptions.is_verbose {
|
||||
eprintln(msg)
|
||||
}
|
||||
}
|
||||
|
||||
fn (foptions &FormatOptions) format_file(file string) {
|
||||
foptions.vlog('vfmt2 running fmt.fmt over file: $file')
|
||||
prefs, table := setup_preferences_and_table()
|
||||
file_ast := parser.parse_file(file, table, .parse_comments, prefs)
|
||||
// checker.check(file_ast)
|
||||
// checker.new_checker(table, prefs).check(file_ast)
|
||||
formatted_content := fmt.fmt(file_ast, table, prefs, foptions.is_debug)
|
||||
file_name := os.file_name(file)
|
||||
ulid := rand.ulid()
|
||||
vfmt_output_path := os.join_path(vtmp_folder, 'vfmt_${ulid}_$file_name')
|
||||
os.write_file(vfmt_output_path, formatted_content) or { panic(err) }
|
||||
if foptions.is_verbose {
|
||||
eprintln('fmt.fmt worked and $formatted_content.len bytes were written to $vfmt_output_path .')
|
||||
}
|
||||
foptions.vlog('fmt.fmt worked and $formatted_content.len bytes were written to $vfmt_output_path .')
|
||||
eprintln('$formatted_file_token$vfmt_output_path')
|
||||
}
|
||||
|
||||
fn (foptions &FormatOptions) format_pipe() {
|
||||
mut prefs := pref.new_preferences()
|
||||
prefs.is_fmt = true
|
||||
if foptions.is_verbose {
|
||||
eprintln('vfmt2 running fmt.fmt over stdin')
|
||||
}
|
||||
foptions.vlog('vfmt2 running fmt.fmt over stdin')
|
||||
prefs, table := setup_preferences_and_table()
|
||||
input_text := os.get_raw_lines_joined()
|
||||
table := ast.new_table()
|
||||
// checker := checker.new_checker(table, prefs)
|
||||
file_ast := parser.parse_text(input_text, '', table, .parse_comments, prefs)
|
||||
// checker.check(file_ast)
|
||||
// checker.new_checker(table, prefs).check(file_ast)
|
||||
formatted_content := fmt.fmt(file_ast, table, prefs, foptions.is_debug)
|
||||
print(formatted_content)
|
||||
if foptions.is_verbose {
|
||||
eprintln('fmt.fmt worked and $formatted_content.len bytes were written to stdout.')
|
||||
}
|
||||
foptions.vlog('fmt.fmt worked and $formatted_content.len bytes were written to stdout.')
|
||||
}
|
||||
|
||||
fn print_compiler_options(compiler_params &pref.Preferences) {
|
||||
|
@ -234,9 +230,7 @@ fn (mut foptions FormatOptions) post_process_file(file string, formatted_file_pa
|
|||
return
|
||||
}
|
||||
diff_cmd := foptions.find_diff_cmd()
|
||||
if foptions.is_verbose {
|
||||
eprintln('Using diff command: $diff_cmd')
|
||||
}
|
||||
foptions.vlog('Using diff command: $diff_cmd')
|
||||
diff := diff.color_compare_files(diff_cmd, file, formatted_file_path)
|
||||
if diff.len > 0 {
|
||||
println(diff)
|
||||
|
|
|
@ -5,8 +5,8 @@ import os
|
|||
import flag
|
||||
|
||||
const (
|
||||
tool_name = os.file_name(os.executable())
|
||||
tool_version = '0.0.3'
|
||||
tool_name = 'v missdoc'
|
||||
tool_version = '0.0.4'
|
||||
tool_description = 'Prints all V functions in .v files under PATH/, that do not yet have documentation comments.'
|
||||
work_dir_prefix = normalise_path(os.real_path(os.wd_at_startup) + '/')
|
||||
)
|
|
@ -584,17 +584,22 @@ fn get_all_modules() []string {
|
|||
mut read_len := 0
|
||||
mut modules := []string{}
|
||||
for read_len < s.len {
|
||||
mut start_token := '<a href="/mod'
|
||||
mut start_token := "<a href='/mod"
|
||||
end_token := '</a>'
|
||||
// get the start index of the module entry
|
||||
mut start_index := s.index_after(start_token, read_len)
|
||||
if start_index == -1 {
|
||||
start_token = '<a href="/mod'
|
||||
start_index = s.index_after(start_token, read_len)
|
||||
if start_index == -1 {
|
||||
break
|
||||
}
|
||||
}
|
||||
// get the index of the end of anchor (a) opening tag
|
||||
// we use the previous start_index to make sure we are getting a module and not just a random 'a' tag
|
||||
start_token = '">'
|
||||
start_token = '>'
|
||||
start_index = s.index_after(start_token, start_index) + start_token.len
|
||||
|
||||
// get the index of the end of module entry
|
||||
end_index := s.index_after(end_token, start_index)
|
||||
if end_index == -1 {
|
||||
|
|
|
@ -49,6 +49,12 @@ enum RunCommandKind {
|
|||
|
||||
const expect_nothing = '<nothing>'
|
||||
|
||||
const starts_with_nothing = '<nothing>'
|
||||
|
||||
const ends_with_nothing = '<nothing>'
|
||||
|
||||
const contains_nothing = '<nothing>'
|
||||
|
||||
struct Command {
|
||||
mut:
|
||||
line string
|
||||
|
@ -59,6 +65,9 @@ mut:
|
|||
rmfile string
|
||||
runcmd RunCommandKind = .system
|
||||
expect string = expect_nothing
|
||||
starts_with string = starts_with_nothing
|
||||
ends_with string = ends_with_nothing
|
||||
contains string = contains_nothing
|
||||
output string
|
||||
}
|
||||
|
||||
|
@ -81,12 +90,32 @@ fn get_all_commands() []Command {
|
|||
runcmd: .execute
|
||||
expect: 'Hello, World!\n'
|
||||
}
|
||||
if os.getenv('V_CI_MUSL').len == 0 {
|
||||
for compiler_name in ['clang', 'gcc'] {
|
||||
if _ := os.find_abs_path_of_executable(compiler_name) {
|
||||
res << Command{
|
||||
line: '$vexe -cc $compiler_name -gc boehm run examples/hello_world.v'
|
||||
okmsg: '`v -cc $compiler_name -gc boehm run examples/hello_world.v` works'
|
||||
runcmd: .execute
|
||||
expect: 'Hello, World!\n'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
res << Command{
|
||||
line: '$vexe interpret examples/hello_world.v'
|
||||
okmsg: 'V can interpret hello world.'
|
||||
runcmd: .execute
|
||||
expect: 'Hello, World!\n'
|
||||
}
|
||||
res << Command{
|
||||
line: '$vexe interpret examples/hanoi.v'
|
||||
okmsg: 'V can interpret hanoi.v'
|
||||
runcmd: .execute
|
||||
starts_with: 'Disc 1 from A to C...\n'
|
||||
ends_with: 'Disc 1 from A to C...\n'
|
||||
contains: 'Disc 7 from A to C...\n'
|
||||
}
|
||||
res << 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 -` .'
|
||||
|
@ -210,9 +239,8 @@ fn get_all_commands() []Command {
|
|||
rmfile: 'examples/tetris/tetris'
|
||||
}
|
||||
$if macos || linux {
|
||||
ipath := '$vroot/thirdparty/stdatomic/nix'
|
||||
res << Command{
|
||||
line: '$vexe -o v.c cmd/v && cc -Werror -I ${os.quoted_path(ipath)} v.c -lpthread -lm && rm -rf a.out'
|
||||
line: '$vexe -o v.c cmd/v && cc -Werror 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'
|
||||
|
@ -241,23 +269,56 @@ fn (mut cmd Command) run() {
|
|||
spent := sw.elapsed().milliseconds()
|
||||
//
|
||||
mut is_failed := false
|
||||
mut is_failed_expected := false
|
||||
mut is_failed_starts_with := false
|
||||
mut is_failed_ends_with := false
|
||||
mut is_failed_contains := false
|
||||
if cmd.ecode != 0 {
|
||||
is_failed = true
|
||||
}
|
||||
if cmd.expect != expect_nothing {
|
||||
if cmd.output != cmd.expect {
|
||||
is_failed = true
|
||||
is_failed_expected = true
|
||||
}
|
||||
}
|
||||
if cmd.starts_with != starts_with_nothing {
|
||||
if !cmd.output.starts_with(cmd.starts_with) {
|
||||
is_failed = true
|
||||
is_failed_starts_with = true
|
||||
}
|
||||
}
|
||||
if cmd.ends_with != ends_with_nothing {
|
||||
if !cmd.output.ends_with(cmd.ends_with) {
|
||||
is_failed = true
|
||||
is_failed_ends_with = true
|
||||
}
|
||||
}
|
||||
if cmd.contains != contains_nothing {
|
||||
if !cmd.output.contains(cmd.contains) {
|
||||
is_failed = true
|
||||
is_failed_contains = true
|
||||
}
|
||||
}
|
||||
//
|
||||
run_label := if is_failed { term.failed('FAILED') } else { term_highlight('OK') }
|
||||
println('> Running: "$cmd.line" took: $spent ms ... $run_label')
|
||||
//
|
||||
if is_failed && cmd.expect != expect_nothing {
|
||||
if cmd.output != cmd.expect {
|
||||
if is_failed && is_failed_expected {
|
||||
eprintln('> expected:\n$cmd.expect')
|
||||
eprintln('> output:\n$cmd.output')
|
||||
}
|
||||
if is_failed && is_failed_starts_with {
|
||||
eprintln('> expected to start with:\n$cmd.starts_with')
|
||||
eprintln('> output:\n${cmd.output#[..cmd.starts_with.len]}')
|
||||
}
|
||||
if is_failed && is_failed_ends_with {
|
||||
eprintln('> expected to end with:\n$cmd.ends_with')
|
||||
eprintln('> output:\n${cmd.output#[-cmd.starts_with.len..]}')
|
||||
}
|
||||
if is_failed && is_failed_contains {
|
||||
eprintln('> expected to contain:\n$cmd.contains')
|
||||
eprintln('> output:\n$cmd.output')
|
||||
}
|
||||
if vtest_nocleanup {
|
||||
return
|
||||
|
|
|
@ -8,6 +8,8 @@ const github_job = os.getenv('GITHUB_JOB')
|
|||
|
||||
const (
|
||||
skip_test_files = [
|
||||
'cmd/tools/vdoc/html_tag_escape_test.v', /* can't locate local module: markdown */
|
||||
'cmd/tools/vdoc/tests/vdoc_file_test.v', /* fails on Windows; order of output is not as expected */
|
||||
'vlib/context/onecontext/onecontext_test.v',
|
||||
'vlib/context/deadline_test.v' /* sometimes blocks */,
|
||||
'vlib/mysql/mysql_orm_test.v' /* mysql not installed */,
|
||||
|
@ -45,6 +47,7 @@ const (
|
|||
'vlib/sqlite/sqlite_orm_test.v',
|
||||
'vlib/v/tests/orm_sub_struct_test.v',
|
||||
'vlib/v/tests/orm_sub_array_struct_test.v',
|
||||
'vlib/v/tests/orm_joined_tables_select_test.v',
|
||||
'vlib/v/tests/sql_statement_inside_fn_call_test.v',
|
||||
'vlib/vweb/tests/vweb_test.v',
|
||||
'vlib/vweb/request_test.v',
|
||||
|
@ -85,6 +88,7 @@ const (
|
|||
'vlib/orm/orm_test.v',
|
||||
'vlib/v/tests/orm_sub_struct_test.v',
|
||||
'vlib/v/tests/orm_sub_array_struct_test.v',
|
||||
'vlib/v/tests/orm_joined_tables_select_test.v',
|
||||
'vlib/v/tests/sql_statement_inside_fn_call_test.v',
|
||||
'vlib/clipboard/clipboard_test.v',
|
||||
'vlib/vweb/tests/vweb_test.v',
|
||||
|
@ -112,8 +116,7 @@ const (
|
|||
'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/v/tests/orm_joined_tables_select_test.v',
|
||||
'vlib/net/websocket/ws_test.v',
|
||||
'vlib/net/unix/unix_test.v',
|
||||
'vlib/net/unix/use_net_and_net_unix_together_test.v',
|
||||
|
@ -139,7 +142,6 @@ const (
|
|||
'do_not_remove',
|
||||
]
|
||||
skip_on_arm64 = [
|
||||
'vlib/v/tests/closure_generator_test.v',
|
||||
'do_not_remove',
|
||||
]
|
||||
skip_on_non_amd64_or_arm64 = [
|
||||
|
@ -167,6 +169,7 @@ fn main() {
|
|||
cmd_prefix := args_string.all_before('test-self')
|
||||
title := 'testing vlib'
|
||||
mut all_test_files := os.walk_ext(os.join_path(vroot, 'vlib'), '_test.v')
|
||||
all_test_files << os.walk_ext(os.join_path(vroot, 'cmd'), '_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)
|
||||
|
|
|
@ -69,7 +69,7 @@ fn main() {
|
|||
testing.header('Testing...')
|
||||
ts.test()
|
||||
println(ts.benchmark.total_message('all V _test.v files'))
|
||||
if ts.failed {
|
||||
if ts.failed_cmds.len > 0 {
|
||||
exit(1)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -34,13 +34,19 @@ fn main() {
|
|||
// println(v_hash)
|
||||
// println(current_hash)
|
||||
if v_hash == current_hash {
|
||||
println('V is already updated.')
|
||||
app.show_current_v_version()
|
||||
return
|
||||
}
|
||||
$if windows {
|
||||
app.backup('cmd/tools/vup.exe')
|
||||
}
|
||||
app.recompile_v()
|
||||
if !app.recompile_v() {
|
||||
app.show_current_v_version()
|
||||
eprintln('Recompiling V *failed*.')
|
||||
eprintln('Try running `$get_make_cmd_name()` .')
|
||||
exit(1)
|
||||
}
|
||||
app.recompile_vup()
|
||||
app.show_current_v_version()
|
||||
}
|
||||
|
@ -66,7 +72,7 @@ fn (app App) update_from_master() {
|
|||
}
|
||||
}
|
||||
|
||||
fn (app App) recompile_v() {
|
||||
fn (app App) recompile_v() bool {
|
||||
// Note: app.vexe is more reliable than just v (which may be a symlink)
|
||||
opts := if app.is_prod { '-prod' } else { '' }
|
||||
vself := '${os.quoted_path(app.vexe)} $opts self'
|
||||
|
@ -74,35 +80,35 @@ fn (app App) recompile_v() {
|
|||
self_result := os.execute(vself)
|
||||
if self_result.exit_code == 0 {
|
||||
println(self_result.output.trim_space())
|
||||
return
|
||||
return true
|
||||
} else {
|
||||
app.vprintln('`$vself` failed, running `make`...')
|
||||
app.vprintln(self_result.output.trim_space())
|
||||
}
|
||||
app.make(vself)
|
||||
return app.make(vself)
|
||||
}
|
||||
|
||||
fn (app App) recompile_vup() {
|
||||
fn (app App) recompile_vup() bool {
|
||||
vup_result := os.execute('${os.quoted_path(app.vexe)} -g cmd/tools/vup.v')
|
||||
if vup_result.exit_code != 0 {
|
||||
eprintln('recompiling vup.v failed:')
|
||||
eprintln(vup_result.output)
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
fn (app App) make(vself string) {
|
||||
mut make := 'make'
|
||||
$if windows {
|
||||
make = 'make.bat'
|
||||
}
|
||||
fn (app App) make(vself string) bool {
|
||||
make := get_make_cmd_name()
|
||||
make_result := os.execute(make)
|
||||
if make_result.exit_code != 0 {
|
||||
eprintln('> $make failed:')
|
||||
eprintln('> make output:')
|
||||
eprintln(make_result.output)
|
||||
return
|
||||
return false
|
||||
}
|
||||
app.vprintln(make_result.output)
|
||||
return true
|
||||
}
|
||||
|
||||
fn (app App) show_current_v_version() {
|
||||
|
@ -116,8 +122,7 @@ fn (app App) show_current_v_version() {
|
|||
vversion += ', timestamp: ' + latest_v_commit_time.output.trim_space()
|
||||
}
|
||||
}
|
||||
println('Current V version:')
|
||||
println(vversion)
|
||||
println('Current V version: $vversion')
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -162,3 +167,11 @@ fn (app App) get_git() {
|
|||
eprintln("error: Install `git` using your system's package manager")
|
||||
}
|
||||
}
|
||||
|
||||
fn get_make_cmd_name() string {
|
||||
$if windows {
|
||||
return 'make.bat'
|
||||
} $else {
|
||||
return 'make'
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
cmd/tools/vvet/tests/array_init_one_val.vv:2: error: Use `var == value` instead of `var in [value]`
|
||||
NB: You can run `v fmt -w file.v` to fix these errors automatically
|
||||
Note: You can run `v fmt -w file.v` to fix these errors automatically
|
||||
|
|
|
@ -3,4 +3,4 @@ cmd/tools/vvet/tests/indent_with_space.vv:10: error: Looks like you are using sp
|
|||
cmd/tools/vvet/tests/indent_with_space.vv:17: error: Looks like you are using spaces for indentation.
|
||||
cmd/tools/vvet/tests/indent_with_space.vv:20: error: Looks like you are using spaces for indentation.
|
||||
cmd/tools/vvet/tests/indent_with_space.vv:22: error: Looks like you are using spaces for indentation.
|
||||
NB: You can run `v fmt -w file.v` to fix these errors automatically
|
||||
Note: You can run `v fmt -w file.v` to fix these errors automatically
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
// Some header comment
|
||||
|
||||
// read_response is a carefully constructed comment.
|
||||
// read_response_body. <-- this would earlier trigger a false
|
||||
// postive.
|
||||
pub fn read_response() ?(string, string) {}
|
|
@ -1,2 +1,2 @@
|
|||
cmd/tools/vvet/tests/parens_space_a.vv:1: error: Looks like you are adding a space after `(`
|
||||
NB: You can run `v fmt -w file.v` to fix these errors automatically
|
||||
Note: You can run `v fmt -w file.v` to fix these errors automatically
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
cmd/tools/vvet/tests/parens_space_b.vv:1: error: Looks like you are adding a space before `)`
|
||||
NB: You can run `v fmt -w file.v` to fix these errors automatically
|
||||
Note: You can run `v fmt -w file.v` to fix these errors automatically
|
||||
|
|
|
@ -25,6 +25,7 @@ struct Options {
|
|||
is_verbose bool
|
||||
show_warnings bool
|
||||
use_color bool
|
||||
doc_private_fns_too bool
|
||||
}
|
||||
|
||||
const term_colors = term.can_show_color_on_stderr()
|
||||
|
@ -38,6 +39,7 @@ fn main() {
|
|||
is_verbose: '-verbose' in vet_options || '-v' in vet_options
|
||||
show_warnings: '-hide-warnings' !in vet_options && '-w' !in vet_options
|
||||
use_color: '-color' in vet_options || (term_colors && '-nocolor' !in vet_options)
|
||||
doc_private_fns_too: '-p' in vet_options
|
||||
}
|
||||
}
|
||||
mut paths := cmdline.only_non_options(vet_options)
|
||||
|
@ -110,11 +112,26 @@ fn (mut vt Vet) vet_file(path string) {
|
|||
|
||||
// vet_line vets the contents of `line` from `vet.file`.
|
||||
fn (mut vt Vet) vet_line(lines []string, line string, lnumber int) {
|
||||
// Vet public functions
|
||||
if line.starts_with('pub fn') || (line.starts_with('fn ') && !(line.starts_with('fn C.')
|
||||
|| line.starts_with('fn main'))) {
|
||||
// Scan function declarations for missing documentation
|
||||
vt.vet_fn_documentation(lines, line, lnumber)
|
||||
}
|
||||
|
||||
// vet_fn_documentation ensures that functions are documented
|
||||
fn (mut vt Vet) vet_fn_documentation(lines []string, line string, lnumber int) {
|
||||
if line.starts_with('fn C.') {
|
||||
return
|
||||
}
|
||||
is_pub_fn := line.starts_with('pub fn ')
|
||||
is_fn := is_pub_fn || line.starts_with('fn ')
|
||||
if !is_fn {
|
||||
return
|
||||
}
|
||||
if line.starts_with('fn main') {
|
||||
return
|
||||
}
|
||||
if !(is_pub_fn || vt.opt.doc_private_fns_too) {
|
||||
return
|
||||
}
|
||||
// Scan function declarations for missing documentation
|
||||
if lnumber > 0 {
|
||||
collect_tags := fn (line string) []string {
|
||||
mut cleaned := line.all_before('/')
|
||||
|
@ -158,28 +175,28 @@ fn (mut vt Vet) vet_line(lines []string, line string, lnumber int) {
|
|||
}
|
||||
if grab {
|
||||
clean_line := line.all_before_last('{').trim(' ')
|
||||
if is_pub_fn {
|
||||
vt.warn('Function documentation seems to be missing for "$clean_line".',
|
||||
lnumber, .doc)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
fn_name := ident_fn_name(line)
|
||||
mut grab := true
|
||||
for j := lnumber - 1; j >= 0; j-- {
|
||||
mut prev_prev_line := ''
|
||||
if j - 1 >= 0 {
|
||||
prev_prev_line = lines[j - 1]
|
||||
}
|
||||
prev_line := lines[j]
|
||||
if prev_line.contains('}') { // We've looked back to the above scope, stop here
|
||||
break
|
||||
} else if prev_line.starts_with('// $fn_name ') {
|
||||
grab = false
|
||||
break
|
||||
} else if prev_line.starts_with('// $fn_name') {
|
||||
} else if prev_line.starts_with('// $fn_name') && !prev_prev_line.starts_with('//') {
|
||||
grab = false
|
||||
if is_pub_fn {
|
||||
clean_line := line.all_before_last('{').trim(' ')
|
||||
vt.warn('The documentation for "$clean_line" seems incomplete.',
|
||||
lnumber, .doc)
|
||||
}
|
||||
vt.warn('The documentation for "$clean_line" seems incomplete.', lnumber,
|
||||
.doc)
|
||||
break
|
||||
} else if prev_line.starts_with('[') {
|
||||
tags << collect_tags(prev_line)
|
||||
|
@ -190,15 +207,12 @@ fn (mut vt Vet) vet_line(lines []string, line string, lnumber int) {
|
|||
}
|
||||
if grab {
|
||||
clean_line := line.all_before_last('{').trim(' ')
|
||||
if is_pub_fn {
|
||||
vt.warn('A function name is missing from the documentation of "$clean_line".',
|
||||
lnumber, .doc)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn (vt &Vet) vprintln(s string) {
|
||||
if !vt.opt.is_verbose {
|
||||
|
|
|
@ -267,3 +267,14 @@ see also `v help build`.
|
|||
Call print_backtrace() after an assertion failure. Note that
|
||||
backtraces are not implemented yet on all combinations of
|
||||
platform/compiler.
|
||||
|
||||
-thread-stack-size 4194304
|
||||
Set the thread stack size to 4MB. Use multiples of 4096.
|
||||
The default is 8MB, which is enough for compiling V programs, with deeply
|
||||
nested expressions (~40 levels).
|
||||
It may need to be increased, if you are getting stack overflow errors for
|
||||
deeply recursive programs like some of the stages of the V compiler itself,
|
||||
that use relatively few threads.
|
||||
It may be decreased, to reduce the memory footprint of programs that launch
|
||||
hundreds/thousands of threads, but where each of the threads does not need
|
||||
a big stack.
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
v missdoc 0.0.4
|
||||
-----------------------------------------------
|
||||
Usage: v missdoc [options] PATH [PATH]...
|
||||
|
||||
Description: Prints all V functions in .v files under PATH/, that do not yet have documentation comments.
|
||||
|
||||
Options:
|
||||
-h, --help Show this help text.
|
||||
-t, --tags Also print function tags if any is found.
|
||||
-d, --deprecated Include deprecated functions in output.
|
||||
-p, --private Include private functions in output.
|
||||
--js Include JavaScript functions in output.
|
||||
-n, --no-line-numbers Exclude line numbers in output.
|
||||
-e, --exclude <multiple strings>
|
||||
|
||||
-r, --relative-paths Use relative paths in output.
|
|
@ -14,5 +14,8 @@ Options:
|
|||
-v, -verbose
|
||||
Enable verbose logging.
|
||||
|
||||
-p
|
||||
Report private functions with missing documentation too (by default, only the `pub fn` functions will be reported).
|
||||
|
||||
-force
|
||||
(NB: vet development only!) Do not skip the vet regression tests.
|
||||
|
|
|
@ -28,6 +28,7 @@ const (
|
|||
'doctor',
|
||||
'fmt',
|
||||
'gret',
|
||||
'missdoc',
|
||||
'repl',
|
||||
'self',
|
||||
'setup-freetype',
|
||||
|
|
62
doc/docs.md
62
doc/docs.md
|
@ -1,5 +1,7 @@
|
|||
# V Documentation
|
||||
|
||||
(See https://modules.vlang.io/ for documentation of V's standard library)
|
||||
|
||||
## Introduction
|
||||
|
||||
V is a statically typed compiled programming language designed for building maintainable software.
|
||||
|
@ -434,7 +436,7 @@ bool
|
|||
string
|
||||
|
||||
i8 i16 int i64 i128 (soon)
|
||||
byte u16 u32 u64 u128 (soon)
|
||||
u8 u16 u32 u64 u128 (soon)
|
||||
|
||||
rune // represents a Unicode code point
|
||||
|
||||
|
@ -460,7 +462,7 @@ These are the allowed possibilities:
|
|||
↘ ↘
|
||||
f32 → f64
|
||||
↗ ↗
|
||||
byte → u16 → u32 → u64 ⬎
|
||||
u8 → u16 → u32 → u64 ⬎
|
||||
↘ ↘ ↘ ptr
|
||||
i8 → i16 → int → i64 ⬏
|
||||
```
|
||||
|
@ -490,7 +492,7 @@ d := b + x // d is of type `f64` - automatic promotion of `x`'s value
|
|||
```v nofmt
|
||||
name := 'Bob'
|
||||
assert name.len == 3 // will print 3
|
||||
assert name[0] == byte(66) // indexing gives a byte, byte(66) == `B`
|
||||
assert name[0] == u8(66) // indexing gives a byte, u8(66) == `B`
|
||||
assert name[1..3] == 'ob' // slicing gives a string 'ob'
|
||||
|
||||
// escape codes
|
||||
|
@ -499,7 +501,7 @@ assert windows_newline.len == 2
|
|||
|
||||
// arbitrary bytes can be directly specified using `\x##` notation where `#` is
|
||||
// a hex digit aardvark_str := '\x61ardvark' assert aardvark_str == 'aardvark'
|
||||
assert '\xc0'[0] == byte(0xc0)
|
||||
assert '\xc0'[0] == u8(0xc0)
|
||||
|
||||
// or using octal escape `\###` notation where `#` is an octal digit
|
||||
aardvark_str2 := '\141ardvark'
|
||||
|
@ -518,7 +520,7 @@ In V, a string is a read-only array of bytes. All Unicode characters are encoded
|
|||
s := 'hello 🌎' // emoji takes 4 bytes
|
||||
assert s.len == 10
|
||||
|
||||
arr := s.bytes() // convert `string` to `[]byte`
|
||||
arr := s.bytes() // convert `string` to `[]u8`
|
||||
assert arr.len == 10
|
||||
|
||||
s2 := arr.bytestr() // convert `[]byte` to `string`
|
||||
|
@ -692,7 +694,7 @@ A `rune` can be converted to UTF-8 bytes by using the `.bytes()` method.
|
|||
|
||||
```v
|
||||
rocket := `🚀`
|
||||
assert rocket.bytes() == [byte(0xf0), 0x9f, 0x9a, 0x80]
|
||||
assert rocket.bytes() == [u8(0xf0), 0x9f, 0x9a, 0x80]
|
||||
```
|
||||
|
||||
Hex, Unicode, and Octal escape sequences also work in a `rune` literal:
|
||||
|
@ -704,9 +706,9 @@ assert `\u0061` == `a`
|
|||
|
||||
// multibyte literals work too
|
||||
assert `\u2605` == `★`
|
||||
assert `\u2605`.bytes() == [byte(0xe2), 0x98, 0x85]
|
||||
assert `\xe2\x98\x85`.bytes() == [byte(0xe2), 0x98, 0x85]
|
||||
assert `\342\230\205`.bytes() == [byte(0xe2), 0x98, 0x85]
|
||||
assert `\u2605`.bytes() == [u8(0xe2), 0x98, 0x85]
|
||||
assert `\xe2\x98\x85`.bytes() == [u8(0xe2), 0x98, 0x85]
|
||||
assert `\342\230\205`.bytes() == [u8(0xe2), 0x98, 0x85]
|
||||
```
|
||||
|
||||
Note that `rune` literals use the same escape syntax as strings, but they can only hold one unicode
|
||||
|
@ -763,7 +765,7 @@ If you want a different type of integer, you can use casting:
|
|||
|
||||
```v
|
||||
a := i64(123)
|
||||
b := byte(42)
|
||||
b := u8(42)
|
||||
c := i16(12345)
|
||||
```
|
||||
|
||||
|
@ -854,7 +856,7 @@ The type of an array is determined by the first element:
|
|||
* `[1, 2, 3]` is an array of ints (`[]int`).
|
||||
* `['a', 'b']` is an array of strings (`[]string`).
|
||||
|
||||
The user can explicitly specify the type for the first element: `[byte(16), 32, 64, 128]`.
|
||||
The user can explicitly specify the type for the first element: `[u8(16), 32, 64, 128]`.
|
||||
V arrays are homogeneous (all elements must have the same type).
|
||||
This means that code like `[1, 'a']` will not compile.
|
||||
|
||||
|
@ -2420,9 +2422,6 @@ 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.
|
||||
|
||||
> Warning: currently works on Unix-based, x64 architectures only.
|
||||
Some work is in progress to make closures work on Windows, then other architectures.
|
||||
|
||||
```v oksyntax
|
||||
my_int := 1
|
||||
my_closure := fn [my_int] () {
|
||||
|
@ -5432,9 +5431,6 @@ numbers: [1, 2, 3]
|
|||
3
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
#### `$env`
|
||||
|
||||
```v
|
||||
|
@ -5450,6 +5446,34 @@ V can bring in values at compile time from environment variables.
|
|||
`$env('ENV_VAR')` can also be used in top-level `#flag` and `#include` statements:
|
||||
`#flag linux -I $env('JAVA_HOME')/include`.
|
||||
|
||||
#### `$compile_error` and `$compile_warn`
|
||||
|
||||
These two comptime functions are very useful for displaying custom errors/warnings during
|
||||
compile time.
|
||||
|
||||
Both receive as their only argument a string literal that contains the message to display:
|
||||
|
||||
```v failcompile nofmt
|
||||
// x.v
|
||||
module main
|
||||
|
||||
$if linux {
|
||||
$compile_error('Linux is not supported')
|
||||
}
|
||||
|
||||
fn main() {
|
||||
}
|
||||
|
||||
$ v run x.v
|
||||
x.v:4:5: error: Linux is not supported
|
||||
2 |
|
||||
3 | $if linux {
|
||||
4 | $compile_error('Linux is not supported')
|
||||
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
5 | }
|
||||
6 |
|
||||
```
|
||||
|
||||
### Environment specific files
|
||||
|
||||
If a file has an environment-specific suffix, it will only be compiled for that environment.
|
||||
|
@ -6024,7 +6048,7 @@ a nested loop, and those do not risk violating memory-safety.
|
|||
|
||||
## Appendix I: Keywords
|
||||
|
||||
V has 41 reserved keywords (3 are literals):
|
||||
V has 42 reserved keywords (3 are literals):
|
||||
|
||||
```v ignore
|
||||
as
|
||||
|
@ -6036,7 +6060,6 @@ const
|
|||
continue
|
||||
defer
|
||||
else
|
||||
embed
|
||||
enum
|
||||
false
|
||||
fn
|
||||
|
@ -6048,6 +6071,7 @@ import
|
|||
in
|
||||
interface
|
||||
is
|
||||
isreftype
|
||||
lock
|
||||
match
|
||||
module
|
||||
|
|
|
@ -556,11 +556,11 @@ fn (mut app App) set_theme(idx int) {
|
|||
}
|
||||
|
||||
fn (mut app App) resize() {
|
||||
mut s := gg.dpi_scale()
|
||||
mut s := app.gg.scale
|
||||
if s == 0.0 {
|
||||
s = 1.0
|
||||
}
|
||||
window_size := gg.window_size()
|
||||
window_size := app.gg.window_size()
|
||||
w := window_size.width
|
||||
h := window_size.height
|
||||
m := f32(math.min(w, h))
|
||||
|
|
|
@ -32,8 +32,7 @@ const (
|
|||
|
||||
struct App {
|
||||
minutes_tic []f32 = [f32(center - tw), tp, center + tw, tp, center + tw, tp, center + tw,
|
||||
tp +
|
||||
1 * th, center - tw, tp + 1 * th]
|
||||
tp + 1 * th, center - tw, tp + 1 * th]
|
||||
hours_tic []f32 = [f32(center - tw), tp, center + tw, tp, center + tw, tp, center + tw, tp + 2 * th,
|
||||
center - tw, tp + 2 * th]
|
||||
hours3_tic []f32 = [f32(center - tw), tp, center + tw, tp, center + tw, tp, center + tw, tp + 3 * th,
|
||||
|
|
|
@ -22,7 +22,7 @@ fn main() {
|
|||
mut a := i64(0)
|
||||
mut b := i64(0)
|
||||
mut c := i64(1)
|
||||
println(a + c + c)
|
||||
println(a + b + c)
|
||||
for _ in 0 .. stop {
|
||||
// Set a and b to the next term
|
||||
a = b
|
||||
|
|
|
@ -25,7 +25,7 @@ fn on_frame(mut app App) {
|
|||
for mut frame in app.frames {
|
||||
for mut rocket in frame {
|
||||
if !rocket.exploded {
|
||||
rocket.color.a = byte(f32_max(rocket.color.a - 8, 0))
|
||||
rocket.color.a = u8(f32_max(rocket.color.a - 8, 0))
|
||||
rocket.draw(mut app.gg)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,8 +5,8 @@ import rand
|
|||
|
||||
pub fn random_color() gx.Color {
|
||||
return gx.Color{
|
||||
r: rand.byte()
|
||||
g: rand.byte()
|
||||
b: rand.byte()
|
||||
r: rand.u8()
|
||||
g: rand.u8()
|
||||
b: rand.u8()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,7 +19,7 @@ pub fn (particle Particle) draw(mut ctx gg.Context) {
|
|||
|
||||
pub fn (mut particle Particle) tick(mut rocket Rocket, mut ctx gg.Context) {
|
||||
particle.lifespan -= get_params().age_rate
|
||||
particle.color.a = byte(particle.lifespan)
|
||||
particle.color.a = u8(particle.lifespan)
|
||||
|
||||
if particle.lifespan <= 0 {
|
||||
rocket.dead = true
|
||||
|
|
|
@ -1,3 +1,18 @@
|
|||
fn main() {
|
||||
graph := {
|
||||
'A': ['B', 'C']
|
||||
'B': ['A', 'D', 'E']
|
||||
'C': ['A', 'F']
|
||||
'D': ['B']
|
||||
'E': ['B', 'F']
|
||||
'F': ['C', 'E']
|
||||
}
|
||||
println('Graph: $graph')
|
||||
path := breadth_first_search_path(graph, 'A', 'F')
|
||||
println('The shortest path from node A to node F is: $path')
|
||||
assert path == ['A', 'C', 'F']
|
||||
}
|
||||
|
||||
// Breadth-First Search (BFS) allows you to find the shortest distance between two nodes in the graph.
|
||||
fn breadth_first_search_path(graph map[string][]string, vertex string, target string) []string {
|
||||
mut path := []string{}
|
||||
|
@ -24,18 +39,3 @@ fn breadth_first_search_path(graph map[string][]string, vertex string, target st
|
|||
}
|
||||
return path
|
||||
}
|
||||
|
||||
fn main() {
|
||||
graph := {
|
||||
'A': ['B', 'C']
|
||||
'B': ['A', 'D', 'E']
|
||||
'C': ['A', 'F']
|
||||
'D': ['B']
|
||||
'E': ['B', 'F']
|
||||
'F': ['C', 'E']
|
||||
}
|
||||
println('Graph: $graph')
|
||||
path := breadth_first_search_path(graph, 'A', 'F')
|
||||
println('The shortest path from node A to node F is: $path')
|
||||
assert path == ['A', 'C', 'F']
|
||||
}
|
|
@ -0,0 +1,92 @@
|
|||
// Author: ccs
|
||||
// I follow literally code in C, done many years ago
|
||||
fn main() {
|
||||
// Adjacency matrix as a map
|
||||
graph := {
|
||||
'A': ['B', 'C']
|
||||
'B': ['A', 'D', 'E']
|
||||
'C': ['A', 'F']
|
||||
'D': ['B']
|
||||
'E': ['B', 'F']
|
||||
'F': ['C', 'E']
|
||||
}
|
||||
println('Graph: $graph')
|
||||
path := breadth_first_search_path(graph, 'A', 'F')
|
||||
println('\n The shortest path from node A to node F is: $path.reverse()')
|
||||
}
|
||||
|
||||
// Breadth-First Search (BFS) allows you to find the shortest distance between two nodes in the graph.
|
||||
fn breadth_first_search_path(graph map[string][]string, start string, target string) []string {
|
||||
mut path := []string{} // ONE PATH with SUCCESS = array
|
||||
mut queue := []string{} // a queue ... many paths
|
||||
// all_nodes := graph.keys() // get a key of this map
|
||||
n_nodes := graph.len // numbers of nodes of this graph
|
||||
// a map to store all the nodes visited to avoid cycles
|
||||
// start all them with False, not visited yet
|
||||
mut visited := a_map_nodes_bool(n_nodes) // a map fully
|
||||
// false ==> not visited yet: {'A': false, 'B': false, 'C': false, 'D': false, 'E': false}
|
||||
queue << start // first arrival
|
||||
for queue.len != 0 {
|
||||
mut node := departure(mut queue) // get the front node and remove it
|
||||
if visited[node] == false { // check if this node is already visited
|
||||
// if no ... test it searchinf for a final node
|
||||
visited[node] = true // means: visit this node
|
||||
if node == target {
|
||||
path = build_path_reverse(graph, start, node, visited)
|
||||
return path
|
||||
}
|
||||
// Expansion of node removed from queue
|
||||
print('\n Expansion of node $node (true/false): ${graph[node]}')
|
||||
// take all nodes from the node
|
||||
for vertex in graph[node] { // println("\n ...${vertex}")
|
||||
// not explored yet
|
||||
if visited[vertex] == false {
|
||||
queue << vertex
|
||||
}
|
||||
}
|
||||
print('\n QUEUE: $queue (only not visited) \n Visited: $visited')
|
||||
}
|
||||
}
|
||||
path = ['Path not found, problem in the Graph, start or end nodes! ']
|
||||
return path
|
||||
}
|
||||
|
||||
// Creating a map for VISITED nodes ...
|
||||
// starting by false ===> means this node was not visited yet
|
||||
fn a_map_nodes_bool(size int) map[string]bool {
|
||||
mut my_map := map[string]bool{} // look this map ...
|
||||
base := u8(65)
|
||||
mut key := base.ascii_str()
|
||||
for i in 0 .. size {
|
||||
key = u8(base + i).ascii_str()
|
||||
my_map[key] = false
|
||||
}
|
||||
return my_map
|
||||
}
|
||||
|
||||
// classical removing of a node from the start of a queue
|
||||
fn departure(mut queue []string) string {
|
||||
mut x := queue[0]
|
||||
queue.delete(0)
|
||||
return x
|
||||
}
|
||||
|
||||
// Based in the current node that is final, search for its parent, already visited, up to the root or start node
|
||||
fn build_path_reverse(graph map[string][]string, start string, final string, visited map[string]bool) []string {
|
||||
print('\n\n Nodes visited (true) or no (false): $visited')
|
||||
array_of_nodes := graph.keys()
|
||||
mut current := final
|
||||
mut path := []string{}
|
||||
path << current
|
||||
|
||||
for (current != start) {
|
||||
for i in array_of_nodes {
|
||||
if (current in graph[i]) && (visited[i] == true) {
|
||||
current = i
|
||||
break // the first ocurrence is enough
|
||||
}
|
||||
}
|
||||
path << current // update the path tracked
|
||||
}
|
||||
return path
|
||||
}
|
|
@ -0,0 +1,103 @@
|
|||
// Author: ccs
|
||||
// I follow literally code in C, done many years ago
|
||||
|
||||
fn main() {
|
||||
// Adjacency matrix as a map
|
||||
// Example 01
|
||||
graph_01 := {
|
||||
'A': ['B', 'C']
|
||||
'B': ['A', 'D', 'E']
|
||||
'C': ['A', 'F']
|
||||
'D': ['B']
|
||||
'E': ['F', 'B', 'F']
|
||||
'F': ['C', 'E']
|
||||
}
|
||||
// Example 02
|
||||
graph_02 := {
|
||||
'A': ['B', 'C', 'D']
|
||||
'B': ['E']
|
||||
'C': ['F']
|
||||
'D': ['E']
|
||||
'E': ['H']
|
||||
'F': ['H']
|
||||
'G': ['H']
|
||||
'H': ['E', 'F', 'G']
|
||||
}
|
||||
// println('Graph: $graph')
|
||||
path_01 := depth_first_search_path(graph_01, 'A', 'F')
|
||||
println('\n Graph_01: a first path from node A to node F is: $path_01.reverse()')
|
||||
path_02 := depth_first_search_path(graph_02, 'A', 'H')
|
||||
println('\n Graph_02: a first path from node A to node F is: $path_02.reverse()')
|
||||
}
|
||||
|
||||
// Depth-First Search (BFS) allows you to find a path between two nodes in the graph.
|
||||
fn depth_first_search_path(graph map[string][]string, start string, target string) []string {
|
||||
mut path := []string{} // ONE PATH with SUCCESS = array
|
||||
mut stack := []string{} // a stack ... many nodes
|
||||
// all_nodes := graph.keys() // get a key of this map
|
||||
n_nodes := graph.len // numbers of nodes of this graph
|
||||
mut visited := a_map_nodes_bool(n_nodes) // a map fully
|
||||
// false ... not visited yet: {'A': false, 'B': false, 'C': false, 'D': false, 'E': false}
|
||||
|
||||
stack << start // first push on the stack
|
||||
for stack.len > 0 {
|
||||
mut node := stack.pop() // get the top node and remove it from the stack
|
||||
|
||||
// check if this node is already visited
|
||||
if visited[node] == false {
|
||||
// if no ... test it searchin for a final node
|
||||
visited[node] = true // means: node visited
|
||||
if node == target {
|
||||
path = build_path_reverse(graph, start, node, visited)
|
||||
return path
|
||||
}
|
||||
// Exploring of node removed from stack and add its relatives
|
||||
print('\n Exploring of node $node (true/false): ${graph[node]}')
|
||||
// graph[node].reverse() take a classical choice for DFS
|
||||
// at most os left in this case.
|
||||
// use vertex in graph[node] the choice is right
|
||||
|
||||
// take all nodes from the node
|
||||
for vertex in graph[node].reverse() {
|
||||
// println("\n ...${vertex}")
|
||||
// not explored yet
|
||||
if visited[vertex] == false {
|
||||
stack << vertex
|
||||
}
|
||||
}
|
||||
print('\n Stack: $stack (only not visited) \n Visited: $visited')
|
||||
}
|
||||
}
|
||||
path = ['Path not found, problem in the Graph, start or end nodes! ']
|
||||
return path
|
||||
}
|
||||
|
||||
// Creating a map for nodes not VISITED visited ...
|
||||
// starting by false ===> means this node was not visited yet
|
||||
fn a_map_nodes_bool(size int) map[string]bool {
|
||||
mut my_map := map[string]bool{} // look this map ...
|
||||
for i in 0 .. size {
|
||||
my_map[u8(65 + i).ascii_str()] = false
|
||||
}
|
||||
return my_map
|
||||
}
|
||||
|
||||
// Based in the current node that is final, search for his parent, that is already visited, up to the root or start node
|
||||
fn build_path_reverse(graph map[string][]string, start string, final string, visited map[string]bool) []string {
|
||||
print('\n\n Nodes visited (true) or no (false): $visited')
|
||||
array_of_nodes := graph.keys()
|
||||
mut current := final
|
||||
mut path := []string{}
|
||||
path << current
|
||||
|
||||
for current != start {
|
||||
for i in array_of_nodes {
|
||||
if (current in graph[i]) && (visited[i] == true) {
|
||||
current = i
|
||||
break // the first ocurrence is enough
|
||||
}
|
||||
}
|
||||
path << current // updating the path tracked
|
||||
}
|
||||
return path
|
||||
}
|
|
@ -0,0 +1,90 @@
|
|||
// https://en.wikipedia.org/wiki/Topological_sorting
|
||||
// A DFS RECURSIVE ALGORITHM ....
|
||||
// An alternative algorithm for topological sorting is based on depth-first search. The algorithm loops through each node of the graph, in an arbitrary order, initiating a depth-first search that terminates when it hits any node that has already been visited since the beginning
|
||||
// of the topological sort or the node has no outgoing edges (i.e. a leaf node)
|
||||
// Discussion: https://www.gatevidyalay.com/topological-sort-topological-sorting/
|
||||
// $ v run dfs_topological_ordering.v
|
||||
// Author: CCS
|
||||
|
||||
// THE DFS RECURSIVE .... classical searchig for leaves nodes
|
||||
// the arguments are used in the function to avoid global variables....
|
||||
fn dfs_recursive(u string, mut visited map[string]bool, graph map[string][]string, mut top_sorting []string) {
|
||||
print(' Visiting: $u -> ')
|
||||
visited[u] = true
|
||||
|
||||
for v in graph[u] {
|
||||
if visited[v] == false {
|
||||
dfs_recursive(v, mut visited, graph, mut top_sorting)
|
||||
}
|
||||
}
|
||||
top_sorting << u
|
||||
}
|
||||
|
||||
// Creating aa map to initialize with of visited nodes .... all with false in the init
|
||||
// so these nodes are NOT VISITED YET
|
||||
fn visited_init(a_graph map[string][]string) map[string]bool {
|
||||
mut array_of_keys := a_graph.keys() // get all keys of this map
|
||||
mut temp := map[string]bool{} // attention in these initializations with maps
|
||||
for i in array_of_keys {
|
||||
temp[i] = false
|
||||
}
|
||||
return temp
|
||||
}
|
||||
|
||||
// attention here a map STRING ---> ONE BOOLEAN ... not a string
|
||||
|
||||
fn main() {
|
||||
// A map illustration to use in a graph
|
||||
// the graph: adjacency matrix
|
||||
graph_01 := {
|
||||
'A': ['C', 'B']
|
||||
'B': ['D']
|
||||
'C': ['D']
|
||||
'D': []
|
||||
}
|
||||
|
||||
graph_02 := {
|
||||
'A': ['B', 'C', 'D']
|
||||
'B': ['E']
|
||||
'C': ['F']
|
||||
'D': ['G']
|
||||
'E': ['H']
|
||||
'F': ['H']
|
||||
'G': ['H']
|
||||
'H': [] // no cycles
|
||||
}
|
||||
// from: https://en.wikipedia.org/wiki/Topological_sorting
|
||||
graph_03 := {
|
||||
'5': ['11']
|
||||
'7': ['11', '8']
|
||||
'3': ['8', '10']
|
||||
'11': ['2', '9', '10']
|
||||
'8': ['9']
|
||||
'2': []
|
||||
'9': []
|
||||
'10': []
|
||||
}
|
||||
|
||||
mut graph := map[string][]string{} // the graph: adjacency matrix
|
||||
for index, g_value in [graph_01, graph_02, graph_03] {
|
||||
println('Topological sorting for the graph $index using a DFS recursive')
|
||||
graph = g_value.clone() // graphs_sample[g].clone() // choice your SAMPLE
|
||||
|
||||
// mut n_nodes := graph.len
|
||||
mut visited := visited_init(graph) // a map with nodes not visited
|
||||
|
||||
// mut start := (graph.keys()).first() // arbitrary, any node if you wish
|
||||
mut top_sorting := []string{}
|
||||
// advantages of map ... getting all nodes
|
||||
for i in graph.keys() {
|
||||
if visited[i] != true {
|
||||
dfs_recursive(i, mut visited, graph, mut top_sorting)
|
||||
}
|
||||
}
|
||||
|
||||
print('\n A topological sorting of graph $index : ')
|
||||
// println(g_value)
|
||||
println(top_sorting.reverse())
|
||||
println('')
|
||||
} // End of for
|
||||
}
|
|
@ -0,0 +1,146 @@
|
|||
// The idea of this algorithm follow :
|
||||
// https://www.gatevidyalay.com/topological-sort-topological-sorting/ (GREEDY)
|
||||
// (no cycles are detected)
|
||||
// https://en.wikipedia.org/wiki/Topological_sorting ... just the input data
|
||||
// and the Kahn algorithm
|
||||
// Author: CCS
|
||||
|
||||
// the idea is rude: https://www.gatevidyalay.com/topological-sort-topological-sorting/
|
||||
fn topog_sort_greedy(graph map[string][]string) []string {
|
||||
n_nodes := graph.len // numbers of nodes of this graph
|
||||
mut top_order := []string{} // a vector with sequence of nodes visited
|
||||
mut count := 0
|
||||
/*
|
||||
IDEA ( a greedy algorythm ):
|
||||
|
||||
1. choose allways the node with smallest input degree
|
||||
2. visit it
|
||||
3. put it in the output vector
|
||||
4. remove it from graph
|
||||
5. update the graph (a new graph)
|
||||
6. find a new vector degree
|
||||
7. until all nodes has been visited
|
||||
Back to step 1 (used the variable count)
|
||||
|
||||
Maybe it seems the Kahn's algorithm
|
||||
*/
|
||||
mut v_degree := in_degree(graph) // return: map [string] int
|
||||
print('V Degree $v_degree')
|
||||
mut small_degree := min_degree(v_degree)
|
||||
mut new_graph := remove_node_from_graph(small_degree, graph)
|
||||
top_order << small_degree
|
||||
count++
|
||||
|
||||
for (count < n_nodes) {
|
||||
v_degree = in_degree(new_graph) // return: map [string] int
|
||||
print('\nV Degree $v_degree')
|
||||
small_degree = min_degree(v_degree)
|
||||
new_graph = remove_node_from_graph(small_degree, new_graph)
|
||||
|
||||
top_order << small_degree
|
||||
count++
|
||||
}
|
||||
// print("\n New Graph ${new_graph}")
|
||||
|
||||
return top_order
|
||||
}
|
||||
|
||||
// Give a node, return a list with all nodes incidents or fathers of this node
|
||||
fn all_fathers(node string, a_map map[string][]string) []string {
|
||||
mut array_of_keys := a_map.keys() // get a key of this map
|
||||
mut all_incident := []string{}
|
||||
for i in array_of_keys {
|
||||
// in : function
|
||||
if node in a_map[i] {
|
||||
all_incident << i // a queue of this search
|
||||
}
|
||||
}
|
||||
return all_incident
|
||||
}
|
||||
|
||||
// Input: a map with input degree values, return the key with smallest value
|
||||
fn min_degree(a_map map[string]int) string {
|
||||
mut array_of_keys := a_map.keys() // get a key of this map
|
||||
mut key_min := array_of_keys.first()
|
||||
mut val_min := a_map[key_min]
|
||||
// print("\n MIN: ${val_min} \t key_min: ${key_min} \n the map inp_degree: ${a_map}")
|
||||
for i in array_of_keys {
|
||||
// there is a smaller
|
||||
if val_min > a_map[i] {
|
||||
val_min = a_map[i]
|
||||
key_min = i
|
||||
}
|
||||
}
|
||||
return key_min // the key with smallest value
|
||||
}
|
||||
|
||||
// Given a graph ... return a list of integer with degree of each node
|
||||
fn in_degree(a_map map[string][]string) map[string]int {
|
||||
mut array_of_keys := a_map.keys() // get a key of this map
|
||||
// print(array_of_keys)
|
||||
mut degree := map[string]int{}
|
||||
for i in array_of_keys {
|
||||
degree[i] = all_fathers(i, a_map).len
|
||||
}
|
||||
// print("\n Degree ${in_degree}" )
|
||||
return degree // a vector of the indegree graph
|
||||
}
|
||||
|
||||
// REMOVE A NODE FROM A GRAPH AND RETURN ANOTHER GRAPH
|
||||
fn remove_node_from_graph(node string, a_map map[string][]string) map[string][]string {
|
||||
// mut new_graph := map [string] string {}
|
||||
mut new_graph := a_map.clone() // copy the graph
|
||||
new_graph.delete(node)
|
||||
mut all_nodes := new_graph.keys() // get all nodes of this graph
|
||||
// FOR THE FUTURE with filter
|
||||
// for i in all_nodes {
|
||||
// new_graph[i] = new_graph[i].filter(index(it) != node)
|
||||
// }
|
||||
// A HELP FROM V discussion GITHUB - thread
|
||||
for key in all_nodes {
|
||||
i := new_graph[key].index(node)
|
||||
if i >= 0 {
|
||||
new_graph[key].delete(i)
|
||||
}
|
||||
}
|
||||
// print("\n NEW ${new_graph}" )
|
||||
return new_graph
|
||||
}
|
||||
|
||||
fn main() {
|
||||
// A map illustration to use in a graph
|
||||
// adjacency matrix
|
||||
graph_01 := {
|
||||
'A': ['C', 'B']
|
||||
'B': ['D']
|
||||
'C': ['D']
|
||||
'D': []
|
||||
}
|
||||
|
||||
graph_02 := {
|
||||
'A': ['B', 'C', 'D']
|
||||
'B': ['E']
|
||||
'C': ['F']
|
||||
'D': ['G']
|
||||
'E': ['H']
|
||||
'F': ['H']
|
||||
'G': ['H']
|
||||
'H': []
|
||||
}
|
||||
// from: https://en.wikipedia.org/wiki/Topological_sorting
|
||||
graph_03 := {
|
||||
'5': ['11']
|
||||
'7': ['11', '8']
|
||||
'3': ['8', '10']
|
||||
'11': ['2', '9', '10']
|
||||
'8': ['9']
|
||||
'2': []
|
||||
'9': []
|
||||
'10': []
|
||||
}
|
||||
|
||||
println('\nA Topological Sort of G1: ${topog_sort_greedy(graph_01)}')
|
||||
println('\nA Topological Sort of G2: ${topog_sort_greedy(graph_02)}')
|
||||
println('\nA Topological Sort of G3: ${topog_sort_greedy(graph_03)}')
|
||||
// ['2', '9', '10', '11', '5', '8', '7', '3']
|
||||
}
|
|
@ -8,8 +8,8 @@ fn main() {
|
|||
conn.close() or {}
|
||||
}
|
||||
|
||||
println(' peer: $conn.peer_addr()')
|
||||
println('local: $conn.addr()')
|
||||
println(' peer: ${conn.peer_addr()?}')
|
||||
println('local: ${conn.addr()?}')
|
||||
|
||||
// Simple http HEAD request for a file
|
||||
conn.write_string('HEAD /index.html HTTP/1.0\r\n\r\n')?
|
||||
|
|
|
@ -9,7 +9,7 @@ fn main() {
|
|||
println('------------------------------------------')
|
||||
is_server := '-l' in os.args
|
||||
port := cmdline.option(os.args, '-p', '40001').int()
|
||||
mut buf := []byte{len: 100}
|
||||
mut buf := []u8{len: 100}
|
||||
if is_server {
|
||||
println('UDP echo server, listening for udp packets on port: $port')
|
||||
mut c := net.listen_udp(':$port')?
|
||||
|
|
|
@ -35,14 +35,14 @@ pub fn (s ImageSettings) to_grid_settings() sim.GridSettings {
|
|||
pub struct PPMWriter {
|
||||
mut:
|
||||
file os.File
|
||||
cache []byte
|
||||
cache []u8
|
||||
cache_size int
|
||||
}
|
||||
|
||||
pub fn ppm_writer_for_fname(fname string, settings ImageSettings) ?&PPMWriter {
|
||||
mut writer := &PPMWriter{
|
||||
cache_size: settings.cache_size
|
||||
cache: []byte{cap: settings.cache_size}
|
||||
cache: []u8{cap: settings.cache_size}
|
||||
}
|
||||
writer.start_for_file(fname, settings)?
|
||||
return writer
|
||||
|
|
|
@ -2,6 +2,6 @@ import rand
|
|||
|
||||
fn main() {
|
||||
for _ in 0 .. 10 {
|
||||
println('${rand.intn(255)}.${rand.intn(255)}.${rand.intn(255)}.${rand.intn(255)}')
|
||||
println('${rand.intn(255)?}.${rand.intn(255)?}.${rand.intn(255)?}.${rand.intn(255)?}')
|
||||
}
|
||||
}
|
||||
|
|
|
@ -50,7 +50,7 @@ fn create_texture(w int, h int, buf &u8) gfx.Image {
|
|||
// usage: .dynamic
|
||||
wrap_u: .clamp_to_edge
|
||||
wrap_v: .clamp_to_edge
|
||||
label: &byte(0)
|
||||
label: &u8(0)
|
||||
d3d11_texture: 0
|
||||
}
|
||||
// commen if .dynamic is enabled
|
||||
|
@ -68,7 +68,7 @@ fn destroy_texture(sg_img gfx.Image) {
|
|||
}
|
||||
|
||||
// Use only if usage: .dynamic is enabled
|
||||
fn update_text_texture(sg_img gfx.Image, w int, h int, buf &byte) {
|
||||
fn update_text_texture(sg_img gfx.Image, w int, h int, buf &u8) {
|
||||
sz := w * h * 4
|
||||
mut tmp_sbc := gfx.ImageData{}
|
||||
tmp_sbc.subimage[0][0] = gfx.Range{
|
||||
|
@ -352,23 +352,23 @@ fn my_init(mut app App) {
|
|||
x := (i & 0xFF) >> 5 // 8 cell
|
||||
// upper left corner
|
||||
if x == 0 && y == 0 {
|
||||
tmp_txt[i] = byte(0xFF)
|
||||
tmp_txt[i + 1] = byte(0)
|
||||
tmp_txt[i + 2] = byte(0)
|
||||
tmp_txt[i + 3] = byte(0xFF)
|
||||
tmp_txt[i] = u8(0xFF)
|
||||
tmp_txt[i + 1] = u8(0)
|
||||
tmp_txt[i + 2] = u8(0)
|
||||
tmp_txt[i + 3] = u8(0xFF)
|
||||
}
|
||||
// low right corner
|
||||
else if x == 7 && y == 7 {
|
||||
tmp_txt[i] = byte(0)
|
||||
tmp_txt[i + 1] = byte(0xFF)
|
||||
tmp_txt[i + 2] = byte(0)
|
||||
tmp_txt[i + 3] = byte(0xFF)
|
||||
tmp_txt[i] = u8(0)
|
||||
tmp_txt[i + 1] = u8(0xFF)
|
||||
tmp_txt[i + 2] = u8(0)
|
||||
tmp_txt[i + 3] = u8(0xFF)
|
||||
} else {
|
||||
col := if ((x + y) & 1) == 1 { 0xFF } else { 0 }
|
||||
tmp_txt[i] = byte(col) // red
|
||||
tmp_txt[i + 1] = byte(col) // green
|
||||
tmp_txt[i + 2] = byte(col) // blue
|
||||
tmp_txt[i + 3] = byte(0xFF) // alpha
|
||||
tmp_txt[i] = u8(col) // red
|
||||
tmp_txt[i + 1] = u8(col) // green
|
||||
tmp_txt[i + 2] = u8(col) // blue
|
||||
tmp_txt[i + 3] = u8(0xFF) // alpha
|
||||
}
|
||||
i += 4
|
||||
}
|
||||
|
|
|
@ -66,7 +66,7 @@ fn create_texture(w int, h int, buf &byte) gfx.Image {
|
|||
// usage: .dynamic
|
||||
wrap_u: .clamp_to_edge
|
||||
wrap_v: .clamp_to_edge
|
||||
label: &byte(0)
|
||||
label: &u8(0)
|
||||
d3d11_texture: 0
|
||||
}
|
||||
// comment if .dynamic is enabled
|
||||
|
@ -524,23 +524,23 @@ fn my_init(mut app App) {
|
|||
x := (i & 0xFF) >> 5 // 8 cell
|
||||
// upper left corner
|
||||
if x == 0 && y == 0 {
|
||||
tmp_txt[i] = byte(0xFF)
|
||||
tmp_txt[i + 1] = byte(0)
|
||||
tmp_txt[i + 2] = byte(0)
|
||||
tmp_txt[i + 3] = byte(0xFF)
|
||||
tmp_txt[i] = u8(0xFF)
|
||||
tmp_txt[i + 1] = u8(0)
|
||||
tmp_txt[i + 2] = u8(0)
|
||||
tmp_txt[i + 3] = u8(0xFF)
|
||||
}
|
||||
// low right corner
|
||||
else if x == 7 && y == 7 {
|
||||
tmp_txt[i + 0] = byte(0)
|
||||
tmp_txt[i + 1] = byte(0xFF)
|
||||
tmp_txt[i + 2] = byte(0)
|
||||
tmp_txt[i + 3] = byte(0xFF)
|
||||
tmp_txt[i + 0] = u8(0)
|
||||
tmp_txt[i + 1] = u8(0xFF)
|
||||
tmp_txt[i + 2] = u8(0)
|
||||
tmp_txt[i + 3] = u8(0xFF)
|
||||
} else {
|
||||
col := if ((x + y) & 1) == 1 { 0xFF } else { 128 }
|
||||
tmp_txt[i + 0] = byte(col) // red
|
||||
tmp_txt[i + 1] = byte(col) // green
|
||||
tmp_txt[i + 2] = byte(col) // blue
|
||||
tmp_txt[i + 3] = byte(0xFF) // alpha
|
||||
tmp_txt[i + 0] = u8(col) // red
|
||||
tmp_txt[i + 1] = u8(col) // green
|
||||
tmp_txt[i + 2] = u8(col) // blue
|
||||
tmp_txt[i + 3] = u8(0xFF) // alpha
|
||||
}
|
||||
i += 4
|
||||
}
|
||||
|
|
|
@ -65,7 +65,7 @@ fn create_texture(w int, h int, buf &byte) gfx.Image {
|
|||
// usage: .dynamic
|
||||
wrap_u: .clamp_to_edge
|
||||
wrap_v: .clamp_to_edge
|
||||
label: &byte(0)
|
||||
label: &u8(0)
|
||||
d3d11_texture: 0
|
||||
}
|
||||
// comment if .dynamic is enabled
|
||||
|
@ -342,23 +342,23 @@ fn my_init(mut app App) {
|
|||
x := (i & 0xFF) >> 5 // 8 cell
|
||||
// upper left corner
|
||||
if x == 0 && y == 0 {
|
||||
tmp_txt[i + 0] = byte(0xFF)
|
||||
tmp_txt[i + 1] = byte(0)
|
||||
tmp_txt[i + 2] = byte(0)
|
||||
tmp_txt[i + 3] = byte(0xFF)
|
||||
tmp_txt[i + 0] = u8(0xFF)
|
||||
tmp_txt[i + 1] = u8(0)
|
||||
tmp_txt[i + 2] = u8(0)
|
||||
tmp_txt[i + 3] = u8(0xFF)
|
||||
}
|
||||
// low right corner
|
||||
else if x == 7 && y == 7 {
|
||||
tmp_txt[i + 0] = byte(0)
|
||||
tmp_txt[i + 1] = byte(0xFF)
|
||||
tmp_txt[i + 2] = byte(0)
|
||||
tmp_txt[i + 3] = byte(0xFF)
|
||||
tmp_txt[i + 0] = u8(0)
|
||||
tmp_txt[i + 1] = u8(0xFF)
|
||||
tmp_txt[i + 2] = u8(0)
|
||||
tmp_txt[i + 3] = u8(0xFF)
|
||||
} else {
|
||||
col := if ((x + y) & 1) == 1 { 0xFF } else { 128 }
|
||||
tmp_txt[i + 0] = byte(col) // red
|
||||
tmp_txt[i + 1] = byte(col) // green
|
||||
tmp_txt[i + 2] = byte(col) // blue
|
||||
tmp_txt[i + 3] = byte(0xFF) // alpha
|
||||
tmp_txt[i + 0] = u8(col) // red
|
||||
tmp_txt[i + 1] = u8(col) // green
|
||||
tmp_txt[i + 2] = u8(col) // blue
|
||||
tmp_txt[i + 3] = u8(0xFF) // alpha
|
||||
}
|
||||
i += 4
|
||||
}
|
||||
|
|
|
@ -67,7 +67,7 @@ fn create_texture(w int, h int, buf byteptr) gfx.Image {
|
|||
// usage: .dynamic
|
||||
wrap_u: .clamp_to_edge
|
||||
wrap_v: .clamp_to_edge
|
||||
label: &byte(0)
|
||||
label: &u8(0)
|
||||
d3d11_texture: 0
|
||||
}
|
||||
// comment if .dynamic is enabled
|
||||
|
@ -530,23 +530,23 @@ fn my_init(mut app App) {
|
|||
x := (i & 0xFF) >> 5 // 8 cell
|
||||
// upper left corner
|
||||
if x == 0 && y == 0 {
|
||||
tmp_txt[i + 0] = byte(0xFF)
|
||||
tmp_txt[i + 1] = byte(0)
|
||||
tmp_txt[i + 2] = byte(0)
|
||||
tmp_txt[i + 3] = byte(0xFF)
|
||||
tmp_txt[i + 0] = u8(0xFF)
|
||||
tmp_txt[i + 1] = u8(0)
|
||||
tmp_txt[i + 2] = u8(0)
|
||||
tmp_txt[i + 3] = u8(0xFF)
|
||||
}
|
||||
// low right corner
|
||||
else if x == 7 && y == 7 {
|
||||
tmp_txt[i + 0] = byte(0)
|
||||
tmp_txt[i + 1] = byte(0xFF)
|
||||
tmp_txt[i + 2] = byte(0)
|
||||
tmp_txt[i + 3] = byte(0xFF)
|
||||
tmp_txt[i + 0] = u8(0)
|
||||
tmp_txt[i + 1] = u8(0xFF)
|
||||
tmp_txt[i + 2] = u8(0)
|
||||
tmp_txt[i + 3] = u8(0xFF)
|
||||
} else {
|
||||
col := if ((x + y) & 1) == 1 { 0xFF } else { 128 }
|
||||
tmp_txt[i + 0] = byte(col) // red
|
||||
tmp_txt[i + 1] = byte(col) // green
|
||||
tmp_txt[i + 2] = byte(col) // blue
|
||||
tmp_txt[i + 3] = byte(0xFF) // alpha
|
||||
tmp_txt[i + 0] = u8(col) // red
|
||||
tmp_txt[i + 1] = u8(col) // green
|
||||
tmp_txt[i + 2] = u8(col) // blue
|
||||
tmp_txt[i + 3] = u8(0xFF) // alpha
|
||||
}
|
||||
i += 4
|
||||
}
|
||||
|
|
|
@ -80,7 +80,7 @@ fn create_texture(w int, h int, buf byteptr) gfx.Image{
|
|||
//usage: .dynamic
|
||||
wrap_u: .clamp_to_edge
|
||||
wrap_v: .clamp_to_edge
|
||||
label: &byte(0)
|
||||
label: &u8(0)
|
||||
d3d11_texture: 0
|
||||
}
|
||||
// comment if .dynamic is enabled
|
||||
|
@ -406,23 +406,23 @@ fn my_init(mut app App) {
|
|||
x := (i & 0xFF) >> 5 // 8 cell
|
||||
// upper left corner
|
||||
if x == 0 && y == 0 {
|
||||
tmp_txt[i + 0] = byte(0xFF)
|
||||
tmp_txt[i + 1] = byte(0)
|
||||
tmp_txt[i + 2] = byte(0)
|
||||
tmp_txt[i + 3] = byte(0xFF)
|
||||
tmp_txt[i + 0] = u8(0xFF)
|
||||
tmp_txt[i + 1] = u8(0)
|
||||
tmp_txt[i + 2] = u8(0)
|
||||
tmp_txt[i + 3] = u8(0xFF)
|
||||
}
|
||||
// low right corner
|
||||
else if x == 7 && y == 7 {
|
||||
tmp_txt[i + 0] = byte(0)
|
||||
tmp_txt[i + 1] = byte(0xFF)
|
||||
tmp_txt[i + 2] = byte(0)
|
||||
tmp_txt[i + 3] = byte(0xFF)
|
||||
tmp_txt[i + 0] = u8(0)
|
||||
tmp_txt[i + 1] = u8(0xFF)
|
||||
tmp_txt[i + 2] = u8(0)
|
||||
tmp_txt[i + 3] = u8(0xFF)
|
||||
} else {
|
||||
col := if ((x + y) & 1) == 1 { 0xFF } else { 128 }
|
||||
tmp_txt[i + 0] = byte(col) // red
|
||||
tmp_txt[i + 1] = byte(col) // green
|
||||
tmp_txt[i + 2] = byte(col) // blue
|
||||
tmp_txt[i + 3] = byte(0xFF) // alpha
|
||||
tmp_txt[i + 0] = u8(col) // red
|
||||
tmp_txt[i + 1] = u8(col) // green
|
||||
tmp_txt[i + 2] = u8(col) // blue
|
||||
tmp_txt[i + 3] = u8(0xFF) // alpha
|
||||
}
|
||||
i += 4
|
||||
}
|
||||
|
|
|
@ -18,7 +18,7 @@ import stbi
|
|||
/******************************************************************************
|
||||
* Texture functions
|
||||
******************************************************************************/
|
||||
pub fn create_texture(w int, h int, buf &byte) gfx.Image {
|
||||
pub fn create_texture(w int, h int, buf &u8) gfx.Image {
|
||||
sz := w * h * 4
|
||||
mut img_desc := gfx.ImageDesc{
|
||||
width: w
|
||||
|
@ -29,7 +29,7 @@ pub fn create_texture(w int, h int, buf &byte) gfx.Image {
|
|||
// usage: .dynamic
|
||||
wrap_u: .clamp_to_edge
|
||||
wrap_v: .clamp_to_edge
|
||||
label: &byte(0)
|
||||
label: &u8(0)
|
||||
d3d11_texture: 0
|
||||
}
|
||||
// comment if .dynamic is enabled
|
||||
|
|
|
@ -23,10 +23,10 @@ pub fn read_lines_from_file(file_path string) []string {
|
|||
return rows
|
||||
}
|
||||
|
||||
// read a file as []byte
|
||||
pub fn read_bytes_from_file(file_path string) []byte {
|
||||
// read a file as []u8
|
||||
pub fn read_bytes_from_file(file_path string) []u8 {
|
||||
mut path := ''
|
||||
mut buffer := []byte{}
|
||||
mut buffer := []u8{}
|
||||
$if android {
|
||||
path = 'models/' + file_path
|
||||
buffer = os.read_apk_asset(path) or {
|
||||
|
|
|
@ -220,10 +220,10 @@ fn my_init(mut app App) {
|
|||
// 1x1 pixel white, default texture
|
||||
unsafe {
|
||||
tmp_txt := malloc(4)
|
||||
tmp_txt[0] = byte(0xFF)
|
||||
tmp_txt[1] = byte(0xFF)
|
||||
tmp_txt[2] = byte(0xFF)
|
||||
tmp_txt[3] = byte(0xFF)
|
||||
tmp_txt[0] = u8(0xFF)
|
||||
tmp_txt[1] = u8(0xFF)
|
||||
tmp_txt[2] = u8(0xFF)
|
||||
tmp_txt[3] = u8(0xFF)
|
||||
app.texture = obj.create_texture(1, 1, tmp_txt)
|
||||
free(tmp_txt)
|
||||
}
|
||||
|
|
|
@ -5,8 +5,8 @@ module particle
|
|||
// * Color
|
||||
pub struct Color {
|
||||
mut:
|
||||
r byte
|
||||
g byte
|
||||
b byte
|
||||
a byte
|
||||
r u8
|
||||
g u8
|
||||
b u8
|
||||
a u8
|
||||
}
|
||||
|
|
|
@ -46,10 +46,10 @@ pub fn (mut p Particle) update(dt f64) {
|
|||
lt := p.life_time - (1000 * dt)
|
||||
if lt > 0 {
|
||||
p.life_time = lt
|
||||
p.color.r = p.color.r - 1 // byte(remap(p.life_time,0.0,p.life_time_init,0,p.color.r))
|
||||
p.color.g = p.color.g - 1 // byte(remap(p.life_time,0.0,p.life_time_init,0,p.color.g))
|
||||
p.color.b = p.color.b - 1 // byte(remap(p.life_time,0.0,p.life_time_init,0,p.color.b))
|
||||
p.color.a = byte(int(remap(p.life_time, 0.0, p.life_time_init, 0, 255))) - 10
|
||||
p.color.r = p.color.r - 1 // u8(remap(p.life_time,0.0,p.life_time_init,0,p.color.r))
|
||||
p.color.g = p.color.g - 1 // u8(remap(p.life_time,0.0,p.life_time_init,0,p.color.g))
|
||||
p.color.b = p.color.b - 1 // u8(remap(p.life_time,0.0,p.life_time_init,0,p.color.b))
|
||||
p.color.a = u8(int(remap(p.life_time, 0.0, p.life_time_init, 0, 255))) - 10
|
||||
} else {
|
||||
p.life_time = 0
|
||||
}
|
||||
|
|
|
@ -22,7 +22,7 @@ fn my_audio_stream_callback(buffer &f32, num_frames int, num_channels int, mut a
|
|||
for ch := 0; ch < num_channels; ch++ {
|
||||
idx := frame * num_channels + ch
|
||||
unsafe {
|
||||
a := f32(byte(y) - 127) / 255.0
|
||||
a := f32(u8(y) - 127) / 255.0
|
||||
soundbuffer[idx] = a
|
||||
acontext.frames[idx & 2047] = a
|
||||
}
|
||||
|
@ -61,8 +61,8 @@ fn graphics_frame(mut state AppState) {
|
|||
}
|
||||
|
||||
[inline]
|
||||
fn (mut state AppState) bsample(idx int) byte {
|
||||
return byte(127 + state.frames[(state.gframe + idx) & 2047] * 128)
|
||||
fn (mut state AppState) bsample(idx int) u8 {
|
||||
return u8(127 + state.frames[(state.gframe + idx) & 2047] * 128)
|
||||
}
|
||||
|
||||
fn (mut state AppState) draw() {
|
||||
|
|
|
@ -92,13 +92,13 @@ fn (mut p Player) free() {
|
|||
// > MUST be placed before the Sound data chunk (but not necessarily
|
||||
// > contiguous to the Sound data chunk).
|
||||
struct RIFFHeader {
|
||||
riff [4]byte
|
||||
riff [4]u8
|
||||
file_size u32
|
||||
form_type [4]byte
|
||||
form_type [4]u8
|
||||
}
|
||||
|
||||
struct RIFFChunkHeader {
|
||||
chunk_type [4]byte
|
||||
chunk_type [4]u8
|
||||
chunk_size u32
|
||||
chunk_data voidptr
|
||||
}
|
||||
|
@ -113,21 +113,21 @@ struct RIFFFormat {
|
|||
cbsize u16 // Size of the extension: 22
|
||||
valid_bits_per_sample u16 // at most 8*M
|
||||
channel_mask u32 // Speaker position mask
|
||||
sub_format [16]byte // GUID
|
||||
sub_format [16]u8 // GUID
|
||||
}
|
||||
|
||||
fn read_wav_file_samples(fpath string) ?[]f32 {
|
||||
mut res := []f32{}
|
||||
// eprintln('> read_wav_file_samples: $fpath -------------------------------------------------')
|
||||
mut bytes := os.read_bytes(fpath)?
|
||||
mut pbytes := &byte(bytes.data)
|
||||
mut pbytes := &u8(bytes.data)
|
||||
mut offset := u32(0)
|
||||
rh := unsafe { &RIFFHeader(pbytes) }
|
||||
// eprintln('rh: $rh')
|
||||
if rh.riff != [byte(`R`), `I`, `F`, `F`]! {
|
||||
if rh.riff != [u8(`R`), `I`, `F`, `F`]! {
|
||||
return error('WAV should start with `RIFF`')
|
||||
}
|
||||
if rh.form_type != [byte(`W`), `A`, `V`, `E`]! {
|
||||
if rh.form_type != [u8(`W`), `A`, `V`, `E`]! {
|
||||
return error('WAV should have `WAVE` form type')
|
||||
}
|
||||
if rh.file_size + 8 != bytes.len {
|
||||
|
@ -145,15 +145,15 @@ fn read_wav_file_samples(fpath string) ?[]f32 {
|
|||
// eprintln('ch: $ch')
|
||||
// eprintln('p: $pbytes | offset: $offset | bytes.len: $bytes.len')
|
||||
// ////////
|
||||
if ch.chunk_type == [byte(`L`), `I`, `S`, `T`]! {
|
||||
if ch.chunk_type == [u8(`L`), `I`, `S`, `T`]! {
|
||||
continue
|
||||
}
|
||||
//
|
||||
if ch.chunk_type == [byte(`i`), `d`, `3`, ` `]! {
|
||||
if ch.chunk_type == [u8(`i`), `d`, `3`, ` `]! {
|
||||
continue
|
||||
}
|
||||
//
|
||||
if ch.chunk_type == [byte(`f`), `m`, `t`, ` `]! {
|
||||
if ch.chunk_type == [u8(`f`), `m`, `t`, ` `]! {
|
||||
// eprintln('`fmt ` chunk')
|
||||
rf = unsafe { &RIFFFormat(&ch.chunk_data) }
|
||||
// eprintln('fmt riff format: $rf')
|
||||
|
@ -169,20 +169,20 @@ fn read_wav_file_samples(fpath string) ?[]f32 {
|
|||
continue
|
||||
}
|
||||
//
|
||||
if ch.chunk_type == [byte(`d`), `a`, `t`, `a`]! {
|
||||
if ch.chunk_type == [u8(`d`), `a`, `t`, `a`]! {
|
||||
if rf == 0 {
|
||||
return error('`data` chunk should be after `fmt ` chunk')
|
||||
}
|
||||
// eprintln('`fmt ` chunk: $rf\n`data` chunk: $ch')
|
||||
mut doffset := 0
|
||||
mut dp := unsafe { &byte(&ch.chunk_data) }
|
||||
mut dp := unsafe { &u8(&ch.chunk_data) }
|
||||
for doffset < ch.chunk_size {
|
||||
for c := 0; c < rf.nchannels; c++ {
|
||||
mut x := f32(0.0)
|
||||
mut step := 0
|
||||
ppos := unsafe { dp + doffset }
|
||||
if rf.bits_per_sample == 8 {
|
||||
d8 := unsafe { &byte(ppos) }
|
||||
d8 := unsafe { &u8(ppos) }
|
||||
x = (f32(*d8) - 128) / 128.0
|
||||
step = 1
|
||||
doffset++
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
Module {
|
||||
name: 'submodule'
|
||||
description: ''
|
||||
version: ''
|
||||
license: ''
|
||||
dependencies: []
|
||||
}
|
|
@ -21,9 +21,9 @@ mut:
|
|||
|
||||
fn random_color() tui.Color {
|
||||
return tui.Color{
|
||||
r: rand.byte()
|
||||
g: rand.byte()
|
||||
b: rand.byte()
|
||||
r: rand.u8()
|
||||
g: rand.u8()
|
||||
b: rand.u8()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -126,7 +126,7 @@ fn create_texture(w int, h int, buf &u8) gfx.Image {
|
|||
// usage: .dynamic
|
||||
wrap_u: .clamp_to_edge
|
||||
wrap_v: .clamp_to_edge
|
||||
label: &byte(0)
|
||||
label: &u8(0)
|
||||
d3d11_texture: 0
|
||||
}
|
||||
// comment if .dynamic is enabled
|
||||
|
@ -144,7 +144,7 @@ fn destroy_texture(sg_img gfx.Image) {
|
|||
}
|
||||
|
||||
// Use only if: .dynamic is enabled
|
||||
fn update_text_texture(sg_img gfx.Image, w int, h int, buf &byte) {
|
||||
fn update_text_texture(sg_img gfx.Image, w int, h int, buf &u8) {
|
||||
sz := w * h * 4
|
||||
mut tmp_sbc := gfx.ImageData{}
|
||||
tmp_sbc.subimage[0][0] = gfx.Range{
|
||||
|
@ -215,9 +215,9 @@ fn (mut app App) read_bytes(path string) bool {
|
|||
return true
|
||||
}
|
||||
|
||||
// read a file as []byte
|
||||
pub fn read_bytes_from_file(file_path string) []byte {
|
||||
mut buffer := []byte{}
|
||||
// read a file as []u8
|
||||
pub fn read_bytes_from_file(file_path string) []u8 {
|
||||
mut buffer := []u8{}
|
||||
buffer = os.read_bytes(file_path) or {
|
||||
eprintln('ERROR: Texure file: [$file_path] NOT FOUND.')
|
||||
exit(0)
|
||||
|
@ -428,7 +428,7 @@ fn frame(mut app App) {
|
|||
|
||||
// println("$w,$h")
|
||||
// white multiplicator for now
|
||||
mut c := [byte(255), 255, 255]!
|
||||
mut c := [u8(255), 255, 255]!
|
||||
sgl.begin_quads()
|
||||
sgl.v2f_t2f_c3b(-w, -h, 0, 0, c[0], c[1], c[2])
|
||||
sgl.v2f_t2f_c3b(w, -h, 1, 0, c[0], c[1], c[2])
|
||||
|
@ -478,7 +478,7 @@ fn frame(mut app App) {
|
|||
bx += (bw_old - bw) / 2 - (tr_x / 8) / app.scale
|
||||
by += (bh_old - bh) / 2 - ((tr_y / 8) / app.scale) * ratio
|
||||
|
||||
c = [byte(255),255,0]! // yellow
|
||||
c = [u8(255),255,0]! // yellow
|
||||
sgl.begin_line_strip()
|
||||
sgl.v2f_c3b(bx , by , c[0], c[1], c[2])
|
||||
sgl.v2f_c3b(bx + bw, by , c[0], c[1], c[2])
|
||||
|
|
|
@ -13,7 +13,7 @@ fn main() {
|
|||
x := rand.read(blocksize)?
|
||||
for c in x {
|
||||
if c >= `0` && c <= `~` {
|
||||
sb.write_byte(c)
|
||||
sb.write_u8(c)
|
||||
}
|
||||
}
|
||||
if sb.len > size {
|
||||
|
|
19
make.bat
19
make.bat
|
@ -39,7 +39,7 @@ if !shift_counter! LSS 1 (
|
|||
if "%~1" == "help" (
|
||||
if not ["%~2"] == [""] set "subcmd=%~2"& shift& set /a shift_counter+=1
|
||||
)
|
||||
for %%z in (build clean cleanall help) do (
|
||||
for %%z in (build clean cleanall check help) do (
|
||||
if "%~1" == "%%z" set target=%1& shift& set /a shift_counter+=1& goto :verifyopt
|
||||
)
|
||||
)
|
||||
|
@ -67,6 +67,12 @@ exit /b 2
|
|||
:init
|
||||
goto :!target!
|
||||
|
||||
:check
|
||||
echo.
|
||||
echo Check everything
|
||||
v.exe test-all
|
||||
exit /b 0
|
||||
|
||||
:cleanall
|
||||
call :clean
|
||||
if %ERRORLEVEL% NEQ 0 exit /b %ERRORLEVEL%
|
||||
|
@ -119,7 +125,7 @@ REM By default, use tcc, since we have it prebuilt:
|
|||
:tcc_strap
|
||||
:tcc32_strap
|
||||
echo ^> Attempting to build v_win.c with "!tcc_exe!"
|
||||
"!tcc_exe!" -Bthirdparty/tcc -Ithirdparty/stdatomic/win -bt10 -g -w -o v.exe vc\v_win.c -ladvapi32
|
||||
"!tcc_exe!" -Bthirdparty/tcc -bt10 -g -w -o v.exe vc\v_win.c -ladvapi32
|
||||
if %ERRORLEVEL% NEQ 0 goto :compile_error
|
||||
echo ^> Compiling .\v.exe with itself
|
||||
v.exe -keepc -g -showcc -cc "!tcc_exe!" -cflags -Bthirdparty/tcc -o v2.exe cmd/v
|
||||
|
@ -137,7 +143,7 @@ if %ERRORLEVEL% NEQ 0 (
|
|||
)
|
||||
|
||||
echo ^> Attempting to build v_win.c with Clang
|
||||
clang -std=c99 -Ithirdparty/stdatomic/win -municode -g -w -o v.exe .\vc\v_win.c -ladvapi32
|
||||
clang -std=c99 -municode -g -w -o v.exe .\vc\v_win.c -ladvapi32
|
||||
if %ERRORLEVEL% NEQ 0 (
|
||||
echo In most cases, compile errors happen because the version of Clang installed is too old
|
||||
clang --version
|
||||
|
@ -160,7 +166,7 @@ if %ERRORLEVEL% NEQ 0 (
|
|||
)
|
||||
|
||||
echo ^> Attempting to build v_win.c with GCC
|
||||
gcc -std=c99 -municode -Ithirdparty/stdatomic/win -g -w -o v.exe .\vc\v_win.c -ladvapi32
|
||||
gcc -std=c99 -municode -g -w -o v.exe .\vc\v_win.c -ladvapi32
|
||||
if %ERRORLEVEL% NEQ 0 (
|
||||
echo In most cases, compile errors happen because the version of GCC installed is too old
|
||||
gcc --version
|
||||
|
@ -202,7 +208,7 @@ if exist "%InstallDir%\Common7\Tools\vsdevcmd.bat" (
|
|||
set ObjFile=.v.c.obj
|
||||
|
||||
echo ^> Attempting to build v_win.c with MSVC
|
||||
cl.exe /volatile:ms /I thirdparty\stdatomic\win /Fo%ObjFile% /O2 /MD /D_VBOOTSTRAP vc\v_win.c user32.lib kernel32.lib advapi32.lib shell32.lib /link /nologo /out:v.exe /incremental:no
|
||||
cl.exe /volatile:ms /Fo%ObjFile% /O2 /MD /D_VBOOTSTRAP vc\v_win.c user32.lib kernel32.lib advapi32.lib shell32.lib /link /nologo /out:v.exe /incremental:no
|
||||
if %ERRORLEVEL% NEQ 0 (
|
||||
echo In some cases, compile errors happen because of the MSVC compiler version
|
||||
cl.exe
|
||||
|
@ -262,7 +268,8 @@ echo Target:
|
|||
echo build[default] Compiles V using the given C compiler
|
||||
echo clean Clean build artifacts and debugging symbols
|
||||
echo cleanall Cleanup entire ALL build artifacts and vc repository
|
||||
echo help Display usage help for the given target
|
||||
echo check Check that tests pass, and the repository is in a good shape for Pull Requests
|
||||
echo help Display help for the given target
|
||||
echo.
|
||||
echo Examples:
|
||||
echo make.bat -msvc
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
The libbacktrace source is distributed here as an amalgamation (https://sqlite.org/amalgamation.html).
|
||||
This means that, rather than mirroring the entire libbacktrace repo here, most of the source code is
|
||||
packaged into one C file while other platform-specific code are into their respective C files which
|
||||
is much easier to handle.
|
|
@ -0,0 +1,111 @@
|
|||
/* Copyright (C) 2012-2021 Free Software Foundation, Inc.
|
||||
Written by Ian Lance Taylor, Google.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
(1) Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
(2) Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in
|
||||
the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
|
||||
(3) The name of the author may not be used to
|
||||
endorse or promote products derived from this software without
|
||||
specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
|
||||
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE. */
|
||||
|
||||
#define HAVE_ATOMIC_FUNCTIONS 1
|
||||
#define HAVE_CLOCK_GETTIME 1
|
||||
#define HAVE_DECL_GETPAGESIZE 0
|
||||
#define HAVE_DECL_STRNLEN 1
|
||||
#define HAVE_DL_ITERATE_PHDR 1
|
||||
#define HAVE_GETIPINFO 1
|
||||
#define HAVE_LSTAT 1
|
||||
#define HAVE_READLINK 1
|
||||
#define HAVE_SYNC_FUNCTIONS 1
|
||||
|
||||
#define HAVE_DLFCN_H 1
|
||||
#define HAVE_INTTYPES_H 1
|
||||
#define HAVE_LINK_H 1
|
||||
#define HAVE_MEMORY_H 1
|
||||
#define HAVE_STDINT_H 1
|
||||
#define HAVE_STDLIB_H 1
|
||||
#define HAVE_STRINGS_H 1
|
||||
#define HAVE_STRING_H 1
|
||||
#define HAVE_UNISTD_H 1
|
||||
#define STDC_HEADERS 1
|
||||
#include <stdint.h>
|
||||
#if UINTPTR_MAX == 0xFFFFFFFF
|
||||
#define BACKTRACE_ELF_SIZE 32
|
||||
#define BACKTRACE_XCOFF_SIZE 32
|
||||
#elif UINTPTR_MAX == 0xFFFFFFFFFFFFFFFFu
|
||||
#define BACKTRACE_ELF_SIZE 64
|
||||
#define BACKTRACE_XCOFF_SIZE 64
|
||||
#endif
|
||||
#ifdef __TINYC__
|
||||
#undef HAVE_ATOMIC_FUNCTIONS
|
||||
#undef HAVE_SYNC_FUNCTIONS
|
||||
#endif
|
||||
#ifndef _WIN32
|
||||
#define HAVE_FCNTL 1
|
||||
#endif
|
||||
#if defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__DragonFly__)
|
||||
#define HAVE_KERN_PROC 1
|
||||
#define HAVE_KERN_PROC_ARGS 1
|
||||
#endif
|
||||
#ifdef __APPLE__
|
||||
#define HAVE_MACH_O_DYLD_H 1
|
||||
#endif
|
||||
#ifndef _ALL_SOURCE
|
||||
#define _ALL_SOURCE 1
|
||||
#endif
|
||||
#ifndef _GNU_SOURCE
|
||||
#define _GNU_SOURCE 1
|
||||
#undef HAVE_DL_ITERATE_PHDR
|
||||
#endif
|
||||
#ifndef _POSIX_PTHREAD_SEMANTICS
|
||||
#define _POSIX_PTHREAD_SEMANTICS 1
|
||||
#endif
|
||||
#ifndef _TANDEM_SOURCE
|
||||
#define _TANDEM_SOURCE 1
|
||||
#endif
|
||||
#ifndef __EXTENSIONS__
|
||||
#define __EXTENSIONS__ 1
|
||||
#endif
|
||||
#ifndef _DARWIN_USE_64_BIT_INODE
|
||||
#define _DARWIN_USE_64_BIT_INODE 1
|
||||
#endif
|
||||
|
||||
#define BACKTRACE_SUPPORTED 1
|
||||
#define BACKTRACE_USES_MALLOC 1
|
||||
#define BACKTRACE_SUPPORTS_THREADS 1
|
||||
#define BACKTRACE_SUPPORTS_DATA 0
|
||||
|
||||
#if __TINYC__
|
||||
#undef BACKTRACE_SUPPORTED
|
||||
#endif
|
||||
|
||||
#include "base.c"
|
||||
|
||||
#if defined(__linux__) || defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__DragonFly__)
|
||||
#include "linux.c"
|
||||
#elif defined(__APPLE__)
|
||||
#include "darwin.c"
|
||||
#elif defined(_WIN32)
|
||||
#include "windows.c"
|
||||
#endif
|
|
@ -0,0 +1,189 @@
|
|||
/* backtrace.h -- Public header file for stack backtrace library.
|
||||
Copyright (C) 2012-2021 Free Software Foundation, Inc.
|
||||
Written by Ian Lance Taylor, Google.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
(1) Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
(2) Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in
|
||||
the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
|
||||
(3) The name of the author may not be used to
|
||||
endorse or promote products derived from this software without
|
||||
specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
|
||||
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE. */
|
||||
|
||||
#ifndef BACKTRACE_H
|
||||
#define BACKTRACE_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* The backtrace state. This struct is intentionally not defined in
|
||||
the public interface. */
|
||||
|
||||
struct backtrace_state;
|
||||
|
||||
/* The type of the error callback argument to backtrace functions.
|
||||
This function, if not NULL, will be called for certain error cases.
|
||||
The DATA argument is passed to the function that calls this one.
|
||||
The MSG argument is an error message. The ERRNUM argument, if
|
||||
greater than 0, holds an errno value. The MSG buffer may become
|
||||
invalid after this function returns.
|
||||
|
||||
As a special case, the ERRNUM argument will be passed as -1 if no
|
||||
debug info can be found for the executable, or if the debug info
|
||||
exists but has an unsupported version, but the function requires
|
||||
debug info (e.g., backtrace_full, backtrace_pcinfo). The MSG in
|
||||
this case will be something along the lines of "no debug info".
|
||||
Similarly, ERRNUM will be passed as -1 if there is no symbol table,
|
||||
but the function requires a symbol table (e.g., backtrace_syminfo).
|
||||
This may be used as a signal that some other approach should be
|
||||
tried. */
|
||||
|
||||
typedef void (*backtrace_error_callback) (void *data, const char *msg,
|
||||
int errnum);
|
||||
|
||||
/* Create state information for the backtrace routines. This must be
|
||||
called before any of the other routines, and its return value must
|
||||
be passed to all of the other routines. FILENAME is the path name
|
||||
of the executable file; if it is NULL the library will try
|
||||
system-specific path names. If not NULL, FILENAME must point to a
|
||||
permanent buffer. If THREADED is non-zero the state may be
|
||||
accessed by multiple threads simultaneously, and the library will
|
||||
use appropriate atomic operations. If THREADED is zero the state
|
||||
may only be accessed by one thread at a time. This returns a state
|
||||
pointer on success, NULL on error. If an error occurs, this will
|
||||
call the ERROR_CALLBACK routine.
|
||||
|
||||
Calling this function allocates resources that cannot be freed.
|
||||
There is no backtrace_free_state function. The state is used to
|
||||
cache information that is expensive to recompute. Programs are
|
||||
expected to call this function at most once and to save the return
|
||||
value for all later calls to backtrace functions. */
|
||||
|
||||
extern struct backtrace_state *backtrace_create_state (
|
||||
const char *filename, int threaded,
|
||||
backtrace_error_callback error_callback, void *data);
|
||||
|
||||
/* The type of the callback argument to the backtrace_full function.
|
||||
DATA is the argument passed to backtrace_full. PC is the program
|
||||
counter. FILENAME is the name of the file containing PC, or NULL
|
||||
if not available. LINENO is the line number in FILENAME containing
|
||||
PC, or 0 if not available. FUNCTION is the name of the function
|
||||
containing PC, or NULL if not available. This should return 0 to
|
||||
continuing tracing. The FILENAME and FUNCTION buffers may become
|
||||
invalid after this function returns. */
|
||||
|
||||
typedef int (*backtrace_full_callback) (void *data, uintptr_t pc,
|
||||
const char *filename, int lineno,
|
||||
const char *function);
|
||||
|
||||
/* Get a full stack backtrace. SKIP is the number of frames to skip;
|
||||
passing 0 will start the trace with the function calling
|
||||
backtrace_full. DATA is passed to the callback routine. If any
|
||||
call to CALLBACK returns a non-zero value, the stack backtrace
|
||||
stops, and backtrace returns that value; this may be used to limit
|
||||
the number of stack frames desired. If all calls to CALLBACK
|
||||
return 0, backtrace returns 0. The backtrace_full function will
|
||||
make at least one call to either CALLBACK or ERROR_CALLBACK. This
|
||||
function requires debug info for the executable. */
|
||||
|
||||
extern int backtrace_full (struct backtrace_state *state, int skip,
|
||||
backtrace_full_callback callback,
|
||||
backtrace_error_callback error_callback,
|
||||
void *data);
|
||||
|
||||
/* The type of the callback argument to the backtrace_simple function.
|
||||
DATA is the argument passed to simple_backtrace. PC is the program
|
||||
counter. This should return 0 to continue tracing. */
|
||||
|
||||
typedef int (*backtrace_simple_callback) (void *data, uintptr_t pc);
|
||||
|
||||
/* Get a simple backtrace. SKIP is the number of frames to skip, as
|
||||
in backtrace. DATA is passed to the callback routine. If any call
|
||||
to CALLBACK returns a non-zero value, the stack backtrace stops,
|
||||
and backtrace_simple returns that value. Otherwise
|
||||
backtrace_simple returns 0. The backtrace_simple function will
|
||||
make at least one call to either CALLBACK or ERROR_CALLBACK. This
|
||||
function does not require any debug info for the executable. */
|
||||
|
||||
extern int backtrace_simple (struct backtrace_state *state, int skip,
|
||||
backtrace_simple_callback callback,
|
||||
backtrace_error_callback error_callback,
|
||||
void *data);
|
||||
|
||||
/* Print the current backtrace in a user readable format to a FILE.
|
||||
SKIP is the number of frames to skip, as in backtrace_full. Any
|
||||
error messages are printed to stderr. This function requires debug
|
||||
info for the executable. */
|
||||
|
||||
extern void backtrace_print (struct backtrace_state *state, int skip, FILE *);
|
||||
|
||||
/* Given PC, a program counter in the current program, call the
|
||||
callback function with filename, line number, and function name
|
||||
information. This will normally call the callback function exactly
|
||||
once. However, if the PC happens to describe an inlined call, and
|
||||
the debugging information contains the necessary information, then
|
||||
this may call the callback function multiple times. This will make
|
||||
at least one call to either CALLBACK or ERROR_CALLBACK. This
|
||||
returns the first non-zero value returned by CALLBACK, or 0. */
|
||||
|
||||
extern int backtrace_pcinfo (struct backtrace_state *state, uintptr_t pc,
|
||||
backtrace_full_callback callback,
|
||||
backtrace_error_callback error_callback,
|
||||
void *data);
|
||||
|
||||
/* The type of the callback argument to backtrace_syminfo. DATA and
|
||||
PC are the arguments passed to backtrace_syminfo. SYMNAME is the
|
||||
name of the symbol for the corresponding code. SYMVAL is the
|
||||
value and SYMSIZE is the size of the symbol. SYMNAME will be NULL
|
||||
if no error occurred but the symbol could not be found. */
|
||||
|
||||
typedef void (*backtrace_syminfo_callback) (void *data, uintptr_t pc,
|
||||
const char *symname,
|
||||
uintptr_t symval,
|
||||
uintptr_t symsize);
|
||||
|
||||
/* Given ADDR, an address or program counter in the current program,
|
||||
call the callback information with the symbol name and value
|
||||
describing the function or variable in which ADDR may be found.
|
||||
This will call either CALLBACK or ERROR_CALLBACK exactly once.
|
||||
This returns 1 on success, 0 on failure. This function requires
|
||||
the symbol table but does not require the debug info. Note that if
|
||||
the symbol table is present but ADDR could not be found in the
|
||||
table, CALLBACK will be called with a NULL SYMNAME argument.
|
||||
Returns 1 on success, 0 on error. */
|
||||
|
||||
extern int backtrace_syminfo (struct backtrace_state *state, uintptr_t addr,
|
||||
backtrace_syminfo_callback callback,
|
||||
backtrace_error_callback error_callback,
|
||||
void *data);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* End extern "C". */
|
||||
#endif
|
||||
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,818 @@
|
|||
// pecoff.c:
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
typedef struct {
|
||||
uint16_t machine;
|
||||
uint16_t number_of_sections;
|
||||
uint32_t time_date_stamp;
|
||||
uint32_t pointer_to_symbol_table;
|
||||
uint32_t number_of_symbols;
|
||||
uint16_t size_of_optional_header;
|
||||
uint16_t characteristics;
|
||||
} b_coff_file_header;
|
||||
|
||||
typedef struct {
|
||||
uint16_t magic;
|
||||
uint8_t major_linker_version;
|
||||
uint8_t minor_linker_version;
|
||||
uint32_t size_of_code;
|
||||
uint32_t size_of_initialized_data;
|
||||
uint32_t size_of_uninitialized_data;
|
||||
uint32_t address_of_entry_point;
|
||||
uint32_t base_of_code;
|
||||
union {
|
||||
struct {
|
||||
uint32_t base_of_data;
|
||||
uint32_t image_base;
|
||||
} pe;
|
||||
struct {
|
||||
uint64_t image_base;
|
||||
} pep;
|
||||
} u;
|
||||
} b_coff_optional_header;
|
||||
|
||||
#define PE_MAGIC 0x10b
|
||||
#define PEP_MAGIC 0x20b
|
||||
|
||||
typedef struct {
|
||||
char name[8];
|
||||
uint32_t virtual_size;
|
||||
uint32_t virtual_address;
|
||||
uint32_t size_of_raw_data;
|
||||
uint32_t pointer_to_raw_data;
|
||||
uint32_t pointer_to_relocations;
|
||||
uint32_t pointer_to_line_numbers;
|
||||
uint16_t number_of_relocations;
|
||||
uint16_t number_of_line_numbers;
|
||||
uint32_t characteristics;
|
||||
} b_coff_section_header;
|
||||
|
||||
typedef union {
|
||||
char short_name[8];
|
||||
struct {
|
||||
unsigned char zeroes[4];
|
||||
unsigned char off[4];
|
||||
} long_name;
|
||||
} b_coff_name;
|
||||
|
||||
typedef struct {
|
||||
b_coff_name name;
|
||||
unsigned char value[4];
|
||||
unsigned char section_number[2];
|
||||
unsigned char type[2];
|
||||
unsigned char storage_class;
|
||||
unsigned char number_of_aux_symbols;
|
||||
} b_coff_external_symbol;
|
||||
|
||||
#define N_TBSHFT 4
|
||||
#define IMAGE_SYM_DTYPE_FUNCTION 2
|
||||
|
||||
#define SYM_SZ 18
|
||||
|
||||
typedef struct {
|
||||
const char *name;
|
||||
uint32_t value;
|
||||
int16_t sec;
|
||||
uint16_t type;
|
||||
uint16_t sc;
|
||||
} b_coff_internal_symbol;
|
||||
|
||||
static const char *const debug_section_names[DEBUG_MAX] = {
|
||||
".debug_info", ".debug_line", ".debug_abbrev",
|
||||
".debug_ranges", ".debug_str", ".debug_addr",
|
||||
".debug_str_offsets", ".debug_line_str", ".debug_rnglists"};
|
||||
|
||||
struct debug_section_info {
|
||||
off_t offset;
|
||||
|
||||
size_t size;
|
||||
};
|
||||
|
||||
struct coff_symbol {
|
||||
const char *name;
|
||||
|
||||
uintptr_t address;
|
||||
};
|
||||
|
||||
struct coff_syminfo_data {
|
||||
struct coff_syminfo_data *next;
|
||||
|
||||
struct coff_symbol *symbols;
|
||||
|
||||
size_t count;
|
||||
};
|
||||
|
||||
static int coff_nodebug(struct backtrace_state *state ATTRIBUTE_UNUSED,
|
||||
uintptr_t pc ATTRIBUTE_UNUSED,
|
||||
backtrace_full_callback callback ATTRIBUTE_UNUSED,
|
||||
backtrace_error_callback error_callback, void *data) {
|
||||
error_callback(data, "no debug info in PE/COFF executable", -1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void coff_nosyms(struct backtrace_state *state ATTRIBUTE_UNUSED,
|
||||
uintptr_t addr ATTRIBUTE_UNUSED,
|
||||
backtrace_syminfo_callback callback ATTRIBUTE_UNUSED,
|
||||
backtrace_error_callback error_callback, void *data) {
|
||||
error_callback(data, "no symbol table in PE/COFF executable", -1);
|
||||
}
|
||||
|
||||
static uint32_t coff_read4(const unsigned char *p) {
|
||||
uint32_t res;
|
||||
|
||||
memcpy(&res, p, 4);
|
||||
return res;
|
||||
}
|
||||
|
||||
static uint16_t coff_read2(const unsigned char *p) {
|
||||
uint16_t res;
|
||||
|
||||
memcpy(&res, p, sizeof(res));
|
||||
return res;
|
||||
}
|
||||
|
||||
static size_t coff_short_name_len(const char *name) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 8; i++)
|
||||
if (name[i] == 0) return i;
|
||||
return 8;
|
||||
}
|
||||
|
||||
static int coff_short_name_eq(const char *name, const char *cname) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 8; i++) {
|
||||
if (name[i] != cname[i]) return 0;
|
||||
if (name[i] == 0) return 1;
|
||||
}
|
||||
return name[8] == 0;
|
||||
}
|
||||
|
||||
static int coff_long_name_eq(const char *name, unsigned int off,
|
||||
struct backtrace_view *str_view) {
|
||||
if (off >= str_view->len) return 0;
|
||||
return strcmp(name, (const char *)str_view->data + off) == 0;
|
||||
}
|
||||
|
||||
static int coff_symbol_compare(const void *v1, const void *v2) {
|
||||
const struct coff_symbol *e1 = (const struct coff_symbol *)v1;
|
||||
const struct coff_symbol *e2 = (const struct coff_symbol *)v2;
|
||||
|
||||
if (e1->address < e2->address)
|
||||
return -1;
|
||||
else if (e1->address > e2->address)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int coff_expand_symbol(b_coff_internal_symbol *isym,
|
||||
const b_coff_external_symbol *sym,
|
||||
uint16_t sects_num, const unsigned char *strtab,
|
||||
size_t strtab_size) {
|
||||
isym->type = coff_read2(sym->type);
|
||||
isym->sec = coff_read2(sym->section_number);
|
||||
isym->sc = sym->storage_class;
|
||||
|
||||
if (isym->sec > 0 && (uint16_t)isym->sec > sects_num) return -1;
|
||||
if (sym->name.short_name[0] != 0)
|
||||
isym->name = sym->name.short_name;
|
||||
else {
|
||||
uint32_t off = coff_read4(sym->name.long_name.off);
|
||||
|
||||
if (off >= strtab_size) return -1;
|
||||
isym->name = (const char *)strtab + off;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int coff_is_function_symbol(const b_coff_internal_symbol *isym) {
|
||||
return (isym->type >> N_TBSHFT) == IMAGE_SYM_DTYPE_FUNCTION && isym->sec > 0;
|
||||
}
|
||||
|
||||
static int coff_initialize_syminfo(
|
||||
struct backtrace_state *state, uintptr_t base_address, int is_64,
|
||||
const b_coff_section_header *sects, size_t sects_num,
|
||||
const b_coff_external_symbol *syms, size_t syms_size,
|
||||
const unsigned char *strtab, size_t strtab_size,
|
||||
backtrace_error_callback error_callback, void *data,
|
||||
struct coff_syminfo_data *sdata) {
|
||||
size_t syms_count;
|
||||
char *coff_symstr;
|
||||
size_t coff_symstr_len;
|
||||
size_t coff_symbol_count;
|
||||
size_t coff_symbol_size;
|
||||
struct coff_symbol *coff_symbols;
|
||||
struct coff_symbol *coff_sym;
|
||||
char *coff_str;
|
||||
size_t i;
|
||||
|
||||
syms_count = syms_size / SYM_SZ;
|
||||
|
||||
coff_symbol_count = 0;
|
||||
coff_symstr_len = 0;
|
||||
for (i = 0; i < syms_count; ++i) {
|
||||
const b_coff_external_symbol *asym = &syms[i];
|
||||
b_coff_internal_symbol isym;
|
||||
|
||||
if (coff_expand_symbol(&isym, asym, sects_num, strtab, strtab_size) < 0) {
|
||||
error_callback(data, "invalid section or offset in coff symbol", 0);
|
||||
return 0;
|
||||
}
|
||||
if (coff_is_function_symbol(&isym)) {
|
||||
++coff_symbol_count;
|
||||
if (asym->name.short_name[0] != 0)
|
||||
coff_symstr_len += coff_short_name_len(asym->name.short_name) + 1;
|
||||
}
|
||||
|
||||
i += asym->number_of_aux_symbols;
|
||||
}
|
||||
|
||||
coff_symbol_size = (coff_symbol_count + 1) * sizeof(struct coff_symbol);
|
||||
coff_symbols = ((struct coff_symbol *)backtrace_alloc(state, coff_symbol_size,
|
||||
error_callback, data));
|
||||
if (coff_symbols == NULL) return 0;
|
||||
|
||||
if (coff_symstr_len > 0) {
|
||||
coff_symstr =
|
||||
((char *)backtrace_alloc(state, coff_symstr_len, error_callback, data));
|
||||
if (coff_symstr == NULL) {
|
||||
backtrace_free(state, coff_symbols, coff_symbol_size, error_callback,
|
||||
data);
|
||||
return 0;
|
||||
}
|
||||
} else
|
||||
coff_symstr = NULL;
|
||||
|
||||
coff_sym = coff_symbols;
|
||||
coff_str = coff_symstr;
|
||||
for (i = 0; i < syms_count; ++i) {
|
||||
const b_coff_external_symbol *asym = &syms[i];
|
||||
b_coff_internal_symbol isym;
|
||||
|
||||
if (coff_expand_symbol(&isym, asym, sects_num, strtab, strtab_size)) {
|
||||
abort();
|
||||
}
|
||||
if (coff_is_function_symbol(&isym)) {
|
||||
const char *name;
|
||||
int16_t secnum;
|
||||
|
||||
if (asym->name.short_name[0] != 0) {
|
||||
size_t len = coff_short_name_len(isym.name);
|
||||
name = coff_str;
|
||||
memcpy(coff_str, isym.name, len);
|
||||
coff_str[len] = 0;
|
||||
coff_str += len + 1;
|
||||
} else
|
||||
name = isym.name;
|
||||
|
||||
if (!is_64) {
|
||||
if (name[0] == '_') name++;
|
||||
}
|
||||
|
||||
secnum = coff_read2(asym->section_number);
|
||||
|
||||
coff_sym->name = name;
|
||||
coff_sym->address = (coff_read4(asym->value) +
|
||||
sects[secnum - 1].virtual_address + base_address);
|
||||
coff_sym++;
|
||||
}
|
||||
|
||||
i += asym->number_of_aux_symbols;
|
||||
}
|
||||
|
||||
coff_sym->name = NULL;
|
||||
coff_sym->address = -1;
|
||||
|
||||
backtrace_qsort(coff_symbols, coff_symbol_count, sizeof(struct coff_symbol),
|
||||
coff_symbol_compare);
|
||||
|
||||
sdata->next = NULL;
|
||||
sdata->symbols = coff_symbols;
|
||||
sdata->count = coff_symbol_count;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void coff_add_syminfo_data(struct backtrace_state *state,
|
||||
struct coff_syminfo_data *sdata) {
|
||||
if (!state->threaded) {
|
||||
struct coff_syminfo_data **pp;
|
||||
|
||||
for (pp = (struct coff_syminfo_data **)(void *)&state->syminfo_data;
|
||||
*pp != NULL; pp = &(*pp)->next)
|
||||
;
|
||||
*pp = sdata;
|
||||
} else {
|
||||
while (1) {
|
||||
struct coff_syminfo_data **pp;
|
||||
|
||||
pp = (struct coff_syminfo_data **)(void *)&state->syminfo_data;
|
||||
|
||||
while (1) {
|
||||
struct coff_syminfo_data *p;
|
||||
|
||||
p = backtrace_atomic_load_pointer(pp);
|
||||
|
||||
if (p == NULL) break;
|
||||
|
||||
pp = &p->next;
|
||||
}
|
||||
|
||||
if (__sync_bool_compare_and_swap(pp, NULL, sdata)) break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int coff_symbol_search(const void *vkey, const void *ventry) {
|
||||
const uintptr_t *key = (const uintptr_t *)vkey;
|
||||
const struct coff_symbol *entry = (const struct coff_symbol *)ventry;
|
||||
uintptr_t addr;
|
||||
|
||||
addr = *key;
|
||||
if (addr < entry->address)
|
||||
return -1;
|
||||
else if (addr >= entry[1].address)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void coff_syminfo(
|
||||
struct backtrace_state *state, uintptr_t addr,
|
||||
backtrace_syminfo_callback callback,
|
||||
backtrace_error_callback error_callback ATTRIBUTE_UNUSED, void *data) {
|
||||
struct coff_syminfo_data *sdata;
|
||||
struct coff_symbol *sym = NULL;
|
||||
|
||||
if (!state->threaded) {
|
||||
for (sdata = (struct coff_syminfo_data *)state->syminfo_data; sdata != NULL;
|
||||
sdata = sdata->next) {
|
||||
sym = ((struct coff_symbol *)bsearch(&addr, sdata->symbols, sdata->count,
|
||||
sizeof(struct coff_symbol),
|
||||
coff_symbol_search));
|
||||
if (sym != NULL) break;
|
||||
}
|
||||
} else {
|
||||
struct coff_syminfo_data **pp;
|
||||
|
||||
pp = (struct coff_syminfo_data **)(void *)&state->syminfo_data;
|
||||
while (1) {
|
||||
sdata = backtrace_atomic_load_pointer(pp);
|
||||
if (sdata == NULL) break;
|
||||
|
||||
sym = ((struct coff_symbol *)bsearch(&addr, sdata->symbols, sdata->count,
|
||||
sizeof(struct coff_symbol),
|
||||
coff_symbol_search));
|
||||
if (sym != NULL) break;
|
||||
|
||||
pp = &sdata->next;
|
||||
}
|
||||
}
|
||||
|
||||
if (sym == NULL)
|
||||
callback(data, addr, NULL, 0, 0);
|
||||
else
|
||||
callback(data, addr, sym->name, sym->address, 0);
|
||||
}
|
||||
|
||||
static int coff_add(struct backtrace_state *state, int descriptor,
|
||||
backtrace_error_callback error_callback, void *data,
|
||||
fileline *fileline_fn, int *found_sym, int *found_dwarf) {
|
||||
struct backtrace_view fhdr_view;
|
||||
off_t fhdr_off;
|
||||
int magic_ok;
|
||||
b_coff_file_header fhdr;
|
||||
off_t opt_sects_off;
|
||||
size_t opt_sects_size;
|
||||
unsigned int sects_num;
|
||||
struct backtrace_view sects_view;
|
||||
int sects_view_valid;
|
||||
const b_coff_optional_header *opt_hdr;
|
||||
const b_coff_section_header *sects;
|
||||
struct backtrace_view str_view;
|
||||
int str_view_valid;
|
||||
size_t str_size;
|
||||
off_t str_off;
|
||||
struct backtrace_view syms_view;
|
||||
off_t syms_off;
|
||||
size_t syms_size;
|
||||
int syms_view_valid;
|
||||
unsigned int syms_num;
|
||||
unsigned int i;
|
||||
struct debug_section_info sections[DEBUG_MAX];
|
||||
off_t min_offset;
|
||||
off_t max_offset;
|
||||
struct backtrace_view debug_view;
|
||||
int debug_view_valid;
|
||||
int is_64;
|
||||
uintptr_t image_base;
|
||||
struct dwarf_sections dwarf_sections;
|
||||
|
||||
*found_sym = 0;
|
||||
*found_dwarf = 0;
|
||||
|
||||
sects_view_valid = 0;
|
||||
syms_view_valid = 0;
|
||||
str_view_valid = 0;
|
||||
debug_view_valid = 0;
|
||||
|
||||
if (!backtrace_get_view(state, descriptor, 0, 0x40, error_callback, data,
|
||||
&fhdr_view))
|
||||
goto fail;
|
||||
|
||||
{
|
||||
const unsigned char *vptr = fhdr_view.data;
|
||||
|
||||
if (vptr[0] == 'M' && vptr[1] == 'Z')
|
||||
fhdr_off = coff_read4(vptr + 0x3c);
|
||||
else
|
||||
fhdr_off = 0;
|
||||
}
|
||||
|
||||
backtrace_release_view(state, &fhdr_view, error_callback, data);
|
||||
|
||||
if (!backtrace_get_view(state, descriptor, fhdr_off,
|
||||
sizeof(b_coff_file_header) + 4, error_callback, data,
|
||||
&fhdr_view))
|
||||
goto fail;
|
||||
|
||||
if (fhdr_off != 0) {
|
||||
const char *magic = (const char *)fhdr_view.data;
|
||||
magic_ok = memcmp(magic, "PE\0", 4) == 0;
|
||||
fhdr_off += 4;
|
||||
|
||||
memcpy(&fhdr, fhdr_view.data + 4, sizeof fhdr);
|
||||
} else {
|
||||
memcpy(&fhdr, fhdr_view.data, sizeof fhdr);
|
||||
|
||||
magic_ok = 0;
|
||||
}
|
||||
backtrace_release_view(state, &fhdr_view, error_callback, data);
|
||||
|
||||
if (!magic_ok) {
|
||||
error_callback(data, "executable file is not COFF", 0);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
sects_num = fhdr.number_of_sections;
|
||||
syms_num = fhdr.number_of_symbols;
|
||||
|
||||
opt_sects_off = fhdr_off + sizeof(fhdr);
|
||||
opt_sects_size = (fhdr.size_of_optional_header +
|
||||
sects_num * sizeof(b_coff_section_header));
|
||||
|
||||
if (!backtrace_get_view(state, descriptor, opt_sects_off, opt_sects_size,
|
||||
error_callback, data, §s_view))
|
||||
goto fail;
|
||||
sects_view_valid = 1;
|
||||
opt_hdr = (const b_coff_optional_header *)sects_view.data;
|
||||
sects = (const b_coff_section_header *)(sects_view.data +
|
||||
fhdr.size_of_optional_header);
|
||||
|
||||
is_64 = 0;
|
||||
if (fhdr.size_of_optional_header > sizeof(*opt_hdr)) {
|
||||
if (opt_hdr->magic == PE_MAGIC)
|
||||
image_base = opt_hdr->u.pe.image_base;
|
||||
else if (opt_hdr->magic == PEP_MAGIC) {
|
||||
image_base = opt_hdr->u.pep.image_base;
|
||||
is_64 = 1;
|
||||
} else {
|
||||
error_callback(data, "bad magic in PE optional header", 0);
|
||||
goto fail;
|
||||
}
|
||||
} else
|
||||
image_base = 0;
|
||||
|
||||
if (fhdr.pointer_to_symbol_table == 0) {
|
||||
str_off = 0;
|
||||
str_size = 0;
|
||||
syms_num = 0;
|
||||
syms_size = 0;
|
||||
} else {
|
||||
syms_off = fhdr.pointer_to_symbol_table;
|
||||
syms_size = syms_num * SYM_SZ;
|
||||
|
||||
if (!backtrace_get_view(state, descriptor, syms_off, syms_size + 4,
|
||||
error_callback, data, &syms_view))
|
||||
goto fail;
|
||||
syms_view_valid = 1;
|
||||
|
||||
str_size = coff_read4(syms_view.data + syms_size);
|
||||
|
||||
str_off = syms_off + syms_size;
|
||||
|
||||
if (str_size > 4) {
|
||||
if (!backtrace_get_view(state, descriptor, str_off, str_size,
|
||||
error_callback, data, &str_view))
|
||||
goto fail;
|
||||
str_view_valid = 1;
|
||||
}
|
||||
}
|
||||
|
||||
memset(sections, 0, sizeof sections);
|
||||
|
||||
for (i = 0; i < sects_num; ++i) {
|
||||
const b_coff_section_header *s = sects + i;
|
||||
unsigned int str_off;
|
||||
int j;
|
||||
|
||||
if (s->name[0] == '/') {
|
||||
str_off = atoi(s->name + 1);
|
||||
} else
|
||||
str_off = 0;
|
||||
|
||||
for (j = 0; j < (int)DEBUG_MAX; ++j) {
|
||||
const char *dbg_name = debug_section_names[j];
|
||||
int match;
|
||||
|
||||
if (str_off != 0)
|
||||
match = coff_long_name_eq(dbg_name, str_off, &str_view);
|
||||
else
|
||||
match = coff_short_name_eq(dbg_name, s->name);
|
||||
if (match) {
|
||||
sections[j].offset = s->pointer_to_raw_data;
|
||||
sections[j].size = s->virtual_size <= s->size_of_raw_data
|
||||
? s->virtual_size
|
||||
: s->size_of_raw_data;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (syms_num != 0) {
|
||||
struct coff_syminfo_data *sdata;
|
||||
|
||||
sdata = ((struct coff_syminfo_data *)backtrace_alloc(state, sizeof *sdata,
|
||||
error_callback, data));
|
||||
if (sdata == NULL) goto fail;
|
||||
|
||||
if (!coff_initialize_syminfo(state, image_base, is_64, sects, sects_num,
|
||||
syms_view.data, syms_size, str_view.data,
|
||||
str_size, error_callback, data, sdata)) {
|
||||
backtrace_free(state, sdata, sizeof *sdata, error_callback, data);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
*found_sym = 1;
|
||||
|
||||
coff_add_syminfo_data(state, sdata);
|
||||
}
|
||||
|
||||
backtrace_release_view(state, §s_view, error_callback, data);
|
||||
sects_view_valid = 0;
|
||||
if (syms_view_valid) {
|
||||
backtrace_release_view(state, &syms_view, error_callback, data);
|
||||
syms_view_valid = 0;
|
||||
}
|
||||
|
||||
min_offset = 0;
|
||||
max_offset = 0;
|
||||
for (i = 0; i < (int)DEBUG_MAX; ++i) {
|
||||
off_t end;
|
||||
|
||||
if (sections[i].size == 0) continue;
|
||||
if (min_offset == 0 || sections[i].offset < min_offset)
|
||||
min_offset = sections[i].offset;
|
||||
end = sections[i].offset + sections[i].size;
|
||||
if (end > max_offset) max_offset = end;
|
||||
}
|
||||
if (min_offset == 0 || max_offset == 0) {
|
||||
if (!backtrace_close(descriptor, error_callback, data)) goto fail;
|
||||
*fileline_fn = coff_nodebug;
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!backtrace_get_view(state, descriptor, min_offset,
|
||||
max_offset - min_offset, error_callback, data,
|
||||
&debug_view))
|
||||
goto fail;
|
||||
debug_view_valid = 1;
|
||||
|
||||
if (!backtrace_close(descriptor, error_callback, data)) goto fail;
|
||||
descriptor = -1;
|
||||
|
||||
for (i = 0; i < (int)DEBUG_MAX; ++i) {
|
||||
size_t size = sections[i].size;
|
||||
dwarf_sections.size[i] = size;
|
||||
if (size == 0)
|
||||
dwarf_sections.data[i] = NULL;
|
||||
else
|
||||
dwarf_sections.data[i] = ((const unsigned char *)debug_view.data +
|
||||
(sections[i].offset - min_offset));
|
||||
}
|
||||
|
||||
if (!backtrace_dwarf_add(state, 0, &dwarf_sections, 0, NULL, error_callback,
|
||||
data, fileline_fn, NULL))
|
||||
goto fail;
|
||||
|
||||
*found_dwarf = 1;
|
||||
|
||||
return 1;
|
||||
|
||||
fail:
|
||||
if (sects_view_valid)
|
||||
backtrace_release_view(state, §s_view, error_callback, data);
|
||||
if (str_view_valid)
|
||||
backtrace_release_view(state, &str_view, error_callback, data);
|
||||
if (syms_view_valid)
|
||||
backtrace_release_view(state, &syms_view, error_callback, data);
|
||||
if (debug_view_valid)
|
||||
backtrace_release_view(state, &debug_view, error_callback, data);
|
||||
if (descriptor != -1) backtrace_close(descriptor, error_callback, data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int backtrace_initialize(struct backtrace_state *state,
|
||||
const char *filename ATTRIBUTE_UNUSED, int descriptor,
|
||||
backtrace_error_callback error_callback, void *data,
|
||||
fileline *fileline_fn) {
|
||||
int ret;
|
||||
int found_sym;
|
||||
int found_dwarf;
|
||||
fileline coff_fileline_fn;
|
||||
|
||||
ret = coff_add(state, descriptor, error_callback, data, &coff_fileline_fn,
|
||||
&found_sym, &found_dwarf);
|
||||
if (!ret) return 0;
|
||||
|
||||
if (!state->threaded) {
|
||||
if (found_sym)
|
||||
state->syminfo_fn = coff_syminfo;
|
||||
else if (state->syminfo_fn == NULL)
|
||||
state->syminfo_fn = coff_nosyms;
|
||||
} else {
|
||||
if (found_sym)
|
||||
backtrace_atomic_store_pointer(&state->syminfo_fn, coff_syminfo);
|
||||
else
|
||||
(void)__sync_bool_compare_and_swap(&state->syminfo_fn, NULL, coff_nosyms);
|
||||
}
|
||||
|
||||
if (!state->threaded) {
|
||||
if (state->fileline_fn == NULL || state->fileline_fn == coff_nodebug)
|
||||
*fileline_fn = coff_fileline_fn;
|
||||
} else {
|
||||
fileline current_fn;
|
||||
|
||||
current_fn = backtrace_atomic_load_pointer(&state->fileline_fn);
|
||||
if (current_fn == NULL || current_fn == coff_nodebug)
|
||||
*fileline_fn = coff_fileline_fn;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
// read.c:
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
int backtrace_get_view(struct backtrace_state *state, int descriptor,
|
||||
off_t offset, uint64_t size,
|
||||
backtrace_error_callback error_callback, void *data,
|
||||
struct backtrace_view *view) {
|
||||
uint64_t got;
|
||||
ssize_t r;
|
||||
|
||||
if ((uint64_t)(size_t)size != size) {
|
||||
error_callback(data, "file size too large", 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (lseek(descriptor, offset, SEEK_SET) < 0) {
|
||||
error_callback(data, "lseek", errno);
|
||||
return 0;
|
||||
}
|
||||
|
||||
view->base = backtrace_alloc(state, size, error_callback, data);
|
||||
if (view->base == NULL) return 0;
|
||||
view->data = view->base;
|
||||
view->len = size;
|
||||
|
||||
got = 0;
|
||||
while (got < size) {
|
||||
r = read(descriptor, view->base, size - got);
|
||||
if (r < 0) {
|
||||
error_callback(data, "read", errno);
|
||||
free(view->base);
|
||||
return 0;
|
||||
}
|
||||
if (r == 0) break;
|
||||
got += (uint64_t)r;
|
||||
}
|
||||
|
||||
if (got < size) {
|
||||
error_callback(data, "file too short", 0);
|
||||
free(view->base);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void backtrace_release_view(struct backtrace_state *state,
|
||||
struct backtrace_view *view,
|
||||
backtrace_error_callback error_callback,
|
||||
void *data) {
|
||||
backtrace_free(state, view->base, view->len, error_callback, data);
|
||||
view->data = NULL;
|
||||
view->base = NULL;
|
||||
}
|
||||
|
||||
// alloc.c:
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
void *backtrace_alloc(struct backtrace_state *state ATTRIBUTE_UNUSED,
|
||||
size_t size, backtrace_error_callback error_callback,
|
||||
void *data) {
|
||||
void *ret;
|
||||
|
||||
ret = malloc(size);
|
||||
if (ret == NULL) {
|
||||
if (error_callback) error_callback(data, "malloc", errno);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void backtrace_free(struct backtrace_state *state ATTRIBUTE_UNUSED, void *p,
|
||||
size_t size ATTRIBUTE_UNUSED,
|
||||
backtrace_error_callback error_callback ATTRIBUTE_UNUSED,
|
||||
void *data ATTRIBUTE_UNUSED) {
|
||||
free(p);
|
||||
}
|
||||
|
||||
void *backtrace_vector_grow(struct backtrace_state *state ATTRIBUTE_UNUSED,
|
||||
size_t size,
|
||||
backtrace_error_callback error_callback, void *data,
|
||||
struct backtrace_vector *vec) {
|
||||
void *ret;
|
||||
|
||||
if (size > vec->alc) {
|
||||
size_t alc;
|
||||
void *base;
|
||||
|
||||
if (vec->size == 0)
|
||||
alc = 32 * size;
|
||||
else if (vec->size >= 4096)
|
||||
alc = vec->size + 4096;
|
||||
else
|
||||
alc = 2 * vec->size;
|
||||
|
||||
if (alc < vec->size + size) alc = vec->size + size;
|
||||
|
||||
base = realloc(vec->base, alc);
|
||||
if (base == NULL) {
|
||||
error_callback(data, "realloc", errno);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
vec->base = base;
|
||||
vec->alc = alc - vec->size;
|
||||
}
|
||||
|
||||
ret = (char *)vec->base + vec->size;
|
||||
vec->size += size;
|
||||
vec->alc -= size;
|
||||
return ret;
|
||||
}
|
||||
|
||||
void *backtrace_vector_finish(struct backtrace_state *state,
|
||||
struct backtrace_vector *vec,
|
||||
backtrace_error_callback error_callback,
|
||||
void *data) {
|
||||
void *ret;
|
||||
|
||||
if (!backtrace_vector_release(state, vec, error_callback, data)) return NULL;
|
||||
ret = vec->base;
|
||||
vec->base = NULL;
|
||||
vec->size = 0;
|
||||
vec->alc = 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
int backtrace_vector_release(struct backtrace_state *state ATTRIBUTE_UNUSED,
|
||||
struct backtrace_vector *vec,
|
||||
backtrace_error_callback error_callback,
|
||||
void *data) {
|
||||
vec->alc = 0;
|
||||
|
||||
if (vec->size == 0) {
|
||||
free(vec->base);
|
||||
vec->base = NULL;
|
||||
return 1;
|
||||
}
|
||||
|
||||
vec->base = realloc(vec->base, vec->size);
|
||||
if (vec->base == NULL) {
|
||||
error_callback(data, "realloc", errno);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,2 @@
|
|||
/* This file is installed for backward compatibility. */
|
||||
#include <gc/gc.h>
|
|
@ -0,0 +1,377 @@
|
|||
/*
|
||||
* Copyright (c) 1993-1994 by Xerox Corporation. All rights reserved.
|
||||
*
|
||||
* THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
|
||||
* OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
|
||||
*
|
||||
* Permission is hereby granted to use or copy this program
|
||||
* for any purpose, provided the above notices are retained on all copies.
|
||||
* Permission to modify the code and to distribute modified code is granted,
|
||||
* provided the above notices are retained, and a notice that the code was
|
||||
* modified is included with the above copyright notice.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Cords are immutable character strings. A number of operations
|
||||
* on long cords are much more efficient than their strings.h counterpart.
|
||||
* In particular, concatenation takes constant time independent of the length
|
||||
* of the arguments. (Cords are represented as trees, with internal
|
||||
* nodes representing concatenation and leaves consisting of either C
|
||||
* strings or a functional description of the string.)
|
||||
*
|
||||
* The following are reasonable applications of cords. They would perform
|
||||
* unacceptably if C strings were used:
|
||||
* - A compiler that produces assembly language output by repeatedly
|
||||
* concatenating instructions onto a cord representing the output file.
|
||||
* - A text editor that converts the input file to a cord, and then
|
||||
* performs editing operations by producing a new cord representing
|
||||
* the file after each character change (and keeping the old ones in an
|
||||
* edit history)
|
||||
*
|
||||
* For optimal performance, cords should be built by
|
||||
* concatenating short sections.
|
||||
* This interface is designed for maximum compatibility with C strings.
|
||||
* ASCII NUL characters may be embedded in cords using CORD_from_fn.
|
||||
* This is handled correctly, but CORD_to_char_star will produce a string
|
||||
* with embedded NULs when given such a cord.
|
||||
*
|
||||
* This interface is fairly big, largely for performance reasons.
|
||||
* The most basic constants and functions:
|
||||
*
|
||||
* CORD - the type of a cord;
|
||||
* CORD_EMPTY - empty cord;
|
||||
* CORD_len(cord) - length of a cord;
|
||||
* CORD_cat(cord1,cord2) - concatenation of two cords;
|
||||
* CORD_substr(cord, start, len) - substring (or subcord);
|
||||
* CORD_pos i; CORD_FOR(i, cord) { ... CORD_pos_fetch(i) ... } -
|
||||
* examine each character in a cord. CORD_pos_fetch(i) is the char.
|
||||
* CORD_fetch(int i) - Retrieve i'th character (slowly).
|
||||
* CORD_cmp(cord1, cord2) - compare two cords.
|
||||
* CORD_from_file(FILE * f) - turn a read-only file into a cord.
|
||||
* CORD_to_char_star(cord) - convert to C string.
|
||||
* (Non-NULL C constant strings are cords.)
|
||||
* CORD_printf (etc.) - cord version of printf. Use %r for cords.
|
||||
*/
|
||||
#ifndef CORD_H
|
||||
#define CORD_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#if defined(GC_DLL) && !defined(CORD_NOT_DLL)
|
||||
/* Same as for GC_API in gc_config_macros.h. */
|
||||
# ifdef CORD_BUILD
|
||||
# if defined(__MINGW32__) || defined(__CEGCC__)
|
||||
# define CORD_API __declspec(dllexport)
|
||||
# elif defined(_MSC_VER) || defined(__DMC__) || defined(__BORLANDC__) \
|
||||
|| defined(__CYGWIN__) || defined(__WATCOMC__)
|
||||
# define CORD_API extern __declspec(dllexport)
|
||||
# elif defined(__GNUC__) && !defined(GC_NO_VISIBILITY) \
|
||||
&& (__GNUC__ >= 4 || defined(GC_VISIBILITY_HIDDEN_SET))
|
||||
/* Only matters if used in conjunction with -fvisibility=hidden option. */
|
||||
# define CORD_API extern __attribute__((__visibility__("default")))
|
||||
# endif
|
||||
# else
|
||||
# if defined(__MINGW32__) || defined(__CEGCC__) || defined(_MSC_VER) \
|
||||
|| defined(__DMC__) || defined(__BORLANDC__) || defined(__CYGWIN__)
|
||||
# define CORD_API __declspec(dllimport)
|
||||
# elif defined(__WATCOMC__)
|
||||
# define CORD_API extern __declspec(dllimport)
|
||||
# endif
|
||||
# endif /* !CORD_BUILD */
|
||||
#endif /* GC_DLL */
|
||||
|
||||
#ifndef CORD_API
|
||||
# define CORD_API extern
|
||||
#endif
|
||||
|
||||
/* Cords have type const char *. This is cheating quite a bit, and not */
|
||||
/* 100% portable. But it means that nonempty character string */
|
||||
/* constants may be used as cords directly, provided the string is */
|
||||
/* never modified in place. The empty cord is represented by, and */
|
||||
/* can be written as, 0. */
|
||||
|
||||
typedef const char * CORD;
|
||||
|
||||
/* An empty cord is always represented as nil */
|
||||
#define CORD_EMPTY 0
|
||||
|
||||
/* Is a nonempty cord represented as a C string? */
|
||||
#define CORD_IS_STRING(s) (*(s) != '\0')
|
||||
|
||||
/* Concatenate two cords. If the arguments are C strings, they may */
|
||||
/* not be subsequently altered. */
|
||||
CORD_API CORD CORD_cat(CORD x, CORD y);
|
||||
|
||||
/* Concatenate a cord and a C string with known length. Except for the */
|
||||
/* empty string case, this is a special case of CORD_cat. Since the */
|
||||
/* length is known, it can be faster. */
|
||||
/* The string y is shared with the resulting CORD. Hence it should */
|
||||
/* not be altered by the caller. */
|
||||
CORD_API CORD CORD_cat_char_star(CORD x, const char * y, size_t leny);
|
||||
|
||||
/* Compute the length of a cord */
|
||||
CORD_API size_t CORD_len(CORD x);
|
||||
|
||||
/* Cords may be represented by functions defining the ith character */
|
||||
typedef char (* CORD_fn)(size_t i, void * client_data);
|
||||
|
||||
/* Turn a functional description into a cord. */
|
||||
CORD_API CORD CORD_from_fn(CORD_fn fn, void * client_data, size_t len);
|
||||
|
||||
/* Return the substring (subcord really) of x with length at most n, */
|
||||
/* starting at position i. (The initial character has position 0.) */
|
||||
CORD_API CORD CORD_substr(CORD x, size_t i, size_t n);
|
||||
|
||||
/* Return the argument, but rebalanced to allow more efficient */
|
||||
/* character retrieval, substring operations, and comparisons. */
|
||||
/* This is useful only for cords that were built using repeated */
|
||||
/* concatenation. Guarantees log time access to the result, unless */
|
||||
/* x was obtained through a large number of repeated substring ops */
|
||||
/* or the embedded functional descriptions take longer to evaluate. */
|
||||
/* May reallocate significant parts of the cord. The argument is not */
|
||||
/* modified; only the result is balanced. */
|
||||
CORD_API CORD CORD_balance(CORD x);
|
||||
|
||||
/* The following traverse a cord by applying a function to each */
|
||||
/* character. This is occasionally appropriate, especially where */
|
||||
/* speed is crucial. But, since C doesn't have nested functions, */
|
||||
/* clients of this sort of traversal are clumsy to write. Consider */
|
||||
/* the functions that operate on cord positions instead. */
|
||||
|
||||
/* Function to iteratively apply to individual characters in cord. */
|
||||
typedef int (* CORD_iter_fn)(char c, void * client_data);
|
||||
|
||||
/* Function to apply to substrings of a cord. Each substring is a */
|
||||
/* a C character string, not a general cord. */
|
||||
typedef int (* CORD_batched_iter_fn)(const char * s, void * client_data);
|
||||
#define CORD_NO_FN ((CORD_batched_iter_fn)0)
|
||||
|
||||
/* Apply f1 to each character in the cord, in ascending order, */
|
||||
/* starting at position i. If */
|
||||
/* f2 is not CORD_NO_FN, then multiple calls to f1 may be replaced by */
|
||||
/* a single call to f2. The parameter f2 is provided only to allow */
|
||||
/* some optimization by the client. This terminates when the right */
|
||||
/* end of this string is reached, or when f1 or f2 return != 0. In the */
|
||||
/* latter case CORD_iter returns != 0. Otherwise it returns 0. */
|
||||
/* The specified value of i must be < CORD_len(x). */
|
||||
CORD_API int CORD_iter5(CORD x, size_t i, CORD_iter_fn f1,
|
||||
CORD_batched_iter_fn f2, void * client_data);
|
||||
|
||||
/* A simpler version that starts at 0, and without f2: */
|
||||
CORD_API int CORD_iter(CORD x, CORD_iter_fn f1, void * client_data);
|
||||
#define CORD_iter(x, f1, cd) CORD_iter5(x, 0, f1, CORD_NO_FN, cd)
|
||||
|
||||
/* Similar to CORD_iter5, but end-to-beginning. No provisions for */
|
||||
/* CORD_batched_iter_fn. */
|
||||
CORD_API int CORD_riter4(CORD x, size_t i, CORD_iter_fn f1, void * client_data);
|
||||
|
||||
/* A simpler version that starts at the end: */
|
||||
CORD_API int CORD_riter(CORD x, CORD_iter_fn f1, void * client_data);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
/* Functions that operate on cord positions. The easy way to traverse */
|
||||
/* cords. A cord position is logically a pair consisting of a cord */
|
||||
/* and an index into that cord. But it is much faster to retrieve a */
|
||||
/* character based on a position than on an index. Unfortunately, */
|
||||
/* positions are big (order of a few 100 bytes), so allocate them with */
|
||||
/* caution. */
|
||||
/* Things in cord_pos.h should be treated as opaque, except as */
|
||||
/* described below. Also note that */
|
||||
/* CORD_pos_fetch, CORD_next and CORD_prev have both macro and function */
|
||||
/* definitions. The former may evaluate their argument more than once. */
|
||||
#include "cord_pos.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
Visible definitions from above:
|
||||
|
||||
typedef <OPAQUE but fairly big> CORD_pos[1];
|
||||
|
||||
* Extract the cord from a position:
|
||||
CORD CORD_pos_to_cord(CORD_pos p);
|
||||
|
||||
* Extract the current index from a position:
|
||||
size_t CORD_pos_to_index(CORD_pos p);
|
||||
|
||||
* Fetch the character located at the given position:
|
||||
char CORD_pos_fetch(CORD_pos p);
|
||||
|
||||
* Initialize the position to refer to the given cord and index.
|
||||
* Note that this is the most expensive function on positions:
|
||||
void CORD_set_pos(CORD_pos p, CORD x, size_t i);
|
||||
|
||||
* Advance the position to the next character.
|
||||
* P must be initialized and valid.
|
||||
* Invalidates p if past end:
|
||||
void CORD_next(CORD_pos p);
|
||||
|
||||
* Move the position to the preceding character.
|
||||
* P must be initialized and valid.
|
||||
* Invalidates p if past beginning:
|
||||
void CORD_prev(CORD_pos p);
|
||||
|
||||
* Is the position valid, i.e. inside the cord?
|
||||
int CORD_pos_valid(CORD_pos p);
|
||||
*/
|
||||
#define CORD_FOR(pos, cord) \
|
||||
for (CORD_set_pos(pos, cord, 0); CORD_pos_valid(pos); CORD_next(pos))
|
||||
|
||||
|
||||
/* An out of memory handler to call. May be supplied by client. */
|
||||
/* Must not return. */
|
||||
extern void (* CORD_oom_fn)(void);
|
||||
|
||||
/* Dump the representation of x to stdout in an implementation defined */
|
||||
/* manner. Intended for debugging only. */
|
||||
CORD_API void CORD_dump(CORD x);
|
||||
|
||||
/* The following could easily be implemented by the client. They are */
|
||||
/* provided in cordxtra.c for convenience. */
|
||||
|
||||
/* Concatenate a character to the end of a cord. */
|
||||
CORD_API CORD CORD_cat_char(CORD x, char c);
|
||||
|
||||
/* Concatenate n cords. */
|
||||
CORD_API CORD CORD_catn(int n, /* CORD */ ...);
|
||||
|
||||
/* Return the character in CORD_substr(x, i, 1) */
|
||||
CORD_API char CORD_fetch(CORD x, size_t i);
|
||||
|
||||
/* Return < 0, 0, or > 0, depending on whether x < y, x = y, x > y */
|
||||
CORD_API int CORD_cmp(CORD x, CORD y);
|
||||
|
||||
/* A generalization that takes both starting positions for the */
|
||||
/* comparison, and a limit on the number of characters to be compared. */
|
||||
CORD_API int CORD_ncmp(CORD x, size_t x_start, CORD y, size_t y_start,
|
||||
size_t len);
|
||||
|
||||
/* Find the first occurrence of s in x at position start or later. */
|
||||
/* Return the position of the first character of s in x, or */
|
||||
/* CORD_NOT_FOUND if there is none. */
|
||||
CORD_API size_t CORD_str(CORD x, size_t start, CORD s);
|
||||
|
||||
/* Return a cord consisting of i copies of (possibly NUL) c. Dangerous */
|
||||
/* in conjunction with CORD_to_char_star. */
|
||||
/* The resulting representation takes constant space, independent of i. */
|
||||
CORD_API CORD CORD_chars(char c, size_t i);
|
||||
#define CORD_nul(i) CORD_chars('\0', (i))
|
||||
|
||||
/* Turn a file into cord. The file must be seekable. Its contents */
|
||||
/* must remain constant. The file may be accessed as an immediate */
|
||||
/* result of this call and/or as a result of subsequent accesses to */
|
||||
/* the cord. Short files are likely to be immediately read, but */
|
||||
/* long files are likely to be read on demand, possibly relying on */
|
||||
/* stdio for buffering. */
|
||||
/* We must have exclusive access to the descriptor f, i.e. we may */
|
||||
/* read it at any time, and expect the file pointer to be */
|
||||
/* where we left it. Normally this should be invoked as */
|
||||
/* CORD_from_file(fopen(...)) */
|
||||
/* CORD_from_file arranges to close the file descriptor when it is no */
|
||||
/* longer needed (e.g. when the result becomes inaccessible). */
|
||||
/* The file f must be such that ftell reflects the actual character */
|
||||
/* position in the file, i.e. the number of characters that can be */
|
||||
/* or were read with fread. On UNIX systems this is always true. On */
|
||||
/* MS Windows systems, f must be opened in binary mode. */
|
||||
CORD_API CORD CORD_from_file(FILE * f);
|
||||
|
||||
/* Equivalent to the above, except that the entire file will be read */
|
||||
/* and the file pointer will be closed immediately. */
|
||||
/* The binary mode restriction from above does not apply. */
|
||||
CORD_API CORD CORD_from_file_eager(FILE * f);
|
||||
|
||||
/* Equivalent to the above, except that the file will be read on demand.*/
|
||||
/* The binary mode restriction applies. */
|
||||
CORD_API CORD CORD_from_file_lazy(FILE * f);
|
||||
|
||||
/* Turn a cord into a C string. The result shares no structure with */
|
||||
/* x, and is thus modifiable. */
|
||||
CORD_API char * CORD_to_char_star(CORD x);
|
||||
|
||||
/* Turn a C string into a CORD. The C string is copied, and so may */
|
||||
/* subsequently be modified. */
|
||||
CORD_API CORD CORD_from_char_star(const char *s);
|
||||
|
||||
/* Identical to the above, but the result may share structure with */
|
||||
/* the argument and is thus not modifiable. */
|
||||
CORD_API const char * CORD_to_const_char_star(CORD x);
|
||||
|
||||
/* Write a cord to a file, starting at the current position. No */
|
||||
/* trailing NULs are newlines are added. */
|
||||
/* Returns EOF if a write error occurs, 1 otherwise. */
|
||||
CORD_API int CORD_put(CORD x, FILE * f);
|
||||
|
||||
/* "Not found" result for the following two functions. */
|
||||
#define CORD_NOT_FOUND ((size_t)(-1))
|
||||
|
||||
/* A vague analog of strchr. Returns the position (an integer, not */
|
||||
/* a pointer) of the first occurrence of (char) c inside x at position */
|
||||
/* i or later. The value i must be < CORD_len(x). */
|
||||
CORD_API size_t CORD_chr(CORD x, size_t i, int c);
|
||||
|
||||
/* A vague analog of strrchr. Returns index of the last occurrence */
|
||||
/* of (char) c inside x at position i or earlier. The value i */
|
||||
/* must be < CORD_len(x). */
|
||||
CORD_API size_t CORD_rchr(CORD x, size_t i, int c);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
/* The following are also not primitive, but are implemented in */
|
||||
/* cordprnt.c. They provide functionality similar to the ANSI C */
|
||||
/* functions with corresponding names, but with the following */
|
||||
/* additions and changes: */
|
||||
/* 1. A %r conversion specification specifies a CORD argument. Field */
|
||||
/* width, precision, etc. have the same semantics as for %s. */
|
||||
/* (Note that %c, %C, and %S were already taken.) */
|
||||
/* 2. The format string is represented as a CORD. */
|
||||
/* 3. CORD_sprintf and CORD_vsprintf assign the result through the 1st */
|
||||
/* argument. Unlike their ANSI C versions, there is no need to guess */
|
||||
/* the correct buffer size. */
|
||||
/* 4. Most of the conversions are implement through the native */
|
||||
/* vsprintf. Hence they are usually no faster, and */
|
||||
/* idiosyncrasies of the native printf are preserved. However, */
|
||||
/* CORD arguments to CORD_sprintf and CORD_vsprintf are NOT copied; */
|
||||
/* the result shares the original structure. This may make them */
|
||||
/* very efficient in some unusual applications. */
|
||||
/* The format string is copied. */
|
||||
/* All functions return the number of characters generated or -1 on */
|
||||
/* error. This complies with the ANSI standard, but is inconsistent */
|
||||
/* with some older implementations of sprintf. */
|
||||
|
||||
/* The implementation of these is probably less portable than the rest */
|
||||
/* of this package. */
|
||||
|
||||
#ifndef CORD_NO_IO
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
# ifdef __cplusplus
|
||||
extern "C" {
|
||||
# endif
|
||||
|
||||
CORD_API int CORD_sprintf(CORD * out, CORD format, ...);
|
||||
CORD_API int CORD_vsprintf(CORD * out, CORD format, va_list args);
|
||||
CORD_API int CORD_fprintf(FILE * f, CORD format, ...);
|
||||
CORD_API int CORD_vfprintf(FILE * f, CORD format, va_list args);
|
||||
CORD_API int CORD_printf(CORD format, ...);
|
||||
CORD_API int CORD_vprintf(CORD format, va_list args);
|
||||
|
||||
# ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
# endif
|
||||
|
||||
#endif /* CORD_NO_IO */
|
||||
|
||||
#endif /* CORD_H */
|
|
@ -0,0 +1,128 @@
|
|||
/*
|
||||
* Copyright (c) 1993-1994 by Xerox Corporation. All rights reserved.
|
||||
*
|
||||
* THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
|
||||
* OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
|
||||
*
|
||||
* Permission is hereby granted to use or copy this program
|
||||
* for any purpose, provided the above notices are retained on all copies.
|
||||
* Permission to modify the code and to distribute modified code is granted,
|
||||
* provided the above notices are retained, and a notice that the code was
|
||||
* modified is included with the above copyright notice.
|
||||
*/
|
||||
|
||||
/* This should never be included directly; included only from cord.h. */
|
||||
#if !defined(CORD_POSITION_H) && defined(CORD_H)
|
||||
#define CORD_POSITION_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* The representation of CORD_position. This is private to the */
|
||||
/* implementation, but the size is known to clients. Also */
|
||||
/* the implementation of some exported macros relies on it. */
|
||||
/* Don't use anything defined here and not in cord.h. */
|
||||
|
||||
# define MAX_DEPTH 48
|
||||
/* The maximum depth of a balanced cord + 1. */
|
||||
/* We don't let cords get deeper than MAX_DEPTH. */
|
||||
|
||||
struct CORD_pe {
|
||||
CORD pe_cord;
|
||||
size_t pe_start_pos;
|
||||
};
|
||||
|
||||
/* A structure describing an entry on the path from the root */
|
||||
/* to current position. */
|
||||
typedef struct CORD_Pos {
|
||||
size_t cur_pos;
|
||||
int path_len;
|
||||
# define CORD_POS_INVALID (0x55555555)
|
||||
/* path_len == INVALID <==> position invalid */
|
||||
const char *cur_leaf; /* Current leaf, if it is a string. */
|
||||
/* If the current leaf is a function, */
|
||||
/* then this may point to function_buf */
|
||||
/* containing the next few characters. */
|
||||
/* Always points to a valid string */
|
||||
/* containing the current character */
|
||||
/* unless cur_end is 0. */
|
||||
size_t cur_start; /* Start position of cur_leaf */
|
||||
size_t cur_end; /* Ending position of cur_leaf */
|
||||
/* 0 if cur_leaf is invalid. */
|
||||
struct CORD_pe path[MAX_DEPTH + 1];
|
||||
/* path[path_len] is the leaf corresponding to cur_pos */
|
||||
/* path[0].pe_cord is the cord we point to. */
|
||||
# define FUNCTION_BUF_SZ 8
|
||||
char function_buf[FUNCTION_BUF_SZ]; /* Space for next few chars */
|
||||
/* from function node. */
|
||||
} CORD_pos[1];
|
||||
|
||||
/* Extract the cord from a position: */
|
||||
CORD_API CORD CORD_pos_to_cord(CORD_pos p);
|
||||
|
||||
/* Extract the current index from a position: */
|
||||
CORD_API size_t CORD_pos_to_index(CORD_pos p);
|
||||
|
||||
/* Fetch the character located at the given position: */
|
||||
CORD_API char CORD_pos_fetch(CORD_pos p);
|
||||
|
||||
/* Initialize the position to refer to the give cord and index. */
|
||||
/* Note that this is the most expensive function on positions: */
|
||||
CORD_API void CORD_set_pos(CORD_pos p, CORD x, size_t i);
|
||||
|
||||
/* Advance the position to the next character. */
|
||||
/* P must be initialized and valid. */
|
||||
/* Invalidates p if past end: */
|
||||
CORD_API void CORD_next(CORD_pos p);
|
||||
|
||||
/* Move the position to the preceding character. */
|
||||
/* P must be initialized and valid. */
|
||||
/* Invalidates p if past beginning: */
|
||||
CORD_API void CORD_prev(CORD_pos p);
|
||||
|
||||
/* Is the position valid, i.e. inside the cord? */
|
||||
CORD_API int CORD_pos_valid(CORD_pos p);
|
||||
|
||||
CORD_API char CORD__pos_fetch(CORD_pos);
|
||||
CORD_API void CORD__next(CORD_pos);
|
||||
CORD_API void CORD__prev(CORD_pos);
|
||||
|
||||
#define CORD_pos_fetch(p) \
|
||||
(((p)[0].cur_end != 0)? \
|
||||
(p)[0].cur_leaf[(p)[0].cur_pos - (p)[0].cur_start] \
|
||||
: CORD__pos_fetch(p))
|
||||
|
||||
#define CORD_next(p) \
|
||||
(((p)[0].cur_pos + 1 < (p)[0].cur_end)? \
|
||||
(p)[0].cur_pos++ \
|
||||
: (CORD__next(p), 0))
|
||||
|
||||
#define CORD_prev(p) \
|
||||
(((p)[0].cur_end != 0 && (p)[0].cur_pos > (p)[0].cur_start)? \
|
||||
(p)[0].cur_pos-- \
|
||||
: (CORD__prev(p), 0))
|
||||
|
||||
#define CORD_pos_to_index(p) ((p)[0].cur_pos)
|
||||
|
||||
#define CORD_pos_to_cord(p) ((p)[0].path[0].pe_cord)
|
||||
|
||||
#define CORD_pos_valid(p) ((p)[0].path_len != CORD_POS_INVALID)
|
||||
|
||||
/* Some grubby stuff for performance-critical friends: */
|
||||
#define CORD_pos_chars_left(p) ((long)((p)[0].cur_end) - (long)((p)[0].cur_pos))
|
||||
/* Number of characters in cache. <= 0 ==> none */
|
||||
|
||||
#define CORD_pos_advance(p,n) ((p)[0].cur_pos += (n) - 1, CORD_next(p))
|
||||
/* Advance position by n characters */
|
||||
/* 0 < n < CORD_pos_chars_left(p) */
|
||||
|
||||
#define CORD_pos_cur_char_addr(p) \
|
||||
(p)[0].cur_leaf + ((p)[0].cur_pos - (p)[0].cur_start)
|
||||
/* address of current character in cache. */
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue