mirror of
https://github.com/vlang/v.git
synced 2023-08-10 21:13:21 +03:00
cgen: parallelize (#10844)
This commit is contained in:
parent
a17b943e87
commit
85b58b03a3
12
.github/workflows/ci.yml
vendored
12
.github/workflows/ci.yml
vendored
@ -191,7 +191,7 @@ jobs:
|
|||||||
- name: v.c can be compiled and run with -os cross
|
- name: v.c can be compiled and run with -os cross
|
||||||
run: |
|
run: |
|
||||||
./v -os cross -o /tmp/v.c cmd/v
|
./v -os cross -o /tmp/v.c cmd/v
|
||||||
gcc -g -std=gnu11 -w -o v_from_vc /tmp/v.c -lm -lpthread
|
gcc -g -std=gnu11 -I ./thirdparty/stdatomic/nix -w -o v_from_vc /tmp/v.c -lm -lpthread
|
||||||
ls -lart v_from_vc
|
ls -lart v_from_vc
|
||||||
./v_from_vc version
|
./v_from_vc version
|
||||||
|
|
||||||
@ -235,7 +235,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++
|
||||||
run: ./v -cc g++-9 -o v2 cmd/v && ./v2 -cc g++-9 -o v3 cmd/v
|
run: ./v -cc g++-9 -no-std -cflags -std=c++11 -o v2 cmd/v && ./v2 -cc g++-9 -no-std -cflags -std=c++11 -o v3 cmd/v
|
||||||
## - name: Running tests with g++
|
## - name: Running tests with g++
|
||||||
## run: ./v -cc g++-9 -silent test-self
|
## run: ./v -cc g++-9 -silent test-self
|
||||||
|
|
||||||
@ -323,7 +323,7 @@ jobs:
|
|||||||
- name: v.c can be compiled and run with -os cross
|
- name: v.c can be compiled and run with -os cross
|
||||||
run: |
|
run: |
|
||||||
./v -os cross -o /tmp/v.c cmd/v
|
./v -os cross -o /tmp/v.c cmd/v
|
||||||
cc -g -std=gnu11 -w -o v_from_vc /tmp/v.c -lm -lpthread
|
cc -g -std=gnu11 -w -o v_from_vc /tmp/v.c -I ./thirdparty/stdatomic/nix -lm -lpthread
|
||||||
ls -lart v_from_vc
|
ls -lart v_from_vc
|
||||||
./v_from_vc version
|
./v_from_vc version
|
||||||
|
|
||||||
@ -627,7 +627,7 @@ jobs:
|
|||||||
gcc --version
|
gcc --version
|
||||||
.\make.bat -gcc
|
.\make.bat -gcc
|
||||||
- name: Test new v.c
|
- name: Test new v.c
|
||||||
run: .\v.exe -o v.c cmd/v && gcc -Werror -municode -w v.c
|
run: .\v.exe -o v.c cmd/v && gcc -Werror -I ./thirdparty/stdatomic/win -municode -w v.c
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: |
|
run: |
|
||||||
.\v.exe setup-freetype
|
.\v.exe setup-freetype
|
||||||
@ -715,7 +715,7 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
.\make.bat -tcc --verbose
|
.\make.bat -tcc --verbose
|
||||||
- name: Test new v.c
|
- name: Test new v.c
|
||||||
run: .\v.exe -o v.c cmd/v && .\thirdparty\tcc\tcc.exe -Werror -w -ladvapi32 -bt10 v.c
|
run: .\v.exe -o v.c cmd/v && .\thirdparty\tcc\tcc.exe -I ./thirdparty/stdatomic/win -Werror -w -ladvapi32 -bt10 v.c
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: |
|
run: |
|
||||||
.\v.exe setup-freetype
|
.\v.exe setup-freetype
|
||||||
@ -764,7 +764,7 @@ jobs:
|
|||||||
.\v.exe wipe-cache
|
.\v.exe wipe-cache
|
||||||
.\make.bat -tcc32 --verbose
|
.\make.bat -tcc32 --verbose
|
||||||
- name: Test new v.c
|
- name: Test new v.c
|
||||||
run: .\v.exe -o v.c cmd/v && .\thirdparty\tcc\tcc.exe -Werror -w -ladvapi32 -bt10 v.c
|
run: .\v.exe -o v.c cmd/v && .\thirdparty\tcc\tcc.exe -I ./thirdparty/stdatomic/win -Werror -w -ladvapi32 -bt10 v.c
|
||||||
- name: v doctor
|
- name: v doctor
|
||||||
run: ./v doctor
|
run: ./v doctor
|
||||||
|
|
||||||
|
4
.github/workflows/ci_cross.yml
vendored
4
.github/workflows/ci_cross.yml
vendored
@ -64,14 +64,14 @@ jobs:
|
|||||||
- name: v.c can be compiled and run with -os cross
|
- name: v.c can be compiled and run with -os cross
|
||||||
run: |
|
run: |
|
||||||
./v -os cross -o /tmp/v.c cmd/v
|
./v -os cross -o /tmp/v.c cmd/v
|
||||||
gcc -g -std=gnu11 -w -o v_from_vc /tmp/v.c -lm -lpthread
|
gcc -g -std=gnu11 -I ./thirdparty/stdatomic/nix -w -o v_from_vc /tmp/v.c -lm -lpthread
|
||||||
ls -lart v_from_vc
|
ls -lart v_from_vc
|
||||||
./v_from_vc version
|
./v_from_vc version
|
||||||
|
|
||||||
- name: v_win.c can be compiled and run with -os windows
|
- name: v_win.c can be compiled and run with -os windows
|
||||||
run: |
|
run: |
|
||||||
./v -os windows -o /tmp/v_win.c cmd/v
|
./v -os windows -o /tmp/v_win.c cmd/v
|
||||||
x86_64-w64-mingw32-gcc /tmp/v_win.c -std=c99 -w -municode -o v_from_vc.exe
|
x86_64-w64-mingw32-gcc -I ./thirdparty/stdatomic/win /tmp/v_win.c -std=c99 -w -municode -o v_from_vc.exe
|
||||||
ls -lart v_from_vc.exe
|
ls -lart v_from_vc.exe
|
||||||
wine v_from_vc.exe version
|
wine v_from_vc.exe version
|
||||||
|
|
||||||
|
2
.gitignore
vendored
2
.gitignore
vendored
@ -99,3 +99,5 @@ shell.nix
|
|||||||
default.nix
|
default.nix
|
||||||
flake.nix
|
flake.nix
|
||||||
.envrc
|
.envrc
|
||||||
|
|
||||||
|
thirdparty/stdatomic/nix/cpp/*.h
|
||||||
|
@ -4,7 +4,7 @@ LABEL maintainer="Vitaly Takmazov <vitalyster@gmail.com>"
|
|||||||
COPY . .
|
COPY . .
|
||||||
RUN make
|
RUN make
|
||||||
RUN ./v -os windows -o v.c cmd/v
|
RUN ./v -os windows -o v.c cmd/v
|
||||||
RUN x86_64-w64-mingw32-gcc v.c -std=c99 -w -municode -o v.exe
|
RUN x86_64-w64-mingw32-gcc v.c -std=c99 -I ./thirdparty/stdatomic/win -w -municode -o v.exe
|
||||||
RUN file v.exe
|
RUN file v.exe
|
||||||
|
|
||||||
CMD [ "bash" ]
|
CMD [ "bash" ]
|
||||||
|
2
Makefile
2
Makefile
@ -3,6 +3,6 @@ CC ?= cc
|
|||||||
all:
|
all:
|
||||||
rm -rf vc/
|
rm -rf vc/
|
||||||
git clone --depth 1 --quiet https://github.com/vlang/vc
|
git clone --depth 1 --quiet https://github.com/vlang/vc
|
||||||
$(CC) -std=gnu11 -w -o v vc/v.c -lm -lexecinfo
|
$(CC) -std=gnu11 -w -o v vc/v.c -lm -lexecinfo -I ./thirdparty/stdatomic/nix
|
||||||
rm -rf vc/
|
rm -rf vc/
|
||||||
@echo "V has been successfully built"
|
@echo "V has been successfully built"
|
||||||
|
@ -21,11 +21,13 @@ fn main() {
|
|||||||
println('fast.html generator needs to be located in `v/cmd/tools/fast`')
|
println('fast.html generator needs to be located in `v/cmd/tools/fast`')
|
||||||
}
|
}
|
||||||
println('fast.html generator\n')
|
println('fast.html generator\n')
|
||||||
println('Fetching updates...')
|
if !os.args.contains('-noupdate') {
|
||||||
ret := os.system('$vdir/v up')
|
println('Fetching updates...')
|
||||||
if ret != 0 {
|
ret := os.system('$vdir/v up')
|
||||||
println('failed to update V')
|
if ret != 0 {
|
||||||
return
|
println('failed to update V')
|
||||||
|
return
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// Fetch the last commit's hash
|
// Fetch the last commit's hash
|
||||||
commit := exec('git rev-parse HEAD')[..8]
|
commit := exec('git rev-parse HEAD')[..8]
|
||||||
@ -55,7 +57,6 @@ fn main() {
|
|||||||
} else {
|
} else {
|
||||||
exec('./v -o vprod -prod -prealloc cmd/v')
|
exec('./v -o vprod -prod -prealloc cmd/v')
|
||||||
}
|
}
|
||||||
// println('cur vdir="$vdir"')
|
|
||||||
// cache vlib modules
|
// cache vlib modules
|
||||||
exec('$vdir/v wipe-cache')
|
exec('$vdir/v wipe-cache')
|
||||||
exec('$vdir/v -o v2 -prod cmd/v')
|
exec('$vdir/v -o v2 -prod cmd/v')
|
||||||
|
@ -111,10 +111,10 @@ pub fn (mut vgit_context VGitContext) compile_oldv_if_needed() {
|
|||||||
mut command_for_building_v_from_c_source := ''
|
mut command_for_building_v_from_c_source := ''
|
||||||
mut command_for_selfbuilding := ''
|
mut command_for_selfbuilding := ''
|
||||||
if 'windows' == os.user_os() {
|
if 'windows' == os.user_os() {
|
||||||
command_for_building_v_from_c_source = '$vgit_context.cc -std=c99 -municode -w -o cv.exe "$vgit_context.path_vc/v_win.c" '
|
command_for_building_v_from_c_source = '$vgit_context.cc -std=c99 -I ./thirdparty/stdatomic/win -municode -w -o cv.exe "$vgit_context.path_vc/v_win.c" '
|
||||||
command_for_selfbuilding = './cv.exe -o $vgit_context.vexename {SOURCE}'
|
command_for_selfbuilding = './cv.exe -o $vgit_context.vexename {SOURCE}'
|
||||||
} else {
|
} else {
|
||||||
command_for_building_v_from_c_source = '$vgit_context.cc -std=gnu11 -w -o cv "$vgit_context.path_vc/v.c" -lm -lpthread'
|
command_for_building_v_from_c_source = '$vgit_context.cc -std=gnu11 -I ./thirdparty/stdatomic/nix -w -o cv "$vgit_context.path_vc/v.c" -lm -lpthread'
|
||||||
command_for_selfbuilding = './cv -o $vgit_context.vexename {SOURCE}'
|
command_for_selfbuilding = './cv -o $vgit_context.vexename {SOURCE}'
|
||||||
}
|
}
|
||||||
scripting.chdir(vgit_context.workdir)
|
scripting.chdir(vgit_context.workdir)
|
||||||
|
@ -8,6 +8,7 @@ import v.parser
|
|||||||
import v.ast
|
import v.ast
|
||||||
import v.pref
|
import v.pref
|
||||||
import v.errors
|
import v.errors
|
||||||
|
import strings
|
||||||
|
|
||||||
struct Context {
|
struct Context {
|
||||||
mut:
|
mut:
|
||||||
@ -208,7 +209,7 @@ fn (t Tree) type_node(typ ast.Type) &Node {
|
|||||||
return create_null()
|
return create_null()
|
||||||
} else {
|
} else {
|
||||||
type_name := t.table.get_type_name(typ)
|
type_name := t.table.get_type_name(typ)
|
||||||
return create_string(type_name)
|
return create_string(strings.repeat(`&`, typ.nr_muls()) + type_name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -148,7 +148,7 @@ fn get_all_commands() []Command {
|
|||||||
}
|
}
|
||||||
$if macos || linux {
|
$if macos || linux {
|
||||||
res << Command{
|
res << Command{
|
||||||
line: '$vexe -o v.c cmd/v && cc -Werror v.c && rm -rf a.out'
|
line: '$vexe -o v.c cmd/v && cc -I "$vroot/thirdparty/stdatomic/nix" -lpthread v.c && rm -rf a.out'
|
||||||
label: 'v.c should be buildable with no warnings...'
|
label: 'v.c should be buildable with no warnings...'
|
||||||
okmsg: 'v.c can be compiled without warnings. This is good :)'
|
okmsg: 'v.c can be compiled without warnings. This is good :)'
|
||||||
rmfile: 'v.c'
|
rmfile: 'v.c'
|
||||||
|
@ -90,6 +90,9 @@ NB: the build flags are shared with the run command too:
|
|||||||
The checker will abort prematurely once this limit has been reached.
|
The checker will abort prematurely once this limit has been reached.
|
||||||
Setting this to 0 or a negative value, will disable the limit.
|
Setting this to 0 or a negative value, will disable the limit.
|
||||||
|
|
||||||
|
-no-parallel
|
||||||
|
Do not run the compiler in parallel (currently only the cgen stage has parallelization).
|
||||||
|
|
||||||
-profile-no-inline
|
-profile-no-inline
|
||||||
Skip [inline] functions when profiling.
|
Skip [inline] functions when profiling.
|
||||||
|
|
||||||
|
20
make.bat
20
make.bat
@ -175,10 +175,10 @@ REM By default, use tcc, since we have it prebuilt:
|
|||||||
:tcc32_strap
|
:tcc32_strap
|
||||||
echo ^> Attempting to build v_win.c with TCC
|
echo ^> Attempting to build v_win.c with TCC
|
||||||
if !flag_verbose! EQU 1 (
|
if !flag_verbose! EQU 1 (
|
||||||
echo [Debug] "!tcc_exe!" -ladvapi32 -bt10 -w -o v.exe vc\v_win.c>>"!log_file!"
|
echo [Debug] "!tcc_exe!" -ladvapi32 -I .\thirdparty\stdatomic\win -bt10 -w -o v.exe vc\v_win.c>>"!log_file!"
|
||||||
echo "!tcc_exe!" -ladvapi32 -bt10 -w -o v.exe vc\v_win.c
|
echo "!tcc_exe!" -ladvapi32 -I .\thirdparty\stdatomic\win -bt10 -w -o v.exe vc\v_win.c
|
||||||
)
|
)
|
||||||
"!tcc_exe!" -ladvapi32 -bt10 -w -o v.exe vc\v_win.c>>"!log_file!"
|
"!tcc_exe!" -ladvapi32 -I .\thirdparty\stdatomic\win -bt10 -w -o v.exe vc\v_win.c>>"!log_file!"
|
||||||
if %ERRORLEVEL% NEQ 0 goto :compile_error
|
if %ERRORLEVEL% NEQ 0 goto :compile_error
|
||||||
|
|
||||||
echo ^> Compiling with .\v.exe self
|
echo ^> Compiling with .\v.exe self
|
||||||
@ -202,8 +202,8 @@ if %ERRORLEVEL% NEQ 0 (
|
|||||||
|
|
||||||
echo ^> Attempting to build v_win.c with Clang
|
echo ^> Attempting to build v_win.c with Clang
|
||||||
if !flag_verbose! EQU 1 (
|
if !flag_verbose! EQU 1 (
|
||||||
echo [Debug] clang -std=c99 -municode -w -o v.exe .\vc\v_win.c>>"!log_File!"
|
echo [Debug] clang -std=c99 -municode -I .\thirdparty\stdatomic\win -w -o v.exe .\vc\v_win.c>>"!log_File!"
|
||||||
echo clang -std=c99 -municode -w -o v.exe .\vc\v_win.c
|
echo clang -std=c99 -municode -I .\thirdparty\stdatomic\win -w -o v.exe .\vc\v_win.c
|
||||||
)
|
)
|
||||||
clang -std=c99 -municode -w -o v.exe .\vc\v_win.c>>"!log_file!"
|
clang -std=c99 -municode -w -o v.exe .\vc\v_win.c>>"!log_file!"
|
||||||
if %ERRORLEVEL% NEQ 0 (
|
if %ERRORLEVEL% NEQ 0 (
|
||||||
@ -231,10 +231,10 @@ if %ERRORLEVEL% NEQ 0 (
|
|||||||
|
|
||||||
echo ^> Attempting to build v_win.c with GCC
|
echo ^> Attempting to build v_win.c with GCC
|
||||||
if !flag_verbose! EQU 1 (
|
if !flag_verbose! EQU 1 (
|
||||||
echo [Debug] gcc -std=c99 -municode -w -o v.exe .\vc\v_win.c>>"!log_File!"
|
echo [Debug] gcc -std=c99 -municode -I .\thirdparty\stdatomic\win -w -o v.exe .\vc\v_win.c>>"!log_File!"
|
||||||
echo gcc -std=c99 -municode -w -o v.exe .\vc\v_win.c
|
echo gcc -std=c99 -municode -I .\thirdparty\stdatomic\win -w -o v.exe .\vc\v_win.c
|
||||||
)
|
)
|
||||||
gcc -std=c99 -municode -w -o v.exe .\vc\v_win.c>>"!log_File!"
|
gcc -std=c99 -municode -I .\thirdparty\stdatomic\win -w -o v.exe .\vc\v_win.c>>"!log_File!"
|
||||||
if %ERRORLEVEL% NEQ 0 (
|
if %ERRORLEVEL% NEQ 0 (
|
||||||
REM In most cases, compile errors happen because the version of GCC installed is too old
|
REM In most cases, compile errors happen because the version of GCC installed is too old
|
||||||
gcc --version>>"!log_File!"
|
gcc --version>>"!log_File!"
|
||||||
@ -279,8 +279,8 @@ set ObjFile=.v.c.obj
|
|||||||
|
|
||||||
echo ^> Attempting to build v_win.c with MSVC
|
echo ^> Attempting to build v_win.c with MSVC
|
||||||
if !flag_verbose! EQU 1 (
|
if !flag_verbose! EQU 1 (
|
||||||
echo [Debug] 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>>"!log_file!"
|
echo [Debug] cl.exe /volatile:ms /Fo%ObjFile% /I .\thirdparty\stdatomic\win /O2 /MD /D_VBOOTSTRAP vc\v_win.c user32.lib kernel32.lib advapi32.lib shell32.lib /link /nologo /out:v.exe /incremental:no>>"!log_file!"
|
||||||
echo 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
|
echo cl.exe /volatile:ms /Fo%ObjFile% /I .\thirdparty\stdatomic\win /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>>"!log_file!"
|
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>>"!log_file!"
|
||||||
if %ERRORLEVEL% NEQ 0 (
|
if %ERRORLEVEL% NEQ 0 (
|
||||||
|
100
thirdparty/stdatomic/nix/atomic.h
vendored
100
thirdparty/stdatomic/nix/atomic.h
vendored
@ -275,160 +275,160 @@ static inline unsigned char atomic_fetch_xor_byte(unsigned char* x, unsigned cha
|
|||||||
// Since V might be confused with "generic" C functions either we provide special versions
|
// Since V might be confused with "generic" C functions either we provide special versions
|
||||||
// for gcc/clang, too
|
// for gcc/clang, too
|
||||||
static inline unsigned long long atomic_load_u64(unsigned long long* x) {
|
static inline unsigned long long atomic_load_u64(unsigned long long* x) {
|
||||||
return atomic_load_explicit((_Atomic unsigned long long*)x, memory_order_seq_cst);
|
return atomic_load_explicit((_Atomic (unsigned long long)*)x, memory_order_seq_cst);
|
||||||
}
|
}
|
||||||
static inline void atomic_store_u64(unsigned long long* x, unsigned long long y) {
|
static inline void atomic_store_u64(unsigned long long* x, unsigned long long y) {
|
||||||
atomic_store_explicit((_Atomic unsigned long long*)x, y, memory_order_seq_cst);
|
atomic_store_explicit((_Atomic(unsigned long long)*)x, y, memory_order_seq_cst);
|
||||||
}
|
}
|
||||||
static inline int atomic_compare_exchange_weak_u64(unsigned long long* x, unsigned long long* expected, unsigned long long y) {
|
static inline int atomic_compare_exchange_weak_u64(unsigned long long* x, unsigned long long* expected, unsigned long long y) {
|
||||||
return (int)atomic_compare_exchange_weak_explicit((_Atomic unsigned long long*)x, expected, y, memory_order_seq_cst, memory_order_seq_cst);
|
return (int)atomic_compare_exchange_weak_explicit((_Atomic(unsigned long long)*)x, expected, y, memory_order_seq_cst, memory_order_seq_cst);
|
||||||
}
|
}
|
||||||
static inline int atomic_compare_exchange_strong_u64(unsigned long long* x, unsigned long long* expected, unsigned long long y) {
|
static inline int atomic_compare_exchange_strong_u64(unsigned long long* x, unsigned long long* expected, unsigned long long y) {
|
||||||
return (int)atomic_compare_exchange_strong_explicit((_Atomic unsigned long long*)x, expected, y, memory_order_seq_cst, memory_order_seq_cst);
|
return (int)atomic_compare_exchange_strong_explicit((_Atomic(unsigned long long)*)x, expected, y, memory_order_seq_cst, memory_order_seq_cst);
|
||||||
}
|
}
|
||||||
static inline unsigned long long atomic_exchange_u64(unsigned long long* x, unsigned long long y) {
|
static inline unsigned long long atomic_exchange_u64(unsigned long long* x, unsigned long long y) {
|
||||||
return atomic_exchange_explicit((_Atomic unsigned long long*)x, y, memory_order_seq_cst);
|
return atomic_exchange_explicit((_Atomic(unsigned long long)*)x, y, memory_order_seq_cst);
|
||||||
}
|
}
|
||||||
static inline unsigned long long atomic_fetch_add_u64(unsigned long long* x, unsigned long long y) {
|
static inline unsigned long long atomic_fetch_add_u64(unsigned long long* x, unsigned long long y) {
|
||||||
return atomic_fetch_add_explicit((_Atomic unsigned long long*)x, y, memory_order_seq_cst);
|
return atomic_fetch_add_explicit((_Atomic(unsigned long long)*)x, y, memory_order_seq_cst);
|
||||||
}
|
}
|
||||||
static inline unsigned long long atomic_fetch_sub_u64(unsigned long long* x, unsigned long long y) {
|
static inline unsigned long long atomic_fetch_sub_u64(unsigned long long* x, unsigned long long y) {
|
||||||
return atomic_fetch_sub_explicit((_Atomic unsigned long long*)x, y, memory_order_seq_cst);
|
return atomic_fetch_sub_explicit((_Atomic(unsigned long long)*)x, y, memory_order_seq_cst);
|
||||||
}
|
}
|
||||||
static inline unsigned long long atomic_fetch_and_u64(unsigned long long* x, unsigned long long y) {
|
static inline unsigned long long atomic_fetch_and_u64(unsigned long long* x, unsigned long long y) {
|
||||||
return atomic_fetch_and_explicit((_Atomic unsigned long long*)x, y, memory_order_seq_cst);
|
return atomic_fetch_and_explicit((_Atomic(unsigned long long)*)x, y, memory_order_seq_cst);
|
||||||
}
|
}
|
||||||
static inline unsigned long long atomic_fetch_or_u64(unsigned long long* x, unsigned long long y) {
|
static inline unsigned long long atomic_fetch_or_u64(unsigned long long* x, unsigned long long y) {
|
||||||
return atomic_fetch_or_explicit((_Atomic unsigned long long*)x, y, memory_order_seq_cst);
|
return atomic_fetch_or_explicit((_Atomic(unsigned long long)*)x, y, memory_order_seq_cst);
|
||||||
}
|
}
|
||||||
static inline unsigned long long atomic_fetch_xor_u64(unsigned long long* x, unsigned long long y) {
|
static inline unsigned long long atomic_fetch_xor_u64(unsigned long long* x, unsigned long long y) {
|
||||||
return atomic_fetch_xor_explicit((_Atomic unsigned long long*)x, y, memory_order_seq_cst);
|
return atomic_fetch_xor_explicit((_Atomic(unsigned long long)*)x, y, memory_order_seq_cst);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static inline void* atomic_load_ptr(void** x) {
|
static inline void* atomic_load_ptr(void** x) {
|
||||||
return (void*)atomic_load_explicit((_Atomic uintptr_t*)x, memory_order_seq_cst);
|
return (void*)atomic_load_explicit((_Atomic(uintptr_t)*)x, memory_order_seq_cst);
|
||||||
}
|
}
|
||||||
static inline void atomic_store_ptr(void** x, void* y) {
|
static inline void atomic_store_ptr(void** x, void* y) {
|
||||||
atomic_store_explicit((_Atomic uintptr_t*)x, (uintptr_t)y, memory_order_seq_cst);
|
atomic_store_explicit((_Atomic(uintptr_t)*)x, (uintptr_t)y, memory_order_seq_cst);
|
||||||
}
|
}
|
||||||
static inline int atomic_compare_exchange_weak_ptr(void** x, void** expected, void* y) {
|
static inline int atomic_compare_exchange_weak_ptr(void** x, void** expected, void* y) {
|
||||||
return (int)atomic_compare_exchange_weak_explicit((_Atomic uintptr_t*)x, (unsigned long *)expected, (uintptr_t)y, memory_order_seq_cst, memory_order_seq_cst);
|
return (int)atomic_compare_exchange_weak_explicit((_Atomic(uintptr_t)*)x, (unsigned long *)expected, (uintptr_t)y, memory_order_seq_cst, memory_order_seq_cst);
|
||||||
}
|
}
|
||||||
static inline int atomic_compare_exchange_strong_ptr(void** x, void** expected, void* y) {
|
static inline int atomic_compare_exchange_strong_ptr(void** x, void** expected, void* y) {
|
||||||
return (int)atomic_compare_exchange_strong_explicit((_Atomic uintptr_t*)x, (unsigned long *)expected, (uintptr_t)y, memory_order_seq_cst, memory_order_seq_cst);
|
return (int)atomic_compare_exchange_strong_explicit((_Atomic(uintptr_t)*)x, (unsigned long *)expected, (uintptr_t)y, memory_order_seq_cst, memory_order_seq_cst);
|
||||||
}
|
}
|
||||||
static inline void* atomic_exchange_ptr(void** x, void* y) {
|
static inline void* atomic_exchange_ptr(void** x, void* y) {
|
||||||
return (void*)atomic_exchange_explicit((_Atomic uintptr_t*)x, (uintptr_t)y, memory_order_seq_cst);
|
return (void*)atomic_exchange_explicit((_Atomic(uintptr_t)*)x, (uintptr_t)y, memory_order_seq_cst);
|
||||||
}
|
}
|
||||||
static inline void* atomic_fetch_add_ptr(void** x, void* y) {
|
static inline void* atomic_fetch_add_ptr(void** x, void* y) {
|
||||||
return (void*)atomic_fetch_add_explicit((_Atomic uintptr_t*)x, (uintptr_t)y, memory_order_seq_cst);
|
return (void*)atomic_fetch_add_explicit((_Atomic(uintptr_t)*)x, (uintptr_t)y, memory_order_seq_cst);
|
||||||
}
|
}
|
||||||
static inline void* atomic_fetch_sub_ptr(void** x, void* y) {
|
static inline void* atomic_fetch_sub_ptr(void** x, void* y) {
|
||||||
return (void*)atomic_fetch_sub_explicit((_Atomic uintptr_t*)x, (uintptr_t)y, memory_order_seq_cst);
|
return (void*)atomic_fetch_sub_explicit((_Atomic(uintptr_t)*)x, (uintptr_t)y, memory_order_seq_cst);
|
||||||
}
|
}
|
||||||
static inline void* atomic_fetch_and_ptr(void** x, void* y) {
|
static inline void* atomic_fetch_and_ptr(void** x, void* y) {
|
||||||
return (void*)atomic_fetch_and_explicit((_Atomic uintptr_t*)x, (uintptr_t)y, memory_order_seq_cst);
|
return (void*)atomic_fetch_and_explicit((_Atomic(uintptr_t)*)x, (uintptr_t)y, memory_order_seq_cst);
|
||||||
}
|
}
|
||||||
static inline void* atomic_fetch_or_ptr(void** x, void* y) {
|
static inline void* atomic_fetch_or_ptr(void** x, void* y) {
|
||||||
return (void*)atomic_fetch_or_explicit((_Atomic uintptr_t*)x, (uintptr_t)y, memory_order_seq_cst);
|
return (void*)atomic_fetch_or_explicit((_Atomic(uintptr_t)*)x, (uintptr_t)y, memory_order_seq_cst);
|
||||||
}
|
}
|
||||||
static inline void* atomic_fetch_xor_ptr(void** x, void* y) {
|
static inline void* atomic_fetch_xor_ptr(void** x, void* y) {
|
||||||
return (void*)atomic_fetch_xor_explicit((_Atomic uintptr_t*)x, (uintptr_t)y, memory_order_seq_cst);
|
return (void*)atomic_fetch_xor_explicit((_Atomic(uintptr_t)*)x, (uintptr_t)y, memory_order_seq_cst);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static inline unsigned atomic_load_u32(unsigned* x) {
|
static inline unsigned atomic_load_u32(unsigned* x) {
|
||||||
return atomic_load_explicit((_Atomic unsigned*)x, memory_order_seq_cst);
|
return atomic_load_explicit((_Atomic(unsigned)*)x, memory_order_seq_cst);
|
||||||
}
|
}
|
||||||
static inline void atomic_store_u32(unsigned* x, unsigned y) {
|
static inline void atomic_store_u32(unsigned* x, unsigned y) {
|
||||||
atomic_store_explicit((_Atomic unsigned*)x, y, memory_order_seq_cst);
|
atomic_store_explicit((_Atomic(unsigned)*)x, y, memory_order_seq_cst);
|
||||||
}
|
}
|
||||||
static inline int atomic_compare_exchange_weak_u32(unsigned* x, unsigned* expected, unsigned y) {
|
static inline int atomic_compare_exchange_weak_u32(unsigned* x, unsigned* expected, unsigned y) {
|
||||||
return (int)atomic_compare_exchange_weak_explicit((_Atomic unsigned*)x, expected, y, memory_order_seq_cst, memory_order_seq_cst);
|
return (int)atomic_compare_exchange_weak_explicit((_Atomic(unsigned)*)x, expected, y, memory_order_seq_cst, memory_order_seq_cst);
|
||||||
}
|
}
|
||||||
static inline int atomic_compare_exchange_strong_u32(unsigned* x, unsigned* expected, unsigned y) {
|
static inline int atomic_compare_exchange_strong_u32(unsigned* x, unsigned* expected, unsigned y) {
|
||||||
return (int)atomic_compare_exchange_strong_explicit((_Atomic unsigned*)x, expected, y, memory_order_seq_cst, memory_order_seq_cst);
|
return (int)atomic_compare_exchange_strong_explicit((_Atomic(unsigned)*)x, expected, y, memory_order_seq_cst, memory_order_seq_cst);
|
||||||
}
|
}
|
||||||
static inline unsigned atomic_exchange_u32(unsigned* x, unsigned y) {
|
static inline unsigned atomic_exchange_u32(unsigned* x, unsigned y) {
|
||||||
return atomic_exchange_explicit((_Atomic unsigned*)x, y, memory_order_seq_cst);
|
return atomic_exchange_explicit((_Atomic(unsigned)*)x, y, memory_order_seq_cst);
|
||||||
}
|
}
|
||||||
static inline unsigned atomic_fetch_add_u32(unsigned* x, unsigned y) {
|
static inline unsigned atomic_fetch_add_u32(unsigned* x, unsigned y) {
|
||||||
return atomic_fetch_add_explicit((_Atomic unsigned*)x, y, memory_order_seq_cst);
|
return atomic_fetch_add_explicit((_Atomic(unsigned)*)x, y, memory_order_seq_cst);
|
||||||
}
|
}
|
||||||
static inline unsigned atomic_fetch_sub_u32(unsigned* x, unsigned y) {
|
static inline unsigned atomic_fetch_sub_u32(unsigned* x, unsigned y) {
|
||||||
return atomic_fetch_sub_explicit((_Atomic unsigned*)x, y, memory_order_seq_cst);
|
return atomic_fetch_sub_explicit((_Atomic(unsigned)*)x, y, memory_order_seq_cst);
|
||||||
}
|
}
|
||||||
static inline unsigned atomic_fetch_and_u32(unsigned* x, unsigned y) {
|
static inline unsigned atomic_fetch_and_u32(unsigned* x, unsigned y) {
|
||||||
return atomic_fetch_and_explicit((_Atomic unsigned*)x, y, memory_order_seq_cst);
|
return atomic_fetch_and_explicit((_Atomic(unsigned)*)x, y, memory_order_seq_cst);
|
||||||
}
|
}
|
||||||
static inline unsigned atomic_fetch_or_u32(unsigned* x, unsigned y) {
|
static inline unsigned atomic_fetch_or_u32(unsigned* x, unsigned y) {
|
||||||
return atomic_fetch_or_explicit((_Atomic unsigned*)x, y, memory_order_seq_cst);
|
return atomic_fetch_or_explicit((_Atomic(unsigned)*)x, y, memory_order_seq_cst);
|
||||||
}
|
}
|
||||||
static inline unsigned atomic_fetch_xor_u32(unsigned* x, unsigned y) {
|
static inline unsigned atomic_fetch_xor_u32(unsigned* x, unsigned y) {
|
||||||
return atomic_fetch_xor_explicit((_Atomic unsigned*)x, y, memory_order_seq_cst);
|
return atomic_fetch_xor_explicit((_Atomic(unsigned)*)x, y, memory_order_seq_cst);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline unsigned short atomic_load_u16(unsigned short* x) {
|
static inline unsigned short atomic_load_u16(unsigned short* x) {
|
||||||
return atomic_load_explicit((_Atomic unsigned short*)x, memory_order_seq_cst);
|
return atomic_load_explicit((_Atomic(unsigned short)*)x, memory_order_seq_cst);
|
||||||
}
|
}
|
||||||
static inline void atomic_store_u16(void* x, unsigned short y) {
|
static inline void atomic_store_u16(void* x, unsigned short y) {
|
||||||
atomic_store_explicit((_Atomic unsigned short*)x, y, memory_order_seq_cst);
|
atomic_store_explicit((_Atomic(unsigned short)*)x, y, memory_order_seq_cst);
|
||||||
}
|
}
|
||||||
static inline int atomic_compare_exchange_weak_u16(void* x, unsigned short* expected, unsigned short y) {
|
static inline int atomic_compare_exchange_weak_u16(void* x, unsigned short* expected, unsigned short y) {
|
||||||
return (int)atomic_compare_exchange_weak_explicit((_Atomic unsigned short*)x, expected, y, memory_order_seq_cst, memory_order_seq_cst);
|
return (int)atomic_compare_exchange_weak_explicit((_Atomic(unsigned short)*)x, expected, y, memory_order_seq_cst, memory_order_seq_cst);
|
||||||
}
|
}
|
||||||
static inline int atomic_compare_exchange_strong_u16(unsigned short* x, unsigned short* expected, unsigned short y) {
|
static inline int atomic_compare_exchange_strong_u16(unsigned short* x, unsigned short* expected, unsigned short y) {
|
||||||
return (int)atomic_compare_exchange_strong_explicit((_Atomic unsigned short*)x, expected, y, memory_order_seq_cst, memory_order_seq_cst);
|
return (int)atomic_compare_exchange_strong_explicit((_Atomic(unsigned short)*)x, expected, y, memory_order_seq_cst, memory_order_seq_cst);
|
||||||
}
|
}
|
||||||
static inline unsigned short atomic_exchange_u16(unsigned short* x, unsigned short y) {
|
static inline unsigned short atomic_exchange_u16(unsigned short* x, unsigned short y) {
|
||||||
return atomic_exchange_explicit((_Atomic unsigned short*)x, y, memory_order_seq_cst);
|
return atomic_exchange_explicit((_Atomic(unsigned short)*)x, y, memory_order_seq_cst);
|
||||||
}
|
}
|
||||||
static inline unsigned short atomic_fetch_add_u16(unsigned short* x, unsigned short y) {
|
static inline unsigned short atomic_fetch_add_u16(unsigned short* x, unsigned short y) {
|
||||||
return atomic_fetch_add_explicit((_Atomic unsigned short*)x, y, memory_order_seq_cst);
|
return atomic_fetch_add_explicit((_Atomic(unsigned short)*)x, y, memory_order_seq_cst);
|
||||||
}
|
}
|
||||||
static inline unsigned short atomic_fetch_sub_u16(unsigned short* x, unsigned short y) {
|
static inline unsigned short atomic_fetch_sub_u16(unsigned short* x, unsigned short y) {
|
||||||
return atomic_fetch_sub_explicit((_Atomic unsigned short*)x, y, memory_order_seq_cst);
|
return atomic_fetch_sub_explicit((_Atomic(unsigned short)*)x, y, memory_order_seq_cst);
|
||||||
}
|
}
|
||||||
static inline unsigned short atomic_fetch_and_u16(unsigned short* x, unsigned short y) {
|
static inline unsigned short atomic_fetch_and_u16(unsigned short* x, unsigned short y) {
|
||||||
return atomic_fetch_and_explicit((_Atomic unsigned short*)x, y, memory_order_seq_cst);
|
return atomic_fetch_and_explicit((_Atomic(unsigned short)*)x, y, memory_order_seq_cst);
|
||||||
}
|
}
|
||||||
static inline unsigned short atomic_fetch_or_u16(unsigned short* x, unsigned short y) {
|
static inline unsigned short atomic_fetch_or_u16(unsigned short* x, unsigned short y) {
|
||||||
return atomic_fetch_or_explicit((_Atomic unsigned short*)x, y, memory_order_seq_cst);
|
return atomic_fetch_or_explicit((_Atomic(unsigned short)*)x, y, memory_order_seq_cst);
|
||||||
}
|
}
|
||||||
static inline unsigned short atomic_fetch_xor_u16(unsigned short* x, unsigned short y) {
|
static inline unsigned short atomic_fetch_xor_u16(unsigned short* x, unsigned short y) {
|
||||||
return atomic_fetch_xor_explicit((_Atomic unsigned short*)x, y, memory_order_seq_cst);
|
return atomic_fetch_xor_explicit((_Atomic(unsigned short)*)x, y, memory_order_seq_cst);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline unsigned char atomic_load_byte(unsigned char* x) {
|
static inline unsigned char atomic_load_byte(unsigned char* x) {
|
||||||
return atomic_load_explicit((_Atomic unsigned char*)x, memory_order_seq_cst);
|
return atomic_load_explicit((_Atomic(unsigned char)*)x, memory_order_seq_cst);
|
||||||
}
|
}
|
||||||
static inline void atomic_store_byte(unsigned char* x, unsigned char y) {
|
static inline void atomic_store_byte(unsigned char* x, unsigned char y) {
|
||||||
atomic_store_explicit((_Atomic unsigned char*)x, y, memory_order_seq_cst);
|
atomic_store_explicit((_Atomic(unsigned char)*)x, y, memory_order_seq_cst);
|
||||||
}
|
}
|
||||||
static inline int atomic_compare_exchange_weak_byte(unsigned char* x, unsigned char* expected, unsigned char y) {
|
static inline int atomic_compare_exchange_weak_byte(unsigned char* x, unsigned char* expected, unsigned char y) {
|
||||||
return (int)atomic_compare_exchange_weak_explicit((_Atomic unsigned char*)x, expected, y, memory_order_seq_cst, memory_order_seq_cst);
|
return (int)atomic_compare_exchange_weak_explicit((_Atomic(unsigned char)*)x, expected, y, memory_order_seq_cst, memory_order_seq_cst);
|
||||||
}
|
}
|
||||||
static inline int atomic_compare_exchange_strong_byte(unsigned char* x, unsigned char* expected, unsigned char y) {
|
static inline int atomic_compare_exchange_strong_byte(unsigned char* x, unsigned char* expected, unsigned char y) {
|
||||||
return (int)atomic_compare_exchange_strong_explicit((_Atomic unsigned char*)x, expected, y, memory_order_seq_cst, memory_order_seq_cst);
|
return (int)atomic_compare_exchange_strong_explicit((_Atomic(unsigned char)*)x, expected, y, memory_order_seq_cst, memory_order_seq_cst);
|
||||||
}
|
}
|
||||||
static inline unsigned char atomic_exchange_byte(unsigned char* x, unsigned char y) {
|
static inline unsigned char atomic_exchange_byte(unsigned char* x, unsigned char y) {
|
||||||
return atomic_exchange_explicit((_Atomic unsigned char*)x, y, memory_order_seq_cst);
|
return atomic_exchange_explicit((_Atomic(unsigned char)*)x, y, memory_order_seq_cst);
|
||||||
}
|
}
|
||||||
static inline unsigned char atomic_fetch_add_byte(unsigned char* x, unsigned char y) {
|
static inline unsigned char atomic_fetch_add_byte(unsigned char* x, unsigned char y) {
|
||||||
return atomic_fetch_add_explicit((_Atomic unsigned char*)x, y, memory_order_seq_cst);
|
return atomic_fetch_add_explicit((_Atomic(unsigned char)*)x, y, memory_order_seq_cst);
|
||||||
}
|
}
|
||||||
static inline unsigned char atomic_fetch_sub_byte(unsigned char* x, unsigned char y) {
|
static inline unsigned char atomic_fetch_sub_byte(unsigned char* x, unsigned char y) {
|
||||||
return atomic_fetch_sub_explicit((_Atomic unsigned char*)x, y, memory_order_seq_cst);
|
return atomic_fetch_sub_explicit((_Atomic(unsigned char)*)x, y, memory_order_seq_cst);
|
||||||
}
|
}
|
||||||
static inline unsigned char atomic_fetch_and_byte(unsigned char* x, unsigned char y) {
|
static inline unsigned char atomic_fetch_and_byte(unsigned char* x, unsigned char y) {
|
||||||
return atomic_fetch_and_explicit((_Atomic unsigned char*)x, y, memory_order_seq_cst);
|
return atomic_fetch_and_explicit((_Atomic(unsigned char)*)x, y, memory_order_seq_cst);
|
||||||
}
|
}
|
||||||
static inline unsigned char atomic_fetch_or_byte(unsigned char* x, unsigned char y) {
|
static inline unsigned char atomic_fetch_or_byte(unsigned char* x, unsigned char y) {
|
||||||
return atomic_fetch_or_explicit((_Atomic unsigned char*)x, y, memory_order_seq_cst);
|
return atomic_fetch_or_explicit((_Atomic(unsigned char)*)x, y, memory_order_seq_cst);
|
||||||
}
|
}
|
||||||
static inline unsigned char atomic_fetch_xor_byte(unsigned char* x, unsigned char y) {
|
static inline unsigned char atomic_fetch_xor_byte(unsigned char* x, unsigned char y) {
|
||||||
return atomic_fetch_xor_explicit((_Atomic unsigned char*)x, y, memory_order_seq_cst);
|
return atomic_fetch_xor_explicit((_Atomic(unsigned char)*)x, y, memory_order_seq_cst);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
7
thirdparty/stdatomic/nix/atomic_cpp.h
vendored
7
thirdparty/stdatomic/nix/atomic_cpp.h
vendored
@ -30,7 +30,7 @@
|
|||||||
#ifndef _STDATOMIC_H_
|
#ifndef _STDATOMIC_H_
|
||||||
#define _STDATOMIC_H_
|
#define _STDATOMIC_H_
|
||||||
#include <sys/cdefs.h>
|
#include <sys/cdefs.h>
|
||||||
#if defined(__cplusplus) && defined(_USING_LIBCXX)
|
#if defined(__cplusplus)
|
||||||
#ifdef __clang__
|
#ifdef __clang__
|
||||||
#if __has_feature(cxx_atomic)
|
#if __has_feature(cxx_atomic)
|
||||||
#define _STDATOMIC_HAVE_ATOMIC
|
#define _STDATOMIC_HAVE_ATOMIC
|
||||||
@ -42,8 +42,9 @@
|
|||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
#ifdef _STDATOMIC_HAVE_ATOMIC
|
#ifdef _STDATOMIC_HAVE_ATOMIC
|
||||||
/* We have a usable C++ <atomic>; use it instead. */
|
|
||||||
#include <atomic>
|
#include "cpp/atomic.h"
|
||||||
|
|
||||||
#undef _Atomic
|
#undef _Atomic
|
||||||
/* Also defined by <atomic> for gcc. But not used in macros. */
|
/* Also defined by <atomic> for gcc. But not used in macros. */
|
||||||
/* Also a clang intrinsic. */
|
/* Also a clang intrinsic. */
|
||||||
|
99
thirdparty/stdatomic/nix/cpp/gen.v
vendored
Normal file
99
thirdparty/stdatomic/nix/cpp/gen.v
vendored
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
import os
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
if os.args.len <= 1 {
|
||||||
|
eprintln('please specify a C++ compiler')
|
||||||
|
exit(1)
|
||||||
|
}
|
||||||
|
cc := os.args[1]
|
||||||
|
if os.execute('$cc -v').exit_code != 0 {
|
||||||
|
eprintln('please specify a valid C++ compiler')
|
||||||
|
exit(1)
|
||||||
|
}
|
||||||
|
cc_type, cc_version, cc_os := get_cc_info(cc)
|
||||||
|
triple := '$cc_type-$cc_version-$cc_os'
|
||||||
|
println('compiler: $triple')
|
||||||
|
|
||||||
|
search_paths := get_search_paths(cc)
|
||||||
|
atomic_path := find_file(search_paths, 'atomic') or {
|
||||||
|
eprintln(err)
|
||||||
|
exit(2)
|
||||||
|
}
|
||||||
|
|
||||||
|
bitsatomicbase_path := find_file(search_paths, 'bits/atomic_base.h') or {
|
||||||
|
if cc_os == 'linux' {
|
||||||
|
eprintln(err)
|
||||||
|
exit(2)
|
||||||
|
}
|
||||||
|
'no_file' // bits/atomic_base.h is only used on linux
|
||||||
|
}
|
||||||
|
|
||||||
|
patch_atomic(os.join_path(os.dir(@FILE), 'atomic.h'), atomic_path) or {
|
||||||
|
eprintln(err)
|
||||||
|
exit(2)
|
||||||
|
}
|
||||||
|
|
||||||
|
if bitsatomicbase_path != 'no_file' {
|
||||||
|
patch_bitsatomicbase(os.join_path(os.dir(@FILE), 'bitsatomicbase.h'), bitsatomicbase_path) or {
|
||||||
|
eprintln(err)
|
||||||
|
exit(2)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
println('$atomic_path:::$bitsatomicbase_path')
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_cc_info(cc string) (string, string, string) {
|
||||||
|
cc_type := if cc.contains('clang') {
|
||||||
|
'clang'
|
||||||
|
} else if cc.contains('g') {
|
||||||
|
'gcc'
|
||||||
|
} else {
|
||||||
|
eprintln('only gcc and clang are supported')
|
||||||
|
exit(1)
|
||||||
|
'none'
|
||||||
|
}
|
||||||
|
|
||||||
|
lines := os.execute('$cc -v').output.split('\n')
|
||||||
|
|
||||||
|
// gcc and clang both have the same way way to say what version they have and what the host target triple is
|
||||||
|
cc_version := lines.filter(it.contains('$cc_type version '))[0].all_after('$cc_type version ').all_before('.')
|
||||||
|
|
||||||
|
cc_os := lines.filter(it.starts_with('Target: '))[0].all_after('Target: ').split('-')[2]
|
||||||
|
|
||||||
|
return cc_type, cc_version, if cc_os.contains('darwin') {
|
||||||
|
'darwin' // remove 20.6.0 from darwin20.6.0
|
||||||
|
} else {
|
||||||
|
cc_os
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_search_paths(cc string) []string {
|
||||||
|
result := os.execute('$cc -v -x c++ /dev/null').output
|
||||||
|
lines := result.split('\n')
|
||||||
|
search_path := lines[lines.index('#include <...> search starts here:') + 1..lines.index('End of search list.')]
|
||||||
|
return search_path.map(os.real_path(it.all_before('(').trim_space()))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn find_file(search_paths []string, file string) ?string {
|
||||||
|
for search_path in search_paths {
|
||||||
|
if os.exists(os.join_path(search_path, file)) {
|
||||||
|
return os.join_path(search_path, file)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return error('$file not found')
|
||||||
|
}
|
||||||
|
|
||||||
|
fn patch_atomic(outfile string, infile string) ? {
|
||||||
|
lines := os.read_file(infile) ?.split('\n')
|
||||||
|
outlines := lines.filter(!it.contains('atomic(const atomic&) = delete;'))
|
||||||
|
outtext := outlines.join('\n').replace('#include <bits/atomic_base.h>', '#include "bitsatomicbase.h"')
|
||||||
|
os.write_file(outfile, outtext) ?
|
||||||
|
}
|
||||||
|
|
||||||
|
fn patch_bitsatomicbase(outfile string, infile string) ? {
|
||||||
|
lines := os.read_file(infile) ?.split('\n')
|
||||||
|
outlines := lines.filter(!it.contains('__atomic_base(const __atomic_base&) = delete;'))
|
||||||
|
outtext := outlines.join('\n').replace('#include <bits/atomic_base.h>', '#include "bitsatomicbase.h"')
|
||||||
|
os.write_file(outfile, outtext) ?
|
||||||
|
}
|
@ -126,3 +126,10 @@ pub:
|
|||||||
arg string
|
arg string
|
||||||
kind AttributeKind
|
kind AttributeKind
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[used]
|
||||||
|
fn v_segmentation_fault_handler(signal int) {
|
||||||
|
eprintln('signal 11: segmentation fault')
|
||||||
|
print_backtrace()
|
||||||
|
exit(128 + 11)
|
||||||
|
}
|
||||||
|
@ -623,8 +623,8 @@ pub fn channel_select(mut channels []&Channel, dir []Direction, mut objrefs []vo
|
|||||||
}
|
}
|
||||||
subscr[i].prev = unsafe { &ch.write_subscriber }
|
subscr[i].prev = unsafe { &ch.write_subscriber }
|
||||||
unsafe {
|
unsafe {
|
||||||
subscr[i].nxt = C.atomic_exchange_ptr(&voidptr(&ch.write_subscriber),
|
subscr[i].nxt = &Subscription(C.atomic_exchange_ptr(&voidptr(&ch.write_subscriber),
|
||||||
&subscr[i])
|
&subscr[i]))
|
||||||
}
|
}
|
||||||
if voidptr(subscr[i].nxt) != voidptr(0) {
|
if voidptr(subscr[i].nxt) != voidptr(0) {
|
||||||
subscr[i].nxt.prev = unsafe { &subscr[i].nxt }
|
subscr[i].nxt.prev = unsafe { &subscr[i].nxt }
|
||||||
@ -637,7 +637,8 @@ pub fn channel_select(mut channels []&Channel, dir []Direction, mut objrefs []vo
|
|||||||
}
|
}
|
||||||
subscr[i].prev = unsafe { &ch.read_subscriber }
|
subscr[i].prev = unsafe { &ch.read_subscriber }
|
||||||
unsafe {
|
unsafe {
|
||||||
subscr[i].nxt = C.atomic_exchange_ptr(&voidptr(&ch.read_subscriber), &subscr[i])
|
subscr[i].nxt = &Subscription(C.atomic_exchange_ptr(&voidptr(&ch.read_subscriber),
|
||||||
|
&subscr[i]))
|
||||||
}
|
}
|
||||||
if voidptr(subscr[i].nxt) != voidptr(0) {
|
if voidptr(subscr[i].nxt) != voidptr(0) {
|
||||||
subscr[i].nxt.prev = unsafe { &subscr[i].nxt }
|
subscr[i].nxt.prev = unsafe { &subscr[i].nxt }
|
||||||
|
@ -32,6 +32,18 @@ fn C.sem_trywait(voidptr) int
|
|||||||
fn C.sem_timedwait(voidptr, voidptr) int
|
fn C.sem_timedwait(voidptr, voidptr) int
|
||||||
fn C.sem_destroy(voidptr) int
|
fn C.sem_destroy(voidptr) int
|
||||||
|
|
||||||
|
[typedef]
|
||||||
|
struct C.pthread_mutex_t {}
|
||||||
|
|
||||||
|
[typedef]
|
||||||
|
struct C.pthread_rwlock_t {}
|
||||||
|
|
||||||
|
[typedef]
|
||||||
|
struct C.pthread_rwlockattr_t {}
|
||||||
|
|
||||||
|
[typedef]
|
||||||
|
struct C.sem_t {}
|
||||||
|
|
||||||
// [init_with=new_mutex] // TODO: implement support for this struct attribute, and disallow Mutex{} from outside the sync.new_mutex() function.
|
// [init_with=new_mutex] // TODO: implement support for this struct attribute, and disallow Mutex{} from outside the sync.new_mutex() function.
|
||||||
[heap]
|
[heap]
|
||||||
pub struct Mutex {
|
pub struct Mutex {
|
||||||
|
@ -1259,7 +1259,7 @@ pub fn (mut t Table) bitsize_to_type(bit_size int) Type {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (mut t Table) does_type_implement_interface(typ Type, inter_typ Type) bool {
|
pub fn (t Table) does_type_implement_interface(typ Type, inter_typ Type) bool {
|
||||||
if typ.idx() == inter_typ.idx() {
|
if typ.idx() == inter_typ.idx() {
|
||||||
// same type -> already casted to the interface
|
// same type -> already casted to the interface
|
||||||
return true
|
return true
|
||||||
|
@ -556,7 +556,7 @@ pub enum Kind {
|
|||||||
thread
|
thread
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (t &TypeSymbol) str() string {
|
pub fn (t TypeSymbol) str() string {
|
||||||
return t.name
|
return t.name
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -641,11 +641,6 @@ pub fn (t &TypeSymbol) is_heap() bool {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
pub fn (t TypeSymbol) str() string {
|
|
||||||
return t.name
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
pub fn (mut t Table) register_builtin_type_symbols() {
|
pub fn (mut t Table) register_builtin_type_symbols() {
|
||||||
// reserve index 0 so nothing can go there
|
// reserve index 0 so nothing can go there
|
||||||
// save index check, 0 will mean not found
|
// save index check, 0 will mean not found
|
||||||
|
@ -550,6 +550,18 @@ fn (mut v Builder) cc() {
|
|||||||
v.setup_ccompiler_options(ccompiler)
|
v.setup_ccompiler_options(ccompiler)
|
||||||
v.build_thirdparty_obj_files()
|
v.build_thirdparty_obj_files()
|
||||||
v.setup_output_name()
|
v.setup_output_name()
|
||||||
|
|
||||||
|
if v.pref.os != .windows && ccompiler.contains('++') {
|
||||||
|
for file in v.parsed_files {
|
||||||
|
if file.imports.any(it.mod.contains('sync')) {
|
||||||
|
x := @VEXE + ' run ' +
|
||||||
|
os.join_path(@VEXEROOT, 'thirdparty', 'stdatomic', 'nix', 'cpp', 'gen.v') +
|
||||||
|
' ' + ccompiler
|
||||||
|
os.execute(x)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
//
|
//
|
||||||
mut libs := []string{} // builtin.o os.o http.o etc
|
mut libs := []string{} // builtin.o os.o http.o etc
|
||||||
if v.pref.build_mode == .build_module {
|
if v.pref.build_mode == .build_module {
|
||||||
|
@ -418,7 +418,9 @@ pub fn (mut c Checker) fail_if_unreadable(expr ast.Expr, typ ast.Type, what stri
|
|||||||
pos = expr.left.position().extend(expr.pos)
|
pos = expr.left.position().extend(expr.pos)
|
||||||
c.fail_if_unreadable(expr.left, expr.left_type, what)
|
c.fail_if_unreadable(expr.left, expr.left_type, what)
|
||||||
}
|
}
|
||||||
else {}
|
else {
|
||||||
|
pos = expr.position()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if typ.has_flag(.shared_f) {
|
if typ.has_flag(.shared_f) {
|
||||||
c.error('you have to create a handle and `rlock` it to use a `shared` element as non-mut $what',
|
c.error('you have to create a handle and `rlock` it to use a `shared` element as non-mut $what',
|
||||||
|
@ -226,7 +226,15 @@ pub fn (mut f Fmt) short_module(name string) string {
|
|||||||
idx := vals.len - 1
|
idx := vals.len - 1
|
||||||
mname, tprefix := f.get_modname_prefix(vals[..idx].join('.'))
|
mname, tprefix := f.get_modname_prefix(vals[..idx].join('.'))
|
||||||
symname := vals[vals.len - 1]
|
symname := vals[vals.len - 1]
|
||||||
aname := f.mod2alias[mname]
|
mut aname := f.mod2alias[mname]
|
||||||
|
if aname == '' {
|
||||||
|
for _, v in f.mod2alias {
|
||||||
|
if v == mname {
|
||||||
|
aname = mname
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
if aname == '' {
|
if aname == '' {
|
||||||
return symname
|
return symname
|
||||||
}
|
}
|
||||||
|
@ -254,7 +254,9 @@ fn (mut g Gen) gen_array_sort(node ast.CallExpr) {
|
|||||||
// the only argument can only be an infix expression like `a < b` or `b.field > a.field`
|
// the only argument can only be an infix expression like `a < b` or `b.field > a.field`
|
||||||
if node.args.len == 0 {
|
if node.args.len == 0 {
|
||||||
comparison_type = g.unwrap(info.elem_type.set_nr_muls(0))
|
comparison_type = g.unwrap(info.elem_type.set_nr_muls(0))
|
||||||
if compare_fn in g.array_sort_fn {
|
shared a := g.array_sort_fn
|
||||||
|
array_sort_fn := a.clone()
|
||||||
|
if compare_fn in array_sort_fn {
|
||||||
g.gen_array_sort_call(node, compare_fn)
|
g.gen_array_sort_call(node, compare_fn)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -273,7 +275,9 @@ fn (mut g Gen) gen_array_sort(node ast.CallExpr) {
|
|||||||
if is_reverse {
|
if is_reverse {
|
||||||
compare_fn += '_reverse'
|
compare_fn += '_reverse'
|
||||||
}
|
}
|
||||||
if compare_fn in g.array_sort_fn {
|
shared a := g.array_sort_fn
|
||||||
|
array_sort_fn := a.clone()
|
||||||
|
if compare_fn in array_sort_fn {
|
||||||
g.gen_array_sort_call(node, compare_fn)
|
g.gen_array_sort_call(node, compare_fn)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -300,8 +304,9 @@ fn (mut g Gen) gen_array_sort(node ast.CallExpr) {
|
|||||||
|
|
||||||
// Register a new custom `compare_xxx` function for qsort()
|
// Register a new custom `compare_xxx` function for qsort()
|
||||||
// TODO: move to checker
|
// TODO: move to checker
|
||||||
g.table.register_fn(name: compare_fn, return_type: ast.int_type)
|
lock g.array_sort_fn {
|
||||||
g.array_sort_fn[compare_fn] = true
|
g.array_sort_fn << compare_fn
|
||||||
|
}
|
||||||
|
|
||||||
stype_arg := g.typ(info.elem_type)
|
stype_arg := g.typ(info.elem_type)
|
||||||
g.definitions.writeln('int ${compare_fn}($stype_arg* a, $stype_arg* b) {')
|
g.definitions.writeln('int ${compare_fn}($stype_arg* a, $stype_arg* b) {')
|
||||||
@ -485,16 +490,22 @@ fn (mut g Gen) gen_array_prepend(node ast.CallExpr) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (mut g Gen) gen_array_contains_method(left_type ast.Type) string {
|
fn (mut g Gen) get_array_contains_method(typ ast.Type) string {
|
||||||
mut unwrap_left_type := g.unwrap_generic(left_type)
|
t := g.table.get_final_type_symbol(g.unwrap_generic(typ).set_nr_muls(0)).idx
|
||||||
if unwrap_left_type.share() == .shared_t {
|
g.array_contains_types << t
|
||||||
unwrap_left_type = unwrap_left_type.clear_flag(.shared_f)
|
return g.typ(t) + '_contains'
|
||||||
}
|
}
|
||||||
mut left_sym := g.table.get_type_symbol(unwrap_left_type)
|
|
||||||
left_final_sym := g.table.get_final_type_symbol(unwrap_left_type)
|
fn (mut g Gen) gen_array_contains_methods() {
|
||||||
mut left_type_str := g.typ(unwrap_left_type).replace('*', '')
|
mut done := []ast.Type{}
|
||||||
fn_name := '${left_type_str}_contains'
|
for t in g.array_contains_types {
|
||||||
if !left_sym.has_method('contains') {
|
left_final_sym := g.table.get_final_type_symbol(t)
|
||||||
|
if left_final_sym.idx in done || g.table.get_type_symbol(t).has_method('contains') {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
done << t
|
||||||
|
mut left_type_str := g.typ(t)
|
||||||
|
fn_name := '${left_type_str}_contains'
|
||||||
left_info := left_final_sym.info as ast.Array
|
left_info := left_final_sym.info as ast.Array
|
||||||
mut elem_type_str := g.typ(left_info.elem_type)
|
mut elem_type_str := g.typ(left_info.elem_type)
|
||||||
elem_sym := g.table.get_type_symbol(left_info.elem_type)
|
elem_sym := g.table.get_type_symbol(left_info.elem_type)
|
||||||
@ -509,15 +520,15 @@ fn (mut g Gen) gen_array_contains_method(left_type ast.Type) string {
|
|||||||
if elem_sym.kind == .string {
|
if elem_sym.kind == .string {
|
||||||
fn_builder.writeln('\t\tif (fast_string_eq(((string*)a.data)[i], v)) {')
|
fn_builder.writeln('\t\tif (fast_string_eq(((string*)a.data)[i], v)) {')
|
||||||
} else if elem_sym.kind == .array && left_info.elem_type.nr_muls() == 0 {
|
} else if elem_sym.kind == .array && left_info.elem_type.nr_muls() == 0 {
|
||||||
ptr_typ := g.gen_array_equality_fn(left_info.elem_type)
|
ptr_typ := g.equality_fn(left_info.elem_type)
|
||||||
fn_builder.writeln('\t\tif (${ptr_typ}_arr_eq((($elem_type_str*)a.data)[i], v)) {')
|
fn_builder.writeln('\t\tif (${ptr_typ}_arr_eq((($elem_type_str*)a.data)[i], v)) {')
|
||||||
} else if elem_sym.kind == .function {
|
} else if elem_sym.kind == .function {
|
||||||
fn_builder.writeln('\t\tif (((voidptr*)a.data)[i] == v) {')
|
fn_builder.writeln('\t\tif (((voidptr*)a.data)[i] == v) {')
|
||||||
} else if elem_sym.kind == .map && left_info.elem_type.nr_muls() == 0 {
|
} else if elem_sym.kind == .map && left_info.elem_type.nr_muls() == 0 {
|
||||||
ptr_typ := g.gen_map_equality_fn(left_info.elem_type)
|
ptr_typ := g.equality_fn(left_info.elem_type)
|
||||||
fn_builder.writeln('\t\tif (${ptr_typ}_map_eq((($elem_type_str*)a.data)[i], v)) {')
|
fn_builder.writeln('\t\tif (${ptr_typ}_map_eq((($elem_type_str*)a.data)[i], v)) {')
|
||||||
} else if elem_sym.kind == .struct_ && left_info.elem_type.nr_muls() == 0 {
|
} else if elem_sym.kind == .struct_ && left_info.elem_type.nr_muls() == 0 {
|
||||||
ptr_typ := g.gen_struct_equality_fn(left_info.elem_type)
|
ptr_typ := g.equality_fn(left_info.elem_type)
|
||||||
fn_builder.writeln('\t\tif (${ptr_typ}_struct_eq((($elem_type_str*)a.data)[i], v)) {')
|
fn_builder.writeln('\t\tif (${ptr_typ}_struct_eq((($elem_type_str*)a.data)[i], v)) {')
|
||||||
} else {
|
} else {
|
||||||
fn_builder.writeln('\t\tif ((($elem_type_str*)a.data)[i] == v) {')
|
fn_builder.writeln('\t\tif ((($elem_type_str*)a.data)[i] == v) {')
|
||||||
@ -528,41 +539,43 @@ fn (mut g Gen) gen_array_contains_method(left_type ast.Type) string {
|
|||||||
fn_builder.writeln('\treturn false;')
|
fn_builder.writeln('\treturn false;')
|
||||||
fn_builder.writeln('}')
|
fn_builder.writeln('}')
|
||||||
g.auto_fn_definitions << fn_builder.str()
|
g.auto_fn_definitions << fn_builder.str()
|
||||||
left_sym.register_method(&ast.Fn{
|
|
||||||
name: 'contains'
|
|
||||||
params: [ast.Param{
|
|
||||||
typ: unwrap_left_type
|
|
||||||
}, ast.Param{
|
|
||||||
typ: left_info.elem_type
|
|
||||||
}]
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
return fn_name
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// `nums.contains(2)`
|
// `nums.contains(2)`
|
||||||
fn (mut g Gen) gen_array_contains(node ast.CallExpr) {
|
fn (mut g Gen) gen_array_contains(typ ast.Type, left ast.Expr, right ast.Expr) {
|
||||||
fn_name := g.gen_array_contains_method(node.left_type)
|
fn_name := g.get_array_contains_method(typ)
|
||||||
g.write('${fn_name}(')
|
g.write('${fn_name}(')
|
||||||
if node.left_type.is_ptr() && node.left_type.share() != .shared_t {
|
g.write(strings.repeat(`*`, typ.nr_muls()))
|
||||||
g.write('*')
|
if typ.share() == .shared_t {
|
||||||
|
g.out.go_back(1)
|
||||||
}
|
}
|
||||||
g.expr(node.left)
|
g.expr(left)
|
||||||
if node.left_type.share() == .shared_t {
|
if typ.share() == .shared_t {
|
||||||
g.write('->val')
|
g.write('->val')
|
||||||
}
|
}
|
||||||
g.write(', ')
|
g.write(', ')
|
||||||
g.expr(node.args[0].expr)
|
g.expr(right)
|
||||||
g.write(')')
|
g.write(')')
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (mut g Gen) gen_array_index_method(left_type ast.Type) string {
|
fn (mut g Gen) get_array_index_method(typ ast.Type) string {
|
||||||
unwrap_left_type := g.unwrap_generic(left_type)
|
t := g.unwrap_generic(typ).set_nr_muls(0)
|
||||||
mut left_sym := g.table.get_type_symbol(unwrap_left_type)
|
g.array_index_types << t
|
||||||
mut left_type_str := g.typ(unwrap_left_type).trim('*')
|
return g.typ(t) + '_index'
|
||||||
fn_name := '${left_type_str}_index'
|
}
|
||||||
if !left_sym.has_method('index') {
|
|
||||||
info := left_sym.info as ast.Array
|
fn (mut g Gen) gen_array_index_methods() {
|
||||||
|
mut done := []ast.Type{}
|
||||||
|
for t in g.array_index_types {
|
||||||
|
if t in done || g.table.get_type_symbol(t).has_method('index') {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
done << t
|
||||||
|
final_left_sym := g.table.get_final_type_symbol(t)
|
||||||
|
mut left_type_str := g.typ(t)
|
||||||
|
fn_name := '${left_type_str}_index'
|
||||||
|
info := final_left_sym.info as ast.Array
|
||||||
mut elem_type_str := g.typ(info.elem_type)
|
mut elem_type_str := g.typ(info.elem_type)
|
||||||
elem_sym := g.table.get_type_symbol(info.elem_type)
|
elem_sym := g.table.get_type_symbol(info.elem_type)
|
||||||
if elem_sym.kind == .function {
|
if elem_sym.kind == .function {
|
||||||
@ -577,15 +590,15 @@ fn (mut g Gen) gen_array_index_method(left_type ast.Type) string {
|
|||||||
if elem_sym.kind == .string {
|
if elem_sym.kind == .string {
|
||||||
fn_builder.writeln('\t\tif (fast_string_eq(*pelem, v)) {')
|
fn_builder.writeln('\t\tif (fast_string_eq(*pelem, v)) {')
|
||||||
} else if elem_sym.kind == .array && !info.elem_type.is_ptr() {
|
} else if elem_sym.kind == .array && !info.elem_type.is_ptr() {
|
||||||
ptr_typ := g.gen_array_equality_fn(info.elem_type)
|
ptr_typ := g.equality_fn(info.elem_type)
|
||||||
fn_builder.writeln('\t\tif (${ptr_typ}_arr_eq( *pelem, v)) {')
|
fn_builder.writeln('\t\tif (${ptr_typ}_arr_eq( *pelem, v)) {')
|
||||||
} else if elem_sym.kind == .function && !info.elem_type.is_ptr() {
|
} else if elem_sym.kind == .function && !info.elem_type.is_ptr() {
|
||||||
fn_builder.writeln('\t\tif ( pelem == v) {')
|
fn_builder.writeln('\t\tif ( pelem == v) {')
|
||||||
} else if elem_sym.kind == .map && !info.elem_type.is_ptr() {
|
} else if elem_sym.kind == .map && !info.elem_type.is_ptr() {
|
||||||
ptr_typ := g.gen_map_equality_fn(info.elem_type)
|
ptr_typ := g.equality_fn(info.elem_type)
|
||||||
fn_builder.writeln('\t\tif (${ptr_typ}_map_eq(( *pelem, v))) {')
|
fn_builder.writeln('\t\tif (${ptr_typ}_map_eq(( *pelem, v))) {')
|
||||||
} else if elem_sym.kind == .struct_ && !info.elem_type.is_ptr() {
|
} else if elem_sym.kind == .struct_ && !info.elem_type.is_ptr() {
|
||||||
ptr_typ := g.gen_struct_equality_fn(info.elem_type)
|
ptr_typ := g.equality_fn(info.elem_type)
|
||||||
fn_builder.writeln('\t\tif (${ptr_typ}_struct_eq( *pelem, v)) {')
|
fn_builder.writeln('\t\tif (${ptr_typ}_struct_eq( *pelem, v)) {')
|
||||||
} else {
|
} else {
|
||||||
fn_builder.writeln('\t\tif (*pelem == v) {')
|
fn_builder.writeln('\t\tif (*pelem == v) {')
|
||||||
@ -596,21 +609,12 @@ fn (mut g Gen) gen_array_index_method(left_type ast.Type) string {
|
|||||||
fn_builder.writeln('\treturn -1;')
|
fn_builder.writeln('\treturn -1;')
|
||||||
fn_builder.writeln('}')
|
fn_builder.writeln('}')
|
||||||
g.auto_fn_definitions << fn_builder.str()
|
g.auto_fn_definitions << fn_builder.str()
|
||||||
left_sym.register_method(&ast.Fn{
|
|
||||||
name: 'index'
|
|
||||||
params: [ast.Param{
|
|
||||||
typ: unwrap_left_type
|
|
||||||
}, ast.Param{
|
|
||||||
typ: info.elem_type
|
|
||||||
}]
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
return fn_name
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// `nums.index(2)`
|
// `nums.index(2)`
|
||||||
fn (mut g Gen) gen_array_index(node ast.CallExpr) {
|
fn (mut g Gen) gen_array_index(node ast.CallExpr) {
|
||||||
fn_name := g.gen_array_index_method(node.left_type)
|
fn_name := g.get_array_index_method(node.left_type)
|
||||||
g.write('${fn_name}(')
|
g.write('${fn_name}(')
|
||||||
if node.left_type.is_ptr() {
|
if node.left_type.is_ptr() {
|
||||||
g.write('*')
|
g.write('*')
|
||||||
|
@ -20,7 +20,7 @@ fn (mut g Gen) gen_assert_stmt(original_assert_statement ast.AssertStmt) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
g.inside_ternary++
|
g.inside_ternary++
|
||||||
if g.is_test {
|
if g.pref.is_test {
|
||||||
g.write('if (')
|
g.write('if (')
|
||||||
g.expr(node.expr)
|
g.expr(node.expr)
|
||||||
g.write(')')
|
g.write(')')
|
||||||
|
@ -5,13 +5,52 @@ module c
|
|||||||
import strings
|
import strings
|
||||||
import v.ast
|
import v.ast
|
||||||
|
|
||||||
|
fn (mut g Gen) equality_fn(typ ast.Type) string {
|
||||||
|
g.needed_equality_fns << typ.set_nr_muls(0)
|
||||||
|
return g.typ(g.unwrap_generic(typ).set_nr_muls(0))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn (mut g Gen) gen_equality_fns() {
|
||||||
|
for needed_typ in g.needed_equality_fns {
|
||||||
|
if needed_typ in g.generated_eq_fns {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
sym := g.table.get_type_symbol(needed_typ)
|
||||||
|
match sym.kind {
|
||||||
|
.sum_type {
|
||||||
|
g.gen_sumtype_equality_fn(needed_typ)
|
||||||
|
}
|
||||||
|
.struct_ {
|
||||||
|
g.gen_struct_equality_fn(needed_typ)
|
||||||
|
}
|
||||||
|
.array {
|
||||||
|
g.gen_array_equality_fn(needed_typ)
|
||||||
|
}
|
||||||
|
.array_fixed {
|
||||||
|
g.gen_fixed_array_equality_fn(needed_typ)
|
||||||
|
}
|
||||||
|
.map {
|
||||||
|
g.gen_map_equality_fn(needed_typ)
|
||||||
|
}
|
||||||
|
.alias {
|
||||||
|
g.gen_alias_equality_fn(needed_typ)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
verror('could not generate equality function for type $sym.kind')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn (mut g Gen) gen_sumtype_equality_fn(left_type ast.Type) string {
|
fn (mut g Gen) gen_sumtype_equality_fn(left_type ast.Type) string {
|
||||||
left := g.unwrap(left_type)
|
left := g.unwrap(left_type)
|
||||||
ptr_styp := g.typ(left.typ.set_nr_muls(0))
|
ptr_styp := g.typ(left.typ.set_nr_muls(0))
|
||||||
if ptr_styp in g.sumtype_fn_definitions {
|
|
||||||
|
if left_type in g.generated_eq_fns {
|
||||||
return ptr_styp
|
return ptr_styp
|
||||||
}
|
}
|
||||||
g.sumtype_fn_definitions << ptr_styp
|
g.generated_eq_fns << left_type
|
||||||
|
|
||||||
info := left.sym.sumtype_info()
|
info := left.sym.sumtype_info()
|
||||||
g.type_definitions.writeln('static bool ${ptr_styp}_sumtype_eq($ptr_styp a, $ptr_styp b); // auto')
|
g.type_definitions.writeln('static bool ${ptr_styp}_sumtype_eq($ptr_styp a, $ptr_styp b); // auto')
|
||||||
|
|
||||||
@ -59,10 +98,10 @@ fn (mut g Gen) gen_struct_equality_fn(left_type ast.Type) string {
|
|||||||
left := g.unwrap(left_type)
|
left := g.unwrap(left_type)
|
||||||
ptr_styp := g.typ(left.typ.set_nr_muls(0))
|
ptr_styp := g.typ(left.typ.set_nr_muls(0))
|
||||||
fn_name := ptr_styp.replace('struct ', '')
|
fn_name := ptr_styp.replace('struct ', '')
|
||||||
if fn_name in g.struct_fn_definitions {
|
if left_type in g.generated_eq_fns {
|
||||||
return fn_name
|
return fn_name
|
||||||
}
|
}
|
||||||
g.struct_fn_definitions << fn_name
|
g.generated_eq_fns << left_type
|
||||||
info := left.sym.struct_info()
|
info := left.sym.struct_info()
|
||||||
g.type_definitions.writeln('static bool ${fn_name}_struct_eq($ptr_styp a, $ptr_styp b); // auto')
|
g.type_definitions.writeln('static bool ${fn_name}_struct_eq($ptr_styp a, $ptr_styp b); // auto')
|
||||||
|
|
||||||
@ -124,10 +163,10 @@ fn (mut g Gen) gen_struct_equality_fn(left_type ast.Type) string {
|
|||||||
fn (mut g Gen) gen_alias_equality_fn(left_type ast.Type) string {
|
fn (mut g Gen) gen_alias_equality_fn(left_type ast.Type) string {
|
||||||
left := g.unwrap(left_type)
|
left := g.unwrap(left_type)
|
||||||
ptr_styp := g.typ(left.typ.set_nr_muls(0))
|
ptr_styp := g.typ(left.typ.set_nr_muls(0))
|
||||||
if ptr_styp in g.alias_fn_definitions {
|
if left_type in g.generated_eq_fns {
|
||||||
return ptr_styp
|
return ptr_styp
|
||||||
}
|
}
|
||||||
g.alias_fn_definitions << ptr_styp
|
g.generated_eq_fns << left_type
|
||||||
info := left.sym.info as ast.Alias
|
info := left.sym.info as ast.Alias
|
||||||
g.type_definitions.writeln('static bool ${ptr_styp}_alias_eq($ptr_styp a, $ptr_styp b); // auto')
|
g.type_definitions.writeln('static bool ${ptr_styp}_alias_eq($ptr_styp a, $ptr_styp b); // auto')
|
||||||
|
|
||||||
@ -164,10 +203,10 @@ fn (mut g Gen) gen_alias_equality_fn(left_type ast.Type) string {
|
|||||||
fn (mut g Gen) gen_array_equality_fn(left_type ast.Type) string {
|
fn (mut g Gen) gen_array_equality_fn(left_type ast.Type) string {
|
||||||
left := g.unwrap(left_type)
|
left := g.unwrap(left_type)
|
||||||
ptr_styp := g.typ(left.typ.set_nr_muls(0))
|
ptr_styp := g.typ(left.typ.set_nr_muls(0))
|
||||||
if ptr_styp in g.array_fn_definitions {
|
if left_type in g.generated_eq_fns {
|
||||||
return ptr_styp
|
return ptr_styp
|
||||||
}
|
}
|
||||||
g.array_fn_definitions << ptr_styp
|
g.generated_eq_fns << left_type
|
||||||
elem := g.unwrap(left.sym.array_info().elem_type)
|
elem := g.unwrap(left.sym.array_info().elem_type)
|
||||||
ptr_elem_styp := g.typ(elem.typ)
|
ptr_elem_styp := g.typ(elem.typ)
|
||||||
g.type_definitions.writeln('static bool ${ptr_styp}_arr_eq($ptr_styp a, $ptr_styp b); // auto')
|
g.type_definitions.writeln('static bool ${ptr_styp}_arr_eq($ptr_styp a, $ptr_styp b); // auto')
|
||||||
@ -216,10 +255,10 @@ fn (mut g Gen) gen_array_equality_fn(left_type ast.Type) string {
|
|||||||
fn (mut g Gen) gen_fixed_array_equality_fn(left_type ast.Type) string {
|
fn (mut g Gen) gen_fixed_array_equality_fn(left_type ast.Type) string {
|
||||||
left := g.unwrap(left_type)
|
left := g.unwrap(left_type)
|
||||||
ptr_styp := g.typ(left.typ.set_nr_muls(0))
|
ptr_styp := g.typ(left.typ.set_nr_muls(0))
|
||||||
if ptr_styp in g.array_fn_definitions {
|
if left_type in g.generated_eq_fns {
|
||||||
return ptr_styp
|
return ptr_styp
|
||||||
}
|
}
|
||||||
g.array_fn_definitions << ptr_styp
|
g.generated_eq_fns << left_type
|
||||||
elem_info := left.sym.array_fixed_info()
|
elem_info := left.sym.array_fixed_info()
|
||||||
elem := g.unwrap(elem_info.elem_type)
|
elem := g.unwrap(elem_info.elem_type)
|
||||||
size := elem_info.size
|
size := elem_info.size
|
||||||
@ -266,10 +305,10 @@ fn (mut g Gen) gen_fixed_array_equality_fn(left_type ast.Type) string {
|
|||||||
fn (mut g Gen) gen_map_equality_fn(left_type ast.Type) string {
|
fn (mut g Gen) gen_map_equality_fn(left_type ast.Type) string {
|
||||||
left := g.unwrap(left_type)
|
left := g.unwrap(left_type)
|
||||||
ptr_styp := g.typ(left.typ.set_nr_muls(0))
|
ptr_styp := g.typ(left.typ.set_nr_muls(0))
|
||||||
if ptr_styp in g.map_fn_definitions {
|
if left_type in g.generated_eq_fns {
|
||||||
return ptr_styp
|
return ptr_styp
|
||||||
}
|
}
|
||||||
g.map_fn_definitions << ptr_styp
|
g.generated_eq_fns << left_type
|
||||||
value := g.unwrap(left.sym.map_info().value_type)
|
value := g.unwrap(left.sym.map_info().value_type)
|
||||||
ptr_value_styp := g.typ(value.typ)
|
ptr_value_styp := g.typ(value.typ)
|
||||||
g.type_definitions.writeln('static bool ${ptr_styp}_map_eq($ptr_styp a, $ptr_styp b); // auto')
|
g.type_definitions.writeln('static bool ${ptr_styp}_map_eq($ptr_styp a, $ptr_styp b); // auto')
|
||||||
|
@ -117,9 +117,26 @@ fn (mut g Gen) gen_str_default(sym ast.TypeSymbol, styp string, str_fn_name stri
|
|||||||
g.auto_str_funcs.writeln('}')
|
g.auto_str_funcs.writeln('}')
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (mut g Gen) gen_str_method_for_type(typ ast.Type) string {
|
struct StrType {
|
||||||
styp := g.typ(typ).replace('*', '')
|
styp string
|
||||||
mut sym := g.table.get_type_symbol(g.unwrap_generic(typ))
|
mut:
|
||||||
|
typ ast.Type
|
||||||
|
}
|
||||||
|
|
||||||
|
fn (mut g Gen) get_str_fn(typ ast.Type) string {
|
||||||
|
mut unwrapped := g.unwrap_generic(typ).set_nr_muls(0).clear_flag(.variadic)
|
||||||
|
if g.pref.nofloat {
|
||||||
|
if typ == ast.f32_type {
|
||||||
|
unwrapped = ast.u32_type
|
||||||
|
} else if typ == ast.f64_type {
|
||||||
|
unwrapped = ast.u64_type
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if typ.has_flag(.optional) {
|
||||||
|
unwrapped.set_flag(.optional)
|
||||||
|
}
|
||||||
|
styp := g.typ(unwrapped)
|
||||||
|
mut sym := g.table.get_type_symbol(unwrapped)
|
||||||
mut str_fn_name := styp_to_str_fn_name(styp)
|
mut str_fn_name := styp_to_str_fn_name(styp)
|
||||||
if mut sym.info is ast.Alias {
|
if mut sym.info is ast.Alias {
|
||||||
if sym.info.is_import {
|
if sym.info.is_import {
|
||||||
@ -127,85 +144,80 @@ fn (mut g Gen) gen_str_method_for_type(typ ast.Type) string {
|
|||||||
str_fn_name = styp_to_str_fn_name(sym.name)
|
str_fn_name = styp_to_str_fn_name(sym.name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
sym_has_str_method, str_method_expects_ptr, str_nr_args := sym.str_method_info()
|
g.str_types << StrType{
|
||||||
already_generated_key := '$styp:$str_fn_name'
|
typ: unwrapped
|
||||||
if !sym_has_str_method && already_generated_key !in g.str_types && !typ.has_flag(.optional) {
|
styp: styp
|
||||||
$if debugautostr ? {
|
|
||||||
eprintln('> gen_str_for_type: |typ: ${typ:5}, ${sym.name:20}|has_str: ${sym_has_str_method:5}|expects_ptr: ${str_method_expects_ptr:5}|nr_args: ${str_nr_args:1}|fn_name: ${str_fn_name:20}')
|
|
||||||
}
|
|
||||||
g.str_types << already_generated_key
|
|
||||||
if g.pref.nofloat {
|
|
||||||
if sym.name == 'f32' {
|
|
||||||
return g.gen_str_method_for_type(ast.u32_type)
|
|
||||||
// return ''
|
|
||||||
} else if sym.name == 'f64' {
|
|
||||||
return g.gen_str_method_for_type(ast.u64_type)
|
|
||||||
// return ''
|
|
||||||
}
|
|
||||||
}
|
|
||||||
match mut sym.info {
|
|
||||||
ast.Alias {
|
|
||||||
if sym.info.is_import {
|
|
||||||
g.gen_str_default(sym, styp, str_fn_name)
|
|
||||||
} else {
|
|
||||||
g.gen_str_for_alias(sym.info, styp, str_fn_name)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ast.Array {
|
|
||||||
g.gen_str_for_array(sym.info, styp, str_fn_name)
|
|
||||||
}
|
|
||||||
ast.ArrayFixed {
|
|
||||||
g.gen_str_for_array_fixed(sym.info, styp, str_fn_name)
|
|
||||||
}
|
|
||||||
ast.Enum {
|
|
||||||
g.gen_str_for_enum(sym.info, styp, str_fn_name)
|
|
||||||
}
|
|
||||||
ast.FnType {
|
|
||||||
g.gen_str_for_fn_type(sym.info, styp, str_fn_name)
|
|
||||||
}
|
|
||||||
ast.Struct {
|
|
||||||
g.gen_str_for_struct(sym.info, styp, str_fn_name)
|
|
||||||
}
|
|
||||||
ast.Map {
|
|
||||||
g.gen_str_for_map(sym.info, styp, str_fn_name)
|
|
||||||
}
|
|
||||||
ast.MultiReturn {
|
|
||||||
g.gen_str_for_multi_return(sym.info, styp, str_fn_name)
|
|
||||||
}
|
|
||||||
ast.SumType {
|
|
||||||
g.gen_str_for_union_sum_type(sym.info, styp, str_fn_name)
|
|
||||||
}
|
|
||||||
ast.Interface {
|
|
||||||
g.gen_str_for_interface(sym.info, styp, str_fn_name)
|
|
||||||
}
|
|
||||||
ast.Chan {
|
|
||||||
g.gen_str_for_chan(sym.info, styp, str_fn_name)
|
|
||||||
}
|
|
||||||
ast.Thread {
|
|
||||||
g.gen_str_for_thread(sym.info, styp, str_fn_name)
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
println(g.table.type_str(typ))
|
|
||||||
verror("1could not generate string method '$str_fn_name' for type '$styp'")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if typ.has_flag(.optional) {
|
|
||||||
option_already_generated_key := 'option_$already_generated_key'
|
|
||||||
if option_already_generated_key !in g.str_types {
|
|
||||||
g.gen_str_for_option(typ, styp, str_fn_name)
|
|
||||||
g.str_types << option_already_generated_key
|
|
||||||
}
|
|
||||||
return str_fn_name
|
|
||||||
}
|
}
|
||||||
return str_fn_name
|
return str_fn_name
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn (mut g Gen) final_gen_str(typ StrType) {
|
||||||
|
if typ in g.generated_str_fns {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
g.generated_str_fns << typ
|
||||||
|
sym := g.table.get_type_symbol(typ.typ)
|
||||||
|
if sym.has_method('str') && !typ.typ.has_flag(.optional) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
styp := typ.styp
|
||||||
|
str_fn_name := styp_to_str_fn_name(styp)
|
||||||
|
if typ.typ.has_flag(.optional) {
|
||||||
|
g.gen_str_for_option(typ.typ, styp, str_fn_name)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
match mut sym.info {
|
||||||
|
ast.Alias {
|
||||||
|
if sym.info.is_import {
|
||||||
|
g.gen_str_default(sym, styp, str_fn_name)
|
||||||
|
} else {
|
||||||
|
g.gen_str_for_alias(sym.info, styp, str_fn_name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ast.Array {
|
||||||
|
g.gen_str_for_array(sym.info, styp, str_fn_name)
|
||||||
|
}
|
||||||
|
ast.ArrayFixed {
|
||||||
|
g.gen_str_for_array_fixed(sym.info, styp, str_fn_name)
|
||||||
|
}
|
||||||
|
ast.Enum {
|
||||||
|
g.gen_str_for_enum(sym.info, styp, str_fn_name)
|
||||||
|
}
|
||||||
|
ast.FnType {
|
||||||
|
g.gen_str_for_fn_type(sym.info, styp, str_fn_name)
|
||||||
|
}
|
||||||
|
ast.Struct {
|
||||||
|
g.gen_str_for_struct(sym.info, styp, str_fn_name)
|
||||||
|
}
|
||||||
|
ast.Map {
|
||||||
|
g.gen_str_for_map(sym.info, styp, str_fn_name)
|
||||||
|
}
|
||||||
|
ast.MultiReturn {
|
||||||
|
g.gen_str_for_multi_return(sym.info, styp, str_fn_name)
|
||||||
|
}
|
||||||
|
ast.SumType {
|
||||||
|
g.gen_str_for_union_sum_type(sym.info, styp, str_fn_name)
|
||||||
|
}
|
||||||
|
ast.Interface {
|
||||||
|
g.gen_str_for_interface(sym.info, styp, str_fn_name)
|
||||||
|
}
|
||||||
|
ast.Chan {
|
||||||
|
g.gen_str_for_chan(sym.info, styp, str_fn_name)
|
||||||
|
}
|
||||||
|
ast.Thread {
|
||||||
|
g.gen_str_for_thread(sym.info, styp, str_fn_name)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
verror("could not generate string method $str_fn_name for type '$styp'")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn (mut g Gen) gen_str_for_option(typ ast.Type, styp string, str_fn_name string) {
|
fn (mut g Gen) gen_str_for_option(typ ast.Type, styp string, str_fn_name string) {
|
||||||
parent_type := typ.clear_flag(.optional)
|
parent_type := typ.clear_flag(.optional)
|
||||||
sym := g.table.get_type_symbol(parent_type)
|
sym := g.table.get_type_symbol(parent_type)
|
||||||
sym_has_str_method, _, _ := sym.str_method_info()
|
sym_has_str_method, _, _ := sym.str_method_info()
|
||||||
parent_str_fn_name := g.gen_str_method_for_type(parent_type)
|
parent_str_fn_name := g.get_str_fn(parent_type)
|
||||||
|
|
||||||
g.type_definitions.writeln('string ${str_fn_name}($styp it); // auto')
|
g.type_definitions.writeln('string ${str_fn_name}($styp it); // auto')
|
||||||
g.auto_str_funcs.writeln('string ${str_fn_name}($styp it) { return indent_${str_fn_name}(it, 0); }')
|
g.auto_str_funcs.writeln('string ${str_fn_name}($styp it) { return indent_${str_fn_name}(it, 0); }')
|
||||||
@ -232,7 +244,7 @@ fn (mut g Gen) gen_str_for_option(typ ast.Type, styp string, str_fn_name string)
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn (mut g Gen) gen_str_for_alias(info ast.Alias, styp string, str_fn_name string) {
|
fn (mut g Gen) gen_str_for_alias(info ast.Alias, styp string, str_fn_name string) {
|
||||||
parent_str_fn_name := g.gen_str_method_for_type(info.parent_type)
|
parent_str_fn_name := g.get_str_fn(info.parent_type)
|
||||||
mut clean_type_v_type_name := util.strip_main_name(styp.replace('__', '.'))
|
mut clean_type_v_type_name := util.strip_main_name(styp.replace('__', '.'))
|
||||||
g.type_definitions.writeln('static string ${str_fn_name}($styp it); // auto')
|
g.type_definitions.writeln('static string ${str_fn_name}($styp it); // auto')
|
||||||
g.auto_str_funcs.writeln('static string ${str_fn_name}($styp it) { return indent_${str_fn_name}(it, 0); }')
|
g.auto_str_funcs.writeln('static string ${str_fn_name}($styp it) { return indent_${str_fn_name}(it, 0); }')
|
||||||
@ -261,7 +273,7 @@ fn (mut g Gen) gen_str_for_multi_return(info ast.MultiReturn, styp string, str_f
|
|||||||
sym := g.table.get_type_symbol(typ)
|
sym := g.table.get_type_symbol(typ)
|
||||||
is_arg_ptr := typ.is_ptr()
|
is_arg_ptr := typ.is_ptr()
|
||||||
sym_has_str_method, str_method_expects_ptr, _ := sym.str_method_info()
|
sym_has_str_method, str_method_expects_ptr, _ := sym.str_method_info()
|
||||||
arg_str_fn_name := g.gen_str_method_for_type(typ)
|
arg_str_fn_name := g.get_str_fn(typ)
|
||||||
|
|
||||||
if should_use_indent_func(sym.kind) && !sym_has_str_method {
|
if should_use_indent_func(sym.kind) && !sym_has_str_method {
|
||||||
fn_builder.writeln('\tstrings__Builder_write_string(&sb, ${arg_str_fn_name}(a.arg$i));')
|
fn_builder.writeln('\tstrings__Builder_write_string(&sb, ${arg_str_fn_name}(a.arg$i));')
|
||||||
@ -346,7 +358,7 @@ fn (mut g Gen) gen_str_for_interface(info ast.Interface, styp string, str_fn_nam
|
|||||||
fn_builder.writeln('static string indent_${str_fn_name}($styp x, int indent_count) { /* gen_str_for_interface */')
|
fn_builder.writeln('static string indent_${str_fn_name}($styp x, int indent_count) { /* gen_str_for_interface */')
|
||||||
for typ in info.types {
|
for typ in info.types {
|
||||||
subtype := g.table.get_type_symbol(typ)
|
subtype := g.table.get_type_symbol(typ)
|
||||||
mut func_name := g.gen_str_method_for_type(typ)
|
mut func_name := g.get_str_fn(typ)
|
||||||
sym_has_str_method, str_method_expects_ptr, _ := subtype.str_method_info()
|
sym_has_str_method, str_method_expects_ptr, _ := subtype.str_method_info()
|
||||||
if should_use_indent_func(subtype.kind) && !sym_has_str_method {
|
if should_use_indent_func(subtype.kind) && !sym_has_str_method {
|
||||||
func_name = 'indent_$func_name'
|
func_name = 'indent_$func_name'
|
||||||
@ -405,7 +417,7 @@ fn (mut g Gen) gen_str_for_union_sum_type(info ast.SumType, styp string, str_fn_
|
|||||||
fn_builder.writeln('\tswitch(x._typ) {')
|
fn_builder.writeln('\tswitch(x._typ) {')
|
||||||
for typ in info.variants {
|
for typ in info.variants {
|
||||||
typ_str := g.typ(typ)
|
typ_str := g.typ(typ)
|
||||||
mut func_name := g.gen_str_method_for_type(typ)
|
mut func_name := g.get_str_fn(typ)
|
||||||
sym := g.table.get_type_symbol(typ)
|
sym := g.table.get_type_symbol(typ)
|
||||||
sym_has_str_method, str_method_expects_ptr, _ := sym.str_method_info()
|
sym_has_str_method, str_method_expects_ptr, _ := sym.str_method_info()
|
||||||
deref := if sym_has_str_method && str_method_expects_ptr { ' ' } else { '*' }
|
deref := if sym_has_str_method && str_method_expects_ptr { ' ' } else { '*' }
|
||||||
@ -512,7 +524,7 @@ fn (mut g Gen) gen_str_for_array(info ast.Array, styp string, str_fn_name string
|
|||||||
field_styp := g.typ(typ)
|
field_styp := g.typ(typ)
|
||||||
is_elem_ptr := typ.is_ptr()
|
is_elem_ptr := typ.is_ptr()
|
||||||
sym_has_str_method, str_method_expects_ptr, _ := sym.str_method_info()
|
sym_has_str_method, str_method_expects_ptr, _ := sym.str_method_info()
|
||||||
mut elem_str_fn_name := g.gen_str_method_for_type(typ)
|
mut elem_str_fn_name := g.get_str_fn(typ)
|
||||||
if sym.kind == .byte {
|
if sym.kind == .byte {
|
||||||
elem_str_fn_name = elem_str_fn_name + '_escaped'
|
elem_str_fn_name = elem_str_fn_name + '_escaped'
|
||||||
}
|
}
|
||||||
@ -584,7 +596,7 @@ fn (mut g Gen) gen_str_for_array_fixed(info ast.ArrayFixed, styp string, str_fn_
|
|||||||
}
|
}
|
||||||
is_elem_ptr := typ.is_ptr()
|
is_elem_ptr := typ.is_ptr()
|
||||||
sym_has_str_method, str_method_expects_ptr, _ := sym.str_method_info()
|
sym_has_str_method, str_method_expects_ptr, _ := sym.str_method_info()
|
||||||
elem_str_fn_name := g.gen_str_method_for_type(typ)
|
elem_str_fn_name := g.get_str_fn(typ)
|
||||||
|
|
||||||
g.type_definitions.writeln('static string ${str_fn_name}($styp a); // auto')
|
g.type_definitions.writeln('static string ${str_fn_name}($styp a); // auto')
|
||||||
g.auto_str_funcs.writeln('static string ${str_fn_name}($styp a) { return indent_${str_fn_name}(a, 0);}')
|
g.auto_str_funcs.writeln('static string ${str_fn_name}($styp a) { return indent_${str_fn_name}(a, 0);}')
|
||||||
@ -645,7 +657,7 @@ fn (mut g Gen) gen_str_for_map(info ast.Map, styp string, str_fn_name string) {
|
|||||||
key_styp := g.typ(key_typ)
|
key_styp := g.typ(key_typ)
|
||||||
key_str_fn_name := key_styp.replace('*', '') + '_str'
|
key_str_fn_name := key_styp.replace('*', '') + '_str'
|
||||||
if !key_sym.has_method('str') {
|
if !key_sym.has_method('str') {
|
||||||
g.gen_str_method_for_type(key_typ)
|
g.get_str_fn(key_typ)
|
||||||
}
|
}
|
||||||
|
|
||||||
mut val_typ := info.value_type
|
mut val_typ := info.value_type
|
||||||
@ -657,7 +669,7 @@ fn (mut g Gen) gen_str_for_map(info ast.Map, styp string, str_fn_name string) {
|
|||||||
val_styp := g.typ(val_typ)
|
val_styp := g.typ(val_typ)
|
||||||
elem_str_fn_name := val_styp.replace('*', '') + '_str'
|
elem_str_fn_name := val_styp.replace('*', '') + '_str'
|
||||||
if !val_sym.has_method('str') {
|
if !val_sym.has_method('str') {
|
||||||
g.gen_str_method_for_type(val_typ)
|
g.get_str_fn(val_typ)
|
||||||
}
|
}
|
||||||
|
|
||||||
g.type_definitions.writeln('static string ${str_fn_name}($styp m); // auto')
|
g.type_definitions.writeln('static string ${str_fn_name}($styp m); // auto')
|
||||||
@ -813,7 +825,7 @@ fn (mut g Gen) gen_str_for_struct(info ast.Struct, styp string, str_fn_name stri
|
|||||||
field_styp_fn_name := if has_custom_str {
|
field_styp_fn_name := if has_custom_str {
|
||||||
'${field_styp}_str'
|
'${field_styp}_str'
|
||||||
} else {
|
} else {
|
||||||
g.gen_str_method_for_type(field.typ)
|
g.get_str_fn(field.typ)
|
||||||
}
|
}
|
||||||
|
|
||||||
// manage the fact hat with float we use always the g representation
|
// manage the fact hat with float we use always the g representation
|
||||||
|
@ -11,6 +11,7 @@ import v.token
|
|||||||
import v.util
|
import v.util
|
||||||
import v.util.version
|
import v.util.version
|
||||||
import v.depgraph
|
import v.depgraph
|
||||||
|
import sync.pool
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// NB: some of the words in c_reserved, are not reserved in C,
|
// NB: some of the words in c_reserved, are not reserved in C,
|
||||||
@ -37,11 +38,12 @@ fn string_array_to_map(a []string) map[string]bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct Gen {
|
struct Gen {
|
||||||
pref &pref.Preferences
|
pref &pref.Preferences
|
||||||
module_built string
|
field_data_type ast.Type // cache her to avoid map lookups
|
||||||
field_data_type ast.Type // cache her to avoid map lookups
|
module_built string
|
||||||
|
timers_should_print bool
|
||||||
|
table &ast.Table
|
||||||
mut:
|
mut:
|
||||||
table &ast.Table
|
|
||||||
out strings.Builder
|
out strings.Builder
|
||||||
cheaders strings.Builder
|
cheaders strings.Builder
|
||||||
includes strings.Builder // all C #includes required by V modules
|
includes strings.Builder // all C #includes required by V modules
|
||||||
@ -50,7 +52,10 @@ mut:
|
|||||||
type_definitions strings.Builder // typedefs, defines etc (everything that goes to the top of the file)
|
type_definitions strings.Builder // typedefs, defines etc (everything that goes to the top of the file)
|
||||||
definitions strings.Builder // typedefs, defines etc (everything that goes to the top of the file)
|
definitions strings.Builder // typedefs, defines etc (everything that goes to the top of the file)
|
||||||
global_inits map[string]strings.Builder // default initializers for globals (goes in _vinit())
|
global_inits map[string]strings.Builder // default initializers for globals (goes in _vinit())
|
||||||
|
global_init strings.Builder // thread local of the above
|
||||||
inits map[string]strings.Builder // contents of `void _vinit/2{}`
|
inits map[string]strings.Builder // contents of `void _vinit/2{}`
|
||||||
|
init strings.Builder
|
||||||
|
cleanup strings.Builder
|
||||||
cleanups map[string]strings.Builder // contents of `void _vcleanup(){}`
|
cleanups map[string]strings.Builder // contents of `void _vcleanup(){}`
|
||||||
gowrappers strings.Builder // all go callsite wrappers
|
gowrappers strings.Builder // all go callsite wrappers
|
||||||
stringliterals strings.Builder // all string literals (they depend on tos3() beeing defined
|
stringliterals strings.Builder // all string literals (they depend on tos3() beeing defined
|
||||||
@ -62,7 +67,6 @@ mut:
|
|||||||
shared_types strings.Builder // shared/lock types
|
shared_types strings.Builder // shared/lock types
|
||||||
shared_functions strings.Builder // shared constructors
|
shared_functions strings.Builder // shared constructors
|
||||||
channel_definitions strings.Builder // channel related code
|
channel_definitions strings.Builder // channel related code
|
||||||
options_typedefs strings.Builder // Option typedefs
|
|
||||||
options strings.Builder // `Option_xxxx` types
|
options strings.Builder // `Option_xxxx` types
|
||||||
json_forward_decls strings.Builder // json type forward decls
|
json_forward_decls strings.Builder // json type forward decls
|
||||||
enum_typedefs strings.Builder // enum types
|
enum_typedefs strings.Builder // enum types
|
||||||
@ -70,32 +74,33 @@ mut:
|
|||||||
file &ast.File
|
file &ast.File
|
||||||
fn_decl &ast.FnDecl // pointer to the FnDecl we are currently inside otherwise 0
|
fn_decl &ast.FnDecl // pointer to the FnDecl we are currently inside otherwise 0
|
||||||
last_fn_c_name string
|
last_fn_c_name string
|
||||||
tmp_count int // counter for unique tmp vars (_tmp1, _tmp2 etc); resets at the start of each fn.
|
tmp_count int // counter for unique tmp vars (_tmp1, _tmp2 etc); resets at the start of each fn.
|
||||||
tmp_count2 int // a separate tmp var counter for autofree fn calls
|
tmp_count2 int // a separate tmp var counter for autofree fn calls
|
||||||
tmp_count_declarations int // counter for unique tmp names (_d1, _d2 etc); does NOT reset, used for C declarations
|
tmp_count_declarations int // counter for unique tmp names (_d1, _d2 etc); does NOT reset, used for C declarations
|
||||||
global_tmp_count int // like tmp_count but global and not resetted in each function
|
global_tmp_count int // like tmp_count but global and not resetted in each function
|
||||||
is_assign_lhs bool // inside left part of assign expr (for array_set(), etc)
|
is_assign_lhs bool // inside left part of assign expr (for array_set(), etc)
|
||||||
discard_or_result bool // do not safe last ExprStmt of `or` block in tmp variable to defer ongoing expr usage
|
discard_or_result bool // do not safe last ExprStmt of `or` block in tmp variable to defer ongoing expr usage
|
||||||
is_void_expr_stmt bool // ExprStmt whos result is discarded
|
is_void_expr_stmt bool // ExprStmt whos result is discarded
|
||||||
is_arraymap_set bool // map or array set value state
|
is_arraymap_set bool // map or array set value state
|
||||||
is_amp bool // for `&Foo{}` to merge PrefixExpr `&` and StructInit `Foo{}`; also for `&byte(0)` etc
|
is_amp bool // for `&Foo{}` to merge PrefixExpr `&` and StructInit `Foo{}`; also for `&byte(0)` etc
|
||||||
is_sql bool // Inside `sql db{}` statement, generating sql instead of C (e.g. `and` instead of `&&` etc)
|
is_sql bool // Inside `sql db{}` statement, generating sql instead of C (e.g. `and` instead of `&&` etc)
|
||||||
is_shared bool // for initialization of hidden mutex in `[rw]shared` literals
|
is_shared bool // for initialization of hidden mutex in `[rw]shared` literals
|
||||||
is_vlines_enabled bool // is it safe to generate #line directives when -g is passed
|
is_vlines_enabled bool // is it safe to generate #line directives when -g is passed
|
||||||
inside_cast_in_heap int // inside cast to interface type in heap (resolve recursive calls)
|
inside_cast_in_heap int // inside cast to interface type in heap (resolve recursive calls)
|
||||||
arraymap_set_pos int // map or array set value position
|
arraymap_set_pos int // map or array set value position
|
||||||
vlines_path string // set to the proper path for generating #line directives
|
vlines_path string // set to the proper path for generating #line directives
|
||||||
optionals []string // to avoid duplicates TODO perf, use map
|
optionals map[string]string // to avoid duplicates
|
||||||
chan_pop_optionals []string // types for `x := <-ch or {...}`
|
done_optionals shared []string // to avoid duplicates
|
||||||
chan_push_optionals []string // types for `ch <- x or {...}`
|
chan_pop_optionals map[string]string // types for `x := <-ch or {...}`
|
||||||
|
chan_push_optionals map[string]string // types for `ch <- x or {...}`
|
||||||
cur_lock ast.LockExpr
|
cur_lock ast.LockExpr
|
||||||
mtxs string // array of mutexes if the `lock` has multiple variables
|
mtxs string // array of mutexes if the `lock` has multiple variables
|
||||||
labeled_loops map[string]&ast.Stmt
|
labeled_loops map[string]&ast.Stmt
|
||||||
inner_loop &ast.Stmt
|
inner_loop &ast.Stmt
|
||||||
shareds []int // types with hidden mutex for which decl has been emitted
|
shareds map[int]string // types with hidden mutex for which decl has been emitted
|
||||||
inside_ternary int // ?: comma separated statements on a single line
|
inside_ternary int // ?: comma separated statements on a single line
|
||||||
inside_map_postfix bool // inside map++/-- postfix expr
|
inside_map_postfix bool // inside map++/-- postfix expr
|
||||||
inside_map_infix bool // inside map<</+=/-= infix expr
|
inside_map_infix bool // inside map<</+=/-= infix expr
|
||||||
inside_map_index bool
|
inside_map_index bool
|
||||||
inside_opt_data bool
|
inside_opt_data bool
|
||||||
inside_if_optional bool
|
inside_if_optional bool
|
||||||
@ -107,24 +112,20 @@ mut:
|
|||||||
is_autofree bool // false, inside the bodies of fns marked with [manualfree], otherwise === g.pref.autofree
|
is_autofree bool // false, inside the bodies of fns marked with [manualfree], otherwise === g.pref.autofree
|
||||||
indent int
|
indent int
|
||||||
empty_line bool
|
empty_line bool
|
||||||
is_test bool
|
|
||||||
assign_op token.Kind // *=, =, etc (for array_set)
|
assign_op token.Kind // *=, =, etc (for array_set)
|
||||||
defer_stmts []ast.DeferStmt
|
defer_stmts []ast.DeferStmt
|
||||||
defer_ifdef string
|
defer_ifdef string
|
||||||
defer_profile_code string
|
defer_profile_code string
|
||||||
str_types []string // types that need automatic str() generation
|
str_types []StrType // types that need automatic str() generation
|
||||||
threaded_fns []string // for generating unique wrapper types and fns for `go xxx()`
|
generated_str_fns []StrType // types that already have a str() function
|
||||||
waiter_fns []string // functions that wait for `go xxx()` to finish
|
threaded_fns []string // for generating unique wrapper types and fns for `go xxx()`
|
||||||
array_fn_definitions []string // array equality functions that have been defined
|
waiter_fns []string // functions that wait for `go xxx()` to finish
|
||||||
map_fn_definitions []string // map equality functions that have been defined
|
auto_fn_definitions []string // auto generated functions defination list
|
||||||
struct_fn_definitions []string // struct equality functions that have been defined
|
sumtype_casting_fns []SumtypeCastingFn
|
||||||
sumtype_fn_definitions []string // sumtype equality functions that have been defined
|
|
||||||
alias_fn_definitions []string // alias equality functions that have been defined
|
|
||||||
auto_fn_definitions []string // auto generated functions defination list
|
|
||||||
anon_fn_definitions []string // anon generated functions defination list
|
anon_fn_definitions []string // anon generated functions defination list
|
||||||
sumtype_definitions map[int]bool // `_TypeA_to_sumtype_TypeB()` fns that have been generated
|
sumtype_definitions map[int]bool // `_TypeA_to_sumtype_TypeB()` fns that have been generated
|
||||||
is_json_fn bool // inside json.encode()
|
is_json_fn bool // inside json.encode()
|
||||||
json_types []string // to avoid json gen duplicates
|
json_types []ast.Type // to avoid json gen duplicates
|
||||||
pcs []ProfileCounterMeta // -prof profile counter fn_names => fn counter name
|
pcs []ProfileCounterMeta // -prof profile counter fn_names => fn counter name
|
||||||
is_builtin_mod bool
|
is_builtin_mod bool
|
||||||
hotcode_fn_names []string
|
hotcode_fn_names []string
|
||||||
@ -177,11 +178,18 @@ mut:
|
|||||||
as_cast_type_names map[string]string // table for type name lookup in runtime (for __as_cast)
|
as_cast_type_names map[string]string // table for type name lookup in runtime (for __as_cast)
|
||||||
obf_table map[string]string
|
obf_table map[string]string
|
||||||
// main_fn_decl_node ast.FnDecl
|
// main_fn_decl_node ast.FnDecl
|
||||||
expected_cast_type ast.Type // for match expr of sumtypes
|
nr_closures int
|
||||||
defer_vars []string
|
array_sort_fn shared []string
|
||||||
anon_fn bool
|
expected_cast_type ast.Type // for match expr of sumtypes
|
||||||
array_sort_fn map[string]bool
|
defer_vars []string
|
||||||
nr_closures int
|
anon_fn bool
|
||||||
|
tests_inited bool
|
||||||
|
cur_concrete_types []ast.Type // do not use table.cur_concrete_types because table is global, so should not be accessed by different threads
|
||||||
|
cur_fn &ast.FnDecl = 0 // same here
|
||||||
|
needed_equality_fns []ast.Type
|
||||||
|
generated_eq_fns []ast.Type
|
||||||
|
array_contains_types []ast.Type
|
||||||
|
array_index_types []ast.Type
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn gen(files []&ast.File, table &ast.Table, pref &pref.Preferences) string {
|
pub fn gen(files []&ast.File, table &ast.Table, pref &pref.Preferences) string {
|
||||||
@ -200,7 +208,7 @@ pub fn gen(files []&ast.File, table &ast.Table, pref &pref.Preferences) string {
|
|||||||
$if time_cgening ? {
|
$if time_cgening ? {
|
||||||
timers_should_print = true
|
timers_should_print = true
|
||||||
}
|
}
|
||||||
mut g := Gen{
|
mut global_g := Gen{
|
||||||
file: 0
|
file: 0
|
||||||
out: strings.new_builder(512000)
|
out: strings.new_builder(512000)
|
||||||
cheaders: strings.new_builder(15000)
|
cheaders: strings.new_builder(15000)
|
||||||
@ -216,7 +224,6 @@ pub fn gen(files []&ast.File, table &ast.Table, pref &pref.Preferences) string {
|
|||||||
pcs_declarations: strings.new_builder(100)
|
pcs_declarations: strings.new_builder(100)
|
||||||
hotcode_definitions: strings.new_builder(100)
|
hotcode_definitions: strings.new_builder(100)
|
||||||
embedded_data: strings.new_builder(1000)
|
embedded_data: strings.new_builder(1000)
|
||||||
options_typedefs: strings.new_builder(100)
|
|
||||||
options: strings.new_builder(100)
|
options: strings.new_builder(100)
|
||||||
shared_types: strings.new_builder(100)
|
shared_types: strings.new_builder(100)
|
||||||
shared_functions: strings.new_builder(100)
|
shared_functions: strings.new_builder(100)
|
||||||
@ -227,61 +234,182 @@ pub fn gen(files []&ast.File, table &ast.Table, pref &pref.Preferences) string {
|
|||||||
table: table
|
table: table
|
||||||
pref: pref
|
pref: pref
|
||||||
fn_decl: 0
|
fn_decl: 0
|
||||||
is_autofree: true
|
is_autofree: pref.autofree
|
||||||
indent: -1
|
indent: -1
|
||||||
module_built: module_built
|
module_built: module_built
|
||||||
|
timers_should_print: timers_should_print
|
||||||
timers: util.new_timers(timers_should_print)
|
timers: util.new_timers(timers_should_print)
|
||||||
inner_loop: &ast.EmptyStmt{}
|
inner_loop: &ast.EmptyStmt{}
|
||||||
field_data_type: ast.Type(table.find_type_idx('FieldData'))
|
field_data_type: ast.Type(table.find_type_idx('FieldData'))
|
||||||
|
init: strings.new_builder(100)
|
||||||
}
|
}
|
||||||
g.timers.start('cgen init')
|
// anon fn may include assert and thus this needs
|
||||||
for mod in g.table.modules {
|
// to be included before any test contents are written
|
||||||
g.inits[mod] = strings.new_builder(100)
|
if pref.is_test {
|
||||||
g.global_inits[mod] = strings.new_builder(100)
|
global_g.write_tests_definitions()
|
||||||
g.cleanups[mod] = strings.new_builder(100)
|
|
||||||
}
|
}
|
||||||
g.init()
|
|
||||||
g.timers.show('cgen init')
|
global_g.timers.start('cgen init')
|
||||||
mut tests_inited := false
|
for mod in global_g.table.modules {
|
||||||
mut autofree_used := false
|
global_g.inits[mod] = strings.new_builder(200)
|
||||||
for file in files {
|
global_g.global_inits[mod] = strings.new_builder(100)
|
||||||
g.timers.start('cgen_file $file.path')
|
global_g.cleanups[mod] = strings.new_builder(100)
|
||||||
g.file = file
|
}
|
||||||
if g.pref.is_vlines {
|
global_g.init()
|
||||||
g.vlines_path = util.vlines_escape_path(file.path, g.pref.ccompiler)
|
global_g.timers.show('cgen init')
|
||||||
}
|
global_g.tests_inited = false
|
||||||
// println('\ncgen "$g.file.path" nr_stmts=$file.stmts.len')
|
if !pref.no_parallel {
|
||||||
// building_v := true && (g.file.path.contains('/vlib/') || g.file.path.contains('cmd/v'))
|
mut pp := pool.new_pool_processor(
|
||||||
g.is_test = g.pref.is_test
|
callback: fn (p &pool.PoolProcessor, idx int, wid int) &Gen {
|
||||||
if g.file.path == '' || !g.pref.autofree {
|
file := p.get_item<&ast.File>(idx)
|
||||||
// cgen test or building V
|
mut global_g := &Gen(p.get_shared_context())
|
||||||
// println('autofree=false')
|
mut g := &Gen{
|
||||||
g.is_autofree = false
|
file: file
|
||||||
} else {
|
out: strings.new_builder(512000)
|
||||||
g.is_autofree = true
|
cheaders: strings.new_builder(15000)
|
||||||
autofree_used = true
|
includes: strings.new_builder(100)
|
||||||
}
|
typedefs: strings.new_builder(100)
|
||||||
// anon fn may include assert and thus this needs
|
typedefs2: strings.new_builder(100)
|
||||||
// to be included before any test contents are written
|
type_definitions: strings.new_builder(100)
|
||||||
if g.is_test && !tests_inited {
|
definitions: strings.new_builder(100)
|
||||||
g.write_tests_definitions()
|
gowrappers: strings.new_builder(100)
|
||||||
tests_inited = true
|
stringliterals: strings.new_builder(100)
|
||||||
}
|
auto_str_funcs: strings.new_builder(100)
|
||||||
g.stmts(file.stmts)
|
comptime_defines: strings.new_builder(100)
|
||||||
// Transfer embedded files
|
pcs_declarations: strings.new_builder(100)
|
||||||
if file.embedded_files.len > 0 {
|
hotcode_definitions: strings.new_builder(100)
|
||||||
for path in file.embedded_files {
|
embedded_data: strings.new_builder(1000)
|
||||||
if path !in g.embedded_files {
|
options: strings.new_builder(100)
|
||||||
g.embedded_files << path
|
shared_types: strings.new_builder(100)
|
||||||
|
shared_functions: strings.new_builder(100)
|
||||||
|
channel_definitions: strings.new_builder(100)
|
||||||
|
json_forward_decls: strings.new_builder(100)
|
||||||
|
enum_typedefs: strings.new_builder(100)
|
||||||
|
sql_buf: strings.new_builder(100)
|
||||||
|
init: strings.new_builder(100)
|
||||||
|
global_init: strings.new_builder(0)
|
||||||
|
cleanup: strings.new_builder(100)
|
||||||
|
table: global_g.table
|
||||||
|
pref: global_g.pref
|
||||||
|
fn_decl: 0
|
||||||
|
indent: -1
|
||||||
|
module_built: global_g.module_built
|
||||||
|
timers: util.new_timers(global_g.timers_should_print)
|
||||||
|
inner_loop: &ast.EmptyStmt{}
|
||||||
|
field_data_type: ast.Type(global_g.table.find_type_idx('FieldData'))
|
||||||
|
array_sort_fn: global_g.array_sort_fn
|
||||||
|
done_optionals: global_g.done_optionals
|
||||||
|
is_autofree: global_g.pref.autofree
|
||||||
|
}
|
||||||
|
g.gen()
|
||||||
|
return g
|
||||||
|
}
|
||||||
|
)
|
||||||
|
pp.set_shared_context(global_g) // TODO: make global_g shared
|
||||||
|
pp.work_on_items(files)
|
||||||
|
global_g.timers.start('cgen unification')
|
||||||
|
// tg = thread gen
|
||||||
|
for g in pp.get_results<Gen>() {
|
||||||
|
global_g.out.write(g.out) or { panic(err) }
|
||||||
|
global_g.cheaders.write(g.cheaders) or { panic(err) }
|
||||||
|
global_g.includes.write(g.includes) or { panic(err) }
|
||||||
|
global_g.typedefs.write(g.typedefs) or { panic(err) }
|
||||||
|
global_g.typedefs2.write(g.typedefs2) or { panic(err) }
|
||||||
|
global_g.type_definitions.write(g.type_definitions) or { panic(err) }
|
||||||
|
global_g.definitions.write(g.definitions) or { panic(err) }
|
||||||
|
global_g.gowrappers.write(g.gowrappers) or { panic(err) }
|
||||||
|
global_g.stringliterals.write(g.stringliterals) or { panic(err) }
|
||||||
|
global_g.auto_str_funcs.write(g.auto_str_funcs) or { panic(err) }
|
||||||
|
global_g.comptime_defines.write(g.comptime_defines) or { panic(err) }
|
||||||
|
global_g.pcs_declarations.write(g.pcs_declarations) or { panic(err) }
|
||||||
|
global_g.hotcode_definitions.write(g.hotcode_definitions) or { panic(err) }
|
||||||
|
global_g.embedded_data.write(g.embedded_data) or { panic(err) }
|
||||||
|
global_g.shared_types.write(g.shared_types) or { panic(err) }
|
||||||
|
global_g.shared_functions.write(g.channel_definitions) or { panic(err) }
|
||||||
|
// merge maps
|
||||||
|
for k, v in g.shareds {
|
||||||
|
global_g.shareds[k] = v
|
||||||
|
}
|
||||||
|
for k, v in g.chan_pop_optionals {
|
||||||
|
global_g.chan_pop_optionals[k] = v
|
||||||
|
}
|
||||||
|
for k, v in g.chan_push_optionals {
|
||||||
|
global_g.chan_push_optionals[k] = v
|
||||||
|
}
|
||||||
|
for k, v in g.optionals {
|
||||||
|
global_g.optionals[k] = v
|
||||||
|
}
|
||||||
|
for k, v in g.as_cast_type_names {
|
||||||
|
global_g.as_cast_type_names[k] = v
|
||||||
|
}
|
||||||
|
for k, v in g.sumtype_definitions {
|
||||||
|
global_g.sumtype_definitions[k] = v
|
||||||
|
}
|
||||||
|
global_g.json_forward_decls.write(g.json_forward_decls) or { panic(err) }
|
||||||
|
global_g.enum_typedefs.write(g.enum_typedefs) or { panic(err) }
|
||||||
|
global_g.channel_definitions.write(g.channel_definitions) or { panic(err) }
|
||||||
|
global_g.sql_buf.write(g.sql_buf) or { panic(err) }
|
||||||
|
|
||||||
|
global_g.cleanups[g.file.mod.name].write(g.cleanup) or { panic(err) } // strings.Builder.write never fails; it is like that in the source
|
||||||
|
global_g.inits[g.file.mod.name].write(g.init) or { panic(err) }
|
||||||
|
global_g.global_inits[g.file.mod.name].write(g.global_init) or { panic(err) }
|
||||||
|
|
||||||
|
for str_type in g.str_types {
|
||||||
|
global_g.str_types << str_type
|
||||||
|
}
|
||||||
|
for scf in g.sumtype_casting_fns {
|
||||||
|
if scf !in global_g.sumtype_casting_fns {
|
||||||
|
global_g.sumtype_casting_fns << scf
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
global_g.nr_closures += g.nr_closures
|
||||||
|
global_g.has_main = global_g.has_main || g.has_main
|
||||||
|
|
||||||
|
global_g.threaded_fns << g.threaded_fns
|
||||||
|
global_g.waiter_fns << g.waiter_fns
|
||||||
|
global_g.auto_fn_definitions << g.auto_fn_definitions
|
||||||
|
global_g.anon_fn_definitions << g.anon_fn_definitions
|
||||||
|
global_g.needed_equality_fns << g.needed_equality_fns // duplicates are resolved later in gen_equality_fns
|
||||||
|
global_g.array_contains_types << g.array_contains_types
|
||||||
|
global_g.array_index_types << g.array_index_types
|
||||||
|
global_g.pcs << g.pcs
|
||||||
|
global_g.json_types << g.json_types
|
||||||
|
global_g.hotcode_fn_names << g.hotcode_fn_names
|
||||||
}
|
}
|
||||||
g.timers.show('cgen_file $file.path')
|
} else {
|
||||||
|
for file in files {
|
||||||
|
global_g.file = file
|
||||||
|
global_g.gen()
|
||||||
|
global_g.inits[file.mod.name].write(global_g.init) or { panic(err) }
|
||||||
|
global_g.init = strings.new_builder(100)
|
||||||
|
global_g.cleanups[file.mod.name].write(global_g.cleanup) or { panic(err) }
|
||||||
|
global_g.cleanup = strings.new_builder(100)
|
||||||
|
global_g.global_inits[file.mod.name].write(global_g.global_init) or { panic(err) }
|
||||||
|
global_g.global_init = strings.new_builder(100)
|
||||||
|
}
|
||||||
|
global_g.timers.start('cgen unification')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
global_g.gen_jsons()
|
||||||
|
global_g.write_optionals()
|
||||||
|
global_g.dump_expr_definitions() // this uses global_g.get_str_fn, so it has to go before the below for loop
|
||||||
|
for i := 0; i < global_g.str_types.len; i++ {
|
||||||
|
global_g.final_gen_str(global_g.str_types[i])
|
||||||
|
}
|
||||||
|
for sumtype_casting_fn in global_g.sumtype_casting_fns {
|
||||||
|
global_g.write_sumtype_casting_fn(sumtype_casting_fn)
|
||||||
|
}
|
||||||
|
global_g.write_shareds()
|
||||||
|
global_g.write_chan_pop_optional_fns()
|
||||||
|
global_g.write_chan_push_optional_fns()
|
||||||
|
global_g.gen_array_contains_methods()
|
||||||
|
global_g.gen_array_index_methods()
|
||||||
|
global_g.gen_equality_fns()
|
||||||
|
global_g.timers.show('cgen unification')
|
||||||
|
|
||||||
|
mut g := global_g
|
||||||
g.timers.start('cgen common')
|
g.timers.start('cgen common')
|
||||||
if autofree_used {
|
|
||||||
g.is_autofree = true // so that void _vcleanup is generated
|
|
||||||
}
|
|
||||||
// to make sure type idx's are the same in cached mods
|
// to make sure type idx's are the same in cached mods
|
||||||
if g.pref.build_mode == .build_module {
|
if g.pref.build_mode == .build_module {
|
||||||
for idx, typ in g.table.type_symbols {
|
for idx, typ in g.table.type_symbols {
|
||||||
@ -299,7 +427,6 @@ pub fn gen(files []&ast.File, table &ast.Table, pref &pref.Preferences) string {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
//
|
//
|
||||||
g.dump_expr_definitions()
|
|
||||||
// v files are finished, what remains is pure C code
|
// v files are finished, what remains is pure C code
|
||||||
g.gen_vlines_reset()
|
g.gen_vlines_reset()
|
||||||
if g.pref.build_mode != .build_module {
|
if g.pref.build_mode != .build_module {
|
||||||
@ -354,10 +481,6 @@ pub fn gen(files []&ast.File, table &ast.Table, pref &pref.Preferences) string {
|
|||||||
b.writeln('\n// V embedded data:')
|
b.writeln('\n// V embedded data:')
|
||||||
b.write_string(g.embedded_data.str())
|
b.write_string(g.embedded_data.str())
|
||||||
}
|
}
|
||||||
if g.options_typedefs.len > 0 {
|
|
||||||
b.writeln('\n// V option typedefs:')
|
|
||||||
b.write_string(g.options_typedefs.str())
|
|
||||||
}
|
|
||||||
if g.shared_functions.len > 0 {
|
if g.shared_functions.len > 0 {
|
||||||
b.writeln('\n// V shared type functions:')
|
b.writeln('\n// V shared type functions:')
|
||||||
b.write_string(g.shared_functions.str())
|
b.write_string(g.shared_functions.str())
|
||||||
@ -398,6 +521,22 @@ pub fn gen(files []&ast.File, table &ast.Table, pref &pref.Preferences) string {
|
|||||||
return b.str()
|
return b.str()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn (mut g Gen) gen() {
|
||||||
|
g.timers.start('cgen_file $g.file.path')
|
||||||
|
|
||||||
|
if g.pref.is_vlines {
|
||||||
|
g.vlines_path = util.vlines_escape_path(g.file.path, g.pref.ccompiler)
|
||||||
|
}
|
||||||
|
g.stmts(g.file.stmts)
|
||||||
|
// Transfer embedded files
|
||||||
|
for path in g.file.embedded_files {
|
||||||
|
if path !in g.embedded_files {
|
||||||
|
g.embedded_files << path
|
||||||
|
}
|
||||||
|
}
|
||||||
|
g.timers.show('cgen_file $g.file.path')
|
||||||
|
}
|
||||||
|
|
||||||
pub fn (g &Gen) hashes() string {
|
pub fn (g &Gen) hashes() string {
|
||||||
mut res := c_commit_hash_default.replace('@@@', version.vhash())
|
mut res := c_commit_hash_default.replace('@@@', version.vhash())
|
||||||
res += c_current_commit_hash_default.replace('@@@', version.githash(g.pref.building_v))
|
res += c_current_commit_hash_default.replace('@@@', version.githash(g.pref.building_v))
|
||||||
@ -508,6 +647,13 @@ pub fn (mut g Gen) init() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// we know that this is being called before the multi-threading starts
|
||||||
|
// and this is being called in the main thread, so we can mutate the table
|
||||||
|
mut muttable := unsafe { &ast.Table(g.table) }
|
||||||
|
muttable.used_fns['v_segmentation_fault_handler'] = true
|
||||||
|
muttable.used_fns['eprintln'] = true
|
||||||
|
muttable.used_fns['print_backtrace'] = true
|
||||||
|
muttable.used_fns['exit'] = true
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (mut g Gen) finish() {
|
pub fn (mut g Gen) finish() {
|
||||||
@ -610,20 +756,16 @@ pub fn (mut g Gen) write_typeof_functions() {
|
|||||||
|
|
||||||
// V type to C typecc
|
// V type to C typecc
|
||||||
fn (mut g Gen) typ(t ast.Type) string {
|
fn (mut g Gen) typ(t ast.Type) string {
|
||||||
styp := g.base_type(t)
|
|
||||||
if t.has_flag(.optional) {
|
if t.has_flag(.optional) {
|
||||||
// Register an optional if it's not registered yet
|
// Register an optional if it's not registered yet
|
||||||
return g.register_optional(t)
|
return g.register_optional(t)
|
||||||
|
} else {
|
||||||
|
return g.base_type(t)
|
||||||
}
|
}
|
||||||
/*
|
|
||||||
if styp.starts_with('C__') {
|
|
||||||
return styp[3..]
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
return styp
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (mut g Gen) base_type(t ast.Type) string {
|
fn (mut g Gen) base_type(_t ast.Type) string {
|
||||||
|
t := g.unwrap_generic(_t)
|
||||||
if g.pref.nofloat {
|
if g.pref.nofloat {
|
||||||
// todo compile time if for perf?
|
// todo compile time if for perf?
|
||||||
if t == ast.f32_type {
|
if t == ast.f32_type {
|
||||||
@ -692,7 +834,7 @@ fn (mut g Gen) optional_type_name(t ast.Type) (string, string) {
|
|||||||
return styp, base
|
return styp, base
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (g &Gen) optional_type_text(styp string, base string) string {
|
fn (g Gen) optional_type_text(styp string, base string) string {
|
||||||
// replace void with something else
|
// replace void with something else
|
||||||
size := if base == 'void' { 'byte' } else { base }
|
size := if base == 'void' { 'byte' } else { base }
|
||||||
ret := 'struct $styp {
|
ret := 'struct $styp {
|
||||||
@ -705,32 +847,44 @@ fn (g &Gen) optional_type_text(styp string, base string) string {
|
|||||||
|
|
||||||
fn (mut g Gen) register_optional(t ast.Type) string {
|
fn (mut g Gen) register_optional(t ast.Type) string {
|
||||||
styp, base := g.optional_type_name(t)
|
styp, base := g.optional_type_name(t)
|
||||||
if styp !in g.optionals {
|
g.optionals[base] = styp
|
||||||
g.typedefs2.writeln('typedef struct $styp $styp;')
|
|
||||||
g.options.write_string(g.optional_type_text(styp, base))
|
|
||||||
g.options.writeln(';\n')
|
|
||||||
g.optionals << styp.clone()
|
|
||||||
}
|
|
||||||
return styp
|
return styp
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (mut g Gen) find_or_register_shared(t ast.Type, base string) string {
|
fn (mut g Gen) write_optionals() {
|
||||||
sh_typ := '__shared__$base'
|
mut done := g.done_optionals.clone()
|
||||||
t_idx := t.idx()
|
for base, styp in g.optionals {
|
||||||
if t_idx in g.shareds {
|
if base in done {
|
||||||
return sh_typ
|
continue
|
||||||
|
}
|
||||||
|
done << base
|
||||||
|
g.typedefs2.writeln('typedef struct $styp $styp;')
|
||||||
|
g.options.write_string(g.optional_type_text(styp, base) + ';\n\n')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn (mut g Gen) find_or_register_shared(t ast.Type, base string) string {
|
||||||
|
g.shareds[t.idx()] = base
|
||||||
|
return '__shared__$base'
|
||||||
|
}
|
||||||
|
|
||||||
|
fn (mut g Gen) write_shareds() {
|
||||||
|
mut done_types := []int{}
|
||||||
|
for typ, base in g.shareds {
|
||||||
|
if typ in done_types {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
done_types << typ
|
||||||
|
sh_typ := '__shared__$base'
|
||||||
|
mtx_typ := 'sync__RwMutex'
|
||||||
|
g.shared_types.writeln('struct $sh_typ { $mtx_typ mtx; $base val; };')
|
||||||
|
g.shared_functions.writeln('static inline voidptr __dup${sh_typ}(voidptr src, int sz) {')
|
||||||
|
g.shared_functions.writeln('\t$sh_typ* dest = memdup(src, sz);')
|
||||||
|
g.shared_functions.writeln('\tsync__RwMutex_init(&dest->mtx);')
|
||||||
|
g.shared_functions.writeln('\treturn dest;')
|
||||||
|
g.shared_functions.writeln('}')
|
||||||
|
g.typedefs2.writeln('typedef struct $sh_typ $sh_typ;')
|
||||||
}
|
}
|
||||||
mtx_typ := 'sync__RwMutex'
|
|
||||||
g.shared_types.writeln('struct $sh_typ { $base val; $mtx_typ mtx; };')
|
|
||||||
g.shared_functions.writeln('static inline voidptr __dup${sh_typ}(voidptr src, int sz) {')
|
|
||||||
g.shared_functions.writeln('\t$sh_typ* dest = memdup(src, sz);')
|
|
||||||
g.shared_functions.writeln('\tsync__RwMutex_init(&dest->mtx);')
|
|
||||||
g.shared_functions.writeln('\treturn dest;')
|
|
||||||
g.shared_functions.writeln('}')
|
|
||||||
g.typedefs2.writeln('typedef struct $sh_typ $sh_typ;')
|
|
||||||
// println('registered shared type $sh_typ')
|
|
||||||
g.shareds << t_idx
|
|
||||||
return sh_typ
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (mut g Gen) register_thread_array_wait_call(eltyp string) string {
|
fn (mut g Gen) register_thread_array_wait_call(eltyp string) string {
|
||||||
@ -765,8 +919,16 @@ $ret_typ ${fn_name}($thread_arr_typ a) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn (mut g Gen) register_chan_pop_optional_call(opt_el_type string, styp string) {
|
fn (mut g Gen) register_chan_pop_optional_call(opt_el_type string, styp string) {
|
||||||
if opt_el_type !in g.chan_pop_optionals {
|
g.chan_pop_optionals[opt_el_type] = styp
|
||||||
g.chan_pop_optionals << opt_el_type
|
}
|
||||||
|
|
||||||
|
fn (mut g Gen) write_chan_pop_optional_fns() {
|
||||||
|
mut done := []string{}
|
||||||
|
for opt_el_type, styp in g.chan_pop_optionals {
|
||||||
|
if opt_el_type in done {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
done << opt_el_type
|
||||||
g.channel_definitions.writeln('
|
g.channel_definitions.writeln('
|
||||||
static inline $opt_el_type __Option_${styp}_popval($styp ch) {
|
static inline $opt_el_type __Option_${styp}_popval($styp ch) {
|
||||||
$opt_el_type _tmp = {0};
|
$opt_el_type _tmp = {0};
|
||||||
@ -778,9 +940,17 @@ static inline $opt_el_type __Option_${styp}_popval($styp ch) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (mut g Gen) register_chan_push_optional_call(el_type string, styp string) {
|
fn (mut g Gen) register_chan_push_optional_fn(el_type string, styp string) {
|
||||||
if styp !in g.chan_push_optionals {
|
g.chan_push_optionals[styp] = el_type
|
||||||
g.chan_push_optionals << styp
|
}
|
||||||
|
|
||||||
|
fn (mut g Gen) write_chan_push_optional_fns() {
|
||||||
|
mut done := []string{}
|
||||||
|
for styp, el_type in g.chan_push_optionals {
|
||||||
|
if styp in done {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
done << styp
|
||||||
g.register_optional(ast.void_type.set_flag(.optional))
|
g.register_optional(ast.void_type.set_flag(.optional))
|
||||||
g.channel_definitions.writeln('
|
g.channel_definitions.writeln('
|
||||||
static inline Option_void __Option_${styp}_pushval($styp ch, $el_type e) {
|
static inline Option_void __Option_${styp}_pushval($styp ch, $el_type e) {
|
||||||
@ -828,7 +998,7 @@ fn (g &Gen) type_sidx(t ast.Type) string {
|
|||||||
sym := g.table.get_type_symbol(t)
|
sym := g.table.get_type_symbol(t)
|
||||||
return '_v_type_idx_${sym.cname}()'
|
return '_v_type_idx_${sym.cname}()'
|
||||||
}
|
}
|
||||||
return '$t.idx()'
|
return t.idx().str()
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
@ -1920,18 +2090,35 @@ fn (mut g Gen) for_in_stmt(node ast.ForInStmt) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (mut g Gen) write_sumtype_casting_fn(got_ ast.Type, exp_ ast.Type) {
|
struct SumtypeCastingFn {
|
||||||
|
fn_name string
|
||||||
|
got ast.Type
|
||||||
|
exp ast.Type
|
||||||
|
}
|
||||||
|
|
||||||
|
fn (mut g Gen) get_sumtype_casting_fn(got_ ast.Type, exp_ ast.Type) string {
|
||||||
got, exp := got_.idx(), exp_.idx()
|
got, exp := got_.idx(), exp_.idx()
|
||||||
i := got | (exp << 16)
|
i := got | (exp << 16)
|
||||||
|
got_cname, exp_cname := g.table.get_type_symbol(got).cname, g.table.get_type_symbol(exp).cname
|
||||||
|
fn_name := '${got_cname}_to_sumtype_$exp_cname'
|
||||||
if got == exp || g.sumtype_definitions[i] {
|
if got == exp || g.sumtype_definitions[i] {
|
||||||
return
|
return fn_name
|
||||||
}
|
}
|
||||||
g.sumtype_definitions[i] = true
|
g.sumtype_definitions[i] = true
|
||||||
got_sym := g.table.get_type_symbol(got)
|
g.sumtype_casting_fns << SumtypeCastingFn{
|
||||||
exp_sym := g.table.get_type_symbol(exp)
|
fn_name: fn_name
|
||||||
mut sb := strings.new_builder(128)
|
got: got
|
||||||
|
exp: exp
|
||||||
|
}
|
||||||
|
return fn_name
|
||||||
|
}
|
||||||
|
|
||||||
|
fn (mut g Gen) write_sumtype_casting_fn(fun SumtypeCastingFn) {
|
||||||
|
got, exp := fun.got, fun.exp
|
||||||
|
got_sym, exp_sym := g.table.get_type_symbol(got), g.table.get_type_symbol(exp)
|
||||||
got_cname, exp_cname := got_sym.cname, exp_sym.cname
|
got_cname, exp_cname := got_sym.cname, exp_sym.cname
|
||||||
sb.writeln('static inline $exp_cname ${got_cname}_to_sumtype_${exp_cname}($got_cname* x) {')
|
mut sb := strings.new_builder(128)
|
||||||
|
sb.writeln('static inline $exp_cname ${fun.fn_name}($got_cname* x) {')
|
||||||
sb.writeln('\t$got_cname* ptr = memdup(x, sizeof($got_cname));')
|
sb.writeln('\t$got_cname* ptr = memdup(x, sizeof($got_cname));')
|
||||||
for embed_hierarchy in g.table.get_embeds(got_sym) {
|
for embed_hierarchy in g.table.get_embeds(got_sym) {
|
||||||
// last embed in the hierarchy
|
// last embed in the hierarchy
|
||||||
@ -1998,9 +2185,9 @@ fn (mut g Gen) call_cfn_for_casting_expr(fname string, expr ast.Expr, exp_is_ptr
|
|||||||
fn (mut g Gen) expr_with_cast(expr ast.Expr, got_type_raw ast.Type, expected_type ast.Type) {
|
fn (mut g Gen) expr_with_cast(expr ast.Expr, got_type_raw ast.Type, expected_type ast.Type) {
|
||||||
got_type := g.table.mktyp(got_type_raw)
|
got_type := g.table.mktyp(got_type_raw)
|
||||||
exp_sym := g.table.get_type_symbol(expected_type)
|
exp_sym := g.table.get_type_symbol(expected_type)
|
||||||
|
got_sym := g.table.get_type_symbol(got_type)
|
||||||
expected_is_ptr := expected_type.is_ptr()
|
expected_is_ptr := expected_type.is_ptr()
|
||||||
got_is_ptr := got_type.is_ptr()
|
got_is_ptr := got_type.is_ptr()
|
||||||
got_sym := g.table.get_type_symbol(got_type)
|
|
||||||
// allow using the new Error struct as a string, to avoid a breaking change
|
// allow using the new Error struct as a string, to avoid a breaking change
|
||||||
// TODO: temporary to allow people to migrate their code; remove soon
|
// TODO: temporary to allow people to migrate their code; remove soon
|
||||||
if got_type == ast.error_type_idx && expected_type == ast.string_type_idx {
|
if got_type == ast.error_type_idx && expected_type == ast.string_type_idx {
|
||||||
@ -2073,7 +2260,7 @@ fn (mut g Gen) expr_with_cast(expr ast.Expr, got_type_raw ast.Type, expected_typ
|
|||||||
g.prevent_sum_type_unwrapping_once = true
|
g.prevent_sum_type_unwrapping_once = true
|
||||||
g.expr(expr)
|
g.expr(expr)
|
||||||
} else {
|
} else {
|
||||||
g.write_sumtype_casting_fn(unwrapped_got_type, unwrapped_expected_type)
|
g.get_sumtype_casting_fn(unwrapped_got_type, unwrapped_expected_type)
|
||||||
fname := '${unwrapped_got_sym.cname}_to_sumtype_$unwrapped_exp_sym.cname'
|
fname := '${unwrapped_got_sym.cname}_to_sumtype_$unwrapped_exp_sym.cname'
|
||||||
g.call_cfn_for_casting_expr(fname, expr, expected_is_ptr, unwrapped_exp_sym.cname,
|
g.call_cfn_for_casting_expr(fname, expr, expected_is_ptr, unwrapped_exp_sym.cname,
|
||||||
got_is_ptr, got_styp)
|
got_is_ptr, got_styp)
|
||||||
@ -2916,7 +3103,7 @@ fn (mut g Gen) gen_assign_stmt(assign_stmt ast.AssignStmt) {
|
|||||||
}
|
}
|
||||||
mut cloned := false
|
mut cloned := false
|
||||||
if g.is_autofree && right_sym.kind in [.array, .string] {
|
if g.is_autofree && right_sym.kind in [.array, .string] {
|
||||||
if g.gen_clone_assignment(val, right_sym, false) {
|
if g.gen_clone_assignment(val, unwrapped_val_type, false) {
|
||||||
cloned = true
|
cloned = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -3092,28 +3279,38 @@ fn (mut g Gen) get_ternary_name(name string) string {
|
|||||||
return g.ternary_names[name]
|
return g.ternary_names[name]
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (mut g Gen) gen_clone_assignment(val ast.Expr, right_sym ast.TypeSymbol, add_eq bool) bool {
|
fn (mut g Gen) gen_clone_assignment(val ast.Expr, typ ast.Type, add_eq bool) bool {
|
||||||
if val !is ast.Ident && val !is ast.SelectorExpr {
|
if val !is ast.Ident && val !is ast.SelectorExpr {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if g.is_autofree && right_sym.kind == .array {
|
right_sym := g.table.get_type_symbol(typ)
|
||||||
// `arr1 = arr2` => `arr1 = arr2.clone()`
|
if g.is_autofree {
|
||||||
if add_eq {
|
if add_eq {
|
||||||
g.write('=')
|
g.write('=')
|
||||||
}
|
}
|
||||||
g.write(' array_clone_static_to_depth(')
|
if right_sym.kind == .array {
|
||||||
g.expr(val)
|
// `arr1 = arr2` => `arr1 = arr2.clone()`
|
||||||
elem_type := (right_sym.info as ast.Array).elem_type
|
shared_styp := g.typ(typ.set_nr_muls(0))
|
||||||
array_depth := g.get_array_depth(elem_type)
|
if typ.share() == .shared_t {
|
||||||
g.write(', $array_depth)')
|
g.write('($shared_styp*)__dup_shared_array(&($shared_styp){.mtx = {0}, .val =')
|
||||||
} else if g.is_autofree && right_sym.kind == .string {
|
}
|
||||||
if add_eq {
|
g.write(' array_clone_static_to_depth(')
|
||||||
g.write('=')
|
g.expr(val)
|
||||||
|
if typ.share() == .shared_t {
|
||||||
|
g.write('->val')
|
||||||
|
}
|
||||||
|
elem_type := (right_sym.info as ast.Array).elem_type
|
||||||
|
array_depth := g.get_array_depth(elem_type)
|
||||||
|
g.write(', $array_depth)')
|
||||||
|
if typ.share() == .shared_t {
|
||||||
|
g.write('}, sizeof($shared_styp))')
|
||||||
|
}
|
||||||
|
} else if right_sym.kind == .string {
|
||||||
|
// `str1 = str2` => `str1 = str2.clone()`
|
||||||
|
g.write(' string_clone_static(')
|
||||||
|
g.expr(val)
|
||||||
|
g.write(')')
|
||||||
}
|
}
|
||||||
// `str1 = str2` => `str1 = str2.clone()`
|
|
||||||
g.write(' string_clone_static(')
|
|
||||||
g.expr(val)
|
|
||||||
g.write(')')
|
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
@ -3203,7 +3400,7 @@ fn (mut g Gen) autofree_scope_vars2(scope &ast.Scope, start_pos int, end_pos int
|
|||||||
// }
|
// }
|
||||||
// ```
|
// ```
|
||||||
// if !isnil(scope.parent) && line_nr > 0 {
|
// if !isnil(scope.parent) && line_nr > 0 {
|
||||||
if free_parent_scopes && !isnil(scope.parent)
|
if free_parent_scopes && !isnil(scope.parent) && !scope.detached_from_parent
|
||||||
&& (stop_pos == -1 || scope.parent.start_pos >= stop_pos) {
|
&& (stop_pos == -1 || scope.parent.start_pos >= stop_pos) {
|
||||||
g.trace_autofree('// af parent scope:')
|
g.trace_autofree('// af parent scope:')
|
||||||
g.autofree_scope_vars2(scope.parent, start_pos, end_pos, line_nr, true, stop_pos)
|
g.autofree_scope_vars2(scope.parent, start_pos, end_pos, line_nr, true, stop_pos)
|
||||||
@ -3217,10 +3414,10 @@ fn (mut g Gen) autofree_variable(v ast.Var) {
|
|||||||
// eprintln(' > var name: ${v.name:-20s} | is_arg: ${v.is_arg.str():6} | var type: ${int(v.typ):8} | type_name: ${sym.name:-33s}')
|
// eprintln(' > var name: ${v.name:-20s} | is_arg: ${v.is_arg.str():6} | var type: ${int(v.typ):8} | type_name: ${sym.name:-33s}')
|
||||||
}
|
}
|
||||||
// }
|
// }
|
||||||
|
free_fn := g.typ(v.typ.set_nr_muls(0)) + '_free'
|
||||||
if sym.kind == .array {
|
if sym.kind == .array {
|
||||||
if sym.has_method('free') {
|
if sym.has_method('free') {
|
||||||
free_method_name := g.typ(v.typ) + '_free'
|
g.autofree_var_call(free_fn, v)
|
||||||
g.autofree_var_call(free_method_name, v)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
g.autofree_var_call('array_free', v)
|
g.autofree_var_call('array_free', v)
|
||||||
@ -3251,7 +3448,7 @@ fn (mut g Gen) autofree_variable(v ast.Var) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
if sym.has_method('free') {
|
if sym.has_method('free') {
|
||||||
g.autofree_var_call(c_name(sym.name) + '_free', v)
|
g.autofree_var_call(free_fn, v)
|
||||||
} else if g.pref.experimental && v.typ.is_ptr() && sym.name.after('.')[0].is_capital() {
|
} else if g.pref.experimental && v.typ.is_ptr() && sym.name.after('.')[0].is_capital() {
|
||||||
// Free user reference types
|
// Free user reference types
|
||||||
g.autofree_var_call('free', v)
|
g.autofree_var_call('free', v)
|
||||||
@ -3281,7 +3478,23 @@ fn (mut g Gen) autofree_var_call(free_fn_name string, v ast.Var) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
if v.typ.is_ptr() {
|
if v.typ.is_ptr() {
|
||||||
g.writeln('\t${free_fn_name}(${c_name(v.name)}); // autofreed ptr var')
|
g.write('\t')
|
||||||
|
if v.typ.share() == .shared_t {
|
||||||
|
g.write(free_fn_name.replace_each(['__shared__', '']))
|
||||||
|
} else {
|
||||||
|
g.write(free_fn_name)
|
||||||
|
}
|
||||||
|
g.write('(')
|
||||||
|
if v.typ.share() == .shared_t {
|
||||||
|
g.write('&')
|
||||||
|
}
|
||||||
|
g.write(strings.repeat(`*`, v.typ.nr_muls() - 1)) // dereference if it is a pointer to a pointer
|
||||||
|
g.write(c_name(v.name))
|
||||||
|
if v.typ.share() == .shared_t {
|
||||||
|
g.write('->val')
|
||||||
|
}
|
||||||
|
|
||||||
|
g.writeln('); // autofreed ptr var')
|
||||||
} else {
|
} else {
|
||||||
if v.typ == ast.error_type && !v.is_autofree_tmp {
|
if v.typ == ast.error_type && !v.is_autofree_tmp {
|
||||||
return
|
return
|
||||||
@ -4183,19 +4396,19 @@ fn (mut g Gen) match_expr_classic(node ast.MatchExpr, is_expr bool, cond_var str
|
|||||||
}
|
}
|
||||||
match type_sym.kind {
|
match type_sym.kind {
|
||||||
.array {
|
.array {
|
||||||
ptr_typ := g.gen_array_equality_fn(node.cond_type)
|
ptr_typ := g.equality_fn(node.cond_type)
|
||||||
g.write('${ptr_typ}_arr_eq($cond_var, ')
|
g.write('${ptr_typ}_arr_eq($cond_var, ')
|
||||||
g.expr(expr)
|
g.expr(expr)
|
||||||
g.write(')')
|
g.write(')')
|
||||||
}
|
}
|
||||||
.array_fixed {
|
.array_fixed {
|
||||||
ptr_typ := g.gen_fixed_array_equality_fn(node.cond_type)
|
ptr_typ := g.equality_fn(node.cond_type)
|
||||||
g.write('${ptr_typ}_arr_eq($cond_var, ')
|
g.write('${ptr_typ}_arr_eq($cond_var, ')
|
||||||
g.expr(expr)
|
g.expr(expr)
|
||||||
g.write(')')
|
g.write(')')
|
||||||
}
|
}
|
||||||
.map {
|
.map {
|
||||||
ptr_typ := g.gen_map_equality_fn(node.cond_type)
|
ptr_typ := g.equality_fn(node.cond_type)
|
||||||
g.write('${ptr_typ}_map_eq($cond_var, ')
|
g.write('${ptr_typ}_map_eq($cond_var, ')
|
||||||
g.expr(expr)
|
g.expr(expr)
|
||||||
g.write(')')
|
g.write(')')
|
||||||
@ -4206,7 +4419,7 @@ fn (mut g Gen) match_expr_classic(node ast.MatchExpr, is_expr bool, cond_var str
|
|||||||
g.write(')')
|
g.write(')')
|
||||||
}
|
}
|
||||||
.struct_ {
|
.struct_ {
|
||||||
ptr_typ := g.gen_struct_equality_fn(node.cond_type)
|
ptr_typ := g.equality_fn(node.cond_type)
|
||||||
g.write('${ptr_typ}_struct_eq($cond_var, ')
|
g.write('${ptr_typ}_struct_eq($cond_var, ')
|
||||||
g.expr(expr)
|
g.expr(expr)
|
||||||
g.write(')')
|
g.write(')')
|
||||||
@ -5236,7 +5449,7 @@ fn (mut g Gen) const_decl_precomputed(mod string, name string, ct_value ast.Comp
|
|||||||
// `error C2099: initializer is not a constant` errors in MSVC,
|
// `error C2099: initializer is not a constant` errors in MSVC,
|
||||||
// so fall back to the delayed initialisation scheme:
|
// so fall back to the delayed initialisation scheme:
|
||||||
g.definitions.writeln('$styp $cname; // inited later')
|
g.definitions.writeln('$styp $cname; // inited later')
|
||||||
g.inits[mod].writeln('\t$cname = _SLIT("$escaped_val");')
|
g.init.writeln('\t$cname = _SLIT("$escaped_val");')
|
||||||
if g.is_autofree {
|
if g.is_autofree {
|
||||||
g.cleanups[mod].writeln('\tstring_free(&$cname);')
|
g.cleanups[mod].writeln('\tstring_free(&$cname);')
|
||||||
}
|
}
|
||||||
@ -5269,35 +5482,33 @@ fn (mut g Gen) const_decl_init_later(mod string, name string, expr ast.Expr, typ
|
|||||||
g.definitions.writeln('$styp $cname; // inited later')
|
g.definitions.writeln('$styp $cname; // inited later')
|
||||||
if cname == '_const_os__args' {
|
if cname == '_const_os__args' {
|
||||||
if g.pref.os == .windows {
|
if g.pref.os == .windows {
|
||||||
g.inits[mod].writeln('\t_const_os__args = os__init_os_args_wide(___argc, (byteptr*)___argv);')
|
g.init.writeln('\t_const_os__args = os__init_os_args_wide(___argc, (byteptr*)___argv);')
|
||||||
} else {
|
} else {
|
||||||
g.inits[mod].writeln('\t_const_os__args = os__init_os_args(___argc, (byte**)___argv);')
|
g.init.writeln('\t_const_os__args = os__init_os_args(___argc, (byte**)___argv);')
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if unwrap_option {
|
if unwrap_option {
|
||||||
g.inits[mod].writeln(g.expr_string_surround('\t$cname = *($styp*)', expr,
|
g.init.writeln(g.expr_string_surround('\t$cname = *($styp*)', expr, '.data;'))
|
||||||
'.data;'))
|
|
||||||
} else {
|
} else {
|
||||||
g.inits[mod].writeln(g.expr_string_surround('\t$cname = ', expr, ';'))
|
g.init.writeln(g.expr_string_surround('\t$cname = ', expr, ';'))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if g.is_autofree {
|
if g.is_autofree {
|
||||||
sym := g.table.get_type_symbol(typ)
|
sym := g.table.get_type_symbol(typ)
|
||||||
if styp.starts_with('Array_') {
|
if styp.starts_with('Array_') {
|
||||||
g.cleanups[mod].writeln('\tarray_free(&$cname);')
|
g.cleanup.writeln('\tarray_free(&$cname);')
|
||||||
} else if styp == 'string' {
|
} else if styp == 'string' {
|
||||||
g.cleanups[mod].writeln('\tstring_free(&$cname);')
|
g.cleanup.writeln('\tstring_free(&$cname);')
|
||||||
} else if sym.kind == .map {
|
} else if sym.kind == .map {
|
||||||
g.cleanups[mod].writeln('\tmap_free(&$cname);')
|
g.cleanup.writeln('\tmap_free(&$cname);')
|
||||||
} else if styp == 'IError' {
|
} else if styp == 'IError' {
|
||||||
g.cleanups[mod].writeln('\tIError_free(&$cname);')
|
g.cleanup.writeln('\tIError_free(&$cname);')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (mut g Gen) global_decl(node ast.GlobalDecl) {
|
fn (mut g Gen) global_decl(node ast.GlobalDecl) {
|
||||||
mod := if g.pref.build_mode == .build_module && g.is_builtin_mod { 'static ' } else { '' }
|
mod := if g.pref.build_mode == .build_module && g.is_builtin_mod { 'static ' } else { '' }
|
||||||
key := node.mod // module name
|
|
||||||
for field in node.fields {
|
for field in node.fields {
|
||||||
if g.pref.skip_unused {
|
if g.pref.skip_unused {
|
||||||
if field.name !in g.table.used_globals {
|
if field.name !in g.table.used_globals {
|
||||||
@ -5314,7 +5525,7 @@ fn (mut g Gen) global_decl(node ast.GlobalDecl) {
|
|||||||
g.definitions.writeln(' = ${g.expr_string(field.expr)}; // global')
|
g.definitions.writeln(' = ${g.expr_string(field.expr)}; // global')
|
||||||
} else {
|
} else {
|
||||||
g.definitions.writeln(';')
|
g.definitions.writeln(';')
|
||||||
g.global_inits[key].writeln('\t$field.name = ${g.expr_string(field.expr)}; // global')
|
g.global_init.writeln('\t$field.name = ${g.expr_string(field.expr)}; // global')
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
default_initializer := g.type_default(field.typ)
|
default_initializer := g.type_default(field.typ)
|
||||||
@ -5323,7 +5534,7 @@ fn (mut g Gen) global_decl(node ast.GlobalDecl) {
|
|||||||
} else {
|
} else {
|
||||||
g.definitions.writeln('$mod$styp $field.name; // global')
|
g.definitions.writeln('$mod$styp $field.name; // global')
|
||||||
if field.name !in ['as_cast_type_indexes', 'g_memory_block'] {
|
if field.name !in ['as_cast_type_indexes', 'g_memory_block'] {
|
||||||
g.global_inits[key].writeln('\t$field.name = *($styp*)&(($styp[]){${g.type_default(field.typ)}}[0]); // global')
|
g.global_init.writeln('\t$field.name = *($styp*)&(($styp[]){${g.type_default(field.typ)}}[0]); // global')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -5406,7 +5617,7 @@ fn (mut g Gen) struct_init(struct_init ast.StructInit) {
|
|||||||
mut cloned := false
|
mut cloned := false
|
||||||
if g.is_autofree && !field.typ.is_ptr() && field_type_sym.kind in [.array, .string] {
|
if g.is_autofree && !field.typ.is_ptr() && field_type_sym.kind in [.array, .string] {
|
||||||
g.write('/*clone1*/')
|
g.write('/*clone1*/')
|
||||||
if g.gen_clone_assignment(field.expr, field_type_sym, false) {
|
if g.gen_clone_assignment(field.expr, field.typ, false) {
|
||||||
cloned = true
|
cloned = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -5498,7 +5709,7 @@ fn (mut g Gen) struct_init(struct_init ast.StructInit) {
|
|||||||
mut cloned := false
|
mut cloned := false
|
||||||
if g.is_autofree && !sfield.typ.is_ptr() && field_type_sym.kind in [.array, .string] {
|
if g.is_autofree && !sfield.typ.is_ptr() && field_type_sym.kind in [.array, .string] {
|
||||||
g.write('/*clone1*/')
|
g.write('/*clone1*/')
|
||||||
if g.gen_clone_assignment(sfield.expr, field_type_sym, false) {
|
if g.gen_clone_assignment(sfield.expr, sfield.typ, false) {
|
||||||
cloned = true
|
cloned = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -5664,8 +5875,11 @@ fn (mut g Gen) write_init_function() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
fn_vinit_start_pos := g.out.len
|
fn_vinit_start_pos := g.out.len
|
||||||
|
|
||||||
// ___argv is declared as voidptr here, because that unifies the windows/unix logic
|
// ___argv is declared as voidptr here, because that unifies the windows/unix logic
|
||||||
g.writeln('void _vinit(int ___argc, voidptr ___argv) {')
|
g.writeln('void _vinit(int ___argc, voidptr ___argv) {')
|
||||||
|
|
||||||
|
g.writeln('#if __STDC_HOSTED__ == 1\n\tsignal(SIGSEGV, v_segmentation_fault_handler);\n#endif')
|
||||||
if g.pref.prealloc {
|
if g.pref.prealloc {
|
||||||
g.writeln('prealloc_vinit();')
|
g.writeln('prealloc_vinit();')
|
||||||
}
|
}
|
||||||
@ -5815,17 +6029,21 @@ fn (mut g Gen) write_types(types []ast.TypeSymbol) {
|
|||||||
// if this is the case then we are going to
|
// if this is the case then we are going to
|
||||||
// buffer manip out in front of the struct
|
// buffer manip out in front of the struct
|
||||||
// write the optional in and then continue
|
// write the optional in and then continue
|
||||||
|
// FIXME: for parallel cgen (two different files using the same optional in struct fields)
|
||||||
if field.typ.has_flag(.optional) {
|
if field.typ.has_flag(.optional) {
|
||||||
// Dont use g.typ() here becuase it will register
|
// Dont use g.typ() here becuase it will register
|
||||||
// optional and we dont want that
|
// optional and we dont want that
|
||||||
styp, base := g.optional_type_name(field.typ)
|
styp, base := g.optional_type_name(field.typ)
|
||||||
if styp !in g.optionals {
|
lock g.done_optionals {
|
||||||
last_text := g.type_definitions.cut_to(start_pos).clone()
|
if base !in g.done_optionals {
|
||||||
g.optionals << styp
|
g.done_optionals << base
|
||||||
g.typedefs2.writeln('typedef struct $styp $styp;')
|
last_text := g.type_definitions.after(start_pos).clone()
|
||||||
g.type_definitions.writeln('${g.optional_type_text(styp,
|
g.type_definitions.go_back_to(start_pos)
|
||||||
base)};')
|
g.typedefs2.writeln('typedef struct $styp $styp;')
|
||||||
g.type_definitions.write_string(last_text)
|
g.type_definitions.writeln('${g.optional_type_text(styp,
|
||||||
|
base)};')
|
||||||
|
g.type_definitions.write_string(last_text)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
type_name := g.typ(field.typ)
|
type_name := g.typ(field.typ)
|
||||||
|
@ -23,14 +23,14 @@ const c_current_commit_hash_default = '
|
|||||||
|
|
||||||
const c_concurrency_helpers = '
|
const c_concurrency_helpers = '
|
||||||
typedef struct __shared_map __shared_map;
|
typedef struct __shared_map __shared_map;
|
||||||
struct __shared_map { map val; sync__RwMutex mtx; };
|
struct __shared_map { sync__RwMutex mtx; map val; };
|
||||||
static inline voidptr __dup_shared_map(voidptr src, int sz) {
|
static inline voidptr __dup_shared_map(voidptr src, int sz) {
|
||||||
__shared_map* dest = memdup(src, sz);
|
__shared_map* dest = memdup(src, sz);
|
||||||
sync__RwMutex_init(&dest->mtx);
|
sync__RwMutex_init(&dest->mtx);
|
||||||
return dest;
|
return dest;
|
||||||
}
|
}
|
||||||
typedef struct __shared_array __shared_array;
|
typedef struct __shared_array __shared_array;
|
||||||
struct __shared_array { array val; sync__RwMutex mtx; };
|
struct __shared_array { sync__RwMutex mtx; array val; };
|
||||||
static inline voidptr __dup_shared_array(voidptr src, int sz) {
|
static inline voidptr __dup_shared_array(voidptr src, int sz) {
|
||||||
__shared_array* dest = memdup(src, sz);
|
__shared_array* dest = memdup(src, sz);
|
||||||
sync__RwMutex_init(&dest->mtx);
|
sync__RwMutex_init(&dest->mtx);
|
||||||
@ -451,6 +451,7 @@ voidptr memdup(voidptr src, int sz);
|
|||||||
|
|
||||||
#include <io.h> // _waccess
|
#include <io.h> // _waccess
|
||||||
#include <direct.h> // _wgetcwd
|
#include <direct.h> // _wgetcwd
|
||||||
|
#include <signal.h> // signal and SIGSEGV for segmentation fault handler
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
// On MSVC these are the same (as long as /volatile:ms is passed)
|
// On MSVC these are the same (as long as /volatile:ms is passed)
|
||||||
|
@ -14,7 +14,6 @@ pub fn (mut g Gen) gen_c_main() {
|
|||||||
main_fn_start_pos := g.out.len
|
main_fn_start_pos := g.out.len
|
||||||
|
|
||||||
is_sokol := 'sokol' in g.table.imports
|
is_sokol := 'sokol' in g.table.imports
|
||||||
|
|
||||||
if (g.pref.os == .android && g.pref.is_apk) || (g.pref.os == .ios && is_sokol) {
|
if (g.pref.os == .android && g.pref.is_apk) || (g.pref.os == .ios && is_sokol) {
|
||||||
g.gen_c_android_sokol_main()
|
g.gen_c_android_sokol_main()
|
||||||
} else {
|
} else {
|
||||||
|
@ -364,7 +364,6 @@ fn (mut g Gen) comp_if_cond(cond ast.Expr, pkg_exist bool) bool {
|
|||||||
name = '${left.expr}.$left.field_name'
|
name = '${left.expr}.$left.field_name'
|
||||||
exp_type = g.comptime_var_type_map[name]
|
exp_type = g.comptime_var_type_map[name]
|
||||||
} else if left is ast.TypeNode {
|
} else if left is ast.TypeNode {
|
||||||
name = left.str()
|
|
||||||
// this is only allowed for generics currently, otherwise blocked by checker
|
// this is only allowed for generics currently, otherwise blocked by checker
|
||||||
exp_type = g.unwrap_generic(left.typ)
|
exp_type = g.unwrap_generic(left.typ)
|
||||||
}
|
}
|
||||||
|
@ -21,7 +21,7 @@ fn (mut g Gen) dump_expr_definitions() {
|
|||||||
mut dump_typedefs := map[string]bool{}
|
mut dump_typedefs := map[string]bool{}
|
||||||
mut dump_fns := strings.new_builder(100)
|
mut dump_fns := strings.new_builder(100)
|
||||||
for dump_type, cname in g.table.dumps {
|
for dump_type, cname in g.table.dumps {
|
||||||
to_string_fn_name := g.gen_str_method_for_type(dump_type)
|
to_string_fn_name := g.get_str_fn(dump_type)
|
||||||
is_ptr := ast.Type(dump_type).is_ptr()
|
is_ptr := ast.Type(dump_type).is_ptr()
|
||||||
ptr_asterisk := if is_ptr { '*' } else { '' }
|
ptr_asterisk := if is_ptr { '*' } else { '' }
|
||||||
dump_sym := g.table.get_type_symbol(dump_type)
|
dump_sym := g.table.get_type_symbol(dump_type)
|
||||||
|
@ -143,7 +143,7 @@ fn (mut g Gen) gen_fn_decl(node &ast.FnDecl, skip bool) {
|
|||||||
// if g.fileis('vweb.v') {
|
// if g.fileis('vweb.v') {
|
||||||
// println('\ngen_fn_decl() $node.name $node.is_generic $g.cur_generic_type')
|
// println('\ngen_fn_decl() $node.name $node.is_generic $g.cur_generic_type')
|
||||||
// }
|
// }
|
||||||
if node.generic_names.len > 0 && g.table.cur_concrete_types.len == 0 { // need the cur_concrete_type check to avoid inf. recursion
|
if node.generic_names.len > 0 && g.cur_concrete_types.len == 0 { // need the cur_concrete_type check to avoid inf. recursion
|
||||||
// loop thru each generic type and generate a function
|
// loop thru each generic type and generate a function
|
||||||
for concrete_types in g.table.fn_generic_types[node.name] {
|
for concrete_types in g.table.fn_generic_types[node.name] {
|
||||||
if g.pref.is_verbose {
|
if g.pref.is_verbose {
|
||||||
@ -151,19 +151,19 @@ fn (mut g Gen) gen_fn_decl(node &ast.FnDecl, skip bool) {
|
|||||||
the_type := syms.map(it.name).join(', ')
|
the_type := syms.map(it.name).join(', ')
|
||||||
println('gen fn `$node.name` for type `$the_type`')
|
println('gen fn `$node.name` for type `$the_type`')
|
||||||
}
|
}
|
||||||
g.table.cur_concrete_types = concrete_types
|
g.cur_concrete_types = concrete_types
|
||||||
g.gen_fn_decl(node, skip)
|
g.gen_fn_decl(node, skip)
|
||||||
}
|
}
|
||||||
g.table.cur_concrete_types = []
|
g.cur_concrete_types = []
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
cur_fn_save := g.table.cur_fn
|
cur_fn_save := g.cur_fn
|
||||||
defer {
|
defer {
|
||||||
g.table.cur_fn = cur_fn_save
|
g.cur_fn = cur_fn_save
|
||||||
}
|
}
|
||||||
unsafe {
|
unsafe {
|
||||||
// TODO remove unsafe
|
// TODO remove unsafe
|
||||||
g.table.cur_fn = node
|
g.cur_fn = node
|
||||||
}
|
}
|
||||||
fn_start_pos := g.out.len
|
fn_start_pos := g.out.len
|
||||||
is_closure := node.scope.has_inherited_vars()
|
is_closure := node.scope.has_inherited_vars()
|
||||||
@ -206,7 +206,7 @@ fn (mut g Gen) gen_fn_decl(node &ast.FnDecl, skip bool) {
|
|||||||
}
|
}
|
||||||
mut type_name := g.typ(node.return_type)
|
mut type_name := g.typ(node.return_type)
|
||||||
|
|
||||||
name = g.generic_fn_name(g.table.cur_concrete_types, name, true)
|
name = g.generic_fn_name(g.cur_concrete_types, name, true)
|
||||||
|
|
||||||
if g.pref.obfuscate && g.cur_mod.name == 'main' && name.starts_with('main__') && !node.is_main
|
if g.pref.obfuscate && g.cur_mod.name == 'main' && name.starts_with('main__') && !node.is_main
|
||||||
&& node.name != 'str' {
|
&& node.name != 'str' {
|
||||||
@ -288,7 +288,7 @@ fn (mut g Gen) gen_fn_decl(node &ast.FnDecl, skip bool) {
|
|||||||
}
|
}
|
||||||
arg_str := g.out.after(arg_start_pos)
|
arg_str := g.out.after(arg_start_pos)
|
||||||
if node.no_body || ((g.pref.use_cache && g.pref.build_mode != .build_module) && node.is_builtin
|
if node.no_body || ((g.pref.use_cache && g.pref.build_mode != .build_module) && node.is_builtin
|
||||||
&& !g.is_test) || skip {
|
&& !g.pref.is_test) || skip {
|
||||||
// Just a function header. Builtin function bodies are defined in builtin.o
|
// Just a function header. Builtin function bodies are defined in builtin.o
|
||||||
g.definitions.writeln(');') // // NO BODY')
|
g.definitions.writeln(');') // // NO BODY')
|
||||||
g.writeln(');')
|
g.writeln(');')
|
||||||
@ -644,14 +644,16 @@ fn (mut g Gen) method_call(node ast.CallExpr) {
|
|||||||
g.checker_bug('CallExpr.receiver_type is 0 in method_call', node.pos)
|
g.checker_bug('CallExpr.receiver_type is 0 in method_call', node.pos)
|
||||||
}
|
}
|
||||||
mut unwrapped_rec_type := node.receiver_type
|
mut unwrapped_rec_type := node.receiver_type
|
||||||
if g.table.cur_fn.generic_names.len > 0 { // in generic fn
|
if g.cur_fn != 0 && g.cur_fn.generic_names.len > 0 { // in generic fn
|
||||||
unwrapped_rec_type = g.unwrap_generic(node.receiver_type)
|
unwrapped_rec_type = g.unwrap_generic(node.receiver_type)
|
||||||
} else { // in non-generic fn
|
} else { // in non-generic fn
|
||||||
sym := g.table.get_type_symbol(node.receiver_type)
|
sym := g.table.get_type_symbol(node.receiver_type)
|
||||||
match sym.info {
|
match sym.info {
|
||||||
ast.Struct, ast.Interface, ast.SumType {
|
ast.Struct, ast.Interface, ast.SumType {
|
||||||
generic_names := sym.info.generic_types.map(g.table.get_type_symbol(it).name)
|
generic_names := sym.info.generic_types.map(g.table.get_type_symbol(it).name)
|
||||||
if utyp := g.table.resolve_generic_to_concrete(node.receiver_type, generic_names,
|
// see comment at top of vlib/v/gen/c/utils.v
|
||||||
|
mut muttable := unsafe { &ast.Table(g.table) }
|
||||||
|
if utyp := muttable.resolve_generic_to_concrete(node.receiver_type, generic_names,
|
||||||
sym.info.concrete_types)
|
sym.info.concrete_types)
|
||||||
{
|
{
|
||||||
unwrapped_rec_type = utyp
|
unwrapped_rec_type = utyp
|
||||||
@ -671,7 +673,7 @@ fn (mut g Gen) method_call(node ast.CallExpr) {
|
|||||||
if typ_sym.kind == .interface_ && (typ_sym.info as ast.Interface).defines_method(node.name) {
|
if typ_sym.kind == .interface_ && (typ_sym.info as ast.Interface).defines_method(node.name) {
|
||||||
// Speaker_name_table[s._interface_idx].speak(s._object)
|
// Speaker_name_table[s._interface_idx].speak(s._object)
|
||||||
$if debug_interface_method_call ? {
|
$if debug_interface_method_call ? {
|
||||||
eprintln('>>> interface typ_sym.name: $typ_sym.name | receiver_type_name: $receiver_type_name')
|
eprintln('>>> interface typ_sym.name: $typ_sym.name | receiver_type_name: $receiver_type_name | pos: $node.pos')
|
||||||
}
|
}
|
||||||
g.write('${c_name(receiver_type_name)}_name_table[')
|
g.write('${c_name(receiver_type_name)}_name_table[')
|
||||||
g.expr(node.left)
|
g.expr(node.left)
|
||||||
@ -712,7 +714,7 @@ fn (mut g Gen) method_call(node ast.CallExpr) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
'contains' {
|
'contains' {
|
||||||
g.gen_array_contains(node)
|
g.gen_array_contains(node.left_type, node.left, node.args[0].expr)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
'index' {
|
'index' {
|
||||||
@ -795,7 +797,7 @@ fn (mut g Gen) method_call(node ast.CallExpr) {
|
|||||||
if rec_type.has_flag(.shared_f) {
|
if rec_type.has_flag(.shared_f) {
|
||||||
rec_type = rec_type.clear_flag(.shared_f).set_nr_muls(0)
|
rec_type = rec_type.clear_flag(.shared_f).set_nr_muls(0)
|
||||||
}
|
}
|
||||||
g.gen_str_method_for_type(rec_type)
|
g.get_str_fn(rec_type)
|
||||||
} else if node.name == 'free' {
|
} else if node.name == 'free' {
|
||||||
mut rec_type := node.receiver_type
|
mut rec_type := node.receiver_type
|
||||||
if rec_type.has_flag(.shared_f) {
|
if rec_type.has_flag(.shared_f) {
|
||||||
@ -1333,7 +1335,8 @@ fn (mut g Gen) call_args(node ast.CallExpr) {
|
|||||||
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 fn_def := g.table.find_fn(node.name) {
|
||||||
if utyp := g.table.resolve_generic_to_concrete(arr_info.elem_type, fn_def.generic_names,
|
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)
|
node.concrete_types)
|
||||||
{
|
{
|
||||||
arr_info.elem_type = utyp
|
arr_info.elem_type = utyp
|
||||||
|
@ -347,11 +347,7 @@ fn (mut g Gen) index_of_map(node ast.IndexExpr, sym ast.TypeSymbol) {
|
|||||||
g.expr(node.left)
|
g.expr(node.left)
|
||||||
}
|
}
|
||||||
if node.left_type.has_flag(.shared_f) {
|
if node.left_type.has_flag(.shared_f) {
|
||||||
if left_is_ptr {
|
g.write('->val')
|
||||||
g.write('->val')
|
|
||||||
} else {
|
|
||||||
g.write('.val')
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
g.write(', &($key_type_str[]){')
|
g.write(', &($key_type_str[]){')
|
||||||
g.expr(node.index)
|
g.expr(node.index)
|
||||||
@ -374,10 +370,13 @@ fn (mut g Gen) index_of_map(node ast.IndexExpr, sym ast.TypeSymbol) {
|
|||||||
} else {
|
} else {
|
||||||
g.write('(*($elem_type_str*)map_get((map*)')
|
g.write('(*($elem_type_str*)map_get((map*)')
|
||||||
}
|
}
|
||||||
if !left_is_ptr {
|
if !left_is_ptr || node.left_type.has_flag(.shared_f) {
|
||||||
g.write('&')
|
g.write('&')
|
||||||
}
|
}
|
||||||
g.expr(node.left)
|
g.expr(node.left)
|
||||||
|
if node.left_type.has_flag(.shared_f) {
|
||||||
|
g.write('->val')
|
||||||
|
}
|
||||||
g.write(', &($key_type_str[]){')
|
g.write(', &($key_type_str[]){')
|
||||||
g.expr(node.index)
|
g.expr(node.index)
|
||||||
g.write('}, &($elem_type_str[]){ $zero }))')
|
g.write('}, &($elem_type_str[]){ $zero }))')
|
||||||
|
@ -63,7 +63,7 @@ fn (mut g Gen) infix_expr_arrow_op(node ast.InfixExpr) {
|
|||||||
tmp_opt := if gen_or { g.new_tmp_var() } else { '' }
|
tmp_opt := if gen_or { g.new_tmp_var() } else { '' }
|
||||||
if gen_or {
|
if gen_or {
|
||||||
elem_styp := g.typ(elem_type)
|
elem_styp := g.typ(elem_type)
|
||||||
g.register_chan_push_optional_call(elem_styp, styp)
|
g.register_chan_push_optional_fn(elem_styp, styp)
|
||||||
g.write('Option_void $tmp_opt = __Option_${styp}_pushval(')
|
g.write('Option_void $tmp_opt = __Option_${styp}_pushval(')
|
||||||
} else {
|
} else {
|
||||||
g.write('__${styp}_pushval(')
|
g.write('__${styp}_pushval(')
|
||||||
@ -114,7 +114,7 @@ fn (mut g Gen) infix_expr_eq_op(node ast.InfixExpr) {
|
|||||||
&& left.sym.kind in [.array, .array_fixed, .alias, .map, .struct_, .sum_type] {
|
&& left.sym.kind in [.array, .array_fixed, .alias, .map, .struct_, .sum_type] {
|
||||||
match left.sym.kind {
|
match left.sym.kind {
|
||||||
.alias {
|
.alias {
|
||||||
ptr_typ := g.gen_alias_equality_fn(left.typ)
|
ptr_typ := g.equality_fn(left.typ)
|
||||||
if node.op == .ne {
|
if node.op == .ne {
|
||||||
g.write('!')
|
g.write('!')
|
||||||
}
|
}
|
||||||
@ -131,7 +131,7 @@ fn (mut g Gen) infix_expr_eq_op(node ast.InfixExpr) {
|
|||||||
g.write(')')
|
g.write(')')
|
||||||
}
|
}
|
||||||
.array {
|
.array {
|
||||||
ptr_typ := g.gen_array_equality_fn(left.unaliased.clear_flag(.shared_f))
|
ptr_typ := g.equality_fn(left.unaliased.clear_flag(.shared_f))
|
||||||
if node.op == .ne {
|
if node.op == .ne {
|
||||||
g.write('!')
|
g.write('!')
|
||||||
}
|
}
|
||||||
@ -141,11 +141,7 @@ fn (mut g Gen) infix_expr_eq_op(node ast.InfixExpr) {
|
|||||||
}
|
}
|
||||||
g.expr(node.left)
|
g.expr(node.left)
|
||||||
if left.typ.has_flag(.shared_f) {
|
if left.typ.has_flag(.shared_f) {
|
||||||
if left.typ.is_ptr() {
|
g.write('->val')
|
||||||
g.write('->val')
|
|
||||||
} else {
|
|
||||||
g.write('.val')
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
g.write(', ')
|
g.write(', ')
|
||||||
if right.typ.is_ptr() && !right.typ.has_flag(.shared_f) {
|
if right.typ.is_ptr() && !right.typ.has_flag(.shared_f) {
|
||||||
@ -153,16 +149,12 @@ fn (mut g Gen) infix_expr_eq_op(node ast.InfixExpr) {
|
|||||||
}
|
}
|
||||||
g.expr(node.right)
|
g.expr(node.right)
|
||||||
if right.typ.has_flag(.shared_f) {
|
if right.typ.has_flag(.shared_f) {
|
||||||
if right.typ.is_ptr() {
|
g.write('->val')
|
||||||
g.write('->val')
|
|
||||||
} else {
|
|
||||||
g.write('.val')
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
g.write(')')
|
g.write(')')
|
||||||
}
|
}
|
||||||
.array_fixed {
|
.array_fixed {
|
||||||
ptr_typ := g.gen_fixed_array_equality_fn(left.unaliased)
|
ptr_typ := g.equality_fn(left.unaliased)
|
||||||
if node.op == .ne {
|
if node.op == .ne {
|
||||||
g.write('!')
|
g.write('!')
|
||||||
}
|
}
|
||||||
@ -184,7 +176,7 @@ fn (mut g Gen) infix_expr_eq_op(node ast.InfixExpr) {
|
|||||||
g.write(')')
|
g.write(')')
|
||||||
}
|
}
|
||||||
.map {
|
.map {
|
||||||
ptr_typ := g.gen_map_equality_fn(left.unaliased)
|
ptr_typ := g.equality_fn(left.unaliased)
|
||||||
if node.op == .ne {
|
if node.op == .ne {
|
||||||
g.write('!')
|
g.write('!')
|
||||||
}
|
}
|
||||||
@ -201,7 +193,7 @@ fn (mut g Gen) infix_expr_eq_op(node ast.InfixExpr) {
|
|||||||
g.write(')')
|
g.write(')')
|
||||||
}
|
}
|
||||||
.struct_ {
|
.struct_ {
|
||||||
ptr_typ := g.gen_struct_equality_fn(left.unaliased)
|
ptr_typ := g.equality_fn(left.unaliased)
|
||||||
if node.op == .ne {
|
if node.op == .ne {
|
||||||
g.write('!')
|
g.write('!')
|
||||||
}
|
}
|
||||||
@ -218,7 +210,7 @@ fn (mut g Gen) infix_expr_eq_op(node ast.InfixExpr) {
|
|||||||
g.write(')')
|
g.write(')')
|
||||||
}
|
}
|
||||||
.sum_type {
|
.sum_type {
|
||||||
ptr_typ := g.gen_sumtype_equality_fn(left.unaliased)
|
ptr_typ := g.equality_fn(left.unaliased)
|
||||||
if node.op == .ne {
|
if node.op == .ne {
|
||||||
g.write('!')
|
g.write('!')
|
||||||
}
|
}
|
||||||
@ -385,19 +377,7 @@ fn (mut g Gen) infix_expr_in_op(node ast.InfixExpr) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn_name := g.gen_array_contains_method(node.right_type)
|
g.gen_array_contains(node.right_type, node.right, node.left)
|
||||||
g.write('(${fn_name}(')
|
|
||||||
if right.typ.is_ptr() && right.typ.share() != .shared_t {
|
|
||||||
g.write('*')
|
|
||||||
}
|
|
||||||
g.expr(node.right)
|
|
||||||
if right.typ.share() == .shared_t {
|
|
||||||
g.write('->val')
|
|
||||||
}
|
|
||||||
g.write(', ')
|
|
||||||
g.expr(node.left)
|
|
||||||
g.write('))')
|
|
||||||
return
|
|
||||||
} else if right.unaliased_sym.kind == .map {
|
} else if right.unaliased_sym.kind == .map {
|
||||||
g.write('_IN_MAP(')
|
g.write('_IN_MAP(')
|
||||||
if !left.typ.is_ptr() {
|
if !left.typ.is_ptr() {
|
||||||
@ -437,7 +417,7 @@ fn (mut g Gen) infix_expr_in_optimization(left ast.Expr, right ast.ArrayInit) {
|
|||||||
if is_str {
|
if is_str {
|
||||||
g.write('string__eq(')
|
g.write('string__eq(')
|
||||||
} else if is_array {
|
} else if is_array {
|
||||||
ptr_typ := g.gen_array_equality_fn(right.elem_type)
|
ptr_typ := g.equality_fn(right.elem_type)
|
||||||
g.write('${ptr_typ}_arr_eq(')
|
g.write('${ptr_typ}_arr_eq(')
|
||||||
}
|
}
|
||||||
g.expr(left)
|
g.expr(left)
|
||||||
@ -580,10 +560,16 @@ fn (mut g Gen) infix_expr_left_shift_op(node ast.InfixExpr) {
|
|||||||
elem_type_str := g.typ(array_info.elem_type)
|
elem_type_str := g.typ(array_info.elem_type)
|
||||||
elem_sym := g.table.get_type_symbol(array_info.elem_type)
|
elem_sym := g.table.get_type_symbol(array_info.elem_type)
|
||||||
g.write('array_push${noscan}((array*)')
|
g.write('array_push${noscan}((array*)')
|
||||||
if !left.typ.is_ptr() {
|
if node.left_type.has_flag(.shared_f) && !node.left_type.deref().is_ptr() {
|
||||||
|
}
|
||||||
|
if !left.typ.is_ptr()
|
||||||
|
|| (node.left_type.has_flag(.shared_f) && !node.left_type.deref().is_ptr()) {
|
||||||
g.write('&')
|
g.write('&')
|
||||||
}
|
}
|
||||||
g.expr(node.left)
|
g.expr(node.left)
|
||||||
|
if node.left_type.has_flag(.shared_f) {
|
||||||
|
g.write('->val')
|
||||||
|
}
|
||||||
if elem_sym.kind == .function {
|
if elem_sym.kind == .function {
|
||||||
g.write(', _MOV((voidptr[]){ ')
|
g.write(', _MOV((voidptr[]){ ')
|
||||||
} else {
|
} else {
|
||||||
|
@ -19,29 +19,34 @@ import strings
|
|||||||
// }
|
// }
|
||||||
// Codegen json_decode/encode funcs
|
// Codegen json_decode/encode funcs
|
||||||
fn (mut g Gen) gen_json_for_type(typ ast.Type) {
|
fn (mut g Gen) gen_json_for_type(typ ast.Type) {
|
||||||
utyp := g.unwrap_generic(typ)
|
utyp := g.unwrap_generic(typ).set_nr_muls(0)
|
||||||
mut dec := strings.new_builder(100)
|
|
||||||
mut enc := strings.new_builder(100)
|
|
||||||
sym := g.table.get_type_symbol(utyp)
|
sym := g.table.get_type_symbol(utyp)
|
||||||
styp := g.typ(utyp)
|
|
||||||
g.register_optional(utyp)
|
|
||||||
if is_js_prim(sym.name) || sym.kind == .enum_ {
|
if is_js_prim(sym.name) || sym.kind == .enum_ {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if sym.kind == .array {
|
g.json_types << utyp
|
||||||
// return
|
}
|
||||||
}
|
|
||||||
if sym.name in g.json_types {
|
fn (mut g Gen) gen_jsons() {
|
||||||
return
|
mut done := []ast.Type{}
|
||||||
}
|
for i := 0; i < g.json_types.len; i++ {
|
||||||
g.json_types << sym.name
|
utyp := g.json_types[i]
|
||||||
// println('gen_json_for_type($sym.name)')
|
if utyp in done {
|
||||||
// decode_TYPE funcs receive an actual cJSON* object to decode
|
continue
|
||||||
// cJSON_Parse(str) call is added by the compiler
|
}
|
||||||
// Code gen decoder
|
done << utyp
|
||||||
dec_fn_name := js_dec_name(styp)
|
mut dec := strings.new_builder(100)
|
||||||
dec_fn_dec := 'Option_$styp ${dec_fn_name}(cJSON* root)'
|
mut enc := strings.new_builder(100)
|
||||||
dec.writeln('
|
sym := g.table.get_type_symbol(utyp)
|
||||||
|
styp := g.typ(utyp)
|
||||||
|
g.register_optional(utyp)
|
||||||
|
// println('gen_json_for_type($sym.name)')
|
||||||
|
// decode_TYPE funcs receive an actual cJSON* object to decode
|
||||||
|
// cJSON_Parse(str) call is added by the compiler
|
||||||
|
// Code gen decoder
|
||||||
|
dec_fn_name := js_dec_name(styp)
|
||||||
|
dec_fn_dec := 'Option_$styp ${dec_fn_name}(cJSON* root)'
|
||||||
|
dec.writeln('
|
||||||
$dec_fn_dec {
|
$dec_fn_dec {
|
||||||
$styp res;
|
$styp res;
|
||||||
if (!root) {
|
if (!root) {
|
||||||
@ -53,69 +58,70 @@ $dec_fn_dec {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
')
|
')
|
||||||
g.json_forward_decls.writeln('$dec_fn_dec;')
|
g.json_forward_decls.writeln('$dec_fn_dec;')
|
||||||
// Code gen encoder
|
// Code gen encoder
|
||||||
// encode_TYPE funcs receive an object to encode
|
// encode_TYPE funcs receive an object to encode
|
||||||
enc_fn_name := js_enc_name(styp)
|
enc_fn_name := js_enc_name(styp)
|
||||||
enc_fn_dec := 'cJSON* ${enc_fn_name}($styp val)'
|
enc_fn_dec := 'cJSON* ${enc_fn_name}($styp val)'
|
||||||
g.json_forward_decls.writeln('$enc_fn_dec;\n')
|
g.json_forward_decls.writeln('$enc_fn_dec;\n')
|
||||||
enc.writeln('
|
enc.writeln('
|
||||||
$enc_fn_dec {
|
$enc_fn_dec {
|
||||||
\tcJSON *o;')
|
\tcJSON *o;')
|
||||||
if sym.kind == .array {
|
if sym.kind == .array {
|
||||||
// Handle arrays
|
// Handle arrays
|
||||||
value_type := g.table.value_type(utyp)
|
value_type := g.table.value_type(utyp)
|
||||||
// If we have `[]Profile`, have to register a Profile en(de)coder first
|
// If we have `[]Profile`, have to register a Profile en(de)coder first
|
||||||
g.gen_json_for_type(value_type)
|
g.gen_json_for_type(value_type)
|
||||||
dec.writeln(g.decode_array(value_type))
|
dec.writeln(g.decode_array(value_type))
|
||||||
enc.writeln(g.encode_array(value_type))
|
enc.writeln(g.encode_array(value_type))
|
||||||
// enc += g.encode_array(t)
|
// enc += g.encode_array(t)
|
||||||
} else if sym.kind == .map {
|
} else if sym.kind == .map {
|
||||||
// Handle maps
|
// Handle maps
|
||||||
m := sym.info as ast.Map
|
m := sym.info as ast.Map
|
||||||
g.gen_json_for_type(m.key_type)
|
g.gen_json_for_type(m.key_type)
|
||||||
g.gen_json_for_type(m.value_type)
|
g.gen_json_for_type(m.value_type)
|
||||||
dec.writeln(g.decode_map(m.key_type, m.value_type))
|
dec.writeln(g.decode_map(m.key_type, m.value_type))
|
||||||
enc.writeln(g.encode_map(m.key_type, m.value_type))
|
enc.writeln(g.encode_map(m.key_type, m.value_type))
|
||||||
} else if sym.kind == .alias {
|
} else if sym.kind == .alias {
|
||||||
a := sym.info as ast.Alias
|
a := sym.info as ast.Alias
|
||||||
parent_typ := a.parent_type
|
parent_typ := a.parent_type
|
||||||
psym := g.table.get_type_symbol(parent_typ)
|
psym := g.table.get_type_symbol(parent_typ)
|
||||||
if is_js_prim(g.typ(parent_typ)) {
|
if is_js_prim(g.typ(parent_typ)) {
|
||||||
g.gen_json_for_type(parent_typ)
|
g.gen_json_for_type(parent_typ)
|
||||||
return
|
continue
|
||||||
}
|
}
|
||||||
enc.writeln('\to = cJSON_CreateObject();')
|
enc.writeln('\to = cJSON_CreateObject();')
|
||||||
if psym.info is ast.Struct {
|
if psym.info is ast.Struct {
|
||||||
g.gen_struct_enc_dec(psym.info, styp, mut enc, mut dec)
|
g.gen_struct_enc_dec(psym.info, styp, mut enc, mut dec)
|
||||||
} else if psym.kind == .sum_type {
|
} else if psym.kind == .sum_type {
|
||||||
verror('json: $sym.name aliased sumtypes does not work at the moment')
|
verror('json: $sym.name aliased sumtypes does not work at the moment')
|
||||||
|
} else {
|
||||||
|
verror('json: $sym.name is not struct')
|
||||||
|
}
|
||||||
|
} else if sym.kind == .sum_type {
|
||||||
|
enc.writeln('\to = cJSON_CreateObject();')
|
||||||
|
// Sumtypes. Range through variants of sumtype
|
||||||
|
if sym.info !is ast.SumType {
|
||||||
|
verror('json: $sym.name is not a sumtype')
|
||||||
|
}
|
||||||
|
g.gen_sumtype_enc_dec(sym, mut enc, mut dec)
|
||||||
} else {
|
} else {
|
||||||
verror('json: $sym.name is not struct')
|
enc.writeln('\to = cJSON_CreateObject();')
|
||||||
|
// Structs. Range through fields
|
||||||
|
if sym.info !is ast.Struct {
|
||||||
|
verror('json: $sym.name is not struct')
|
||||||
|
}
|
||||||
|
g.gen_struct_enc_dec(sym.info, styp, mut enc, mut dec)
|
||||||
}
|
}
|
||||||
} else if sym.kind == .sum_type {
|
// cJSON_delete
|
||||||
enc.writeln('\to = cJSON_CreateObject();')
|
// p.cgen.fns << '$dec return opt_ok(res); \n}'
|
||||||
// Sumtypes. Range through variants of sumtype
|
dec.writeln('\tOption_$styp ret;')
|
||||||
if sym.info !is ast.SumType {
|
dec.writeln('\topt_ok(&res, (Option*)&ret, sizeof(res));')
|
||||||
verror('json: $sym.name is not a sumtype')
|
dec.writeln('\treturn ret;\n}')
|
||||||
}
|
enc.writeln('\treturn o;\n}')
|
||||||
g.gen_sumtype_enc_dec(sym, mut enc, mut dec)
|
g.definitions.writeln(dec.str())
|
||||||
} else {
|
g.gowrappers.writeln(enc.str())
|
||||||
enc.writeln('\to = cJSON_CreateObject();')
|
|
||||||
// Structs. Range through fields
|
|
||||||
if sym.info !is ast.Struct {
|
|
||||||
verror('json: $sym.name is not struct')
|
|
||||||
}
|
|
||||||
g.gen_struct_enc_dec(sym.info, styp, mut enc, mut dec)
|
|
||||||
}
|
}
|
||||||
// cJSON_delete
|
|
||||||
// p.cgen.fns << '$dec return opt_ok(res); \n}'
|
|
||||||
dec.writeln('\tOption_$styp ret;')
|
|
||||||
dec.writeln('\topt_ok(&res, (Option*)&ret, sizeof(res));')
|
|
||||||
dec.writeln('\treturn ret;\n}')
|
|
||||||
enc.writeln('\treturn o;\n}')
|
|
||||||
g.definitions.writeln(dec.str())
|
|
||||||
g.gowrappers.writeln(enc.str())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[inline]
|
[inline]
|
||||||
@ -150,7 +156,7 @@ fn (mut g Gen) gen_sumtype_enc_dec(sym ast.TypeSymbol, mut enc strings.Builder,
|
|||||||
g.gen_json_for_type(variant)
|
g.gen_json_for_type(variant)
|
||||||
|
|
||||||
// Helpers for decoding
|
// Helpers for decoding
|
||||||
g.write_sumtype_casting_fn(variant, typ)
|
g.get_sumtype_casting_fn(variant, typ)
|
||||||
g.definitions.writeln('static inline $sym.cname ${variant_typ}_to_sumtype_${sym.cname}($variant_typ* x);')
|
g.definitions.writeln('static inline $sym.cname ${variant_typ}_to_sumtype_${sym.cname}($variant_typ* x);')
|
||||||
|
|
||||||
// ENCODING
|
// ENCODING
|
||||||
|
@ -80,7 +80,7 @@ fn (mut g Gen) gen_expr_to_string(expr ast.Expr, etype ast.Type) {
|
|||||||
}
|
}
|
||||||
sym_has_str_method, str_method_expects_ptr, _ := sym.str_method_info()
|
sym_has_str_method, str_method_expects_ptr, _ := sym.str_method_info()
|
||||||
if typ.has_flag(.variadic) {
|
if typ.has_flag(.variadic) {
|
||||||
str_fn_name := g.gen_str_method_for_type(typ)
|
str_fn_name := g.get_str_fn(typ)
|
||||||
g.write('${str_fn_name}(')
|
g.write('${str_fn_name}(')
|
||||||
g.expr(expr)
|
g.expr(expr)
|
||||||
g.write(')')
|
g.write(')')
|
||||||
@ -93,7 +93,7 @@ fn (mut g Gen) gen_expr_to_string(expr ast.Expr, etype ast.Type) {
|
|||||||
g.write('_SLIT("<none>")')
|
g.write('_SLIT("<none>")')
|
||||||
} else if sym.kind == .enum_ {
|
} else if sym.kind == .enum_ {
|
||||||
if expr !is ast.EnumVal {
|
if expr !is ast.EnumVal {
|
||||||
str_fn_name := g.gen_str_method_for_type(typ)
|
str_fn_name := g.get_str_fn(typ)
|
||||||
g.write('${str_fn_name}(')
|
g.write('${str_fn_name}(')
|
||||||
g.enum_expr(expr)
|
g.enum_expr(expr)
|
||||||
g.write(')')
|
g.write(')')
|
||||||
@ -106,7 +106,7 @@ fn (mut g Gen) gen_expr_to_string(expr ast.Expr, etype ast.Type) {
|
|||||||
|| sym.kind in [.array, .array_fixed, .map, .struct_, .multi_return, .sum_type, .interface_] {
|
|| sym.kind in [.array, .array_fixed, .map, .struct_, .multi_return, .sum_type, .interface_] {
|
||||||
is_ptr := typ.is_ptr()
|
is_ptr := typ.is_ptr()
|
||||||
is_var_mut := expr.is_auto_deref_var()
|
is_var_mut := expr.is_auto_deref_var()
|
||||||
str_fn_name := g.gen_str_method_for_type(typ)
|
str_fn_name := g.get_str_fn(typ)
|
||||||
if is_ptr && !is_var_mut {
|
if is_ptr && !is_var_mut {
|
||||||
g.write('str_intp(1, _MOV((StrIntpData[]){{_SLIT("&"), $si_s_code ,{.d_s=')
|
g.write('str_intp(1, _MOV((StrIntpData[]){{_SLIT("&"), $si_s_code ,{.d_s=')
|
||||||
}
|
}
|
||||||
@ -132,7 +132,7 @@ fn (mut g Gen) gen_expr_to_string(expr ast.Expr, etype ast.Type) {
|
|||||||
// g.write(')')
|
// g.write(')')
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
str_fn_name := g.gen_str_method_for_type(typ)
|
str_fn_name := g.get_str_fn(typ)
|
||||||
g.write('${str_fn_name}(')
|
g.write('${str_fn_name}(')
|
||||||
if expr.is_auto_deref_var() {
|
if expr.is_auto_deref_var() {
|
||||||
g.write('*')
|
g.write('*')
|
||||||
|
@ -7,8 +7,20 @@ import v.ast
|
|||||||
|
|
||||||
fn (mut g Gen) unwrap_generic(typ ast.Type) ast.Type {
|
fn (mut g Gen) unwrap_generic(typ ast.Type) ast.Type {
|
||||||
if typ.has_flag(.generic) {
|
if typ.has_flag(.generic) {
|
||||||
if t_typ := g.table.resolve_generic_to_concrete(typ, g.table.cur_fn.generic_names,
|
/*
|
||||||
g.table.cur_concrete_types)
|
resolve_generic_to_concrete should not mutate the table.
|
||||||
|
It mutates if the generic type is for example []T and the
|
||||||
|
concrete type is an array type that has not been registered
|
||||||
|
yet. This should have already happened in the checker, since
|
||||||
|
it also calls resolve_generic_to_concrete. g.table is made
|
||||||
|
non-mut to make sure no one else can accidentally mutates the table.
|
||||||
|
*/
|
||||||
|
mut muttable := unsafe { &ast.Table(g.table) }
|
||||||
|
if t_typ := muttable.resolve_generic_to_concrete(typ, if g.cur_fn != 0 {
|
||||||
|
g.cur_fn.generic_names
|
||||||
|
} else {
|
||||||
|
[]string{}
|
||||||
|
}, g.cur_concrete_types)
|
||||||
{
|
{
|
||||||
return t_typ
|
return t_typ
|
||||||
}
|
}
|
||||||
|
@ -129,7 +129,6 @@ fn (mut g JsGen) comp_if_cond(cond ast.Expr, pkg_exist bool) bool {
|
|||||||
name = '${left.expr}.$left.field_name'
|
name = '${left.expr}.$left.field_name'
|
||||||
exp_type = g.comptime_var_type_map[name]
|
exp_type = g.comptime_var_type_map[name]
|
||||||
} else if left is ast.TypeNode {
|
} else if left is ast.TypeNode {
|
||||||
name = left.str()
|
|
||||||
// this is only allowed for generics currently, otherwise blocked by checker
|
// this is only allowed for generics currently, otherwise blocked by checker
|
||||||
exp_type = g.unwrap_generic(left.typ)
|
exp_type = g.unwrap_generic(left.typ)
|
||||||
}
|
}
|
||||||
|
@ -346,7 +346,7 @@ pub fn parse_files(paths []string, table &ast.Table, pref &pref.Preferences) []&
|
|||||||
}
|
}
|
||||||
$if macos {
|
$if macos {
|
||||||
/*
|
/*
|
||||||
if pref.is_parallel && paths[0].contains('/array.v') {
|
if !pref.no_parallel && paths[0].contains('/array.v') {
|
||||||
println('\n\n\nparse_files() nr_files=$paths.len')
|
println('\n\n\nparse_files() nr_files=$paths.len')
|
||||||
println(paths)
|
println(paths)
|
||||||
nr_cpus := runtime.nr_cpus()
|
nr_cpus := runtime.nr_cpus()
|
||||||
|
@ -136,6 +136,10 @@ pub fn (mut p Preferences) fill_with_defaults() {
|
|||||||
if p.bare_builtin_dir == '' {
|
if p.bare_builtin_dir == '' {
|
||||||
p.bare_builtin_dir = os.join_path(p.vroot, 'vlib', 'builtin', 'linux_bare')
|
p.bare_builtin_dir = os.join_path(p.vroot, 'vlib', 'builtin', 'linux_bare')
|
||||||
}
|
}
|
||||||
|
$if prealloc {
|
||||||
|
eprintln('disabling parallel cgen, since V was built with -prealloc')
|
||||||
|
p.no_parallel = true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const cc_to_windows = 'x86_64-w64-mingw32-gcc'
|
pub const cc_to_windows = 'x86_64-w64-mingw32-gcc'
|
||||||
|
@ -175,7 +175,7 @@ pub mut:
|
|||||||
no_rsp bool // when true, pass C backend options directly on the CLI (do not use `.rsp` files for them, some older C compilers do not support them)
|
no_rsp bool // when true, pass C backend options directly on the CLI (do not use `.rsp` files for them, some older C compilers do not support them)
|
||||||
no_std bool // when true, do not pass -std=c99 to the C backend
|
no_std bool // when true, do not pass -std=c99 to the C backend
|
||||||
use_color ColorOutput // whether the warnings/errors should use ANSI color escapes.
|
use_color ColorOutput // whether the warnings/errors should use ANSI color escapes.
|
||||||
is_parallel bool
|
no_parallel bool
|
||||||
is_vweb bool // skip _ var warning in templates
|
is_vweb bool // skip _ var warning in templates
|
||||||
only_check_syntax bool // when true, just parse the files, then stop, before running checker
|
only_check_syntax bool // when true, just parse the files, then stop, before running checker
|
||||||
check_only bool // same as only_check_syntax, but also runs the checker
|
check_only bool // same as only_check_syntax, but also runs the checker
|
||||||
@ -474,8 +474,8 @@ pub fn parse_args(known_external_commands []string, args []string) (&Preferences
|
|||||||
res.prealloc = true
|
res.prealloc = true
|
||||||
res.build_options << arg
|
res.build_options << arg
|
||||||
}
|
}
|
||||||
'-parallel' {
|
'-no-parallel' {
|
||||||
res.is_parallel = true
|
res.no_parallel = true
|
||||||
}
|
}
|
||||||
'-native' {
|
'-native' {
|
||||||
res.backend = .native
|
res.backend = .native
|
||||||
|
@ -85,12 +85,10 @@ fn test_comptime_for_fields() {
|
|||||||
if field.name == 'f' {
|
if field.name == 'f' {
|
||||||
assert sizeof(field) == 8
|
assert sizeof(field) == 8
|
||||||
assert isreftype(field) == false
|
assert isreftype(field) == false
|
||||||
// assert typeof(field) == 'u64'
|
|
||||||
assert typeof(field).name == 'u64'
|
assert typeof(field).name == 'u64'
|
||||||
fields_found++
|
fields_found++
|
||||||
}
|
}
|
||||||
if field.name == 'g' {
|
if field.name == 'g' {
|
||||||
// assert typeof(field) == 'string'
|
|
||||||
assert typeof(field).name == 'string'
|
assert typeof(field).name == 'string'
|
||||||
assert isreftype(field) == true
|
assert isreftype(field) == true
|
||||||
fields_found++
|
fields_found++
|
||||||
|
@ -7,7 +7,7 @@ fn inc_array_elem(shared b []int, i int) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn test_autolock_array() {
|
fn test_autolock_array() {
|
||||||
shared a := &[1, 2, 7, 5]
|
shared a := [1, 2, 7, 5]
|
||||||
t := go inc_array_elem(shared a, 2)
|
t := go inc_array_elem(shared a, 2)
|
||||||
for _ in 0 .. iterations {
|
for _ in 0 .. iterations {
|
||||||
a[2]++
|
a[2]++
|
||||||
@ -23,7 +23,7 @@ fn inc_map_elem(shared b map[string]int, k string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn test_autolock_map() {
|
fn test_autolock_map() {
|
||||||
shared m := &{
|
shared m := {
|
||||||
'xy': 1
|
'xy': 1
|
||||||
'qwe': 2
|
'qwe': 2
|
||||||
'asd': 7
|
'asd': 7
|
||||||
|
Loading…
Reference in New Issue
Block a user