Compare commits
264 Commits
398db21388
...
e493725190
Author | SHA1 | Date |
---|---|---|
Jef Roosens | e493725190 | |
Jef Roosens | 8e4b53acc4 | |
Jef Roosens | 60ff01f692 | |
Jef Roosens | 3ce87c3ffc | |
Jef Roosens | 7af1cb3ac4 | |
yuyi | 585b5145fa | |
Delyan Angelov | 6a4ba22eae | |
pancake | 23d1c792c0 | |
Delyan Angelov | 74fb473301 | |
Delyan Angelov | 6c060b76fd | |
Delyan Angelov | 48b2ab157b | |
yuyi | c64c4907a2 | |
Delyan Angelov | e2e3992e0d | |
ghosttk | 8172fecb51 | |
Larpon | 9f5e442dab | |
yuyi | c160ba2a8d | |
Delyan Angelov | c6f94e9cab | |
yuyi | cab6355a38 | |
Delyan Angelov | f08c768c8e | |
Ulises Jeremias Cornejo Fandos | e505fcdac0 | |
yuyi | f6f77e5264 | |
David 'Epper' Marshall | 524df8da1b | |
Delyan Angelov | 473d26ce47 | |
pancake | 1caff5b379 | |
yuyi | 8703e336e0 | |
Delyan Angelov | 1fc9e1a716 | |
Delyan Angelov | fa2e8d8459 | |
Delyan Angelov | 0e4198f23b | |
yuyi | cf1fc6f090 | |
Alexander Medvednikov | 924239026c | |
Alexander Medvednikov | bc60b0d1a3 | |
Alexander Medvednikov | d215618f4c | |
yuyi | de136f6baf | |
Delyan Angelov | 37ef1ee453 | |
Delyan Angelov | 7b1ade237b | |
Delyan Angelov | b9cb56572f | |
Alexander Medvednikov | 6875a173ec | |
Delyan Angelov | 97be840a6d | |
lemon | e0310964d9 | |
Alexander Medvednikov | 10051e005a | |
wahur666 | 18dfaf6164 | |
yuyi | 01fdd5d07f | |
Alexander Medvednikov | b89617726c | |
Louis Schmieder | 5df3d8ac75 | |
Alexander Medvednikov | fb5a40d1c8 | |
yuyi | 26714fadc5 | |
Alexander Medvednikov | 9c72b85f72 | |
Danilo Lekovic | df239b9208 | |
yuyi | f2962c34dd | |
Delyan Angelov | 205221074c | |
yuyi | 0c1708db23 | |
yuyi | 5135952c9c | |
yuyi | 7f38b92ca8 | |
yuyi | 7c50d276c7 | |
lemon | e4e858b132 | |
yuyi | 6d8a0ad15d | |
Spydr | 2f1a896d18 | |
Leo Developer | 67716b5b59 | |
yuyi | 5efa67906c | |
yuyi | 3535927bcd | |
Delyan Angelov | 139c34c07d | |
Delyan Angelov | 4682e17ac1 | |
Delyan Angelov | 7e06203da8 | |
Delyan Angelov | ff8e286c88 | |
Spydr | 5c104cf981 | |
Spydr | 8fa1e30dd2 | |
Alexander Medvednikov | f08266ab66 | |
Joe Conigliaro | f3351b6a29 | |
Delyan Angelov | 5cea8d30fa | |
yuyi | a538ab7e8c | |
yuyi | cdf4ffc513 | |
lemon | c7a619d16e | |
Dialga | da7a166708 | |
spaceface | 26d051475a | |
Delyan Angelov | b27b6b2047 | |
yuyi | fcaf529228 | |
Larpon | 690a8422d1 | |
Delyan Angelov | f4869bcdc6 | |
Delyan Angelov | ea71ea3ec1 | |
yuyi | 922f003729 | |
Larpon | be23ddc253 | |
yuyi | 784361f153 | |
Delyan Angelov | e1360ccf8c | |
Ben | 39e54a508b | |
spaceface | 4ed9780b80 | |
yuyi | e6580fefaa | |
Spydr | 8563696476 | |
Larpon | f58e5a94c2 | |
Ben | c6b1c8d07a | |
Mikey | 5ac9b5c9f1 | |
Delyan Angelov | 4b3c3d9082 | |
Larpon | 96a9faf2fd | |
David Valdespino Pavon | 1d462136bc | |
Larpon | 8027919285 | |
Delyan Angelov | 82594c0156 | |
Delyan Angelov | a942ecf737 | |
Delyan Angelov | 82d23dedf1 | |
yuyi | 7780f56c31 | |
ChAoS_UnItY | 73b59c7b16 | |
yuyi | abf35270cf | |
ChAoS_UnItY | ce26d5bc5c | |
Delyan Angelov | 778fe2cde0 | |
Delyan Angelov | 6398043094 | |
Alexander Medvednikov | 7f67981637 | |
yuyi | 8a2236d3f8 | |
Alexander Medvednikov | e89a6269e4 | |
yuyi | ce771876a3 | |
ChAoS_UnItY | df80b33dc0 | |
Leo Developer | 3a90d8ef14 | |
Ikko Ashimine | 7b25957a26 | |
ChAoS_UnItY | b000728845 | |
yuyi | 4cf6abd99d | |
ChAoS_UnItY | f6ebbc99cd | |
yuyi | 5d429140a4 | |
Wertzui123 | d71fd04c81 | |
Delyan Angelov | 3c5ae41712 | |
Delyan Angelov | 3ac3375b43 | |
Delyan Angelov | 82eb495617 | |
Delyan Angelov | f2171b4148 | |
Delyan Angelov | 4cfff58fdf | |
Alexander Medvednikov | a8461a900d | |
yuyi | 66572d5ead | |
Delyan Angelov | c15d1c6e7e | |
Delyan Angelov | 6f9070e06d | |
Delyan Angelov | dbaecdc058 | |
yuyi | daa94de93f | |
yuyi | dcbd8d6405 | |
ChAoS_UnItY | 65066098d8 | |
yuyi | 251716fa0e | |
Delyan Angelov | 9f7656f328 | |
Delyan Angelov | c892b3203e | |
Hunam | 41414b5d5f | |
Delyan Angelov | aae5b9fb95 | |
Delyan Angelov | ed759b2ec9 | |
Delyan Angelov | 031629faa1 | |
Delyan Angelov | 9a0ec7f367 | |
yuyi | 545eaae77b | |
Alexander Medvednikov | 8b0e843cb8 | |
yuyi | 10fb16e00b | |
Claudio Cesar de Sá | 5bf246fce6 | |
Ben | e201665e92 | |
Wertzui123 | f971da9a93 | |
ChAoS_UnItY | a95cdac635 | |
yuyi | 55951e0943 | |
Hunam | d0a1608ede | |
yuyi | 33a2d00445 | |
Delyan Angelov | bf70f0b436 | |
Delyan Angelov | c91b646372 | |
yuyi | 786045c7da | |
Delyan Angelov | 5a2c271bd4 | |
Delyan Angelov | 2fa64f1471 | |
yuyi | fefb9643b2 | |
Delyan Angelov | 846ddfd728 | |
Alexander Medvednikov | f40c30c3dc | |
Alexander Medvednikov | c54c9b817c | |
Larpon | 84e375e38a | |
yuyi | 80cc88427b | |
playX | db34adaec8 | |
Delyan Angelov | dc30089c74 | |
Ben | 4ffdcf8058 | |
Delyan Angelov | 928dafeb6d | |
Delyan Angelov | fc64f09f0b | |
Delyan Angelov | 0f3b2c2ae7 | |
Delyan Angelov | 58ebc0680e | |
yuyi | 844ba2a177 | |
Hunam | 78d1b7f4ef | |
yuyi | 2c5febe25e | |
yuyi | 79d861ad4f | |
Delyan Angelov | 63d15086e7 | |
Delyan Angelov | c006d5c242 | |
yuyi | c0ef6dbde8 | |
yuyi | 7dcc19df55 | |
Delyan Angelov | c6a6eb9a3c | |
yuyi | b8e8768928 | |
yuyi | a46cf10e92 | |
Delyan Angelov | 4894f61998 | |
yuyi | a971b9a99a | |
Larpon | f3e7f24ee6 | |
spaceface | 52a3e5e780 | |
Delyan Angelov | f7995c8916 | |
Delyan Angelov | 36cb552918 | |
Delyan Angelov | 156aa661ee | |
Louis Schmieder | a83ac948a0 | |
yuyi | b97ef09b2d | |
Delyan Angelov | bb6ef8bba8 | |
Delyan Angelov | 8c969efe6b | |
Wertzui123 | 1017335365 | |
yuyi | 3849cdcecc | |
Delyan Angelov | 410b57b2fa | |
Larpon | 95cc535fc7 | |
Larpon | 9f5e999b4a | |
Larpon | 6c08af63ff | |
yuyi | 59e57f0c62 | |
kahsa | dd8c96f6bc | |
Delyan Angelov | 31c234485a | |
yuyi | e19ac0c4a7 | |
yuyi | 79a75c5ac0 | |
yuyi | 0eb3f8854d | |
Ben | f431020764 | |
yuyi | f35f7fe997 | |
yuyi | a5b98cb267 | |
yuyi | 5ade39f8db | |
Delyan Angelov | 953ef1f8c9 | |
Delyan Angelov | dda49fe735 | |
yuyi | a3c0a9b791 | |
yuyi | 4ef9e2c05a | |
Alexander Medvednikov | 863eeca2e0 | |
Daniel Däschle | 5e95bdc451 | |
yuyi | 7f03b89611 | |
spaceface | ba859c584b | |
Delyan Angelov | 5328dabad1 | |
spaceface | e5ff2ab455 | |
yuyi | 1f3336c9d3 | |
Alexander Medvednikov | 245d28d57a | |
Daniel Däschle | d3ffd983c8 | |
Subhomoy Haldar | 3647fb4def | |
Delyan Angelov | 64a686f41f | |
yuyi | 50ab2cfd1a | |
Delyan Angelov | 0ceb16f285 | |
Delyan Angelov | c0dcc80e18 | |
Delyan Angelov | a7afb2d1eb | |
Ben | 971c55cf30 | |
Daniel Däschle | efc5cab8c3 | |
Alexander Medvednikov | 53c217fe5e | |
Vincenzo Palazzo | 17bba712bd | |
Daniel Däschle | d81fbb1ccd | |
Delyan Angelov | dd1049f21d | |
yuyi | 28b0cbddad | |
yuyi | 913164bc73 | |
yuyi | bf44572f30 | |
StunxFS | 11bdb04d0c | |
Delyan Angelov | ca00b59b3f | |
David 'Epper' Marshall | 120f31b4d9 | |
David 'Epper' Marshall | 23568f19da | |
crthpl | 95d24e543d | |
yuyi | 55e7daa2f9 | |
crthpl | 46f94e8d68 | |
Daniel Däschle | a52fbc5e51 | |
yuyi | 3291c59ebf | |
Delyan Angelov | 634e8c3624 | |
yuyi | 15c62bc8e8 | |
Delyan Angelov | 25812e52f0 | |
Delyan Angelov | a52590572f | |
Delyan Angelov | 3d5617c4fa | |
Delyan Angelov | 809b1ca3b4 | |
yuyi | b482c0512b | |
Delyan Angelov | 805a7d9713 | |
yuyi | 5b96f7e8fd | |
yuyi | 4cbfa884c5 | |
Delyan Angelov | f2447a4bd8 | |
Delyan Angelov | 2cc3b74e19 | |
Larpon | 9de0c725f6 | |
Adam Oates | a786c58d0a | |
yuyi | 417a6dc506 | |
Larpon | 8eea861c93 | |
Delyan Angelov | ed17779434 | |
Delyan Angelov | ebac3bebb1 | |
playX | a608516b82 | |
spaceface | b5fb848508 | |
Delyan Angelov | 65d9c8fa6f | |
Delyan Angelov | dfa2d63616 | |
Delyan Angelov | 4e56147223 | |
Alexander Medvednikov | 2a06290ac7 | |
Ned | db4b49a5ca |
|
@ -15,6 +15,7 @@ concurrency:
|
||||||
jobs:
|
jobs:
|
||||||
ubuntu-tcc:
|
ubuntu-tcc:
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-20.04
|
||||||
|
if: github.event_name != 'push' || github.event.ref == 'refs/heads/master' || github.event.repository.full_name != 'vlang/v'
|
||||||
timeout-minutes: 121
|
timeout-minutes: 121
|
||||||
env:
|
env:
|
||||||
VFLAGS: -cc tcc -no-retry-compilation
|
VFLAGS: -cc tcc -no-retry-compilation
|
||||||
|
@ -60,7 +61,7 @@ jobs:
|
||||||
- name: Self tests
|
- name: Self tests
|
||||||
run: ./v test-self
|
run: ./v test-self
|
||||||
# - name: Self tests (-cstrict)
|
# - name: Self tests (-cstrict)
|
||||||
# run: ./v -cstrict test-self
|
# run: V_CI_CSTRICT=1 ./v -cstrict test-self
|
||||||
- name: Test time functions in a timezone UTC-12
|
- name: Test time functions in a timezone UTC-12
|
||||||
run: TZ=Etc/GMT+12 ./v test vlib/time/
|
run: TZ=Etc/GMT+12 ./v test vlib/time/
|
||||||
- name: Test time functions in a timezone UTC-3
|
- name: Test time functions in a timezone UTC-3
|
||||||
|
@ -94,6 +95,7 @@ jobs:
|
||||||
|
|
||||||
ubuntu-tcc-boehm-gc:
|
ubuntu-tcc-boehm-gc:
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-20.04
|
||||||
|
if: github.event_name != 'push' || github.event.ref == 'refs/heads/master' || github.event.repository.full_name != 'vlang/v'
|
||||||
timeout-minutes: 121
|
timeout-minutes: 121
|
||||||
env:
|
env:
|
||||||
VFLAGS: -cc tcc -no-retry-compilation
|
VFLAGS: -cc tcc -no-retry-compilation
|
||||||
|
@ -149,7 +151,8 @@ jobs:
|
||||||
[ "$(stat -c %s leaks.txt)" = "0" ]
|
[ "$(stat -c %s leaks.txt)" = "0" ]
|
||||||
|
|
||||||
macos:
|
macos:
|
||||||
runs-on: macOS-latest
|
runs-on: macOS-12
|
||||||
|
if: github.event_name != 'push' || github.event.ref == 'refs/heads/master' || github.event.repository.full_name != 'vlang/v'
|
||||||
timeout-minutes: 121
|
timeout-minutes: 121
|
||||||
env:
|
env:
|
||||||
VFLAGS: -cc clang
|
VFLAGS: -cc clang
|
||||||
|
@ -194,7 +197,7 @@ jobs:
|
||||||
./v cmd/tools/test_if_v_test_system_works.v
|
./v cmd/tools/test_if_v_test_system_works.v
|
||||||
./cmd/tools/test_if_v_test_system_works
|
./cmd/tools/test_if_v_test_system_works
|
||||||
- name: All code is formatted
|
- name: All code is formatted
|
||||||
run: ./v test-cleancode
|
run: VJOBS=1 ./v test-cleancode
|
||||||
- name: Self tests
|
- name: Self tests
|
||||||
run: VJOBS=1 ./v test-self
|
run: VJOBS=1 ./v test-self
|
||||||
- name: Build examples
|
- name: Build examples
|
||||||
|
@ -239,6 +242,7 @@ jobs:
|
||||||
|
|
||||||
ubuntu:
|
ubuntu:
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-20.04
|
||||||
|
if: github.event_name != 'push' || github.event.ref == 'refs/heads/master' || github.event.repository.full_name != 'vlang/v'
|
||||||
timeout-minutes: 121
|
timeout-minutes: 121
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
|
@ -294,7 +298,7 @@ jobs:
|
||||||
- name: Self tests (-prod)
|
- name: Self tests (-prod)
|
||||||
run: ./v -o vprod -prod cmd/v && ./vprod test-self
|
run: ./v -o vprod -prod cmd/v && ./vprod test-self
|
||||||
- name: Self tests (-cstrict)
|
- name: Self tests (-cstrict)
|
||||||
run: ./v -cc gcc -cstrict test-self
|
run: VTEST_JUST_ESSENTIAL=1 V_CI_CSTRICT=1 ./v -cc gcc -cstrict test-self
|
||||||
- name: Build examples
|
- name: Build examples
|
||||||
run: ./v build-examples
|
run: ./v build-examples
|
||||||
- name: Build tetris.v with -autofree
|
- name: Build tetris.v with -autofree
|
||||||
|
@ -338,6 +342,7 @@ jobs:
|
||||||
|
|
||||||
ubuntu-clang:
|
ubuntu-clang:
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-20.04
|
||||||
|
if: github.event_name != 'push' || github.event.ref == 'refs/heads/master' || github.event.repository.full_name != 'vlang/v'
|
||||||
timeout-minutes: 121
|
timeout-minutes: 121
|
||||||
env:
|
env:
|
||||||
VFLAGS: -cc clang
|
VFLAGS: -cc clang
|
||||||
|
@ -383,12 +388,16 @@ jobs:
|
||||||
./cmd/tools/test_if_v_test_system_works
|
./cmd/tools/test_if_v_test_system_works
|
||||||
- name: All code is formatted
|
- name: All code is formatted
|
||||||
run: ./v test-cleancode
|
run: ./v test-cleancode
|
||||||
|
|
||||||
- name: Self tests
|
- name: Self tests
|
||||||
run: ./v test-self
|
run: ./v test-self
|
||||||
- name: Self tests (-prod)
|
- name: Self tests (vprod)
|
||||||
run: ./v -o vprod -prod cmd/v && ./vprod test-self
|
run: |
|
||||||
|
./v -o vprod -prod cmd/v
|
||||||
|
./vprod test-self
|
||||||
- name: Self tests (-cstrict)
|
- name: Self tests (-cstrict)
|
||||||
run: ./v -cstrict test-self
|
run: VTEST_JUST_ESSENTIAL=1 V_CI_CSTRICT=1 ./vprod -cstrict test-self
|
||||||
|
|
||||||
- name: Build examples
|
- name: Build examples
|
||||||
run: ./v build-examples
|
run: ./v build-examples
|
||||||
- name: Build examples with -autofree
|
- name: Build examples with -autofree
|
||||||
|
@ -424,6 +433,7 @@ jobs:
|
||||||
|
|
||||||
windows-gcc:
|
windows-gcc:
|
||||||
runs-on: windows-2019
|
runs-on: windows-2019
|
||||||
|
if: github.event_name != 'push' || github.event.ref == 'refs/heads/master' || github.event.repository.full_name != 'vlang/v'
|
||||||
timeout-minutes: 121
|
timeout-minutes: 121
|
||||||
env:
|
env:
|
||||||
VFLAGS: -cc gcc
|
VFLAGS: -cc gcc
|
||||||
|
@ -486,6 +496,7 @@ jobs:
|
||||||
|
|
||||||
windows-msvc:
|
windows-msvc:
|
||||||
runs-on: windows-2019
|
runs-on: windows-2019
|
||||||
|
if: github.event_name != 'push' || github.event.ref == 'refs/heads/master' || github.event.repository.full_name != 'vlang/v'
|
||||||
timeout-minutes: 121
|
timeout-minutes: 121
|
||||||
env:
|
env:
|
||||||
VFLAGS: -cc msvc
|
VFLAGS: -cc msvc
|
||||||
|
@ -533,6 +544,7 @@ jobs:
|
||||||
|
|
||||||
windows-tcc:
|
windows-tcc:
|
||||||
runs-on: windows-2019
|
runs-on: windows-2019
|
||||||
|
if: github.event_name != 'push' || github.event.ref == 'refs/heads/master' || github.event.repository.full_name != 'vlang/v'
|
||||||
timeout-minutes: 121
|
timeout-minutes: 121
|
||||||
env:
|
env:
|
||||||
VFLAGS: -cc tcc -no-retry-compilation
|
VFLAGS: -cc tcc -no-retry-compilation
|
||||||
|
@ -582,7 +594,9 @@ jobs:
|
||||||
- name: Build examples
|
- name: Build examples
|
||||||
run: ./v build-examples
|
run: ./v build-examples
|
||||||
- name: v2 self compilation
|
- name: v2 self compilation
|
||||||
run: .\v.exe -o v2.exe cmd/v && .\v2.exe -o v3.exe cmd/v
|
run: .\v.exe -o v2.exe cmd/v && .\v2.exe -o v3.exe cmd/v && .\v3.exe -o v4.exe cmd/v
|
||||||
|
- name: v2 self compilation with -gc boehm
|
||||||
|
run: .\v.exe -o v2.exe -gc boehm cmd/v && .\v2.exe -o v3.exe -gc boehm cmd/v && .\v3.exe -o v4.exe -gc boehm cmd/v
|
||||||
|
|
||||||
## ## tcc32
|
## ## tcc32
|
||||||
## - name: Build with make.bat -tcc32
|
## - name: Build with make.bat -tcc32
|
||||||
|
@ -627,6 +641,7 @@ jobs:
|
||||||
|
|
||||||
# ubuntu-autofree-selfcompile:
|
# ubuntu-autofree-selfcompile:
|
||||||
# runs-on: ubuntu-20.04
|
# runs-on: ubuntu-20.04
|
||||||
|
# if: github.event_name != 'push' || github.event.ref == 'refs/heads/master' || github.event.repository.full_name != 'vlang/v'
|
||||||
# timeout-minutes: 121
|
# timeout-minutes: 121
|
||||||
# env:
|
# env:
|
||||||
# VFLAGS: -cc gcc
|
# VFLAGS: -cc gcc
|
||||||
|
@ -640,6 +655,7 @@ jobs:
|
||||||
|
|
||||||
# ubuntu-musl:
|
# ubuntu-musl:
|
||||||
# runs-on: ubuntu-20.04
|
# runs-on: ubuntu-20.04
|
||||||
|
# if: github.event_name != 'push' || github.event.ref == 'refs/heads/master' || github.event.repository.full_name != 'vlang/v'
|
||||||
# timeout-minutes: 121
|
# timeout-minutes: 121
|
||||||
# env:
|
# env:
|
||||||
# VFLAGS: -cc musl-gcc
|
# VFLAGS: -cc musl-gcc
|
||||||
|
|
|
@ -11,6 +11,7 @@ on:
|
||||||
jobs:
|
jobs:
|
||||||
ubuntu:
|
ubuntu:
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-20.04
|
||||||
|
if: github.event_name != 'push' || github.event.ref == 'refs/heads/master' || github.event.repository.full_name != 'vlang/v'
|
||||||
timeout-minutes: 30
|
timeout-minutes: 30
|
||||||
env:
|
env:
|
||||||
VFLAGS: -cc tcc -no-retry-compilation
|
VFLAGS: -cc tcc -no-retry-compilation
|
||||||
|
@ -49,6 +50,7 @@ jobs:
|
||||||
|
|
||||||
macos:
|
macos:
|
||||||
runs-on: macos-11
|
runs-on: macos-11
|
||||||
|
if: github.event_name != 'push' || github.event.ref == 'refs/heads/master' || github.event.repository.full_name != 'vlang/v'
|
||||||
timeout-minutes: 30
|
timeout-minutes: 30
|
||||||
env:
|
env:
|
||||||
VFLAGS: -cc clang
|
VFLAGS: -cc clang
|
||||||
|
|
|
@ -12,6 +12,7 @@ jobs:
|
||||||
|
|
||||||
macos-cross:
|
macos-cross:
|
||||||
runs-on: macOS-latest
|
runs-on: macOS-latest
|
||||||
|
if: github.event_name != 'push' || github.event.ref == 'refs/heads/master' || github.event.repository.full_name != 'vlang/v'
|
||||||
timeout-minutes: 25
|
timeout-minutes: 25
|
||||||
env:
|
env:
|
||||||
VFLAGS: -cc clang
|
VFLAGS: -cc clang
|
||||||
|
@ -44,10 +45,11 @@ jobs:
|
||||||
- name: Compile to raw Android (non-graphic) compatible
|
- name: Compile to raw Android (non-graphic) compatible
|
||||||
run: |
|
run: |
|
||||||
# Test that V can compile non-graphic app to Android compatible code *without* using the -apk flag
|
# Test that V can compile non-graphic app to Android compatible code *without* using the -apk flag
|
||||||
./v -os android examples/toml.v
|
./v -os android -gc none examples/toml.v
|
||||||
|
|
||||||
linux-cross:
|
linux-cross:
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-20.04
|
||||||
|
if: github.event_name != 'push' || github.event.ref == 'refs/heads/master' || github.event.repository.full_name != 'vlang/v'
|
||||||
timeout-minutes: 25
|
timeout-minutes: 25
|
||||||
env:
|
env:
|
||||||
VFLAGS: -cc tcc -no-retry-compilation
|
VFLAGS: -cc tcc -no-retry-compilation
|
||||||
|
@ -96,11 +98,12 @@ jobs:
|
||||||
- name: toml.v can be compiled to raw Android C
|
- name: toml.v can be compiled to raw Android C
|
||||||
run: |
|
run: |
|
||||||
# Test that V can compile non-graphic app to Android compatible code *without* using the -apk flag
|
# Test that V can compile non-graphic app to Android compatible code *without* using the -apk flag
|
||||||
./v -os android examples/toml.v
|
./v -os android -gc none examples/toml.v
|
||||||
|
|
||||||
|
|
||||||
windows-cross:
|
windows-cross:
|
||||||
runs-on: windows-2019
|
runs-on: windows-2019
|
||||||
|
if: github.event_name != 'push' || github.event.ref == 'refs/heads/master' || github.event.repository.full_name != 'vlang/v'
|
||||||
timeout-minutes: 25
|
timeout-minutes: 25
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
|
|
|
@ -74,6 +74,7 @@ concurrency:
|
||||||
jobs:
|
jobs:
|
||||||
tests-sanitize-undefined-clang:
|
tests-sanitize-undefined-clang:
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-20.04
|
||||||
|
if: github.event_name != 'push' || github.event.ref == 'refs/heads/master' || github.event.repository.full_name != 'vlang/v'
|
||||||
timeout-minutes: 180
|
timeout-minutes: 180
|
||||||
env:
|
env:
|
||||||
VFLAGS: -cc clang
|
VFLAGS: -cc clang
|
||||||
|
@ -101,6 +102,7 @@ jobs:
|
||||||
|
|
||||||
tests-sanitize-undefined-gcc:
|
tests-sanitize-undefined-gcc:
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-20.04
|
||||||
|
if: github.event_name != 'push' || github.event.ref == 'refs/heads/master' || github.event.repository.full_name != 'vlang/v'
|
||||||
timeout-minutes: 180
|
timeout-minutes: 180
|
||||||
env:
|
env:
|
||||||
VFLAGS: -cc gcc
|
VFLAGS: -cc gcc
|
||||||
|
@ -127,6 +129,7 @@ jobs:
|
||||||
|
|
||||||
tests-sanitize-address-clang:
|
tests-sanitize-address-clang:
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-20.04
|
||||||
|
if: github.event_name != 'push' || github.event.ref == 'refs/heads/master' || github.event.repository.full_name != 'vlang/v'
|
||||||
timeout-minutes: 180
|
timeout-minutes: 180
|
||||||
env:
|
env:
|
||||||
VFLAGS: -cc clang
|
VFLAGS: -cc clang
|
||||||
|
@ -158,6 +161,7 @@ jobs:
|
||||||
|
|
||||||
tests-sanitize-address-msvc:
|
tests-sanitize-address-msvc:
|
||||||
runs-on: windows-2019
|
runs-on: windows-2019
|
||||||
|
if: github.event_name != 'push' || github.event.ref == 'refs/heads/master' || github.event.repository.full_name != 'vlang/v'
|
||||||
timeout-minutes: 180
|
timeout-minutes: 180
|
||||||
env:
|
env:
|
||||||
VFLAGS: -cc msvc
|
VFLAGS: -cc msvc
|
||||||
|
@ -189,6 +193,7 @@ jobs:
|
||||||
|
|
||||||
tests-sanitize-address-gcc:
|
tests-sanitize-address-gcc:
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-20.04
|
||||||
|
if: github.event_name != 'push' || github.event.ref == 'refs/heads/master' || github.event.repository.full_name != 'vlang/v'
|
||||||
timeout-minutes: 180
|
timeout-minutes: 180
|
||||||
env:
|
env:
|
||||||
VFLAGS: -cc gcc
|
VFLAGS: -cc gcc
|
||||||
|
@ -220,9 +225,10 @@ jobs:
|
||||||
|
|
||||||
tests-sanitize-memory-clang:
|
tests-sanitize-memory-clang:
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-20.04
|
||||||
|
if: github.event_name != 'push' || github.event.ref == 'refs/heads/master' || github.event.repository.full_name != 'vlang/v'
|
||||||
timeout-minutes: 180
|
timeout-minutes: 180
|
||||||
env:
|
env:
|
||||||
VFLAGS: -cc clang
|
VFLAGS: -cc clang -gc none
|
||||||
VJOBS: 1
|
VJOBS: 1
|
||||||
VTEST_SHOW_START: 1
|
VTEST_SHOW_START: 1
|
||||||
steps:
|
steps:
|
||||||
|
|
|
@ -12,6 +12,7 @@ jobs:
|
||||||
run:
|
run:
|
||||||
name: Run
|
name: Run
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
if: github.event_name != 'push' || github.event.ref == 'refs/heads/master' || github.event.repository.full_name != 'vlang/v'
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v2
|
||||||
|
|
|
@ -16,7 +16,8 @@ jobs:
|
||||||
|
|
||||||
alpine-docker-musl-gcc:
|
alpine-docker-musl-gcc:
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-20.04
|
||||||
timeout-minutes: 121
|
if: github.event_name != 'push' || github.event.ref == 'refs/heads/master' || github.event.repository.full_name != 'vlang/v'
|
||||||
|
timeout-minutes: 181
|
||||||
container:
|
container:
|
||||||
# Alpine docker pre-built container
|
# Alpine docker pre-built container
|
||||||
image: thevlang/vlang:alpine-build
|
image: thevlang/vlang:alpine-build
|
||||||
|
@ -45,18 +46,19 @@ jobs:
|
||||||
- name: All code is formatted
|
- name: All code is formatted
|
||||||
run: ./v test-cleancode
|
run: ./v test-cleancode
|
||||||
|
|
||||||
- name: Test V fixed tests
|
- name: Run only essential tests
|
||||||
run: ./v test-self
|
run: VTEST_JUST_ESSENTIAL=1 ./v test-self
|
||||||
|
|
||||||
ubuntu-docker-musl:
|
ubuntu-docker-musl:
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-20.04
|
||||||
|
if: github.event_name != 'push' || github.event.ref == 'refs/heads/master' || github.event.repository.full_name != 'vlang/v'
|
||||||
timeout-minutes: 121
|
timeout-minutes: 121
|
||||||
container:
|
container:
|
||||||
image: thevlang/vlang:ubuntu-build
|
image: thevlang/vlang:ubuntu-build
|
||||||
env:
|
env:
|
||||||
V_CI_MUSL: 1
|
V_CI_MUSL: 1
|
||||||
V_CI_UBUNTU_MUSL: 1
|
V_CI_UBUNTU_MUSL: 1
|
||||||
VFLAGS: -cc musl-gcc
|
VFLAGS: -cc musl-gcc -gc none
|
||||||
volumes:
|
volumes:
|
||||||
- ${{github.workspace}}:/opt/vlang
|
- ${{github.workspace}}:/opt/vlang
|
||||||
|
|
||||||
|
|
|
@ -21,7 +21,7 @@ jobs:
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-20.04
|
||||||
timeout-minutes: 5
|
timeout-minutes: 5
|
||||||
env:
|
env:
|
||||||
MOPTIONS: --no-line-numbers --relative-paths --exclude /vlib/v/ --exclude /builtin/linux_bare/ --exclude /testdata/ --exclude /tests/ vlib/
|
MOPTIONS: --relative-paths --exclude /vlib/v/ --exclude /builtin/linux_bare/ --exclude /testdata/ --exclude /tests/
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
- name: Build V
|
- name: Build V
|
||||||
|
@ -35,14 +35,4 @@ jobs:
|
||||||
|
|
||||||
- name: Check against parent commit
|
- name: Check against parent commit
|
||||||
run: |
|
run: |
|
||||||
./v run cmd/tools/missdoc.v $MOPTIONS | sort > /tmp/n_v.txt
|
./v missdoc --diff $MOPTIONS pv/vlib vlib
|
||||||
cd pv/ && ../v run ../cmd/tools/missdoc.v $MOPTIONS | sort > /tmp/o_v.txt
|
|
||||||
count_new=$(cat /tmp/n_v.txt | wc -l)
|
|
||||||
count_old=$(cat /tmp/o_v.txt | wc -l)
|
|
||||||
echo "new pubs: $count_new | old pubs: $count_old"
|
|
||||||
echo "new head: $(head -n1 /tmp/n_v.txt)"
|
|
||||||
echo "old head: $(head -n1 /tmp/o_v.txt)"
|
|
||||||
if [[ ${count_new} -gt ${count_old} ]]; then
|
|
||||||
echo "The following $((count_new-count_old)) function(s) are introduced with no documentation:"
|
|
||||||
diff /tmp/n_v.txt /tmp/o_v.txt ## diff does exit(1) when files are different
|
|
||||||
fi
|
|
||||||
|
|
|
@ -10,6 +10,7 @@ on:
|
||||||
jobs:
|
jobs:
|
||||||
build-vc:
|
build-vc:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
if: github.event_name != 'push' || github.event.ref == 'refs/heads/master' || github.event.repository.full_name != 'vlang/v'
|
||||||
env:
|
env:
|
||||||
VREPO: github.com/vlang/vc.git
|
VREPO: github.com/vlang/vc.git
|
||||||
steps:
|
steps:
|
||||||
|
|
|
@ -11,6 +11,7 @@ on:
|
||||||
jobs:
|
jobs:
|
||||||
gg-regressions:
|
gg-regressions:
|
||||||
runs-on: ubuntu-18.04
|
runs-on: ubuntu-18.04
|
||||||
|
if: github.event_name != 'push' || github.event.ref == 'refs/heads/master' || github.event.repository.full_name != 'vlang/v'
|
||||||
timeout-minutes: 10
|
timeout-minutes: 10
|
||||||
env:
|
env:
|
||||||
VFLAGS: -cc tcc
|
VFLAGS: -cc tcc
|
||||||
|
@ -20,25 +21,24 @@ jobs:
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v2
|
||||||
|
|
||||||
- name: Build local v
|
- name: Build local v
|
||||||
run: make -j4
|
run: make
|
||||||
|
|
||||||
|
- uses: openrndr/setup-opengl@v1.1
|
||||||
|
|
||||||
- name: Setup dependencies
|
- name: Setup dependencies
|
||||||
run: |
|
run: |
|
||||||
|
# imagemagick : convert, mogrify
|
||||||
# xvfb : xvfb (installed by openrndr/setup-opengl@v1.1)
|
# xvfb : xvfb (installed by openrndr/setup-opengl@v1.1)
|
||||||
# openimageio-tools : idiff
|
# openimageio-tools : idiff
|
||||||
# libxcursor-dev libxi-dev : V gfx deps
|
# libxcursor-dev libxi-dev : V gfx deps
|
||||||
# mesa-common-dev : For headless rendering
|
# mesa-common-dev : For headless rendering
|
||||||
# freeglut3-dev : Fixes graphic apps compilation with tcc
|
# freeglut3-dev : Fixes graphic apps compilation with tcc
|
||||||
|
sudo apt-get update
|
||||||
sudo apt-get install imagemagick openimageio-tools mesa-common-dev libxcursor-dev libxi-dev freeglut3-dev
|
sudo apt-get install imagemagick openimageio-tools mesa-common-dev libxcursor-dev libxi-dev freeglut3-dev
|
||||||
wget https://raw.githubusercontent.com/tremby/imgur.sh/c98345d/imgur.sh
|
wget https://raw.githubusercontent.com/tremby/imgur.sh/c98345d/imgur.sh
|
||||||
|
git clone https://github.com/Larpon/gg-regression-images gg-regression-images
|
||||||
chmod +x ./imgur.sh
|
chmod +x ./imgur.sh
|
||||||
|
|
||||||
- uses: openrndr/setup-opengl@v1.1
|
|
||||||
- uses: actions/checkout@v2
|
|
||||||
with:
|
|
||||||
repository: Larpon/gg-regression-images
|
|
||||||
path: gg-regression-images
|
|
||||||
|
|
||||||
- name: Sample and compare
|
- name: Sample and compare
|
||||||
id: compare
|
id: compare
|
||||||
continue-on-error: true
|
continue-on-error: true
|
||||||
|
@ -50,4 +50,5 @@ jobs:
|
||||||
if: steps.compare.outcome != 'success'
|
if: steps.compare.outcome != 'success'
|
||||||
run: |
|
run: |
|
||||||
./imgur.sh /tmp/fail.png
|
./imgur.sh /tmp/fail.png
|
||||||
|
./imgur.sh /tmp/diff.png
|
||||||
exit 1
|
exit 1
|
|
@ -0,0 +1,36 @@
|
||||||
|
name: native backend CI
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
paths-ignore:
|
||||||
|
- "**.md"
|
||||||
|
pull_request:
|
||||||
|
paths-ignore:
|
||||||
|
- "**.md"
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: native-backend-ci-${{ github.event.pull_request.number || github.sha }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
native-backend:
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
os: [ubuntu-18.04, ubuntu-20.04, macos-10.15, macos-11, macos-12, windows-2016, windows-2019, windows-2022]
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
|
||||||
|
- name: Build V with make.bat
|
||||||
|
if: ${{ startsWith(matrix.os, 'windows') }}
|
||||||
|
run: |
|
||||||
|
.\make.bat
|
||||||
|
.\v.exe symlink -githubci
|
||||||
|
- name: Build V with make
|
||||||
|
if: ${{ !startsWith(matrix.os, 'windows') }}
|
||||||
|
run: |
|
||||||
|
make
|
||||||
|
./v symlink -githubci
|
||||||
|
|
||||||
|
- name: Test the native backend
|
||||||
|
run: v test vlib/v/gen/native/
|
|
@ -15,6 +15,7 @@ concurrency:
|
||||||
jobs:
|
jobs:
|
||||||
no-gpl-by-accident:
|
no-gpl-by-accident:
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-20.04
|
||||||
|
if: github.event_name != 'push' || github.event.ref == 'refs/heads/master' || github.event.repository.full_name != 'vlang/v'
|
||||||
timeout-minutes: 15
|
timeout-minutes: 15
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
|
@ -24,6 +25,7 @@ jobs:
|
||||||
|
|
||||||
code-formatting:
|
code-formatting:
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-20.04
|
||||||
|
if: github.event_name != 'push' || github.event.ref == 'refs/heads/master' || github.event.repository.full_name != 'vlang/v'
|
||||||
timeout-minutes: 15
|
timeout-minutes: 15
|
||||||
env:
|
env:
|
||||||
VFLAGS: -cc gcc
|
VFLAGS: -cc gcc
|
||||||
|
@ -40,6 +42,7 @@ jobs:
|
||||||
|
|
||||||
performance-regressions:
|
performance-regressions:
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-20.04
|
||||||
|
if: github.event_name != 'push' || github.event.ref == 'refs/heads/master' || github.event.repository.full_name != 'vlang/v'
|
||||||
timeout-minutes: 15
|
timeout-minutes: 15
|
||||||
env:
|
env:
|
||||||
VFLAGS: -cc gcc
|
VFLAGS: -cc gcc
|
||||||
|
@ -64,6 +67,7 @@ jobs:
|
||||||
|
|
||||||
misc-tooling:
|
misc-tooling:
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-20.04
|
||||||
|
if: github.event_name != 'push' || github.event.ref == 'refs/heads/master' || github.event.repository.full_name != 'vlang/v'
|
||||||
timeout-minutes: 121
|
timeout-minutes: 121
|
||||||
env:
|
env:
|
||||||
VFLAGS: -cc tcc -no-retry-compilation
|
VFLAGS: -cc tcc -no-retry-compilation
|
||||||
|
@ -85,7 +89,6 @@ jobs:
|
||||||
- name: g++ version
|
- name: g++ version
|
||||||
run: g++-9 --version
|
run: g++-9 --version
|
||||||
- name: V self compilation with g++
|
- 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
|
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++
|
## - name: Running tests with g++
|
||||||
## run: ./v -cc g++-9 test-self
|
## run: ./v -cc g++-9 test-self
|
||||||
|
@ -94,7 +97,6 @@ jobs:
|
||||||
run: ./v -autofree -o v2 cmd/v ## NB: this does not mean it runs, but at least keeps it from regressing
|
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
|
- name: Shader examples can be build
|
||||||
continue-on-error: true
|
|
||||||
run: |
|
run: |
|
||||||
wget https://github.com/floooh/sokol-tools-bin/raw/33d2e4cc26088c6c28eaef5467990f8940d15aab/bin/linux/sokol-shdc
|
wget https://github.com/floooh/sokol-tools-bin/raw/33d2e4cc26088c6c28eaef5467990f8940d15aab/bin/linux/sokol-shdc
|
||||||
chmod +x ./sokol-shdc
|
chmod +x ./sokol-shdc
|
||||||
|
@ -112,6 +114,7 @@ jobs:
|
||||||
|
|
||||||
parser-silent:
|
parser-silent:
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-20.04
|
||||||
|
if: github.event_name != 'push' || github.event.ref == 'refs/heads/master' || github.event.repository.full_name != 'vlang/v'
|
||||||
timeout-minutes: 121
|
timeout-minutes: 121
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
|
|
|
@ -16,6 +16,7 @@ jobs:
|
||||||
|
|
||||||
space-paths-linux:
|
space-paths-linux:
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-20.04
|
||||||
|
if: github.event_name != 'push' || github.event.ref == 'refs/heads/master' || github.event.repository.full_name != 'vlang/v'
|
||||||
timeout-minutes: 30
|
timeout-minutes: 30
|
||||||
env:
|
env:
|
||||||
MY_V_PATH: '你好 my $path, @с интервали'
|
MY_V_PATH: '你好 my $path, @с интервали'
|
||||||
|
@ -41,6 +42,7 @@ jobs:
|
||||||
|
|
||||||
space-paths-macos:
|
space-paths-macos:
|
||||||
runs-on: macOS-latest
|
runs-on: macOS-latest
|
||||||
|
if: github.event_name != 'push' || github.event.ref == 'refs/heads/master' || github.event.repository.full_name != 'vlang/v'
|
||||||
timeout-minutes: 30
|
timeout-minutes: 30
|
||||||
env:
|
env:
|
||||||
MY_V_PATH: '你好 my $path, @с интервали'
|
MY_V_PATH: '你好 my $path, @с интервали'
|
||||||
|
@ -69,6 +71,7 @@ jobs:
|
||||||
|
|
||||||
space-paths-windows:
|
space-paths-windows:
|
||||||
runs-on: windows-2022
|
runs-on: windows-2022
|
||||||
|
if: github.event_name != 'push' || github.event.ref == 'refs/heads/master' || github.event.repository.full_name != 'vlang/v'
|
||||||
timeout-minutes: 30
|
timeout-minutes: 30
|
||||||
env:
|
env:
|
||||||
MY_V_PATH: 'path with some $punctuation, and some spaces'
|
MY_V_PATH: 'path with some $punctuation, and some spaces'
|
||||||
|
|
|
@ -2,57 +2,56 @@ name: Periodic
|
||||||
|
|
||||||
on:
|
on:
|
||||||
schedule:
|
schedule:
|
||||||
- cron: '0 */2 * * *'
|
- cron: '0 */6 * * *'
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
network-tests-ubuntu:
|
network-tests-ubuntu:
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-20.04
|
||||||
timeout-minutes: 30
|
timeout-minutes: 30
|
||||||
env:
|
env:
|
||||||
V_CI_PERIODIC: 1
|
V_CI_PERIODIC: 1
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
- name: Install dependencies
|
- name: Install dependencies 1
|
||||||
run: sudo apt-get install --quiet -y libssl-dev sqlite3 libsqlite3-dev valgrind
|
run: sudo apt-get install --quiet -y libssl-dev sqlite3 libsqlite3-dev
|
||||||
- name: Build v
|
- name: Build v
|
||||||
run: make -j4
|
run: make
|
||||||
- name: Symlink V
|
- name: Symlink V
|
||||||
run: sudo ./v symlink
|
run: sudo ./v symlink
|
||||||
## - name: Run network tests
|
## - name: Run network tests
|
||||||
## run: ./v -d network test vlib/net
|
## run: ./v -d network test vlib/net
|
||||||
|
|
||||||
|
|
||||||
network-tests-macos:
|
network-tests-macos:
|
||||||
runs-on: macOS-latest
|
runs-on: macOS-latest
|
||||||
timeout-minutes: 30
|
timeout-minutes: 30
|
||||||
env:
|
env:
|
||||||
V_CI_PERIODIC: 1
|
V_CI_PERIODIC: 1
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
- name: Setup openssl library path
|
- name: Setup openssl library path
|
||||||
run: export LIBRARY_PATH="$LIBRARY_PATH:/usr/local/opt/openssl/lib/"
|
run: export LIBRARY_PATH="$LIBRARY_PATH:/usr/local/opt/openssl/lib/"
|
||||||
- name: Build V
|
- name: Build V
|
||||||
run: make -j4
|
run: make
|
||||||
- name: Symlink V
|
- name: Symlink V
|
||||||
run: sudo ./v symlink
|
run: sudo ./v symlink
|
||||||
- name: Ensure thirdparty/cJSON/cJSON.o is compiled, before running tests.
|
- name: Ensure thirdparty/cJSON/cJSON.o is compiled, before running tests.
|
||||||
run: ./v examples/json.v
|
run: ./v examples/json.v
|
||||||
## - name: Run network tests
|
## - name: Run network tests
|
||||||
## run: ./v -d network test vlib/net
|
## run: ./v -d network test vlib/net
|
||||||
|
|
||||||
|
|
||||||
network-windows-msvc:
|
network-windows-msvc:
|
||||||
runs-on: windows-2019
|
runs-on: windows-2019
|
||||||
timeout-minutes: 30
|
timeout-minutes: 30
|
||||||
env:
|
env:
|
||||||
V_CI_PERIODIC: 1
|
V_CI_PERIODIC: 1
|
||||||
VFLAGS: -cc msvc
|
VFLAGS: -cc msvc
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
- name: Build
|
- name: Build
|
||||||
run: |
|
run: |
|
||||||
echo %VFLAGS%
|
echo %VFLAGS%
|
||||||
echo $VFLAGS
|
echo $VFLAGS
|
||||||
.\make.bat -msvc
|
.\make.bat -msvc
|
||||||
## - name: Run network tests
|
## - name: Run network tests
|
||||||
## run: .\v.exe -d network test vlib/net
|
## run: .\v.exe -d network test vlib/net
|
||||||
|
|
|
@ -11,6 +11,7 @@ on:
|
||||||
jobs:
|
jobs:
|
||||||
v-compiles-sdl-examples:
|
v-compiles-sdl-examples:
|
||||||
runs-on: ubuntu-18.04
|
runs-on: ubuntu-18.04
|
||||||
|
if: github.event_name != 'push' || github.event.ref == 'refs/heads/master' || github.event.repository.full_name != 'vlang/v'
|
||||||
timeout-minutes: 30
|
timeout-minutes: 30
|
||||||
env:
|
env:
|
||||||
VFLAGS: -cc tcc
|
VFLAGS: -cc tcc
|
||||||
|
|
|
@ -11,6 +11,7 @@ on:
|
||||||
jobs:
|
jobs:
|
||||||
toml-module-pass-external-test-suites:
|
toml-module-pass-external-test-suites:
|
||||||
runs-on: ubuntu-18.04
|
runs-on: ubuntu-18.04
|
||||||
|
if: github.event_name != 'push' || github.event.ref == 'refs/heads/master' || github.event.repository.full_name != 'vlang/v'
|
||||||
timeout-minutes: 30
|
timeout-minutes: 30
|
||||||
env:
|
env:
|
||||||
TOML_BS_TESTS_PATH: vlib/toml/tests/testdata/burntsushi/toml-test
|
TOML_BS_TESTS_PATH: vlib/toml/tests/testdata/burntsushi/toml-test
|
||||||
|
|
|
@ -9,12 +9,13 @@ on:
|
||||||
- "**.md"
|
- "**.md"
|
||||||
|
|
||||||
concurrency:
|
concurrency:
|
||||||
group: build-other-${{ github.event.pull_request.number || github.sha }}
|
group: build-v-apps-and-modules-${{ github.event.pull_request.number || github.sha }}
|
||||||
cancel-in-progress: true
|
cancel-in-progress: true
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
v-apps-compile:
|
v-apps-compile:
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-20.04
|
||||||
|
if: github.event_name != 'push' || github.event.ref == 'refs/heads/master' || github.event.repository.full_name != 'vlang/v'
|
||||||
timeout-minutes: 121
|
timeout-minutes: 121
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
|
@ -24,34 +25,94 @@ jobs:
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: |
|
run: |
|
||||||
sudo apt-get update
|
sudo apt-get update
|
||||||
sudo apt-get install --quiet -y libgc-dev
|
sudo apt-get install --quiet -y libgc-dev libsodium-dev libssl-dev sqlite3 libsqlite3-dev valgrind libfreetype6-dev libxi-dev libxcursor-dev libgl-dev xfonts-75dpi xfonts-base
|
||||||
sudo apt-get install --quiet -y libsodium-dev libssl-dev sqlite3 libsqlite3-dev valgrind
|
sudo apt-get install --quiet -y --no-install-recommends gfortran liblapacke-dev libopenblas-dev
|
||||||
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)
|
- name: Build V Language Server (VLS)
|
||||||
continue-on-error: true
|
|
||||||
run: |
|
run: |
|
||||||
echo "Clone VLS"
|
echo "Clone VLS"
|
||||||
git clone --depth 1 https://github.com/vlang/vls
|
git clone --depth 1 https://github.com/vlang/vls /tmp/vls
|
||||||
echo "Build VLS"
|
echo "Build VLS"
|
||||||
pushd vls; v cmd/vls ; popd
|
v /tmp/vls/cmd/vls
|
||||||
echo "Build VLS with -prod"
|
echo "Build VLS with -prod"
|
||||||
pushd vls; v -prod cmd/vls; popd
|
v -prod /tmp/vls/cmd/vls
|
||||||
echo "Build VLS with -gc boehm -skip-unused"
|
echo "Build VLS with -gc boehm -skip-unused"
|
||||||
pushd vls; v -gc boehm -skip-unused cmd/vls; popd
|
v -gc boehm -skip-unused /tmp/vls/cmd/vls
|
||||||
|
|
||||||
|
- name: Build V Coreutils
|
||||||
|
run: |
|
||||||
|
echo "Clone Coreutils"
|
||||||
|
git clone --depth 1 https://github.com/vlang/coreutils /tmp/coreutils
|
||||||
|
echo "Build Coreutils"
|
||||||
|
cd /tmp/coreutils; make
|
||||||
|
|
||||||
|
- name: Build VAB
|
||||||
|
run: |
|
||||||
|
echo "Install VAB"
|
||||||
|
v install vab
|
||||||
|
echo "Build vab"
|
||||||
|
v ~/.vmodules/vab
|
||||||
|
echo "Build vab with -gc boehm -skip-unused"
|
||||||
|
v -gc boehm -skip-unused ~/.vmodules/vab
|
||||||
|
|
||||||
|
- name: Build Gitly
|
||||||
|
run: |
|
||||||
|
echo "Install markdown"
|
||||||
|
v install markdown
|
||||||
|
echo "Clone Gitly"
|
||||||
|
git clone https://github.com/vlang/gitly /tmp/gitly
|
||||||
|
echo "Build Gitly"
|
||||||
|
v /tmp/gitly
|
||||||
|
echo "Build Gitly with -autofree"
|
||||||
|
v -autofree /tmp/gitly
|
||||||
|
echo "Run first_run.v"
|
||||||
|
v run /tmp/gitly/tests/first_run.v
|
||||||
|
# /tmp/gitly/gitly -ci_run
|
||||||
|
|
||||||
|
- name: Build libsodium
|
||||||
|
run: |
|
||||||
|
echo "Install the libsodium wrapper"
|
||||||
|
v install libsodium
|
||||||
|
echo "Test libsodium"
|
||||||
|
VJOBS=1 v test ~/.vmodules/libsodium
|
||||||
|
|
||||||
|
- name: Build VEX
|
||||||
|
run: |
|
||||||
|
echo "Install Vex"
|
||||||
|
v install 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
|
||||||
|
run: |
|
||||||
|
echo "Clone Go2V"
|
||||||
|
git clone --depth=1 https://github.com/vlang/go2v /tmp/go2v/
|
||||||
|
echo "Build Go2V"
|
||||||
|
v /tmp/go2v/
|
||||||
|
echo "Run Go2V tests"
|
||||||
|
VJOBS=1 v -stats test /tmp/go2v/
|
||||||
|
|
||||||
|
- name: Build vlang/pdf
|
||||||
|
run: |
|
||||||
|
v install pdf
|
||||||
|
echo "PDF examples should compile"
|
||||||
|
v should-compile-all ~/.vmodules/pdf/examples
|
||||||
|
|
||||||
|
- name: Install UI through VPM
|
||||||
|
run: |
|
||||||
|
echo "Official VPM modules should be installable"
|
||||||
|
v install ui
|
||||||
|
echo "Examples of UI should compile"
|
||||||
|
v ~/.vmodules/ui/examples/build_examples.vsh
|
||||||
|
|
||||||
- name: Build VSL
|
- name: Build VSL
|
||||||
continue-on-error: true
|
|
||||||
run: |
|
run: |
|
||||||
git clone --depth 1 https://github.com/vlang/vsl ~/.vmodules/vsl
|
echo "Install VSL"
|
||||||
sudo apt-get install --quiet -y --no-install-recommends gfortran liblapacke-dev libopenblas-dev libgc-dev
|
v install vsl
|
||||||
echo "Execute Tests using Pure V Backend"
|
echo "Execute Tests using Pure V Backend"
|
||||||
~/.vmodules/vsl/bin/test
|
~/.vmodules/vsl/bin/test
|
||||||
echo "Execute Tests using Pure V Backend with Pure V Math"
|
echo "Execute Tests using Pure V Backend with Pure V Math"
|
||||||
|
@ -62,12 +123,10 @@ jobs:
|
||||||
~/.vmodules/vsl/bin/test --use-cblas --use-gc boehm
|
~/.vmodules/vsl/bin/test --use-cblas --use-gc boehm
|
||||||
|
|
||||||
- name: Build VTL
|
- name: Build VTL
|
||||||
continue-on-error: true
|
|
||||||
run: |
|
run: |
|
||||||
echo "Clone VTL"
|
echo "Install VTL"
|
||||||
git clone --depth 1 https://github.com/vlang/vtl ~/.vmodules/vtl
|
v install vtl
|
||||||
echo "Install dependencies"
|
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"
|
echo "Execute Tests using Pure V Backend"
|
||||||
~/.vmodules/vtl/bin/test
|
~/.vmodules/vtl/bin/test
|
||||||
echo "Execute Tests using Pure V Backend with Pure V Math"
|
echo "Execute Tests using Pure V Backend with Pure V Math"
|
||||||
|
@ -76,70 +135,3 @@ jobs:
|
||||||
~/.vmodules/vtl/bin/test --use-gc boehm
|
~/.vmodules/vtl/bin/test --use-gc boehm
|
||||||
echo "Execute Tests using Pure V Backend with Pure V Math and Garbage Collection enabled"
|
echo "Execute Tests using Pure V Backend with Pure V Math and Garbage Collection enabled"
|
||||||
~/.vmodules/vtl/bin/test --use-cblas --use-gc boehm
|
~/.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
|
|
||||||
|
|
|
@ -11,6 +11,7 @@ on:
|
||||||
jobs:
|
jobs:
|
||||||
vab-compiles-v-examples:
|
vab-compiles-v-examples:
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-20.04
|
||||||
|
if: github.event_name != 'push' || github.event.ref == 'refs/heads/master' || github.event.repository.full_name != 'vlang/v'
|
||||||
timeout-minutes: 121
|
timeout-minutes: 121
|
||||||
env:
|
env:
|
||||||
VAB_FLAGS: --api 30 --build-tools 29.0.0 -v 3
|
VAB_FLAGS: --api 30 --build-tools 29.0.0 -v 3
|
||||||
|
@ -24,20 +25,14 @@ jobs:
|
||||||
- name: Build V
|
- name: Build V
|
||||||
run: make && sudo ./v symlink
|
run: make && sudo ./v symlink
|
||||||
|
|
||||||
- name: Checkout vab
|
- name: Install vab
|
||||||
uses: actions/checkout@v2
|
|
||||||
with:
|
|
||||||
repository: vlang/vab
|
|
||||||
path: vab
|
|
||||||
|
|
||||||
- name: Build vab
|
|
||||||
run: |
|
run: |
|
||||||
cd vab
|
v install vab
|
||||||
v -g vab.v
|
v -g ~/.vmodules/vab
|
||||||
sudo ln -s $(pwd)/vab /usr/local/bin/vab
|
sudo ln -s ~/.vmodules/vab/vab /usr/local/bin/vab
|
||||||
|
|
||||||
- name: Run tests
|
- name: Run tests
|
||||||
run: v test vab
|
run: v test ~/.vmodules/vab
|
||||||
|
|
||||||
- name: Run vab --help
|
- name: Run vab --help
|
||||||
run: vab --help
|
run: vab --help
|
||||||
|
|
|
@ -13,6 +13,9 @@ on:
|
||||||
jobs:
|
jobs:
|
||||||
vinix-build:
|
vinix-build:
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-20.04
|
||||||
|
if: github.event_name != 'push' || github.event.ref == 'refs/heads/master' || github.event.repository.full_name != 'vlang/v'
|
||||||
|
env:
|
||||||
|
VFLAGS: -gc none
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,7 @@ on:
|
||||||
jobs:
|
jobs:
|
||||||
websocket_tests:
|
websocket_tests:
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-20.04
|
||||||
|
if: github.event_name != 'push' || github.event.ref == 'refs/heads/master' || github.event.repository.full_name != 'vlang/v'
|
||||||
timeout-minutes: 121
|
timeout-minutes: 121
|
||||||
env:
|
env:
|
||||||
VFLAGS: -cc tcc -no-retry-compilation
|
VFLAGS: -cc tcc -no-retry-compilation
|
||||||
|
|
|
@ -0,0 +1,61 @@
|
||||||
|
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
|
||||||
|
|
||||||
|
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,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
|
|
@ -191,7 +191,6 @@ to create a copy of the compiler rather than replacing it with `v self`.
|
||||||
| `debug_codegen` | Prints automatically generated V code during the scanning phase |
|
| `debug_codegen` | Prints automatically generated V code during the scanning phase |
|
||||||
| `debug_interface_table` | Prints generated interfaces during C generation |
|
| `debug_interface_table` | Prints generated interfaces during C generation |
|
||||||
| `debug_interface_type_implements` | Prints debug information when checking that a type implements in interface |
|
| `debug_interface_type_implements` | Prints debug information when checking that a type implements in interface |
|
||||||
| `debug_embed_file_in_prod` | Prints debug information about the embedded files with `$embed_file('somefile')` |
|
|
||||||
| `print_vweb_template_expansions` | Prints vweb compiled HTML files |
|
| `print_vweb_template_expansions` | Prints vweb compiled HTML files |
|
||||||
| `time_checking` | Prints the time spent checking files and other related information |
|
| `time_checking` | Prints the time spent checking files and other related information |
|
||||||
| `time_parsing` | Prints the time spent parsing files and other related information |
|
| `time_parsing` | Prints the time spent parsing files and other related information |
|
||||||
|
@ -204,3 +203,4 @@ to create a copy of the compiler rather than replacing it with `v self`.
|
||||||
| `trace_thirdparty_obj_files` | Prints details about built thirdparty obj files |
|
| `trace_thirdparty_obj_files` | Prints details about built thirdparty obj files |
|
||||||
| `trace_usecache` | Prints details when -usecache is used |
|
| `trace_usecache` | Prints details when -usecache is used |
|
||||||
| `trace_embed_file` | Prints details when $embed_file is used |
|
| `trace_embed_file` | Prints details when $embed_file is used |
|
||||||
|
| `embed_only_metadata` | Embed only the metadata for the file(s) with `$embed_file('somefile')`; faster; for development, *not* distribution |
|
||||||
|
|
|
@ -0,0 +1,33 @@
|
||||||
|
FROM alpine:3.16
|
||||||
|
|
||||||
|
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 -gc none
|
||||||
|
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 \
|
||||||
|
diffutils \
|
||||||
|
mandoc
|
||||||
|
|
||||||
|
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"]
|
|
@ -5,7 +5,7 @@ TMPDIR ?= /tmp
|
||||||
VROOT ?= .
|
VROOT ?= .
|
||||||
VC ?= ./vc
|
VC ?= ./vc
|
||||||
V ?= ./v
|
V ?= ./v
|
||||||
VCREPO ?= https://github.com/vlang/vc
|
VCREPO ?= https://git.rustybever.be/vieter/vc
|
||||||
TCCREPO ?= https://github.com/vlang/tccbin
|
TCCREPO ?= https://github.com/vlang/tccbin
|
||||||
|
|
||||||
VCFILE := v.c
|
VCFILE := v.c
|
||||||
|
@ -28,6 +28,9 @@ endif
|
||||||
ifeq ($(_SYS),Linux)
|
ifeq ($(_SYS),Linux)
|
||||||
LINUX := 1
|
LINUX := 1
|
||||||
TCCOS := linux
|
TCCOS := linux
|
||||||
|
ifneq ($(shell ldd /bin/ls | grep musl),)
|
||||||
|
TCCOS := linuxmusl
|
||||||
|
endif
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ifeq ($(_SYS),Darwin)
|
ifeq ($(_SYS),Darwin)
|
||||||
|
@ -113,7 +116,7 @@ endif
|
||||||
|
|
||||||
check_for_working_tcc:
|
check_for_working_tcc:
|
||||||
@$(TMPTCC)/tcc.exe --version > /dev/null 2> /dev/null || echo "The executable '$(TMPTCC)/tcc.exe' does not work."
|
@$(TMPTCC)/tcc.exe --version > /dev/null 2> /dev/null || echo "The executable '$(TMPTCC)/tcc.exe' does not work."
|
||||||
|
|
||||||
fresh_vc:
|
fresh_vc:
|
||||||
rm -rf $(VC)
|
rm -rf $(VC)
|
||||||
$(GITFASTCLONE) $(VCREPO) $(VC)
|
$(GITFASTCLONE) $(VCREPO) $(VC)
|
||||||
|
|
2
Makefile
2
Makefile
|
@ -7,7 +7,7 @@ LDFLAGS ?=
|
||||||
|
|
||||||
all:
|
all:
|
||||||
rm -rf vc/
|
rm -rf vc/
|
||||||
git clone --depth 1 --quiet https://github.com/vlang/vc
|
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)
|
$(CC) $(CFLAGS) -std=gnu11 -w -o v1 vc/v.c -lm -lexecinfo -lpthread $(LDFLAGS)
|
||||||
./v1 -no-parallel -o v2 $(VFLAGS) cmd/v
|
./v1 -no-parallel -o v2 $(VFLAGS) cmd/v
|
||||||
./v2 -o v $(VFLAGS) cmd/v
|
./v2 -o v $(VFLAGS) cmd/v
|
||||||
|
|
|
@ -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"
|
||||||
|
}
|
|
@ -0,0 +1,67 @@
|
||||||
|
import os
|
||||||
|
import time
|
||||||
|
import v.ast
|
||||||
|
import v.pref
|
||||||
|
import v.parser
|
||||||
|
import v.errors
|
||||||
|
import v.scanner
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
files := os.args#[1..]
|
||||||
|
if files.len > 0 && files[0].starts_with('@') {
|
||||||
|
lst_path := files[0].all_after('@')
|
||||||
|
listed_files := os.read_file(lst_path)?.split('\n')
|
||||||
|
process_files(listed_files)?
|
||||||
|
return
|
||||||
|
}
|
||||||
|
process_files(files)?
|
||||||
|
}
|
||||||
|
|
||||||
|
fn process_files(files []string) ? {
|
||||||
|
mut table := ast.new_table()
|
||||||
|
mut pref := pref.new_preferences()
|
||||||
|
pref.is_fmt = true
|
||||||
|
pref.skip_warnings = true
|
||||||
|
pref.output_mode = .silent
|
||||||
|
mut sw := time.new_stopwatch()
|
||||||
|
mut total_us := i64(0)
|
||||||
|
mut total_bytes := i64(0)
|
||||||
|
mut total_tokens := i64(0)
|
||||||
|
for f in files {
|
||||||
|
if f == '' {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if f.ends_with('_test.v') {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
// do not measure the scanning, but only the parsing:
|
||||||
|
mut p := new_parser(f, .skip_comments, table, pref)
|
||||||
|
///
|
||||||
|
sw.restart()
|
||||||
|
_ := p.parse()
|
||||||
|
f_us := sw.elapsed().microseconds()
|
||||||
|
///
|
||||||
|
total_us += f_us
|
||||||
|
total_bytes += p.scanner.text.len
|
||||||
|
total_tokens += p.scanner.all_tokens.len
|
||||||
|
println('${f_us:10}us ${p.scanner.all_tokens.len:10} ${p.scanner.text.len:10} ${(f64(p.scanner.text.len) / p.scanner.all_tokens.len):7.3} ${p.errors.len:4} $f')
|
||||||
|
}
|
||||||
|
println('${total_us:10}us ${total_tokens:10} ${total_bytes:10} ${(f64(total_tokens) / total_bytes):7.3} | speed: ${(f64(total_bytes) / total_us):2.5f} MB/s')
|
||||||
|
}
|
||||||
|
|
||||||
|
fn new_parser(path string, comments_mode scanner.CommentsMode, table &ast.Table, pref &pref.Preferences) &parser.Parser {
|
||||||
|
mut p := &parser.Parser{
|
||||||
|
scanner: scanner.new_scanner_file(path, comments_mode, pref) or { panic(err) }
|
||||||
|
comments_mode: comments_mode
|
||||||
|
table: table
|
||||||
|
pref: pref
|
||||||
|
scope: &ast.Scope{
|
||||||
|
start_pos: 0
|
||||||
|
parent: table.global_scope
|
||||||
|
}
|
||||||
|
errors: []errors.Error{}
|
||||||
|
warnings: []errors.Warning{}
|
||||||
|
}
|
||||||
|
p.set_path(path)
|
||||||
|
return p
|
||||||
|
}
|
|
@ -0,0 +1,42 @@
|
||||||
|
import os
|
||||||
|
import time
|
||||||
|
import v.scanner
|
||||||
|
import v.pref
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
files := os.args#[1..]
|
||||||
|
if files.len > 0 && files[0].starts_with('@') {
|
||||||
|
lst_path := files[0].all_after('@')
|
||||||
|
listed_files := os.read_file(lst_path)?.split('\n')
|
||||||
|
process_files(listed_files)?
|
||||||
|
return
|
||||||
|
}
|
||||||
|
process_files(files)?
|
||||||
|
}
|
||||||
|
|
||||||
|
fn process_files(files []string) ? {
|
||||||
|
mut pref := pref.new_preferences()
|
||||||
|
pref.is_fmt = true
|
||||||
|
pref.skip_warnings = true
|
||||||
|
pref.output_mode = .silent
|
||||||
|
mut sw := time.new_stopwatch()
|
||||||
|
mut total_us := i64(0)
|
||||||
|
mut total_bytes := i64(0)
|
||||||
|
mut total_tokens := i64(0)
|
||||||
|
for f in files {
|
||||||
|
if f == '' {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if f.ends_with('_test.v') {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
sw.restart()
|
||||||
|
s := scanner.new_scanner_file(f, .skip_comments, pref)?
|
||||||
|
f_us := sw.elapsed().microseconds()
|
||||||
|
total_us += f_us
|
||||||
|
total_bytes += s.text.len
|
||||||
|
total_tokens += s.all_tokens.len
|
||||||
|
println('${f_us:10}us ${s.all_tokens.len:10} ${s.text.len:10} ${(f64(s.text.len) / s.all_tokens.len):7.3f} $f')
|
||||||
|
}
|
||||||
|
println('${total_us:10}us ${total_tokens:10} ${total_bytes:10} ${(f64(total_tokens) / total_bytes):7.3f} | speed: ${(f64(total_bytes) / total_us):2.5f} MB/s')
|
||||||
|
}
|
|
@ -24,6 +24,7 @@ pub fn cprint(omessage string) {
|
||||||
message = term.cyan(message)
|
message = term.cyan(message)
|
||||||
}
|
}
|
||||||
print(message)
|
print(message)
|
||||||
|
flush_stdout()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn cprint_strong(omessage string) {
|
pub fn cprint_strong(omessage string) {
|
||||||
|
@ -32,16 +33,19 @@ pub fn cprint_strong(omessage string) {
|
||||||
message = term.bright_green(message)
|
message = term.bright_green(message)
|
||||||
}
|
}
|
||||||
print(message)
|
print(message)
|
||||||
|
flush_stdout()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn cprintln(omessage string) {
|
pub fn cprintln(omessage string) {
|
||||||
cprint(omessage)
|
cprint(omessage)
|
||||||
println('')
|
println('')
|
||||||
|
flush_stdout()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn cprintln_strong(omessage string) {
|
pub fn cprintln_strong(omessage string) {
|
||||||
cprint_strong(omessage)
|
cprint_strong(omessage)
|
||||||
println('')
|
println('')
|
||||||
|
flush_stdout()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn verbose_trace(label string, message string) {
|
pub fn verbose_trace(label string, message string) {
|
||||||
|
|
|
@ -123,6 +123,7 @@ pub fn (mut ts TestSession) print_messages() {
|
||||||
// progress mode, the last line is rewritten many times:
|
// progress mode, the last line is rewritten many times:
|
||||||
if is_ok && !ts.silent_mode {
|
if is_ok && !ts.silent_mode {
|
||||||
print('\r$empty\r$msg')
|
print('\r$empty\r$msg')
|
||||||
|
flush_stdout()
|
||||||
} else {
|
} else {
|
||||||
// the last \n is needed, so SKIP/FAIL messages
|
// the last \n is needed, so SKIP/FAIL messages
|
||||||
// will not get overwritten by the OK ones
|
// will not get overwritten by the OK ones
|
||||||
|
@ -560,6 +561,7 @@ pub fn eheader(msg string) {
|
||||||
|
|
||||||
pub fn header(msg string) {
|
pub fn header(msg string) {
|
||||||
println(term.header_left(msg, '-'))
|
println(term.header_left(msg, '-'))
|
||||||
|
flush_stdout()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn setup_new_vtmp_folder() string {
|
pub fn setup_new_vtmp_folder() string {
|
||||||
|
|
|
@ -200,8 +200,13 @@ fn (mut context Context) parse_options() ? {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn flushed_print(s string) {
|
||||||
|
print(s)
|
||||||
|
flush_stdout()
|
||||||
|
}
|
||||||
|
|
||||||
fn (mut context Context) clear_line() {
|
fn (mut context Context) clear_line() {
|
||||||
print(context.cline)
|
flushed_print(context.cline)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (mut context Context) expand_all_commands(commands []string) []string {
|
fn (mut context Context) expand_all_commands(commands []string) []string {
|
||||||
|
@ -247,7 +252,7 @@ fn (mut context Context) run() {
|
||||||
println('Series: ${si:4}/${context.series:-4}, command: $cmd')
|
println('Series: ${si:4}/${context.series:-4}, command: $cmd')
|
||||||
if context.warmup > 0 && run_warmups < context.commands.len {
|
if context.warmup > 0 && run_warmups < context.commands.len {
|
||||||
for i in 1 .. context.warmup + 1 {
|
for i in 1 .. context.warmup + 1 {
|
||||||
print('${context.cgoback}warming up run: ${i:4}/${context.warmup:-4} for ${cmd:-50s} took ${duration:6} ms ...')
|
flushed_print('${context.cgoback}warming up run: ${i:4}/${context.warmup:-4} for ${cmd:-50s} took ${duration:6} ms ...')
|
||||||
mut sw := time.new_stopwatch()
|
mut sw := time.new_stopwatch()
|
||||||
res := os.execute(cmd)
|
res := os.execute(cmd)
|
||||||
if res.exit_code != 0 {
|
if res.exit_code != 0 {
|
||||||
|
@ -260,9 +265,9 @@ fn (mut context Context) run() {
|
||||||
context.clear_line()
|
context.clear_line()
|
||||||
for i in 1 .. (context.count + 1) {
|
for i in 1 .. (context.count + 1) {
|
||||||
avg := f64(sum) / f64(i)
|
avg := f64(sum) / f64(i)
|
||||||
print('${context.cgoback}Average: ${avg:9.3f}ms | run: ${i:4}/${context.count:-4} | took ${duration:6} ms')
|
flushed_print('${context.cgoback}Average: ${avg:9.3f}ms | run: ${i:4}/${context.count:-4} | took ${duration:6} ms')
|
||||||
if context.show_output {
|
if context.show_output {
|
||||||
print(' | result: ${oldres:s}')
|
flushed_print(' | result: ${oldres:s}')
|
||||||
}
|
}
|
||||||
mut sw := time.new_stopwatch()
|
mut sw := time.new_stopwatch()
|
||||||
res := scripting.exec(cmd) or { continue }
|
res := scripting.exec(cmd) or { continue }
|
||||||
|
@ -288,7 +293,7 @@ fn (mut context Context) run() {
|
||||||
context.results[icmd].atiming = new_aints(context.results[icmd].timings, context.nmins,
|
context.results[icmd].atiming = new_aints(context.results[icmd].timings, context.nmins,
|
||||||
context.nmaxs)
|
context.nmaxs)
|
||||||
context.clear_line()
|
context.clear_line()
|
||||||
print(context.cgoback)
|
flushed_print(context.cgoback)
|
||||||
mut m := map[string][]int{}
|
mut m := map[string][]int{}
|
||||||
ioutputs := context.results[icmd].outputs
|
ioutputs := context.results[icmd].outputs
|
||||||
for o in ioutputs {
|
for o in ioutputs {
|
||||||
|
@ -358,7 +363,7 @@ fn (mut context Context) show_diff_summary() {
|
||||||
println('context: $context')
|
println('context: $context')
|
||||||
}
|
}
|
||||||
if int(base) > context.fail_on_maxtime {
|
if int(base) > context.fail_on_maxtime {
|
||||||
print(performance_regression_label)
|
flushed_print(performance_regression_label)
|
||||||
println('average time: ${base:6.1f} ms > $context.fail_on_maxtime ms threshold.')
|
println('average time: ${base:6.1f} ms > $context.fail_on_maxtime ms threshold.')
|
||||||
exit(2)
|
exit(2)
|
||||||
}
|
}
|
||||||
|
@ -367,7 +372,7 @@ fn (mut context Context) show_diff_summary() {
|
||||||
}
|
}
|
||||||
fail_threshold_max := f64(context.fail_on_regress_percent)
|
fail_threshold_max := f64(context.fail_on_regress_percent)
|
||||||
if first_cmd_percentage > fail_threshold_max {
|
if first_cmd_percentage > fail_threshold_max {
|
||||||
print(performance_regression_label)
|
flushed_print(performance_regression_label)
|
||||||
println('${first_cmd_percentage:5.1f}% > ${fail_threshold_max:5.1f}% threshold.')
|
println('${first_cmd_percentage:5.1f}% > ${fail_threshold_max:5.1f}% threshold.')
|
||||||
exit(3)
|
exit(3)
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,45 @@
|
||||||
|
// Copyright (c) 2019-2022 Alexander Medvednikov. All rights reserved.
|
||||||
|
// Use of this source code is governed by an MIT license that can be found in the LICENSE file.
|
||||||
|
module main
|
||||||
|
|
||||||
|
import os
|
||||||
|
import v.util
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
vmodules := os.vmodules_dir()
|
||||||
|
c2v_dir := os.join_path(vmodules, 'c2v_alpha')
|
||||||
|
c2v_bin := os.join_path(c2v_dir, 'c2v')
|
||||||
|
// Git clone c2v
|
||||||
|
if !os.exists(c2v_dir) {
|
||||||
|
println('C2V is not installed. Cloning C2V to $c2v_dir ...')
|
||||||
|
os.chdir(vmodules)?
|
||||||
|
res := os.execute('git clone --depth 1 git@github.com:/vlang/c2v_alpha.git')
|
||||||
|
if res.exit_code != 0 {
|
||||||
|
eprintln('Failed to download C2V. Perhaps it is not released yet? Is it June 20 yet?')
|
||||||
|
exit(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Compile c2v
|
||||||
|
if !os.exists(c2v_bin) {
|
||||||
|
os.chdir(c2v_dir)?
|
||||||
|
println('Compiling c2v ...')
|
||||||
|
res2 := os.execute('v -keepc -g -experimental -o c2v .')
|
||||||
|
if res2.exit_code != 0 {
|
||||||
|
eprintln(res2.output)
|
||||||
|
eprintln('Failed to compile C2V. This should never happen, please report it via GitHub.')
|
||||||
|
exit(2)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if os.args.len < 3 {
|
||||||
|
eprintln('Wrong number of args. Use `v translate file.c`.')
|
||||||
|
exit(3)
|
||||||
|
}
|
||||||
|
passed_args := util.args_quote_paths(os.args[2..])
|
||||||
|
// println(passed_args)
|
||||||
|
os.chdir(os.wd_at_startup)?
|
||||||
|
res := os.system('$c2v_bin $passed_args')
|
||||||
|
if res != 0 {
|
||||||
|
eprintln('C2V failed to translate the C files. Please report it via GitHub.')
|
||||||
|
exit(4)
|
||||||
|
}
|
||||||
|
}
|
|
@ -1358,6 +1358,7 @@ fn (t Tree) postfix_expr(node ast.PostfixExpr) &Node {
|
||||||
obj.add_terse('expr', t.expr(node.expr))
|
obj.add_terse('expr', t.expr(node.expr))
|
||||||
obj.add('auto_locked', t.string_node(node.auto_locked))
|
obj.add('auto_locked', t.string_node(node.auto_locked))
|
||||||
obj.add('pos', t.pos(node.pos))
|
obj.add('pos', t.pos(node.pos))
|
||||||
|
obj.add('is_c2v_prefix', t.bool_node(node.is_c2v_prefix))
|
||||||
return obj
|
return obj
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -76,7 +76,7 @@ SUBCMD:
|
||||||
|
|
||||||
// Snooped from cmd/v/v.v, vlib/v/pref/pref.v
|
// Snooped from cmd/v/v.v, vlib/v/pref/pref.v
|
||||||
const (
|
const (
|
||||||
auto_complete_commands = [
|
auto_complete_commands = [
|
||||||
// simple_cmd
|
// simple_cmd
|
||||||
'ast',
|
'ast',
|
||||||
'doc',
|
'doc',
|
||||||
|
@ -114,7 +114,6 @@ const (
|
||||||
'help',
|
'help',
|
||||||
'new',
|
'new',
|
||||||
'init',
|
'init',
|
||||||
'complete',
|
|
||||||
'translate',
|
'translate',
|
||||||
'self',
|
'self',
|
||||||
'search',
|
'search',
|
||||||
|
@ -130,8 +129,13 @@ const (
|
||||||
'run',
|
'run',
|
||||||
'build',
|
'build',
|
||||||
'build-module',
|
'build-module',
|
||||||
|
'missdoc',
|
||||||
]
|
]
|
||||||
auto_complete_flags = [
|
// Entries in the flag arrays below should be entered as is:
|
||||||
|
// * Short flags, e.g.: "-v", should be entered: '-v'
|
||||||
|
// * Long flags, e.g.: "--version", should be entered: '--version'
|
||||||
|
// * Single-dash flags, e.g.: "-version", should be entered: '-version'
|
||||||
|
auto_complete_flags = [
|
||||||
'-apk',
|
'-apk',
|
||||||
'-show-timings',
|
'-show-timings',
|
||||||
'-check-syntax',
|
'-check-syntax',
|
||||||
|
@ -150,6 +154,7 @@ const (
|
||||||
'-autofree',
|
'-autofree',
|
||||||
'-compress',
|
'-compress',
|
||||||
'-freestanding',
|
'-freestanding',
|
||||||
|
'-no-parallel',
|
||||||
'-no-preludes',
|
'-no-preludes',
|
||||||
'-prof',
|
'-prof',
|
||||||
'-profile',
|
'-profile',
|
||||||
|
@ -190,7 +195,7 @@ const (
|
||||||
'-version',
|
'-version',
|
||||||
'--version',
|
'--version',
|
||||||
]
|
]
|
||||||
auto_complete_flags_doc = [
|
auto_complete_flags_doc = [
|
||||||
'-all',
|
'-all',
|
||||||
'-f',
|
'-f',
|
||||||
'-h',
|
'-h',
|
||||||
|
@ -209,7 +214,7 @@ const (
|
||||||
'-s',
|
'-s',
|
||||||
'-l',
|
'-l',
|
||||||
]
|
]
|
||||||
auto_complete_flags_fmt = [
|
auto_complete_flags_fmt = [
|
||||||
'-c',
|
'-c',
|
||||||
'-diff',
|
'-diff',
|
||||||
'-l',
|
'-l',
|
||||||
|
@ -217,7 +222,7 @@ const (
|
||||||
'-debug',
|
'-debug',
|
||||||
'-verify',
|
'-verify',
|
||||||
]
|
]
|
||||||
auto_complete_flags_bin2v = [
|
auto_complete_flags_bin2v = [
|
||||||
'-h',
|
'-h',
|
||||||
'--help',
|
'--help',
|
||||||
'-m',
|
'-m',
|
||||||
|
@ -227,22 +232,46 @@ const (
|
||||||
'-w',
|
'-w',
|
||||||
'--write',
|
'--write',
|
||||||
]
|
]
|
||||||
auto_complete_flags_shader = [
|
auto_complete_flags_shader = [
|
||||||
'help',
|
'--help',
|
||||||
'h',
|
'-h',
|
||||||
'force-update',
|
'--force-update',
|
||||||
'u',
|
'-u',
|
||||||
'verbose',
|
'--verbose',
|
||||||
'v',
|
'-v',
|
||||||
'slang',
|
'--slang',
|
||||||
'l',
|
'-l',
|
||||||
'output',
|
'--output',
|
||||||
'o',
|
'-o',
|
||||||
]
|
]
|
||||||
auto_complete_flags_self = [
|
auto_complete_flags_missdoc = [
|
||||||
|
'--help',
|
||||||
|
'-h',
|
||||||
|
'--tags',
|
||||||
|
'-t',
|
||||||
|
'--deprecated',
|
||||||
|
'-d',
|
||||||
|
'--private',
|
||||||
|
'-p',
|
||||||
|
'--no-line-numbers',
|
||||||
|
'-n',
|
||||||
|
'--exclude',
|
||||||
|
'-e',
|
||||||
|
'--relative-paths',
|
||||||
|
'-r',
|
||||||
|
'--js',
|
||||||
|
'--verify',
|
||||||
|
'--diff',
|
||||||
|
]
|
||||||
|
auto_complete_flags_bump = [
|
||||||
|
'--patch',
|
||||||
|
'--minor',
|
||||||
|
'--major',
|
||||||
|
]
|
||||||
|
auto_complete_flags_self = [
|
||||||
'-prod',
|
'-prod',
|
||||||
]
|
]
|
||||||
auto_complete_compilers = [
|
auto_complete_compilers = [
|
||||||
'cc',
|
'cc',
|
||||||
'gcc',
|
'gcc',
|
||||||
'tcc',
|
'tcc',
|
||||||
|
@ -372,12 +401,17 @@ fn auto_complete_request(args []string) []string {
|
||||||
parent_command = parts[i]
|
parent_command = parts[i]
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
get_flags := fn (base []string, flag string) []string {
|
if part.starts_with('-') { // 'v [subcmd] -<tab>' or 'v [subcmd] --<tab>'-> flags.
|
||||||
if flag.len == 1 { return base
|
get_flags := fn (base []string, flag string) []string {
|
||||||
} else { return base.filter(it.starts_with(flag))
|
mut results := []string{}
|
||||||
}
|
for entry in base {
|
||||||
}
|
if entry.starts_with(flag) {
|
||||||
if part.starts_with('-') { // 'v -<tab>' -> flags.
|
results << entry
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return results
|
||||||
|
}
|
||||||
|
|
||||||
match parent_command {
|
match parent_command {
|
||||||
'bin2v' { // 'v bin2v -<tab>'
|
'bin2v' { // 'v bin2v -<tab>'
|
||||||
list = get_flags(auto_complete_flags_bin2v, part)
|
list = get_flags(auto_complete_flags_bin2v, part)
|
||||||
|
@ -397,6 +431,12 @@ fn auto_complete_request(args []string) []string {
|
||||||
'shader' { // 'v shader -<tab>' -> flags.
|
'shader' { // 'v shader -<tab>' -> flags.
|
||||||
list = get_flags(auto_complete_flags_shader, part)
|
list = get_flags(auto_complete_flags_shader, part)
|
||||||
}
|
}
|
||||||
|
'missdoc' { // 'v missdoc -<tab>' -> flags.
|
||||||
|
list = get_flags(auto_complete_flags_missdoc, part)
|
||||||
|
}
|
||||||
|
'bump' { // 'v bump -<tab>' -> flags.
|
||||||
|
list = get_flags(auto_complete_flags_bump, part)
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
for flag in auto_complete_flags {
|
for flag in auto_complete_flags {
|
||||||
if flag == part {
|
if flag == part {
|
||||||
|
@ -414,6 +454,11 @@ fn auto_complete_request(args []string) []string {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Clear the list if the result is identical to the part examined
|
||||||
|
// (the flag must have already been completed)
|
||||||
|
if list.len == 1 && part == list[0] {
|
||||||
|
list.clear()
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
match part {
|
match part {
|
||||||
'help' { // 'v help <tab>' -> top level commands except "help".
|
'help' { // 'v help <tab>' -> top level commands except "help".
|
||||||
|
|
|
@ -183,6 +183,7 @@ fn (foptions &FormatOptions) format_pipe() {
|
||||||
// checker.new_checker(table, prefs).check(file_ast)
|
// checker.new_checker(table, prefs).check(file_ast)
|
||||||
formatted_content := fmt.fmt(file_ast, table, prefs, foptions.is_debug)
|
formatted_content := fmt.fmt(file_ast, table, prefs, foptions.is_debug)
|
||||||
print(formatted_content)
|
print(formatted_content)
|
||||||
|
flush_stdout()
|
||||||
foptions.vlog('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.')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -279,6 +280,7 @@ fn (mut foptions FormatOptions) post_process_file(file string, formatted_file_pa
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
print(formatted_fc)
|
print(formatted_fc)
|
||||||
|
flush_stdout()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (f FormatOptions) str() string {
|
fn (f FormatOptions) str() string {
|
||||||
|
|
|
@ -37,7 +37,7 @@ import flag
|
||||||
import toml
|
import toml
|
||||||
|
|
||||||
const (
|
const (
|
||||||
tool_name = os.file_name(os.executable())
|
tool_name = 'vgret'
|
||||||
tool_version = '0.0.1'
|
tool_version = '0.0.1'
|
||||||
tool_description = '\n Dump and/or compare rendered frames of `gg` based apps
|
tool_description = '\n Dump and/or compare rendered frames of `gg` based apps
|
||||||
|
|
||||||
|
@ -57,7 +57,7 @@ Examples:
|
||||||
const (
|
const (
|
||||||
supported_hosts = ['linux']
|
supported_hosts = ['linux']
|
||||||
// External tool executables
|
// External tool executables
|
||||||
v_exe = vexe()
|
v_exe = os.getenv('VEXE')
|
||||||
idiff_exe = os.find_abs_path_of_executable('idiff') or { '' }
|
idiff_exe = os.find_abs_path_of_executable('idiff') or { '' }
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -105,11 +105,27 @@ mut:
|
||||||
config Config
|
config Config
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn (opt Options) verbose_execute(cmd string) os.Result {
|
||||||
|
opt.verbose_eprintln('Running `$cmd`')
|
||||||
|
return os.execute(cmd)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn (opt Options) verbose_eprintln(msg string) {
|
||||||
|
if opt.verbose {
|
||||||
|
eprintln(msg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
if os.args.len == 1 {
|
if runtime_os !in supported_hosts {
|
||||||
println('Usage: $tool_name PATH \n$tool_description\n$tool_name -h for more help...')
|
eprintln('$tool_name is currently only supported on $supported_hosts hosts')
|
||||||
exit(1)
|
exit(1)
|
||||||
}
|
}
|
||||||
|
if os.args.len == 1 {
|
||||||
|
eprintln('Usage: $tool_name PATH \n$tool_description\n$tool_name -h for more help...')
|
||||||
|
exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
mut fp := flag.new_flag_parser(os.args[1..])
|
mut fp := flag.new_flag_parser(os.args[1..])
|
||||||
fp.application(tool_name)
|
fp.application(tool_name)
|
||||||
fp.version(tool_version)
|
fp.version(tool_version)
|
||||||
|
@ -131,17 +147,17 @@ fn main() {
|
||||||
}
|
}
|
||||||
|
|
||||||
toml_conf := fp.string('toml-config', `t`, default_toml, 'Path or string with TOML configuration')
|
toml_conf := fp.string('toml-config', `t`, default_toml, 'Path or string with TOML configuration')
|
||||||
|
arg_paths := fp.finalize()?
|
||||||
ensure_env(opt) or { panic(err) }
|
|
||||||
|
|
||||||
arg_paths := fp.finalize() or { panic(err) }
|
|
||||||
|
|
||||||
if arg_paths.len == 0 {
|
if arg_paths.len == 0 {
|
||||||
println(fp.usage())
|
println(fp.usage())
|
||||||
println('\nError missing arguments')
|
println('\nError missing arguments')
|
||||||
exit(1)
|
exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !os.exists(tmp_dir) {
|
||||||
|
os.mkdir_all(tmp_dir)?
|
||||||
|
}
|
||||||
|
|
||||||
opt.config = new_config(opt.root_path, toml_conf)?
|
opt.config = new_config(opt.root_path, toml_conf)?
|
||||||
|
|
||||||
gen_in_path := arg_paths[0]
|
gen_in_path := arg_paths[0]
|
||||||
|
@ -154,13 +170,15 @@ fn main() {
|
||||||
all_paths_in_use := [path, gen_in_path, target_path]
|
all_paths_in_use := [path, gen_in_path, target_path]
|
||||||
for path_in_use in all_paths_in_use {
|
for path_in_use in all_paths_in_use {
|
||||||
if !os.is_dir(path_in_use) {
|
if !os.is_dir(path_in_use) {
|
||||||
panic('`$path_in_use` is not a directory')
|
eprintln('`$path_in_use` is not a directory')
|
||||||
|
exit(1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if path == target_path || gen_in_path == target_path || gen_in_path == path {
|
if path == target_path || gen_in_path == target_path || gen_in_path == path {
|
||||||
panic('Compare paths can not be the same directory `$path`/`$target_path`/`$gen_in_path`')
|
eprintln('Compare paths can not be the same directory `$path`/`$target_path`/`$gen_in_path`')
|
||||||
|
exit(1)
|
||||||
}
|
}
|
||||||
compare_screenshots(opt, gen_in_path, target_path) or { panic(err) }
|
compare_screenshots(opt, gen_in_path, target_path)?
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -184,21 +202,15 @@ fn generate_screenshots(mut opt Options, output_path string) ? {
|
||||||
rel_out_path = file
|
rel_out_path = file
|
||||||
}
|
}
|
||||||
|
|
||||||
if opt.verbose {
|
opt.verbose_eprintln('Compiling shaders (if needed) for `$file`')
|
||||||
eprintln('Compiling shaders (if needed) for `$file`')
|
sh_result := opt.verbose_execute('${os.quoted_path(v_exe)} shader ${os.quoted_path(app_path)}')
|
||||||
}
|
|
||||||
sh_result := os.execute('${os.quoted_path(v_exe)} shader ${os.quoted_path(app_path)}')
|
|
||||||
if sh_result.exit_code != 0 {
|
if sh_result.exit_code != 0 {
|
||||||
if opt.verbose {
|
opt.verbose_eprintln('Skipping shader compile for `$file` v shader failed with:\n$sh_result.output')
|
||||||
eprintln('Skipping shader compile for `$file` v shader failed with:\n$sh_result.output')
|
|
||||||
}
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if !os.exists(dst_path) {
|
if !os.exists(dst_path) {
|
||||||
if opt.verbose {
|
opt.verbose_eprintln('Creating output path `$dst_path`')
|
||||||
eprintln('Creating output path `$dst_path`')
|
|
||||||
}
|
|
||||||
os.mkdir_all(dst_path)?
|
os.mkdir_all(dst_path)?
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -221,18 +233,13 @@ fn compare_screenshots(opt Options, output_path string, target_path string) ? {
|
||||||
mut warns := map[string]string{}
|
mut warns := map[string]string{}
|
||||||
for app_config in opt.config.apps {
|
for app_config in opt.config.apps {
|
||||||
screenshots := app_config.screenshots
|
screenshots := app_config.screenshots
|
||||||
if opt.verbose {
|
opt.verbose_eprintln('Comparing $screenshots.len screenshots in `$output_path` with `$target_path`')
|
||||||
eprintln('Comparing $screenshots.len screenshots in `$output_path` with `$target_path`')
|
|
||||||
}
|
|
||||||
for screenshot in screenshots {
|
for screenshot in screenshots {
|
||||||
relative_screenshot := screenshot.all_after(output_path + os.path_separator)
|
relative_screenshot := screenshot.all_after(output_path + os.path_separator)
|
||||||
|
|
||||||
src := screenshot
|
src := screenshot
|
||||||
target := os.join_path(target_path, relative_screenshot)
|
target := os.join_path(target_path, relative_screenshot)
|
||||||
|
opt.verbose_eprintln('Comparing `$src` with `$target` with $app_config.compare.method')
|
||||||
if opt.verbose {
|
|
||||||
eprintln('Comparing `$src` with `$target` with $app_config.compare.method')
|
|
||||||
}
|
|
||||||
|
|
||||||
if app_config.compare.method == 'idiff' {
|
if app_config.compare.method == 'idiff' {
|
||||||
if idiff_exe == '' {
|
if idiff_exe == '' {
|
||||||
|
@ -242,14 +249,9 @@ fn compare_screenshots(opt Options, output_path string, target_path string) ? {
|
||||||
'.diff.tif')
|
'.diff.tif')
|
||||||
flags := app_config.compare.flags.join(' ')
|
flags := app_config.compare.flags.join(' ')
|
||||||
diff_cmd := '${os.quoted_path(idiff_exe)} $flags -abs -od -o ${os.quoted_path(diff_file)} -abs ${os.quoted_path(src)} ${os.quoted_path(target)}'
|
diff_cmd := '${os.quoted_path(idiff_exe)} $flags -abs -od -o ${os.quoted_path(diff_file)} -abs ${os.quoted_path(src)} ${os.quoted_path(target)}'
|
||||||
if opt.verbose {
|
result := opt.verbose_execute(diff_cmd)
|
||||||
eprintln('Running: $diff_cmd')
|
if result.exit_code == 0 {
|
||||||
}
|
opt.verbose_eprintln('OUTPUT: \n$result.output')
|
||||||
|
|
||||||
result := os.execute(diff_cmd)
|
|
||||||
|
|
||||||
if opt.verbose && result.exit_code == 0 {
|
|
||||||
eprintln('OUTPUT: \n$result.output')
|
|
||||||
}
|
}
|
||||||
if result.exit_code != 0 {
|
if result.exit_code != 0 {
|
||||||
eprintln('OUTPUT: \n$result.output')
|
eprintln('OUTPUT: \n$result.output')
|
||||||
|
@ -278,15 +280,19 @@ fn compare_screenshots(opt Options, output_path string, target_path string) ? {
|
||||||
}
|
}
|
||||||
first := fails.keys()[0]
|
first := fails.keys()[0]
|
||||||
fail_copy := os.join_path(os.temp_dir(), 'fail.' + first.all_after_last('.'))
|
fail_copy := os.join_path(os.temp_dir(), 'fail.' + first.all_after_last('.'))
|
||||||
os.cp(first, fail_copy) or { panic(err) }
|
os.cp(first, fail_copy)?
|
||||||
eprintln('First failed file `$first` is copied to `$fail_copy`')
|
eprintln('First failed file `$first` is copied to `$fail_copy`')
|
||||||
|
|
||||||
diff_file := os.join_path(os.temp_dir(), os.file_name(first).all_before_last('.') +
|
diff_file := os.join_path(os.temp_dir(), os.file_name(first).all_before_last('.') +
|
||||||
'.diff.tif')
|
'.diff.tif')
|
||||||
diff_copy := os.join_path(os.temp_dir(), 'diff.tif')
|
diff_copy := os.join_path(os.temp_dir(), 'diff.tif')
|
||||||
if os.is_file(diff_file) {
|
if os.is_file(diff_file) {
|
||||||
os.cp(diff_file, diff_copy) or { panic(err) }
|
os.cp(diff_file, diff_copy)?
|
||||||
eprintln('First failed diff file `$diff_file` is copied to `$diff_copy`')
|
eprintln('First failed diff file `$diff_file` is copied to `$diff_copy`')
|
||||||
|
eprintln('Removing alpha channel from $diff_copy ...')
|
||||||
|
final_fail_result_file := os.join_path(os.temp_dir(), 'diff.png')
|
||||||
|
opt.verbose_execute('convert ${os.quoted_path(diff_copy)} -alpha off ${os.quoted_path(final_fail_result_file)}')
|
||||||
|
eprintln('Final diff file: `$final_fail_result_file`')
|
||||||
}
|
}
|
||||||
exit(1)
|
exit(1)
|
||||||
}
|
}
|
||||||
|
@ -295,25 +301,16 @@ fn compare_screenshots(opt Options, output_path string, target_path string) ? {
|
||||||
fn take_screenshots(opt Options, app AppConfig) ?[]string {
|
fn take_screenshots(opt Options, app AppConfig) ?[]string {
|
||||||
out_path := app.screenshots_path
|
out_path := app.screenshots_path
|
||||||
if !opt.compare_only {
|
if !opt.compare_only {
|
||||||
if opt.verbose {
|
opt.verbose_eprintln('Taking screenshot(s) of `$app.path` to `$out_path`')
|
||||||
eprintln('Taking screenshot(s) of `$app.path` to `$out_path`')
|
|
||||||
}
|
|
||||||
|
|
||||||
if app.capture.method == 'gg_record' {
|
if app.capture.method == 'gg_record' {
|
||||||
for k, v in app.capture.env {
|
for k, v in app.capture.env {
|
||||||
rv := v.replace('\$OUT_PATH', out_path)
|
rv := v.replace('\$OUT_PATH', out_path)
|
||||||
if opt.verbose {
|
opt.verbose_eprintln('Setting ENV `$k` = $rv ...')
|
||||||
eprintln('Setting ENV `$k` = $rv ...')
|
|
||||||
}
|
|
||||||
os.setenv('$k', rv, true)
|
os.setenv('$k', rv, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
mut flags := app.capture.flags.join(' ')
|
mut flags := app.capture.flags.join(' ')
|
||||||
v_cmd := '${os.quoted_path(v_exe)} $flags -d gg_record run ${os.quoted_path(app.abs_path)}'
|
result := opt.verbose_execute('${os.quoted_path(v_exe)} $flags -d gg_record run ${os.quoted_path(app.abs_path)}')
|
||||||
if opt.verbose {
|
|
||||||
eprintln('Running `$v_cmd`')
|
|
||||||
}
|
|
||||||
result := os.execute('$v_cmd')
|
|
||||||
if result.exit_code != 0 {
|
if result.exit_code != 0 {
|
||||||
return error('Failed taking screenshot of `$app.abs_path`:\n$result.output')
|
return error('Failed taking screenshot of `$app.abs_path`:\n$result.output')
|
||||||
}
|
}
|
||||||
|
@ -329,30 +326,6 @@ fn take_screenshots(opt Options, app AppConfig) ?[]string {
|
||||||
return screenshots
|
return screenshots
|
||||||
}
|
}
|
||||||
|
|
||||||
// ensure_env returns nothing if everything is okay.
|
|
||||||
fn ensure_env(opt Options) ? {
|
|
||||||
if !os.exists(tmp_dir) {
|
|
||||||
os.mkdir_all(tmp_dir)?
|
|
||||||
}
|
|
||||||
|
|
||||||
if runtime_os !in supported_hosts {
|
|
||||||
return error('$tool_name is currently only supported on $supported_hosts hosts')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// vexe returns the absolute path to the V compiler.
|
|
||||||
fn vexe() string {
|
|
||||||
mut exe := os.getenv('VEXE')
|
|
||||||
if os.is_executable(exe) {
|
|
||||||
return os.real_path(exe)
|
|
||||||
}
|
|
||||||
possible_symlink := os.find_abs_path_of_executable('v') or { '' }
|
|
||||||
if os.is_executable(possible_symlink) {
|
|
||||||
exe = os.real_path(possible_symlink)
|
|
||||||
}
|
|
||||||
return exe
|
|
||||||
}
|
|
||||||
|
|
||||||
fn new_config(root_path string, toml_config string) ?Config {
|
fn new_config(root_path string, toml_config string) ?Config {
|
||||||
doc := if os.is_file(toml_config) {
|
doc := if os.is_file(toml_config) {
|
||||||
toml.parse_file(toml_config)?
|
toml.parse_file(toml_config)?
|
||||||
|
|
|
@ -6,12 +6,13 @@ import flag
|
||||||
|
|
||||||
const (
|
const (
|
||||||
tool_name = 'v missdoc'
|
tool_name = 'v missdoc'
|
||||||
tool_version = '0.0.4'
|
tool_version = '0.1.0'
|
||||||
tool_description = 'Prints all V functions in .v files under PATH/, that do not yet have documentation comments.'
|
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) + '/')
|
work_dir_prefix = normalise_path(os.real_path(os.wd_at_startup) + os.path_separator)
|
||||||
)
|
)
|
||||||
|
|
||||||
struct UndocumentedFN {
|
struct UndocumentedFN {
|
||||||
|
file string
|
||||||
line int
|
line int
|
||||||
signature string
|
signature string
|
||||||
tags []string
|
tags []string
|
||||||
|
@ -26,11 +27,15 @@ struct Options {
|
||||||
no_line_numbers bool
|
no_line_numbers bool
|
||||||
exclude []string
|
exclude []string
|
||||||
relative_paths bool
|
relative_paths bool
|
||||||
|
mut:
|
||||||
|
verify bool
|
||||||
|
diff bool
|
||||||
|
additional_args []string
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (opt Options) report_undocumented_functions_in_path(path string) {
|
fn (opt Options) collect_undocumented_functions_in_dir(directory string) []UndocumentedFN {
|
||||||
mut files := []string{}
|
mut files := []string{}
|
||||||
collect(path, mut files, fn (npath string, mut accumulated_paths []string) {
|
collect(directory, mut files, fn (npath string, mut accumulated_paths []string) {
|
||||||
if !npath.ends_with('.v') {
|
if !npath.ends_with('.v') {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -39,6 +44,7 @@ fn (opt Options) report_undocumented_functions_in_path(path string) {
|
||||||
}
|
}
|
||||||
accumulated_paths << npath
|
accumulated_paths << npath
|
||||||
})
|
})
|
||||||
|
mut undocumented_fns := []UndocumentedFN{}
|
||||||
for file in files {
|
for file in files {
|
||||||
if !opt.js && file.ends_with('.js.v') {
|
if !opt.js && file.ends_with('.js.v') {
|
||||||
continue
|
continue
|
||||||
|
@ -46,46 +52,64 @@ fn (opt Options) report_undocumented_functions_in_path(path string) {
|
||||||
if opt.exclude.len > 0 && opt.exclude.any(file.contains(it)) {
|
if opt.exclude.len > 0 && opt.exclude.any(file.contains(it)) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
opt.report_undocumented_functions_in_file(file)
|
undocumented_fns << opt.collect_undocumented_functions_in_file(file)
|
||||||
}
|
}
|
||||||
|
return undocumented_fns
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (opt &Options) report_undocumented_functions_in_file(nfile string) {
|
fn (opt &Options) collect_undocumented_functions_in_file(nfile string) []UndocumentedFN {
|
||||||
file := os.real_path(nfile)
|
file := os.real_path(nfile)
|
||||||
contents := os.read_file(file) or { panic(err) }
|
contents := os.read_file(file) or { panic(err) }
|
||||||
lines := contents.split('\n')
|
lines := contents.split('\n')
|
||||||
mut info := []UndocumentedFN{}
|
mut list := []UndocumentedFN{}
|
||||||
|
mut comments := []string{}
|
||||||
|
mut tags := []string{}
|
||||||
for i, line in lines {
|
for i, line in lines {
|
||||||
if line.starts_with('pub fn') || (opt.private && (line.starts_with('fn ')
|
if line.starts_with('//') {
|
||||||
&& !(line.starts_with('fn C.') || line.starts_with('fn main')))) {
|
comments << line
|
||||||
// println('Match: $line')
|
} else if line.trim_space().starts_with('[') {
|
||||||
if i > 0 && lines.len > 0 {
|
tags << collect_tags(line)
|
||||||
mut line_above := lines[i - 1]
|
} else if line.starts_with('pub fn')
|
||||||
if !line_above.starts_with('//') {
|
|| (opt.private && (line.starts_with('fn ') && !(line.starts_with('fn C.')
|
||||||
mut tags := []string{}
|
|| line.starts_with('fn main')))) {
|
||||||
mut grab := true
|
if comments.len == 0 {
|
||||||
for j := i - 1; j >= 0; j-- {
|
clean_line := line.all_before_last(' {')
|
||||||
prev_line := lines[j]
|
list << UndocumentedFN{
|
||||||
if prev_line.contains('}') { // We've looked back to the above scope, stop here
|
line: i + 1
|
||||||
break
|
signature: clean_line
|
||||||
} else if prev_line.starts_with('[') {
|
tags: tags
|
||||||
tags << collect_tags(prev_line)
|
file: file
|
||||||
continue
|
|
||||||
} else if prev_line.starts_with('//') { // Single-line comment
|
|
||||||
grab = false
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if grab {
|
|
||||||
clean_line := line.all_before_last(' {')
|
|
||||||
info << UndocumentedFN{i + 1, clean_line, tags}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
tags = []
|
||||||
|
comments = []
|
||||||
|
} else {
|
||||||
|
tags = []
|
||||||
|
comments = []
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if info.len > 0 {
|
return list
|
||||||
for undocumented_fn in info {
|
}
|
||||||
|
|
||||||
|
fn (opt &Options) collect_undocumented_functions_in_path(path string) []UndocumentedFN {
|
||||||
|
mut undocumented_functions := []UndocumentedFN{}
|
||||||
|
if os.is_file(path) {
|
||||||
|
undocumented_functions << opt.collect_undocumented_functions_in_file(path)
|
||||||
|
} else {
|
||||||
|
undocumented_functions << opt.collect_undocumented_functions_in_dir(path)
|
||||||
|
}
|
||||||
|
return undocumented_functions
|
||||||
|
}
|
||||||
|
|
||||||
|
fn (opt &Options) report_undocumented_functions_in_path(path string) int {
|
||||||
|
mut list := opt.collect_undocumented_functions_in_path(path)
|
||||||
|
opt.report_undocumented_functions(list)
|
||||||
|
return list.len
|
||||||
|
}
|
||||||
|
|
||||||
|
fn (opt &Options) report_undocumented_functions(list []UndocumentedFN) {
|
||||||
|
if list.len > 0 {
|
||||||
|
for undocumented_fn in list {
|
||||||
mut line_numbers := '$undocumented_fn.line:0:'
|
mut line_numbers := '$undocumented_fn.line:0:'
|
||||||
if opt.no_line_numbers {
|
if opt.no_line_numbers {
|
||||||
line_numbers = ''
|
line_numbers = ''
|
||||||
|
@ -95,10 +119,11 @@ fn (opt &Options) report_undocumented_functions_in_file(nfile string) {
|
||||||
} else {
|
} else {
|
||||||
''
|
''
|
||||||
}
|
}
|
||||||
|
file := undocumented_fn.file
|
||||||
ofile := if opt.relative_paths {
|
ofile := if opt.relative_paths {
|
||||||
nfile.replace(work_dir_prefix, '')
|
file.replace(work_dir_prefix, '')
|
||||||
} else {
|
} else {
|
||||||
os.real_path(nfile)
|
os.real_path(file)
|
||||||
}
|
}
|
||||||
if opt.deprecated {
|
if opt.deprecated {
|
||||||
println('$ofile:$line_numbers$undocumented_fn.signature $tags_str')
|
println('$ofile:$line_numbers$undocumented_fn.signature $tags_str')
|
||||||
|
@ -118,6 +143,54 @@ fn (opt &Options) report_undocumented_functions_in_file(nfile string) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn (opt &Options) diff_undocumented_functions_in_paths(path_old string, path_new string) []UndocumentedFN {
|
||||||
|
old := os.real_path(path_old)
|
||||||
|
new := os.real_path(path_new)
|
||||||
|
|
||||||
|
mut old_undocumented_functions := opt.collect_undocumented_functions_in_path(old)
|
||||||
|
mut new_undocumented_functions := opt.collect_undocumented_functions_in_path(new)
|
||||||
|
|
||||||
|
mut differs := []UndocumentedFN{}
|
||||||
|
if new_undocumented_functions.len > old_undocumented_functions.len {
|
||||||
|
for new_undoc_fn in new_undocumented_functions {
|
||||||
|
new_relative_file := new_undoc_fn.file.replace(new, '').trim_string_left(os.path_separator)
|
||||||
|
mut found := false
|
||||||
|
for old_undoc_fn in old_undocumented_functions {
|
||||||
|
old_relative_file := old_undoc_fn.file.replace(old, '').trim_string_left(os.path_separator)
|
||||||
|
if new_relative_file == old_relative_file
|
||||||
|
&& new_undoc_fn.signature == old_undoc_fn.signature {
|
||||||
|
found = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !found {
|
||||||
|
differs << new_undoc_fn
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
differs.sort_with_compare(sort_undoc_fns)
|
||||||
|
return differs
|
||||||
|
}
|
||||||
|
|
||||||
|
fn sort_undoc_fns(a &UndocumentedFN, b &UndocumentedFN) int {
|
||||||
|
if a.file < b.file {
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
if a.file > b.file {
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
// same file sort by signature
|
||||||
|
else {
|
||||||
|
if a.signature < b.signature {
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
if a.signature > b.signature {
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn normalise_path(path string) string {
|
fn normalise_path(path string) string {
|
||||||
return path.replace('\\', '/')
|
return path.replace('\\', '/')
|
||||||
}
|
}
|
||||||
|
@ -145,17 +218,15 @@ fn collect_tags(line string) []string {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
if os.args.len == 1 {
|
mut fp := flag.new_flag_parser(os.args[1..]) // skip the "v" command.
|
||||||
println('Usage: $tool_name PATH \n$tool_description\n$tool_name -h for more help...')
|
|
||||||
exit(1)
|
|
||||||
}
|
|
||||||
mut fp := flag.new_flag_parser(os.args[1..])
|
|
||||||
fp.application(tool_name)
|
fp.application(tool_name)
|
||||||
fp.version(tool_version)
|
fp.version(tool_version)
|
||||||
fp.description(tool_description)
|
fp.description(tool_description)
|
||||||
fp.arguments_description('PATH [PATH]...')
|
fp.arguments_description('PATH [PATH]...')
|
||||||
|
fp.skip_executable() // skip the "missdoc" command.
|
||||||
|
|
||||||
// Collect tool options
|
// Collect tool options
|
||||||
opt := Options{
|
mut opt := Options{
|
||||||
show_help: fp.bool('help', `h`, false, 'Show this help text.')
|
show_help: fp.bool('help', `h`, false, 'Show this help text.')
|
||||||
deprecated: fp.bool('deprecated', `d`, false, 'Include deprecated functions in output.')
|
deprecated: fp.bool('deprecated', `d`, false, 'Include deprecated functions in output.')
|
||||||
private: fp.bool('private', `p`, false, 'Include private functions in output.')
|
private: fp.bool('private', `p`, false, 'Include private functions in output.')
|
||||||
|
@ -164,16 +235,58 @@ fn main() {
|
||||||
collect_tags: fp.bool('tags', `t`, false, 'Also print function tags if any is found.')
|
collect_tags: fp.bool('tags', `t`, false, 'Also print function tags if any is found.')
|
||||||
exclude: fp.string_multi('exclude', `e`, '')
|
exclude: fp.string_multi('exclude', `e`, '')
|
||||||
relative_paths: fp.bool('relative-paths', `r`, false, 'Use relative paths in output.')
|
relative_paths: fp.bool('relative-paths', `r`, false, 'Use relative paths in output.')
|
||||||
|
diff: fp.bool('diff', 0, false, 'exit(1) and show difference between two PATH inputs, return 0 otherwise.')
|
||||||
|
verify: fp.bool('verify', 0, false, 'exit(1) if documentation is missing, 0 otherwise.')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
opt.additional_args = fp.finalize() or { panic(err) }
|
||||||
|
|
||||||
if opt.show_help {
|
if opt.show_help {
|
||||||
println(fp.usage())
|
println(fp.usage())
|
||||||
exit(0)
|
exit(0)
|
||||||
}
|
}
|
||||||
for path in os.args[1..] {
|
if opt.additional_args.len == 0 {
|
||||||
if os.is_file(path) {
|
println(fp.usage())
|
||||||
opt.report_undocumented_functions_in_file(path)
|
eprintln('Error: $tool_name is missing PATH input')
|
||||||
} else {
|
exit(1)
|
||||||
opt.report_undocumented_functions_in_path(path)
|
}
|
||||||
|
// Allow short-long versions to prevent false positive situations, should
|
||||||
|
// the user miss a `-`. E.g.: the `-verify` flag would be ignored and missdoc
|
||||||
|
// will return 0 for success plus a list of any undocumented functions.
|
||||||
|
if '-verify' in opt.additional_args {
|
||||||
|
opt.verify = true
|
||||||
|
}
|
||||||
|
if '-diff' in opt.additional_args {
|
||||||
|
opt.diff = true
|
||||||
|
}
|
||||||
|
if opt.diff {
|
||||||
|
if opt.additional_args.len < 2 {
|
||||||
|
println(fp.usage())
|
||||||
|
eprintln('Error: $tool_name --diff needs two valid PATH inputs')
|
||||||
|
exit(1)
|
||||||
|
}
|
||||||
|
path_old := opt.additional_args[0]
|
||||||
|
path_new := opt.additional_args[1]
|
||||||
|
if !(os.is_file(path_old) || os.is_dir(path_old)) || !(os.is_file(path_new)
|
||||||
|
|| os.is_dir(path_new)) {
|
||||||
|
println(fp.usage())
|
||||||
|
eprintln('Error: $tool_name --diff needs two valid PATH inputs')
|
||||||
|
exit(1)
|
||||||
|
}
|
||||||
|
list := opt.diff_undocumented_functions_in_paths(path_old, path_new)
|
||||||
|
if list.len > 0 {
|
||||||
|
opt.report_undocumented_functions(list)
|
||||||
|
exit(1)
|
||||||
|
}
|
||||||
|
exit(0)
|
||||||
|
}
|
||||||
|
mut total := 0
|
||||||
|
for path in opt.additional_args {
|
||||||
|
if os.is_file(path) || os.is_dir(path) {
|
||||||
|
total += opt.report_undocumented_functions_in_path(path)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if opt.verify && total > 0 {
|
||||||
|
exit(1)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
103
cmd/tools/vpm.v
103
cmd/tools/vpm.v
|
@ -4,6 +4,7 @@
|
||||||
module main
|
module main
|
||||||
|
|
||||||
import os
|
import os
|
||||||
|
import rand
|
||||||
import os.cmdline
|
import os.cmdline
|
||||||
import net.http
|
import net.http
|
||||||
import net.urllib
|
import net.urllib
|
||||||
|
@ -12,7 +13,8 @@ import vhelp
|
||||||
import v.vmod
|
import v.vmod
|
||||||
|
|
||||||
const (
|
const (
|
||||||
default_vpm_server_urls = ['https://vpm.vlang.io']
|
default_vpm_server_urls = ['https://vpm.vlang.io', 'https://vpm.url4e.com']
|
||||||
|
vpm_server_urls = rand.shuffle_clone(default_vpm_server_urls) or { [] } // ensure that all queries are distributed fairly
|
||||||
valid_vpm_commands = ['help', 'search', 'install', 'update', 'upgrade', 'outdated',
|
valid_vpm_commands = ['help', 'search', 'install', 'update', 'upgrade', 'outdated',
|
||||||
'list', 'remove', 'show']
|
'list', 'remove', 'show']
|
||||||
excluded_dirs = ['cache', 'vlib']
|
excluded_dirs = ['cache', 'vlib']
|
||||||
|
@ -208,24 +210,24 @@ fn vpm_install_from_vpm(module_names []string) {
|
||||||
println('VPM needs `$vcs` to be installed.')
|
println('VPM needs `$vcs` to be installed.')
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
mod_name_as_path := mod.name.replace('.', os.path_separator).replace('-', '_').to_lower()
|
//
|
||||||
final_module_path := os.real_path(os.join_path(settings.vmodules_path, mod_name_as_path))
|
minfo := mod_name_info(mod.name)
|
||||||
if os.exists(final_module_path) {
|
if os.exists(minfo.final_module_path) {
|
||||||
vpm_update([name])
|
vpm_update([name])
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
println('Installing module "$name" from "$mod.url" to "$final_module_path" ...')
|
println('Installing module "$name" from "$mod.url" to "$minfo.final_module_path" ...')
|
||||||
vcs_install_cmd := supported_vcs_install_cmds[vcs]
|
vcs_install_cmd := supported_vcs_install_cmds[vcs]
|
||||||
cmd := '$vcs_install_cmd "$mod.url" "$final_module_path"'
|
cmd := '$vcs_install_cmd "$mod.url" "$minfo.final_module_path"'
|
||||||
verbose_println(' command: $cmd')
|
verbose_println(' command: $cmd')
|
||||||
cmdres := os.execute(cmd)
|
cmdres := os.execute(cmd)
|
||||||
if cmdres.exit_code != 0 {
|
if cmdres.exit_code != 0 {
|
||||||
errors++
|
errors++
|
||||||
println('Failed installing module "$name" to "$final_module_path" .')
|
println('Failed installing module "$name" to "$minfo.final_module_path" .')
|
||||||
print_failed_cmd(cmd, cmdres)
|
print_failed_cmd(cmd, cmdres)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
resolve_dependencies(name, final_module_path, module_names)
|
resolve_dependencies(name, minfo.final_module_path, module_names)
|
||||||
}
|
}
|
||||||
if errors > 0 {
|
if errors > 0 {
|
||||||
exit(1)
|
exit(1)
|
||||||
|
@ -270,7 +272,7 @@ fn vpm_install_from_vcs(module_names []string, vcs_key string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
repo_name := url.substr(second_cut_pos + 1, first_cut_pos)
|
repo_name := url.substr(second_cut_pos + 1, first_cut_pos)
|
||||||
mut name := repo_name + os.path_separator + mod_name
|
mut name := os.join_path(repo_name, mod_name)
|
||||||
mod_name_as_path := name.replace('-', '_').to_lower()
|
mod_name_as_path := name.replace('-', '_').to_lower()
|
||||||
mut final_module_path := os.real_path(os.join_path(settings.vmodules_path, mod_name_as_path))
|
mut final_module_path := os.real_path(os.join_path(settings.vmodules_path, mod_name_as_path))
|
||||||
if os.exists(final_module_path) {
|
if os.exists(final_module_path) {
|
||||||
|
@ -297,20 +299,19 @@ fn vpm_install_from_vcs(module_names []string, vcs_key string) {
|
||||||
if os.exists(vmod_path) {
|
if os.exists(vmod_path) {
|
||||||
data := os.read_file(vmod_path) or { return }
|
data := os.read_file(vmod_path) or { return }
|
||||||
vmod := parse_vmod(data)
|
vmod := parse_vmod(data)
|
||||||
mod_path := os.real_path(os.join_path(settings.vmodules_path, vmod.name.replace('.',
|
minfo := mod_name_info(vmod.name)
|
||||||
os.path_separator)))
|
println('Relocating module from "$name" to "$vmod.name" ( "$minfo.final_module_path" ) ...')
|
||||||
println('Relocating module from "$name" to "$vmod.name" ( "$mod_path" ) ...')
|
if os.exists(minfo.final_module_path) {
|
||||||
if os.exists(mod_path) {
|
println('Warning module "$minfo.final_module_path" already exsits!')
|
||||||
println('Warning module "$mod_path" already exsits!')
|
println('Removing module "$minfo.final_module_path" ...')
|
||||||
println('Removing module "$mod_path" ...')
|
os.rmdir_all(minfo.final_module_path) or {
|
||||||
os.rmdir_all(mod_path) or {
|
|
||||||
errors++
|
errors++
|
||||||
println('Errors while removing "$mod_path" :')
|
println('Errors while removing "$minfo.final_module_path" :')
|
||||||
println(err)
|
println(err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
os.mv(final_module_path, mod_path) or {
|
os.mv(final_module_path, minfo.final_module_path) or {
|
||||||
errors++
|
errors++
|
||||||
println('Errors while relocating module "$name" :')
|
println('Errors while relocating module "$name" :')
|
||||||
println(err)
|
println(err)
|
||||||
|
@ -323,7 +324,7 @@ fn vpm_install_from_vcs(module_names []string, vcs_key string) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
println('Module "$name" relocated to "$vmod.name" successfully.')
|
println('Module "$name" relocated to "$vmod.name" successfully.')
|
||||||
final_module_path = mod_path
|
final_module_path = minfo.final_module_path
|
||||||
name = vmod.name
|
name = vmod.name
|
||||||
}
|
}
|
||||||
resolve_dependencies(name, final_module_path, module_names)
|
resolve_dependencies(name, final_module_path, module_names)
|
||||||
|
@ -377,10 +378,7 @@ fn vpm_update(m []string) {
|
||||||
}
|
}
|
||||||
mut errors := 0
|
mut errors := 0
|
||||||
for modulename in module_names {
|
for modulename in module_names {
|
||||||
mut zname := modulename
|
zname := url_to_module_name(modulename)
|
||||||
if mod := get_mod_by_url(modulename) {
|
|
||||||
zname = mod.name
|
|
||||||
}
|
|
||||||
final_module_path := valid_final_path_of_existing_module(modulename) or { continue }
|
final_module_path := valid_final_path_of_existing_module(modulename) or { continue }
|
||||||
os.chdir(final_module_path) or {}
|
os.chdir(final_module_path) or {}
|
||||||
println('Updating module "$zname" in "$final_module_path" ...')
|
println('Updating module "$zname" in "$final_module_path" ...')
|
||||||
|
@ -503,26 +501,21 @@ fn vpm_remove(module_names []string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn valid_final_path_of_existing_module(modulename string) ?string {
|
fn valid_final_path_of_existing_module(modulename string) ?string {
|
||||||
mut name := modulename
|
name := if mod := get_mod_by_url(modulename) { mod.name } else { modulename }
|
||||||
if mod := get_mod_by_url(name) {
|
minfo := mod_name_info(name)
|
||||||
name = mod.name
|
if !os.exists(minfo.final_module_path) {
|
||||||
}
|
println('No module with name "$minfo.mname_normalised" exists at $minfo.final_module_path')
|
||||||
mod_name_as_path := name.replace('.', os.path_separator).replace('-', '_').to_lower()
|
|
||||||
name_of_vmodules_folder := os.join_path(settings.vmodules_path, mod_name_as_path)
|
|
||||||
final_module_path := os.real_path(name_of_vmodules_folder)
|
|
||||||
if !os.exists(final_module_path) {
|
|
||||||
println('No module with name "$name" exists at $name_of_vmodules_folder')
|
|
||||||
return none
|
return none
|
||||||
}
|
}
|
||||||
if !os.is_dir(final_module_path) {
|
if !os.is_dir(minfo.final_module_path) {
|
||||||
println('Skipping "$name_of_vmodules_folder", since it is not a folder.')
|
println('Skipping "$minfo.final_module_path", since it is not a folder.')
|
||||||
return none
|
return none
|
||||||
}
|
}
|
||||||
vcs_used_in_dir(final_module_path) or {
|
vcs_used_in_dir(minfo.final_module_path) or {
|
||||||
println('Skipping "$name_of_vmodules_folder", since it does not use a supported vcs.')
|
println('Skipping "$minfo.final_module_path", since it does not use a supported vcs.')
|
||||||
return none
|
return none
|
||||||
}
|
}
|
||||||
return final_module_path
|
return minfo.final_module_path
|
||||||
}
|
}
|
||||||
|
|
||||||
fn ensure_vmodules_dir_exist() {
|
fn ensure_vmodules_dir_exist() {
|
||||||
|
@ -573,6 +566,31 @@ fn get_installed_modules() []string {
|
||||||
return modules
|
return modules
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct ModNameInfo {
|
||||||
|
mut:
|
||||||
|
mname string // The-user.The-mod , *never* The-user.The-mod.git
|
||||||
|
mname_normalised string // the_user.the_mod
|
||||||
|
mname_as_path string // the_user/the_mod
|
||||||
|
final_module_path string // ~/.vmodules/the_user/the_mod
|
||||||
|
}
|
||||||
|
|
||||||
|
fn mod_name_info(mod_name string) ModNameInfo {
|
||||||
|
mut info := ModNameInfo{}
|
||||||
|
info.mname = if mod_name.ends_with('.git') { mod_name.replace('.git', '') } else { mod_name }
|
||||||
|
info.mname_normalised = info.mname.replace('-', '_').to_lower()
|
||||||
|
info.mname_as_path = info.mname_normalised.replace('.', os.path_separator)
|
||||||
|
info.final_module_path = os.real_path(os.join_path(settings.vmodules_path, info.mname_as_path))
|
||||||
|
return info
|
||||||
|
}
|
||||||
|
|
||||||
|
fn url_to_module_name(modulename string) string {
|
||||||
|
mut res := if mod := get_mod_by_url(modulename) { mod.name } else { modulename }
|
||||||
|
if res.ends_with('.git') {
|
||||||
|
res = res.replace('.git', '')
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
fn get_all_modules() []string {
|
fn get_all_modules() []string {
|
||||||
url := get_working_server_url()
|
url := get_working_server_url()
|
||||||
r := http.get(url) or { panic(err) }
|
r := http.get(url) or { panic(err) }
|
||||||
|
@ -580,7 +598,7 @@ fn get_all_modules() []string {
|
||||||
println('Failed to search vpm.vlang.io. Status code: $r.status_code')
|
println('Failed to search vpm.vlang.io. Status code: $r.status_code')
|
||||||
exit(1)
|
exit(1)
|
||||||
}
|
}
|
||||||
s := r.text
|
s := r.body
|
||||||
mut read_len := 0
|
mut read_len := 0
|
||||||
mut modules := []string{}
|
mut modules := []string{}
|
||||||
for read_len < s.len {
|
for read_len < s.len {
|
||||||
|
@ -648,7 +666,7 @@ fn get_working_server_url() string {
|
||||||
server_urls := if settings.server_urls.len > 0 {
|
server_urls := if settings.server_urls.len > 0 {
|
||||||
settings.server_urls
|
settings.server_urls
|
||||||
} else {
|
} else {
|
||||||
default_vpm_server_urls
|
vpm_server_urls
|
||||||
}
|
}
|
||||||
for url in server_urls {
|
for url in server_urls {
|
||||||
verbose_println('Trying server url: $url')
|
verbose_println('Trying server url: $url')
|
||||||
|
@ -709,7 +727,8 @@ fn get_module_meta_info(name string) ?Mod {
|
||||||
return mod
|
return mod
|
||||||
}
|
}
|
||||||
mut errors := []string{}
|
mut errors := []string{}
|
||||||
for server_url in default_vpm_server_urls {
|
|
||||||
|
for server_url in vpm_server_urls {
|
||||||
modurl := server_url + '/jsmod/$name'
|
modurl := server_url + '/jsmod/$name'
|
||||||
verbose_println('Retrieving module metadata from: "$modurl" ...')
|
verbose_println('Retrieving module metadata from: "$modurl" ...')
|
||||||
r := http.get(modurl) or {
|
r := http.get(modurl) or {
|
||||||
|
@ -717,7 +736,7 @@ fn get_module_meta_info(name string) ?Mod {
|
||||||
errors << 'Error details: $err'
|
errors << 'Error details: $err'
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if r.status_code == 404 || r.text.trim_space() == '404' {
|
if r.status_code == 404 || r.body.trim_space() == '404' {
|
||||||
errors << 'Skipping module "$name", since "$server_url" reported that "$name" does not exist.'
|
errors << 'Skipping module "$name", since "$server_url" reported that "$name" does not exist.'
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
@ -725,7 +744,7 @@ fn get_module_meta_info(name string) ?Mod {
|
||||||
errors << 'Skipping module "$name", since "$server_url" responded with $r.status_code http status code. Please try again later.'
|
errors << 'Skipping module "$name", since "$server_url" responded with $r.status_code http status code. Please try again later.'
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
s := r.text
|
s := r.body
|
||||||
if s.len > 0 && s[0] != `{` {
|
if s.len > 0 && s[0] != `{` {
|
||||||
errors << 'Invalid json data'
|
errors << 'Invalid json data'
|
||||||
errors << s.trim_space().limit(100) + ' ...'
|
errors << s.trim_space().limit(100) + ' ...'
|
||||||
|
|
|
@ -305,7 +305,6 @@ fn run_repl(workdir string, vrepl_prefix string) int {
|
||||||
return int(rc)
|
return int(rc)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break
|
|
||||||
}
|
}
|
||||||
r.line = line
|
r.line = line
|
||||||
if r.line == '\n' {
|
if r.line == '\n' {
|
||||||
|
@ -388,13 +387,13 @@ fn run_repl(workdir string, vrepl_prefix string) int {
|
||||||
'#include ',
|
'#include ',
|
||||||
'for ',
|
'for ',
|
||||||
'or ',
|
'or ',
|
||||||
'insert',
|
'insert(',
|
||||||
'delete',
|
'delete(',
|
||||||
'prepend',
|
'prepend(',
|
||||||
'sort',
|
'sort(',
|
||||||
'clear',
|
'clear(',
|
||||||
'trim',
|
'trim(',
|
||||||
'as',
|
' as ',
|
||||||
]
|
]
|
||||||
mut is_statement := false
|
mut is_statement := false
|
||||||
if filter_line.count('=') % 2 == 1 {
|
if filter_line.count('=') % 2 == 1 {
|
||||||
|
|
|
@ -26,6 +26,7 @@ fn main() {
|
||||||
spent := sw.elapsed().milliseconds()
|
spent := sw.elapsed().milliseconds()
|
||||||
oks := commands.filter(it.ecode == 0)
|
oks := commands.filter(it.ecode == 0)
|
||||||
fails := commands.filter(it.ecode != 0)
|
fails := commands.filter(it.ecode != 0)
|
||||||
|
flush_stdout()
|
||||||
println('')
|
println('')
|
||||||
println(term.header_left(term_highlight('Summary of `v test-all`:'), '-'))
|
println(term.header_left(term_highlight('Summary of `v test-all`:'), '-'))
|
||||||
println(term_highlight('Total runtime: $spent ms'))
|
println(term_highlight('Total runtime: $spent ms'))
|
||||||
|
@ -37,6 +38,7 @@ fn main() {
|
||||||
msg := if fcmd.errmsg != '' { fcmd.errmsg } else { fcmd.line }
|
msg := if fcmd.errmsg != '' { fcmd.errmsg } else { fcmd.line }
|
||||||
println(term.failed('> Failed:') + ' $msg')
|
println(term.failed('> Failed:') + ' $msg')
|
||||||
}
|
}
|
||||||
|
flush_stdout()
|
||||||
if fails.len > 0 {
|
if fails.len > 0 {
|
||||||
exit(1)
|
exit(1)
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,52 +5,67 @@ import testing
|
||||||
import v.util
|
import v.util
|
||||||
import arrays
|
import arrays
|
||||||
|
|
||||||
const (
|
const vet_known_failing = [
|
||||||
vet_known_failing_exceptions = []string{}
|
'do_not_delete_this',
|
||||||
vet_folders = [
|
]
|
||||||
'vlib/sqlite',
|
|
||||||
'vlib/v',
|
|
||||||
'vlib/x/json2',
|
|
||||||
'vlib/x/ttf',
|
|
||||||
'cmd/v',
|
|
||||||
'cmd/tools',
|
|
||||||
'examples/2048',
|
|
||||||
'examples/tetris',
|
|
||||||
'examples/term.ui',
|
|
||||||
]
|
|
||||||
verify_known_failing_exceptions = [
|
|
||||||
// Handcrafted meaningful formatting of code parts (mostly arrays)
|
|
||||||
'examples/sokol/02_cubes_glsl/cube_glsl.v',
|
|
||||||
'examples/sokol/03_march_tracing_glsl/rt_glsl.v',
|
|
||||||
'examples/sokol/04_multi_shader_glsl/rt_glsl.v',
|
|
||||||
'examples/sokol/05_instancing_glsl/rt_glsl.v',
|
|
||||||
'examples/sokol/06_obj_viewer/show_obj.v',
|
|
||||||
'vlib/v/checker/tests/modules/deprecated_module/main.v' /* adds deprecated_module. module prefix to imports, even though the folder has v.mod */,
|
|
||||||
'vlib/gg/m4/graphic.v',
|
|
||||||
'vlib/gg/m4/m4_test.v',
|
|
||||||
'vlib/gg/m4/matrix.v',
|
|
||||||
'vlib/builtin/int_test.v' /* special number formatting that should be tested */,
|
|
||||||
// TODOs and unfixed vfmt bugs
|
|
||||||
'vlib/v/gen/js/tests/js.v', /* local `hello` fn, gets replaced with module `hello` aliased as `hl` */
|
|
||||||
]
|
|
||||||
vfmt_verify_list = [
|
|
||||||
'cmd/',
|
|
||||||
'examples/',
|
|
||||||
'tutorials/',
|
|
||||||
'vlib/',
|
|
||||||
]
|
|
||||||
vfmt_known_failing_exceptions = arrays.merge(verify_known_failing_exceptions, [
|
|
||||||
'vlib/regex/regex_test.v' /* contains meaningfull formatting of the test case data */,
|
|
||||||
'vlib/crypto/sha512/sha512block_generic.v' /* formatting of large constant arrays wraps to too many lines */,
|
|
||||||
'vlib/crypto/aes/const.v' /* formatting of large constant arrays wraps to too many lines */,
|
|
||||||
])
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
const vet_known_failing_windows = [
|
||||||
vexe = os.getenv('VEXE')
|
'do_not_delete_this',
|
||||||
vroot = os.dir(vexe)
|
'vlib/v/gen/js/tests/testdata/byte_is_space.v',
|
||||||
is_fix = '-fix' in os.args
|
'vlib/v/gen/js/tests/testdata/compare_ints.v',
|
||||||
)
|
'vlib/v/gen/js/tests/testdata/hw.v',
|
||||||
|
'vlib/v/gen/js/tests/testdata/string_methods.v',
|
||||||
|
'vlib/v/tests/project_with_modules_having_submodules/bin/main.vsh',
|
||||||
|
'vlib/v/tests/valgrind/simple_interpolation_script_mode.v',
|
||||||
|
'vlib/v/tests/valgrind/simple_interpolation_script_mode_more_scopes.v',
|
||||||
|
]
|
||||||
|
|
||||||
|
const vet_folders = [
|
||||||
|
'vlib/sqlite',
|
||||||
|
'vlib/v',
|
||||||
|
'vlib/x/json2',
|
||||||
|
'vlib/x/ttf',
|
||||||
|
'cmd/v',
|
||||||
|
'cmd/tools',
|
||||||
|
'examples/2048',
|
||||||
|
'examples/tetris',
|
||||||
|
'examples/term.ui',
|
||||||
|
]
|
||||||
|
|
||||||
|
const verify_known_failing_exceptions = [
|
||||||
|
// Handcrafted meaningful formatting of code parts (mostly arrays)
|
||||||
|
'examples/sokol/02_cubes_glsl/cube_glsl.v',
|
||||||
|
'examples/sokol/03_march_tracing_glsl/rt_glsl.v',
|
||||||
|
'examples/sokol/04_multi_shader_glsl/rt_glsl.v',
|
||||||
|
'examples/sokol/05_instancing_glsl/rt_glsl.v',
|
||||||
|
'examples/sokol/06_obj_viewer/show_obj.v',
|
||||||
|
'vlib/v/checker/tests/modules/deprecated_module/main.v' /* adds deprecated_module. module prefix to imports, even though the folder has v.mod */,
|
||||||
|
'vlib/gg/m4/graphic.v',
|
||||||
|
'vlib/gg/m4/m4_test.v',
|
||||||
|
'vlib/gg/m4/matrix.v',
|
||||||
|
'vlib/builtin/int_test.v' /* special number formatting that should be tested */,
|
||||||
|
// TODOs and unfixed vfmt bugs
|
||||||
|
'vlib/v/gen/js/tests/js.v', /* local `hello` fn, gets replaced with module `hello` aliased as `hl` */
|
||||||
|
]
|
||||||
|
|
||||||
|
const vfmt_verify_list = [
|
||||||
|
'cmd/',
|
||||||
|
'examples/',
|
||||||
|
'tutorials/',
|
||||||
|
'vlib/',
|
||||||
|
]
|
||||||
|
|
||||||
|
const vfmt_known_failing_exceptions = arrays.merge(verify_known_failing_exceptions, [
|
||||||
|
'vlib/regex/regex_test.v' /* contains meaningfull formatting of the test case data */,
|
||||||
|
'vlib/crypto/sha512/sha512block_generic.v' /* formatting of large constant arrays wraps to too many lines */,
|
||||||
|
'vlib/crypto/aes/const.v' /* formatting of large constant arrays wraps to too many lines */,
|
||||||
|
])
|
||||||
|
|
||||||
|
const vexe = os.getenv('VEXE')
|
||||||
|
|
||||||
|
const vroot = os.dir(vexe)
|
||||||
|
|
||||||
|
const is_fix = '-fix' in os.args
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
args_string := os.args[1..].join(' ')
|
args_string := os.args[1..].join(' ')
|
||||||
|
@ -76,8 +91,12 @@ fn tsession(vargs string, tool_source string, tool_cmd string, tool_args string,
|
||||||
|
|
||||||
fn v_test_vetting(vargs string) {
|
fn v_test_vetting(vargs string) {
|
||||||
expanded_vet_list := util.find_all_v_files(vet_folders) or { return }
|
expanded_vet_list := util.find_all_v_files(vet_folders) or { return }
|
||||||
|
mut vet_known_exceptions := vet_known_failing.clone()
|
||||||
|
if os.user_os() == 'windows' {
|
||||||
|
vet_known_exceptions << vet_known_failing_windows
|
||||||
|
}
|
||||||
vet_session := tsession(vargs, 'vvet', '${os.quoted_path(vexe)} vet', 'vet', expanded_vet_list,
|
vet_session := tsession(vargs, 'vvet', '${os.quoted_path(vexe)} vet', 'vet', expanded_vet_list,
|
||||||
vet_known_failing_exceptions)
|
vet_known_exceptions)
|
||||||
//
|
//
|
||||||
fmt_cmd, fmt_args := if is_fix {
|
fmt_cmd, fmt_args := if is_fix {
|
||||||
'${os.quoted_path(vexe)} fmt -w', 'fmt -w'
|
'${os.quoted_path(vexe)} fmt -w', 'fmt -w'
|
||||||
|
|
|
@ -6,7 +6,83 @@ import v.pref
|
||||||
|
|
||||||
const github_job = os.getenv('GITHUB_JOB')
|
const github_job = os.getenv('GITHUB_JOB')
|
||||||
|
|
||||||
|
const just_essential = os.getenv('VTEST_JUST_ESSENTIAL') != ''
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
essential_list = [
|
||||||
|
'cmd/tools/vvet/vet_test.v',
|
||||||
|
'vlib/arrays/arrays_test.v',
|
||||||
|
'vlib/bitfield/bitfield_test.v',
|
||||||
|
//
|
||||||
|
'vlib/builtin/int_test.v',
|
||||||
|
'vlib/builtin/array_test.v',
|
||||||
|
'vlib/builtin/float_test.v',
|
||||||
|
'vlib/builtin/byte_test.v',
|
||||||
|
'vlib/builtin/rune_test.v',
|
||||||
|
'vlib/builtin/builtin_test.v',
|
||||||
|
'vlib/builtin/map_of_floats_test.v',
|
||||||
|
'vlib/builtin/string_int_test.v',
|
||||||
|
'vlib/builtin/utf8_test.v',
|
||||||
|
'vlib/builtin/map_test.v',
|
||||||
|
'vlib/builtin/string_test.v',
|
||||||
|
'vlib/builtin/sorting_test.v',
|
||||||
|
'vlib/builtin/gated_array_string_test.v',
|
||||||
|
'vlib/builtin/array_shrinkage_test.v',
|
||||||
|
'vlib/builtin/isnil_test.v',
|
||||||
|
'vlib/builtin/string_match_glob_test.v',
|
||||||
|
'vlib/builtin/string_strip_margin_test.v',
|
||||||
|
//
|
||||||
|
'vlib/cli/command_test.v',
|
||||||
|
'vlib/crypto/md5/md5_test.v',
|
||||||
|
'vlib/dl/dl_test.v',
|
||||||
|
'vlib/encoding/base64/base64_test.v',
|
||||||
|
'vlib/encoding/utf8/encoding_utf8_test.v',
|
||||||
|
'vlib/encoding/utf8/utf8_util_test.v',
|
||||||
|
'vlib/flag/flag_test.v',
|
||||||
|
'vlib/json/json_decode_test.v',
|
||||||
|
'vlib/math/math_test.v',
|
||||||
|
'vlib/net/tcp_test.v',
|
||||||
|
'vlib/net/http/http_test.v',
|
||||||
|
'vlib/net/http/server_test.v',
|
||||||
|
'vlib/net/http/request_test.v',
|
||||||
|
'vlib/io/io_test.v',
|
||||||
|
'vlib/io/os_file_reader_test.v',
|
||||||
|
'vlib/os/process_test.v',
|
||||||
|
'vlib/os/file_test.v',
|
||||||
|
'vlib/os/notify/notify_test.v',
|
||||||
|
'vlib/os/filepath_test.v',
|
||||||
|
'vlib/os/environment_test.v',
|
||||||
|
'vlib/os/glob_test.v',
|
||||||
|
'vlib/os/os_test.v',
|
||||||
|
'vlib/rand/random_numbers_test.v',
|
||||||
|
'vlib/rand/wyrand/wyrand_test.v',
|
||||||
|
'vlib/runtime/runtime_test.v',
|
||||||
|
'vlib/semver/semver_test.v',
|
||||||
|
'vlib/sync/stdatomic/atomic_test.v',
|
||||||
|
'vlib/sync/thread_test.v',
|
||||||
|
'vlib/sync/waitgroup_test.v',
|
||||||
|
'vlib/sync/pool/pool_test.v',
|
||||||
|
'vlib/strings/builder_test.v',
|
||||||
|
'vlib/strconv/atof_test.v',
|
||||||
|
'vlib/strconv/atoi_test.v',
|
||||||
|
'vlib/strconv/f32_f64_to_string_test.v',
|
||||||
|
'vlib/strconv/format_test.v',
|
||||||
|
'vlib/strconv/number_to_base_test.v',
|
||||||
|
'vlib/time/time_test.v',
|
||||||
|
'vlib/toml/tests/toml_test.v',
|
||||||
|
'vlib/v/compiler_errors_test.v',
|
||||||
|
'vlib/v/doc/doc_test.v',
|
||||||
|
'vlib/v/eval/interpret_test.v',
|
||||||
|
'vlib/v/fmt/fmt_keep_test.v',
|
||||||
|
'vlib/v/fmt/fmt_test.v',
|
||||||
|
'vlib/v/gen/c/coutput_test.v',
|
||||||
|
'vlib/v/gen/js/program_test.v',
|
||||||
|
'vlib/v/gen/native/macho_test.v',
|
||||||
|
'vlib/v/gen/native/tests/native_test.v',
|
||||||
|
'vlib/v/pkgconfig/pkgconfig_test.v',
|
||||||
|
'vlib/v/tests/inout/compiler_test.v',
|
||||||
|
'vlib/x/json2/json2_test.v',
|
||||||
|
]
|
||||||
skip_test_files = [
|
skip_test_files = [
|
||||||
'cmd/tools/vdoc/html_tag_escape_test.v', /* can't locate local module: markdown */
|
'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 */
|
'cmd/tools/vdoc/tests/vdoc_file_test.v', /* fails on Windows; order of output is not as expected */
|
||||||
|
@ -66,6 +142,7 @@ const (
|
||||||
]
|
]
|
||||||
skip_with_werror = [
|
skip_with_werror = [
|
||||||
'do_not_remove',
|
'do_not_remove',
|
||||||
|
'vlib/v/embed_file/tests/embed_file_test.v',
|
||||||
]
|
]
|
||||||
skip_with_asan_compiler = [
|
skip_with_asan_compiler = [
|
||||||
'do_not_remove',
|
'do_not_remove',
|
||||||
|
@ -109,6 +186,10 @@ const (
|
||||||
skip_on_non_linux = [
|
skip_on_non_linux = [
|
||||||
'do_not_remove',
|
'do_not_remove',
|
||||||
]
|
]
|
||||||
|
skip_on_windows_msvc = [
|
||||||
|
'do_not_remove',
|
||||||
|
'vlib/v/tests/const_fixed_array_containing_references_to_itself_test.v', // error C2099: initializer is not a constant
|
||||||
|
]
|
||||||
skip_on_windows = [
|
skip_on_windows = [
|
||||||
'vlib/context/cancel_test.v',
|
'vlib/context/cancel_test.v',
|
||||||
'vlib/context/deadline_test.v',
|
'vlib/context/deadline_test.v',
|
||||||
|
@ -172,6 +253,11 @@ fn main() {
|
||||||
all_test_files << os.walk_ext(os.join_path(vroot, 'cmd'), '_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')
|
test_js_files := os.walk_ext(os.join_path(vroot, 'vlib'), '_test.js.v')
|
||||||
all_test_files << test_js_files
|
all_test_files << test_js_files
|
||||||
|
|
||||||
|
if just_essential {
|
||||||
|
rooted_essential_list := essential_list.map(os.join_path(vroot, it))
|
||||||
|
all_test_files = all_test_files.filter(rooted_essential_list.contains(it))
|
||||||
|
}
|
||||||
testing.eheader(title)
|
testing.eheader(title)
|
||||||
mut tsession := testing.new_test_session(cmd_prefix, true)
|
mut tsession := testing.new_test_session(cmd_prefix, true)
|
||||||
tsession.files << all_test_files.filter(!it.contains('testdata' + os.path_separator))
|
tsession.files << all_test_files.filter(!it.contains('testdata' + os.path_separator))
|
||||||
|
@ -264,6 +350,9 @@ fn main() {
|
||||||
}
|
}
|
||||||
$if windows {
|
$if windows {
|
||||||
tsession.skip_files << skip_on_windows
|
tsession.skip_files << skip_on_windows
|
||||||
|
$if msvc {
|
||||||
|
tsession.skip_files << skip_on_windows_msvc
|
||||||
|
}
|
||||||
}
|
}
|
||||||
$if !windows {
|
$if !windows {
|
||||||
tsession.skip_files << skip_on_non_windows
|
tsession.skip_files << skip_on_non_windows
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
fn abc() int {
|
||||||
|
return if true {
|
||||||
|
0x4000 // 16KB
|
||||||
|
} else {
|
||||||
|
0x1000 // 4KB
|
||||||
|
}
|
||||||
|
}
|
|
@ -89,6 +89,7 @@ mut:
|
||||||
v_cycles int // how many times the worker has restarted the V compiler
|
v_cycles int // how many times the worker has restarted the V compiler
|
||||||
scan_cycles int // how many times the worker has scanned for source file changes
|
scan_cycles int // how many times the worker has scanned for source file changes
|
||||||
clear_terminal bool // whether to clear the terminal before each re-run
|
clear_terminal bool // whether to clear the terminal before each re-run
|
||||||
|
keep_running bool // when true, re-run the program automatically if it exits on its own. Useful for gg apps.
|
||||||
silent bool // when true, watch will not print a timestamp line before each re-run
|
silent bool // when true, watch will not print a timestamp line before each re-run
|
||||||
add_files []string // path to additional files that have to be watched for changes
|
add_files []string // path to additional files that have to be watched for changes
|
||||||
ignore_exts []string // extensions of files that will be ignored, even if they change (useful for sqlite.db files for example)
|
ignore_exts []string // extensions of files that will be ignored, even if they change (useful for sqlite.db files for example)
|
||||||
|
@ -207,7 +208,7 @@ fn change_detection_loop(ocontext &Context) {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (mut context Context) kill_pgroup() {
|
fn (mut context Context) kill_pgroup() {
|
||||||
if context.child_process == 0 {
|
if unsafe { context.child_process == 0 } {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if context.child_process.is_alive() {
|
if context.child_process.is_alive() {
|
||||||
|
@ -260,6 +261,9 @@ fn (mut context Context) compilation_runner_loop() {
|
||||||
if notalive_count == 1 {
|
if notalive_count == 1 {
|
||||||
// a short lived process finished, do cleanup:
|
// a short lived process finished, do cleanup:
|
||||||
context.run_after_cmd()
|
context.run_after_cmd()
|
||||||
|
if context.keep_running {
|
||||||
|
break
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
select {
|
select {
|
||||||
|
@ -282,6 +286,7 @@ fn (mut context Context) compilation_runner_loop() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !context.child_process.is_alive() {
|
if !context.child_process.is_alive() {
|
||||||
|
context.elog('> child_process is no longer alive | notalive_count: $notalive_count')
|
||||||
context.child_process.wait()
|
context.child_process.wait()
|
||||||
context.child_process.close()
|
context.child_process.close()
|
||||||
if notalive_count == 0 {
|
if notalive_count == 0 {
|
||||||
|
@ -317,6 +322,7 @@ fn main() {
|
||||||
context.is_worker = fp.bool('vwatchworker', 0, false, 'Internal flag. Used to distinguish vwatch manager and worker processes.')
|
context.is_worker = fp.bool('vwatchworker', 0, false, 'Internal flag. Used to distinguish vwatch manager and worker processes.')
|
||||||
context.silent = fp.bool('silent', `s`, false, 'Be more silent; do not print the watch timestamp before each re-run.')
|
context.silent = fp.bool('silent', `s`, false, 'Be more silent; do not print the watch timestamp before each re-run.')
|
||||||
context.clear_terminal = fp.bool('clear', `c`, false, 'Clears the terminal before each re-run.')
|
context.clear_terminal = fp.bool('clear', `c`, false, 'Clears the terminal before each re-run.')
|
||||||
|
context.keep_running = fp.bool('keep', `k`, false, 'Keep the program running. Restart it automatically, if it exits by itself. Useful for gg/ui apps.')
|
||||||
context.add_files = fp.string('add', `a`, '', 'Add more files to be watched. Useful with `v watch -add=/tmp/feature.v run cmd/v /tmp/feature.v`, if you change *both* the compiler, and the feature.v file.').split(',')
|
context.add_files = fp.string('add', `a`, '', 'Add more files to be watched. Useful with `v watch -add=/tmp/feature.v run cmd/v /tmp/feature.v`, if you change *both* the compiler, and the feature.v file.').split(',')
|
||||||
context.ignore_exts = fp.string('ignore', `i`, '', 'Ignore files having these extensions. Useful with `v watch -ignore=.db run server.v`, if your server writes to an sqlite.db file in the same folder.').split(',')
|
context.ignore_exts = fp.string('ignore', `i`, '', 'Ignore files having these extensions. Useful with `v watch -ignore=.db run server.v`, if your server writes to an sqlite.db file in the same folder.').split(',')
|
||||||
show_help := fp.bool('help', `h`, false, 'Show this help screen.')
|
show_help := fp.bool('help', `h`, false, 'Show this help screen.')
|
||||||
|
|
|
@ -25,7 +25,20 @@ see also `v help build`.
|
||||||
|
|
||||||
-cstrict
|
-cstrict
|
||||||
Turn on additional C warnings. This slows down compilation
|
Turn on additional C warnings. This slows down compilation
|
||||||
slightly (~10% for gcc), but sometimes provides better diagnosis.
|
slightly (~10% for gcc), but sometimes provides better error diagnosis.
|
||||||
|
|
||||||
|
-cmain <MainFunctionName>
|
||||||
|
Useful with framework like code, that uses macros to re-define `main`, like SDL2 does for example.
|
||||||
|
With that option, V will always generate:
|
||||||
|
`int MainFunctionName(int ___argc, char** ___argv) {` , for the program entry point function, *no matter* the OS.
|
||||||
|
Without it, on non Windows systems, it will generate:
|
||||||
|
`int main(int ___argc, char** ___argv) {`
|
||||||
|
... and on Windows, it will generate:
|
||||||
|
a) `int WINAPI wWinMain(HINSTANCE instance, HINSTANCE prev_instance, LPWSTR cmd_line, int show_cmd){`
|
||||||
|
when you are compiling applications that `import gg`.
|
||||||
|
... or it will generate:
|
||||||
|
b) `int wmain(int ___argc, wchar_t* ___argv[], wchar_t* ___envp[]){`
|
||||||
|
when you are compiling console apps.
|
||||||
|
|
||||||
-showcc
|
-showcc
|
||||||
Prints the C command that is used to build the program.
|
Prints the C command that is used to build the program.
|
||||||
|
@ -239,7 +252,15 @@ see also `v help build`.
|
||||||
|
|
||||||
-dump-c-flags file.txt
|
-dump-c-flags file.txt
|
||||||
Write all C flags into `file.txt`, one flag per line.
|
Write all C flags into `file.txt`, one flag per line.
|
||||||
If `file.txt` is `-`, then write the flags to stdout, one flag per line.
|
If `file.txt` is `-`, write to stdout instead.
|
||||||
|
|
||||||
|
-dump-modules file.txt
|
||||||
|
Write all module names used by the program in `file.txt`, one module per line.
|
||||||
|
If `file.txt` is `-`, write to stdout instead.
|
||||||
|
|
||||||
|
-dump-files file.txt
|
||||||
|
Write all used V file paths used by the program in `file.txt`, one module per line.
|
||||||
|
If `file.txt` is `-`, write to stdout instead.
|
||||||
|
|
||||||
-no-rsp
|
-no-rsp
|
||||||
By default, V passes all C compiler options to the backend C compiler
|
By default, V passes all C compiler options to the backend C compiler
|
||||||
|
|
|
@ -14,4 +14,4 @@ For more general build help, see also `v help build`.
|
||||||
-os <os>, -target-os <os>
|
-os <os>, -target-os <os>
|
||||||
Change the target OS that V compiles for.
|
Change the target OS that V compiles for.
|
||||||
|
|
||||||
The supported targets for the native backend are: `macos`, `linux`
|
The supported targets for the native backend are: `macos`, `linux` and 'windows'
|
||||||
|
|
|
@ -7,6 +7,7 @@ Examples:
|
||||||
v hello.v Compile the file `hello.v` and output it as `hello` or `hello.exe`.
|
v hello.v Compile the file `hello.v` and output it as `hello` or `hello.exe`.
|
||||||
v run hello.v Same as above but also run the produced executable immediately after compilation.
|
v run hello.v Same as above but also run the produced executable immediately after compilation.
|
||||||
v -cg run hello.v Same as above, but make debugging easier (in case your program crashes).
|
v -cg run hello.v Same as above, but make debugging easier (in case your program crashes).
|
||||||
|
v crun hello.v Same as above, but do not recompile, if the executable already exists, and is newer than the sources.
|
||||||
v -o h.c hello.v Translate `hello.v` to `h.c`. Do not compile further.
|
v -o h.c hello.v Translate `hello.v` to `h.c`. Do not compile further.
|
||||||
v -o - hello.v Translate `hello.v` and output the C source code to stdout. Do not compile further.
|
v -o - hello.v Translate `hello.v` and output the C source code to stdout. Do not compile further.
|
||||||
|
|
||||||
|
@ -20,7 +21,10 @@ V supports the following commands:
|
||||||
init Setup the file structure for an already existing V project.
|
init Setup the file structure for an already existing V project.
|
||||||
|
|
||||||
* Ordinary development:
|
* Ordinary development:
|
||||||
run Compile and run a V program.
|
run Compile and run a V program. Delete the executable after the run.
|
||||||
|
crun Compile and run a V program without deleting the executable.
|
||||||
|
If you run the same program a second time, without changing the source files,
|
||||||
|
V will just run the executable, without recompilation. Suitable for scripting.
|
||||||
test Run all test files in the provided directory.
|
test Run all test files in the provided directory.
|
||||||
fmt Format the V code provided.
|
fmt Format the V code provided.
|
||||||
vet Report suspicious code constructs.
|
vet Report suspicious code constructs.
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
v missdoc 0.0.4
|
v missdoc 0.1.0
|
||||||
-----------------------------------------------
|
-----------------------------------------------
|
||||||
Usage: v missdoc [options] PATH [PATH]...
|
Usage: v missdoc [options] PATH [PATH]...
|
||||||
|
|
||||||
|
@ -12,5 +12,25 @@ Options:
|
||||||
--js Include JavaScript functions in output.
|
--js Include JavaScript functions in output.
|
||||||
-n, --no-line-numbers Exclude line numbers in output.
|
-n, --no-line-numbers Exclude line numbers in output.
|
||||||
-e, --exclude <multiple strings>
|
-e, --exclude <multiple strings>
|
||||||
|
|
||||||
-r, --relative-paths Use relative paths in output.
|
-r, --relative-paths Use relative paths in output.
|
||||||
|
--verify exit(1) if documentation is missing, 0 otherwise.
|
||||||
|
--diff exit(1) and show difference between two PATH inputs, return 0 otherwise.
|
||||||
|
--version output version information and exit
|
||||||
|
|
||||||
|
-----------------------------------------------
|
||||||
|
|
||||||
|
PATH can be both files and directories.
|
||||||
|
|
||||||
|
The `--verify` flag is useful for use in CI setups for checking if a V project
|
||||||
|
has all it's functions and methods documented:
|
||||||
|
```
|
||||||
|
v missdoc --verify path/to/code
|
||||||
|
```
|
||||||
|
|
||||||
|
The `--diff` flag is useful if your project is not yet fully documented
|
||||||
|
but you want to ensure that no new functions or methods are introduced
|
||||||
|
between commits or branches:
|
||||||
|
```
|
||||||
|
v missdoc --diff current/code new/code
|
||||||
|
```
|
||||||
|
|
81
cmd/v/v.v
81
cmd/v/v.v
|
@ -93,17 +93,21 @@ fn main() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
match command {
|
match command {
|
||||||
|
'run', 'crun', 'build', 'build-module' {
|
||||||
|
rebuild(prefs)
|
||||||
|
return
|
||||||
|
}
|
||||||
'help' {
|
'help' {
|
||||||
invoke_help_and_exit(args)
|
invoke_help_and_exit(args)
|
||||||
}
|
}
|
||||||
|
'version' {
|
||||||
|
println(version.full_v_version(prefs.is_verbose))
|
||||||
|
return
|
||||||
|
}
|
||||||
'new', 'init' {
|
'new', 'init' {
|
||||||
util.launch_tool(prefs.is_verbose, 'vcreate', os.args[1..])
|
util.launch_tool(prefs.is_verbose, 'vcreate', os.args[1..])
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
'translate' {
|
|
||||||
eprintln('Translating C to V will be available in V 0.3')
|
|
||||||
exit(1)
|
|
||||||
}
|
|
||||||
'install', 'list', 'outdated', 'remove', 'search', 'show', 'update', 'upgrade' {
|
'install', 'list', 'outdated', 'remove', 'search', 'show', 'update', 'upgrade' {
|
||||||
util.launch_tool(prefs.is_verbose, 'vpm', os.args[1..])
|
util.launch_tool(prefs.is_verbose, 'vpm', os.args[1..])
|
||||||
return
|
return
|
||||||
|
@ -118,42 +122,25 @@ fn main() {
|
||||||
eprintln('V Error: Use `v install` to install modules from vpm.vlang.io')
|
eprintln('V Error: Use `v install` to install modules from vpm.vlang.io')
|
||||||
exit(1)
|
exit(1)
|
||||||
}
|
}
|
||||||
'version' {
|
'translate' {
|
||||||
println(version.full_v_version(prefs.is_verbose))
|
util.launch_tool(prefs.is_verbose, 'translate', os.args[1..])
|
||||||
return
|
// exit(1)
|
||||||
|
// return
|
||||||
}
|
}
|
||||||
else {}
|
else {
|
||||||
}
|
if command.ends_with('.v') || os.exists(command) {
|
||||||
if command in ['run', 'build', 'build-module'] || command.ends_with('.v') || os.exists(command) {
|
// println('command')
|
||||||
// println('command')
|
// println(prefs.path)
|
||||||
// println(prefs.path)
|
rebuild(prefs)
|
||||||
match prefs.backend {
|
return
|
||||||
.c {
|
|
||||||
$if no_bootstrapv ? {
|
|
||||||
// TODO: improve the bootstrapping with a split C backend here.
|
|
||||||
// C code generated by `VEXE=v cmd/tools/builders/c_builder -os cross -o c.c cmd/tools/builders/c_builder.v`
|
|
||||||
// is enough to bootstrap the C backend, and thus the rest, but currently bootstrapping relies on
|
|
||||||
// `v -os cross -o v.c cmd/v` having a functional C codegen inside instead.
|
|
||||||
util.launch_tool(prefs.is_verbose, 'builders/c_builder', os.args[1..])
|
|
||||||
}
|
|
||||||
builder.compile('build', prefs, cbuilder.compile_c)
|
|
||||||
}
|
|
||||||
.js_node, .js_freestanding, .js_browser {
|
|
||||||
util.launch_tool(prefs.is_verbose, 'builders/js_builder', os.args[1..])
|
|
||||||
}
|
|
||||||
.native {
|
|
||||||
util.launch_tool(prefs.is_verbose, 'builders/native_builder', os.args[1..])
|
|
||||||
}
|
|
||||||
.interpret {
|
|
||||||
util.launch_tool(prefs.is_verbose, 'builders/interpret_builder', os.args[1..])
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return
|
|
||||||
}
|
}
|
||||||
if prefs.is_help {
|
if prefs.is_help {
|
||||||
invoke_help_and_exit(args)
|
invoke_help_and_exit(args)
|
||||||
}
|
}
|
||||||
eprintln('v $command: unknown command\nRun ${term.highlight_command('v help')} for usage.')
|
eprintln('v $command: unknown command')
|
||||||
|
eprintln('Run ${term.highlight_command('v help')} for usage.')
|
||||||
exit(1)
|
exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -163,7 +150,31 @@ fn invoke_help_and_exit(remaining []string) {
|
||||||
2 { help.print_and_exit(remaining[1]) }
|
2 { help.print_and_exit(remaining[1]) }
|
||||||
else {}
|
else {}
|
||||||
}
|
}
|
||||||
println('${term.highlight_command('v help')}: provide only one help topic.')
|
eprintln('${term.highlight_command('v help')}: provide only one help topic.')
|
||||||
println('For usage information, use ${term.highlight_command('v help')}.')
|
eprintln('For usage information, use ${term.highlight_command('v help')}.')
|
||||||
exit(1)
|
exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn rebuild(prefs &pref.Preferences) {
|
||||||
|
match prefs.backend {
|
||||||
|
.c {
|
||||||
|
$if no_bootstrapv ? {
|
||||||
|
// TODO: improve the bootstrapping with a split C backend here.
|
||||||
|
// C code generated by `VEXE=v cmd/tools/builders/c_builder -os cross -o c.c cmd/tools/builders/c_builder.v`
|
||||||
|
// is enough to bootstrap the C backend, and thus the rest, but currently bootstrapping relies on
|
||||||
|
// `v -os cross -o v.c cmd/v` having a functional C codegen inside instead.
|
||||||
|
util.launch_tool(prefs.is_verbose, 'builders/c_builder', os.args[1..])
|
||||||
|
}
|
||||||
|
builder.compile('build', prefs, cbuilder.compile_c)
|
||||||
|
}
|
||||||
|
.js_node, .js_freestanding, .js_browser {
|
||||||
|
util.launch_tool(prefs.is_verbose, 'builders/js_builder', os.args[1..])
|
||||||
|
}
|
||||||
|
.native {
|
||||||
|
util.launch_tool(prefs.is_verbose, 'builders/native_builder', os.args[1..])
|
||||||
|
}
|
||||||
|
.interpret {
|
||||||
|
util.launch_tool(prefs.is_verbose, 'builders/interpret_builder', os.args[1..])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
34
doc/docs.md
34
doc/docs.md
|
@ -616,7 +616,7 @@ Also note: in most cases, it's best to leave the format type empty. Floats will
|
||||||
default as `g`, integers will be rendered by default as `d`, and `s` is almost always redundant.
|
default as `g`, integers will be rendered by default as `d`, and `s` is almost always redundant.
|
||||||
There are only three cases where specifying a type is recommended:
|
There are only three cases where specifying a type is recommended:
|
||||||
|
|
||||||
- format strings are parsed at compile time, so specifing a type can help detect errors then
|
- format strings are parsed at compile time, so specifying a type can help detect errors then
|
||||||
- format strings default to using lowercase letters for hex digits and the `e` in exponents. Use a
|
- format strings default to using lowercase letters for hex digits and the `e` in exponents. Use a
|
||||||
uppercase type to force the use of uppercase hex digits and an uppercase `E` in exponents.
|
uppercase type to force the use of uppercase hex digits and an uppercase `E` in exponents.
|
||||||
- format strings are the most convenient way to get hex, binary or octal strings from an integer.
|
- format strings are the most convenient way to get hex, binary or octal strings from an integer.
|
||||||
|
@ -1295,6 +1295,16 @@ mm := map[string]int{}
|
||||||
val := mm['bad_key'] or { panic('key not found') }
|
val := mm['bad_key'] or { panic('key not found') }
|
||||||
```
|
```
|
||||||
|
|
||||||
|
You can also check, if a key is present, and get its value, if it was present, in one go:
|
||||||
|
```v
|
||||||
|
m := {
|
||||||
|
'abc': 'def'
|
||||||
|
}
|
||||||
|
if v := m['abc'] {
|
||||||
|
println('the map value for that key is: $v')
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
The same optional check applies to arrays:
|
The same optional check applies to arrays:
|
||||||
|
|
||||||
```v
|
```v
|
||||||
|
@ -4104,17 +4114,16 @@ fn (data &MyType) free() {
|
||||||
Just as the compiler frees C data types with C's `free()`, it will statically insert
|
Just as the compiler frees C data types with C's `free()`, it will statically insert
|
||||||
`free()` calls for your data type at the end of each variable's lifetime.
|
`free()` calls for your data type at the end of each variable's lifetime.
|
||||||
|
|
||||||
|
Autofree can be enabled with an `-autofree` flag.
|
||||||
|
|
||||||
For developers willing to have more low level control, autofree can be disabled with
|
For developers willing to have more low level control, autofree can be disabled with
|
||||||
`-manualfree`, or by adding a `[manualfree]` on each function that wants manage its
|
`-manualfree`, or by adding a `[manualfree]` on each function that wants manage its
|
||||||
memory manually. (See [attributes](#attributes)).
|
memory manually. (See [attributes](#attributes)).
|
||||||
|
|
||||||
_Note: right now autofree is hidden behind the -autofree flag. It will be enabled by
|
|
||||||
default in V 0.3. If autofree is not used, V programs will leak memory._
|
|
||||||
|
|
||||||
Note 2: Autofree is still WIP. Until it stabilises and becomes the default, please
|
Note 2: Autofree is still WIP. Until it stabilises and becomes the default, please
|
||||||
compile your long running processes with `-gc boehm`, which will use the
|
avoid using it. Right now allocations are handled by a minimal and well performing GC
|
||||||
Boehm-Demers-Weiser conservative garbage collector, to free the memory, that your
|
until V's autofree engine is production ready.
|
||||||
programs leak, at runtime.
|
|
||||||
|
|
||||||
### Examples
|
### Examples
|
||||||
|
|
||||||
|
@ -5905,6 +5914,19 @@ fn main() {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Struct field deprecations:
|
||||||
|
```v oksyntax
|
||||||
|
module abc
|
||||||
|
|
||||||
|
// Note that only *direct* accesses to Xyz.d in *other modules*, will produce deprecation notices/warnings:
|
||||||
|
pub struct Xyz {
|
||||||
|
pub mut:
|
||||||
|
a int
|
||||||
|
d int [deprecated: 'use Xyz.a instead'; deprecated_after: '2999-03-01'] // produce a notice, the deprecation date is in the far future
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Function/method deprecations:
|
||||||
```v
|
```v
|
||||||
// Calling this function will result in a deprecation warning
|
// Calling this function will result in a deprecation warning
|
||||||
[deprecated]
|
[deprecated]
|
||||||
|
|
|
@ -7,9 +7,9 @@ fn vlang_time(mut wg sync.WaitGroup) ?string {
|
||||||
data := http.get('https://vlang.io/utc_now')?
|
data := http.get('https://vlang.io/utc_now')?
|
||||||
finish := time.ticks()
|
finish := time.ticks()
|
||||||
println('Finish getting time ${finish - start} ms')
|
println('Finish getting time ${finish - start} ms')
|
||||||
println(data.text)
|
println(data.body)
|
||||||
wg.done()
|
wg.done()
|
||||||
return data.text
|
return data.body
|
||||||
}
|
}
|
||||||
|
|
||||||
fn remote_ip(mut wg sync.WaitGroup) ?string {
|
fn remote_ip(mut wg sync.WaitGroup) ?string {
|
||||||
|
@ -17,9 +17,9 @@ fn remote_ip(mut wg sync.WaitGroup) ?string {
|
||||||
data := http.get('https://api.ipify.org')?
|
data := http.get('https://api.ipify.org')?
|
||||||
finish := time.ticks()
|
finish := time.ticks()
|
||||||
println('Finish getting ip ${finish - start} ms')
|
println('Finish getting ip ${finish - start} ms')
|
||||||
println(data.text)
|
println(data.body)
|
||||||
wg.done()
|
wg.done()
|
||||||
return data.text
|
return data.body
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
|
|
@ -1,12 +1,15 @@
|
||||||
module main
|
module main
|
||||||
|
|
||||||
|
// Note: This program, requires that the shared library was already compiled.
|
||||||
|
// To do so, run `v -d no_backtrace -o library -shared modules/library/library.v`
|
||||||
|
// before running this program.
|
||||||
import os
|
import os
|
||||||
import dl
|
import dl
|
||||||
|
|
||||||
type FNAdder = fn (int, int) int
|
type FNAdder = fn (int, int) int
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
library_file_path := os.join_path(os.getwd(), dl.get_libname('library'))
|
library_file_path := os.join_path(os.dir(@FILE), dl.get_libname('library'))
|
||||||
handle := dl.open_opt(library_file_path, dl.rtld_lazy)?
|
handle := dl.open_opt(library_file_path, dl.rtld_lazy)?
|
||||||
eprintln('handle: ${ptr_str(handle)}')
|
eprintln('handle: ${ptr_str(handle)}')
|
||||||
f := FNAdder(dl.sym_opt(handle, 'add_1')?)
|
f := FNAdder(dl.sym_opt(handle, 'add_1')?)
|
||||||
|
|
|
@ -7,6 +7,6 @@ fn main() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
t := time.unix(resp.text.int())
|
t := time.unix(resp.body.int())
|
||||||
println(t.format())
|
println(t.format())
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,7 +42,7 @@ fn (mut l Layer) populate(nb_neurons int, nb_inputs int) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Network {
|
pub struct Network {
|
||||||
mut:
|
mut:
|
||||||
layers []Layer
|
layers []Layer
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,7 +46,7 @@ fn main() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
weather := json.decode(Weather, resp.text) or {
|
weather := json.decode(Weather, resp.body) or {
|
||||||
println('failed to decode weather json')
|
println('failed to decode weather json')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,8 +7,12 @@ const pwidth = 800
|
||||||
|
|
||||||
const pheight = 600
|
const pheight = 600
|
||||||
|
|
||||||
|
const chunk_height = 2 // the image is recalculated in chunks, each chunk processed in a separate thread
|
||||||
|
|
||||||
const zoom_factor = 1.1
|
const zoom_factor = 1.1
|
||||||
|
|
||||||
|
const max_iterations = 255
|
||||||
|
|
||||||
struct ViewRect {
|
struct ViewRect {
|
||||||
mut:
|
mut:
|
||||||
x_min f64
|
x_min f64
|
||||||
|
@ -17,22 +21,48 @@ mut:
|
||||||
y_max f64
|
y_max f64
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn (v &ViewRect) width() f64 {
|
||||||
|
return v.x_max - v.x_min
|
||||||
|
}
|
||||||
|
|
||||||
|
fn (v &ViewRect) height() f64 {
|
||||||
|
return v.y_max - v.y_min
|
||||||
|
}
|
||||||
|
|
||||||
struct AppState {
|
struct AppState {
|
||||||
mut:
|
mut:
|
||||||
gg &gg.Context = 0
|
gg &gg.Context = 0
|
||||||
iidx int
|
iidx int
|
||||||
pixels []u32 = []u32{len: pwidth * pheight}
|
pixels &u32 = unsafe { vcalloc(pwidth * pheight * sizeof(u32)) }
|
||||||
npixels []u32 = []u32{len: pwidth * pheight} // all drawing happens here, results are copied at the end
|
npixels &u32 = unsafe { vcalloc(pwidth * pheight * sizeof(u32)) } // all drawing happens here, results are swapped at the end
|
||||||
view ViewRect = ViewRect{-2.7610033817025625, 1.1788897130338223, -1.824584023871934, 2.1153096311072788}
|
view ViewRect = ViewRect{-3.0773593290970673, 1.4952456603855397, -2.019938598189011, 2.3106642054225945}
|
||||||
|
scale int = 1
|
||||||
ntasks int = runtime.nr_jobs()
|
ntasks int = runtime.nr_jobs()
|
||||||
}
|
}
|
||||||
|
|
||||||
const colors = [gx.black, gx.blue, gx.red, gx.green, gx.yellow, gx.orange, gx.purple, gx.white,
|
const colors = [gx.black, gx.blue, gx.red, gx.green, gx.yellow, gx.orange, gx.purple, gx.white,
|
||||||
gx.indigo, gx.violet, gx.black]
|
gx.indigo, gx.violet, gx.black, gx.blue, gx.orange, gx.yellow, gx.green].map(u32(it.abgr8()))
|
||||||
|
|
||||||
|
struct MandelChunk {
|
||||||
|
cview ViewRect
|
||||||
|
ymin f64
|
||||||
|
ymax f64
|
||||||
|
}
|
||||||
|
|
||||||
fn (mut state AppState) update() {
|
fn (mut state AppState) update() {
|
||||||
mut sw := time.new_stopwatch()
|
mut chunk_channel := chan MandelChunk{cap: state.ntasks}
|
||||||
|
mut chunk_ready_channel := chan bool{cap: 1000}
|
||||||
|
mut threads := []thread{cap: state.ntasks}
|
||||||
|
defer {
|
||||||
|
chunk_channel.close()
|
||||||
|
threads.wait()
|
||||||
|
}
|
||||||
|
for t in 0 .. state.ntasks {
|
||||||
|
threads << go state.worker(t, chunk_channel, chunk_ready_channel)
|
||||||
|
}
|
||||||
|
//
|
||||||
mut oview := ViewRect{}
|
mut oview := ViewRect{}
|
||||||
|
mut sw := time.new_stopwatch()
|
||||||
for {
|
for {
|
||||||
sw.restart()
|
sw.restart()
|
||||||
cview := state.view
|
cview := state.view
|
||||||
|
@ -40,39 +70,61 @@ fn (mut state AppState) update() {
|
||||||
time.sleep(5 * time.millisecond)
|
time.sleep(5 * time.millisecond)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
sheight := pheight / state.ntasks
|
// schedule chunks, describing the work:
|
||||||
mut threads := []thread{}
|
mut nchunks := 0
|
||||||
for start := 0; start < pheight; start += sheight {
|
for start := 0; start < pheight; start += chunk_height {
|
||||||
threads << go state.recalc_lines(cview, start, start + sheight)
|
chunk_channel <- MandelChunk{
|
||||||
|
cview: cview
|
||||||
|
ymin: start
|
||||||
|
ymax: start + chunk_height
|
||||||
|
}
|
||||||
|
nchunks++
|
||||||
}
|
}
|
||||||
threads.wait()
|
// wait for all chunks to be processed:
|
||||||
state.pixels = state.npixels
|
for _ in 0 .. nchunks {
|
||||||
println('$state.ntasks threads; $sw.elapsed().milliseconds() ms / frame')
|
_ := <-chunk_ready_channel
|
||||||
|
}
|
||||||
|
// everything is done, swap the buffer pointers
|
||||||
|
state.pixels, state.npixels = state.npixels, state.pixels
|
||||||
|
println('${state.ntasks:2} threads; ${sw.elapsed().milliseconds():3} ms / frame; scale: ${state.scale:4}')
|
||||||
oview = cview
|
oview = cview
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (mut state AppState) recalc_lines(cview ViewRect, ymin f64, ymax f64) {
|
[direct_array_access]
|
||||||
for y_pixel := ymin; y_pixel < ymax && y_pixel < pheight; y_pixel++ {
|
fn (mut state AppState) worker(id int, input chan MandelChunk, ready chan bool) {
|
||||||
y0 := (y_pixel / pheight) * (cview.y_max - cview.y_min) + cview.y_min
|
for {
|
||||||
for x_pixel := 0.0; x_pixel < pwidth; x_pixel++ {
|
chunk := <-input or { break }
|
||||||
x0 := (x_pixel / pwidth) * (cview.x_max - cview.x_min) + cview.x_min
|
yscale := chunk.cview.height() / pheight
|
||||||
mut x, mut y := x0, y0
|
xscale := chunk.cview.width() / pwidth
|
||||||
mut iter := 0
|
mut x, mut y, mut iter := 0.0, 0.0, 0
|
||||||
for ; iter < 80; iter++ {
|
mut y0 := chunk.ymin * yscale + chunk.cview.y_min
|
||||||
x, y = x * x - y * y + x0, 2 * x * y + y0
|
mut x0 := chunk.cview.x_min
|
||||||
if x * x + y * y > 4 {
|
for y_pixel := chunk.ymin; y_pixel < chunk.ymax && y_pixel < pheight; y_pixel++ {
|
||||||
break
|
yrow := unsafe { &state.npixels[int(y_pixel * pwidth)] }
|
||||||
|
y0 += yscale
|
||||||
|
x0 = chunk.cview.x_min
|
||||||
|
for x_pixel := 0; x_pixel < pwidth; x_pixel++ {
|
||||||
|
x0 += xscale
|
||||||
|
x, y = x0, y0
|
||||||
|
for iter = 0; iter < max_iterations; iter++ {
|
||||||
|
x, y = x * x - y * y + x0, 2 * x * y + y0
|
||||||
|
if x * x + y * y > 4 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
unsafe {
|
||||||
|
yrow[x_pixel] = colors[iter & 15]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
state.npixels[int(y_pixel) * pwidth + int(x_pixel)] = u32(colors[iter % 8].abgr8())
|
|
||||||
}
|
}
|
||||||
|
ready <- true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (mut state AppState) draw() {
|
fn (mut state AppState) draw() {
|
||||||
mut istream_image := state.gg.get_cached_image_by_idx(state.iidx)
|
mut istream_image := state.gg.get_cached_image_by_idx(state.iidx)
|
||||||
istream_image.update_pixel_data(&state.pixels[0])
|
istream_image.update_pixel_data(state.pixels)
|
||||||
size := gg.window_size()
|
size := gg.window_size()
|
||||||
state.gg.draw_image(0, 0, size.width, size.height, istream_image)
|
state.gg.draw_image(0, 0, size.width, size.height, istream_image)
|
||||||
}
|
}
|
||||||
|
@ -84,6 +136,7 @@ fn (mut state AppState) zoom(zoom_factor f64) {
|
||||||
state.view.x_max = c_x + zoom_factor * d_x
|
state.view.x_max = c_x + zoom_factor * d_x
|
||||||
state.view.y_min = c_y - zoom_factor * d_y
|
state.view.y_min = c_y - zoom_factor * d_y
|
||||||
state.view.y_max = c_y + zoom_factor * d_y
|
state.view.y_max = c_y + zoom_factor * d_y
|
||||||
|
state.scale += if zoom_factor < 1 { 1 } else { -1 }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (mut state AppState) center(s_x f64, s_y f64) {
|
fn (mut state AppState) center(s_x f64, s_y f64) {
|
||||||
|
@ -110,8 +163,8 @@ fn graphics_frame(mut state AppState) {
|
||||||
fn graphics_click(x f32, y f32, btn gg.MouseButton, mut state AppState) {
|
fn graphics_click(x f32, y f32, btn gg.MouseButton, mut state AppState) {
|
||||||
if btn == .right {
|
if btn == .right {
|
||||||
size := gg.window_size()
|
size := gg.window_size()
|
||||||
m_x := (x / size.width) * (state.view.x_max - state.view.x_min) + state.view.x_min
|
m_x := (x / size.width) * state.view.width() + state.view.x_min
|
||||||
m_y := (y / size.height) * (state.view.y_max - state.view.y_min) + state.view.y_min
|
m_y := (y / size.height) * state.view.height() + state.view.y_min
|
||||||
state.center(m_x, m_y)
|
state.center(m_x, m_y)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -119,8 +172,8 @@ fn graphics_click(x f32, y f32, btn gg.MouseButton, mut state AppState) {
|
||||||
fn graphics_move(x f32, y f32, mut state AppState) {
|
fn graphics_move(x f32, y f32, mut state AppState) {
|
||||||
if state.gg.mouse_buttons.has(.left) {
|
if state.gg.mouse_buttons.has(.left) {
|
||||||
size := gg.window_size()
|
size := gg.window_size()
|
||||||
d_x := (f64(state.gg.mouse_dx) / size.width) * (state.view.x_max - state.view.x_min)
|
d_x := (f64(state.gg.mouse_dx) / size.width) * state.view.width()
|
||||||
d_y := (f64(state.gg.mouse_dy) / size.height) * (state.view.y_max - state.view.y_min)
|
d_y := (f64(state.gg.mouse_dy) / size.height) * state.view.height()
|
||||||
state.view.x_min -= d_x
|
state.view.x_min -= d_x
|
||||||
state.view.x_max -= d_x
|
state.view.x_max -= d_x
|
||||||
state.view.y_min -= d_y
|
state.view.y_min -= d_y
|
||||||
|
@ -133,12 +186,12 @@ fn graphics_scroll(e &gg.Event, mut state AppState) {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn graphics_keydown(code gg.KeyCode, mod gg.Modifier, mut state AppState) {
|
fn graphics_keydown(code gg.KeyCode, mod gg.Modifier, mut state AppState) {
|
||||||
s_x := (state.view.x_max - state.view.x_min) / 5
|
s_x := state.view.width() / 5
|
||||||
s_y := (state.view.y_max - state.view.y_min) / 5
|
s_y := state.view.height() / 5
|
||||||
// movement
|
// movement
|
||||||
mut d_x, mut d_y := 0.0, 0.0
|
mut d_x, mut d_y := 0.0, 0.0
|
||||||
if code == .enter {
|
if code == .enter {
|
||||||
println('> $state.view.x_min | $state.view.x_max | $state.view.y_min | $state.view.y_max')
|
println('> ViewRect{$state.view.x_min, $state.view.x_max, $state.view.y_min, $state.view.y_max}')
|
||||||
}
|
}
|
||||||
if state.gg.pressed_keys[int(gg.KeyCode.left)] {
|
if state.gg.pressed_keys[int(gg.KeyCode.left)] {
|
||||||
d_x -= s_x
|
d_x -= s_x
|
||||||
|
|
|
@ -0,0 +1,163 @@
|
||||||
|
/*
|
||||||
|
A V program for Bellman-Ford's single source
|
||||||
|
shortest path algorithm.
|
||||||
|
literaly adapted from:
|
||||||
|
https://www.geeksforgeeks.org/bellman-ford-algorithm-dp-23/
|
||||||
|
// Adapted from this site... from C++ and Python codes
|
||||||
|
|
||||||
|
For Portugese reference
|
||||||
|
http://rascunhointeligente.blogspot.com/2010/10/o-algoritmo-de-bellman-ford-um.html
|
||||||
|
|
||||||
|
By CCS
|
||||||
|
*/
|
||||||
|
|
||||||
|
const large = 999999 // almost inifinity
|
||||||
|
|
||||||
|
// a structure to represent a weighted edge in graph
|
||||||
|
struct EDGE {
|
||||||
|
mut:
|
||||||
|
src int
|
||||||
|
dest int
|
||||||
|
weight int
|
||||||
|
}
|
||||||
|
|
||||||
|
// building a map of with all edges etc of a graph, represented from a matrix adjacency
|
||||||
|
// Input: matrix adjacency --> Output: edges list of src, dest and weight
|
||||||
|
fn build_map_edges_from_graph<T>(g [][]T) map[T]EDGE {
|
||||||
|
n := g.len // TOTAL OF NODES for this graph -- its dimmension
|
||||||
|
mut edges_map := map[int]EDGE{} // a graph represented by map of edges
|
||||||
|
|
||||||
|
mut edge := 0 // a counter of edges
|
||||||
|
for i in 0 .. n {
|
||||||
|
for j in 0 .. n {
|
||||||
|
// if exist an arc ... include as new edge
|
||||||
|
if g[i][j] != 0 {
|
||||||
|
edges_map[edge] = EDGE{i, j, g[i][j]}
|
||||||
|
edge++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// print('${edges_map}')
|
||||||
|
return edges_map
|
||||||
|
}
|
||||||
|
|
||||||
|
fn print_sol(dist []int) {
|
||||||
|
n_vertex := dist.len
|
||||||
|
print('\n Vertex Distance from Source')
|
||||||
|
for i in 0 .. n_vertex {
|
||||||
|
print('\n $i --> ${dist[i]}')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// The main function that finds shortest distances from src
|
||||||
|
// to all other vertices using Bellman-Ford algorithm. The
|
||||||
|
// function also detects negative weight cycle
|
||||||
|
fn bellman_ford<T>(graph [][]T, src int) {
|
||||||
|
mut edges := build_map_edges_from_graph(graph)
|
||||||
|
// this function was done to adapt a graph representation
|
||||||
|
// by a adjacency matrix, to list of adjacency (using a MAP)
|
||||||
|
n_edges := edges.len // number of EDGES
|
||||||
|
|
||||||
|
// Step 1: Initialize distances from src to all other
|
||||||
|
// vertices as INFINITE
|
||||||
|
n_vertex := graph.len // adjc matrix ... n nodes or vertex
|
||||||
|
mut dist := []int{len: n_vertex, init: large} // dist with -1 instead of INIFINITY
|
||||||
|
// mut path := []int{len: n , init:-1} // previous node of each shortest paht
|
||||||
|
dist[src] = 0
|
||||||
|
|
||||||
|
// Step 2: Relax all edges |V| - 1 times. A simple
|
||||||
|
// shortest path from src to any other vertex can have
|
||||||
|
// at-most |V| - 1 edges
|
||||||
|
|
||||||
|
for _ in 0 .. n_vertex {
|
||||||
|
for j in 0 .. n_edges {
|
||||||
|
mut u := edges[j].src
|
||||||
|
mut v := edges[j].dest
|
||||||
|
mut weight := edges[j].weight
|
||||||
|
if (dist[u] != large) && (dist[u] + weight < dist[v]) {
|
||||||
|
dist[v] = dist[u] + weight
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 3: check for negative-weight cycles. The above
|
||||||
|
// step guarantees shortest distances if graph doesn't
|
||||||
|
// contain negative weight cycle. If we get a shorter
|
||||||
|
// path, then there is a cycle.
|
||||||
|
for j in 0 .. n_vertex {
|
||||||
|
mut u := edges[j].src
|
||||||
|
mut v := edges[j].dest
|
||||||
|
mut weight := edges[j].weight
|
||||||
|
if (dist[u] != large) && (dist[u] + weight < dist[v]) {
|
||||||
|
print('\n Graph contains negative weight cycle')
|
||||||
|
// If negative cycle is detected, simply
|
||||||
|
// return or an exit(1)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
print_sol(dist)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
// adjacency matrix = cost or weight
|
||||||
|
graph_01 := [
|
||||||
|
[0, -1, 4, 0, 0],
|
||||||
|
[0, 0, 3, 2, 2],
|
||||||
|
[0, 0, 0, 0, 0],
|
||||||
|
[0, 1, 5, 0, 0],
|
||||||
|
[0, 0, 0, -3, 0],
|
||||||
|
]
|
||||||
|
// data from https://www.geeksforgeeks.org/bellman-ford-algorithm-dp-23/
|
||||||
|
|
||||||
|
graph_02 := [
|
||||||
|
[0, 2, 0, 6, 0],
|
||||||
|
[2, 0, 3, 8, 5],
|
||||||
|
[0, 3, 0, 0, 7],
|
||||||
|
[6, 8, 0, 0, 9],
|
||||||
|
[0, 5, 7, 9, 0],
|
||||||
|
]
|
||||||
|
// data from https://www.geeksforgeeks.org/prims-minimum-spanning-tree-mst-greedy-algo-5/
|
||||||
|
/*
|
||||||
|
The graph:
|
||||||
|
2 3
|
||||||
|
(0)--(1)--(2)
|
||||||
|
| / \ |
|
||||||
|
6| 8/ \5 |7
|
||||||
|
| / \ |
|
||||||
|
(3)-------(4)
|
||||||
|
9
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
Let us create following weighted graph
|
||||||
|
From https://www.geeksforgeeks.org/kruskals-minimum-spanning-tree-algorithm-greedy-algo-2/?ref=lbp
|
||||||
|
10
|
||||||
|
0--------1
|
||||||
|
| \ |
|
||||||
|
6| 5\ |15
|
||||||
|
| \ |
|
||||||
|
2--------3
|
||||||
|
4
|
||||||
|
*/
|
||||||
|
graph_03 := [
|
||||||
|
[0, 10, 6, 5],
|
||||||
|
[10, 0, 0, 15],
|
||||||
|
[6, 0, 0, 4],
|
||||||
|
[5, 15, 4, 0],
|
||||||
|
]
|
||||||
|
|
||||||
|
// To find number of coluns
|
||||||
|
// mut cols := an_array[0].len
|
||||||
|
mut graph := [][]int{} // the graph: adjacency matrix
|
||||||
|
// for index, g_value in [graph_01, graph_02, graph_03] {
|
||||||
|
for index, g_value in [graph_01, graph_02, graph_03] {
|
||||||
|
graph = g_value.clone() // graphs_sample[g].clone() // choice your SAMPLE
|
||||||
|
// allways starting by node 0
|
||||||
|
start_node := 0
|
||||||
|
println('\n\n Graph ${index + 1} using Bellman-Ford algorithm (source node: $start_node)')
|
||||||
|
bellman_ford(graph, start_node)
|
||||||
|
}
|
||||||
|
println('\n BYE -- OK')
|
||||||
|
}
|
||||||
|
|
||||||
|
//=================================================
|
|
@ -1,4 +1,4 @@
|
||||||
// Author: ccs
|
// Author: CCS
|
||||||
// I follow literally code in C, done many years ago
|
// I follow literally code in C, done many years ago
|
||||||
fn main() {
|
fn main() {
|
||||||
// Adjacency matrix as a map
|
// Adjacency matrix as a map
|
||||||
|
@ -20,10 +20,9 @@ fn breadth_first_search_path(graph map[string][]string, start string, target str
|
||||||
mut path := []string{} // ONE PATH with SUCCESS = array
|
mut path := []string{} // ONE PATH with SUCCESS = array
|
||||||
mut queue := []string{} // a queue ... many paths
|
mut queue := []string{} // a queue ... many paths
|
||||||
// all_nodes := graph.keys() // get a key of this map
|
// 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
|
// a map to store all the nodes visited to avoid cycles
|
||||||
// start all them with False, not visited yet
|
// start all them with False, not visited yet
|
||||||
mut visited := a_map_nodes_bool(n_nodes) // a map fully
|
mut visited := visited_init(graph) // a map fully
|
||||||
// false ==> not visited yet: {'A': false, 'B': false, 'C': false, 'D': false, 'E': false}
|
// false ==> not visited yet: {'A': false, 'B': false, 'C': false, 'D': false, 'E': false}
|
||||||
queue << start // first arrival
|
queue << start // first arrival
|
||||||
for queue.len != 0 {
|
for queue.len != 0 {
|
||||||
|
@ -51,19 +50,6 @@ fn breadth_first_search_path(graph map[string][]string, start string, target str
|
||||||
return path
|
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
|
// classical removing of a node from the start of a queue
|
||||||
fn departure(mut queue []string) string {
|
fn departure(mut queue []string) string {
|
||||||
mut x := queue[0]
|
mut x := queue[0]
|
||||||
|
@ -71,6 +57,17 @@ fn departure(mut queue []string) string {
|
||||||
return x
|
return x
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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
|
||||||
|
}
|
||||||
|
|
||||||
// Based in the current node that is final, search for its parent, already visited, up to the root or start node
|
// 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 {
|
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')
|
print('\n\n Nodes visited (true) or no (false): $visited')
|
||||||
|
@ -90,3 +87,5 @@ fn build_path_reverse(graph map[string][]string, start string, final string, vis
|
||||||
}
|
}
|
||||||
return path
|
return path
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//======================================================
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// Author: ccs
|
// Author: CCS
|
||||||
// I follow literally code in C, done many years ago
|
// I follow literally code in C, done many years ago
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
@ -35,8 +35,7 @@ fn depth_first_search_path(graph map[string][]string, start string, target strin
|
||||||
mut path := []string{} // ONE PATH with SUCCESS = array
|
mut path := []string{} // ONE PATH with SUCCESS = array
|
||||||
mut stack := []string{} // a stack ... many nodes
|
mut stack := []string{} // a stack ... many nodes
|
||||||
// all_nodes := graph.keys() // get a key of this map
|
// all_nodes := graph.keys() // get a key of this map
|
||||||
n_nodes := graph.len // numbers of nodes of this graph
|
mut visited := visited_init(graph) // a map fully with false in all vertex
|
||||||
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}
|
// false ... not visited yet: {'A': false, 'B': false, 'C': false, 'D': false, 'E': false}
|
||||||
|
|
||||||
stack << start // first push on the stack
|
stack << start // first push on the stack
|
||||||
|
@ -72,14 +71,15 @@ fn depth_first_search_path(graph map[string][]string, start string, target strin
|
||||||
return path
|
return path
|
||||||
}
|
}
|
||||||
|
|
||||||
// Creating a map for nodes not VISITED visited ...
|
// Creating aa map to initialize with of visited nodes .... all with false in the init
|
||||||
// starting by false ===> means this node was not visited yet
|
// so these nodes are NOT VISITED YET
|
||||||
fn a_map_nodes_bool(size int) map[string]bool {
|
fn visited_init(a_graph map[string][]string) map[string]bool {
|
||||||
mut my_map := map[string]bool{} // look this map ...
|
mut array_of_keys := a_graph.keys() // get all keys of this map
|
||||||
for i in 0 .. size {
|
mut temp := map[string]bool{} // attention in these initializations with maps
|
||||||
my_map[u8(65 + i).ascii_str()] = false
|
for i in array_of_keys {
|
||||||
|
temp[i] = false
|
||||||
}
|
}
|
||||||
return my_map
|
return temp
|
||||||
}
|
}
|
||||||
|
|
||||||
// Based in the current node that is final, search for his parent, that is already visited, up to the root or start node
|
// Based in the current node that is final, search for his parent, that is already visited, up to the root or start node
|
||||||
|
@ -101,3 +101,5 @@ fn build_path_reverse(graph map[string][]string, start string, final string, vis
|
||||||
}
|
}
|
||||||
return path
|
return path
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//*****************************************************
|
||||||
|
|
|
@ -0,0 +1,241 @@
|
||||||
|
/*
|
||||||
|
Exploring Dijkstra,
|
||||||
|
The data example is from
|
||||||
|
https://www.geeksforgeeks.org/dijkstras-shortest-path-algorithm-greedy-algo-7/
|
||||||
|
|
||||||
|
by CCS
|
||||||
|
Dijkstra's single source shortest path algorithm.
|
||||||
|
The program uses an adjacency matrix representation of a graph
|
||||||
|
|
||||||
|
This Dijkstra algorithm uses a priority queue to save
|
||||||
|
the shortest paths. The queue structure has a data
|
||||||
|
which is the number of the node,
|
||||||
|
and the priority field which is the shortest distance.
|
||||||
|
|
||||||
|
PS: all the pre-requisites of Dijkstra are considered
|
||||||
|
|
||||||
|
$ v run file_name.v
|
||||||
|
// Creating a executable
|
||||||
|
$ v run file_name.v -o an_executable.EXE
|
||||||
|
$ ./an_executable.EXE
|
||||||
|
|
||||||
|
Code based from : Data Structures and Algorithms Made Easy: Data Structures and Algorithmic Puzzles, Fifth Edition (English Edition)
|
||||||
|
pseudo code written in C
|
||||||
|
This idea is quite different: it uses a priority queue to store the current
|
||||||
|
shortest path evaluted
|
||||||
|
The priority queue structure built using a list to simulate
|
||||||
|
the queue. A heap is not used in this case.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// a structure
|
||||||
|
struct NODE {
|
||||||
|
mut:
|
||||||
|
data int // NUMBER OF NODE
|
||||||
|
priority int // Lower values priority indicate ==> higher priority
|
||||||
|
}
|
||||||
|
|
||||||
|
// Function to push according to priority ... the lower priority is goes ahead
|
||||||
|
// The "push" always sorted in pq
|
||||||
|
fn push_pq<T>(mut prior_queue []T, data int, priority int) {
|
||||||
|
mut temp := []T{}
|
||||||
|
lenght_pq := prior_queue.len
|
||||||
|
|
||||||
|
mut i := 0
|
||||||
|
for (i < lenght_pq) && (priority > prior_queue[i].priority) {
|
||||||
|
temp << prior_queue[i]
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
// INSERTING SORTED in the queue
|
||||||
|
temp << NODE{data, priority} // do the copy in the right place
|
||||||
|
// copy the another part (tail) of original prior_queue
|
||||||
|
for i < lenght_pq {
|
||||||
|
temp << prior_queue[i]
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
prior_queue = temp.clone() // I am not sure if it the right way
|
||||||
|
// IS IT THE RIGHT WAY?
|
||||||
|
}
|
||||||
|
|
||||||
|
// Change the priority of a value/node ... exist a value, change its priority
|
||||||
|
fn updating_priority<T>(mut prior_queue []T, search_data int, new_priority int) {
|
||||||
|
mut i := 0
|
||||||
|
mut lenght_pq := prior_queue.len
|
||||||
|
|
||||||
|
for i < lenght_pq {
|
||||||
|
if search_data == prior_queue[i].data {
|
||||||
|
prior_queue[i] = NODE{search_data, new_priority} // do the copy in the right place
|
||||||
|
break
|
||||||
|
}
|
||||||
|
i++
|
||||||
|
// all the list was examined
|
||||||
|
if i >= lenght_pq {
|
||||||
|
print('\n This data $search_data does exist ... PRIORITY QUEUE problem\n')
|
||||||
|
exit(1) // panic(s string)
|
||||||
|
}
|
||||||
|
} // end for
|
||||||
|
}
|
||||||
|
|
||||||
|
// a single departure or remove from queue
|
||||||
|
fn departure_priority<T>(mut prior_queue []T) int {
|
||||||
|
mut x := prior_queue[0].data
|
||||||
|
prior_queue.delete(0) // or .delete_many(0, 1 )
|
||||||
|
return x
|
||||||
|
}
|
||||||
|
|
||||||
|
// give a NODE v, return a list with all adjacents
|
||||||
|
// Take care, only positive EDGES
|
||||||
|
fn all_adjacents<T>(g [][]T, v int) []int {
|
||||||
|
mut temp := []int{} //
|
||||||
|
for i in 0 .. (g.len) {
|
||||||
|
if g[v][i] > 0 {
|
||||||
|
temp << i
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return temp
|
||||||
|
}
|
||||||
|
|
||||||
|
// print the costs from origin up to all nodes
|
||||||
|
fn print_solution<T>(dist []T) {
|
||||||
|
print('Vertex \tDistance from Source')
|
||||||
|
for node in 0 .. (dist.len) {
|
||||||
|
print('\n $node ==> \t ${dist[node]}')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// print all paths and their cost or weight
|
||||||
|
fn print_paths_dist<T>(path []T, dist []T) {
|
||||||
|
print('\n Read the nodes from right to left (a path): \n')
|
||||||
|
|
||||||
|
for node in 1 .. (path.len) {
|
||||||
|
print('\n $node ')
|
||||||
|
mut i := node
|
||||||
|
for path[i] != -1 {
|
||||||
|
print(' <= ${path[i]} ')
|
||||||
|
i = path[i]
|
||||||
|
}
|
||||||
|
print('\t PATH COST: ${dist[node]}')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// check structure from: https://www.geeksforgeeks.org/dijkstras-shortest-path-algorithm-greedy-algo-7/
|
||||||
|
// s: source for all nodes
|
||||||
|
// Two results are obtained ... cost and paths
|
||||||
|
fn dijkstra(g [][]int, s int) {
|
||||||
|
mut pq_queue := []NODE{} // creating a priority queue
|
||||||
|
push_pq(mut pq_queue, s, 0) // goes s with priority 0
|
||||||
|
mut n := g.len
|
||||||
|
|
||||||
|
mut dist := []int{len: n, init: -1} // dist with -1 instead of INIFINITY
|
||||||
|
mut path := []int{len: n, init: -1} // previous node of each shortest paht
|
||||||
|
|
||||||
|
// Distance of source vertex from itself is always 0
|
||||||
|
dist[s] = 0
|
||||||
|
|
||||||
|
for pq_queue.len != 0 {
|
||||||
|
mut v := departure_priority(mut pq_queue)
|
||||||
|
// for all W adjcents vertices of v
|
||||||
|
mut adjs_of_v := all_adjacents(g, v) // all_ADJ of v ....
|
||||||
|
// print('\n ADJ ${v} is ${adjs_of_v}')
|
||||||
|
mut new_dist := 0
|
||||||
|
for w in adjs_of_v {
|
||||||
|
new_dist = dist[v] + g[v][w]
|
||||||
|
if dist[w] == -1 {
|
||||||
|
dist[w] = new_dist
|
||||||
|
push_pq(mut pq_queue, w, dist[w])
|
||||||
|
path[w] = v // collecting the previous node -- lowest weight
|
||||||
|
}
|
||||||
|
if dist[w] > new_dist {
|
||||||
|
dist[w] = new_dist
|
||||||
|
updating_priority(mut pq_queue, w, dist[w])
|
||||||
|
path[w] = v //
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// print the constructed distance array
|
||||||
|
print_solution(dist)
|
||||||
|
// print('\n \n Previous node of shortest path: ${path}')
|
||||||
|
print_paths_dist(path, dist)
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Solution Expected
|
||||||
|
Vertex Distance from Source
|
||||||
|
0 0
|
||||||
|
1 4
|
||||||
|
2 12
|
||||||
|
3 19
|
||||||
|
4 21
|
||||||
|
5 11
|
||||||
|
6 9
|
||||||
|
7 8
|
||||||
|
8 14
|
||||||
|
*/
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
// adjacency matrix = cost or weight
|
||||||
|
graph_01 := [
|
||||||
|
[0, 4, 0, 0, 0, 0, 0, 8, 0],
|
||||||
|
[4, 0, 8, 0, 0, 0, 0, 11, 0],
|
||||||
|
[0, 8, 0, 7, 0, 4, 0, 0, 2],
|
||||||
|
[0, 0, 7, 0, 9, 14, 0, 0, 0],
|
||||||
|
[0, 0, 0, 9, 0, 10, 0, 0, 0],
|
||||||
|
[0, 0, 4, 14, 10, 0, 2, 0, 0],
|
||||||
|
[0, 0, 0, 0, 0, 2, 0, 1, 6],
|
||||||
|
[8, 11, 0, 0, 0, 0, 1, 0, 7],
|
||||||
|
[0, 0, 2, 0, 0, 0, 6, 7, 0],
|
||||||
|
]
|
||||||
|
|
||||||
|
graph_02 := [
|
||||||
|
[0, 2, 0, 6, 0],
|
||||||
|
[2, 0, 3, 8, 5],
|
||||||
|
[0, 3, 0, 0, 7],
|
||||||
|
[6, 8, 0, 0, 9],
|
||||||
|
[0, 5, 7, 9, 0],
|
||||||
|
]
|
||||||
|
// data from https://www.geeksforgeeks.org/prims-minimum-spanning-tree-mst-greedy-algo-5/
|
||||||
|
/*
|
||||||
|
The graph:
|
||||||
|
2 3
|
||||||
|
(0)--(1)--(2)
|
||||||
|
| / \ |
|
||||||
|
6| 8/ \5 |7
|
||||||
|
| / \ |
|
||||||
|
(3)-------(4)
|
||||||
|
9
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
Let us create following weighted graph
|
||||||
|
From https://www.geeksforgeeks.org/kruskals-minimum-spanning-tree-algorithm-greedy-algo-2/?ref=lbp
|
||||||
|
10
|
||||||
|
0--------1
|
||||||
|
| \ |
|
||||||
|
6| 5\ |15
|
||||||
|
| \ |
|
||||||
|
2--------3
|
||||||
|
4
|
||||||
|
*/
|
||||||
|
graph_03 := [
|
||||||
|
[0, 10, 6, 5],
|
||||||
|
[10, 0, 0, 15],
|
||||||
|
[6, 0, 0, 4],
|
||||||
|
[5, 15, 4, 0],
|
||||||
|
]
|
||||||
|
|
||||||
|
// To find number of coluns
|
||||||
|
// mut cols := an_array[0].len
|
||||||
|
mut graph := [][]int{} // the graph: adjacency matrix
|
||||||
|
// for index, g_value in [graph_01, graph_02, graph_03] {
|
||||||
|
for index, g_value in [graph_01, graph_02, graph_03] {
|
||||||
|
graph = g_value.clone() // graphs_sample[g].clone() // choice your SAMPLE
|
||||||
|
// allways starting by node 0
|
||||||
|
start_node := 0
|
||||||
|
println('\n\n Graph ${index + 1} using Dijkstra algorithm (source node: $start_node)')
|
||||||
|
dijkstra(graph, start_node)
|
||||||
|
}
|
||||||
|
|
||||||
|
println('\n BYE -- OK')
|
||||||
|
}
|
||||||
|
|
||||||
|
//********************************************************************
|
|
@ -0,0 +1,230 @@
|
||||||
|
/*
|
||||||
|
Exploring PRIMS,
|
||||||
|
The data example is from
|
||||||
|
https://www.geeksforgeeks.org/prims-minimum-spanning-tree-mst-greedy-algo-5/
|
||||||
|
|
||||||
|
by CCS
|
||||||
|
|
||||||
|
PS: all the pre-requisites of Dijkstra are considered
|
||||||
|
|
||||||
|
$ v run file_name.v
|
||||||
|
Creating a executable
|
||||||
|
$ v run file_name.v -o an_executable.EXE
|
||||||
|
$ ./an_executable.EXE
|
||||||
|
|
||||||
|
Code based from : Data Structures and Algorithms Made Easy: Data Structures and Algorithmic Puzzles, Fifth Edition (English Edition)
|
||||||
|
pseudo code written in C
|
||||||
|
This idea is quite different: it uses a priority queue to store the current
|
||||||
|
shortest path evaluted
|
||||||
|
The priority queue structure built using a list to simulate
|
||||||
|
the queue. A heap is not used in this case.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// a structure
|
||||||
|
struct NODE {
|
||||||
|
mut:
|
||||||
|
data int // number of nodes
|
||||||
|
priority int // Lower values priority indicate ==> higher priority
|
||||||
|
}
|
||||||
|
|
||||||
|
// Function to push according to priority ... the lower priority is goes ahead
|
||||||
|
// The "push" always sorted in pq
|
||||||
|
fn push_pq<T>(mut prior_queue []T, data int, priority int) {
|
||||||
|
mut temp := []T{}
|
||||||
|
lenght_pq := prior_queue.len
|
||||||
|
|
||||||
|
mut i := 0
|
||||||
|
for (i < lenght_pq) && (priority > prior_queue[i].priority) {
|
||||||
|
temp << prior_queue[i]
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
// INSERTING SORTED in the queue
|
||||||
|
temp << NODE{data, priority} // do the copy in the right place
|
||||||
|
// copy the another part (tail) of original prior_queue
|
||||||
|
for i < lenght_pq {
|
||||||
|
temp << prior_queue[i]
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
prior_queue = temp.clone()
|
||||||
|
// I am not sure if it the right way
|
||||||
|
// IS IT THE RIGHT WAY?
|
||||||
|
}
|
||||||
|
|
||||||
|
// Change the priority of a value/node ... exist a value, change its priority
|
||||||
|
fn updating_priority<T>(mut prior_queue []T, search_data int, new_priority int) {
|
||||||
|
mut i := 0
|
||||||
|
mut lenght_pq := prior_queue.len
|
||||||
|
|
||||||
|
for i < lenght_pq {
|
||||||
|
if search_data == prior_queue[i].data {
|
||||||
|
prior_queue[i] = NODE{search_data, new_priority} // do the copy in the right place
|
||||||
|
break
|
||||||
|
}
|
||||||
|
i++
|
||||||
|
// all the list was examined
|
||||||
|
if i >= lenght_pq {
|
||||||
|
// print('\n Priority Queue: ${prior_queue}')
|
||||||
|
// print('\n These data ${search_data} and ${new_priority} do not exist ... PRIORITY QUEUE problem\n')
|
||||||
|
// if it does not find ... then push it
|
||||||
|
push_pq(mut prior_queue, search_data, new_priority)
|
||||||
|
// exit(1) // panic(s string)
|
||||||
|
}
|
||||||
|
} // end for
|
||||||
|
}
|
||||||
|
|
||||||
|
// a single departure or remove from queue
|
||||||
|
fn departure_priority<T>(mut prior_queue []T) int {
|
||||||
|
mut x := prior_queue[0].data
|
||||||
|
prior_queue.delete(0) // or .delete_many(0, 1 )
|
||||||
|
return x
|
||||||
|
}
|
||||||
|
|
||||||
|
// give a NODE v, return a list with all adjacents
|
||||||
|
// Take care, only positive EDGES
|
||||||
|
fn all_adjacents<T>(g [][]T, v int) []int {
|
||||||
|
mut temp := []int{} //
|
||||||
|
for i in 0 .. (g.len) {
|
||||||
|
if g[v][i] > 0 {
|
||||||
|
temp << i
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return temp
|
||||||
|
}
|
||||||
|
|
||||||
|
// print the costs from origin up to all nodes
|
||||||
|
// A utility function to print the
|
||||||
|
// constructed MST stored in parent[]
|
||||||
|
// print all paths and their cost or weight
|
||||||
|
fn print_solution(path []int, g [][]int) {
|
||||||
|
// print(' PATH: ${path} ==> ${path.len}')
|
||||||
|
print(' Edge \tWeight\n')
|
||||||
|
mut sum := 0
|
||||||
|
for node in 0 .. (path.len) {
|
||||||
|
if path[node] == -1 {
|
||||||
|
print('\n $node <== reference or start node')
|
||||||
|
} else {
|
||||||
|
print('\n $node <--> ${path[node]} \t${g[node][path[node]]}')
|
||||||
|
sum += g[node][path[node]]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
print('\n Minimum Cost Spanning Tree: $sum\n\n')
|
||||||
|
}
|
||||||
|
|
||||||
|
// check structure from: https://www.geeksforgeeks.org/dijkstras-shortest-path-algorithm-greedy-algo-7/
|
||||||
|
// s: source for all nodes
|
||||||
|
// Two results are obtained ... cost and paths
|
||||||
|
fn prim_mst(g [][]int, s int) {
|
||||||
|
mut pq_queue := []NODE{} // creating a priority queue
|
||||||
|
push_pq(mut pq_queue, s, 0) // goes s with priority 0
|
||||||
|
mut n := g.len
|
||||||
|
|
||||||
|
mut dist := []int{len: n, init: -1} // dist with -1 instead of INIFINITY
|
||||||
|
mut path := []int{len: n, init: -1} // previous node of each shortest paht
|
||||||
|
|
||||||
|
// Distance of source vertex from itself is always 0
|
||||||
|
dist[s] = 0
|
||||||
|
|
||||||
|
for pq_queue.len != 0 {
|
||||||
|
mut v := departure_priority(mut pq_queue)
|
||||||
|
// for all W adjcents vertices of v
|
||||||
|
mut adjs_of_v := all_adjacents(g, v) // all_ADJ of v ....
|
||||||
|
// print('\n :${dist} :: ${pq_queue}')
|
||||||
|
// print('\n ADJ ${v} is ${adjs_of_v}')
|
||||||
|
mut new_dist := 0
|
||||||
|
for w in adjs_of_v {
|
||||||
|
new_dist = dist[v] + g[v][w]
|
||||||
|
|
||||||
|
if dist[w] == -1 {
|
||||||
|
dist[w] = g[v][w]
|
||||||
|
push_pq(mut pq_queue, w, dist[w])
|
||||||
|
path[w] = v // collecting the previous node -- lowest weight
|
||||||
|
}
|
||||||
|
|
||||||
|
if dist[w] > new_dist {
|
||||||
|
dist[w] = g[v][w] // new_dist//
|
||||||
|
updating_priority(mut pq_queue, w, dist[w])
|
||||||
|
path[w] = v // father / previous node
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// print('\n \n Previous node of shortest path: ${path}')
|
||||||
|
// print_paths_dist(path , dist)
|
||||||
|
print_solution(path, g)
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Solution Expected graph_02
|
||||||
|
Edge Weight
|
||||||
|
0 - 1 2
|
||||||
|
1 - 2 3
|
||||||
|
0 - 3 6
|
||||||
|
1 - 4 5
|
||||||
|
*/
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
// adjacency matrix = cost or weight
|
||||||
|
graph_01 := [
|
||||||
|
[0, 4, 0, 0, 0, 0, 0, 8, 0],
|
||||||
|
[4, 0, 8, 0, 0, 0, 0, 11, 0],
|
||||||
|
[0, 8, 0, 7, 0, 4, 0, 0, 2],
|
||||||
|
[0, 0, 7, 0, 9, 14, 0, 0, 0],
|
||||||
|
[0, 0, 0, 9, 0, 10, 0, 0, 0],
|
||||||
|
[0, 0, 4, 14, 10, 0, 2, 0, 0],
|
||||||
|
[0, 0, 0, 0, 0, 2, 0, 1, 6],
|
||||||
|
[8, 11, 0, 0, 0, 0, 1, 0, 7],
|
||||||
|
[0, 0, 2, 0, 0, 0, 6, 7, 0],
|
||||||
|
]
|
||||||
|
|
||||||
|
graph_02 := [
|
||||||
|
[0, 2, 0, 6, 0],
|
||||||
|
[2, 0, 3, 8, 5],
|
||||||
|
[0, 3, 0, 0, 7],
|
||||||
|
[6, 8, 0, 0, 9],
|
||||||
|
[0, 5, 7, 9, 0],
|
||||||
|
]
|
||||||
|
// data from https://www.geeksforgeeks.org/prims-minimum-spanning-tree-mst-greedy-algo-5/
|
||||||
|
/*
|
||||||
|
The graph:
|
||||||
|
2 3
|
||||||
|
(0)--(1)--(2)
|
||||||
|
| / \ |
|
||||||
|
6| 8/ \5 |7
|
||||||
|
| / \ |
|
||||||
|
(3)-------(4)
|
||||||
|
9
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
Let us create following weighted graph
|
||||||
|
From https://www.geeksforgeeks.org/kruskals-minimum-spanning-tree-algorithm-greedy-algo-2/?ref=lbp
|
||||||
|
10
|
||||||
|
0--------1
|
||||||
|
| \ |
|
||||||
|
6| 5\ |15
|
||||||
|
| \ |
|
||||||
|
2--------3
|
||||||
|
4
|
||||||
|
*/
|
||||||
|
graph_03 := [
|
||||||
|
[0, 10, 6, 5],
|
||||||
|
[10, 0, 0, 15],
|
||||||
|
[6, 0, 0, 4],
|
||||||
|
[5, 15, 4, 0],
|
||||||
|
]
|
||||||
|
|
||||||
|
// To find number of coluns
|
||||||
|
// mut cols := an_array[0].len
|
||||||
|
mut graph := [][]int{} // the graph: adjacency matrix
|
||||||
|
// for index, g_value in [graph_01, graph_02, graph_03] {
|
||||||
|
for index, g_value in [graph_01, graph_02, graph_03] {
|
||||||
|
println('\n Minimal Spanning Tree of graph ${index + 1} using PRIM algorithm')
|
||||||
|
graph = g_value.clone() // graphs_sample[g].clone() // choice your SAMPLE
|
||||||
|
// starting by node x ... see the graphs dimmension
|
||||||
|
start_node := 0
|
||||||
|
prim_mst(graph, start_node)
|
||||||
|
}
|
||||||
|
println('\n BYE -- OK')
|
||||||
|
}
|
||||||
|
|
||||||
|
//********************************************************************
|
|
@ -11,7 +11,7 @@ fn (h ExampleHandler) handle(req Request) Response {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
mut status_code := 200
|
mut status_code := 200
|
||||||
res.text = match req.url {
|
res.body = match req.url {
|
||||||
'/foo' {
|
'/foo' {
|
||||||
'bar\n'
|
'bar\n'
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,7 @@ fn send_request(mut wg sync.WaitGroup) ?string {
|
||||||
finish := time.ticks()
|
finish := time.ticks()
|
||||||
println('Finish getting time ${finish - start} ms')
|
println('Finish getting time ${finish - start} ms')
|
||||||
wg.done()
|
wg.done()
|
||||||
return data.text
|
return data.body
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
|
|
@ -16,7 +16,7 @@ fn worker_fetch(p &pool.PoolProcessor, cursor int, worker_id int) voidptr {
|
||||||
println('failed to fetch data from /v0/item/${id}.json')
|
println('failed to fetch data from /v0/item/${id}.json')
|
||||||
return pool.no_result
|
return pool.no_result
|
||||||
}
|
}
|
||||||
story := json.decode(Story, resp.text) or {
|
story := json.decode(Story, resp.body) or {
|
||||||
println('failed to decode a story')
|
println('failed to decode a story')
|
||||||
return pool.no_result
|
return pool.no_result
|
||||||
}
|
}
|
||||||
|
@ -30,7 +30,7 @@ fn main() {
|
||||||
println('failed to fetch data from /v0/topstories.json')
|
println('failed to fetch data from /v0/topstories.json')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
ids := json.decode([]int, resp.text) or {
|
ids := json.decode([]int, resp.body) or {
|
||||||
println('failed to decode topstories.json')
|
println('failed to decode topstories.json')
|
||||||
return
|
return
|
||||||
}#[0..10]
|
}#[0..10]
|
||||||
|
|
|
@ -95,7 +95,7 @@ pub fn (mut s System) explode(x f32, y f32) {
|
||||||
|
|
||||||
pub fn (mut s System) free() {
|
pub fn (mut s System) free() {
|
||||||
for p in s.pool {
|
for p in s.pool {
|
||||||
if p == 0 {
|
if unsafe { p == 0 } {
|
||||||
print(ptr_str(p) + ' ouch')
|
print(ptr_str(p) + ' ouch')
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
@ -103,7 +103,7 @@ pub fn (mut s System) free() {
|
||||||
}
|
}
|
||||||
s.pool.clear()
|
s.pool.clear()
|
||||||
for p in s.bin {
|
for p in s.bin {
|
||||||
if p == 0 {
|
if unsafe { p == 0 } {
|
||||||
print(ptr_str(p) + ' ouch')
|
print(ptr_str(p) + ' ouch')
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,13 @@
|
||||||
#!/usr/local/bin/v run
|
#!/usr/local/bin/v
|
||||||
|
|
||||||
// The shebang above associates the file to V on Unix-like systems,
|
// The shebang above associates the file to V on Unix-like systems,
|
||||||
// so it can be run just by specifying the path to the file
|
// so it can be run just by specifying the path to the file
|
||||||
// once it's made executable using `chmod +x`.
|
// once it's made executable using `chmod +x`.
|
||||||
|
|
||||||
|
// Note that you can also use: `#!/usr/bin/env -S v crun`, if your system supports the -S flag to env
|
||||||
|
// The benefit is that in this case, v could be anywhere in your path, while /usr/bin/env is guaranteed
|
||||||
|
// to be present on most Unix systems in that exact place.
|
||||||
|
|
||||||
for _ in 0 .. 3 {
|
for _ in 0 .. 3 {
|
||||||
println('V script')
|
println('V script')
|
||||||
}
|
}
|
||||||
|
|
|
@ -1611,7 +1611,12 @@ _SOKOL_PRIVATE bool _saudio_backend_init(void) {
|
||||||
fmtex.Format.nAvgBytesPerSec = fmtex.Format.nSamplesPerSec * fmtex.Format.nBlockAlign;
|
fmtex.Format.nAvgBytesPerSec = fmtex.Format.nSamplesPerSec * fmtex.Format.nBlockAlign;
|
||||||
fmtex.Format.cbSize = 22; /* WORD + DWORD + GUID */
|
fmtex.Format.cbSize = 22; /* WORD + DWORD + GUID */
|
||||||
fmtex.Samples.wValidBitsPerSample = 32;
|
fmtex.Samples.wValidBitsPerSample = 32;
|
||||||
fmtex.dwChannelMask = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT;
|
if (_saudio.num_channels == 1) {
|
||||||
|
fmtex.dwChannelMask = SPEAKER_FRONT_CENTER;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
fmtex.dwChannelMask = SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT;
|
||||||
|
}
|
||||||
fmtex.SubFormat = _saudio_KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
|
fmtex.SubFormat = _saudio_KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
|
||||||
dur = (REFERENCE_TIME)
|
dur = (REFERENCE_TIME)
|
||||||
(((double)_saudio.buffer_frames) / (((double)_saudio.sample_rate) * (1.0/10000000.0)));
|
(((double)_saudio.buffer_frames) / (((double)_saudio.sample_rate) * (1.0/10000000.0)));
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
/*
|
/*
|
||||||
Compability header for stdatomic.h that works for all compilers supported
|
Compatibility header for stdatomic.h that works for all compilers supported by V.
|
||||||
by V. For TCC libatomic from the operating system is used
|
For TCC, we use libatomic from the OS.
|
||||||
|
|
||||||
*/
|
*/
|
||||||
#ifndef __ATOMIC_H
|
#ifndef __ATOMIC_H
|
||||||
#define __ATOMIC_H
|
#define __ATOMIC_H
|
||||||
|
|
|
@ -614,7 +614,7 @@ fn (mut a array) set_unsafe(i int, val voidptr) {
|
||||||
unsafe { vmemcpy(&u8(a.data) + u64(a.element_size) * u64(i), val, a.element_size) }
|
unsafe { vmemcpy(&u8(a.data) + u64(a.element_size) * u64(i), val, a.element_size) }
|
||||||
}
|
}
|
||||||
|
|
||||||
// Private function. Used to implement assigment to the array element.
|
// Private function. Used to implement assignment to the array element.
|
||||||
fn (mut a array) set(i int, val voidptr) {
|
fn (mut a array) set(i int, val voidptr) {
|
||||||
$if !no_bounds_checking ? {
|
$if !no_bounds_checking ? {
|
||||||
if i < 0 || i >= a.len {
|
if i < 0 || i >= a.len {
|
||||||
|
@ -636,6 +636,9 @@ fn (mut a array) push(val voidptr) {
|
||||||
// `val` is array.data and user facing usage is `a << [1,2,3]`
|
// `val` is array.data and user facing usage is `a << [1,2,3]`
|
||||||
[unsafe]
|
[unsafe]
|
||||||
pub fn (mut a3 array) push_many(val voidptr, size int) {
|
pub fn (mut a3 array) push_many(val voidptr, size int) {
|
||||||
|
if size <= 0 || isnil(val) {
|
||||||
|
return
|
||||||
|
}
|
||||||
a3.ensure_cap(a3.len + size)
|
a3.ensure_cap(a3.len + size)
|
||||||
if a3.data == val && a3.data != 0 {
|
if a3.data == val && a3.data != 0 {
|
||||||
// handle `arr << arr`
|
// handle `arr << arr`
|
||||||
|
|
|
@ -227,6 +227,9 @@ fn (mut a array) push_noscan(val voidptr) {
|
||||||
// `val` is array.data and user facing usage is `a << [1,2,3]`
|
// `val` is array.data and user facing usage is `a << [1,2,3]`
|
||||||
[unsafe]
|
[unsafe]
|
||||||
fn (mut a3 array) push_many_noscan(val voidptr, size int) {
|
fn (mut a3 array) push_many_noscan(val voidptr, size int) {
|
||||||
|
if size <= 0 || isnil(val) {
|
||||||
|
return
|
||||||
|
}
|
||||||
if a3.data == val && a3.data != 0 {
|
if a3.data == val && a3.data != 0 {
|
||||||
// handle `arr << arr`
|
// handle `arr << arr`
|
||||||
copy := a3.clone()
|
copy := a3.clone()
|
||||||
|
|
|
@ -1590,3 +1590,14 @@ fn test_inline_array_element_access() {
|
||||||
a2 := [1][0]
|
a2 := [1][0]
|
||||||
assert a2 == 1
|
assert a2 == 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
fn f(x int, y int) []int {
|
||||||
|
return [x, y]
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_2d_array_init_with_it() {
|
||||||
|
a := [][]int{len: 6, init: f(it, 2 * it)}
|
||||||
|
assert a == [[0, 0], [1, 2], [2, 4], [3, 6], [4, 8], [5, 10]]
|
||||||
|
}
|
||||||
|
|
|
@ -55,7 +55,7 @@ fn panic_debug(line_no int, file string, mod string, fn_name string, s string) {
|
||||||
C.exit(1)
|
C.exit(1)
|
||||||
}
|
}
|
||||||
$if use_libbacktrace ? {
|
$if use_libbacktrace ? {
|
||||||
print_libbacktrace(1)
|
eprint_libbacktrace(1)
|
||||||
} $else {
|
} $else {
|
||||||
print_backtrace_skipping_top_frames(1)
|
print_backtrace_skipping_top_frames(1)
|
||||||
}
|
}
|
||||||
|
@ -106,7 +106,7 @@ pub fn panic(s string) {
|
||||||
C.exit(1)
|
C.exit(1)
|
||||||
}
|
}
|
||||||
$if use_libbacktrace ? {
|
$if use_libbacktrace ? {
|
||||||
print_libbacktrace(1)
|
eprint_libbacktrace(1)
|
||||||
} $else {
|
} $else {
|
||||||
print_backtrace_skipping_top_frames(1)
|
print_backtrace_skipping_top_frames(1)
|
||||||
}
|
}
|
||||||
|
@ -268,13 +268,28 @@ fn _write_buf_to_fd(fd int, buf &u8, buf_len int) {
|
||||||
if buf_len <= 0 {
|
if buf_len <= 0 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
unsafe {
|
mut ptr := unsafe { buf }
|
||||||
mut ptr := buf
|
mut remaining_bytes := isize(buf_len)
|
||||||
mut remaining_bytes := buf_len
|
mut x := isize(0)
|
||||||
for remaining_bytes > 0 {
|
$if freestanding || vinix {
|
||||||
x := C.write(fd, ptr, remaining_bytes)
|
unsafe {
|
||||||
ptr += x
|
for remaining_bytes > 0 {
|
||||||
remaining_bytes -= x
|
x = C.write(fd, ptr, remaining_bytes)
|
||||||
|
ptr += x
|
||||||
|
remaining_bytes -= x
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} $else {
|
||||||
|
mut stream := voidptr(C.stdout)
|
||||||
|
if fd == 2 {
|
||||||
|
stream = voidptr(C.stderr)
|
||||||
|
}
|
||||||
|
unsafe {
|
||||||
|
for remaining_bytes > 0 {
|
||||||
|
x = isize(C.fwrite(ptr, 1, remaining_bytes, stream))
|
||||||
|
ptr += x
|
||||||
|
remaining_bytes -= x
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -373,6 +388,49 @@ pub fn malloc_noscan(n isize) &u8 {
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// malloc_uncollectable dynamically allocates a `n` bytes block of memory
|
||||||
|
// on the heap, which will NOT be garbage-collected (but its contents will).
|
||||||
|
[unsafe]
|
||||||
|
pub fn malloc_uncollectable(n isize) &u8 {
|
||||||
|
if n <= 0 {
|
||||||
|
panic('malloc_uncollectable($n <= 0)')
|
||||||
|
}
|
||||||
|
$if vplayground ? {
|
||||||
|
if n > 10000 {
|
||||||
|
panic('allocating more than 10 KB at once is not allowed in the V playground')
|
||||||
|
}
|
||||||
|
if total_m > 50 * 1024 * 1024 {
|
||||||
|
panic('allocating more than 50 MB is not allowed in the V playground')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$if trace_malloc ? {
|
||||||
|
total_m += n
|
||||||
|
C.fprintf(C.stderr, c'malloc_uncollectable %6d total %10d\n', n, total_m)
|
||||||
|
// print_backtrace()
|
||||||
|
}
|
||||||
|
mut res := &u8(0)
|
||||||
|
$if prealloc {
|
||||||
|
return unsafe { prealloc_malloc(n) }
|
||||||
|
} $else $if gcboehm ? {
|
||||||
|
unsafe {
|
||||||
|
res = C.GC_MALLOC_UNCOLLECTABLE(n)
|
||||||
|
}
|
||||||
|
} $else $if freestanding {
|
||||||
|
res = unsafe { __malloc(usize(n)) }
|
||||||
|
} $else {
|
||||||
|
res = unsafe { C.malloc(n) }
|
||||||
|
}
|
||||||
|
if res == 0 {
|
||||||
|
panic('malloc_uncollectable($n) failed')
|
||||||
|
}
|
||||||
|
$if debug_malloc ? {
|
||||||
|
// Fill in the memory with something != 0 i.e. `M`, so it is easier to spot
|
||||||
|
// when the calling code wrongly relies on it being zeroed.
|
||||||
|
unsafe { C.memset(res, 0x4D, n) }
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
// v_realloc resizes the memory block `b` with `n` bytes.
|
// v_realloc resizes the memory block `b` with `n` bytes.
|
||||||
// The `b byteptr` must be a pointer to an existing memory block
|
// The `b byteptr` must be a pointer to an existing memory block
|
||||||
// previously allocated with `malloc`, `v_calloc` or `vcalloc`.
|
// previously allocated with `malloc`, `v_calloc` or `vcalloc`.
|
||||||
|
@ -540,6 +598,21 @@ pub fn memdup_noscan(src voidptr, sz int) voidptr {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// memdup_uncollectable dynamically allocates a `sz` bytes block of memory
|
||||||
|
// on the heap, which will NOT be garbage-collected (but its contents will).
|
||||||
|
// memdup_uncollectable then copies the contents of `src` into the allocated
|
||||||
|
// space and returns a pointer to the newly allocated space.
|
||||||
|
[unsafe]
|
||||||
|
pub fn memdup_uncollectable(src voidptr, sz int) voidptr {
|
||||||
|
if sz == 0 {
|
||||||
|
return vcalloc(1)
|
||||||
|
}
|
||||||
|
unsafe {
|
||||||
|
mem := malloc_uncollectable(sz)
|
||||||
|
return C.memcpy(mem, src, sz)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
[inline]
|
[inline]
|
||||||
fn v_fixed_index(i int, len int) int {
|
fn v_fixed_index(i int, len int) int {
|
||||||
$if !no_bounds_checking ? {
|
$if !no_bounds_checking ? {
|
||||||
|
|
|
@ -130,6 +130,10 @@ pub:
|
||||||
[markused]
|
[markused]
|
||||||
fn v_segmentation_fault_handler(signal int) {
|
fn v_segmentation_fault_handler(signal int) {
|
||||||
eprintln('signal 11: segmentation fault')
|
eprintln('signal 11: segmentation fault')
|
||||||
print_backtrace()
|
$if use_libbacktrace ? {
|
||||||
|
eprint_libbacktrace(1)
|
||||||
|
} $else {
|
||||||
|
print_backtrace()
|
||||||
|
}
|
||||||
exit(128 + 11)
|
exit(128 + 11)
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,16 +3,16 @@ module builtin
|
||||||
$if dynamic_boehm ? {
|
$if dynamic_boehm ? {
|
||||||
$if windows {
|
$if windows {
|
||||||
$if tinyc {
|
$if tinyc {
|
||||||
#flag -I@VEXEROOT/thirdparty/libgc/include
|
#flag -I @VEXEROOT/thirdparty/libgc/include
|
||||||
#flag -L@VEXEROOT/thirdparty/tcc/lib
|
#flag -L @VEXEROOT/thirdparty/tcc/lib
|
||||||
#flag -lgc
|
#flag -lgc
|
||||||
} $else $if msvc {
|
} $else $if msvc {
|
||||||
#flag -DGC_BUILTIN_ATOMIC=1
|
#flag -DGC_BUILTIN_ATOMIC=1
|
||||||
#flag -I@VEXEROOT/thirdparty/libgc/include
|
#flag -I @VEXEROOT/thirdparty/libgc/include
|
||||||
} $else {
|
} $else {
|
||||||
#flag -DGC_WIN32_THREADS=1
|
#flag -DGC_WIN32_THREADS=1
|
||||||
#flag -DGC_BUILTIN_ATOMIC=1
|
#flag -DGC_BUILTIN_ATOMIC=1
|
||||||
#flag -I@VEXEROOT/thirdparty/libgc
|
#flag -I @VEXEROOT/thirdparty/libgc
|
||||||
#flag @VEXEROOT/thirdparty/libgc/gc.o
|
#flag @VEXEROOT/thirdparty/libgc/gc.o
|
||||||
}
|
}
|
||||||
} $else {
|
} $else {
|
||||||
|
@ -31,21 +31,21 @@ $if dynamic_boehm ? {
|
||||||
#flag -DGC_BUILTIN_ATOMIC=1
|
#flag -DGC_BUILTIN_ATOMIC=1
|
||||||
$if macos || linux {
|
$if macos || linux {
|
||||||
#flag -DGC_PTHREADS=1
|
#flag -DGC_PTHREADS=1
|
||||||
#flag -I@VEXEROOT/thirdparty/libgc/include
|
#flag -I @VEXEROOT/thirdparty/libgc/include
|
||||||
#flag -lpthread
|
$if (!macos && prod && !tinyc && !debug) || !(amd64 || arm64 || i386 || arm32) {
|
||||||
$if (prod && !tinyc && !debug) || !(amd64 || arm64 || i386 || arm32) {
|
|
||||||
// TODO: replace the architecture check with a `!$exists("@VEXEROOT/thirdparty/tcc/lib/libgc.a")` comptime call
|
// TODO: replace the architecture check with a `!$exists("@VEXEROOT/thirdparty/tcc/lib/libgc.a")` comptime call
|
||||||
#flag @VEXEROOT/thirdparty/libgc/gc.o
|
#flag @VEXEROOT/thirdparty/libgc/gc.o
|
||||||
} $else {
|
} $else {
|
||||||
#flag @VEXEROOT/thirdparty/tcc/lib/libgc.a
|
#flag @VEXEROOT/thirdparty/tcc/lib/libgc.a
|
||||||
}
|
}
|
||||||
#flag -ldl
|
#flag -ldl
|
||||||
|
#flag -lpthread
|
||||||
} $else $if freebsd {
|
} $else $if freebsd {
|
||||||
// Tested on FreeBSD 13.0-RELEASE-p3, with clang, gcc and tcc:
|
// Tested on FreeBSD 13.0-RELEASE-p3, with clang, gcc and tcc:
|
||||||
#flag -DBUS_PAGE_FAULT=T_PAGEFLT
|
#flag -DBUS_PAGE_FAULT=T_PAGEFLT
|
||||||
#flag -DGC_PTHREADS=1
|
#flag -DGC_PTHREADS=1
|
||||||
$if !tinyc {
|
$if !tinyc {
|
||||||
#flag -I@VEXEROOT/thirdparty/libgc/include
|
#flag -I @VEXEROOT/thirdparty/libgc/include
|
||||||
#flag @VEXEROOT/thirdparty/libgc/gc.o
|
#flag @VEXEROOT/thirdparty/libgc/gc.o
|
||||||
}
|
}
|
||||||
$if tinyc {
|
$if tinyc {
|
||||||
|
@ -59,15 +59,14 @@ $if dynamic_boehm ? {
|
||||||
#flag $first_existing("/usr/local/lib/libgc.a", "/usr/lib/libgc.a")
|
#flag $first_existing("/usr/local/lib/libgc.a", "/usr/lib/libgc.a")
|
||||||
#flag -lpthread
|
#flag -lpthread
|
||||||
} $else $if windows {
|
} $else $if windows {
|
||||||
|
#flag -DGC_NOT_DLL=1
|
||||||
|
#flag -DGC_WIN32_THREADS=1
|
||||||
$if tinyc {
|
$if tinyc {
|
||||||
#flag -I@VEXEROOT/thirdparty/libgc/include
|
#flag -I @VEXEROOT/thirdparty/libgc/include
|
||||||
#flag -L@VEXEROOT/thirdparty/tcc/lib
|
#flag @VEXEROOT/thirdparty/tcc/lib/libgc.a
|
||||||
#flag -lgc
|
#flag -luser32
|
||||||
} $else {
|
} $else {
|
||||||
#flag -DGC_NOT_DLL=1
|
#flag -I @VEXEROOT/thirdparty/libgc/include
|
||||||
#flag -DGC_WIN32_THREADS=1
|
|
||||||
#flag -DGC_BUILTIN_ATOMIC=1
|
|
||||||
#flag -I@VEXEROOT/thirdparty/libgc/include
|
|
||||||
#flag @VEXEROOT/thirdparty/libgc/gc.o
|
#flag @VEXEROOT/thirdparty/libgc/gc.o
|
||||||
}
|
}
|
||||||
} $else $if $pkgconfig('bdw-gc') {
|
} $else $if $pkgconfig('bdw-gc') {
|
||||||
|
|
|
@ -33,11 +33,11 @@ fn init_bt_state() &C.backtrace_state {
|
||||||
}
|
}
|
||||||
|
|
||||||
// for bt_error_callback
|
// for bt_error_callback
|
||||||
// struct BacktraceData {
|
struct BacktraceOptions {
|
||||||
// state &C.backtrace_state
|
stdin bool = true
|
||||||
// }
|
}
|
||||||
|
|
||||||
fn bt_print_callback(data voidptr, pc voidptr, filename_ptr &char, line int, fn_name_ptr &char) int {
|
fn bt_print_callback(data &BacktraceOptions, pc voidptr, filename_ptr &char, line int, fn_name_ptr &char) int {
|
||||||
filename := if isnil(filename_ptr) { '???' } else { unsafe { filename_ptr.vstring() } }
|
filename := if isnil(filename_ptr) { '???' } else { unsafe { filename_ptr.vstring() } }
|
||||||
fn_name := if isnil(fn_name_ptr) {
|
fn_name := if isnil(fn_name_ptr) {
|
||||||
'???'
|
'???'
|
||||||
|
@ -46,7 +46,12 @@ fn bt_print_callback(data voidptr, pc voidptr, filename_ptr &char, line int, fn_
|
||||||
}
|
}
|
||||||
// keep it for later
|
// keep it for later
|
||||||
// pc_64 := u64(pc)
|
// pc_64 := u64(pc)
|
||||||
println('$filename:$line: by $fn_name')
|
bt_str := '$filename:$line: by $fn_name'
|
||||||
|
if data.stdin {
|
||||||
|
println(bt_str)
|
||||||
|
} else {
|
||||||
|
eprintln(bt_str)
|
||||||
|
}
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -81,6 +86,17 @@ fn print_libbacktrace(frames_to_skip int) {
|
||||||
$if no_backtrace ? {
|
$if no_backtrace ? {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// data := &BacktraceData{bt_state}
|
data := &BacktraceOptions{}
|
||||||
C.backtrace_full(bt_state, frames_to_skip, bt_print_callback, bt_error_callback, 0)
|
C.backtrace_full(bt_state, frames_to_skip, bt_print_callback, bt_error_callback, data)
|
||||||
|
}
|
||||||
|
|
||||||
|
[noinline]
|
||||||
|
fn eprint_libbacktrace(frames_to_skip int) {
|
||||||
|
$if no_backtrace ? {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
data := &BacktraceOptions{
|
||||||
|
stdin: false
|
||||||
|
}
|
||||||
|
C.backtrace_full(bt_state, frames_to_skip, bt_print_callback, bt_error_callback, data)
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,3 +2,7 @@ module builtin
|
||||||
|
|
||||||
fn print_libbacktrace(frames_to_skip int) {
|
fn print_libbacktrace(frames_to_skip int) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[noinline]
|
||||||
|
fn eprint_libbacktrace(frames_to_skip int) {
|
||||||
|
}
|
||||||
|
|
|
@ -14,6 +14,14 @@ $if js_freestanding {
|
||||||
#globalPrint = globalThis.print
|
#globalPrint = globalThis.print
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn flush_stdout() {
|
||||||
|
// needed for parity with builtin.c.v
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn flush_stderr() {
|
||||||
|
// needed for parity with builtin.c.v
|
||||||
|
}
|
||||||
|
|
||||||
pub fn println(s string) {
|
pub fn println(s string) {
|
||||||
$if js_freestanding {
|
$if js_freestanding {
|
||||||
#globalPrint(s.str)
|
#globalPrint(s.str)
|
||||||
|
|
|
@ -205,7 +205,11 @@ pub fn (s string) hash() int {
|
||||||
|
|
||||||
// int returns the value of the string as an integer `'1'.int() == 1`.
|
// int returns the value of the string as an integer `'1'.int() == 1`.
|
||||||
pub fn (s string) int() int {
|
pub fn (s string) int() int {
|
||||||
return int(JS.parseInt(s.str))
|
res := int(0)
|
||||||
|
#if (typeof(s) == "string") { res.val = parseInt(s) }
|
||||||
|
#else { res.val = parseInt(s.str) }
|
||||||
|
|
||||||
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
// i64 returns the value of the string as i64 `'1'.i64() == i64(1)`.
|
// i64 returns the value of the string as i64 `'1'.i64() == i64(1)`.
|
||||||
|
|
|
@ -113,14 +113,6 @@ struct Option {
|
||||||
// derived Option_xxx types
|
// derived Option_xxx types
|
||||||
}
|
}
|
||||||
|
|
||||||
fn opt_ok(data voidptr, mut option Option, size int) {
|
|
||||||
unsafe {
|
|
||||||
*option = Option{}
|
|
||||||
// use err to get the end of OptionBase and then memcpy into it
|
|
||||||
vmemcpy(&u8(&option.err) + sizeof(IError), data, size)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// option is the base of V's internal optional return system.
|
// option is the base of V's internal optional return system.
|
||||||
struct _option {
|
struct _option {
|
||||||
state u8
|
state u8
|
||||||
|
@ -130,6 +122,14 @@ struct _option {
|
||||||
// derived _option_xxx types
|
// derived _option_xxx types
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn _option_ok(data voidptr, mut option _option, size int) {
|
||||||
|
unsafe {
|
||||||
|
*option = _option{}
|
||||||
|
// use err to get the end of OptionBase and then memcpy into it
|
||||||
|
vmemcpy(&u8(&option.err) + sizeof(IError), data, size)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn opt_ok2(data voidptr, mut option _option, size int) {
|
fn opt_ok2(data voidptr, mut option _option, size int) {
|
||||||
unsafe {
|
unsafe {
|
||||||
*option = _option{}
|
*option = _option{}
|
||||||
|
|
|
@ -32,9 +32,10 @@ mut:
|
||||||
[unsafe]
|
[unsafe]
|
||||||
fn vmemory_block_new(prev &VMemoryBlock, at_least isize) &VMemoryBlock {
|
fn vmemory_block_new(prev &VMemoryBlock, at_least isize) &VMemoryBlock {
|
||||||
mut v := unsafe { &VMemoryBlock(C.calloc(1, sizeof(VMemoryBlock))) }
|
mut v := unsafe { &VMemoryBlock(C.calloc(1, sizeof(VMemoryBlock))) }
|
||||||
if prev != 0 {
|
if unsafe { prev != 0 } {
|
||||||
v.id = prev.id + 1
|
v.id = prev.id + 1
|
||||||
}
|
}
|
||||||
|
|
||||||
v.previous = prev
|
v.previous = prev
|
||||||
block_size := if at_least < prealloc_block_size { prealloc_block_size } else { at_least }
|
block_size := if at_least < prealloc_block_size { prealloc_block_size } else { at_least }
|
||||||
v.start = unsafe { C.malloc(block_size) }
|
v.start = unsafe { C.malloc(block_size) }
|
||||||
|
@ -79,7 +80,7 @@ fn prealloc_vcleanup() {
|
||||||
// The second loop however should *not* allocate at all.
|
// The second loop however should *not* allocate at all.
|
||||||
mut nr_mallocs := i64(0)
|
mut nr_mallocs := i64(0)
|
||||||
mut mb := g_memory_block
|
mut mb := g_memory_block
|
||||||
for mb != 0 {
|
for unsafe { mb != 0 } {
|
||||||
nr_mallocs += mb.mallocs
|
nr_mallocs += mb.mallocs
|
||||||
eprintln('> freeing mb.id: ${mb.id:3} | cap: ${mb.cap:7} | rem: ${mb.remaining:7} | start: ${voidptr(mb.start)} | current: ${voidptr(mb.current)} | diff: ${u64(mb.current) - u64(mb.start):7} bytes | mallocs: $mb.mallocs')
|
eprintln('> freeing mb.id: ${mb.id:3} | cap: ${mb.cap:7} | rem: ${mb.remaining:7} | start: ${voidptr(mb.start)} | current: ${voidptr(mb.current)} | diff: ${u64(mb.current) - u64(mb.start):7} bytes | mallocs: $mb.mallocs')
|
||||||
mb = mb.previous
|
mb = mb.previous
|
||||||
|
|
|
@ -37,26 +37,26 @@ pub enum StrIntpType {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (x StrIntpType) str() string {
|
pub fn (x StrIntpType) str() string {
|
||||||
match x {
|
return match x {
|
||||||
.si_no_str { return 'no_str' }
|
.si_no_str { 'no_str' }
|
||||||
.si_c { return 'c' }
|
.si_c { 'c' }
|
||||||
.si_u8 { return 'u8' }
|
.si_u8 { 'u8' }
|
||||||
.si_i8 { return 'i8' }
|
.si_i8 { 'i8' }
|
||||||
.si_u16 { return 'u16' }
|
.si_u16 { 'u16' }
|
||||||
.si_i16 { return 'i16' }
|
.si_i16 { 'i16' }
|
||||||
.si_u32 { return 'u32' }
|
.si_u32 { 'u32' }
|
||||||
.si_i32 { return 'i32' }
|
.si_i32 { 'i32' }
|
||||||
.si_u64 { return 'u64' }
|
.si_u64 { 'u64' }
|
||||||
.si_i64 { return 'i64' }
|
.si_i64 { 'i64' }
|
||||||
.si_f32 { return 'f32' }
|
.si_f32 { 'f32' }
|
||||||
.si_f64 { return 'f64' }
|
.si_f64 { 'f64' }
|
||||||
.si_g32 { return 'f32' } // g32 format use f32 data
|
.si_g32 { 'f32' } // g32 format use f32 data
|
||||||
.si_g64 { return 'f64' } // g64 format use f64 data
|
.si_g64 { 'f64' } // g64 format use f64 data
|
||||||
.si_e32 { return 'f32' } // e32 format use f32 data
|
.si_e32 { 'f32' } // e32 format use f32 data
|
||||||
.si_e64 { return 'f64' } // e64 format use f64 data
|
.si_e64 { 'f64' } // e64 format use f64 data
|
||||||
.si_s { return 's' }
|
.si_s { 's' }
|
||||||
.si_p { return 'p' }
|
.si_p { 'p' }
|
||||||
.si_vp { return 'vp' }
|
.si_vp { 'vp' }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -53,7 +53,7 @@ pub fn (cmd Command) str() string {
|
||||||
res << ' cb execute: $cmd.execute'
|
res << ' cb execute: $cmd.execute'
|
||||||
res << ' cb pre_execute: $cmd.pre_execute'
|
res << ' cb pre_execute: $cmd.pre_execute'
|
||||||
res << ' cb post_execute: $cmd.post_execute'
|
res << ' cb post_execute: $cmd.post_execute'
|
||||||
if cmd.parent == 0 {
|
if unsafe { cmd.parent == 0 } {
|
||||||
res << ' parent: &Command(0)'
|
res << ' parent: &Command(0)'
|
||||||
} else {
|
} else {
|
||||||
res << ' parent: &Command{$cmd.parent.name ...}'
|
res << ' parent: &Command{$cmd.parent.name ...}'
|
||||||
|
|
|
@ -49,7 +49,7 @@ pub fn print_help_for_command(help_cmd Command) ? {
|
||||||
}
|
}
|
||||||
print(cmd.help_message())
|
print(cmd.help_message())
|
||||||
} else {
|
} else {
|
||||||
if help_cmd.parent != 0 {
|
if unsafe { help_cmd.parent != 0 } {
|
||||||
print(help_cmd.parent.help_message())
|
print(help_cmd.parent.help_message())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,7 +41,7 @@ pub fn print_manpage_for_command(man_cmd Command) ? {
|
||||||
}
|
}
|
||||||
print(cmd.manpage())
|
print(cmd.manpage())
|
||||||
} else {
|
} else {
|
||||||
if man_cmd.parent != 0 {
|
if unsafe { man_cmd.parent != 0 } {
|
||||||
print(man_cmd.parent.manpage())
|
print(man_cmd.parent.manpage())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -55,7 +55,7 @@ pub fn (cmd Command) manpage() string {
|
||||||
mdoc += '.Os\n.Sh NAME\n.Nm ${cmd.full_name().replace(' ', '-')}\n.Nd $cmd.description\n'
|
mdoc += '.Os\n.Sh NAME\n.Nm ${cmd.full_name().replace(' ', '-')}\n.Nd $cmd.description\n'
|
||||||
mdoc += '.Sh SYNOPSIS\n'
|
mdoc += '.Sh SYNOPSIS\n'
|
||||||
mdoc += '.Nm $cmd.root().name\n'
|
mdoc += '.Nm $cmd.root().name\n'
|
||||||
if cmd.parent != 0 {
|
if unsafe { cmd.parent != 0 } {
|
||||||
mut parents := []Command{}
|
mut parents := []Command{}
|
||||||
if !cmd.parent.is_root() {
|
if !cmd.parent.is_root() {
|
||||||
parents.prepend(cmd.parent)
|
parents.prepend(cmd.parent)
|
||||||
|
@ -96,7 +96,7 @@ pub fn (cmd Command) manpage() string {
|
||||||
}
|
}
|
||||||
if cmd.commands.len > 0 {
|
if cmd.commands.len > 0 {
|
||||||
mdoc += '.Nm $cmd.root().name\n'
|
mdoc += '.Nm $cmd.root().name\n'
|
||||||
if cmd.parent != 0 {
|
if unsafe { cmd.parent != 0 } {
|
||||||
mut parents := []Command{}
|
mut parents := []Command{}
|
||||||
if !cmd.parent.is_root() {
|
if !cmd.parent.is_root() {
|
||||||
parents.prepend(cmd.parent)
|
parents.prepend(cmd.parent)
|
||||||
|
@ -158,7 +158,7 @@ pub fn (cmd Command) manpage() string {
|
||||||
if cmd.commands.len > 0 {
|
if cmd.commands.len > 0 {
|
||||||
mdoc += '.Sh SEE ALSO\n'
|
mdoc += '.Sh SEE ALSO\n'
|
||||||
mut cmds := []string{}
|
mut cmds := []string{}
|
||||||
if cmd.parent != 0 {
|
if unsafe { cmd.parent != 0 } {
|
||||||
cmds << cmd.parent.full_name().replace(' ', '-')
|
cmds << cmd.parent.full_name().replace(' ', '-')
|
||||||
}
|
}
|
||||||
for c in cmd.commands {
|
for c in cmd.commands {
|
||||||
|
|
|
@ -55,7 +55,7 @@ fn C.DestroyWindow(hwnd C.HWND)
|
||||||
//
|
//
|
||||||
// System "copy" and "paste" actions utilize the clipboard for temporary storage.
|
// System "copy" and "paste" actions utilize the clipboard for temporary storage.
|
||||||
[heap]
|
[heap]
|
||||||
struct Clipboard {
|
pub struct Clipboard {
|
||||||
max_retries int
|
max_retries int
|
||||||
retry_delay int
|
retry_delay int
|
||||||
mut:
|
mut:
|
||||||
|
|
|
@ -1,4 +1,8 @@
|
||||||
## Description:
|
## Description:
|
||||||
|
|
||||||
`compress` is a namespace for (multiple) compression algorithms supported by V.
|
`compress` is a namespace for (multiple) compression algorithms supported by V.
|
||||||
At the moment, only `compress.zlib` is implemented.
|
|
||||||
|
At the moment, the following compression algorithms are implemented:
|
||||||
|
- `compress.deflate`
|
||||||
|
- `compress.gzip`
|
||||||
|
- `compress.zlib`
|
||||||
|
|
|
@ -0,0 +1,44 @@
|
||||||
|
module compress
|
||||||
|
|
||||||
|
#flag -I @VEXEROOT/thirdparty/zip
|
||||||
|
#include "miniz.h"
|
||||||
|
|
||||||
|
pub const max_size = u64(1 << 31)
|
||||||
|
|
||||||
|
fn C.tdefl_compress_mem_to_heap(source_buf voidptr, source_buf_len usize, out_len &usize, flags int) voidptr
|
||||||
|
fn C.tinfl_decompress_mem_to_heap(source_buf voidptr, source_buf_len usize, out_len &usize, flags int) voidptr
|
||||||
|
|
||||||
|
// compresses an array of bytes based on providing flags and returns the compressed bytes in a new array
|
||||||
|
// NB: this is a low level api, a high level implementation like zlib/gzip should be preferred
|
||||||
|
[manualfree]
|
||||||
|
pub fn compress(data []u8, flags int) ?[]u8 {
|
||||||
|
if u64(data.len) > compress.max_size {
|
||||||
|
return error('data too large ($data.len > $compress.max_size)')
|
||||||
|
}
|
||||||
|
mut out_len := usize(0)
|
||||||
|
|
||||||
|
address := C.tdefl_compress_mem_to_heap(data.data, data.len, &out_len, flags)
|
||||||
|
if address == 0 {
|
||||||
|
return error('compression failed')
|
||||||
|
}
|
||||||
|
if u64(out_len) > compress.max_size {
|
||||||
|
return error('compressed data is too large ($out_len > $compress.max_size)')
|
||||||
|
}
|
||||||
|
return unsafe { address.vbytes(int(out_len)) }
|
||||||
|
}
|
||||||
|
|
||||||
|
// decompresses an array of bytes based on providing flags and returns the decompressed bytes in a new array
|
||||||
|
// NB: this is a low level api, a high level implementation like zlib/gzip should be preferred
|
||||||
|
[manualfree]
|
||||||
|
pub fn decompress(data []u8, flags int) ?[]u8 {
|
||||||
|
mut out_len := usize(0)
|
||||||
|
|
||||||
|
address := C.tinfl_decompress_mem_to_heap(data.data, data.len, &out_len, flags)
|
||||||
|
if address == 0 {
|
||||||
|
return error('decompression failed')
|
||||||
|
}
|
||||||
|
if u64(out_len) > compress.max_size {
|
||||||
|
return error('decompressed data is too large ($out_len > $compress.max_size)')
|
||||||
|
}
|
||||||
|
return unsafe { address.vbytes(int(out_len)) }
|
||||||
|
}
|
|
@ -0,0 +1,18 @@
|
||||||
|
## Description:
|
||||||
|
|
||||||
|
`compress.deflate` is a module that assists in the compression and
|
||||||
|
decompression of binary data using `deflate` compression
|
||||||
|
|
||||||
|
|
||||||
|
## Examples:
|
||||||
|
|
||||||
|
```v
|
||||||
|
import compress.deflate
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
uncompressed := 'Hello world!'
|
||||||
|
compressed := deflate.compress(uncompressed.bytes())?
|
||||||
|
decompressed := deflate.decompress(compressed)?
|
||||||
|
assert decompressed == uncompressed.bytes()
|
||||||
|
}
|
||||||
|
```
|
|
@ -0,0 +1,15 @@
|
||||||
|
module deflate
|
||||||
|
|
||||||
|
import compress
|
||||||
|
|
||||||
|
// compresses an array of bytes using deflate and returns the compressed bytes in a new array
|
||||||
|
// Example: compressed := deflate.compress(b)?
|
||||||
|
pub fn compress(data []u8) ?[]u8 {
|
||||||
|
return compress.compress(data, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
// decompresses an array of bytes using deflate and returns the decompressed bytes in a new array
|
||||||
|
// Example: decompressed := deflate.decompress(b)?
|
||||||
|
pub fn decompress(data []u8) ?[]u8 {
|
||||||
|
return compress.decompress(data, 0)
|
||||||
|
}
|
|
@ -0,0 +1,12 @@
|
||||||
|
module deflate
|
||||||
|
|
||||||
|
const gzip_magic_numbers = [u8(0x1f), 0x8b]
|
||||||
|
|
||||||
|
fn test_gzip() ? {
|
||||||
|
uncompressed := 'Hello world!'
|
||||||
|
compressed := compress(uncompressed.bytes())?
|
||||||
|
first2 := compressed[0..2]
|
||||||
|
assert first2 != deflate.gzip_magic_numbers
|
||||||
|
decompressed := decompress(compressed)?
|
||||||
|
assert decompressed == uncompressed.bytes()
|
||||||
|
}
|
|
@ -0,0 +1,18 @@
|
||||||
|
## Description:
|
||||||
|
|
||||||
|
`compress.gzip` is a module that assists in the compression and
|
||||||
|
decompression of binary data using `gzip` compression
|
||||||
|
|
||||||
|
|
||||||
|
## Examples:
|
||||||
|
|
||||||
|
```v
|
||||||
|
import compress.gzip
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
uncompressed := 'Hello world!'
|
||||||
|
compressed := gzip.compress(uncompressed.bytes())?
|
||||||
|
decompressed := gzip.decompress(compressed)?
|
||||||
|
assert decompressed == uncompressed.bytes()
|
||||||
|
}
|
||||||
|
```
|
|
@ -0,0 +1,121 @@
|
||||||
|
// [rfc1952](https://datatracker.ietf.org/doc/html/rfc1952) compliant
|
||||||
|
// gzip compression/decompression
|
||||||
|
|
||||||
|
module gzip
|
||||||
|
|
||||||
|
import compress
|
||||||
|
import hash.crc32
|
||||||
|
|
||||||
|
// compresses an array of bytes using gzip and returns the compressed bytes in a new array
|
||||||
|
// Example: compressed := gzip.compress(b)?
|
||||||
|
pub fn compress(data []u8) ?[]u8 {
|
||||||
|
compressed := compress.compress(data, 0)?
|
||||||
|
// header
|
||||||
|
mut result := [
|
||||||
|
u8(0x1f), // magic numbers (1F 8B)
|
||||||
|
0x8b,
|
||||||
|
0x08, // deflate
|
||||||
|
0x00, // header flags
|
||||||
|
0x00, // 4-byte timestamp, 0 = no timestamp (00 00 00 00)
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x00, // extra flags
|
||||||
|
0xff, // operating system id (0xff = unknown)
|
||||||
|
] // 10 bytes
|
||||||
|
result << compressed
|
||||||
|
// trailer
|
||||||
|
checksum := crc32.sum(data)
|
||||||
|
length := data.len
|
||||||
|
result << [
|
||||||
|
u8(checksum >> 24),
|
||||||
|
u8(checksum >> 16),
|
||||||
|
u8(checksum >> 8),
|
||||||
|
u8(checksum),
|
||||||
|
u8(length >> 24),
|
||||||
|
u8(length >> 16),
|
||||||
|
u8(length >> 8),
|
||||||
|
u8(length),
|
||||||
|
] // 8 bytes
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
[params]
|
||||||
|
pub struct DecompressParams {
|
||||||
|
verify_header_checksum bool = true
|
||||||
|
verify_length bool = true
|
||||||
|
verify_checksum bool = true
|
||||||
|
}
|
||||||
|
|
||||||
|
// decompresses an array of bytes using zlib and returns the decompressed bytes in a new array
|
||||||
|
// Example: decompressed := gzip.decompress(b)?
|
||||||
|
pub fn decompress(data []u8, params DecompressParams) ?[]u8 {
|
||||||
|
if data.len < 18 {
|
||||||
|
return error('data is too short, not gzip compressed?')
|
||||||
|
} else if data[0] != 0x1f || data[1] != 0x8b {
|
||||||
|
return error('wrong magic numbers, not gzip compressed?')
|
||||||
|
} else if data[2] != 0x08 {
|
||||||
|
return error('gzip data is not compressed with DEFLATE')
|
||||||
|
}
|
||||||
|
mut header_length := 10
|
||||||
|
|
||||||
|
// parse flags, we ignore most of them, but we still need to parse them
|
||||||
|
// correctly, so we dont accidently decompress something that belongs
|
||||||
|
// to the header
|
||||||
|
|
||||||
|
if data[4] & 0b1110_0000 > 0 { // reserved bits
|
||||||
|
// rfc 1952 2.3.1.2 Compliance
|
||||||
|
// A compliant decompressor must give an error indication if any
|
||||||
|
// reserved bit is non-zero, since such a bit could indicate the
|
||||||
|
// presence of a new field that would cause subsequent data to be
|
||||||
|
// interpreted incorrectly.
|
||||||
|
return error('reserved flags are set, unsupported field detected')
|
||||||
|
}
|
||||||
|
|
||||||
|
// if data[4] & 0b0000_0001 {} // FTEXT
|
||||||
|
if data[4] & 0b0000_0100 > 0 { // FEXTRA, extra data
|
||||||
|
xlen := data[header_length]
|
||||||
|
header_length += xlen + 1
|
||||||
|
}
|
||||||
|
if data[4] & 0b0000_1000 > 0 { // FNAME, file name
|
||||||
|
// filename is zero-terminated, so skip until we hit a zero byte
|
||||||
|
for header_length < data.len && data[header_length] != 0x00 {
|
||||||
|
header_length++
|
||||||
|
}
|
||||||
|
header_length++
|
||||||
|
}
|
||||||
|
if data[4] & 0b0001_0000 > 0 { // FCOMMENT
|
||||||
|
// comment is zero-terminated, so skip until we hit a zero byte
|
||||||
|
for header_length < data.len && data[header_length] != 0x00 {
|
||||||
|
header_length++
|
||||||
|
}
|
||||||
|
header_length++
|
||||||
|
}
|
||||||
|
if data[4] & 0b0000_0010 > 0 { // FHCRC, flag header crc
|
||||||
|
if header_length + 12 > data.len {
|
||||||
|
return error('data too short')
|
||||||
|
}
|
||||||
|
checksum_header := crc32.sum(data[..header_length])
|
||||||
|
checksum_header_expected := (u32(data[header_length]) << 24) | (u32(data[header_length + 1]) << 16) | (u32(data[
|
||||||
|
header_length + 2]) << 8) | data[header_length + 3]
|
||||||
|
if params.verify_header_checksum && checksum_header != checksum_header_expected {
|
||||||
|
return error('header checksum verification failed')
|
||||||
|
}
|
||||||
|
header_length += 4
|
||||||
|
}
|
||||||
|
if header_length + 8 > data.len {
|
||||||
|
return error('data too short')
|
||||||
|
}
|
||||||
|
|
||||||
|
decompressed := compress.decompress(data[header_length..data.len - 8], 0)?
|
||||||
|
length_expected := (u32(data[data.len - 4]) << 24) | (u32(data[data.len - 3]) << 16) | (u32(data[data.len - 2]) << 8) | data[data.len - 1]
|
||||||
|
if params.verify_length && decompressed.len != length_expected {
|
||||||
|
return error('length verification failed, got $decompressed.len, expected $length_expected')
|
||||||
|
}
|
||||||
|
checksum := crc32.sum(decompressed)
|
||||||
|
checksum_expected := (u32(data[data.len - 8]) << 24) | (u32(data[data.len - 7]) << 16) | (u32(data[data.len - 6]) << 8) | data[data.len - 5]
|
||||||
|
if params.verify_checksum && checksum != checksum_expected {
|
||||||
|
return error('checksum verification failed')
|
||||||
|
}
|
||||||
|
return decompressed
|
||||||
|
}
|
|
@ -0,0 +1,134 @@
|
||||||
|
module gzip
|
||||||
|
|
||||||
|
import hash.crc32
|
||||||
|
|
||||||
|
fn test_gzip() ? {
|
||||||
|
uncompressed := 'Hello world!'
|
||||||
|
compressed := compress(uncompressed.bytes())?
|
||||||
|
decompressed := decompress(compressed)?
|
||||||
|
assert decompressed == uncompressed.bytes()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn assert_decompress_error(data []u8, reason string) ? {
|
||||||
|
decompress(data) or {
|
||||||
|
assert err.msg() == reason
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return error('did not error')
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_gzip_invalid_too_short() ? {
|
||||||
|
assert_decompress_error([]u8{}, 'data is too short, not gzip compressed?')?
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_gzip_invalid_magic_numbers() ? {
|
||||||
|
assert_decompress_error([]u8{len: 100}, 'wrong magic numbers, not gzip compressed?')?
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_gzip_invalid_compression() ? {
|
||||||
|
mut data := []u8{len: 100}
|
||||||
|
data[0] = 0x1f
|
||||||
|
data[1] = 0x8b
|
||||||
|
assert_decompress_error(data, 'gzip data is not compressed with DEFLATE')?
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_gzip_with_ftext() ? {
|
||||||
|
uncompressed := 'Hello world!'
|
||||||
|
mut compressed := compress(uncompressed.bytes())?
|
||||||
|
compressed[4] |= 0b0000_0001 // FTEXT
|
||||||
|
decompressed := decompress(compressed)?
|
||||||
|
assert decompressed == uncompressed.bytes()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_gzip_with_fname() ? {
|
||||||
|
uncompressed := 'Hello world!'
|
||||||
|
mut compressed := compress(uncompressed.bytes())?
|
||||||
|
compressed[4] |= 0b0000_1000
|
||||||
|
compressed.insert(10, `h`)
|
||||||
|
compressed.insert(11, `i`)
|
||||||
|
compressed.insert(12, 0x00)
|
||||||
|
decompressed := decompress(compressed)?
|
||||||
|
assert decompressed == uncompressed.bytes()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_gzip_with_fcomment() ? {
|
||||||
|
uncompressed := 'Hello world!'
|
||||||
|
mut compressed := compress(uncompressed.bytes())?
|
||||||
|
compressed[4] |= 0b0001_0000
|
||||||
|
compressed.insert(10, `h`)
|
||||||
|
compressed.insert(11, `i`)
|
||||||
|
compressed.insert(12, 0x00)
|
||||||
|
decompressed := decompress(compressed)?
|
||||||
|
assert decompressed == uncompressed.bytes()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_gzip_with_fname_fcomment() ? {
|
||||||
|
uncompressed := 'Hello world!'
|
||||||
|
mut compressed := compress(uncompressed.bytes())?
|
||||||
|
compressed[4] |= 0b0001_1000
|
||||||
|
compressed.insert(10, `h`)
|
||||||
|
compressed.insert(11, `i`)
|
||||||
|
compressed.insert(12, 0x00)
|
||||||
|
compressed.insert(10, `h`)
|
||||||
|
compressed.insert(11, `i`)
|
||||||
|
compressed.insert(12, 0x00)
|
||||||
|
decompressed := decompress(compressed)?
|
||||||
|
assert decompressed == uncompressed.bytes()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_gzip_with_fextra() ? {
|
||||||
|
uncompressed := 'Hello world!'
|
||||||
|
mut compressed := compress(uncompressed.bytes())?
|
||||||
|
compressed[4] |= 0b0000_0100
|
||||||
|
compressed.insert(10, 2)
|
||||||
|
compressed.insert(11, `h`)
|
||||||
|
compressed.insert(12, `i`)
|
||||||
|
decompressed := decompress(compressed)?
|
||||||
|
assert decompressed == uncompressed.bytes()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_gzip_with_hcrc() ? {
|
||||||
|
uncompressed := 'Hello world!'
|
||||||
|
mut compressed := compress(uncompressed.bytes())?
|
||||||
|
compressed[4] |= 0b0000_0010
|
||||||
|
checksum := crc32.sum(compressed[..10])
|
||||||
|
compressed.insert(10, u8(checksum >> 24))
|
||||||
|
compressed.insert(11, u8(checksum >> 16))
|
||||||
|
compressed.insert(12, u8(checksum >> 8))
|
||||||
|
compressed.insert(13, u8(checksum))
|
||||||
|
decompressed := decompress(compressed)?
|
||||||
|
assert decompressed == uncompressed.bytes()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_gzip_with_invalid_hcrc() ? {
|
||||||
|
uncompressed := 'Hello world!'
|
||||||
|
mut compressed := compress(uncompressed.bytes())?
|
||||||
|
compressed[4] |= 0b0000_0010
|
||||||
|
checksum := crc32.sum(compressed[..10])
|
||||||
|
compressed.insert(10, u8(checksum >> 24))
|
||||||
|
compressed.insert(11, u8(checksum >> 16))
|
||||||
|
compressed.insert(12, u8(checksum >> 8))
|
||||||
|
compressed.insert(13, u8(checksum + 1))
|
||||||
|
assert_decompress_error(compressed, 'header checksum verification failed')?
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_gzip_with_invalid_checksum() ? {
|
||||||
|
uncompressed := 'Hello world!'
|
||||||
|
mut compressed := compress(uncompressed.bytes())?
|
||||||
|
compressed[compressed.len - 5] += 1
|
||||||
|
assert_decompress_error(compressed, 'checksum verification failed')?
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_gzip_with_invalid_length() ? {
|
||||||
|
uncompressed := 'Hello world!'
|
||||||
|
mut compressed := compress(uncompressed.bytes())?
|
||||||
|
compressed[compressed.len - 1] += 1
|
||||||
|
assert_decompress_error(compressed, 'length verification failed, got 12, expected 13')?
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_gzip_with_invalid_flags() ? {
|
||||||
|
uncompressed := 'Hello world!'
|
||||||
|
mut compressed := compress(uncompressed.bytes())?
|
||||||
|
compressed[4] |= 0b1000_0000
|
||||||
|
assert_decompress_error(compressed, 'reserved flags are set, unsupported field detected')?
|
||||||
|
}
|
|
@ -1,60 +1,17 @@
|
||||||
module zlib
|
module zlib
|
||||||
|
|
||||||
#flag -I @VEXEROOT/thirdparty/zip
|
import compress
|
||||||
#include "miniz.h"
|
|
||||||
|
|
||||||
pub const max_size = u64(1 << 31)
|
|
||||||
|
|
||||||
fn C.tdefl_compress_mem_to_heap(source_buf voidptr, source_buf_len usize, out_len &usize, flags int) voidptr
|
|
||||||
fn C.tinfl_decompress_mem_to_heap(source_buf voidptr, source_buf_len usize, out_len &usize, flags int) voidptr
|
|
||||||
|
|
||||||
// compresses an array of bytes using zlib and returns the compressed bytes in a new array
|
// compresses an array of bytes using zlib and returns the compressed bytes in a new array
|
||||||
// Example: compressed := zlib.compress(b)?
|
// Example: compressed := zlib.compress(b)?
|
||||||
[manualfree]
|
|
||||||
pub fn compress(data []u8) ?[]u8 {
|
pub fn compress(data []u8) ?[]u8 {
|
||||||
if u64(data.len) > zlib.max_size {
|
|
||||||
return error('data too large ($data.len > $zlib.max_size)')
|
|
||||||
}
|
|
||||||
mut out_len := usize(0)
|
|
||||||
|
|
||||||
// flags = TDEFL_WRITE_ZLIB_HEADER (0x01000)
|
// flags = TDEFL_WRITE_ZLIB_HEADER (0x01000)
|
||||||
address := C.tdefl_compress_mem_to_heap(data.data, data.len, &out_len, 0x01000)
|
return compress.compress(data, 0x01000)
|
||||||
if address == 0 {
|
|
||||||
return error('compression failed')
|
|
||||||
}
|
|
||||||
if u64(out_len) > zlib.max_size {
|
|
||||||
return error('compressed data is too large ($out_len > $zlib.max_size)')
|
|
||||||
}
|
|
||||||
compressed := unsafe {
|
|
||||||
address.vbytes(int(out_len))
|
|
||||||
}
|
|
||||||
copy := compressed.clone()
|
|
||||||
unsafe {
|
|
||||||
free(address)
|
|
||||||
}
|
|
||||||
return copy
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// decompresses an array of bytes using zlib and returns the decompressed bytes in a new array
|
// decompresses an array of bytes using zlib and returns the decompressed bytes in a new array
|
||||||
// Example: decompressed := zlib.decompress(b)?
|
// Example: decompressed := zlib.decompress(b)?
|
||||||
[manualfree]
|
|
||||||
pub fn decompress(data []u8) ?[]u8 {
|
pub fn decompress(data []u8) ?[]u8 {
|
||||||
mut out_len := usize(0)
|
|
||||||
|
|
||||||
// flags = TINFL_FLAG_PARSE_ZLIB_HEADER (0x1)
|
// flags = TINFL_FLAG_PARSE_ZLIB_HEADER (0x1)
|
||||||
address := C.tinfl_decompress_mem_to_heap(data.data, data.len, &out_len, 0x1)
|
return compress.decompress(data, 0x1)
|
||||||
if address == 0 {
|
|
||||||
return error('decompression failed')
|
|
||||||
}
|
|
||||||
if u64(out_len) > zlib.max_size {
|
|
||||||
return error('decompressed data is too large ($out_len > $zlib.max_size)')
|
|
||||||
}
|
|
||||||
decompressed := unsafe {
|
|
||||||
address.vbytes(int(out_len))
|
|
||||||
}
|
|
||||||
copy := decompressed.clone()
|
|
||||||
unsafe {
|
|
||||||
free(address)
|
|
||||||
}
|
|
||||||
return copy
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,8 +9,14 @@
|
||||||
module md5
|
module md5
|
||||||
|
|
||||||
import math.bits
|
import math.bits
|
||||||
import encoding.binary
|
|
||||||
|
|
||||||
|
[direct_array_access; inline]
|
||||||
|
fn get_le_u32(b []u8, start int) u32 {
|
||||||
|
return u32(b[start]) | (u32(b[1 + start]) << u32(8)) | (u32(b[2 + start]) << u32(16)) | (u32(b[
|
||||||
|
3 + start]) << u32(24))
|
||||||
|
}
|
||||||
|
|
||||||
|
[direct_array_access]
|
||||||
fn block_generic(mut dig Digest, p []u8) {
|
fn block_generic(mut dig Digest, p []u8) {
|
||||||
// load state
|
// load state
|
||||||
mut a := dig.s[0]
|
mut a := dig.s[0]
|
||||||
|
@ -19,8 +25,6 @@ fn block_generic(mut dig Digest, p []u8) {
|
||||||
mut d := dig.s[3]
|
mut d := dig.s[3]
|
||||||
|
|
||||||
for i := 0; i <= p.len - block_size; i += block_size {
|
for i := 0; i <= p.len - block_size; i += block_size {
|
||||||
mut q := p[i..]
|
|
||||||
q = q[..block_size]
|
|
||||||
// save current state
|
// save current state
|
||||||
aa := a
|
aa := a
|
||||||
bb := b
|
bb := b
|
||||||
|
@ -28,22 +32,22 @@ fn block_generic(mut dig Digest, p []u8) {
|
||||||
dd := d
|
dd := d
|
||||||
|
|
||||||
// load input block
|
// load input block
|
||||||
x0 := binary.little_endian_u32(q[4 * 0x0..])
|
x0 := get_le_u32(p, 4 * 0x0 + i)
|
||||||
x1 := binary.little_endian_u32(q[4 * 0x1..])
|
x1 := get_le_u32(p, 4 * 0x1 + i)
|
||||||
x2 := binary.little_endian_u32(q[4 * 0x2..])
|
x2 := get_le_u32(p, 4 * 0x2 + i)
|
||||||
x3 := binary.little_endian_u32(q[4 * 0x3..])
|
x3 := get_le_u32(p, 4 * 0x3 + i)
|
||||||
x4 := binary.little_endian_u32(q[4 * 0x4..])
|
x4 := get_le_u32(p, 4 * 0x4 + i)
|
||||||
x5 := binary.little_endian_u32(q[4 * 0x5..])
|
x5 := get_le_u32(p, 4 * 0x5 + i)
|
||||||
x6 := binary.little_endian_u32(q[4 * 0x6..])
|
x6 := get_le_u32(p, 4 * 0x6 + i)
|
||||||
x7 := binary.little_endian_u32(q[4 * 0x7..])
|
x7 := get_le_u32(p, 4 * 0x7 + i)
|
||||||
x8 := binary.little_endian_u32(q[4 * 0x8..])
|
x8 := get_le_u32(p, 4 * 0x8 + i)
|
||||||
x9 := binary.little_endian_u32(q[4 * 0x9..])
|
x9 := get_le_u32(p, 4 * 0x9 + i)
|
||||||
xa := binary.little_endian_u32(q[4 * 0xa..])
|
xa := get_le_u32(p, 4 * 0xa + i)
|
||||||
xb := binary.little_endian_u32(q[4 * 0xb..])
|
xb := get_le_u32(p, 4 * 0xb + i)
|
||||||
xc := binary.little_endian_u32(q[4 * 0xc..])
|
xc := get_le_u32(p, 4 * 0xc + i)
|
||||||
xd := binary.little_endian_u32(q[4 * 0xd..])
|
xd := get_le_u32(p, 4 * 0xd + i)
|
||||||
xe := binary.little_endian_u32(q[4 * 0xe..])
|
xe := get_le_u32(p, 4 * 0xe + i)
|
||||||
xf := binary.little_endian_u32(q[4 * 0xf..])
|
xf := get_le_u32(p, 4 * 0xf + i)
|
||||||
|
|
||||||
// round 1
|
// round 1
|
||||||
a = b + bits.rotate_left_32((((c ^ d) & b) ^ d) + a + x0 + u32(0xd76aa478), 7)
|
a = b + bits.rotate_left_32((((c ^ d) & b) ^ d) + a + x0 + u32(0xd76aa478), 7)
|
||||||
|
|
|
@ -76,13 +76,13 @@ pub fn (mut bst BSTree<T>) insert(value T) bool {
|
||||||
// insert_helper walks the tree and inserts the given node.
|
// insert_helper walks the tree and inserts the given node.
|
||||||
fn (mut bst BSTree<T>) insert_helper(mut node BSTreeNode<T>, value T) bool {
|
fn (mut bst BSTree<T>) insert_helper(mut node BSTreeNode<T>, value T) bool {
|
||||||
if node.value < value {
|
if node.value < value {
|
||||||
if node.right != 0 && node.right.is_init {
|
if unsafe { node.right != 0 } && node.right.is_init {
|
||||||
return bst.insert_helper(mut node.right, value)
|
return bst.insert_helper(mut node.right, value)
|
||||||
}
|
}
|
||||||
node.right = new_node(node, value)
|
node.right = new_node(node, value)
|
||||||
return true
|
return true
|
||||||
} else if node.value > value {
|
} else if node.value > value {
|
||||||
if node.left != 0 && node.left.is_init {
|
if unsafe { node.left != 0 } && node.left.is_init {
|
||||||
return bst.insert_helper(mut node.left, value)
|
return bst.insert_helper(mut node.left, value)
|
||||||
}
|
}
|
||||||
node.left = new_node(node, value)
|
node.left = new_node(node, value)
|
||||||
|
@ -99,7 +99,7 @@ pub fn (bst &BSTree<T>) contains(value T) bool {
|
||||||
// contains_helper is a helper function to walk the tree, and return
|
// contains_helper is a helper function to walk the tree, and return
|
||||||
// the absence or presence of the `value`.
|
// the absence or presence of the `value`.
|
||||||
fn (bst &BSTree<T>) contains_helper(node &BSTreeNode<T>, value T) bool {
|
fn (bst &BSTree<T>) contains_helper(node &BSTreeNode<T>, value T) bool {
|
||||||
if node == 0 || !node.is_init {
|
if unsafe { node == 0 } || !node.is_init {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if node.value < value {
|
if node.value < value {
|
||||||
|
@ -124,12 +124,12 @@ fn (mut bst BSTree<T>) remove_helper(mut node BSTreeNode<T>, value T, left bool)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if node.value == value {
|
if node.value == value {
|
||||||
if node.left != 0 && node.left.is_init {
|
if unsafe { node.left != 0 } && node.left.is_init {
|
||||||
// In order to remove the element we need to bring up as parent the max of the
|
// In order to remove the element we need to bring up as parent the max of the
|
||||||
// left sub-tree.
|
// left sub-tree.
|
||||||
mut max_node := bst.get_max_from_right(node.left)
|
mut max_node := bst.get_max_from_right(node.left)
|
||||||
node.bind(mut max_node, true)
|
node.bind(mut max_node, true)
|
||||||
} else if node.right != 0 && node.right.is_init {
|
} else if unsafe { node.right != 0 } && node.right.is_init {
|
||||||
// Bring up the element with the minimum value in the right sub-tree.
|
// Bring up the element with the minimum value in the right sub-tree.
|
||||||
mut min_node := bst.get_min_from_left(node.right)
|
mut min_node := bst.get_min_from_left(node.right)
|
||||||
node.bind(mut min_node, false)
|
node.bind(mut min_node, false)
|
||||||
|
@ -153,11 +153,11 @@ fn (mut bst BSTree<T>) remove_helper(mut node BSTreeNode<T>, value T, left bool)
|
||||||
|
|
||||||
// get_max_from_right returns the max element of the BST following the right branch.
|
// get_max_from_right returns the max element of the BST following the right branch.
|
||||||
fn (bst &BSTree<T>) get_max_from_right(node &BSTreeNode<T>) &BSTreeNode<T> {
|
fn (bst &BSTree<T>) get_max_from_right(node &BSTreeNode<T>) &BSTreeNode<T> {
|
||||||
if node == 0 {
|
if unsafe { node == 0 } {
|
||||||
return new_none_node<T>(false)
|
return new_none_node<T>(false)
|
||||||
}
|
}
|
||||||
right_node := node.right
|
right_node := node.right
|
||||||
if right_node == 0 || !right_node.is_init {
|
if unsafe { right_node == 0 } || !right_node.is_init {
|
||||||
return node
|
return node
|
||||||
}
|
}
|
||||||
return bst.get_max_from_right(right_node)
|
return bst.get_max_from_right(right_node)
|
||||||
|
@ -165,11 +165,11 @@ fn (bst &BSTree<T>) get_max_from_right(node &BSTreeNode<T>) &BSTreeNode<T> {
|
||||||
|
|
||||||
// get_min_from_left returns the min element of the BST by following the left branch.
|
// get_min_from_left returns the min element of the BST by following the left branch.
|
||||||
fn (bst &BSTree<T>) get_min_from_left(node &BSTreeNode<T>) &BSTreeNode<T> {
|
fn (bst &BSTree<T>) get_min_from_left(node &BSTreeNode<T>) &BSTreeNode<T> {
|
||||||
if node == 0 {
|
if unsafe { node == 0 } {
|
||||||
return new_none_node<T>(false)
|
return new_none_node<T>(false)
|
||||||
}
|
}
|
||||||
left_node := node.left
|
left_node := node.left
|
||||||
if left_node == 0 || !left_node.is_init {
|
if unsafe { left_node == 0 } || !left_node.is_init {
|
||||||
return node
|
return node
|
||||||
}
|
}
|
||||||
return bst.get_min_from_left(left_node)
|
return bst.get_min_from_left(left_node)
|
||||||
|
@ -177,7 +177,7 @@ fn (bst &BSTree<T>) get_min_from_left(node &BSTreeNode<T>) &BSTreeNode<T> {
|
||||||
|
|
||||||
// is_empty checks if the BST is empty
|
// is_empty checks if the BST is empty
|
||||||
pub fn (bst &BSTree<T>) is_empty() bool {
|
pub fn (bst &BSTree<T>) is_empty() bool {
|
||||||
return bst.root == 0
|
return unsafe { bst.root == 0 }
|
||||||
}
|
}
|
||||||
|
|
||||||
// in_order_traversal traverses the BST in order, and returns the result as an array.
|
// in_order_traversal traverses the BST in order, and returns the result as an array.
|
||||||
|
@ -189,7 +189,7 @@ pub fn (bst &BSTree<T>) in_order_traversal() []T {
|
||||||
|
|
||||||
// in_order_traversal_helper helps traverse the BST, and accumulates the result in the `result` array.
|
// in_order_traversal_helper helps traverse the BST, and accumulates the result in the `result` array.
|
||||||
fn (bst &BSTree<T>) in_order_traversal_helper(node &BSTreeNode<T>, mut result []T) {
|
fn (bst &BSTree<T>) in_order_traversal_helper(node &BSTreeNode<T>, mut result []T) {
|
||||||
if node == 0 || !node.is_init {
|
if unsafe { node == 0 } || !node.is_init {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
bst.in_order_traversal_helper(node.left, mut result)
|
bst.in_order_traversal_helper(node.left, mut result)
|
||||||
|
@ -207,7 +207,7 @@ pub fn (bst &BSTree<T>) post_order_traversal() []T {
|
||||||
// post_order_traversal_helper is a helper function that traverses the BST in post order,
|
// post_order_traversal_helper is a helper function that traverses the BST in post order,
|
||||||
// accumulating the result in an array.
|
// accumulating the result in an array.
|
||||||
fn (bst &BSTree<T>) post_order_traversal_helper(node &BSTreeNode<T>, mut result []T) {
|
fn (bst &BSTree<T>) post_order_traversal_helper(node &BSTreeNode<T>, mut result []T) {
|
||||||
if node == 0 || !node.is_init {
|
if unsafe { node == 0 } || !node.is_init {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -226,7 +226,7 @@ pub fn (bst &BSTree<T>) pre_order_traversal() []T {
|
||||||
// pre_order_traversal_helper is a helper function to traverse the BST
|
// pre_order_traversal_helper is a helper function to traverse the BST
|
||||||
// in pre order and accumulates the results in an array.
|
// in pre order and accumulates the results in an array.
|
||||||
fn (bst &BSTree<T>) pre_order_traversal_helper(node &BSTreeNode<T>, mut result []T) {
|
fn (bst &BSTree<T>) pre_order_traversal_helper(node &BSTreeNode<T>, mut result []T) {
|
||||||
if node == 0 || !node.is_init {
|
if unsafe { node == 0 } || !node.is_init {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
result << node.value
|
result << node.value
|
||||||
|
@ -236,7 +236,7 @@ fn (bst &BSTree<T>) pre_order_traversal_helper(node &BSTreeNode<T>, mut result [
|
||||||
|
|
||||||
// get_node is a helper method to ge the internal rapresentation of the node with the `value`.
|
// get_node is a helper method to ge the internal rapresentation of the node with the `value`.
|
||||||
fn (bst &BSTree<T>) get_node(node &BSTreeNode<T>, value T) &BSTreeNode<T> {
|
fn (bst &BSTree<T>) get_node(node &BSTreeNode<T>, value T) &BSTreeNode<T> {
|
||||||
if node == 0 || !node.is_init {
|
if unsafe { node == 0 } || !node.is_init {
|
||||||
return new_none_node<T>(false)
|
return new_none_node<T>(false)
|
||||||
}
|
}
|
||||||
if node.value == value {
|
if node.value == value {
|
||||||
|
|
|
@ -251,7 +251,7 @@ pub fn (mut list DoublyLinkedList<T>) delete(idx int) {
|
||||||
pub fn (list DoublyLinkedList<T>) str() string {
|
pub fn (list DoublyLinkedList<T>) str() string {
|
||||||
mut result_array := []T{}
|
mut result_array := []T{}
|
||||||
mut node := list.head
|
mut node := list.head
|
||||||
for node != 0 {
|
for unsafe { node != 0 } {
|
||||||
result_array << node.data
|
result_array << node.data
|
||||||
node = node.next
|
node = node.next
|
||||||
}
|
}
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue