Compare commits
24 Commits
32d7ae7835
...
9d764cd25e
| Author | SHA1 | Date |
|---|---|---|
|
|
9d764cd25e | |
|
|
4dd35da9b0 | |
|
|
73260c6fc0 | |
|
|
80c278222c | |
|
|
864a4ffa6c | |
|
|
13e2d73339 | |
|
|
262ec40851 | |
|
|
47ae5a93d4 | |
|
|
1a76b50004 | |
|
|
1e42538e22 | |
|
|
43e810024c | |
|
|
1cb4fe5a0a | |
|
|
5ec0820332 | |
|
|
81a178ee8d | |
|
|
9abf3a62c0 | |
|
|
f7dbbba7ae | |
|
|
fac15fb862 | |
|
|
ae3906141d | |
|
|
9c7da323f1 | |
|
|
9c9b50933c | |
|
|
0065dba88a | |
|
|
f3ce968124 | |
|
|
b03aa06152 | |
|
|
43efdd464e |
|
|
@ -429,7 +429,7 @@ jobs:
|
|||
- name: Test new v.c
|
||||
run: |
|
||||
.\v.exe -o v.c cmd/v
|
||||
gcc -Werror -I ./thirdparty/stdatomic/win -municode -w v.c
|
||||
gcc -Werror -municode -w v.c
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
.\v.exe setup-freetype
|
||||
|
|
@ -534,7 +534,7 @@ jobs:
|
|||
- name: Test new v.c
|
||||
run: |
|
||||
.\v.exe -o v.c cmd/v
|
||||
.\thirdparty\tcc\tcc.exe -I ./thirdparty/stdatomic/win -Werror -w -ladvapi32 -bt10 v.c
|
||||
.\thirdparty\tcc\tcc.exe -Werror -w -ladvapi32 -bt10 v.c
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
.\v.exe setup-freetype
|
||||
|
|
@ -575,7 +575,7 @@ jobs:
|
|||
## .\v.exe wipe-cache
|
||||
## .\make.bat -tcc32
|
||||
## - name: Test new v.c
|
||||
## run: .\v.exe -o v.c cmd/v && .\thirdparty\tcc\tcc.exe -I ./thirdparty/stdatomic/win -Werror -g -w -ladvapi32 -bt10 v.c
|
||||
## run: .\v.exe -o v.c cmd/v && .\thirdparty\tcc\tcc.exe -Werror -g -w -ladvapi32 -bt10 v.c
|
||||
## - name: v doctor
|
||||
## run: ./v doctor
|
||||
##
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ jobs:
|
|||
timeout-minutes: 30
|
||||
env:
|
||||
VFLAGS: -cc tcc -no-retry-compilation
|
||||
B_CFLAGS: -g -std=gnu11 -I ./thirdparty/stdatomic/nix -w
|
||||
B_CFLAGS: -g -std=gnu11 -w
|
||||
B_LFLAGS: -lm -lpthread
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
|
@ -52,7 +52,7 @@ jobs:
|
|||
timeout-minutes: 30
|
||||
env:
|
||||
VFLAGS: -cc clang
|
||||
B_CFLAGS: -g -std=gnu11 -I ./thirdparty/stdatomic/nix -w
|
||||
B_CFLAGS: -g -std=gnu11 -w
|
||||
B_LFLAGS: -lm -lpthread
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
|
|
|||
|
|
@ -71,14 +71,14 @@ jobs:
|
|||
- name: v.c can be compiled and run with -os cross
|
||||
run: |
|
||||
./v -os cross -o /tmp/v.c cmd/v
|
||||
gcc -g -std=gnu11 -I ./thirdparty/stdatomic/nix -w -o v_from_vc /tmp/v.c -lm -lpthread
|
||||
gcc -g -std=gnu11 -w -o v_from_vc /tmp/v.c -lm -lpthread
|
||||
ls -lart v_from_vc
|
||||
./v_from_vc version
|
||||
|
||||
- name: v_win.c can be compiled and run with -os windows
|
||||
run: |
|
||||
./v -cc msvc -os windows -o /tmp/v_win.c cmd/v
|
||||
x86_64-w64-mingw32-gcc -I ./thirdparty/stdatomic/win /tmp/v_win.c -std=c99 -w -municode -o v_from_vc.exe
|
||||
x86_64-w64-mingw32-gcc /tmp/v_win.c -std=c99 -w -municode -o v_from_vc.exe
|
||||
ls -lart v_from_vc.exe
|
||||
wine64 ./v_from_vc.exe version
|
||||
|
||||
|
|
|
|||
|
|
@ -210,7 +210,7 @@ jobs:
|
|||
|
||||
## gitly
|
||||
- name: Install markdown
|
||||
run: ./v 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
|
||||
|
|
@ -222,6 +222,15 @@ jobs:
|
|||
./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
|
||||
|
|
@ -234,18 +243,6 @@ jobs:
|
|||
- name: Run Vex Tests
|
||||
run: ./v test ~/.vmodules/nedpals/vex
|
||||
|
||||
## vpm modules
|
||||
- name: Install UI through VPM
|
||||
run: ./v install ui
|
||||
|
||||
## libsodium
|
||||
- name: Install libsodium-dev package
|
||||
run: sudo apt-get install --quiet -y libsodium-dev
|
||||
- name: Installl the libsodium wrapper through VPM
|
||||
run: ./v install libsodium
|
||||
- name: Test libsodium
|
||||
run: VJOBS=1 ./v -stats test ~/.vmodules/libsodium
|
||||
|
||||
## Go2V
|
||||
- name: Clone & Build go2v
|
||||
run: git clone --depth=1 https://github.com/vlang/go2v go2v/
|
||||
|
|
@ -259,3 +256,7 @@ jobs:
|
|||
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
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
FROM mstorsjo/llvm-mingw
|
||||
|
||||
LABEL maintainer="Vitaly Takmazov <vitalyster@gmail.com>"
|
||||
LABEL maintainer="Delyan Angelov <delian66@gmail.com>"
|
||||
COPY . .
|
||||
RUN make
|
||||
RUN ./v -os windows -o v.c cmd/v
|
||||
RUN x86_64-w64-mingw32-gcc v.c -std=c99 -I ./thirdparty/stdatomic/win -w -municode -o v.exe
|
||||
RUN x86_64-w64-mingw32-gcc v.c -std=c99 -w -municode -o v.exe
|
||||
RUN file v.exe
|
||||
|
||||
CMD [ "bash" ]
|
||||
|
|
|
|||
|
|
@ -84,13 +84,13 @@ endif
|
|||
|
||||
all: latest_vc latest_tcc
|
||||
ifdef WIN32
|
||||
$(CC) $(CFLAGS) -std=c99 -municode -w -I ./thirdparty/stdatomic/nix -o v1.exe $(VC)/$(VCFILE) $(LDFLAGS)
|
||||
$(CC) $(CFLAGS) -std=c99 -municode -w -o v1.exe $(VC)/$(VCFILE) $(LDFLAGS)
|
||||
v1.exe -no-parallel -o v2.exe $(VFLAGS) cmd/v
|
||||
v2.exe -o $(V) $(VFLAGS) cmd/v
|
||||
del v1.exe
|
||||
del v2.exe
|
||||
else
|
||||
$(CC) $(CFLAGS) -std=gnu99 -w -I ./thirdparty/stdatomic/nix -o v1.exe $(VC)/$(VCFILE) -lm -lpthread $(LDFLAGS)
|
||||
$(CC) $(CFLAGS) -std=gnu99 -w -o v1.exe $(VC)/$(VCFILE) -lm -lpthread $(LDFLAGS)
|
||||
./v1.exe -no-parallel -o v2.exe $(VFLAGS) cmd/v
|
||||
./v2.exe -o $(V) $(VFLAGS) cmd/v
|
||||
rm -rf v1.exe v2.exe
|
||||
|
|
|
|||
2
Makefile
2
Makefile
|
|
@ -6,7 +6,7 @@ LDFLAGS ?=
|
|||
all:
|
||||
rm -rf vc/
|
||||
git clone --depth 1 --quiet https://git.rustybever.be/Chewing_Bever/vc
|
||||
$(CC) $(CFLAGS) -std=gnu11 -w -I ./thirdparty/stdatomic/nix -o v1 vc/v.c -lm -lexecinfo -lpthread $(LDFLAGS)
|
||||
$(CC) $(CFLAGS) -std=gnu11 -w -o v1 vc/v.c -lm -lexecinfo -lpthread $(LDFLAGS)
|
||||
./v1 -no-parallel -o v2 $(VFLAGS) cmd/v
|
||||
./v2 -o v $(VFLAGS) cmd/v
|
||||
rm -rf v1 v2 vc/
|
||||
|
|
|
|||
|
|
@ -28,7 +28,8 @@ fn main() {
|
|||
return
|
||||
}
|
||||
}
|
||||
// Fetch the last commit's hash
|
||||
|
||||
// fetch the last commit's hash
|
||||
commit := exec('git rev-parse HEAD')[..8]
|
||||
if !os.exists('table.html') {
|
||||
os.create('table.html') ?
|
||||
|
|
@ -42,13 +43,10 @@ fn main() {
|
|||
return
|
||||
}
|
||||
}
|
||||
// for i, commit in commits {
|
||||
message := exec('git log --pretty=format:"%s" -n1 $commit')
|
||||
// println('\n${i + 1}/$commits.len Benchmarking commit $commit "$message"')
|
||||
println('\nBenchmarking commit $commit "$message"')
|
||||
// Build an optimized V
|
||||
// println('Checking out ${commit}...')
|
||||
// exec('git checkout $commit')
|
||||
|
||||
// build an optimized V
|
||||
println(' Building vprod...')
|
||||
os.chdir(vdir) ?
|
||||
if os.args.contains('-noprod') {
|
||||
|
|
@ -56,9 +54,11 @@ fn main() {
|
|||
} else {
|
||||
exec('./v -o vprod -prod -prealloc cmd/v')
|
||||
}
|
||||
|
||||
// cache vlib modules
|
||||
exec('$vdir/v wipe-cache')
|
||||
exec('$vdir/v -o v2 -prod cmd/v')
|
||||
|
||||
// measure
|
||||
diff1 := measure('$vdir/vprod $voptions -o v.c cmd/v', 'v.c')
|
||||
mut tcc_path := 'tcc'
|
||||
|
|
@ -71,23 +71,24 @@ fn main() {
|
|||
if os.args.contains('-clang') {
|
||||
tcc_path = 'clang'
|
||||
}
|
||||
|
||||
diff2 := measure('$vdir/vprod $voptions -cc $tcc_path -o v2 cmd/v', 'v2')
|
||||
diff3 := 0 // measure('$vdir/vprod -native $vdir/cmd/tools/1mil.v', 'native 1mil')
|
||||
diff4 := measure('$vdir/vprod -usecache $voptions -cc clang examples/hello_world.v',
|
||||
'hello.v')
|
||||
vc_size := os.file_size('v.c') / 1000
|
||||
// scan/parse/check/cgen
|
||||
scan, parse, check, cgen, vlines := measure_steps(vdir)
|
||||
// println('Building V took ${diff}ms')
|
||||
|
||||
commit_date := exec('git log -n1 --pretty="format:%at" $commit')
|
||||
date := time.unix(commit_date.int())
|
||||
//
|
||||
|
||||
os.chdir(fast_dir) ?
|
||||
mut out := os.create('table.html') ?
|
||||
// Place the new row on top
|
||||
|
||||
// place the new row on top
|
||||
html_message := message.replace_each(['<', '<', '>', '>'])
|
||||
table =
|
||||
'<tr>
|
||||
' <tr>
|
||||
<td>$date.format()</td>
|
||||
<td><a target=_blank href="https://github.com/vlang/v/commit/$commit">$commit</a></td>
|
||||
<td>$html_message</td>
|
||||
|
|
@ -106,7 +107,8 @@ fn main() {
|
|||
table.trim_space()
|
||||
out.writeln(table) ?
|
||||
out.close()
|
||||
// Regenerate index.html
|
||||
|
||||
// regenerate index.html
|
||||
header := os.read_file('header.html') ?
|
||||
footer := os.read_file('footer.html') ?
|
||||
mut res := os.create('index.html') ?
|
||||
|
|
@ -114,10 +116,8 @@ fn main() {
|
|||
res.writeln(table) ?
|
||||
res.writeln(footer) ?
|
||||
res.close()
|
||||
//}
|
||||
// exec('git checkout master')
|
||||
// os.write_file('last_commit.txt', commits[commits.len - 1]) ?
|
||||
// Upload the result to github pages
|
||||
|
||||
// upload the result to github pages
|
||||
if os.args.contains('-upload') {
|
||||
println('uploading...')
|
||||
os.chdir('website') ?
|
||||
|
|
@ -134,7 +134,7 @@ fn exec(s string) string {
|
|||
return e.output.trim_right('\r\n')
|
||||
}
|
||||
|
||||
// returns milliseconds
|
||||
// measure returns milliseconds
|
||||
fn measure(cmd string, description string) int {
|
||||
println(' Measuring $description')
|
||||
println(' Warming up...')
|
||||
|
|
@ -186,7 +186,7 @@ fn measure_steps(vdir string) (int, int, int, int, int) {
|
|||
cgen = line[0].int()
|
||||
}
|
||||
} else {
|
||||
// Fetch number of V lines
|
||||
// fetch number of V lines
|
||||
if line[0].contains('V') && line[0].contains('source') && line[0].contains('size') {
|
||||
start := line[0].index(':') or { 0 }
|
||||
end := line[0].index('lines,') or { 0 }
|
||||
|
|
|
|||
|
|
@ -584,17 +584,22 @@ fn get_all_modules() []string {
|
|||
mut read_len := 0
|
||||
mut modules := []string{}
|
||||
for read_len < s.len {
|
||||
mut start_token := '<a href="/mod'
|
||||
mut start_token := "<a href='/mod"
|
||||
end_token := '</a>'
|
||||
// get the start index of the module entry
|
||||
mut start_index := s.index_after(start_token, read_len)
|
||||
if start_index == -1 {
|
||||
break
|
||||
start_token = '<a href="/mod'
|
||||
start_index = s.index_after(start_token, read_len)
|
||||
if start_index == -1 {
|
||||
break
|
||||
}
|
||||
}
|
||||
// get the index of the end of anchor (a) opening tag
|
||||
// we use the previous start_index to make sure we are getting a module and not just a random 'a' tag
|
||||
start_token = '">'
|
||||
start_token = '>'
|
||||
start_index = s.index_after(start_token, start_index) + start_token.len
|
||||
|
||||
// get the index of the end of module entry
|
||||
end_index := s.index_after(end_token, start_index)
|
||||
if end_index == -1 {
|
||||
|
|
|
|||
|
|
@ -81,6 +81,18 @@ fn get_all_commands() []Command {
|
|||
runcmd: .execute
|
||||
expect: 'Hello, World!\n'
|
||||
}
|
||||
if os.getenv('V_CI_MUSL').len == 0 {
|
||||
for compiler_name in ['clang', 'gcc'] {
|
||||
if _ := os.find_abs_path_of_executable(compiler_name) {
|
||||
res << Command{
|
||||
line: '$vexe -cc $compiler_name -gc boehm run examples/hello_world.v'
|
||||
okmsg: '`v -cc $compiler_name -gc boehm run examples/hello_world.v` works'
|
||||
runcmd: .execute
|
||||
expect: 'Hello, World!\n'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
res << Command{
|
||||
line: '$vexe interpret examples/hello_world.v'
|
||||
okmsg: 'V can interpret hello world.'
|
||||
|
|
@ -210,9 +222,8 @@ fn get_all_commands() []Command {
|
|||
rmfile: 'examples/tetris/tetris'
|
||||
}
|
||||
$if macos || linux {
|
||||
ipath := '$vroot/thirdparty/stdatomic/nix'
|
||||
res << Command{
|
||||
line: '$vexe -o v.c cmd/v && cc -Werror -I ${os.quoted_path(ipath)} v.c -lpthread -lm && rm -rf a.out'
|
||||
line: '$vexe -o v.c cmd/v && cc -Werror v.c -lpthread -lm && rm -rf a.out'
|
||||
label: 'v.c should be buildable with no warnings...'
|
||||
okmsg: 'v.c can be compiled without warnings. This is good :)'
|
||||
rmfile: 'v.c'
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
# V Documentation
|
||||
|
||||
(See https://modules.vlang.io/ for documentation of V's standard library)
|
||||
|
||||
## Introduction
|
||||
|
||||
V is a statically typed compiled programming language designed for building maintainable software.
|
||||
|
|
|
|||
8
make.bat
8
make.bat
|
|
@ -119,7 +119,7 @@ REM By default, use tcc, since we have it prebuilt:
|
|||
:tcc_strap
|
||||
:tcc32_strap
|
||||
echo ^> Attempting to build v_win.c with "!tcc_exe!"
|
||||
"!tcc_exe!" -Bthirdparty/tcc -Ithirdparty/stdatomic/win -bt10 -g -w -o v.exe vc\v_win.c -ladvapi32
|
||||
"!tcc_exe!" -Bthirdparty/tcc -bt10 -g -w -o v.exe vc\v_win.c -ladvapi32
|
||||
if %ERRORLEVEL% NEQ 0 goto :compile_error
|
||||
echo ^> Compiling .\v.exe with itself
|
||||
v.exe -keepc -g -showcc -cc "!tcc_exe!" -cflags -Bthirdparty/tcc -o v2.exe cmd/v
|
||||
|
|
@ -137,7 +137,7 @@ if %ERRORLEVEL% NEQ 0 (
|
|||
)
|
||||
|
||||
echo ^> Attempting to build v_win.c with Clang
|
||||
clang -std=c99 -Ithirdparty/stdatomic/win -municode -g -w -o v.exe .\vc\v_win.c -ladvapi32
|
||||
clang -std=c99 -municode -g -w -o v.exe .\vc\v_win.c -ladvapi32
|
||||
if %ERRORLEVEL% NEQ 0 (
|
||||
echo In most cases, compile errors happen because the version of Clang installed is too old
|
||||
clang --version
|
||||
|
|
@ -160,7 +160,7 @@ if %ERRORLEVEL% NEQ 0 (
|
|||
)
|
||||
|
||||
echo ^> Attempting to build v_win.c with GCC
|
||||
gcc -std=c99 -municode -Ithirdparty/stdatomic/win -g -w -o v.exe .\vc\v_win.c -ladvapi32
|
||||
gcc -std=c99 -municode -g -w -o v.exe .\vc\v_win.c -ladvapi32
|
||||
if %ERRORLEVEL% NEQ 0 (
|
||||
echo In most cases, compile errors happen because the version of GCC installed is too old
|
||||
gcc --version
|
||||
|
|
@ -202,7 +202,7 @@ if exist "%InstallDir%\Common7\Tools\vsdevcmd.bat" (
|
|||
set ObjFile=.v.c.obj
|
||||
|
||||
echo ^> Attempting to build v_win.c with MSVC
|
||||
cl.exe /volatile:ms /I thirdparty\stdatomic\win /Fo%ObjFile% /O2 /MD /D_VBOOTSTRAP vc\v_win.c user32.lib kernel32.lib advapi32.lib shell32.lib /link /nologo /out:v.exe /incremental:no
|
||||
cl.exe /volatile:ms /Fo%ObjFile% /O2 /MD /D_VBOOTSTRAP vc\v_win.c user32.lib kernel32.lib advapi32.lib shell32.lib /link /nologo /out:v.exe /incremental:no
|
||||
if %ERRORLEVEL% NEQ 0 (
|
||||
echo In some cases, compile errors happen because of the MSVC compiler version
|
||||
cl.exe
|
||||
|
|
|
|||
|
|
@ -32,13 +32,14 @@ $if dynamic_boehm ? {
|
|||
$if macos || linux {
|
||||
#flag -DGC_PTHREADS=1
|
||||
#flag -I@VEXEROOT/thirdparty/libgc/include
|
||||
#flag -lpthread -ldl
|
||||
#flag -lpthread
|
||||
$if (prod && !tinyc && !debug) || !(amd64 || arm64 || i386 || arm32) {
|
||||
// TODO: replace the architecture check with a `!$exists("@VEXEROOT/thirdparty/tcc/lib/libgc.a")` comptime call
|
||||
#flag @VEXEROOT/thirdparty/libgc/gc.o
|
||||
} $else {
|
||||
#flag @VEXEROOT/thirdparty/tcc/lib/libgc.a
|
||||
}
|
||||
#flag -ldl
|
||||
} $else $if freebsd {
|
||||
// Tested on FreeBSD 13.0-RELEASE-p3, with clang, gcc and tcc:
|
||||
#flag -DBUS_PAGE_FAULT=T_PAGEFLT
|
||||
|
|
|
|||
|
|
@ -53,6 +53,7 @@ fn C.chmod(&char, u32) int
|
|||
fn C.printf(&char, ...voidptr) int
|
||||
|
||||
fn C.puts(&char) int
|
||||
fn C.abs(f64) f64
|
||||
|
||||
fn C.fputs(str &char, stream &C.FILE) int
|
||||
|
||||
|
|
|
|||
|
|
@ -775,7 +775,7 @@ fn test_byte_keys() {
|
|||
m[i]++
|
||||
assert m[i] == i + 1
|
||||
}
|
||||
assert m.len == int(byte_max)
|
||||
assert m.len == byte_max
|
||||
keys := m.keys()
|
||||
for i in u8(0) .. byte_max {
|
||||
assert keys[i] == i
|
||||
|
|
@ -827,7 +827,7 @@ fn test_u16_keys() {
|
|||
m[i]++
|
||||
assert m[i] == i + 1
|
||||
}
|
||||
assert m.len == int(end)
|
||||
assert m.len == end
|
||||
keys := m.keys()
|
||||
for i in u16(0) .. end {
|
||||
assert keys[i] == i
|
||||
|
|
|
|||
|
|
@ -763,7 +763,7 @@ fn test_byte_keys() {
|
|||
m[i]++
|
||||
assert m[i] == i + 1
|
||||
}
|
||||
assert m.len == int(byte_max)
|
||||
assert m.len == byte_max
|
||||
keys := m.keys()
|
||||
for i in u8(0) .. byte_max {
|
||||
assert keys[i] == i
|
||||
|
|
@ -815,7 +815,7 @@ fn test_u16_keys() {
|
|||
m[i]++
|
||||
assert m[i] == i + 1
|
||||
}
|
||||
assert m.len == int(end)
|
||||
assert m.len == end
|
||||
keys := m.keys()
|
||||
for i in u16(0) .. end {
|
||||
assert keys[i] == i
|
||||
|
|
|
|||
|
|
@ -1937,7 +1937,7 @@ pub fn (name string) match_glob(pattern string) bool {
|
|||
mut is_inverted := false
|
||||
mut inner_match := false
|
||||
mut inner_idx := bstart + 1
|
||||
mut inner_c := u8(0)
|
||||
mut inner_c := 0
|
||||
if inner_idx < plen {
|
||||
inner_c = pattern[inner_idx]
|
||||
if inner_c == `^` {
|
||||
|
|
|
|||
|
|
@ -113,7 +113,7 @@ fn (bst &BSTree<T>) contains_helper(node &BSTreeNode<T>, value T) bool {
|
|||
|
||||
// remove removes an element with `value` from the BST.
|
||||
pub fn (mut bst BSTree<T>) remove(value T) bool {
|
||||
if bst.root == 0 {
|
||||
if bst.is_empty() {
|
||||
return false
|
||||
}
|
||||
return bst.remove_helper(mut bst.root, value, false)
|
||||
|
|
@ -153,6 +153,9 @@ fn (mut bst BSTree<T>) remove_helper(mut node BSTreeNode<T>, value T, left bool)
|
|||
|
||||
// get_max_from_right returns the max element of the BST following the right branch.
|
||||
fn (bst &BSTree<T>) get_max_from_right(node &BSTreeNode<T>) &BSTreeNode<T> {
|
||||
if node == 0 {
|
||||
return new_none_node<T>(false)
|
||||
}
|
||||
right_node := node.right
|
||||
if right_node == 0 || !right_node.is_init {
|
||||
return node
|
||||
|
|
@ -162,6 +165,9 @@ fn (bst &BSTree<T>) get_max_from_right(node &BSTreeNode<T>) &BSTreeNode<T> {
|
|||
|
||||
// get_min_from_left returns the min element of the BST by following the left branch.
|
||||
fn (bst &BSTree<T>) get_min_from_left(node &BSTreeNode<T>) &BSTreeNode<T> {
|
||||
if node == 0 {
|
||||
return new_none_node<T>(false)
|
||||
}
|
||||
left_node := node.left
|
||||
if left_node == 0 || !left_node.is_init {
|
||||
return node
|
||||
|
|
@ -251,6 +257,9 @@ fn (bst &BSTree<T>) get_node(node &BSTreeNode<T>, value T) &BSTreeNode<T> {
|
|||
// left_value, exist := bst.to_left(10)
|
||||
//```
|
||||
pub fn (bst &BSTree<T>) to_left(value T) ?T {
|
||||
if bst.is_empty() {
|
||||
return none
|
||||
}
|
||||
node := bst.get_node(bst.root, value)
|
||||
if !node.is_init {
|
||||
return none
|
||||
|
|
@ -267,6 +276,9 @@ pub fn (bst &BSTree<T>) to_left(value T) ?T {
|
|||
// left_value, exist := bst.to_right(10)
|
||||
//```
|
||||
pub fn (bst &BSTree<T>) to_right(value T) ?T {
|
||||
if bst.is_empty() {
|
||||
return none
|
||||
}
|
||||
node := bst.get_node(bst.root, value)
|
||||
if !node.is_init {
|
||||
return none
|
||||
|
|
@ -278,6 +290,9 @@ pub fn (bst &BSTree<T>) to_right(value T) ?T {
|
|||
// max return the max element inside the BST.
|
||||
// Time complexity O(N) if the BST is not balanced
|
||||
pub fn (bst &BSTree<T>) max() ?T {
|
||||
if bst.is_empty() {
|
||||
return none
|
||||
}
|
||||
max := bst.get_max_from_right(bst.root)
|
||||
if !max.is_init {
|
||||
return none
|
||||
|
|
@ -288,6 +303,9 @@ pub fn (bst &BSTree<T>) max() ?T {
|
|||
// min return the minimum element in the BST.
|
||||
// Time complexity O(N) if the BST is not balanced.
|
||||
pub fn (bst &BSTree<T>) min() ?T {
|
||||
if bst.is_empty() {
|
||||
return none
|
||||
}
|
||||
min := bst.get_min_from_left(bst.root)
|
||||
if !min.is_init {
|
||||
return none
|
||||
|
|
|
|||
|
|
@ -116,6 +116,7 @@ fn test_remove_from_bst_two() {
|
|||
// check if we are able to get the max from the BST.
|
||||
fn test_get_max_in_bst() {
|
||||
mut bst := BSTree<int>{}
|
||||
assert (bst.max() or { -1 }) == -1
|
||||
assert bst.insert(10)
|
||||
assert bst.insert(20)
|
||||
assert bst.insert(21)
|
||||
|
|
@ -127,6 +128,7 @@ fn test_get_max_in_bst() {
|
|||
// check if we are able to get the min from the BST.
|
||||
fn test_get_min_in_bst() {
|
||||
mut bst := BSTree<int>{}
|
||||
assert (bst.min() or { -1 }) == -1
|
||||
assert bst.insert(10)
|
||||
assert bst.insert(20)
|
||||
assert bst.insert(21)
|
||||
|
|
|
|||
|
|
@ -367,7 +367,8 @@ pub fn expand_tilde_to_home(path string) string {
|
|||
return path
|
||||
}
|
||||
|
||||
// write_file writes `text` data to a file in `path`.
|
||||
// write_file writes `text` data to the file in `path`.
|
||||
// If `path` exists, the contents of `path` will be overwritten with the contents of `text`.
|
||||
pub fn write_file(path string, text string) ? {
|
||||
mut f := create(path) ?
|
||||
unsafe { f.write_full_buffer(text.str, usize(text.len)) ? }
|
||||
|
|
|
|||
|
|
@ -5,8 +5,10 @@ module stdatomic
|
|||
|
||||
$if windows {
|
||||
#flag -I @VEXEROOT/thirdparty/stdatomic/win
|
||||
#insert "@VEXEROOT/thirdparty/stdatomic/win/atomic.h"
|
||||
} $else {
|
||||
#flag -I @VEXEROOT/thirdparty/stdatomic/nix
|
||||
#insert "@VEXEROOT/thirdparty/stdatomic/nix/atomic.h"
|
||||
}
|
||||
|
||||
$if linux {
|
||||
|
|
@ -48,7 +50,6 @@ $if linux {
|
|||
}
|
||||
}
|
||||
|
||||
#include <atomic.h>
|
||||
// The following functions are actually generic in C
|
||||
fn C.atomic_load_ptr(voidptr) voidptr
|
||||
fn C.atomic_store_ptr(voidptr, voidptr)
|
||||
|
|
|
|||
|
|
@ -262,8 +262,7 @@ pub fn (t Type) str() string {
|
|||
}
|
||||
|
||||
pub fn (t &Table) type_str(typ Type) string {
|
||||
sym := t.sym(typ)
|
||||
return sym.name
|
||||
return t.sym(typ).name
|
||||
}
|
||||
|
||||
// debug returns a verbose representation of the information in the type `t`, useful for tracing/debugging
|
||||
|
|
@ -375,7 +374,7 @@ pub fn (typ Type) is_unsigned() bool {
|
|||
}
|
||||
|
||||
pub fn (typ Type) flip_signedness() Type {
|
||||
r := match typ {
|
||||
return match typ {
|
||||
ast.i8_type { ast.byte_type }
|
||||
ast.i16_type { ast.u16_type }
|
||||
ast.int_type { ast.u32_type }
|
||||
|
|
@ -388,7 +387,6 @@ pub fn (typ Type) flip_signedness() Type {
|
|||
ast.u64_type { ast.i64_type }
|
||||
else { typ }
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
[inline]
|
||||
|
|
@ -510,7 +508,7 @@ pub const (
|
|||
)
|
||||
|
||||
pub fn merge_types(params ...[]Type) []Type {
|
||||
mut res := []Type{}
|
||||
mut res := []Type{cap: params.len}
|
||||
for types in params {
|
||||
res << types
|
||||
}
|
||||
|
|
@ -518,10 +516,10 @@ pub fn merge_types(params ...[]Type) []Type {
|
|||
}
|
||||
|
||||
pub fn mktyp(typ Type) Type {
|
||||
match typ {
|
||||
ast.float_literal_type { return ast.f64_type }
|
||||
ast.int_literal_type { return ast.int_type }
|
||||
else { return typ }
|
||||
return match typ {
|
||||
ast.float_literal_type { ast.f64_type }
|
||||
ast.int_literal_type { ast.int_type }
|
||||
else { typ }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -827,7 +825,7 @@ pub fn (t &TypeSymbol) is_builtin() bool {
|
|||
|
||||
// for debugging/errors only, perf is not an issue
|
||||
pub fn (k Kind) str() string {
|
||||
k_str := match k {
|
||||
return match k {
|
||||
.placeholder { 'placeholder' }
|
||||
.void { 'void' }
|
||||
.voidptr { 'voidptr' }
|
||||
|
|
@ -868,7 +866,6 @@ pub fn (k Kind) str() string {
|
|||
.aggregate { 'aggregate' }
|
||||
.thread { 'thread' }
|
||||
}
|
||||
return k_str
|
||||
}
|
||||
|
||||
pub fn (kinds []Kind) str() string {
|
||||
|
|
|
|||
|
|
@ -275,18 +275,10 @@ pub fn (mut c Checker) assign_stmt(mut node ast.AssignStmt) {
|
|||
if !c.inside_unsafe && !c.pref.translated && !c.file.is_translated {
|
||||
c.error('modifying variables via dereferencing can only be done in `unsafe` blocks',
|
||||
node.pos)
|
||||
} else {
|
||||
} else if mut left.right is ast.Ident {
|
||||
// mark `p` in `*p = val` as used:
|
||||
match mut left.right {
|
||||
ast.Ident {
|
||||
match mut left.right.obj {
|
||||
ast.Var {
|
||||
left.right.obj.is_used = true
|
||||
}
|
||||
else {}
|
||||
}
|
||||
}
|
||||
else {}
|
||||
if mut left.right.obj is ast.Var {
|
||||
left.right.obj.is_used = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -330,14 +322,25 @@ pub fn (mut c Checker) assign_stmt(mut node ast.AssignStmt) {
|
|||
left_sym := c.table.sym(left_type_unwrapped)
|
||||
right_sym := c.table.sym(right_type_unwrapped)
|
||||
if left_sym.kind == .array && !c.inside_unsafe && node.op in [.assign, .decl_assign]
|
||||
&& right_sym.kind == .array && (left is ast.Ident && !left.is_blank_ident())
|
||||
&& right_sym.kind == .array && left is ast.Ident && !left.is_blank_ident()
|
||||
&& right is ast.Ident {
|
||||
// Do not allow `a = b`, only `a = b.clone()`
|
||||
c.error('use `array2 $node.op.str() array1.clone()` instead of `array2 $node.op.str() array1` (or use `unsafe`)',
|
||||
node.pos)
|
||||
}
|
||||
if left_sym.kind == .array && right_sym.kind == .array {
|
||||
// `mut arr := [u8(1),2,3]`
|
||||
// `arr = [byte(4),5,6]`
|
||||
left_info := left_sym.info as ast.Array
|
||||
left_elem_type := c.table.unaliased_type(left_info.elem_type)
|
||||
right_info := right_sym.info as ast.Array
|
||||
right_elem_type := c.table.unaliased_type(right_info.elem_type)
|
||||
if left_info.nr_dims == right_info.nr_dims && left_elem_type == right_elem_type {
|
||||
continue
|
||||
}
|
||||
}
|
||||
if left_sym.kind == .array_fixed && !c.inside_unsafe && node.op in [.assign, .decl_assign]
|
||||
&& right_sym.kind == .array_fixed && (left is ast.Ident && !left.is_blank_ident())
|
||||
&& right_sym.kind == .array_fixed && left is ast.Ident && !left.is_blank_ident()
|
||||
&& right is ast.Ident {
|
||||
if right_sym.info is ast.ArrayFixed {
|
||||
if right_sym.info.elem_type.is_ptr() {
|
||||
|
|
@ -347,8 +350,8 @@ pub fn (mut c Checker) assign_stmt(mut node ast.AssignStmt) {
|
|||
}
|
||||
}
|
||||
if left_sym.kind == .map && node.op in [.assign, .decl_assign] && right_sym.kind == .map
|
||||
&& ((right is ast.Ident && right.is_auto_deref_var())
|
||||
|| !right_type.is_ptr()) && !left.is_blank_ident() && right.is_lvalue() {
|
||||
&& !left.is_blank_ident() && right.is_lvalue()
|
||||
&& (!right_type.is_ptr() || (right is ast.Ident && right.is_auto_deref_var())) {
|
||||
// Do not allow `a = b`
|
||||
c.error('cannot copy map: call `move` or `clone` method (or use a reference)',
|
||||
right.pos())
|
||||
|
|
@ -364,8 +367,8 @@ pub fn (mut c Checker) assign_stmt(mut node ast.AssignStmt) {
|
|||
c.error('cannot assign to `$left`: ' +
|
||||
c.expected_msg(right_type_unwrapped, left_type_unwrapped), right.pos())
|
||||
}
|
||||
if (right is ast.StructInit || !right_is_ptr) && !(right_sym.is_number()
|
||||
|| left_type.has_flag(.shared_f)) {
|
||||
if !right_sym.is_number() && !left_type.has_flag(.shared_f)
|
||||
&& (right is ast.StructInit || !right_is_ptr) {
|
||||
left_name := c.table.type_to_str(left_type_unwrapped)
|
||||
mut rtype := right_type_unwrapped
|
||||
if rtype.is_ptr() {
|
||||
|
|
@ -476,8 +479,8 @@ pub fn (mut c Checker) assign_stmt(mut node ast.AssignStmt) {
|
|||
else {}
|
||||
}
|
||||
if node.op in [.plus_assign, .minus_assign, .mod_assign, .mult_assign, .div_assign]
|
||||
&& ((left_sym.kind == .struct_ && right_sym.kind == .struct_)
|
||||
|| left_sym.kind == .alias) {
|
||||
&& (left_sym.kind == .alias || (left_sym.kind == .struct_
|
||||
&& right_sym.kind == .struct_)) {
|
||||
left_name := c.table.type_to_str(left_type_unwrapped)
|
||||
right_name := c.table.type_to_str(right_type_unwrapped)
|
||||
parent_sym := c.table.final_sym(left_type_unwrapped)
|
||||
|
|
@ -552,7 +555,7 @@ pub fn (mut c Checker) assign_stmt(mut node ast.AssignStmt) {
|
|||
is_shared = left_first.info.share == .shared_t
|
||||
}
|
||||
old_inside_ref_lit := c.inside_ref_lit
|
||||
c.inside_ref_lit = (c.inside_ref_lit || right_node.op == .amp || is_shared)
|
||||
c.inside_ref_lit = c.inside_ref_lit || right_node.op == .amp || is_shared
|
||||
c.expr(right_node.right)
|
||||
c.inside_ref_lit = old_inside_ref_lit
|
||||
if right_node.op == .amp {
|
||||
|
|
|
|||
|
|
@ -429,13 +429,13 @@ fn (mut c Checker) check_shift(mut node ast.InfixExpr, left_type ast.Type, right
|
|||
|
||||
pub fn (mut c Checker) promote(left_type ast.Type, right_type ast.Type) ast.Type {
|
||||
if left_type.is_any_kind_of_pointer() {
|
||||
if right_type.is_int() {
|
||||
if right_type.is_int() || c.pref.translated {
|
||||
return left_type
|
||||
} else {
|
||||
return ast.void_type
|
||||
}
|
||||
} else if right_type.is_any_kind_of_pointer() {
|
||||
if left_type.is_int() {
|
||||
if left_type.is_int() || c.pref.translated {
|
||||
return right_type
|
||||
} else {
|
||||
return ast.void_type
|
||||
|
|
@ -489,6 +489,8 @@ fn (c &Checker) promote_num(left_type ast.Type, right_type ast.Type) ast.Type {
|
|||
return if idx_lo == ast.i64_type_idx { type_lo } else { type_hi }
|
||||
} else if idx_hi - idx_lo < (ast.byte_type_idx - ast.i8_type_idx) {
|
||||
return type_lo // conversion unsigned -> signed if signed type is larger
|
||||
} else if c.pref.translated {
|
||||
return type_hi
|
||||
} else {
|
||||
return ast.void_type // conversion signed -> unsigned not allowed
|
||||
}
|
||||
|
|
|
|||
|
|
@ -442,7 +442,7 @@ pub fn (mut c Checker) alias_type_decl(node ast.AliasTypeDecl) {
|
|||
c.check_valid_pascal_case(node.name, 'type alias', node.pos)
|
||||
}
|
||||
c.ensure_type_exists(node.parent_type, node.type_pos) or { return }
|
||||
typ_sym := c.table.sym(node.parent_type)
|
||||
mut typ_sym := c.table.sym(node.parent_type)
|
||||
if typ_sym.kind in [.placeholder, .int_literal, .float_literal] {
|
||||
c.error('unknown type `$typ_sym.name`', node.type_pos)
|
||||
} else if typ_sym.kind == .alias {
|
||||
|
|
@ -594,6 +594,7 @@ pub fn (mut c Checker) infix_expr(mut node ast.InfixExpr) ast.Type {
|
|||
}
|
||||
}
|
||||
mut return_type := left_type
|
||||
|
||||
if node.op != .key_is {
|
||||
match mut node.left {
|
||||
ast.Ident, ast.SelectorExpr {
|
||||
|
|
@ -661,6 +662,15 @@ pub fn (mut c Checker) infix_expr(mut node ast.InfixExpr) ast.Type {
|
|||
}
|
||||
node.left_type = map_info.key_type
|
||||
}
|
||||
.array_fixed {
|
||||
if left_sym.kind !in [.sum_type, .interface_] {
|
||||
elem_type := right_final.array_fixed_info().elem_type
|
||||
c.check_expected(left_type, elem_type) or {
|
||||
c.error('left operand to `$node.op` does not match the fixed array element type: $err.msg()',
|
||||
left_right_pos)
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
c.error('`$node.op.str()` can only be used with arrays and maps',
|
||||
node.pos)
|
||||
|
|
@ -681,7 +691,7 @@ pub fn (mut c Checker) infix_expr(mut node ast.InfixExpr) ast.Type {
|
|||
left_sym = c.table.sym((left_sym.info as ast.Alias).parent_type)
|
||||
}
|
||||
// Check if the alias type is not a primitive then allow using operator overloading for aliased `arrays` and `maps`
|
||||
if left_sym.kind == .alias && left_sym.info is ast.Alias
|
||||
if !c.pref.translated && left_sym.kind == .alias && left_sym.info is ast.Alias
|
||||
&& !(c.table.sym((left_sym.info as ast.Alias).parent_type).is_primitive()) {
|
||||
if left_sym.has_method(node.op.str()) {
|
||||
if method := left_sym.find_method(node.op.str()) {
|
||||
|
|
@ -699,7 +709,7 @@ pub fn (mut c Checker) infix_expr(mut node ast.InfixExpr) ast.Type {
|
|||
c.error('mismatched types `$left_name` and `$right_name`', left_right_pos)
|
||||
}
|
||||
}
|
||||
} else if right_sym.kind == .alias && right_sym.info is ast.Alias
|
||||
} else if !c.pref.translated && right_sym.kind == .alias && right_sym.info is ast.Alias
|
||||
&& !(c.table.sym((right_sym.info as ast.Alias).parent_type).is_primitive()) {
|
||||
if right_sym.has_method(node.op.str()) {
|
||||
if method := right_sym.find_method(node.op.str()) {
|
||||
|
|
@ -806,6 +816,7 @@ pub fn (mut c Checker) infix_expr(mut node ast.InfixExpr) ast.Type {
|
|||
if node.op in [.div, .mod] {
|
||||
c.check_div_mod_by_zero(node.right, node.op)
|
||||
}
|
||||
|
||||
return_type = promoted_type
|
||||
}
|
||||
}
|
||||
|
|
@ -2260,7 +2271,8 @@ fn (mut c Checker) hash_stmt(mut node ast.HashStmt) {
|
|||
return
|
||||
}
|
||||
match node.kind {
|
||||
'include' {
|
||||
'include', 'insert' {
|
||||
original_flag := node.main
|
||||
mut flag := node.main
|
||||
if flag.contains('@VROOT') {
|
||||
// c.note(checker.vroot_is_deprecated_message, node.pos)
|
||||
|
|
@ -2268,13 +2280,13 @@ fn (mut c Checker) hash_stmt(mut node ast.HashStmt) {
|
|||
c.error(err.msg(), node.pos)
|
||||
return
|
||||
}
|
||||
node.val = 'include $vroot'
|
||||
node.val = '$node.kind $vroot'
|
||||
node.main = vroot
|
||||
flag = vroot
|
||||
}
|
||||
if flag.contains('@VEXEROOT') {
|
||||
vroot := flag.replace('@VEXEROOT', os.dir(pref.vexe_path()))
|
||||
node.val = 'include $vroot'
|
||||
node.val = '$node.kind $vroot'
|
||||
node.main = vroot
|
||||
flag = vroot
|
||||
}
|
||||
|
|
@ -2283,7 +2295,7 @@ fn (mut c Checker) hash_stmt(mut node ast.HashStmt) {
|
|||
c.error(err.msg(), node.pos)
|
||||
return
|
||||
}
|
||||
node.val = 'include $vroot'
|
||||
node.val = '$node.kind $vroot'
|
||||
node.main = vroot
|
||||
flag = vroot
|
||||
}
|
||||
|
|
@ -2295,10 +2307,33 @@ fn (mut c Checker) hash_stmt(mut node ast.HashStmt) {
|
|||
node.main = env
|
||||
}
|
||||
flag_no_comment := flag.all_before('//').trim_space()
|
||||
if !((flag_no_comment.starts_with('"') && flag_no_comment.ends_with('"'))
|
||||
|| (flag_no_comment.starts_with('<') && flag_no_comment.ends_with('>'))) {
|
||||
c.error('including C files should use either `"header_file.h"` or `<header_file.h>` quoting',
|
||||
node.pos)
|
||||
if node.kind == 'include' {
|
||||
if !((flag_no_comment.starts_with('"') && flag_no_comment.ends_with('"'))
|
||||
|| (flag_no_comment.starts_with('<') && flag_no_comment.ends_with('>'))) {
|
||||
c.error('including C files should use either `"header_file.h"` or `<header_file.h>` quoting',
|
||||
node.pos)
|
||||
}
|
||||
}
|
||||
if node.kind == 'insert' {
|
||||
if !(flag_no_comment.starts_with('"') && flag_no_comment.ends_with('"')) {
|
||||
c.error('inserting .c or .h files, should use `"header_file.h"` quoting',
|
||||
node.pos)
|
||||
}
|
||||
node.main = node.main.trim('"')
|
||||
if fcontent := os.read_file(node.main) {
|
||||
node.val = fcontent
|
||||
} else {
|
||||
mut missing_message := 'The file $original_flag, needed for insertion by module `$node.mod`,'
|
||||
if os.is_file(node.main) {
|
||||
missing_message += ' is not readable.'
|
||||
} else {
|
||||
missing_message += ' does not exist.'
|
||||
}
|
||||
if node.msg != '' {
|
||||
missing_message += ' ${node.msg}.'
|
||||
}
|
||||
c.error(missing_message, node.pos)
|
||||
}
|
||||
}
|
||||
}
|
||||
'pkgconfig' {
|
||||
|
|
@ -2361,7 +2396,7 @@ fn (mut c Checker) hash_stmt(mut node ast.HashStmt) {
|
|||
}
|
||||
else {
|
||||
if node.kind != 'define' {
|
||||
c.error('expected `#define`, `#flag`, `#include` or `#pkgconfig` not $node.val',
|
||||
c.error('expected `#define`, `#flag`, `#include`, `#insert` or `#pkgconfig` not $node.val',
|
||||
node.pos)
|
||||
}
|
||||
}
|
||||
|
|
@ -3471,7 +3506,7 @@ pub fn (mut c Checker) lock_expr(mut node ast.LockExpr) ast.Type {
|
|||
// handle `x := rlock a { a.getval() }`
|
||||
mut ret_type := ast.void_type
|
||||
if node.stmts.len > 0 {
|
||||
last_stmt := node.stmts[node.stmts.len - 1]
|
||||
last_stmt := node.stmts.last()
|
||||
if last_stmt is ast.ExprStmt {
|
||||
ret_type = last_stmt.typ
|
||||
}
|
||||
|
|
|
|||
|
|
@ -302,7 +302,7 @@ fn (mut c Checker) fn_decl(mut node ast.FnDecl) {
|
|||
// c.table.cur_fn = node
|
||||
// Add return if `fn(...) ? {...}` have no return at end
|
||||
if node.return_type != ast.void_type && node.return_type.has_flag(.optional)
|
||||
&& (node.stmts.len == 0 || node.stmts[node.stmts.len - 1] !is ast.Return) {
|
||||
&& (node.stmts.len == 0 || node.stmts.last() !is ast.Return) {
|
||||
sym := c.table.sym(node.return_type)
|
||||
if sym.kind == .void {
|
||||
node.stmts << ast.Return{
|
||||
|
|
@ -708,8 +708,8 @@ pub fn (mut c Checker) fn_call(mut node ast.CallExpr, mut continue_check &bool)
|
|||
}
|
||||
if node.concrete_types.len > 0 && func.generic_names.len > 0
|
||||
&& node.concrete_types.len != func.generic_names.len {
|
||||
desc := if node.concrete_types.len > func.generic_names.len { 'many' } else { 'little' }
|
||||
c.error('too $desc generic parameters got $node.concrete_types.len, expected $func.generic_names.len',
|
||||
plural := if func.generic_names.len == 1 { '' } else { 's' }
|
||||
c.error('expected $func.generic_names.len generic parameter$plural, got $node.concrete_types.len',
|
||||
node.concrete_list_pos)
|
||||
}
|
||||
for concrete_type in node.concrete_types {
|
||||
|
|
@ -781,6 +781,7 @@ pub fn (mut c Checker) fn_call(mut node ast.CallExpr, mut continue_check &bool)
|
|||
if func.params.len == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
param := if func.is_variadic && i >= func.params.len - 1 {
|
||||
func.params[func.params.len - 1]
|
||||
} else {
|
||||
|
|
@ -1231,12 +1232,8 @@ pub fn (mut c Checker) method_call(mut node ast.CallExpr) ast.Type {
|
|||
}
|
||||
if node.concrete_types.len > 0 && method.generic_names.len > 0
|
||||
&& node.concrete_types.len != method.generic_names.len {
|
||||
desc := if node.concrete_types.len > method.generic_names.len {
|
||||
'many'
|
||||
} else {
|
||||
'little'
|
||||
}
|
||||
c.error('too $desc generic parameters got $node.concrete_types.len, expected $method.generic_names.len',
|
||||
plural := if method.generic_names.len == 1 { '' } else { 's' }
|
||||
c.error('expected $method.generic_names.len generic parameter$plural, got $node.concrete_types.len',
|
||||
node.concrete_list_pos)
|
||||
}
|
||||
for concrete_type in node.concrete_types {
|
||||
|
|
@ -1277,6 +1274,7 @@ pub fn (mut c Checker) method_call(mut node ast.CallExpr) ast.Type {
|
|||
}
|
||||
exp_arg_sym := c.table.sym(exp_arg_typ)
|
||||
c.expected_type = exp_arg_typ
|
||||
|
||||
mut got_arg_typ := c.check_expr_opt_call(arg.expr, c.expr(arg.expr))
|
||||
node.args[i].typ = got_arg_typ
|
||||
if no_type_promotion {
|
||||
|
|
@ -1895,6 +1893,17 @@ fn (mut c Checker) array_builtin_method_call(mut node ast.CallExpr, left_type as
|
|||
node.return_type = ast.void_type
|
||||
} else if method_name == 'contains' {
|
||||
// c.warn('use `value in arr` instead of `arr.contains(value)`', node.pos)
|
||||
if node.args.len != 1 {
|
||||
c.error('`.contains()` expected 1 argument, but got $node.args.len', node.pos)
|
||||
} else {
|
||||
arg_typ := ast.mktyp(c.expr(node.args[0].expr))
|
||||
elem_typ_str := c.table.type_to_str(elem_typ)
|
||||
arg_typ_str := c.table.type_to_str(arg_typ)
|
||||
if !left_sym.has_method('contains') && elem_typ_str != arg_typ_str {
|
||||
c.error('`.contains()` expected `$elem_typ_str` argument, but got `$arg_typ_str`',
|
||||
node.pos)
|
||||
}
|
||||
}
|
||||
node.return_type = ast.bool_type
|
||||
} else if method_name == 'index' {
|
||||
node.return_type = ast.int_type
|
||||
|
|
|
|||
|
|
@ -11,8 +11,8 @@ pub fn (mut c Checker) if_expr(mut node ast.IfExpr) ast.Type {
|
|||
mut node_is_expr := false
|
||||
if node.branches.len > 0 && node.has_else {
|
||||
stmts := node.branches[0].stmts
|
||||
if stmts.len > 0 && stmts[stmts.len - 1] is ast.ExprStmt
|
||||
&& (stmts[stmts.len - 1] as ast.ExprStmt).typ != ast.void_type {
|
||||
if stmts.len > 0 && stmts.last() is ast.ExprStmt
|
||||
&& (stmts.last() as ast.ExprStmt).typ != ast.void_type {
|
||||
node_is_expr = true
|
||||
}
|
||||
}
|
||||
|
|
@ -173,6 +173,13 @@ pub fn (mut c Checker) if_expr(mut node ast.IfExpr) ast.Type {
|
|||
continue
|
||||
}
|
||||
last_expr.typ = c.expr(last_expr.expr)
|
||||
if c.table.type_kind(c.expected_type) == .multi_return
|
||||
&& c.table.type_kind(last_expr.typ) == .multi_return {
|
||||
if node.typ == ast.void_type {
|
||||
node.is_expr = true
|
||||
node.typ = c.expected_type
|
||||
}
|
||||
}
|
||||
if !c.check_types(last_expr.typ, node.typ) {
|
||||
if node.typ == ast.void_type {
|
||||
// first branch of if expression
|
||||
|
|
@ -210,6 +217,15 @@ pub fn (mut c Checker) if_expr(mut node ast.IfExpr) ast.Type {
|
|||
if is_noreturn_callexpr(last_expr.expr) {
|
||||
continue
|
||||
}
|
||||
node_sym := c.table.sym(node.typ)
|
||||
last_sym := c.table.sym(last_expr.typ)
|
||||
if node_sym.kind == .multi_return && last_sym.kind == .multi_return {
|
||||
node_types := node_sym.mr_info().types
|
||||
last_types := last_sym.mr_info().types.map(ast.mktyp(it))
|
||||
if node_types == last_types {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
c.error('mismatched types `${c.table.type_to_str(node.typ)}` and `${c.table.type_to_str(last_expr.typ)}`',
|
||||
node.pos)
|
||||
|
|
|
|||
|
|
@ -72,7 +72,7 @@ pub fn (mut c Checker) match_expr(mut node ast.MatchExpr) ast.Type {
|
|||
expr_type := c.expr(stmt.expr)
|
||||
if first_iteration {
|
||||
if node.is_expr && (node.expected_type.has_flag(.optional)
|
||||
|| c.table.type_kind(node.expected_type) == .sum_type) {
|
||||
|| c.table.type_kind(node.expected_type) in [.sum_type, .multi_return]) {
|
||||
ret_type = node.expected_type
|
||||
} else {
|
||||
ret_type = expr_type
|
||||
|
|
@ -86,6 +86,14 @@ pub fn (mut c Checker) match_expr(mut node ast.MatchExpr) ast.Type {
|
|||
&& (ret_type.has_flag(.generic)
|
||||
|| c.table.is_sumtype_or_in_variant(ret_type, expr_type)))
|
||||
&& !is_noreturn {
|
||||
expr_sym := c.table.sym(expr_type)
|
||||
if expr_sym.kind == .multi_return && ret_sym.kind == .multi_return {
|
||||
ret_types := ret_sym.mr_info().types
|
||||
expr_types := expr_sym.mr_info().types.map(ast.mktyp(it))
|
||||
if expr_types == ret_types {
|
||||
continue
|
||||
}
|
||||
}
|
||||
c.error('return type mismatch, it should be `$ret_sym.name`',
|
||||
stmt.expr.pos())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,35 @@
|
|||
vlib/v/checker/tests/array_contains_args_err.vv:3:17: error: `.contains()` expected `int` argument, but got `[]int`
|
||||
1 | fn main() {
|
||||
2 | arr := [0]
|
||||
3 | mut ret := [0].contains([0])
|
||||
| ~~~~~~~~~~~~~
|
||||
4 | ret = [0].contains()
|
||||
5 | ret = [0, 1, 2].contains(0, 1, 2)
|
||||
vlib/v/checker/tests/array_contains_args_err.vv:4:12: error: `.contains()` expected 1 argument, but got 0
|
||||
2 | arr := [0]
|
||||
3 | mut ret := [0].contains([0])
|
||||
4 | ret = [0].contains()
|
||||
| ~~~~~~~~~~
|
||||
5 | ret = [0, 1, 2].contains(0, 1, 2)
|
||||
6 | ret = [0].contains('a')
|
||||
vlib/v/checker/tests/array_contains_args_err.vv:5:18: error: `.contains()` expected 1 argument, but got 3
|
||||
3 | mut ret := [0].contains([0])
|
||||
4 | ret = [0].contains()
|
||||
5 | ret = [0, 1, 2].contains(0, 1, 2)
|
||||
| ~~~~~~~~~~~~~~~~~
|
||||
6 | ret = [0].contains('a')
|
||||
7 | ret = [0].contains(arr)
|
||||
vlib/v/checker/tests/array_contains_args_err.vv:6:12: error: `.contains()` expected `int` argument, but got `string`
|
||||
4 | ret = [0].contains()
|
||||
5 | ret = [0, 1, 2].contains(0, 1, 2)
|
||||
6 | ret = [0].contains('a')
|
||||
| ~~~~~~~~~~~~~
|
||||
7 | ret = [0].contains(arr)
|
||||
8 | println(ret)
|
||||
vlib/v/checker/tests/array_contains_args_err.vv:7:12: error: `.contains()` expected `int` argument, but got `[]int`
|
||||
5 | ret = [0, 1, 2].contains(0, 1, 2)
|
||||
6 | ret = [0].contains('a')
|
||||
7 | ret = [0].contains(arr)
|
||||
| ~~~~~~~~~~~~~
|
||||
8 | println(ret)
|
||||
9 | }
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
fn main() {
|
||||
arr := [0]
|
||||
mut ret := [0].contains([0])
|
||||
ret = [0].contains()
|
||||
ret = [0, 1, 2].contains(0, 1, 2)
|
||||
ret = [0].contains('a')
|
||||
ret = [0].contains(arr)
|
||||
println(ret)
|
||||
}
|
||||
|
|
@ -4,24 +4,24 @@ vlib/v/checker/tests/check_err_msg_with_generics.vv:15:10: error: cannot cast st
|
|||
15 | println(int(typ))
|
||||
| ~~~~~~~~
|
||||
16 | }
|
||||
vlib/datatypes/bstree.v:190:17: error: cannot append `T` to `[]T`
|
||||
188 | }
|
||||
189 | bst.in_order_traversal_helper(node.left, mut result)
|
||||
190 | result << node.value
|
||||
vlib/datatypes/bstree.v:196:17: error: cannot append `T` to `[]T`
|
||||
194 | }
|
||||
195 | bst.in_order_traversal_helper(node.left, mut result)
|
||||
196 | result << node.value
|
||||
| ~~~~~
|
||||
191 | bst.in_order_traversal_helper(node.right, mut result)
|
||||
192 | }
|
||||
vlib/datatypes/bstree.v:210:17: error: cannot append `T` to `[]T`
|
||||
208 | bst.post_order_traversal_helper(node.left, mut result)
|
||||
209 | bst.post_order_traversal_helper(node.right, mut result)
|
||||
210 | result << node.value
|
||||
197 | bst.in_order_traversal_helper(node.right, mut result)
|
||||
198 | }
|
||||
vlib/datatypes/bstree.v:216:17: error: cannot append `T` to `[]T`
|
||||
214 | bst.post_order_traversal_helper(node.left, mut result)
|
||||
215 | bst.post_order_traversal_helper(node.right, mut result)
|
||||
216 | result << node.value
|
||||
| ~~~~~
|
||||
211 | }
|
||||
212 |
|
||||
vlib/datatypes/bstree.v:226:17: error: cannot append `T` to `[]T`
|
||||
224 | return
|
||||
225 | }
|
||||
226 | result << node.value
|
||||
217 | }
|
||||
218 |
|
||||
vlib/datatypes/bstree.v:232:17: error: cannot append `T` to `[]T`
|
||||
230 | return
|
||||
231 | }
|
||||
232 | result << node.value
|
||||
| ~~~~~
|
||||
227 | bst.pre_order_traversal_helper(node.left, mut result)
|
||||
228 | bst.pre_order_traversal_helper(node.right, mut result)
|
||||
233 | bst.pre_order_traversal_helper(node.left, mut result)
|
||||
234 | bst.pre_order_traversal_helper(node.right, mut result)
|
||||
|
|
@ -0,0 +1 @@
|
|||
// just some text
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
vlib/v/checker/tests/comptime_insert_err.vv:6:1: error: The file "@VEXEROOT/vlib/v/checker/tests/Non_Existant_File.cc", needed for insertion by module `main`, does not exist.
|
||||
4 | // some more comments
|
||||
5 |
|
||||
6 | #insert "@VEXEROOT/vlib/v/checker/tests/Non_Existant_File.cc"
|
||||
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
7 |
|
||||
8 | fn main() {
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
// The following file exists, so there should not be a checker error for it:
|
||||
#insert "@VEXEROOT/vlib/v/checker/tests/comptime_insert_err.cc"
|
||||
|
||||
// some more comments
|
||||
|
||||
#insert "@VEXEROOT/vlib/v/checker/tests/Non_Existant_File.cc"
|
||||
|
||||
fn main() {
|
||||
println('hello')
|
||||
}
|
||||
|
|
@ -1,25 +1,25 @@
|
|||
vlib/v/checker/tests/generics_fn_arguments_count_err.vv:12:18: error: too little generic parameters got 1, expected 2
|
||||
vlib/v/checker/tests/generics_fn_arguments_count_err.vv:12:18: error: expected 2 generic parameters, got 1
|
||||
10 |
|
||||
11 | fn main() {
|
||||
12 | ret1 := get_name<int>(11, 22)
|
||||
| ~~~~~
|
||||
13 | println(ret1)
|
||||
14 |
|
||||
vlib/v/checker/tests/generics_fn_arguments_count_err.vv:15:18: error: too many generic parameters got 3, expected 2
|
||||
vlib/v/checker/tests/generics_fn_arguments_count_err.vv:15:18: error: expected 2 generic parameters, got 3
|
||||
13 | println(ret1)
|
||||
14 |
|
||||
15 | ret2 := get_name<int, int, string>(11, 22, 'hello')
|
||||
| ~~~~~~~~~~~~~~~~~~
|
||||
16 | println(ret2)
|
||||
17 |
|
||||
vlib/v/checker/tests/generics_fn_arguments_count_err.vv:19:22: error: too little generic parameters got 1, expected 2
|
||||
vlib/v/checker/tests/generics_fn_arguments_count_err.vv:19:22: error: expected 2 generic parameters, got 1
|
||||
17 |
|
||||
18 | foo := Foo{}
|
||||
19 | ret3 := foo.get_name<int>(11, 22)
|
||||
| ~~~~~
|
||||
20 | println(ret3)
|
||||
21 |
|
||||
vlib/v/checker/tests/generics_fn_arguments_count_err.vv:22:22: error: too many generic parameters got 3, expected 2
|
||||
vlib/v/checker/tests/generics_fn_arguments_count_err.vv:22:22: error: expected 2 generic parameters, got 3
|
||||
20 | println(ret3)
|
||||
21 |
|
||||
22 | ret4 := foo.get_name<int, int, string>(11, 22, 'hello')
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
vlib/v/checker/tests/generics_too_many_parameters.vv:6:8: error: too many generic parameters got 5, expected 1
|
||||
4 |
|
||||
vlib/v/checker/tests/generics_too_many_parameters.vv:6:8: error: expected 1 generic parameter, got 5
|
||||
4 |
|
||||
5 | fn main() {
|
||||
6 | foo<bool, int, bool, bool, int>(1)
|
||||
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
|
|
|||
|
|
@ -1797,6 +1797,7 @@ fn (mut g Gen) stmt(node ast.Stmt) {
|
|||
g.writeln('goto ${c_name(node.name)};')
|
||||
}
|
||||
ast.HashStmt {
|
||||
line_nr := node.pos.line_nr + 1
|
||||
mut ct_condition := ''
|
||||
if node.ct_conds.len > 0 {
|
||||
ct_condition_start := g.out.len
|
||||
|
|
@ -1830,7 +1831,7 @@ fn (mut g Gen) stmt(node ast.Stmt) {
|
|||
}
|
||||
// Objective C code import, include it after V types, so that e.g. `string` is
|
||||
// available there
|
||||
g.definitions.writeln('// added by module `$node.mod`')
|
||||
g.definitions.writeln('// added by module `$node.mod`, file: ${os.file_name(node.source_file)}:$line_nr:')
|
||||
g.definitions.writeln(guarded_include)
|
||||
if ct_condition.len > 0 {
|
||||
g.definitions.writeln('#endif // \$if $ct_condition')
|
||||
|
|
@ -1841,13 +1842,22 @@ fn (mut g Gen) stmt(node ast.Stmt) {
|
|||
if ct_condition.len > 0 {
|
||||
g.includes.writeln('#if $ct_condition')
|
||||
}
|
||||
g.includes.writeln('// added by module `$node.mod`')
|
||||
g.includes.writeln('// added by module `$node.mod`, file: ${os.file_name(node.source_file)}:$line_nr:')
|
||||
g.includes.writeln(guarded_include)
|
||||
if ct_condition.len > 0 {
|
||||
g.includes.writeln('#endif // \$if $ct_condition')
|
||||
}
|
||||
g.includes.writeln('\n')
|
||||
}
|
||||
} else if node.kind == 'insert' {
|
||||
if ct_condition.len > 0 {
|
||||
g.includes.writeln('#if $ct_condition')
|
||||
}
|
||||
g.includes.writeln('// inserted by module `$node.mod`, file: ${os.file_name(node.source_file)}:$line_nr:')
|
||||
g.includes.writeln(node.val)
|
||||
if ct_condition.len > 0 {
|
||||
g.includes.writeln('#endif // \$if $ct_condition')
|
||||
}
|
||||
} else if node.kind == 'define' {
|
||||
if ct_condition.len > 0 {
|
||||
g.includes.writeln('#if $ct_condition')
|
||||
|
|
@ -4933,8 +4943,8 @@ fn (mut g Gen) or_block(var_name string, or_block ast.OrExpr, return_type ast.Ty
|
|||
g.inside_or_block = false
|
||||
}
|
||||
stmts := or_block.stmts
|
||||
if stmts.len > 0 && stmts[or_block.stmts.len - 1] is ast.ExprStmt
|
||||
&& (stmts[stmts.len - 1] as ast.ExprStmt).typ != ast.void_type {
|
||||
if stmts.len > 0 && stmts.last() is ast.ExprStmt
|
||||
&& (stmts.last() as ast.ExprStmt).typ != ast.void_type {
|
||||
g.indent++
|
||||
for i, stmt in stmts {
|
||||
if i == stmts.len - 1 {
|
||||
|
|
@ -4956,7 +4966,7 @@ fn (mut g Gen) or_block(var_name string, or_block ast.OrExpr, return_type ast.Ty
|
|||
g.indent--
|
||||
} else {
|
||||
g.stmts(stmts)
|
||||
if stmts.len > 0 && stmts[or_block.stmts.len - 1] is ast.ExprStmt {
|
||||
if stmts.len > 0 && stmts.last() is ast.ExprStmt {
|
||||
g.writeln(';')
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -441,6 +441,54 @@ fn (mut g Gen) infix_expr_in_op(node ast.InfixExpr) {
|
|||
g.expr(node.right)
|
||||
}
|
||||
g.write(')')
|
||||
} else if right.unaliased_sym.kind == .array_fixed {
|
||||
if left.sym.kind in [.sum_type, .interface_] {
|
||||
if node.right is ast.ArrayInit {
|
||||
if node.right.exprs.len > 0 {
|
||||
mut infix_exprs := []ast.InfixExpr{}
|
||||
for i in 0 .. node.right.exprs.len {
|
||||
infix_exprs << ast.InfixExpr{
|
||||
op: .key_is
|
||||
left: node.left
|
||||
left_type: node.left_type
|
||||
right: node.right.exprs[i]
|
||||
right_type: node.right.expr_types[i]
|
||||
}
|
||||
}
|
||||
g.write('(')
|
||||
g.infix_expr_in_sumtype_interface_array(infix_exprs)
|
||||
g.write(')')
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
if node.right is ast.ArrayInit {
|
||||
if node.right.exprs.len > 0 {
|
||||
// `a in [1,2,3]!` optimization => `a == 1 || a == 2 || a == 3`
|
||||
// avoids an allocation
|
||||
g.write('(')
|
||||
g.infix_expr_in_optimization(node.left, node.right)
|
||||
g.write(')')
|
||||
return
|
||||
}
|
||||
}
|
||||
if right.sym.info is ast.Array {
|
||||
elem_type := right.sym.info.elem_type
|
||||
elem_type_ := g.unwrap(elem_type)
|
||||
if elem_type_.sym.kind == .sum_type {
|
||||
if node.left_type in elem_type_.sym.sumtype_info().variants {
|
||||
new_node_left := ast.CastExpr{
|
||||
arg: ast.EmptyExpr{}
|
||||
typ: elem_type
|
||||
expr: node.left
|
||||
expr_type: node.left_type
|
||||
}
|
||||
g.gen_array_contains(node.right_type, node.right, new_node_left)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
g.gen_array_contains(node.right_type, node.right, node.left)
|
||||
} else if right.unaliased_sym.kind == .string {
|
||||
g.write('string_contains(')
|
||||
g.expr(node.right)
|
||||
|
|
|
|||
|
|
@ -282,7 +282,7 @@ fn (mut g JsGen) infix_in_not_in_op(node ast.InfixExpr) {
|
|||
if node.op == .not_in {
|
||||
g.write('!')
|
||||
}
|
||||
if r_sym.unaliased_sym.kind == .array {
|
||||
if r_sym.unaliased_sym.kind in [.array, .array_fixed] {
|
||||
fn_name := g.gen_array_contains_method(node.right_type)
|
||||
g.write('(${fn_name}(')
|
||||
g.expr(node.right)
|
||||
|
|
|
|||
|
|
@ -69,7 +69,7 @@ fn (mut p Parser) array_init() ast.ArrayInit {
|
|||
// [100]u8
|
||||
elem_type = p.parse_type()
|
||||
if p.table.sym(elem_type).name == 'byte' {
|
||||
p.error('`byte` has been deprecated in favor of `u8`: use `[10]u8` instead of `[10]byte`')
|
||||
p.error('`byte` has been deprecated in favor of `u8`: use `[10]u8{}` instead of `[10]byte{}`')
|
||||
}
|
||||
last_pos = p.tok.pos()
|
||||
is_fixed = true
|
||||
|
|
|
|||
|
|
@ -0,0 +1,10 @@
|
|||
fn test_assign_array_of_aliases() {
|
||||
mut arr := [u8(1), 2, 3]
|
||||
arr = [byte(4), 5, 6]
|
||||
|
||||
println(arr)
|
||||
assert arr.len == 3
|
||||
assert arr[0] == 4
|
||||
assert arr[1] == 5
|
||||
assert arr[2] == 6
|
||||
}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
fn test_fixed_array_in_op() {
|
||||
assert 1 in [1, 2]!
|
||||
assert `a` in [`a`, `b`]!
|
||||
assert 'a' in ['a', 'b']!
|
||||
|
||||
ch := `"`
|
||||
assert ch in [`"`, `'`]!
|
||||
}
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
fn multret1(i int, j int) (int, int) {
|
||||
return if i > j { i, 10 } else { 10, j }
|
||||
}
|
||||
|
||||
fn multret2(i int, j int) (int, int) {
|
||||
return match i > j {
|
||||
true { i, 10 }
|
||||
false { 10, j }
|
||||
}
|
||||
}
|
||||
|
||||
fn multret3(i int, j int) (int, int) {
|
||||
if i > j {
|
||||
return i, 10
|
||||
} else {
|
||||
return 10, j
|
||||
}
|
||||
}
|
||||
|
||||
fn multret4(i int, j int) (int, int) {
|
||||
match i > j {
|
||||
true { return i, 10 }
|
||||
false { return 10, j }
|
||||
}
|
||||
}
|
||||
|
||||
fn test_fn_multi_return() {
|
||||
mut a, mut b := 0, 0
|
||||
|
||||
println(multret1(3, 14))
|
||||
a, b = multret1(3, 14)
|
||||
assert a == 10
|
||||
assert b == 14
|
||||
|
||||
println(multret2(3, 14))
|
||||
a, b = multret2(3, 14)
|
||||
assert a == 10
|
||||
assert b == 14
|
||||
|
||||
println(multret3(3, 14))
|
||||
a, b = multret3(3, 14)
|
||||
assert a == 10
|
||||
assert b == 14
|
||||
|
||||
println(multret4(3, 14))
|
||||
a, b = multret4(3, 14)
|
||||
assert a == 10
|
||||
assert b == 14
|
||||
}
|
||||
|
|
@ -36,7 +36,7 @@ const (
|
|||
]
|
||||
)
|
||||
|
||||
const builtin_module_names = ['builtin', 'strconv', 'strings', 'dlmalloc']
|
||||
const builtin_module_names = ['builtin', 'strconv', 'strings', 'dlmalloc', 'math']
|
||||
|
||||
pub fn module_is_builtin(mod string) bool {
|
||||
// NOTE: using util.builtin_module_parts here breaks -usecache on macos
|
||||
|
|
|
|||
Loading…
Reference in New Issue