Compare commits
40 Commits
b10cf3e0f4
...
12ec3b9d53
Author | SHA1 | Date |
---|---|---|
WoodyAtHome | 12ec3b9d53 | |
Alexander Medvednikov | d118af0dac | |
playX | 15b84567ec | |
Delyan Angelov | ec5559a379 | |
Delyan Angelov | 972c1855bc | |
yuyi | 57055a9c63 | |
Delyan Angelov | 1064085656 | |
Delyan Angelov | e814497831 | |
yuyi | cdfdf19697 | |
Larpon | f1b35aff22 | |
yuyi | 9eba367a46 | |
spaceface | 4179e1cac2 | |
WoodyAtHome | 9e179ab11f | |
Delyan Angelov | ff02e5667b | |
Delyan Angelov | baf72a7459 | |
Ben | 6a87650935 | |
yuyi | 689f3f7128 | |
Larpon | cf2f34cf3f | |
Jah-On | cd43bae0b4 | |
WoodyAtHome | 8ce7860e8a | |
spaceface | ec2346d45c | |
Delyan Angelov | a133f038bd | |
crthpl | 82018034ef | |
David 'Epper' Marshall | fd17b62ea6 | |
Delyan Angelov | 771ec47a04 | |
Delyan Angelov | 3f2bb98152 | |
Delyan Angelov | 4f1f764485 | |
Larpon | 7492907e77 | |
David 'Epper' Marshall | 153b095518 | |
Delyan Angelov | 46ee0ff572 | |
Delyan Angelov | 1f6849e89c | |
yuyi | f983dd8a95 | |
Alexander Medvednikov | 5a427907d5 | |
Alexander Medvednikov | 58c54a5c05 | |
Daniel Däschle | c6b0ebe06f | |
JalonSolov | b2f520028f | |
j. redhead | 9abaadb690 | |
Delyan Angelov | 638b267e4e | |
Delyan Angelov | b74461f255 | |
Delyan Angelov | d1b8a67bca |
|
@ -33,6 +33,7 @@ jobs:
|
||||||
run: |
|
run: |
|
||||||
echo $VFLAGS
|
echo $VFLAGS
|
||||||
make
|
make
|
||||||
|
./v test-cleancode
|
||||||
./v -d debug_malloc -d debug_realloc -o v cmd/v
|
./v -d debug_malloc -d debug_realloc -o v cmd/v
|
||||||
./v -cg -cstrict -o v cmd/v
|
./v -cg -cstrict -o v cmd/v
|
||||||
# Test v -realloc arena allocation
|
# Test v -realloc arena allocation
|
||||||
|
@ -609,40 +610,40 @@ jobs:
|
||||||
## 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
|
||||||
|
|
||||||
|
|
||||||
# ubuntu-autofree-selfcompile:
|
# ubuntu-autofree-selfcompile:
|
||||||
# runs-on: ubuntu-20.04
|
# runs-on: ubuntu-20.04
|
||||||
# timeout-minutes: 121
|
# timeout-minutes: 121
|
||||||
# env:
|
# env:
|
||||||
# VFLAGS: -cc gcc
|
# VFLAGS: -cc gcc
|
||||||
# steps:
|
# steps:
|
||||||
# - uses: actions/checkout@v2
|
# - uses: actions/checkout@v2
|
||||||
# - name: Build V
|
# - name: Build V
|
||||||
# run: make -j4
|
# run: make -j4
|
||||||
# - name: V self compilation with -autofree
|
# - name: V self compilation with -autofree
|
||||||
# run: ./v -o v2 -autofree cmd/v && ./v2 -o v3 -autofree cmd/v && ./v3 -o v4 -autofree cmd/v
|
# run: ./v -o v2 -autofree cmd/v && ./v2 -o v3 -autofree cmd/v && ./v3 -o v4 -autofree cmd/v
|
||||||
|
|
||||||
|
|
||||||
# ubuntu-musl:
|
# ubuntu-musl:
|
||||||
# runs-on: ubuntu-20.04
|
# runs-on: ubuntu-20.04
|
||||||
# timeout-minutes: 121
|
# timeout-minutes: 121
|
||||||
# env:
|
# env:
|
||||||
# VFLAGS: -cc musl-gcc
|
# VFLAGS: -cc musl-gcc
|
||||||
# V_CI_MUSL: 1
|
# V_CI_MUSL: 1
|
||||||
# steps:
|
# steps:
|
||||||
# - uses: actions/checkout@v2
|
# - uses: actions/checkout@v2
|
||||||
# - uses: actions/setup-node@v1
|
# - uses: actions/setup-node@v1
|
||||||
# with:
|
# with:
|
||||||
# node-version: 12.x
|
# node-version: 12.x
|
||||||
# - name: Install dependencies
|
# - name: Install dependencies
|
||||||
# run: |
|
# run: |
|
||||||
# sudo apt-get install --quiet -y musl musl-tools libssl-dev sqlite3 libsqlite3-dev valgrind
|
# sudo apt-get install --quiet -y musl musl-tools libssl-dev sqlite3 libsqlite3-dev valgrind
|
||||||
# - name: Build v
|
# - name: Build v
|
||||||
# run: echo $VFLAGS && make -j4 && ./v -cg -o v cmd/v
|
# run: echo $VFLAGS && make -j4 && ./v -cg -o v cmd/v
|
||||||
# # - name: Test v binaries
|
# # - name: Test v binaries
|
||||||
# # run: ./v build-vbinaries
|
# # run: ./v build-vbinaries
|
||||||
# ## - name: Test v->js
|
# ## - name: Test v->js
|
||||||
# ## run: ./v -o hi.js examples/hello_v_js.v && node hi.js
|
# ## run: ./v -o hi.js examples/hello_v_js.v && node hi.js
|
||||||
# - name: quick debug
|
# - name: quick debug
|
||||||
# run: ./v -stats vlib/strconv/format_test.v
|
# run: ./v -stats vlib/strconv/format_test.v
|
||||||
# - name: Self tests
|
# - name: Self tests
|
||||||
# run: ./v test-self
|
# run: ./v test-self
|
||||||
|
|
|
@ -16,7 +16,7 @@ on:
|
||||||
paths:
|
paths:
|
||||||
- '!**'
|
- '!**'
|
||||||
- 'cmd/tools/vtest*'
|
- 'cmd/tools/vtest*'
|
||||||
- 'cmd/tools/builders/**.v'
|
- 'cmd/tools/builders/**.v'
|
||||||
- 'vlib/builtin/**.v'
|
- 'vlib/builtin/**.v'
|
||||||
- 'vlib/strconv/**.v'
|
- 'vlib/strconv/**.v'
|
||||||
- 'vlib/strings/**.v'
|
- 'vlib/strings/**.v'
|
||||||
|
@ -43,7 +43,7 @@ on:
|
||||||
paths:
|
paths:
|
||||||
- '!**'
|
- '!**'
|
||||||
- 'cmd/tools/vtest*'
|
- 'cmd/tools/vtest*'
|
||||||
- 'cmd/tools/builders/**.v'
|
- 'cmd/tools/builders/**.v'
|
||||||
- 'vlib/builtin/**.v'
|
- 'vlib/builtin/**.v'
|
||||||
- 'vlib/strconv/**.v'
|
- 'vlib/strconv/**.v'
|
||||||
- 'vlib/strings/**.v'
|
- 'vlib/strings/**.v'
|
||||||
|
@ -91,7 +91,9 @@ jobs:
|
||||||
sudo apt-get install --quiet -y libfreetype6-dev libxi-dev libxcursor-dev libgl-dev
|
sudo apt-get install --quiet -y libfreetype6-dev libxi-dev libxcursor-dev libgl-dev
|
||||||
sudo apt-get install clang
|
sudo apt-get install clang
|
||||||
- name: Build V
|
- name: Build V
|
||||||
run: make -j4 && ./v -cg -cstrict -o v cmd/v
|
run: make && ./v -cg -cstrict -o v cmd/v
|
||||||
|
- name: Ensure code is well formatted
|
||||||
|
run: ./v test-cleancode
|
||||||
- name: Self tests (-fsanitize=undefined)
|
- name: Self tests (-fsanitize=undefined)
|
||||||
run: ./v -cflags "-fsanitize=undefined" -o v2 cmd/v && ./v2 -cflags -fsanitize=undefined test-self
|
run: ./v -cflags "-fsanitize=undefined" -o v2 cmd/v && ./v2 -cflags -fsanitize=undefined test-self
|
||||||
- name: Build examples (V compiled with -fsanitize=undefined)
|
- name: Build examples (V compiled with -fsanitize=undefined)
|
||||||
|
@ -115,7 +117,9 @@ jobs:
|
||||||
sudo apt-get install --quiet -y postgresql libpq-dev libssl-dev sqlite3 libsqlite3-dev valgrind
|
sudo apt-get install --quiet -y postgresql libpq-dev libssl-dev sqlite3 libsqlite3-dev valgrind
|
||||||
sudo apt-get install --quiet -y libfreetype6-dev libxi-dev libxcursor-dev libgl-dev
|
sudo apt-get install --quiet -y libfreetype6-dev libxi-dev libxcursor-dev libgl-dev
|
||||||
- name: Build V
|
- name: Build V
|
||||||
run: make -j4 && ./v -cg -cstrict -o v cmd/v
|
run: make && ./v -cg -cstrict -o v cmd/v
|
||||||
|
- name: Ensure code is well formatted
|
||||||
|
run: ./v test-cleancode
|
||||||
- name: Self tests (-fsanitize=undefined)
|
- name: Self tests (-fsanitize=undefined)
|
||||||
run: ./v -cflags "-fsanitize=undefined" -o v2 cmd/v && ./v2 -cflags -fsanitize=undefined test-self
|
run: ./v -cflags "-fsanitize=undefined" -o v2 cmd/v && ./v2 -cflags -fsanitize=undefined test-self
|
||||||
- name: Build examples (V compiled with -fsanitize=undefined)
|
- name: Build examples (V compiled with -fsanitize=undefined)
|
||||||
|
@ -140,7 +144,9 @@ jobs:
|
||||||
sudo apt-get install --quiet -y libfreetype6-dev libxi-dev libxcursor-dev libgl-dev
|
sudo apt-get install --quiet -y libfreetype6-dev libxi-dev libxcursor-dev libgl-dev
|
||||||
sudo apt-get install clang
|
sudo apt-get install clang
|
||||||
- name: Build V
|
- name: Build V
|
||||||
run: make -j4 && ./v -cg -cstrict -o v cmd/v
|
run: make && ./v -cg -cstrict -o v cmd/v
|
||||||
|
- name: Ensure code is well formatted
|
||||||
|
run: ./v test-cleancode
|
||||||
- name: Self tests (-fsanitize=address)
|
- name: Self tests (-fsanitize=address)
|
||||||
run: ASAN_OPTIONS=detect_leaks=0 ./v -cflags "-fsanitize=address,pointer-compare,pointer-subtract" test-self
|
run: ASAN_OPTIONS=detect_leaks=0 ./v -cflags "-fsanitize=address,pointer-compare,pointer-subtract" test-self
|
||||||
- name: Self tests (V compiled with -fsanitize=address)
|
- name: Self tests (V compiled with -fsanitize=address)
|
||||||
|
@ -168,6 +174,11 @@ jobs:
|
||||||
echo $VFLAGS
|
echo $VFLAGS
|
||||||
.\make.bat -msvc
|
.\make.bat -msvc
|
||||||
.\v.exe self
|
.\v.exe self
|
||||||
|
- name: Ensure code is well formatted
|
||||||
|
run: |
|
||||||
|
.\v.exe fmt -verify vlib/builtin/ vlib/v/scanner/ vlib/v/parser/ vlib/v/gen/
|
||||||
|
## TODO: check to see why `v test-cleancode` does not work with msvc on windows
|
||||||
|
|
||||||
## - name: Install dependencies
|
## - name: Install dependencies
|
||||||
## run: |
|
## run: |
|
||||||
## .\v.exe setup-freetype
|
## .\v.exe setup-freetype
|
||||||
|
@ -195,7 +206,9 @@ jobs:
|
||||||
sudo apt-get install --quiet -y libfreetype6-dev libxi-dev libxcursor-dev libgl-dev
|
sudo apt-get install --quiet -y libfreetype6-dev libxi-dev libxcursor-dev libgl-dev
|
||||||
sudo apt-get install clang
|
sudo apt-get install clang
|
||||||
- name: Build V
|
- name: Build V
|
||||||
run: make -j4 && ./v -cg -cstrict -o v cmd/v
|
run: make && ./v -cg -cstrict -o v cmd/v
|
||||||
|
- name: Ensure code is well formatted
|
||||||
|
run: ./v test-cleancode
|
||||||
- name: Self tests (-fsanitize=address)
|
- name: Self tests (-fsanitize=address)
|
||||||
run: ASAN_OPTIONS=detect_leaks=0 ./v -cflags -fsanitize=address test-self
|
run: ASAN_OPTIONS=detect_leaks=0 ./v -cflags -fsanitize=address test-self
|
||||||
- name: Self tests (V compiled with -fsanitize=address)
|
- name: Self tests (V compiled with -fsanitize=address)
|
||||||
|
@ -224,11 +237,14 @@ jobs:
|
||||||
sudo apt-get install --quiet -y libfreetype6-dev libxi-dev libxcursor-dev libgl-dev
|
sudo apt-get install --quiet -y libfreetype6-dev libxi-dev libxcursor-dev libgl-dev
|
||||||
sudo apt-get install clang
|
sudo apt-get install clang
|
||||||
- name: Build V
|
- name: Build V
|
||||||
run: make -j4 && ./v -cc clang -cg -cstrict -o v cmd/v
|
run: make && ./v -cc clang -cg -cstrict -o v cmd/v
|
||||||
|
- name: Ensure code is well formatted
|
||||||
|
run: ./v test-cleancode
|
||||||
- name: Self tests (-fsanitize=memory)
|
- name: Self tests (-fsanitize=memory)
|
||||||
run: ./v -cflags -fsanitize=memory test-self
|
run: ./v -cflags -fsanitize=memory test-self
|
||||||
- name: Self tests (V compiled with -fsanitize=memory)
|
- name: Self tests (V compiled with -fsanitize=memory)
|
||||||
run:
|
run: |
|
||||||
./v -cflags -fsanitize=memory -o v cmd/v && ./v -cc tcc test-self -msan-compiler
|
./v -cflags -fsanitize=memory -o v cmd/v
|
||||||
|
./v -cc tcc test-self -msan-compiler
|
||||||
- name: Build examples (V compiled with -fsanitize=memory)
|
- name: Build examples (V compiled with -fsanitize=memory)
|
||||||
run: ./v build-examples
|
run: ./v build-examples
|
||||||
|
|
|
@ -85,6 +85,7 @@ 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
|
||||||
|
@ -93,6 +94,7 @@ jobs:
|
||||||
run: ./v -autofree -o v2 cmd/v ## NB: this does not mean it runs, but at least keeps it from regressing
|
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
|
||||||
|
@ -146,117 +148,3 @@ jobs:
|
||||||
./v test-parser -S examples/regex_example_fuzz.v
|
./v test-parser -S examples/regex_example_fuzz.v
|
||||||
./v test-parser -S examples/2048/2048_fuzz.v
|
./v test-parser -S examples/2048/2048_fuzz.v
|
||||||
|
|
||||||
v-apps-compile:
|
|
||||||
runs-on: ubuntu-20.04
|
|
||||||
timeout-minutes: 121
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v2
|
|
||||||
- name: Build V
|
|
||||||
run: make && sudo ./v symlink
|
|
||||||
|
|
||||||
- name: Install dependencies
|
|
||||||
run: |
|
|
||||||
sudo apt-get update
|
|
||||||
sudo apt-get install --quiet -y libgc-dev
|
|
||||||
sudo apt-get install --quiet -y libsodium-dev libssl-dev sqlite3 libsqlite3-dev valgrind
|
|
||||||
sudo apt-get install --quiet -y libfreetype6-dev libxi-dev libxcursor-dev libgl-dev
|
|
||||||
sudo apt-get install --quiet -y xfonts-75dpi xfonts-base
|
|
||||||
|
|
||||||
## vls
|
|
||||||
- name: Clone VLS
|
|
||||||
run: git clone --depth 1 https://github.com/vlang/vls
|
|
||||||
- name: Build VLS
|
|
||||||
run: pushd vls; v cmd/vls ; popd
|
|
||||||
- name: Build VLS with -prod
|
|
||||||
run: pushd vls; v -prod cmd/vls; popd
|
|
||||||
- name: Build VLS with -gc boehm -skip-unused
|
|
||||||
run: pushd vls; v -gc boehm -skip-unused cmd/vls; popd
|
|
||||||
|
|
||||||
## vsl
|
|
||||||
- name: Clone VSL
|
|
||||||
run: git clone --depth 1 https://github.com/vlang/vsl ~/.vmodules/vsl
|
|
||||||
- name: Install dependencies
|
|
||||||
run: sudo apt-get install --quiet -y --no-install-recommends gfortran liblapacke-dev libopenblas-dev libgc-dev
|
|
||||||
- name: Execute Tests using Pure V Backend
|
|
||||||
run: ~/.vmodules/vsl/bin/test
|
|
||||||
- name: Execute Tests using Pure V Backend with Pure V Math
|
|
||||||
run: ~/.vmodules/vsl/bin/test --use-cblas
|
|
||||||
- name: Execute Tests using Pure V Backend and Garbage Collection enabled
|
|
||||||
run: ~/.vmodules/vsl/bin/test --use-gc boehm
|
|
||||||
- name: Execute Tests using Pure V Backend with Pure V Math and Garbage Collection enabled
|
|
||||||
run: ~/.vmodules/vsl/bin/test --use-cblas --use-gc boehm
|
|
||||||
|
|
||||||
## vtl
|
|
||||||
- name: Clone VTL
|
|
||||||
run: git clone --depth 1 https://github.com/vlang/vtl ~/.vmodules/vtl
|
|
||||||
- name: Install dependencies
|
|
||||||
run: sudo apt-get install --quiet -y --no-install-recommends gfortran liblapacke-dev libopenblas-dev libgc-dev
|
|
||||||
- name: Execute Tests using Pure V Backend
|
|
||||||
run: ~/.vmodules/vtl/bin/test
|
|
||||||
- name: Execute Tests using Pure V Backend with Pure V Math
|
|
||||||
run: ~/.vmodules/vtl/bin/test --use-cblas
|
|
||||||
- name: Execute Tests using Pure V Backend and Garbage Collection enabled
|
|
||||||
run: ~/.vmodules/vtl/bin/test --use-gc boehm
|
|
||||||
- name: Execute Tests using Pure V Backend with Pure V Math and Garbage Collection enabled
|
|
||||||
run: ~/.vmodules/vtl/bin/test --use-cblas --use-gc boehm
|
|
||||||
|
|
||||||
## vab
|
|
||||||
- name: Clone vab
|
|
||||||
run: git clone --depth 1 https://github.com/vlang/vab
|
|
||||||
- name: Build vab
|
|
||||||
run: cd vab; ../v ./vab.v ; cd ..
|
|
||||||
- name: Build vab with -gc boehm -skip-unused
|
|
||||||
run: cd vab; ../v -gc boehm -skip-unused ./vab.v ; cd ..
|
|
||||||
|
|
||||||
## gitly
|
|
||||||
- name: Install markdown
|
|
||||||
run: git clone https://github.com/vlang/markdown ~/.vmodules/markdown
|
|
||||||
- name: Build Gitly
|
|
||||||
run: |
|
|
||||||
git clone --depth 1 https://github.com/vlang/gitly
|
|
||||||
cd gitly
|
|
||||||
../v .
|
|
||||||
# ./gitly -ci_run
|
|
||||||
../v -autofree .
|
|
||||||
../v -o x tests/first_run.v
|
|
||||||
./x
|
|
||||||
cd ..
|
|
||||||
|
|
||||||
## libsodium
|
|
||||||
- name: Install libsodium-dev package
|
|
||||||
run: sudo apt-get install --quiet -y libsodium-dev
|
|
||||||
- name: Install the libsodium wrapper
|
|
||||||
run: git clone https://github.com/vlang/libsodium ~/.vmodules/libsodium
|
|
||||||
- name: Test libsodium
|
|
||||||
run: VJOBS=1 ./v -stats test ~/.vmodules/libsodium
|
|
||||||
|
|
||||||
|
|
||||||
## vex
|
|
||||||
- name: Install Vex dependencies
|
|
||||||
run: sudo apt-get install --quiet -y libsodium-dev libssl-dev sqlite3 libsqlite3-dev
|
|
||||||
- name: Install Vex
|
|
||||||
run: mkdir -p ~/.vmodules/nedpals; git clone https://github.com/nedpals/vex ~/.vmodules/nedpals/vex
|
|
||||||
- name: Compile all of the Vex examples
|
|
||||||
run: ./v should-compile-all ~/.vmodules/nedpals/vex/examples
|
|
||||||
- name: Compile the simple Vex example with -gc boehm -skip-unused
|
|
||||||
run: ./v -gc boehm -skip-unused ~/.vmodules/nedpals/vex/examples/simple_example.v
|
|
||||||
- name: Run Vex Tests
|
|
||||||
run: ./v test ~/.vmodules/nedpals/vex
|
|
||||||
|
|
||||||
## Go2V
|
|
||||||
- name: Clone & Build go2v
|
|
||||||
run: git clone --depth=1 https://github.com/vlang/go2v go2v/
|
|
||||||
- name: Build go2v
|
|
||||||
run: ./v go2v/
|
|
||||||
## - name: Run tests for go2v
|
|
||||||
## run: VJOBS=1 ./v -stats test go2v/
|
|
||||||
|
|
||||||
## vlang/pdf
|
|
||||||
- name: Clone & Build vlang/pdf
|
|
||||||
run: git clone --depth=1 https://github.com/vlang/pdf ~/.vmodules/pdf/
|
|
||||||
- name: PDF examples should compile
|
|
||||||
run: ./v should-compile-all ~/.vmodules/pdf/examples
|
|
||||||
|
|
||||||
## vpm modules
|
|
||||||
- name: Install UI through VPM
|
|
||||||
run: ./v install ui
|
|
||||||
|
|
|
@ -0,0 +1,145 @@
|
||||||
|
name: V Apps and Modules
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
paths-ignore:
|
||||||
|
- "**.md"
|
||||||
|
pull_request:
|
||||||
|
paths-ignore:
|
||||||
|
- "**.md"
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: build-other-${{ github.event.pull_request.number || github.sha }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
v-apps-compile:
|
||||||
|
runs-on: ubuntu-20.04
|
||||||
|
timeout-minutes: 121
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
- name: Build V
|
||||||
|
run: make && sudo ./v symlink
|
||||||
|
|
||||||
|
- name: Install dependencies
|
||||||
|
run: |
|
||||||
|
sudo apt-get update
|
||||||
|
sudo apt-get install --quiet -y libgc-dev
|
||||||
|
sudo apt-get install --quiet -y libsodium-dev libssl-dev sqlite3 libsqlite3-dev valgrind
|
||||||
|
sudo apt-get install --quiet -y libfreetype6-dev libxi-dev libxcursor-dev libgl-dev
|
||||||
|
sudo apt-get install --quiet -y xfonts-75dpi xfonts-base
|
||||||
|
|
||||||
|
- name: Install UI through VPM
|
||||||
|
continue-on-error: true
|
||||||
|
run: |
|
||||||
|
echo "Official VPM modules should be installable"
|
||||||
|
./v install ui
|
||||||
|
|
||||||
|
- name: Build V Language Server (VLS)
|
||||||
|
continue-on-error: true
|
||||||
|
run: |
|
||||||
|
echo "Clone VLS"
|
||||||
|
git clone --depth 1 https://github.com/vlang/vls
|
||||||
|
echo "Build VLS"
|
||||||
|
pushd vls; v cmd/vls ; popd
|
||||||
|
echo "Build VLS with -prod"
|
||||||
|
pushd vls; v -prod cmd/vls; popd
|
||||||
|
echo "Build VLS with -gc boehm -skip-unused"
|
||||||
|
pushd vls; v -gc boehm -skip-unused cmd/vls; popd
|
||||||
|
|
||||||
|
- name: Build VSL
|
||||||
|
continue-on-error: true
|
||||||
|
run: |
|
||||||
|
git clone --depth 1 https://github.com/vlang/vsl ~/.vmodules/vsl
|
||||||
|
sudo apt-get install --quiet -y --no-install-recommends gfortran liblapacke-dev libopenblas-dev libgc-dev
|
||||||
|
echo "Execute Tests using Pure V Backend"
|
||||||
|
~/.vmodules/vsl/bin/test
|
||||||
|
echo "Execute Tests using Pure V Backend with Pure V Math"
|
||||||
|
~/.vmodules/vsl/bin/test --use-cblas
|
||||||
|
echo "Execute Tests using Pure V Backend and Garbage Collection enabled"
|
||||||
|
~/.vmodules/vsl/bin/test --use-gc boehm
|
||||||
|
echo "Execute Tests using Pure V Backend with Pure V Math and Garbage Collection enabled"
|
||||||
|
~/.vmodules/vsl/bin/test --use-cblas --use-gc boehm
|
||||||
|
|
||||||
|
- name: Build VTL
|
||||||
|
continue-on-error: true
|
||||||
|
run: |
|
||||||
|
echo "Clone VTL"
|
||||||
|
git clone --depth 1 https://github.com/vlang/vtl ~/.vmodules/vtl
|
||||||
|
echo "Install dependencies"
|
||||||
|
sudo apt-get install --quiet -y --no-install-recommends gfortran liblapacke-dev libopenblas-dev libgc-dev
|
||||||
|
echo "Execute Tests using Pure V Backend"
|
||||||
|
~/.vmodules/vtl/bin/test
|
||||||
|
echo "Execute Tests using Pure V Backend with Pure V Math"
|
||||||
|
~/.vmodules/vtl/bin/test --use-cblas
|
||||||
|
echo "Execute Tests using Pure V Backend and Garbage Collection enabled"
|
||||||
|
~/.vmodules/vtl/bin/test --use-gc boehm
|
||||||
|
echo "Execute Tests using Pure V Backend with Pure V Math and Garbage Collection enabled"
|
||||||
|
~/.vmodules/vtl/bin/test --use-cblas --use-gc boehm
|
||||||
|
|
||||||
|
- name: Build VAB
|
||||||
|
continue-on-error: true
|
||||||
|
run: |
|
||||||
|
echo "Clone vab"
|
||||||
|
git clone --depth 1 https://github.com/vlang/vab
|
||||||
|
echo "Build vab"
|
||||||
|
cd vab; ../v ./vab.v ; cd ..
|
||||||
|
echo "Build vab with -gc boehm -skip-unused"
|
||||||
|
cd vab; ../v -gc boehm -skip-unused ./vab.v ; cd ..
|
||||||
|
|
||||||
|
- name: Build Gitly
|
||||||
|
continue-on-error: true
|
||||||
|
run: |
|
||||||
|
echo "Clone markdown"
|
||||||
|
git clone https://github.com/vlang/markdown ~/.vmodules/markdown
|
||||||
|
echo "Clone Gitly"
|
||||||
|
git clone --depth 1 https://github.com/vlang/gitly
|
||||||
|
cd gitly
|
||||||
|
echo "Build Gitly"
|
||||||
|
../v .
|
||||||
|
echo "Build Gitly with -autofree"
|
||||||
|
../v -autofree .
|
||||||
|
echo "Run first_run.v"
|
||||||
|
../v run tests/first_run.v
|
||||||
|
# ./gitly -ci_run
|
||||||
|
|
||||||
|
- name: Build libsodium
|
||||||
|
continue-on-error: true
|
||||||
|
run: |
|
||||||
|
echo "Install libsodium-dev package"
|
||||||
|
sudo apt-get install --quiet -y libsodium-dev
|
||||||
|
echo "Clone the libsodium wrapper"
|
||||||
|
git clone https://github.com/vlang/libsodium ~/.vmodules/libsodium
|
||||||
|
echo "Test libsodium"
|
||||||
|
VJOBS=1 ./v -stats test ~/.vmodules/libsodium
|
||||||
|
|
||||||
|
- name: Build VEX
|
||||||
|
continue-on-error: true
|
||||||
|
run: |
|
||||||
|
echo "Install Vex dependencies"
|
||||||
|
sudo apt-get install --quiet -y libsodium-dev libssl-dev sqlite3 libsqlite3-dev
|
||||||
|
echo "Clone Vex"
|
||||||
|
mkdir -p ~/.vmodules/nedpals; git clone https://github.com/nedpals/vex ~/.vmodules/nedpals/vex
|
||||||
|
echo "Compile all of the Vex examples"
|
||||||
|
./v should-compile-all ~/.vmodules/nedpals/vex/examples
|
||||||
|
echo "Compile the simple Vex example with -gc boehm -skip-unused"
|
||||||
|
./v -gc boehm -skip-unused ~/.vmodules/nedpals/vex/examples/simple_example.v
|
||||||
|
echo "Run Vex Tests"
|
||||||
|
./v test ~/.vmodules/nedpals/vex
|
||||||
|
|
||||||
|
- name: Build go2v
|
||||||
|
continue-on-error: true
|
||||||
|
run: |
|
||||||
|
echo "Clone go2v"
|
||||||
|
clone --depth=1 https://github.com/vlang/go2v go2v/
|
||||||
|
echo "Build go2v"
|
||||||
|
./v go2v/
|
||||||
|
## echo "Run tests for go2v"
|
||||||
|
## VJOBS=1 ./v -stats test go2v/
|
||||||
|
|
||||||
|
- name: Build vlang/pdf
|
||||||
|
continue-on-error: true
|
||||||
|
run: |
|
||||||
|
git clone --depth=1 https://github.com/vlang/pdf ~/.vmodules/pdf/
|
||||||
|
echo "PDF examples should compile"
|
||||||
|
./v should-compile-all ~/.vmodules/pdf/examples
|
|
@ -37,7 +37,6 @@ pub mut:
|
||||||
vroot string
|
vroot string
|
||||||
vtmp_dir string
|
vtmp_dir string
|
||||||
vargs string
|
vargs string
|
||||||
failed bool
|
|
||||||
fail_fast bool
|
fail_fast bool
|
||||||
benchmark benchmark.Benchmark
|
benchmark benchmark.Benchmark
|
||||||
rm_binaries bool = true
|
rm_binaries bool = true
|
||||||
|
@ -288,7 +287,7 @@ pub fn (mut ts TestSession) test() {
|
||||||
fn worker_trunner(mut p pool.PoolProcessor, idx int, thread_id int) voidptr {
|
fn worker_trunner(mut p pool.PoolProcessor, idx int, thread_id int) voidptr {
|
||||||
mut ts := &TestSession(p.get_shared_context())
|
mut ts := &TestSession(p.get_shared_context())
|
||||||
if ts.fail_fast {
|
if ts.fail_fast {
|
||||||
if ts.failed {
|
if ts.failed_cmds.len > 0 {
|
||||||
return pool.no_result
|
return pool.no_result
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -380,7 +379,6 @@ fn worker_trunner(mut p pool.PoolProcessor, idx int, thread_id int) voidptr {
|
||||||
goto test_passed_system
|
goto test_passed_system
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ts.failed = true
|
|
||||||
ts.benchmark.fail()
|
ts.benchmark.fail()
|
||||||
tls_bench.fail()
|
tls_bench.fail()
|
||||||
ts.add_failed_cmd(cmd)
|
ts.add_failed_cmd(cmd)
|
||||||
|
@ -396,7 +394,6 @@ fn worker_trunner(mut p pool.PoolProcessor, idx int, thread_id int) voidptr {
|
||||||
}
|
}
|
||||||
mut r := os.execute(cmd)
|
mut r := os.execute(cmd)
|
||||||
if r.exit_code < 0 {
|
if r.exit_code < 0 {
|
||||||
ts.failed = true
|
|
||||||
ts.benchmark.fail()
|
ts.benchmark.fail()
|
||||||
tls_bench.fail()
|
tls_bench.fail()
|
||||||
ts.append_message(.fail, tls_bench.step_message_fail(normalised_relative_file))
|
ts.append_message(.fail, tls_bench.step_message_fail(normalised_relative_file))
|
||||||
|
@ -422,7 +419,6 @@ fn worker_trunner(mut p pool.PoolProcessor, idx int, thread_id int) voidptr {
|
||||||
goto test_passed_execute
|
goto test_passed_execute
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ts.failed = true
|
|
||||||
ts.benchmark.fail()
|
ts.benchmark.fail()
|
||||||
tls_bench.fail()
|
tls_bench.fail()
|
||||||
ending_newline := if r.output.ends_with('\n') { '\n' } else { '' }
|
ending_newline := if r.output.ends_with('\n') { '\n' } else { '' }
|
||||||
|
@ -510,7 +506,7 @@ pub fn v_build_failing_skipped(zargs string, folder string, oskipped []string, c
|
||||||
cb(mut session)
|
cb(mut session)
|
||||||
session.test()
|
session.test()
|
||||||
eprintln(session.benchmark.total_message(finish_label))
|
eprintln(session.benchmark.total_message(finish_label))
|
||||||
return session.failed
|
return session.failed_cmds.len > 0
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn build_v_cmd_failed(cmd string) bool {
|
pub fn build_v_cmd_failed(cmd string) bool {
|
||||||
|
|
|
@ -43,7 +43,7 @@ fn main() {
|
||||||
// eprintln('> session.skip_files: $session.skip_files')
|
// eprintln('> session.skip_files: $session.skip_files')
|
||||||
session.test()
|
session.test()
|
||||||
eprintln(session.benchmark.total_message(finish_label))
|
eprintln(session.benchmark.total_message(finish_label))
|
||||||
if session.failed {
|
if session.failed_cmds.len > 0 {
|
||||||
exit(1)
|
exit(1)
|
||||||
}
|
}
|
||||||
//
|
//
|
||||||
|
|
|
@ -8,6 +8,8 @@ const github_job = os.getenv('GITHUB_JOB')
|
||||||
|
|
||||||
const (
|
const (
|
||||||
skip_test_files = [
|
skip_test_files = [
|
||||||
|
'cmd/tools/vdoc/html_tag_escape_test.v', /* can't locate local module: markdown */
|
||||||
|
'cmd/tools/vdoc/tests/vdoc_file_test.v', /* fails on Windows; order of output is not as expected */
|
||||||
'vlib/context/onecontext/onecontext_test.v',
|
'vlib/context/onecontext/onecontext_test.v',
|
||||||
'vlib/context/deadline_test.v' /* sometimes blocks */,
|
'vlib/context/deadline_test.v' /* sometimes blocks */,
|
||||||
'vlib/mysql/mysql_orm_test.v' /* mysql not installed */,
|
'vlib/mysql/mysql_orm_test.v' /* mysql not installed */,
|
||||||
|
@ -164,6 +166,7 @@ fn main() {
|
||||||
cmd_prefix := args_string.all_before('test-self')
|
cmd_prefix := args_string.all_before('test-self')
|
||||||
title := 'testing vlib'
|
title := 'testing vlib'
|
||||||
mut all_test_files := os.walk_ext(os.join_path(vroot, 'vlib'), '_test.v')
|
mut all_test_files := os.walk_ext(os.join_path(vroot, 'vlib'), '_test.v')
|
||||||
|
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
|
||||||
testing.eheader(title)
|
testing.eheader(title)
|
||||||
|
|
|
@ -69,7 +69,7 @@ fn main() {
|
||||||
testing.header('Testing...')
|
testing.header('Testing...')
|
||||||
ts.test()
|
ts.test()
|
||||||
println(ts.benchmark.total_message('all V _test.v files'))
|
println(ts.benchmark.total_message('all V _test.v files'))
|
||||||
if ts.failed {
|
if ts.failed_cmds.len > 0 {
|
||||||
exit(1)
|
exit(1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,2 +1,2 @@
|
||||||
cmd/tools/vvet/tests/array_init_one_val.vv:2: error: Use `var == value` instead of `var in [value]`
|
cmd/tools/vvet/tests/array_init_one_val.vv:2: error: Use `var == value` instead of `var in [value]`
|
||||||
NB: You can run `v fmt -w file.v` to fix these errors automatically
|
Note: You can run `v fmt -w file.v` to fix these errors automatically
|
||||||
|
|
|
@ -3,4 +3,4 @@ cmd/tools/vvet/tests/indent_with_space.vv:10: error: Looks like you are using sp
|
||||||
cmd/tools/vvet/tests/indent_with_space.vv:17: error: Looks like you are using spaces for indentation.
|
cmd/tools/vvet/tests/indent_with_space.vv:17: error: Looks like you are using spaces for indentation.
|
||||||
cmd/tools/vvet/tests/indent_with_space.vv:20: error: Looks like you are using spaces for indentation.
|
cmd/tools/vvet/tests/indent_with_space.vv:20: error: Looks like you are using spaces for indentation.
|
||||||
cmd/tools/vvet/tests/indent_with_space.vv:22: error: Looks like you are using spaces for indentation.
|
cmd/tools/vvet/tests/indent_with_space.vv:22: error: Looks like you are using spaces for indentation.
|
||||||
NB: You can run `v fmt -w file.v` to fix these errors automatically
|
Note: You can run `v fmt -w file.v` to fix these errors automatically
|
||||||
|
|
|
@ -0,0 +1,6 @@
|
||||||
|
// Some header comment
|
||||||
|
|
||||||
|
// read_response is a carefully constructed comment.
|
||||||
|
// read_response_body. <-- this would earlier trigger a false
|
||||||
|
// postive.
|
||||||
|
pub fn read_response() ?(string, string) {}
|
|
@ -1,2 +1,2 @@
|
||||||
cmd/tools/vvet/tests/parens_space_a.vv:1: error: Looks like you are adding a space after `(`
|
cmd/tools/vvet/tests/parens_space_a.vv:1: error: Looks like you are adding a space after `(`
|
||||||
NB: You can run `v fmt -w file.v` to fix these errors automatically
|
Note: You can run `v fmt -w file.v` to fix these errors automatically
|
||||||
|
|
|
@ -1,2 +1,2 @@
|
||||||
cmd/tools/vvet/tests/parens_space_b.vv:1: error: Looks like you are adding a space before `)`
|
cmd/tools/vvet/tests/parens_space_b.vv:1: error: Looks like you are adding a space before `)`
|
||||||
NB: You can run `v fmt -w file.v` to fix these errors automatically
|
Note: You can run `v fmt -w file.v` to fix these errors automatically
|
||||||
|
|
|
@ -182,13 +182,17 @@ fn (mut vt Vet) vet_fn_documentation(lines []string, line string, lnumber int) {
|
||||||
fn_name := ident_fn_name(line)
|
fn_name := ident_fn_name(line)
|
||||||
mut grab := true
|
mut grab := true
|
||||||
for j := lnumber - 1; j >= 0; j-- {
|
for j := lnumber - 1; j >= 0; j-- {
|
||||||
|
mut prev_prev_line := ''
|
||||||
|
if j - 1 >= 0 {
|
||||||
|
prev_prev_line = lines[j - 1]
|
||||||
|
}
|
||||||
prev_line := lines[j]
|
prev_line := lines[j]
|
||||||
if prev_line.contains('}') { // We've looked back to the above scope, stop here
|
if prev_line.contains('}') { // We've looked back to the above scope, stop here
|
||||||
break
|
break
|
||||||
} else if prev_line.starts_with('// $fn_name ') {
|
} else if prev_line.starts_with('// $fn_name ') {
|
||||||
grab = false
|
grab = false
|
||||||
break
|
break
|
||||||
} else if prev_line.starts_with('// $fn_name') {
|
} else if prev_line.starts_with('// $fn_name') && !prev_prev_line.starts_with('//') {
|
||||||
grab = false
|
grab = false
|
||||||
clean_line := line.all_before_last('{').trim(' ')
|
clean_line := line.all_before_last('{').trim(' ')
|
||||||
vt.warn('The documentation for "$clean_line" seems incomplete.', lnumber,
|
vt.warn('The documentation for "$clean_line" seems incomplete.', lnumber,
|
||||||
|
|
|
@ -556,11 +556,11 @@ fn (mut app App) set_theme(idx int) {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (mut app App) resize() {
|
fn (mut app App) resize() {
|
||||||
mut s := gg.dpi_scale()
|
mut s := app.gg.scale
|
||||||
if s == 0.0 {
|
if s == 0.0 {
|
||||||
s = 1.0
|
s = 1.0
|
||||||
}
|
}
|
||||||
window_size := gg.window_size()
|
window_size := app.gg.window_size()
|
||||||
w := window_size.width
|
w := window_size.width
|
||||||
h := window_size.height
|
h := window_size.height
|
||||||
m := f32(math.min(w, h))
|
m := f32(math.min(w, h))
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
Module {
|
||||||
|
name: 'submodule'
|
||||||
|
description: ''
|
||||||
|
version: ''
|
||||||
|
license: ''
|
||||||
|
dependencies: []
|
||||||
|
}
|
|
@ -2002,3 +2002,8 @@ pub fn (name string) match_glob(pattern string) bool {
|
||||||
// Matched all of `pattern` to all of `name`
|
// Matched all of `pattern` to all of `name`
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// is_ascii returns true if all characters belong to the US-ASCII set ([` `..`~`])
|
||||||
|
pub fn (s string) is_ascii() bool {
|
||||||
|
return !s.bytes().any(it < u8(` `) || it > u8(`~`))
|
||||||
|
}
|
||||||
|
|
|
@ -989,6 +989,16 @@ fn test_string_f32() {
|
||||||
assert '-123.456'.f32() - (-123.456) <= f32_epsilon
|
assert '-123.456'.f32() - (-123.456) <= f32_epsilon
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn test_string_is_ascii() {
|
||||||
|
assert ''.is_ascii() == true
|
||||||
|
assert ' '.is_ascii() == true
|
||||||
|
assert '~~'.is_ascii() == true
|
||||||
|
assert ' Az~'.is_ascii() == true
|
||||||
|
assert ' Aö~'.is_ascii() == false
|
||||||
|
assert '👋'.is_ascii() == false
|
||||||
|
assert 'a👋bc'.is_ascii() == false
|
||||||
|
}
|
||||||
|
|
||||||
fn test_string_with_zero_byte_escape() {
|
fn test_string_with_zero_byte_escape() {
|
||||||
assert '\x00'.bytes() == [u8(0)]
|
assert '\x00'.bytes() == [u8(0)]
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,7 @@ module clipboard
|
||||||
// Clipboard represents a system clipboard.
|
// Clipboard represents a system clipboard.
|
||||||
//
|
//
|
||||||
// System "copy" and "paste" actions utilize the clipboard for temporary storage.
|
// System "copy" and "paste" actions utilize the clipboard for temporary storage.
|
||||||
|
[heap]
|
||||||
pub struct Clipboard {
|
pub struct Clipboard {
|
||||||
pb voidptr
|
pb voidptr
|
||||||
last_cb_serial i64
|
last_cb_serial i64
|
||||||
|
|
|
@ -54,6 +54,7 @@ fn C.DestroyWindow(hwnd C.HWND)
|
||||||
// Clipboard represents a system clipboard.
|
// Clipboard represents a system clipboard.
|
||||||
//
|
//
|
||||||
// System "copy" and "paste" actions utilize the clipboard for temporary storage.
|
// System "copy" and "paste" actions utilize the clipboard for temporary storage.
|
||||||
|
[heap]
|
||||||
struct Clipboard {
|
struct Clipboard {
|
||||||
max_retries int
|
max_retries int
|
||||||
retry_delay int
|
retry_delay int
|
||||||
|
|
|
@ -3,6 +3,7 @@ module dummy
|
||||||
// Clipboard represents a system clipboard.
|
// Clipboard represents a system clipboard.
|
||||||
//
|
//
|
||||||
// System "copy" and "paste" actions utilize the clipboard for temporary storage.
|
// System "copy" and "paste" actions utilize the clipboard for temporary storage.
|
||||||
|
[heap]
|
||||||
pub struct Clipboard {
|
pub struct Clipboard {
|
||||||
mut:
|
mut:
|
||||||
text string // text data sent or received
|
text string // text data sent or received
|
||||||
|
|
|
@ -138,6 +138,7 @@ enum AtomType {
|
||||||
text_html = 9
|
text_html = 9
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[heap]
|
||||||
pub struct Clipboard {
|
pub struct Clipboard {
|
||||||
display &C.Display
|
display &C.Display
|
||||||
mut:
|
mut:
|
||||||
|
@ -291,6 +292,7 @@ fn (mut cb Clipboard) start_listener() {
|
||||||
mut sent_request := false
|
mut sent_request := false
|
||||||
mut to_be_requested := Atom(0)
|
mut to_be_requested := Atom(0)
|
||||||
for {
|
for {
|
||||||
|
time.sleep(1 * time.millisecond)
|
||||||
C.XNextEvent(cb.display, &event)
|
C.XNextEvent(cb.display, &event)
|
||||||
if unsafe { event.@type == 0 } {
|
if unsafe { event.@type == 0 } {
|
||||||
println('error')
|
println('error')
|
||||||
|
|
|
@ -1,5 +1,17 @@
|
||||||
module math
|
module math
|
||||||
|
|
||||||
|
// The vlang code is a modified version of the original C code from
|
||||||
|
// http://www.netlib.org/fdlibm/s_cbrt.c and came with this notice.
|
||||||
|
//
|
||||||
|
// ====================================================
|
||||||
|
// Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
|
||||||
|
//
|
||||||
|
// Developed at SunSoft, a Sun Microsystems, Inc. business.
|
||||||
|
// Permission to use, copy, modify, and distribute this
|
||||||
|
// software is freely granted, provided that this notice
|
||||||
|
// is preserved.
|
||||||
|
// ====================================================
|
||||||
|
|
||||||
// cbrt returns the cube root of a.
|
// cbrt returns the cube root of a.
|
||||||
//
|
//
|
||||||
// special cases are:
|
// special cases are:
|
||||||
|
@ -25,12 +37,12 @@ pub fn cbrt(a f64) f64 {
|
||||||
sign = true
|
sign = true
|
||||||
}
|
}
|
||||||
// rough cbrt to 5 bits
|
// rough cbrt to 5 bits
|
||||||
mut t := f64_from_bits(f64_bits(x) / u64(3 + (u64(b1) << 32)))
|
mut t := f64_from_bits(f64_bits(x) / u64(3) + (u64(b1) << 32))
|
||||||
if x < smallest_normal {
|
if x < smallest_normal {
|
||||||
// subnormal number
|
// subnormal number
|
||||||
t = f64(u64(1) << 54) // set t= 2**54
|
t = f64(u64(1) << 54) // set t= 2**54
|
||||||
t *= x
|
t *= x
|
||||||
t = f64_from_bits(f64_bits(t) / u64(3 + (u64(b2) << 32)))
|
t = f64_from_bits(f64_bits(t) / u64(3) + (u64(b2) << 32))
|
||||||
}
|
}
|
||||||
// new cbrt to 23 bits
|
// new cbrt to 23 bits
|
||||||
mut r := t * t / x
|
mut r := t * t / x
|
||||||
|
|
|
@ -506,6 +506,13 @@ fn test_mod() {
|
||||||
assert (0.6447968302508578) == f
|
assert (0.6447968302508578) == f
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn test_cbrt() {
|
||||||
|
cbrts := [2.0, 10, 56]
|
||||||
|
for idx, i in [8.0, 1000, 175_616] {
|
||||||
|
assert cbrt(i) == cbrts[idx]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn test_exp() {
|
fn test_exp() {
|
||||||
for i := 0; i < math.vf_.len; i++ {
|
for i := 0; i < math.vf_.len; i++ {
|
||||||
f := exp(math.vf_[i])
|
f := exp(math.vf_[i])
|
||||||
|
|
|
@ -66,6 +66,7 @@ mut:
|
||||||
buffer_size int
|
buffer_size int
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// new returns an `FTP` instance.
|
||||||
pub fn new() FTP {
|
pub fn new() FTP {
|
||||||
mut f := FTP{
|
mut f := FTP{
|
||||||
conn: 0
|
conn: 0
|
||||||
|
@ -101,6 +102,7 @@ fn (mut zftp FTP) read() ?(int, string) {
|
||||||
return code, data
|
return code, data
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// connect establishes an FTP connection to the host at `ip` port 21.
|
||||||
pub fn (mut zftp FTP) connect(ip string) ?bool {
|
pub fn (mut zftp FTP) connect(ip string) ?bool {
|
||||||
zftp.conn = net.dial_tcp('$ip:21')?
|
zftp.conn = net.dial_tcp('$ip:21')?
|
||||||
zftp.reader = io.new_buffered_reader(reader: zftp.conn)
|
zftp.reader = io.new_buffered_reader(reader: zftp.conn)
|
||||||
|
@ -111,6 +113,7 @@ pub fn (mut zftp FTP) connect(ip string) ?bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// login sends the "USER `user`" and "PASS `passwd`" commands to the remote host.
|
||||||
pub fn (mut zftp FTP) login(user string, passwd string) ?bool {
|
pub fn (mut zftp FTP) login(user string, passwd string) ?bool {
|
||||||
zftp.write('USER $user') or {
|
zftp.write('USER $user') or {
|
||||||
$if debug {
|
$if debug {
|
||||||
|
@ -138,11 +141,13 @@ pub fn (mut zftp FTP) login(user string, passwd string) ?bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// close closes the FTP connection.
|
||||||
pub fn (mut zftp FTP) close() ? {
|
pub fn (mut zftp FTP) close() ? {
|
||||||
zftp.write('QUIT')?
|
zftp.write('QUIT')?
|
||||||
zftp.conn.close()?
|
zftp.conn.close()?
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// pwd returns the current working directory on the remote host for the logged in user.
|
||||||
pub fn (mut zftp FTP) pwd() ?string {
|
pub fn (mut zftp FTP) pwd() ?string {
|
||||||
zftp.write('PWD')?
|
zftp.write('PWD')?
|
||||||
_, data := zftp.read()?
|
_, data := zftp.read()?
|
||||||
|
@ -153,6 +158,7 @@ pub fn (mut zftp FTP) pwd() ?string {
|
||||||
return data
|
return data
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// cd changes the current working directory to the specified remote directory `dir`.
|
||||||
pub fn (mut zftp FTP) cd(dir string) ? {
|
pub fn (mut zftp FTP) cd(dir string) ? {
|
||||||
zftp.write('CWD $dir') or { return }
|
zftp.write('CWD $dir') or { return }
|
||||||
mut code, mut data := zftp.read()?
|
mut code, mut data := zftp.read()?
|
||||||
|
@ -201,6 +207,7 @@ fn (mut zftp FTP) pasv() ?&DTP {
|
||||||
return dtp
|
return dtp
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// dir returns a list of the files in the current working directory.
|
||||||
pub fn (mut zftp FTP) dir() ?[]string {
|
pub fn (mut zftp FTP) dir() ?[]string {
|
||||||
mut dtp := zftp.pasv() or { return error('Cannot establish data connection') }
|
mut dtp := zftp.pasv() or { return error('Cannot establish data connection') }
|
||||||
zftp.write('LIST')?
|
zftp.write('LIST')?
|
||||||
|
@ -227,6 +234,7 @@ pub fn (mut zftp FTP) dir() ?[]string {
|
||||||
return dir
|
return dir
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// get retrieves `file` from the remote host.
|
||||||
pub fn (mut zftp FTP) get(file string) ?[]u8 {
|
pub fn (mut zftp FTP) get(file string) ?[]u8 {
|
||||||
mut dtp := zftp.pasv() or { return error('Cannot stablish data connection') }
|
mut dtp := zftp.pasv() or { return error('Cannot stablish data connection') }
|
||||||
zftp.write('RETR $file')?
|
zftp.write('RETR $file')?
|
||||||
|
|
|
@ -151,30 +151,31 @@ pub fn (mut s SSLConn) socket_read_into_ptr(buf_ptr &u8, len int) ?int {
|
||||||
mut res := 0
|
mut res := 0
|
||||||
for {
|
for {
|
||||||
res = C.SSL_read(voidptr(s.ssl), buf_ptr, len)
|
res = C.SSL_read(voidptr(s.ssl), buf_ptr, len)
|
||||||
if res < 0 {
|
if res >= 0 {
|
||||||
|
return res
|
||||||
|
} else {
|
||||||
err_res := ssl_error(res, s.ssl)?
|
err_res := ssl_error(res, s.ssl)?
|
||||||
if err_res == .ssl_error_want_read {
|
match err_res {
|
||||||
for {
|
.ssl_error_want_read {
|
||||||
ready := @select(s.handle, .read, s.duration)?
|
ready := @select(s.handle, .read, s.duration)?
|
||||||
if ready {
|
if !ready {
|
||||||
break
|
return net.err_timed_out
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
continue
|
.ssl_error_want_write {
|
||||||
} else if err_res == .ssl_error_want_write {
|
|
||||||
for {
|
|
||||||
ready := @select(s.handle, .write, s.duration)?
|
ready := @select(s.handle, .write, s.duration)?
|
||||||
if ready {
|
if !ready {
|
||||||
break
|
return net.err_timed_out
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
continue
|
.ssl_error_zero_return {
|
||||||
} else if err_res == .ssl_error_zero_return {
|
return 0
|
||||||
return 0
|
}
|
||||||
|
else {
|
||||||
|
return error('Could not read using SSL. ($err_res)')
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return error('Could not read using SSL. ($err_res)')
|
|
||||||
}
|
}
|
||||||
break
|
|
||||||
}
|
}
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
|
@ -228,13 +228,20 @@ fn (mut c Client) send_data() ? {
|
||||||
fn (mut c Client) send_body(cfg Mail) ? {
|
fn (mut c Client) send_body(cfg Mail) ? {
|
||||||
is_html := cfg.body_type == .html
|
is_html := cfg.body_type == .html
|
||||||
date := cfg.date.custom_format('ddd, D MMM YYYY HH:mm ZZ')
|
date := cfg.date.custom_format('ddd, D MMM YYYY HH:mm ZZ')
|
||||||
|
nonascii_subject := cfg.subject.bytes().any(it < u8(` `) || it > u8(`~`))
|
||||||
mut sb := strings.new_builder(200)
|
mut sb := strings.new_builder(200)
|
||||||
sb.write_string('From: $cfg.from\r\n')
|
sb.write_string('From: $cfg.from\r\n')
|
||||||
sb.write_string('To: <$cfg.to>\r\n')
|
sb.write_string('To: <$cfg.to>\r\n')
|
||||||
sb.write_string('Cc: <$cfg.cc>\r\n')
|
sb.write_string('Cc: <$cfg.cc>\r\n')
|
||||||
sb.write_string('Bcc: <$cfg.bcc>\r\n')
|
sb.write_string('Bcc: <$cfg.bcc>\r\n')
|
||||||
sb.write_string('Date: $date\r\n')
|
sb.write_string('Date: $date\r\n')
|
||||||
sb.write_string('Subject: $cfg.subject\r\n')
|
if nonascii_subject {
|
||||||
|
// handle UTF-8 subjects according RFC 1342
|
||||||
|
sb.write_string('Subject: =?utf-8?B?' + base64.encode_str(cfg.subject) + '?=\r\n')
|
||||||
|
} else {
|
||||||
|
sb.write_string('Subject: $cfg.subject\r\n')
|
||||||
|
}
|
||||||
|
|
||||||
if is_html {
|
if is_html {
|
||||||
sb.write_string('Content-Type: text/html; charset=UTF-8')
|
sb.write_string('Content-Type: text/html; charset=UTF-8')
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -0,0 +1,86 @@
|
||||||
|
module os
|
||||||
|
|
||||||
|
// Collection of useful functions for manipulation, validation and analysis of system paths.
|
||||||
|
// The following functions handle paths depending on the operating system,
|
||||||
|
// therefore results may be different for certain operating systems.
|
||||||
|
|
||||||
|
const (
|
||||||
|
fslash = `/`
|
||||||
|
bslash = `\\`
|
||||||
|
dot = `.`
|
||||||
|
)
|
||||||
|
|
||||||
|
// is_abs_path returns `true` if the given `path` is absolute.
|
||||||
|
pub fn is_abs_path(path string) bool {
|
||||||
|
if path.len == 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
$if windows {
|
||||||
|
return is_device_path(path) || is_drive_rooted(path) || is_normal_path(path)
|
||||||
|
}
|
||||||
|
return path[0] == os.fslash
|
||||||
|
}
|
||||||
|
|
||||||
|
// win_volume_len returns the length of the
|
||||||
|
// Windows volume/drive from the given `path`.
|
||||||
|
fn win_volume_len(path string) int {
|
||||||
|
plen := path.len
|
||||||
|
if plen < 2 {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
if has_drive_letter(path) {
|
||||||
|
return 2
|
||||||
|
}
|
||||||
|
// its UNC path / DOS device path?
|
||||||
|
if path.len >= 5 && starts_w_slash_slash(path) && !is_slash(path[2]) {
|
||||||
|
for i := 3; i < plen; i++ {
|
||||||
|
if is_slash(path[i]) {
|
||||||
|
if i + 1 >= plen || is_slash(path[i + 1]) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
i++
|
||||||
|
for ; i < plen; i++ {
|
||||||
|
if is_slash(path[i]) {
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_slash(b u8) bool {
|
||||||
|
$if windows {
|
||||||
|
return b == os.bslash || b == os.fslash
|
||||||
|
}
|
||||||
|
return b == os.fslash
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_device_path(path string) bool {
|
||||||
|
return win_volume_len(path) >= 5 && starts_w_slash_slash(path)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn has_drive_letter(path string) bool {
|
||||||
|
return path.len >= 2 && path[0].is_letter() && path[1] == `:`
|
||||||
|
}
|
||||||
|
|
||||||
|
fn starts_w_slash_slash(path string) bool {
|
||||||
|
return path.len >= 2 && is_slash(path[0]) && is_slash(path[1])
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_drive_rooted(path string) bool {
|
||||||
|
return path.len >= 3 && has_drive_letter(path) && is_slash(path[2])
|
||||||
|
}
|
||||||
|
|
||||||
|
// is_normal_path returns `true` if the given
|
||||||
|
// `path` is NOT a network or Windows device path.
|
||||||
|
fn is_normal_path(path string) bool {
|
||||||
|
plen := path.len
|
||||||
|
if plen == 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return (plen == 1 && is_slash(path[0])) || (plen >= 2 && is_slash(path[0])
|
||||||
|
&& !is_slash(path[1]))
|
||||||
|
}
|
|
@ -0,0 +1,29 @@
|
||||||
|
module os
|
||||||
|
|
||||||
|
fn test_is_abs_path() {
|
||||||
|
$if windows {
|
||||||
|
assert is_abs_path('/')
|
||||||
|
assert is_abs_path('\\')
|
||||||
|
assert !is_abs_path('\\\\')
|
||||||
|
assert is_abs_path(r'C:\path\to\files\file.v')
|
||||||
|
assert is_abs_path(r'\\Host\share')
|
||||||
|
assert is_abs_path(r'//Host\share\files\file.v')
|
||||||
|
assert is_abs_path(r'\\.\BootPartition\Windows')
|
||||||
|
assert !is_abs_path(r'\\.\')
|
||||||
|
assert !is_abs_path(r'\\?\\')
|
||||||
|
assert !is_abs_path(r'C:path\to\dir')
|
||||||
|
assert !is_abs_path(r'dir')
|
||||||
|
assert !is_abs_path(r'.\')
|
||||||
|
assert !is_abs_path(r'.')
|
||||||
|
assert !is_abs_path(r'\\Host')
|
||||||
|
assert !is_abs_path(r'\\Host\')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
assert is_abs_path('/')
|
||||||
|
assert is_abs_path('/path/to/files/file.v')
|
||||||
|
assert !is_abs_path('\\')
|
||||||
|
assert !is_abs_path('path/to/files/file.v')
|
||||||
|
assert !is_abs_path('dir')
|
||||||
|
assert !is_abs_path('./')
|
||||||
|
assert !is_abs_path('.')
|
||||||
|
}
|
12
vlib/os/os.v
12
vlib/os/os.v
|
@ -454,18 +454,6 @@ pub fn is_file(path string) bool {
|
||||||
return exists(path) && !is_dir(path)
|
return exists(path) && !is_dir(path)
|
||||||
}
|
}
|
||||||
|
|
||||||
// is_abs_path returns `true` if `path` is absolute.
|
|
||||||
pub fn is_abs_path(path string) bool {
|
|
||||||
if path.len == 0 {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
$if windows {
|
|
||||||
return path[0] == `/` || // incase we're in MingGW bash
|
|
||||||
(path[0].is_letter() && path.len > 1 && path[1] == `:`)
|
|
||||||
}
|
|
||||||
return path[0] == `/`
|
|
||||||
}
|
|
||||||
|
|
||||||
// join_path returns a path as string from input string parameter(s).
|
// join_path returns a path as string from input string parameter(s).
|
||||||
[manualfree]
|
[manualfree]
|
||||||
pub fn join_path(base string, dirs ...string) string {
|
pub fn join_path(base string, dirs ...string) string {
|
||||||
|
|
|
@ -590,14 +590,6 @@ fn test_ext() {
|
||||||
assert os.file_ext('file') == ''
|
assert os.file_ext('file') == ''
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_is_abs() {
|
|
||||||
assert os.is_abs_path('/home/user')
|
|
||||||
assert os.is_abs_path('v/vlib') == false
|
|
||||||
$if windows {
|
|
||||||
assert os.is_abs_path('C:\\Windows\\')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn test_join() {
|
fn test_join() {
|
||||||
$if windows {
|
$if windows {
|
||||||
assert os.join_path('v', 'vlib', 'os') == 'v\\vlib\\os'
|
assert os.join_path('v', 'vlib', 'os') == 'v\\vlib\\os'
|
||||||
|
|
|
@ -7,8 +7,17 @@ module sync
|
||||||
// For that, please look at `channel_select_2_test.v` or `channel_select_3_test.v`
|
// For that, please look at `channel_select_2_test.v` or `channel_select_3_test.v`
|
||||||
// This test case uses the implementation in `sync/channels.v` directly
|
// This test case uses the implementation in `sync/channels.v` directly
|
||||||
// in order to test it independently from the support in the core language
|
// in order to test it independently from the support in the core language
|
||||||
|
import os
|
||||||
import time
|
import time
|
||||||
|
|
||||||
|
fn test_should_run_flaky_test() {
|
||||||
|
if os.getenv('VTEST_RUN_FLAKY') != '1' {
|
||||||
|
eprintln('> skipping running flaky test, set VTEST_RUN_FLAKY to 1, to run it')
|
||||||
|
exit(0)
|
||||||
|
}
|
||||||
|
assert true
|
||||||
|
}
|
||||||
|
|
||||||
fn do_rec_i64(mut ch Channel) {
|
fn do_rec_i64(mut ch Channel) {
|
||||||
mut sum := i64(0)
|
mut sum := i64(0)
|
||||||
for _ in 0 .. 300 {
|
for _ in 0 .. 300 {
|
||||||
|
|
|
@ -184,3 +184,17 @@ fn test_parse_rfc3339() {
|
||||||
assert expected == output
|
assert expected == output
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn test_ad_second_to_parse_result_in_2001() ? {
|
||||||
|
now_tm := time.parse('2001-01-01 04:00:00')?
|
||||||
|
future_tm := now_tm.add_seconds(60)
|
||||||
|
assert future_tm.str() == '2001-01-01 04:01:00'
|
||||||
|
assert now_tm.unix < future_tm.unix
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_ad_second_to_parse_result_pre_2001() ? {
|
||||||
|
now_tm := time.parse('2000-01-01 04:00:00')?
|
||||||
|
future_tm := now_tm.add_seconds(60)
|
||||||
|
assert future_tm.str() == '2000-01-01 04:01:00'
|
||||||
|
assert now_tm.unix < future_tm.unix
|
||||||
|
}
|
||||||
|
|
|
@ -16,9 +16,10 @@ pub const (
|
||||||
seconds_per_hour = 60 * seconds_per_minute
|
seconds_per_hour = 60 * seconds_per_minute
|
||||||
seconds_per_day = 24 * seconds_per_hour
|
seconds_per_day = 24 * seconds_per_hour
|
||||||
seconds_per_week = 7 * seconds_per_day
|
seconds_per_week = 7 * seconds_per_day
|
||||||
days_per_400_years = 365 * 400 + 97
|
days_per_400_years = days_in_year * 400 + 97
|
||||||
days_per_100_years = 365 * 100 + 24
|
days_per_100_years = days_in_year * 100 + 24
|
||||||
days_per_4_years = 365 * 4 + 1
|
days_per_4_years = days_in_year * 4 + 1
|
||||||
|
days_in_year = 365
|
||||||
days_before = [
|
days_before = [
|
||||||
0,
|
0,
|
||||||
31,
|
31,
|
||||||
|
@ -179,13 +180,13 @@ pub fn (t Time) relative() string {
|
||||||
}
|
}
|
||||||
return '$prefix$d days$suffix'
|
return '$prefix$d days$suffix'
|
||||||
}
|
}
|
||||||
if secs < time.seconds_per_hour * 24 * 365 {
|
if secs < time.seconds_per_hour * 24 * time.days_in_year {
|
||||||
if prefix == 'in ' {
|
if prefix == 'in ' {
|
||||||
return 'on $t.md()'
|
return 'on $t.md()'
|
||||||
}
|
}
|
||||||
return 'last $t.md()'
|
return 'last $t.md()'
|
||||||
}
|
}
|
||||||
y := secs / time.seconds_per_hour / 24 / 365
|
y := secs / time.seconds_per_hour / 24 / time.days_in_year
|
||||||
if y == 1 {
|
if y == 1 {
|
||||||
return '${prefix}1 year$suffix'
|
return '${prefix}1 year$suffix'
|
||||||
}
|
}
|
||||||
|
@ -234,14 +235,14 @@ pub fn (t Time) relative_short() string {
|
||||||
}
|
}
|
||||||
return '$prefix${h}h$suffix'
|
return '$prefix${h}h$suffix'
|
||||||
}
|
}
|
||||||
if secs < time.seconds_per_hour * 24 * 365 {
|
if secs < time.seconds_per_hour * 24 * time.days_in_year {
|
||||||
d := secs / time.seconds_per_hour / 24
|
d := secs / time.seconds_per_hour / 24
|
||||||
if d == 1 {
|
if d == 1 {
|
||||||
return '${prefix}1d$suffix'
|
return '${prefix}1d$suffix'
|
||||||
}
|
}
|
||||||
return '$prefix${d}d$suffix'
|
return '$prefix${d}d$suffix'
|
||||||
}
|
}
|
||||||
y := secs / time.seconds_per_hour / 24 / 365
|
y := secs / time.seconds_per_hour / 24 / time.days_in_year
|
||||||
if y == 1 {
|
if y == 1 {
|
||||||
return '${prefix}1y$suffix'
|
return '${prefix}1y$suffix'
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,13 +5,13 @@ fn test_add_to_day_in_the_previous_century() ? {
|
||||||
aa := a.add_days(180)
|
aa := a.add_days(180)
|
||||||
dump(a.debug())
|
dump(a.debug())
|
||||||
dump(aa.debug())
|
dump(aa.debug())
|
||||||
assert aa.ymmdd() == '1900-06-29'
|
assert aa.ymmdd() == '1900-06-30'
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_add_to_day_in_the_past() ? {
|
fn test_add_to_day_in_the_past() ? {
|
||||||
a := time.parse_iso8601('1990-03-01')?
|
a := time.parse_iso8601('1990-03-01')?
|
||||||
aa := a.add_days(180)
|
aa := a.add_days(180)
|
||||||
assert aa.ymmdd() == '1990-08-27'
|
assert aa.ymmdd() == '1990-08-28'
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_add_to_day_in_the_recent_past() ? {
|
fn test_add_to_day_in_the_recent_past() ? {
|
||||||
|
|
|
@ -267,3 +267,9 @@ fn test_recursive_local_call() {
|
||||||
fn test_strftime() {
|
fn test_strftime() {
|
||||||
assert '1980 July 11' == time_to_test.strftime('%Y %B %d')
|
assert '1980 July 11' == time_to_test.strftime('%Y %B %d')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn test_add_seconds_to_time() {
|
||||||
|
now_tm := time.now()
|
||||||
|
future_tm := now_tm.add_seconds(60)
|
||||||
|
assert now_tm.unix < future_tm.unix
|
||||||
|
}
|
||||||
|
|
|
@ -48,67 +48,39 @@ pub fn unix2(abs i64, microsecond int) Time {
|
||||||
|
|
||||||
fn calculate_date_from_offset(day_offset_ i64) (int, int, int) {
|
fn calculate_date_from_offset(day_offset_ i64) (int, int, int) {
|
||||||
mut day_offset := day_offset_
|
mut day_offset := day_offset_
|
||||||
// Move offset to year 2001 as it's the start of a new 400-year cycle
|
|
||||||
// Code below this rely on the fact that the day_offset is lined up with the 400-year cycle
|
// source: http://howardhinnant.github.io/date_algorithms.html#civil_from_days
|
||||||
// 1970-2000 (inclusive) has 31 years (8 of which are leap years)
|
|
||||||
mut year := 2001
|
// shift from 1970-01-01 to 0000-03-01
|
||||||
day_offset -= 31 * 365 + 8
|
day_offset += 719468 // int(days_per_400_years * 1970 / 400 - (28+31))
|
||||||
// Account for 400 year cycle
|
|
||||||
year += int(day_offset / days_per_400_years) * 400
|
mut era := 0
|
||||||
day_offset %= days_per_400_years
|
if day_offset >= 0 {
|
||||||
// Account for 100 year cycle
|
era = int(day_offset / days_per_400_years)
|
||||||
if day_offset == days_per_100_years * 4 {
|
|
||||||
year += 300
|
|
||||||
day_offset -= days_per_100_years * 3
|
|
||||||
} else {
|
} else {
|
||||||
year += int(day_offset / days_per_100_years) * 100
|
era = int((day_offset - days_per_400_years - 1) / days_per_400_years)
|
||||||
day_offset %= days_per_100_years
|
|
||||||
}
|
}
|
||||||
// Account for 4 year cycle
|
// doe(day of era) [0, 146096]
|
||||||
if day_offset == days_per_4_years * 25 {
|
doe := day_offset - era * days_per_400_years
|
||||||
year += 96
|
// yoe(year of era) [0, 399]
|
||||||
day_offset -= days_per_4_years * 24
|
yoe := (doe - doe / (days_per_4_years - 1) + doe / days_per_100_years - doe / (days_per_400_years - 1)) / days_in_year
|
||||||
|
// year number
|
||||||
|
mut y := int(yoe + era * 400)
|
||||||
|
// doy (day of year), with year beginning Mar 1 [0, 365]
|
||||||
|
doy := doe - (days_in_year * yoe + yoe / 4 - yoe / 100)
|
||||||
|
|
||||||
|
mp := (5 * doy + 2) / 153
|
||||||
|
d := int(doy - (153 * mp + 2) / 5 + 1)
|
||||||
|
mut m := int(mp)
|
||||||
|
if mp < 10 {
|
||||||
|
m += 3
|
||||||
} else {
|
} else {
|
||||||
year += int(day_offset / days_per_4_years) * 4
|
m -= 9
|
||||||
day_offset %= days_per_4_years
|
|
||||||
}
|
}
|
||||||
// Account for every year
|
if m <= 2 {
|
||||||
if day_offset == 365 * 4 {
|
y += 1
|
||||||
year += 3
|
|
||||||
day_offset -= 365 * 3
|
|
||||||
} else {
|
|
||||||
year += int(day_offset / 365)
|
|
||||||
day_offset %= 365
|
|
||||||
}
|
}
|
||||||
if day_offset < 0 {
|
return y, m, d
|
||||||
year--
|
|
||||||
if is_leap_year(year) {
|
|
||||||
day_offset += 366
|
|
||||||
} else {
|
|
||||||
day_offset += 365
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if is_leap_year(year) {
|
|
||||||
if day_offset > 31 + 29 - 1 {
|
|
||||||
// After leap day; pretend it wasn't there.
|
|
||||||
day_offset--
|
|
||||||
} else if day_offset == 31 + 29 - 1 {
|
|
||||||
// Leap day.
|
|
||||||
return year, 2, 29
|
|
||||||
}
|
|
||||||
}
|
|
||||||
mut estimated_month := day_offset / 31
|
|
||||||
for day_offset >= days_before[estimated_month + 1] {
|
|
||||||
estimated_month++
|
|
||||||
}
|
|
||||||
for day_offset < days_before[estimated_month] {
|
|
||||||
if estimated_month == 0 {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
estimated_month--
|
|
||||||
}
|
|
||||||
day_offset -= days_before[estimated_month]
|
|
||||||
return year, int(estimated_month + 1), int(day_offset + 1)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn calculate_time_from_offset(second_offset_ i64) (int, int, int) {
|
fn calculate_time_from_offset(second_offset_ i64) (int, int, int) {
|
||||||
|
|
|
@ -256,13 +256,14 @@ pub:
|
||||||
mut_pos token.Pos
|
mut_pos token.Pos
|
||||||
next_token token.Kind
|
next_token token.Kind
|
||||||
pub mut:
|
pub mut:
|
||||||
expr Expr // expr.field_name
|
expr Expr // expr.field_name
|
||||||
expr_type Type // type of `Foo` in `Foo.bar`
|
expr_type Type // type of `Foo` in `Foo.bar`
|
||||||
typ Type // type of the entire thing (`Foo.bar`)
|
typ Type // type of the entire thing (`Foo.bar`)
|
||||||
name_type Type // T in `T.name` or typeof in `typeof(expr).name`
|
name_type Type // T in `T.name` or typeof in `typeof(expr).name`
|
||||||
gkind_field GenericKindField // `T.name` => ast.GenericKindField.name, `T.typ` => ast.GenericKindField.typ, or .unknown
|
gkind_field GenericKindField // `T.name` => ast.GenericKindField.name, `T.typ` => ast.GenericKindField.typ, or .unknown
|
||||||
scope &Scope
|
scope &Scope
|
||||||
from_embed_types []Type // holds the type of the embed that the method is called from
|
from_embed_types []Type // holds the type of the embed that the method is called from
|
||||||
|
has_hidden_receiver bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// root_ident returns the origin ident where the selector started.
|
// root_ident returns the origin ident where the selector started.
|
||||||
|
|
|
@ -1464,7 +1464,6 @@ pub fn (t &TypeSymbol) find_method_with_generic_parent(name string) ?Fn {
|
||||||
param.typ = pt
|
param.typ = pt
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
method.generic_names.clear()
|
|
||||||
return method
|
return method
|
||||||
}
|
}
|
||||||
else {}
|
else {}
|
||||||
|
|
|
@ -927,9 +927,10 @@ pub fn (mut c Checker) infix_expr(mut node ast.InfixExpr) ast.Type {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if left_type.has_flag(.optional) && right_type.has_flag(.optional) {
|
} else if left_type.has_flag(.optional) || right_type.has_flag(.optional) {
|
||||||
|
opt_comp_pos := if left_type.has_flag(.optional) { left_pos } else { right_pos }
|
||||||
c.error('unwrapped optional cannot be compared in an infix expression',
|
c.error('unwrapped optional cannot be compared in an infix expression',
|
||||||
left_right_pos)
|
opt_comp_pos)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.left_shift {
|
.left_shift {
|
||||||
|
@ -1143,8 +1144,11 @@ pub fn (mut c Checker) infix_expr(mut node ast.InfixExpr) ast.Type {
|
||||||
// TODO move this to symmetric_check? Right now it would break `return 0` for `fn()?int `
|
// TODO move this to symmetric_check? Right now it would break `return 0` for `fn()?int `
|
||||||
left_is_optional := left_type.has_flag(.optional)
|
left_is_optional := left_type.has_flag(.optional)
|
||||||
right_is_optional := right_type.has_flag(.optional)
|
right_is_optional := right_type.has_flag(.optional)
|
||||||
if (left_is_optional && !right_is_optional) || (!left_is_optional && right_is_optional) {
|
if left_is_optional && right_is_optional {
|
||||||
c.error('unwrapped optional cannot be used in an infix expression', left_right_pos)
|
c.error('unwrapped optionals cannot be used in an infix expression', left_right_pos)
|
||||||
|
} else if left_is_optional || right_is_optional {
|
||||||
|
opt_infix_pos := if left_is_optional { left_pos } else { right_pos }
|
||||||
|
c.error('unwrapped optional cannot be used in an infix expression', opt_infix_pos)
|
||||||
}
|
}
|
||||||
// Dual sides check (compatibility check)
|
// Dual sides check (compatibility check)
|
||||||
if !(c.symmetric_check(left_type, right_type) && c.symmetric_check(right_type, left_type))
|
if !(c.symmetric_check(left_type, right_type) && c.symmetric_check(right_type, left_type))
|
||||||
|
@ -1846,6 +1850,37 @@ pub fn (mut c Checker) selector_expr(mut node ast.SelectorExpr) ast.Type {
|
||||||
node.typ = field.typ
|
node.typ = field.typ
|
||||||
return field.typ
|
return field.typ
|
||||||
}
|
}
|
||||||
|
if mut method := c.table.find_method(sym, field_name) {
|
||||||
|
if c.expected_type != 0 && c.expected_type != ast.none_type {
|
||||||
|
fn_type := ast.new_type(c.table.find_or_register_fn_type(c.mod, method, false,
|
||||||
|
true))
|
||||||
|
// if the expected type includes the receiver, don't hide it behind a closure
|
||||||
|
if c.check_types(fn_type, c.expected_type) {
|
||||||
|
return fn_type
|
||||||
|
}
|
||||||
|
}
|
||||||
|
receiver := method.params[0].typ
|
||||||
|
if receiver.nr_muls() > 0 {
|
||||||
|
if !c.inside_unsafe {
|
||||||
|
rec_sym := c.table.sym(receiver.set_nr_muls(0))
|
||||||
|
if !rec_sym.is_heap() {
|
||||||
|
suggestion := if rec_sym.kind == .struct_ {
|
||||||
|
'declaring `$rec_sym.name` as `[heap]`'
|
||||||
|
} else {
|
||||||
|
'wrapping the `$rec_sym.name` object in a `struct` declared as `[heap]`'
|
||||||
|
}
|
||||||
|
c.error('method `${c.table.type_to_str(receiver.idx())}.$method.name` cannot be used as a variable outside `unsafe` blocks as its receiver might refer to an object stored on stack. Consider ${suggestion}.',
|
||||||
|
node.expr.pos().extend(node.pos))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
method.params = method.params[1..]
|
||||||
|
node.has_hidden_receiver = true
|
||||||
|
method.name = ''
|
||||||
|
fn_type := ast.new_type(c.table.find_or_register_fn_type(c.mod, method, false,
|
||||||
|
true))
|
||||||
|
return fn_type
|
||||||
|
}
|
||||||
if sym.kind !in [.struct_, .aggregate, .interface_, .sum_type] {
|
if sym.kind !in [.struct_, .aggregate, .interface_, .sum_type] {
|
||||||
if sym.kind != .placeholder {
|
if sym.kind != .placeholder {
|
||||||
unwrapped_sym := c.table.sym(c.unwrap_generic(typ))
|
unwrapped_sym := c.table.sym(c.unwrap_generic(typ))
|
||||||
|
@ -3371,7 +3406,21 @@ pub fn (mut c Checker) ident(mut node ast.Ident) ast.Type {
|
||||||
c.note('`[if $node.name]` is deprecated. Use `[if $node.name?]` instead',
|
c.note('`[if $node.name]` is deprecated. Use `[if $node.name?]` instead',
|
||||||
node.pos)
|
node.pos)
|
||||||
} else {
|
} else {
|
||||||
c.error('undefined ident: `$node.name`', node.pos)
|
cname_mod := node.name.all_before('.')
|
||||||
|
if cname_mod.len != node.name.len {
|
||||||
|
mut const_names_in_mod := []string{}
|
||||||
|
for _, so in c.table.global_scope.objects {
|
||||||
|
if so is ast.ConstField {
|
||||||
|
if so.mod == cname_mod {
|
||||||
|
const_names_in_mod << so.name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
c.error(util.new_suggestion(node.name, const_names_in_mod).say('undefined ident: `$node.name`'),
|
||||||
|
node.pos)
|
||||||
|
} else {
|
||||||
|
c.error('undefined ident: `$node.name`', node.pos)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if c.table.known_type(node.name) {
|
if c.table.known_type(node.name) {
|
||||||
|
@ -3533,6 +3582,7 @@ pub fn (mut c Checker) select_expr(mut node ast.SelectExpr) ast.Type {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (mut c Checker) lock_expr(mut node ast.LockExpr) ast.Type {
|
pub fn (mut c Checker) lock_expr(mut node ast.LockExpr) ast.Type {
|
||||||
|
expected_type := c.expected_type
|
||||||
if c.rlocked_names.len > 0 || c.locked_names.len > 0 {
|
if c.rlocked_names.len > 0 || c.locked_names.len > 0 {
|
||||||
c.error('nested `lock`/`rlock` not allowed', node.pos)
|
c.error('nested `lock`/`rlock` not allowed', node.pos)
|
||||||
}
|
}
|
||||||
|
@ -3556,16 +3606,17 @@ pub fn (mut c Checker) lock_expr(mut node ast.LockExpr) ast.Type {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
c.stmts(node.stmts)
|
c.stmts(node.stmts)
|
||||||
c.rlocked_names = []
|
|
||||||
c.locked_names = []
|
|
||||||
// handle `x := rlock a { a.getval() }`
|
// handle `x := rlock a { a.getval() }`
|
||||||
mut ret_type := ast.void_type
|
mut ret_type := ast.void_type
|
||||||
if node.stmts.len > 0 {
|
if node.stmts.len > 0 {
|
||||||
last_stmt := node.stmts.last()
|
last_stmt := node.stmts.last()
|
||||||
if last_stmt is ast.ExprStmt {
|
if last_stmt is ast.ExprStmt {
|
||||||
ret_type = last_stmt.typ
|
c.expected_type = expected_type
|
||||||
|
ret_type = c.expr(last_stmt.expr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
c.rlocked_names = []
|
||||||
|
c.locked_names = []
|
||||||
if ret_type != ast.void_type {
|
if ret_type != ast.void_type {
|
||||||
node.is_expr = true
|
node.is_expr = true
|
||||||
}
|
}
|
||||||
|
|
|
@ -958,6 +958,9 @@ pub fn (mut c Checker) fn_call(mut node ast.CallExpr, mut continue_check &bool)
|
||||||
if param.typ == ast.voidptr_type_idx || arg_typ == ast.voidptr_type_idx {
|
if param.typ == ast.voidptr_type_idx || arg_typ == ast.voidptr_type_idx {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
if param.typ.is_any_kind_of_pointer() && arg_typ.is_any_kind_of_pointer() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
param_typ_sym_ := c.table.sym(c.table.unaliased_type(param.typ))
|
param_typ_sym_ := c.table.sym(c.table.unaliased_type(param.typ))
|
||||||
arg_typ_sym_ := c.table.sym(c.table.unaliased_type(arg_typ))
|
arg_typ_sym_ := c.table.sym(c.table.unaliased_type(arg_typ))
|
||||||
// Allow `[32]i8` as `&i8` etc
|
// Allow `[32]i8` as `&i8` etc
|
||||||
|
@ -968,6 +971,17 @@ pub fn (mut c Checker) fn_call(mut node ast.CallExpr, mut continue_check &bool)
|
||||||
&& (typ_is_number || c.table.unaliased_type(arg_typ).is_any_kind_of_pointer())) {
|
&& (typ_is_number || c.table.unaliased_type(arg_typ).is_any_kind_of_pointer())) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
// Allow `[N]anyptr` as `[N]anyptr`
|
||||||
|
if arg_typ_sym_.kind == .array && param_typ_sym_.kind == .array {
|
||||||
|
if (arg_typ_sym_.info as ast.Array).elem_type.is_any_kind_of_pointer()
|
||||||
|
&& (param_typ_sym_.info as ast.Array).elem_type.is_any_kind_of_pointer() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
} else if arg_typ_sym_.kind == .array_fixed && param_typ_sym_.kind == .array_fixed {
|
||||||
|
if (arg_typ_sym_.info as ast.ArrayFixed).elem_type.is_any_kind_of_pointer()&& (param_typ_sym_.info as ast.ArrayFixed).elem_type.is_any_kind_of_pointer() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
// Allow `int` as `&i8`
|
// Allow `int` as `&i8`
|
||||||
if param.typ.is_any_kind_of_pointer() && typ_is_number {
|
if param.typ.is_any_kind_of_pointer() && typ_is_number {
|
||||||
continue
|
continue
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
vlib/v/checker/tests/infix_compare_optional_err.vv:6:5: error: unwrapped optional cannot be compared in an infix expression
|
vlib/v/checker/tests/infix_compare_optional_err.vv:6:5: error: unwrapped optional cannot be compared in an infix expression
|
||||||
4 |
|
4 |
|
||||||
5 | fn main(){
|
5 | fn main(){
|
||||||
6 | if foo() > foo() {}
|
6 | if foo() > foo() {}
|
||||||
| ~~~~~~~~~~~~~
|
| ~~~~~
|
||||||
7 | }
|
7 | }
|
||||||
|
|
|
@ -26,11 +26,11 @@ vlib/v/checker/tests/infix_err.vv:11:7: error: `+` cannot be used with `?int`
|
||||||
| ^
|
| ^
|
||||||
12 | _ = int(0) + g() // FIXME not detected
|
12 | _ = int(0) + g() // FIXME not detected
|
||||||
13 | _ = g() + int(3)
|
13 | _ = g() + int(3)
|
||||||
vlib/v/checker/tests/infix_err.vv:12:5: error: unwrapped optional cannot be used in an infix expression
|
vlib/v/checker/tests/infix_err.vv:12:14: error: unwrapped optional cannot be used in an infix expression
|
||||||
10 |
|
10 |
|
||||||
11 | _ = 4 + g()
|
11 | _ = 4 + g()
|
||||||
12 | _ = int(0) + g() // FIXME not detected
|
12 | _ = int(0) + g() // FIXME not detected
|
||||||
| ~~~~~~~~~~~~
|
| ~~~
|
||||||
13 | _ = g() + int(3)
|
13 | _ = g() + int(3)
|
||||||
14 | _ = g() + 3
|
14 | _ = g() + 3
|
||||||
vlib/v/checker/tests/infix_err.vv:13:9: error: `+` cannot be used with `?int`
|
vlib/v/checker/tests/infix_err.vv:13:9: error: `+` cannot be used with `?int`
|
||||||
|
|
|
@ -5,6 +5,13 @@ vlib/v/checker/tests/lock_already_locked.vv:11:3: error: nested `lock`/`rlock` n
|
||||||
| ~~~~~
|
| ~~~~~
|
||||||
12 | a.x++
|
12 | a.x++
|
||||||
13 | }
|
13 | }
|
||||||
|
vlib/v/checker/tests/lock_already_locked.vv:12:4: error: a has an `rlock` but needs a `lock`
|
||||||
|
10 | lock a {
|
||||||
|
11 | rlock a {
|
||||||
|
12 | a.x++
|
||||||
|
| ^
|
||||||
|
13 | }
|
||||||
|
14 | }
|
||||||
vlib/v/checker/tests/lock_already_locked.vv:15:10: error: `a` is `shared` and must be `rlock`ed or `lock`ed to be used as non-mut argument to print
|
vlib/v/checker/tests/lock_already_locked.vv:15:10: error: `a` is `shared` and must be `rlock`ed or `lock`ed to be used as non-mut argument to print
|
||||||
13 | }
|
13 | }
|
||||||
14 | }
|
14 | }
|
||||||
|
|
|
@ -0,0 +1,6 @@
|
||||||
|
vlib/v/checker/tests/misspelled_mod_const_should_have_suggestion.vv:3:21: error: undefined ident: `time.secondz`.
|
||||||
|
Did you mean `time.second`?
|
||||||
|
1 | import time
|
||||||
|
2 |
|
||||||
|
3 | time.sleep(1 * time.secondz)
|
||||||
|
| ~~~~~~~
|
|
@ -0,0 +1,3 @@
|
||||||
|
import time
|
||||||
|
|
||||||
|
time.sleep(1 * time.secondz)
|
|
@ -0,0 +1,7 @@
|
||||||
|
vlib/v/checker/tests/unsafe_method_as_field.vv:23:7: error: method `Foo.ref` cannot be used as a variable outside `unsafe` blocks as its receiver might refer to an object stored on stack. Consider declaring `Foo` as `[heap]`.
|
||||||
|
21 | f := Foo{}
|
||||||
|
22 | _ := f.no_ref // no error
|
||||||
|
23 | _ := f.ref // error
|
||||||
|
| ~~~~~
|
||||||
|
24 |
|
||||||
|
25 | b := Bar{}
|
|
@ -0,0 +1,27 @@
|
||||||
|
struct Foo {
|
||||||
|
}
|
||||||
|
|
||||||
|
fn (f Foo) no_ref() int {
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
fn (f &Foo) ref() int {
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
[heap]
|
||||||
|
struct Bar {
|
||||||
|
}
|
||||||
|
|
||||||
|
fn (f &Bar) ref() int {
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
f := Foo{}
|
||||||
|
_ := f.no_ref // no error
|
||||||
|
_ := f.ref // error
|
||||||
|
|
||||||
|
b := Bar{}
|
||||||
|
_ := b.ref // no error
|
||||||
|
}
|
|
@ -2,5 +2,4 @@ vlib/v/checker/tests/unwrapped_optional_infix.vv:5:9: error: unwrapped optional
|
||||||
3 | }
|
3 | }
|
||||||
4 |
|
4 |
|
||||||
5 | println(test() == "")
|
5 | println(test() == "")
|
||||||
| ~~~~~~~~~~~~
|
| ~~~~~~
|
||||||
|
|
||||||
|
|
|
@ -1951,7 +1951,8 @@ pub fn (mut f Fmt) if_expr(node ast.IfExpr) {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn branch_is_single_line(b ast.IfBranch) bool {
|
fn branch_is_single_line(b ast.IfBranch) bool {
|
||||||
if b.stmts.len == 1 && b.comments.len == 0 && stmt_is_single_line(b.stmts[0]) {
|
if b.stmts.len == 1 && b.comments.len == 0 && stmt_is_single_line(b.stmts[0])
|
||||||
|
&& b.pos.line_nr == b.stmts[0].pos.line_nr {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
|
|
|
@ -0,0 +1,10 @@
|
||||||
|
fn main() {
|
||||||
|
a := fn () {
|
||||||
|
if true {
|
||||||
|
println('a')
|
||||||
|
} else {
|
||||||
|
println('a')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
a()
|
||||||
|
}
|
|
@ -0,0 +1,10 @@
|
||||||
|
fn main() {
|
||||||
|
a := fn () {
|
||||||
|
if true {
|
||||||
|
println('a')
|
||||||
|
} else {
|
||||||
|
println('a')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
a()
|
||||||
|
}
|
|
@ -64,8 +64,7 @@ a: 5
|
||||||
lock x { // wait for ongoing reads to finish, don't start new ones
|
lock x { // wait for ongoing reads to finish, don't start new ones
|
||||||
x.a = 17 // this value should never be read
|
x.a = 17 // this value should never be read
|
||||||
time.sleep(50* time.millisecond)
|
time.sleep(50* time.millisecond)
|
||||||
x.a = if (i & 1) == 0 {
|
x.a = if (i & 1) == 0 { 7 } else { 5 }
|
||||||
7} else {5}
|
|
||||||
} // now new reads are possible again
|
} // now new reads are possible again
|
||||||
time.sleep(20*time.millisecond)
|
time.sleep(20*time.millisecond)
|
||||||
}
|
}
|
||||||
|
|
|
@ -211,7 +211,11 @@ fn (mut g Gen) gen_assign_stmt(node_ ast.AssignStmt) {
|
||||||
} else if g.inside_for_c_stmt {
|
} else if g.inside_for_c_stmt {
|
||||||
g.expr(val)
|
g.expr(val)
|
||||||
} else {
|
} else {
|
||||||
g.write('{$styp _ = ')
|
if left_sym.kind == .function {
|
||||||
|
g.write('{void* _ = ')
|
||||||
|
} else {
|
||||||
|
g.write('{$styp _ = ')
|
||||||
|
}
|
||||||
g.expr(val)
|
g.expr(val)
|
||||||
g.writeln(';}')
|
g.writeln(';}')
|
||||||
}
|
}
|
||||||
|
@ -456,6 +460,8 @@ fn (mut g Gen) gen_assign_stmt(node_ ast.AssignStmt) {
|
||||||
}
|
}
|
||||||
if val is ast.ArrayInit {
|
if val is ast.ArrayInit {
|
||||||
g.array_init(val, ident.name)
|
g.array_init(val, ident.name)
|
||||||
|
} else if val_type.has_flag(.shared_f) {
|
||||||
|
g.expr_with_cast(val, val_type, var_type)
|
||||||
} else {
|
} else {
|
||||||
g.expr(val)
|
g.expr(val)
|
||||||
}
|
}
|
||||||
|
|
|
@ -3339,6 +3339,68 @@ fn (mut g Gen) selector_expr(node ast.SelectorExpr) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else if m := g.table.find_method(sym, node.field_name) {
|
||||||
|
mut has_embeds := false
|
||||||
|
if sym.info in [ast.Struct, ast.Aggregate] {
|
||||||
|
if node.from_embed_types.len > 0 {
|
||||||
|
has_embeds = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !has_embeds {
|
||||||
|
if !node.has_hidden_receiver {
|
||||||
|
g.write('${g.typ(node.expr_type.idx())}_$m.name')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
receiver := m.params[0]
|
||||||
|
expr_styp := g.typ(node.expr_type.idx())
|
||||||
|
data_styp := g.typ(receiver.typ.idx())
|
||||||
|
mut sb := strings.new_builder(256)
|
||||||
|
name := '_V_closure_${expr_styp}_${m.name}_$node.pos.pos'
|
||||||
|
sb.write_string('${g.typ(m.return_type)} ${name}(')
|
||||||
|
for i in 1 .. m.params.len {
|
||||||
|
param := m.params[i]
|
||||||
|
if i != 1 {
|
||||||
|
sb.write_string(', ')
|
||||||
|
}
|
||||||
|
sb.write_string('${g.typ(param.typ)} a$i')
|
||||||
|
}
|
||||||
|
sb.writeln(') {')
|
||||||
|
sb.writeln('\t$data_styp* a0 = *($data_styp**)(__RETURN_ADDRESS() - __CLOSURE_DATA_OFFSET);')
|
||||||
|
if m.return_type != ast.void_type {
|
||||||
|
sb.write_string('\treturn ')
|
||||||
|
} else {
|
||||||
|
sb.write_string('\t')
|
||||||
|
}
|
||||||
|
sb.write_string('${expr_styp}_${m.name}(')
|
||||||
|
if !receiver.typ.is_ptr() {
|
||||||
|
sb.write_string('*')
|
||||||
|
}
|
||||||
|
for i in 0 .. m.params.len {
|
||||||
|
if i != 0 {
|
||||||
|
sb.write_string(', ')
|
||||||
|
}
|
||||||
|
sb.write_string('a$i')
|
||||||
|
}
|
||||||
|
sb.writeln(');')
|
||||||
|
sb.writeln('}')
|
||||||
|
|
||||||
|
g.anon_fn_definitions << sb.str()
|
||||||
|
g.nr_closures++
|
||||||
|
|
||||||
|
g.write('__closure_create($name, ')
|
||||||
|
if !receiver.typ.is_ptr() {
|
||||||
|
g.write('memdup(')
|
||||||
|
}
|
||||||
|
if !node.expr_type.is_ptr() {
|
||||||
|
g.write('&')
|
||||||
|
}
|
||||||
|
g.expr(node.expr)
|
||||||
|
if !receiver.typ.is_ptr() {
|
||||||
|
g.write(', sizeof($expr_styp))')
|
||||||
|
}
|
||||||
|
g.write(')')
|
||||||
|
return
|
||||||
|
}
|
||||||
}
|
}
|
||||||
n_ptr := node.expr_type.nr_muls() - 1
|
n_ptr := node.expr_type.nr_muls() - 1
|
||||||
if n_ptr > 0 {
|
if n_ptr > 0 {
|
||||||
|
|
|
@ -1625,15 +1625,29 @@ fn (mut g Gen) call_args(node ast.CallExpr) {
|
||||||
arr_sym := g.table.sym(varg_type)
|
arr_sym := g.table.sym(varg_type)
|
||||||
mut arr_info := arr_sym.info as ast.Array
|
mut arr_info := arr_sym.info as ast.Array
|
||||||
if varg_type.has_flag(.generic) {
|
if varg_type.has_flag(.generic) {
|
||||||
if fn_def := g.table.find_fn(node.name) {
|
if node.is_method {
|
||||||
mut muttable := unsafe { &ast.Table(g.table) }
|
left_sym := g.table.sym(node.left_type)
|
||||||
if utyp := muttable.resolve_generic_to_concrete(arr_info.elem_type, fn_def.generic_names,
|
if fn_def := left_sym.find_method_with_generic_parent(node.name) {
|
||||||
node.concrete_types)
|
mut muttable := unsafe { &ast.Table(g.table) }
|
||||||
{
|
if utyp := muttable.resolve_generic_to_concrete(arr_info.elem_type,
|
||||||
arr_info.elem_type = utyp
|
fn_def.generic_names, node.concrete_types)
|
||||||
|
{
|
||||||
|
arr_info.elem_type = utyp
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
g.error('unable to find method $node.name', node.pos)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
g.error('unable to find function $node.name', node.pos)
|
if fn_def := g.table.find_fn(node.name) {
|
||||||
|
mut muttable := unsafe { &ast.Table(g.table) }
|
||||||
|
if utyp := muttable.resolve_generic_to_concrete(arr_info.elem_type,
|
||||||
|
fn_def.generic_names, node.concrete_types)
|
||||||
|
{
|
||||||
|
arr_info.elem_type = utyp
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
g.error('unable to find function $node.name', node.pos)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
elem_type := g.typ(arr_info.elem_type)
|
elem_type := g.typ(arr_info.elem_type)
|
||||||
|
|
|
@ -78,7 +78,8 @@ fn (mut g Gen) if_expr(node ast.IfExpr) {
|
||||||
g.write(' ? ')
|
g.write(' ? ')
|
||||||
}
|
}
|
||||||
prev_expected_cast_type := g.expected_cast_type
|
prev_expected_cast_type := g.expected_cast_type
|
||||||
if node.is_expr && g.table.sym(node.typ).kind == .sum_type {
|
if node.is_expr
|
||||||
|
&& (g.table.sym(node.typ).kind == .sum_type || node.typ.has_flag(.shared_f)) {
|
||||||
g.expected_cast_type = node.typ
|
g.expected_cast_type = node.typ
|
||||||
}
|
}
|
||||||
g.stmts(branch.stmts)
|
g.stmts(branch.stmts)
|
||||||
|
@ -204,7 +205,8 @@ fn (mut g Gen) if_expr(node ast.IfExpr) {
|
||||||
}
|
}
|
||||||
if needs_tmp_var {
|
if needs_tmp_var {
|
||||||
prev_expected_cast_type := g.expected_cast_type
|
prev_expected_cast_type := g.expected_cast_type
|
||||||
if node.is_expr && g.table.sym(node.typ).kind == .sum_type {
|
if node.is_expr
|
||||||
|
&& (g.table.sym(node.typ).kind == .sum_type || node.typ.has_flag(.shared_f)) {
|
||||||
g.expected_cast_type = node.typ
|
g.expected_cast_type = node.typ
|
||||||
}
|
}
|
||||||
g.stmts_with_tmp_var(branch.stmts, tmp)
|
g.stmts_with_tmp_var(branch.stmts, tmp)
|
||||||
|
|
|
@ -172,8 +172,7 @@ fn (mut g Gen) index_of_array(node ast.IndexExpr, sym ast.TypeSymbol) {
|
||||||
}
|
}
|
||||||
// `vals[i].field = x` is an exception and requires `array_get`:
|
// `vals[i].field = x` is an exception and requires `array_get`:
|
||||||
// `(*(Val*)array_get(vals, i)).field = x;`
|
// `(*(Val*)array_get(vals, i)).field = x;`
|
||||||
is_selector := node.left is ast.SelectorExpr
|
if g.is_assign_lhs && node.is_setter {
|
||||||
if g.is_assign_lhs && !is_selector && node.is_setter {
|
|
||||||
is_direct_array_access := (g.fn_decl != 0 && g.fn_decl.is_direct_arr) || node.is_direct
|
is_direct_array_access := (g.fn_decl != 0 && g.fn_decl.is_direct_arr) || node.is_direct
|
||||||
is_op_assign := g.assign_op != .assign && info.elem_type != ast.string_type
|
is_op_assign := g.assign_op != .assign && info.elem_type != ast.string_type
|
||||||
if is_direct_array_access {
|
if is_direct_array_access {
|
||||||
|
|
|
@ -201,21 +201,25 @@ fn (mut g Gen) infix_expr_eq_op(node ast.InfixExpr) {
|
||||||
g.write(')')
|
g.write(')')
|
||||||
}
|
}
|
||||||
.struct_ {
|
.struct_ {
|
||||||
ptr_typ := g.equality_fn(left.unaliased)
|
if g.pref.translated {
|
||||||
if node.op == .ne {
|
g.gen_plain_infix_expr(node)
|
||||||
g.write('!')
|
} else {
|
||||||
|
ptr_typ := g.equality_fn(left.unaliased)
|
||||||
|
if node.op == .ne {
|
||||||
|
g.write('!')
|
||||||
|
}
|
||||||
|
g.write('${ptr_typ}_struct_eq(')
|
||||||
|
if left.typ.is_ptr() {
|
||||||
|
g.write('*')
|
||||||
|
}
|
||||||
|
g.expr(node.left)
|
||||||
|
g.write(', ')
|
||||||
|
if right.typ.is_ptr() {
|
||||||
|
g.write('*')
|
||||||
|
}
|
||||||
|
g.expr(node.right)
|
||||||
|
g.write(')')
|
||||||
}
|
}
|
||||||
g.write('${ptr_typ}_struct_eq(')
|
|
||||||
if left.typ.is_ptr() {
|
|
||||||
g.write('*')
|
|
||||||
}
|
|
||||||
g.expr(node.left)
|
|
||||||
g.write(', ')
|
|
||||||
if right.typ.is_ptr() {
|
|
||||||
g.write('*')
|
|
||||||
}
|
|
||||||
g.expr(node.right)
|
|
||||||
g.write(')')
|
|
||||||
}
|
}
|
||||||
.sum_type {
|
.sum_type {
|
||||||
ptr_typ := g.equality_fn(left.unaliased)
|
ptr_typ := g.equality_fn(left.unaliased)
|
||||||
|
|
|
@ -46,18 +46,7 @@ fn (mut g Gen) struct_init(node ast.StructInit) {
|
||||||
g.write('($styp){')
|
g.write('($styp){')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// mut fields := []string{}
|
mut inited_fields := map[string]int{}
|
||||||
mut inited_fields := map[string]int{} // TODO this is done in checker, move to ast node
|
|
||||||
/*
|
|
||||||
if node.fields.len == 0 && node.exprs.len > 0 {
|
|
||||||
// Get fields for {a,b} short syntax. Fields array wasn't set in the parser.
|
|
||||||
for f in info.fields {
|
|
||||||
fields << f.name
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
fields = node.fields
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
if is_multiline {
|
if is_multiline {
|
||||||
g.indent++
|
g.indent++
|
||||||
}
|
}
|
||||||
|
@ -149,8 +138,6 @@ fn (mut g Gen) struct_init(node ast.StructInit) {
|
||||||
}
|
}
|
||||||
g.is_shared = old_is_shared2
|
g.is_shared = old_is_shared2
|
||||||
}
|
}
|
||||||
// g.zero_struct_fields(info, inited_fields)
|
|
||||||
// nr_fields = info.fields.len
|
|
||||||
for mut field in info.fields {
|
for mut field in info.fields {
|
||||||
if !field.typ.has_flag(.shared_f) {
|
if !field.typ.has_flag(.shared_f) {
|
||||||
g.is_shared = false
|
g.is_shared = false
|
||||||
|
@ -183,6 +170,9 @@ fn (mut g Gen) struct_init(node ast.StructInit) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !cloned {
|
if !cloned {
|
||||||
|
inside_cast_in_heap := g.inside_cast_in_heap
|
||||||
|
g.inside_cast_in_heap = 0 // prevent use of pointers in child structs
|
||||||
|
|
||||||
if field_type_sym.kind == .array_fixed && sfield.expr is ast.Ident {
|
if field_type_sym.kind == .array_fixed && sfield.expr is ast.Ident {
|
||||||
fixed_array_info := field_type_sym.info as ast.ArrayFixed
|
fixed_array_info := field_type_sym.info as ast.ArrayFixed
|
||||||
g.write('{')
|
g.write('{')
|
||||||
|
@ -202,6 +192,7 @@ fn (mut g Gen) struct_init(node ast.StructInit) {
|
||||||
}
|
}
|
||||||
g.expr_with_cast(sfield.expr, sfield.typ, sfield.expected_type)
|
g.expr_with_cast(sfield.expr, sfield.typ, sfield.expected_type)
|
||||||
}
|
}
|
||||||
|
g.inside_cast_in_heap = inside_cast_in_heap // restore value for further struct inits
|
||||||
}
|
}
|
||||||
if is_multiline {
|
if is_multiline {
|
||||||
g.writeln(',')
|
g.writeln(',')
|
||||||
|
|
|
@ -378,6 +378,11 @@ fn (mut w Walker) expr(node_ ast.Expr) {
|
||||||
}
|
}
|
||||||
ast.SelectorExpr {
|
ast.SelectorExpr {
|
||||||
w.expr(node.expr)
|
w.expr(node.expr)
|
||||||
|
if node.expr_type != 0 {
|
||||||
|
if method := w.table.find_method(w.table.sym(node.expr_type), node.field_name) {
|
||||||
|
w.fn_by_name(method.fkey())
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
ast.SqlExpr {
|
ast.SqlExpr {
|
||||||
w.expr(node.db_expr)
|
w.expr(node.db_expr)
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
vlib/v/parser/tests/dollar_err.vv:1:1: error: unexpected eof, expecting `if`
|
vlib/v/parser/tests/dollar_err.vv:1:1: error: unexpected eof
|
||||||
1 | $
|
1 | $
|
||||||
| ^
|
| ^
|
||||||
|
|
|
@ -287,13 +287,13 @@ fn vweb_tmpl_${fn_name}() string {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.js {
|
.js {
|
||||||
if line.contains('//V_TEMPLATE') {
|
// if line.contains('//V_TEMPLATE') {
|
||||||
source.writeln(insert_template_code(fn_name, tmpl_str_start, line))
|
source.writeln(insert_template_code(fn_name, tmpl_str_start, line))
|
||||||
} else {
|
//} else {
|
||||||
// replace `$` to `\$` at first to escape JavaScript template literal syntax
|
// replace `$` to `\$` at first to escape JavaScript template literal syntax
|
||||||
source.writeln(line.replace(r'$', r'\$').replace(r'$$', r'@').replace(r'.$',
|
// source.writeln(line.replace(r'$', r'\$').replace(r'$$', r'@').replace(r'.$',
|
||||||
r'.@').replace(r"'", r"\'"))
|
// r'.@').replace(r"'", r"\'"))
|
||||||
}
|
//}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
.css {
|
.css {
|
||||||
|
|
|
@ -0,0 +1,43 @@
|
||||||
|
struct Vec {
|
||||||
|
mut:
|
||||||
|
x f64
|
||||||
|
y f64
|
||||||
|
z f64
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Plane {
|
||||||
|
position Vec
|
||||||
|
normal Vec
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Sphere {
|
||||||
|
position Vec
|
||||||
|
radius f64
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Object {
|
||||||
|
position Vec
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_append_struct_to_interface_array() {
|
||||||
|
mut scene := []Object{}
|
||||||
|
|
||||||
|
scene << Plane{
|
||||||
|
position: Vec{0, -10, 0}
|
||||||
|
normal: Vec{0, -1, 0}
|
||||||
|
}
|
||||||
|
scene << Sphere{
|
||||||
|
position: Vec{0, 0, -20}
|
||||||
|
radius: 7
|
||||||
|
}
|
||||||
|
|
||||||
|
println(scene)
|
||||||
|
|
||||||
|
assert scene.len == 2
|
||||||
|
assert scene[0].position.x == 0
|
||||||
|
assert scene[0].position.y == -10
|
||||||
|
assert scene[0].position.z == 0
|
||||||
|
assert scene[1].position.x == 0
|
||||||
|
assert scene[1].position.y == 0
|
||||||
|
assert scene[1].position.z == -20
|
||||||
|
}
|
|
@ -60,7 +60,11 @@ fn main() {
|
||||||
(aa % gcd) == big.zero_int,
|
(aa % gcd) == big.zero_int,
|
||||||
(bb % gcd) == big.zero_int,
|
(bb % gcd) == big.zero_int,
|
||||||
].all(it == true)
|
].all(it == true)
|
||||||
{ true } else { false }
|
{
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
cfgs := [
|
cfgs := [
|
||||||
|
|
|
@ -0,0 +1,17 @@
|
||||||
|
struct Foo<T> {
|
||||||
|
mut:
|
||||||
|
arr []T
|
||||||
|
}
|
||||||
|
|
||||||
|
fn (mut foo Foo<T>) push<T>(items ...T) {
|
||||||
|
for item in items {
|
||||||
|
foo.arr << item
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_generic_method_with_variadic_args() {
|
||||||
|
mut f := Foo<int>{}
|
||||||
|
f.push(1, 2, 3, 5, 8, 13, 21, 34, 55)
|
||||||
|
println(f.arr)
|
||||||
|
assert f.arr == [1, 2, 3, 5, 8, 13, 21, 34, 55]
|
||||||
|
}
|
|
@ -9,6 +9,11 @@ import v.util.vtest
|
||||||
|
|
||||||
const turn_off_vcolors = os.setenv('VCOLORS', 'never', true)
|
const turn_off_vcolors = os.setenv('VCOLORS', 'never', true)
|
||||||
|
|
||||||
|
const skip_files = [
|
||||||
|
'do_not_remove_this',
|
||||||
|
'tmpl_parse_html.vv', // skipped, due to a V template compilation problem after b42c824
|
||||||
|
]
|
||||||
|
|
||||||
fn test_all() {
|
fn test_all() {
|
||||||
mut total_errors := 0
|
mut total_errors := 0
|
||||||
vexe := os.getenv('VEXE')
|
vexe := os.getenv('VEXE')
|
||||||
|
@ -25,6 +30,11 @@ fn test_all() {
|
||||||
paths := vtest.filter_vtest_only(tests, basepath: dir)
|
paths := vtest.filter_vtest_only(tests, basepath: dir)
|
||||||
for path in paths {
|
for path in paths {
|
||||||
print(path + ' ')
|
print(path + ' ')
|
||||||
|
fname := os.file_name(path)
|
||||||
|
if fname in skip_files {
|
||||||
|
println(term.bright_yellow('SKIP'))
|
||||||
|
continue
|
||||||
|
}
|
||||||
program := path
|
program := path
|
||||||
tname := rand.ulid()
|
tname := rand.ulid()
|
||||||
compilation := os.execute('${os.quoted_path(vexe)} -o $tname -cflags "-w" -cg ${os.quoted_path(program)}')
|
compilation := os.execute('${os.quoted_path(vexe)} -o $tname -cflags "-w" -cg ${os.quoted_path(program)}')
|
||||||
|
|
|
@ -0,0 +1,119 @@
|
||||||
|
struct Foo {
|
||||||
|
s string
|
||||||
|
mut:
|
||||||
|
i int
|
||||||
|
}
|
||||||
|
|
||||||
|
fn (f Foo) get_s() string {
|
||||||
|
return f.s
|
||||||
|
}
|
||||||
|
|
||||||
|
fn (f &Foo) get_s_ref() string {
|
||||||
|
return f.s
|
||||||
|
}
|
||||||
|
|
||||||
|
fn (f Foo) add(a int) int {
|
||||||
|
return a + f.i
|
||||||
|
}
|
||||||
|
|
||||||
|
fn (f &Foo) add_ref(a int) int {
|
||||||
|
return a + f.i
|
||||||
|
}
|
||||||
|
|
||||||
|
fn (mut f Foo) set(a int) {
|
||||||
|
f.i = a
|
||||||
|
}
|
||||||
|
|
||||||
|
fn (f_ Foo) set_val(a int) int {
|
||||||
|
mut f := unsafe { &f_ }
|
||||||
|
old := f.i
|
||||||
|
f.i = a
|
||||||
|
return old
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_methods_as_fields() {
|
||||||
|
mut f := Foo{
|
||||||
|
s: 'hello'
|
||||||
|
i: 1
|
||||||
|
}
|
||||||
|
|
||||||
|
get_s := f.get_s
|
||||||
|
get_s_ref := unsafe { f.get_s_ref }
|
||||||
|
add := f.add
|
||||||
|
add_ref := unsafe { f.add_ref }
|
||||||
|
set := unsafe { f.set }
|
||||||
|
set_val := f.set_val
|
||||||
|
|
||||||
|
assert typeof(get_s).str() == 'fn () string'
|
||||||
|
assert typeof(get_s_ref).str() == 'fn () string'
|
||||||
|
assert typeof(add).str() == 'fn (int) int'
|
||||||
|
assert typeof(add_ref).str() == 'fn (int) int'
|
||||||
|
|
||||||
|
assert get_s() == 'hello'
|
||||||
|
assert get_s_ref() == 'hello'
|
||||||
|
assert add(2) == 3
|
||||||
|
assert add_ref(2) == 3
|
||||||
|
|
||||||
|
assert f.i == 1
|
||||||
|
set(2)
|
||||||
|
assert f.i == 2
|
||||||
|
old := set_val(3)
|
||||||
|
assert f.i == 2
|
||||||
|
new := set_val(5)
|
||||||
|
assert old == new && old == 1
|
||||||
|
}
|
||||||
|
|
||||||
|
// the difference between these two tests is that here `f` is &Foo
|
||||||
|
fn test_methods_as_fields_ref() {
|
||||||
|
mut f := &Foo{
|
||||||
|
s: 'hello'
|
||||||
|
i: 1
|
||||||
|
}
|
||||||
|
|
||||||
|
get_s := f.get_s
|
||||||
|
get_s_ref := unsafe { f.get_s_ref }
|
||||||
|
add := f.add
|
||||||
|
add_ref := unsafe { f.add_ref }
|
||||||
|
set := unsafe { f.set }
|
||||||
|
set_val := f.set_val
|
||||||
|
|
||||||
|
assert typeof(get_s).str() == 'fn () string'
|
||||||
|
assert typeof(get_s_ref).str() == 'fn () string'
|
||||||
|
assert typeof(add).str() == 'fn (int) int'
|
||||||
|
assert typeof(add_ref).str() == 'fn (int) int'
|
||||||
|
|
||||||
|
assert get_s() == 'hello'
|
||||||
|
assert get_s_ref() == 'hello'
|
||||||
|
assert add(2) == 3
|
||||||
|
assert add_ref(2) == 3
|
||||||
|
|
||||||
|
assert f.i == 1
|
||||||
|
set(2)
|
||||||
|
assert f.i == 2
|
||||||
|
old := set_val(3)
|
||||||
|
assert f.i == 2
|
||||||
|
new := set_val(5)
|
||||||
|
assert old == new && old == 1
|
||||||
|
}
|
||||||
|
|
||||||
|
struct GG_Ctx {
|
||||||
|
frame_fn fn (voidptr) int
|
||||||
|
}
|
||||||
|
|
||||||
|
[heap]
|
||||||
|
struct App {
|
||||||
|
msg string = 'hello'
|
||||||
|
}
|
||||||
|
|
||||||
|
fn (app &App) frame() int {
|
||||||
|
return app.msg.len
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_ctx_arg_expected() {
|
||||||
|
mut app := &App{}
|
||||||
|
mut ctx := &GG_Ctx{
|
||||||
|
frame_fn: app.frame
|
||||||
|
}
|
||||||
|
assert typeof(ctx.frame_fn).str() == 'fn (voidptr) int'
|
||||||
|
assert ctx.frame_fn(app) == 5
|
||||||
|
}
|
|
@ -0,0 +1,19 @@
|
||||||
|
type AA = bool | int
|
||||||
|
|
||||||
|
fn test_shared_if_expr() {
|
||||||
|
shared a := [1, 2, 3]
|
||||||
|
b := [4, 5, 6]
|
||||||
|
c := lock a {
|
||||||
|
if a == b { a } else { b }
|
||||||
|
}
|
||||||
|
assert c == [4, 5, 6]
|
||||||
|
d := lock a {
|
||||||
|
if a != b {
|
||||||
|
a << 5
|
||||||
|
a
|
||||||
|
} else {
|
||||||
|
b
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assert d == [1, 2, 3, 5]
|
||||||
|
}
|
|
@ -0,0 +1,12 @@
|
||||||
|
struct Foo {
|
||||||
|
x int
|
||||||
|
}
|
||||||
|
|
||||||
|
fn (f Foo) hi() int {
|
||||||
|
return f.x
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
f := Foo{123}
|
||||||
|
_ = f.hi
|
||||||
|
}
|
|
@ -0,0 +1,17 @@
|
||||||
|
struct App {
|
||||||
|
mut:
|
||||||
|
buffer []string
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_struct_field_array_index() {
|
||||||
|
mut app := &App{
|
||||||
|
buffer: []string{len: 2}
|
||||||
|
}
|
||||||
|
|
||||||
|
app.buffer[0] += 'hello'
|
||||||
|
app.buffer[1] += 'world'
|
||||||
|
|
||||||
|
println(app)
|
||||||
|
|
||||||
|
assert app.buffer == ['hello', 'world']
|
||||||
|
}
|
|
@ -20,8 +20,8 @@ fn test_template_interpolation_can_be_selectively_turned_on_in_script_tags() {
|
||||||
text := $tmpl('tmpl/selective_interpolation_in_script_tag.html')
|
text := $tmpl('tmpl/selective_interpolation_in_script_tag.html')
|
||||||
dump(text)
|
dump(text)
|
||||||
assert text.contains('Username: abcd')
|
assert text.contains('Username: abcd')
|
||||||
assert text.contains('var non_interpolated_labels = @benchmark_plot_data.dates;')
|
assert text.contains("var non_interpolated_labels = ['2012-11-30', '2022-12-29'];")
|
||||||
assert text.contains('var non_interpolated_values = @benchmark_plot_data.numerical_result;')
|
assert text.contains('var non_interpolated_values = [5, 6, 7, 1];')
|
||||||
assert text.contains("var real_labels = ['2012-11-30', '2022-12-29']; //V_TEMPLATE")
|
assert text.contains("var real_labels = ['2012-11-30', '2022-12-29']; //V_TEMPLATE")
|
||||||
assert text.contains('var real_values = [5, 6, 7, 1]; //V_TEMPLATE')
|
assert text.contains('var real_values = [5, 6, 7, 1]; //V_TEMPLATE')
|
||||||
assert text.contains('Year: 2022')
|
assert text.contains('Year: 2022')
|
||||||
|
|
Loading…
Reference in New Issue