cgen: parallelize (#10844)
parent
a17b943e87
commit
85b58b03a3
|
@ -191,7 +191,7 @@ jobs:
|
|||
- name: v.c can be compiled and run with -os cross
|
||||
run: |
|
||||
./v -os cross -o /tmp/v.c cmd/v
|
||||
gcc -g -std=gnu11 -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
|
||||
./v_from_vc version
|
||||
|
||||
|
@ -235,7 +235,7 @@ jobs:
|
|||
- name: g++ version
|
||||
run: g++-9 --version
|
||||
- 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++
|
||||
## run: ./v -cc g++-9 -silent test-self
|
||||
|
||||
|
@ -323,7 +323,7 @@ jobs:
|
|||
- name: v.c can be compiled and run with -os cross
|
||||
run: |
|
||||
./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
|
||||
./v_from_vc version
|
||||
|
||||
|
@ -627,7 +627,7 @@ jobs:
|
|||
gcc --version
|
||||
.\make.bat -gcc
|
||||
- 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
|
||||
run: |
|
||||
.\v.exe setup-freetype
|
||||
|
@ -715,7 +715,7 @@ jobs:
|
|||
run: |
|
||||
.\make.bat -tcc --verbose
|
||||
- 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
|
||||
run: |
|
||||
.\v.exe setup-freetype
|
||||
|
@ -764,7 +764,7 @@ jobs:
|
|||
.\v.exe wipe-cache
|
||||
.\make.bat -tcc32 --verbose
|
||||
- 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
|
||||
run: ./v doctor
|
||||
|
||||
|
|
|
@ -64,14 +64,14 @@ jobs:
|
|||
- name: v.c can be compiled and run with -os cross
|
||||
run: |
|
||||
./v -os cross -o /tmp/v.c cmd/v
|
||||
gcc -g -std=gnu11 -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
|
||||
./v_from_vc version
|
||||
|
||||
- name: v_win.c can be compiled and run with -os windows
|
||||
run: |
|
||||
./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
|
||||
wine v_from_vc.exe version
|
||||
|
||||
|
|
|
@ -99,3 +99,5 @@ shell.nix
|
|||
default.nix
|
||||
flake.nix
|
||||
.envrc
|
||||
|
||||
thirdparty/stdatomic/nix/cpp/*.h
|
||||
|
|
|
@ -4,7 +4,7 @@ LABEL maintainer="Vitaly Takmazov <vitalyster@gmail.com>"
|
|||
COPY . .
|
||||
RUN make
|
||||
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
|
||||
|
||||
CMD [ "bash" ]
|
||||
|
|
2
Makefile
2
Makefile
|
@ -3,6 +3,6 @@ CC ?= cc
|
|||
all:
|
||||
rm -rf 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/
|
||||
@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\n')
|
||||
println('Fetching updates...')
|
||||
ret := os.system('$vdir/v up')
|
||||
if ret != 0 {
|
||||
println('failed to update V')
|
||||
return
|
||||
if !os.args.contains('-noupdate') {
|
||||
println('Fetching updates...')
|
||||
ret := os.system('$vdir/v up')
|
||||
if ret != 0 {
|
||||
println('failed to update V')
|
||||
return
|
||||
}
|
||||
}
|
||||
// Fetch the last commit's hash
|
||||
commit := exec('git rev-parse HEAD')[..8]
|
||||
|
@ -55,7 +57,6 @@ fn main() {
|
|||
} else {
|
||||
exec('./v -o vprod -prod -prealloc cmd/v')
|
||||
}
|
||||
// println('cur vdir="$vdir"')
|
||||
// cache vlib modules
|
||||
exec('$vdir/v wipe-cache')
|
||||
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_selfbuilding := ''
|
||||
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}'
|
||||
} 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}'
|
||||
}
|
||||
scripting.chdir(vgit_context.workdir)
|
||||
|
|
|
@ -8,6 +8,7 @@ import v.parser
|
|||
import v.ast
|
||||
import v.pref
|
||||
import v.errors
|
||||
import strings
|
||||
|
||||
struct Context {
|
||||
mut:
|
||||
|
@ -208,7 +209,7 @@ fn (t Tree) type_node(typ ast.Type) &Node {
|
|||
return create_null()
|
||||
} else {
|
||||
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 {
|
||||
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...'
|
||||
okmsg: 'v.c can be compiled without warnings. This is good :)'
|
||||
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.
|
||||
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
|
||||
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
|
||||
echo ^> Attempting to build v_win.c with TCC
|
||||
if !flag_verbose! EQU 1 (
|
||||
echo [Debug] "!tcc_exe!" -ladvapi32 -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 [Debug] "!tcc_exe!" -ladvapi32 -I .\thirdparty\stdatomic\win -bt10 -w -o v.exe vc\v_win.c>>"!log_file!"
|
||||
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
|
||||
|
||||
echo ^> Compiling with .\v.exe self
|
||||
|
@ -202,8 +202,8 @@ if %ERRORLEVEL% NEQ 0 (
|
|||
|
||||
echo ^> Attempting to build v_win.c with Clang
|
||||
if !flag_verbose! EQU 1 (
|
||||
echo [Debug] clang -std=c99 -municode -w -o v.exe .\vc\v_win.c>>"!log_File!"
|
||||
echo clang -std=c99 -municode -w -o v.exe .\vc\v_win.c
|
||||
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 -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!"
|
||||
if %ERRORLEVEL% NEQ 0 (
|
||||
|
@ -231,10 +231,10 @@ if %ERRORLEVEL% NEQ 0 (
|
|||
|
||||
echo ^> Attempting to build v_win.c with GCC
|
||||
if !flag_verbose! EQU 1 (
|
||||
echo [Debug] gcc -std=c99 -municode -w -o v.exe .\vc\v_win.c>>"!log_File!"
|
||||
echo gcc -std=c99 -municode -w -o v.exe .\vc\v_win.c
|
||||
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 -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 (
|
||||
REM In most cases, compile errors happen because the version of GCC installed is too old
|
||||
gcc --version>>"!log_File!"
|
||||
|
@ -279,8 +279,8 @@ set ObjFile=.v.c.obj
|
|||
|
||||
echo ^> Attempting to build v_win.c with MSVC
|
||||
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 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 [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% /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!"
|
||||
if %ERRORLEVEL% NEQ 0 (
|
||||
|
|
|
@ -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
|
||||
// for gcc/clang, too
|
||||
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) {
|
||||
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) {
|
||||
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) {
|
||||
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) {
|
||||
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) {
|
||||
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) {
|
||||
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) {
|
||||
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) {
|
||||
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) {
|
||||
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) {
|
||||
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) {
|
||||
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) {
|
||||
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) {
|
||||
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) {
|
||||
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) {
|
||||
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) {
|
||||
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) {
|
||||
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) {
|
||||
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) {
|
||||
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) {
|
||||
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) {
|
||||
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) {
|
||||
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) {
|
||||
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) {
|
||||
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) {
|
||||
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) {
|
||||
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) {
|
||||
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) {
|
||||
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) {
|
||||
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) {
|
||||
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) {
|
||||
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) {
|
||||
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) {
|
||||
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) {
|
||||
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) {
|
||||
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) {
|
||||
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) {
|
||||
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) {
|
||||
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) {
|
||||
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) {
|
||||
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) {
|
||||
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) {
|
||||
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) {
|
||||
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) {
|
||||
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) {
|
||||
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) {
|
||||
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) {
|
||||
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) {
|
||||
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) {
|
||||
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
|
||||
|
|
|
@ -30,7 +30,7 @@
|
|||
#ifndef _STDATOMIC_H_
|
||||
#define _STDATOMIC_H_
|
||||
#include <sys/cdefs.h>
|
||||
#if defined(__cplusplus) && defined(_USING_LIBCXX)
|
||||
#if defined(__cplusplus)
|
||||
#ifdef __clang__
|
||||
#if __has_feature(cxx_atomic)
|
||||
#define _STDATOMIC_HAVE_ATOMIC
|
||||
|
@ -42,8 +42,9 @@
|
|||
#endif
|
||||
#endif
|
||||
#ifdef _STDATOMIC_HAVE_ATOMIC
|
||||
/* We have a usable C++ <atomic>; use it instead. */
|
||||
#include <atomic>
|
||||
|
||||
#include "cpp/atomic.h"
|
||||
|
||||
#undef _Atomic
|
||||
/* Also defined by <atomic> for gcc. But not used in macros. */
|
||||
/* Also a clang intrinsic. */
|
||||
|
|
|
@ -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
|
||||
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 }
|
||||
unsafe {
|
||||
subscr[i].nxt = C.atomic_exchange_ptr(&voidptr(&ch.write_subscriber),
|
||||
&subscr[i])
|
||||
subscr[i].nxt = &Subscription(C.atomic_exchange_ptr(&voidptr(&ch.write_subscriber),
|
||||
&subscr[i]))
|
||||
}
|
||||
if voidptr(subscr[i].nxt) != voidptr(0) {
|
||||
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 }
|
||||
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) {
|
||||
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_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.
|
||||
[heap]
|
||||
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() {
|
||||
// same type -> already casted to the interface
|
||||
return true
|
||||
|
|
|
@ -556,7 +556,7 @@ pub enum Kind {
|
|||
thread
|
||||
}
|
||||
|
||||
pub fn (t &TypeSymbol) str() string {
|
||||
pub fn (t TypeSymbol) str() string {
|
||||
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() {
|
||||
// reserve index 0 so nothing can go there
|
||||
// save index check, 0 will mean not found
|
||||
|
|
|
@ -550,6 +550,18 @@ fn (mut v Builder) cc() {
|
|||
v.setup_ccompiler_options(ccompiler)
|
||||
v.build_thirdparty_obj_files()
|
||||
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
|
||||
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)
|
||||
c.fail_if_unreadable(expr.left, expr.left_type, what)
|
||||
}
|
||||
else {}
|
||||
else {
|
||||
pos = expr.position()
|
||||
}
|
||||
}
|
||||
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',
|
||||
|
|
|
@ -226,7 +226,15 @@ pub fn (mut f Fmt) short_module(name string) string {
|
|||
idx := vals.len - 1
|
||||
mname, tprefix := f.get_modname_prefix(vals[..idx].join('.'))
|
||||
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 == '' {
|
||||
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`
|
||||
if node.args.len == 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)
|
||||
return
|
||||
}
|
||||
|
@ -273,7 +275,9 @@ fn (mut g Gen) gen_array_sort(node ast.CallExpr) {
|
|||
if is_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)
|
||||
return
|
||||
}
|
||||
|
@ -300,8 +304,9 @@ fn (mut g Gen) gen_array_sort(node ast.CallExpr) {
|
|||
|
||||
// Register a new custom `compare_xxx` function for qsort()
|
||||
// TODO: move to checker
|
||||
g.table.register_fn(name: compare_fn, return_type: ast.int_type)
|
||||
g.array_sort_fn[compare_fn] = true
|
||||
lock g.array_sort_fn {
|
||||
g.array_sort_fn << compare_fn
|
||||
}
|
||||
|
||||
stype_arg := g.typ(info.elem_type)
|
||||
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 {
|
||||
mut unwrap_left_type := g.unwrap_generic(left_type)
|
||||
if unwrap_left_type.share() == .shared_t {
|
||||
unwrap_left_type = unwrap_left_type.clear_flag(.shared_f)
|
||||
}
|
||||
mut left_sym := g.table.get_type_symbol(unwrap_left_type)
|
||||
left_final_sym := g.table.get_final_type_symbol(unwrap_left_type)
|
||||
mut left_type_str := g.typ(unwrap_left_type).replace('*', '')
|
||||
fn_name := '${left_type_str}_contains'
|
||||
if !left_sym.has_method('contains') {
|
||||
fn (mut g Gen) get_array_contains_method(typ ast.Type) string {
|
||||
t := g.table.get_final_type_symbol(g.unwrap_generic(typ).set_nr_muls(0)).idx
|
||||
g.array_contains_types << t
|
||||
return g.typ(t) + '_contains'
|
||||
}
|
||||
|
||||
fn (mut g Gen) gen_array_contains_methods() {
|
||||
mut done := []ast.Type{}
|
||||
for t in g.array_contains_types {
|
||||
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
|
||||
mut elem_type_str := g.typ(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 {
|
||||
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 {
|
||||
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)) {')
|
||||
} else if elem_sym.kind == .function {
|
||||
fn_builder.writeln('\t\tif (((voidptr*)a.data)[i] == v) {')
|
||||
} 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)) {')
|
||||
} 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)) {')
|
||||
} else {
|
||||
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('}')
|
||||
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)`
|
||||
fn (mut g Gen) gen_array_contains(node ast.CallExpr) {
|
||||
fn_name := g.gen_array_contains_method(node.left_type)
|
||||
fn (mut g Gen) gen_array_contains(typ ast.Type, left ast.Expr, right ast.Expr) {
|
||||
fn_name := g.get_array_contains_method(typ)
|
||||
g.write('${fn_name}(')
|
||||
if node.left_type.is_ptr() && node.left_type.share() != .shared_t {
|
||||
g.write('*')
|
||||
g.write(strings.repeat(`*`, typ.nr_muls()))
|
||||
if typ.share() == .shared_t {
|
||||
g.out.go_back(1)
|
||||
}
|
||||
g.expr(node.left)
|
||||
if node.left_type.share() == .shared_t {
|
||||
g.expr(left)
|
||||
if typ.share() == .shared_t {
|
||||
g.write('->val')
|
||||
}
|
||||
g.write(', ')
|
||||
g.expr(node.args[0].expr)
|
||||
g.expr(right)
|
||||
g.write(')')
|
||||
}
|
||||
|
||||
fn (mut g Gen) gen_array_index_method(left_type ast.Type) string {
|
||||
unwrap_left_type := g.unwrap_generic(left_type)
|
||||
mut left_sym := g.table.get_type_symbol(unwrap_left_type)
|
||||
mut left_type_str := g.typ(unwrap_left_type).trim('*')
|
||||
fn_name := '${left_type_str}_index'
|
||||
if !left_sym.has_method('index') {
|
||||
info := left_sym.info as ast.Array
|
||||
fn (mut g Gen) get_array_index_method(typ ast.Type) string {
|
||||
t := g.unwrap_generic(typ).set_nr_muls(0)
|
||||
g.array_index_types << t
|
||||
return g.typ(t) + '_index'
|
||||
}
|
||||
|
||||
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)
|
||||
elem_sym := g.table.get_type_symbol(info.elem_type)
|
||||
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 {
|
||||
fn_builder.writeln('\t\tif (fast_string_eq(*pelem, v)) {')
|
||||
} 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)) {')
|
||||
} else if elem_sym.kind == .function && !info.elem_type.is_ptr() {
|
||||
fn_builder.writeln('\t\tif ( pelem == v) {')
|
||||
} 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))) {')
|
||||
} 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)) {')
|
||||
} else {
|
||||
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('}')
|
||||
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)`
|
||||
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}(')
|
||||
if node.left_type.is_ptr() {
|
||||
g.write('*')
|
||||
|
|
|
@ -20,7 +20,7 @@ fn (mut g Gen) gen_assert_stmt(original_assert_statement ast.AssertStmt) {
|
|||
}
|
||||
}
|
||||
g.inside_ternary++
|
||||
if g.is_test {
|
||||
if g.pref.is_test {
|
||||
g.write('if (')
|
||||
g.expr(node.expr)
|
||||
g.write(')')
|
||||
|
|
|
@ -5,13 +5,52 @@ module c
|
|||
import strings
|
||||
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 {
|
||||
left := g.unwrap(left_type)
|
||||
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
|
||||
}
|
||||
g.sumtype_fn_definitions << ptr_styp
|
||||
g.generated_eq_fns << left_type
|
||||
|
||||
info := left.sym.sumtype_info()
|
||||
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)
|
||||
ptr_styp := g.typ(left.typ.set_nr_muls(0))
|
||||
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
|
||||
}
|
||||
g.struct_fn_definitions << fn_name
|
||||
g.generated_eq_fns << left_type
|
||||
info := left.sym.struct_info()
|
||||
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 {
|
||||
left := g.unwrap(left_type)
|
||||
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
|
||||
}
|
||||
g.alias_fn_definitions << ptr_styp
|
||||
g.generated_eq_fns << left_type
|
||||
info := left.sym.info as ast.Alias
|
||||
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 {
|
||||
left := g.unwrap(left_type)
|
||||
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
|
||||
}
|
||||
g.array_fn_definitions << ptr_styp
|
||||
g.generated_eq_fns << left_type
|
||||
elem := g.unwrap(left.sym.array_info().elem_type)
|
||||
ptr_elem_styp := g.typ(elem.typ)
|
||||
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 {
|
||||
left := g.unwrap(left_type)
|
||||
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
|
||||
}
|
||||
g.array_fn_definitions << ptr_styp
|
||||
g.generated_eq_fns << left_type
|
||||
elem_info := left.sym.array_fixed_info()
|
||||
elem := g.unwrap(elem_info.elem_type)
|
||||
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 {
|
||||
left := g.unwrap(left_type)
|
||||
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
|
||||
}
|
||||
g.map_fn_definitions << ptr_styp
|
||||
g.generated_eq_fns << left_type
|
||||
value := g.unwrap(left.sym.map_info().value_type)
|
||||
ptr_value_styp := g.typ(value.typ)
|
||||
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('}')
|
||||
}
|
||||
|
||||
fn (mut g Gen) gen_str_method_for_type(typ ast.Type) string {
|
||||
styp := g.typ(typ).replace('*', '')
|
||||
mut sym := g.table.get_type_symbol(g.unwrap_generic(typ))
|
||||
struct StrType {
|
||||
styp string
|
||||
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)
|
||||
if mut sym.info is ast.Alias {
|
||||
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)
|
||||
}
|
||||
}
|
||||
sym_has_str_method, str_method_expects_ptr, str_nr_args := sym.str_method_info()
|
||||
already_generated_key := '$styp:$str_fn_name'
|
||||
if !sym_has_str_method && already_generated_key !in g.str_types && !typ.has_flag(.optional) {
|
||||
$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
|
||||
g.str_types << StrType{
|
||||
typ: unwrapped
|
||||
styp: styp
|
||||
}
|
||||
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) {
|
||||
parent_type := typ.clear_flag(.optional)
|
||||
sym := g.table.get_type_symbol(parent_type)
|
||||
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.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) {
|
||||
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('__', '.'))
|
||||
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); }')
|
||||
|
@ -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)
|
||||
is_arg_ptr := typ.is_ptr()
|
||||
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 {
|
||||
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 */')
|
||||
for typ in info.types {
|
||||
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()
|
||||
if should_use_indent_func(subtype.kind) && !sym_has_str_method {
|
||||
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) {')
|
||||
for typ in info.variants {
|
||||
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_has_str_method, str_method_expects_ptr, _ := sym.str_method_info()
|
||||
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)
|
||||
is_elem_ptr := typ.is_ptr()
|
||||
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 {
|
||||
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()
|
||||
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.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_str_fn_name := key_styp.replace('*', '') + '_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
|
||||
|
@ -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)
|
||||
elem_str_fn_name := val_styp.replace('*', '') + '_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')
|
||||
|
@ -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}_str'
|
||||
} 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
|
||||
|
|
|
@ -11,6 +11,7 @@ import v.token
|
|||
import v.util
|
||||
import v.util.version
|
||||
import v.depgraph
|
||||
import sync.pool
|
||||
|
||||
const (
|
||||
// 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 {
|
||||
pref &pref.Preferences
|
||||
module_built string
|
||||
field_data_type ast.Type // cache her to avoid map lookups
|
||||
pref &pref.Preferences
|
||||
field_data_type ast.Type // cache her to avoid map lookups
|
||||
module_built string
|
||||
timers_should_print bool
|
||||
table &ast.Table
|
||||
mut:
|
||||
table &ast.Table
|
||||
out strings.Builder
|
||||
cheaders strings.Builder
|
||||
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)
|
||||
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_init strings.Builder // thread local of the above
|
||||
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(){}`
|
||||
gowrappers strings.Builder // all go callsite wrappers
|
||||
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_functions strings.Builder // shared constructors
|
||||
channel_definitions strings.Builder // channel related code
|
||||
options_typedefs strings.Builder // Option typedefs
|
||||
options strings.Builder // `Option_xxxx` types
|
||||
json_forward_decls strings.Builder // json type forward decls
|
||||
enum_typedefs strings.Builder // enum types
|
||||
|
@ -70,32 +74,33 @@ mut:
|
|||
file &ast.File
|
||||
fn_decl &ast.FnDecl // pointer to the FnDecl we are currently inside otherwise 0
|
||||
last_fn_c_name string
|
||||
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_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
|
||||
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
|
||||
is_void_expr_stmt bool // ExprStmt whos result is discarded
|
||||
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_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_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)
|
||||
arraymap_set_pos int // map or array set value position
|
||||
vlines_path string // set to the proper path for generating #line directives
|
||||
optionals []string // to avoid duplicates TODO perf, use map
|
||||
chan_pop_optionals []string // types for `x := <-ch or {...}`
|
||||
chan_push_optionals []string // types for `ch <- x or {...}`
|
||||
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_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
|
||||
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
|
||||
is_void_expr_stmt bool // ExprStmt whos result is discarded
|
||||
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_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_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)
|
||||
arraymap_set_pos int // map or array set value position
|
||||
vlines_path string // set to the proper path for generating #line directives
|
||||
optionals map[string]string // to avoid duplicates
|
||||
done_optionals shared []string // to avoid duplicates
|
||||
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
|
||||
mtxs string // array of mutexes if the `lock` has multiple variables
|
||||
labeled_loops map[string]&ast.Stmt
|
||||
inner_loop &ast.Stmt
|
||||
shareds []int // types with hidden mutex for which decl has been emitted
|
||||
inside_ternary int // ?: comma separated statements on a single line
|
||||
inside_map_postfix bool // inside map++/-- postfix expr
|
||||
inside_map_infix bool // inside map<</+=/-= infix expr
|
||||
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_map_postfix bool // inside map++/-- postfix expr
|
||||
inside_map_infix bool // inside map<</+=/-= infix expr
|
||||
inside_map_index bool
|
||||
inside_opt_data 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
|
||||
indent int
|
||||
empty_line bool
|
||||
is_test bool
|
||||
assign_op token.Kind // *=, =, etc (for array_set)
|
||||
defer_stmts []ast.DeferStmt
|
||||
defer_ifdef string
|
||||
defer_profile_code string
|
||||
str_types []string // types that need automatic str() generation
|
||||
threaded_fns []string // for generating unique wrapper types and fns for `go xxx()`
|
||||
waiter_fns []string // functions that wait for `go xxx()` to finish
|
||||
array_fn_definitions []string // array equality functions that have been defined
|
||||
map_fn_definitions []string // map equality functions that have been defined
|
||||
struct_fn_definitions []string // struct equality functions that have been defined
|
||||
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
|
||||
str_types []StrType // types that need automatic str() generation
|
||||
generated_str_fns []StrType // types that already have a str() function
|
||||
threaded_fns []string // for generating unique wrapper types and fns for `go xxx()`
|
||||
waiter_fns []string // functions that wait for `go xxx()` to finish
|
||||
auto_fn_definitions []string // auto generated functions defination list
|
||||
sumtype_casting_fns []SumtypeCastingFn
|
||||
anon_fn_definitions []string // anon generated functions defination list
|
||||
sumtype_definitions map[int]bool // `_TypeA_to_sumtype_TypeB()` fns that have been generated
|
||||
is_json_fn bool // inside json.encode()
|
||||
json_types []string // to avoid json gen duplicates
|
||||
is_json_fn bool // inside json.encode()
|
||||
json_types []ast.Type // to avoid json gen duplicates
|
||||
pcs []ProfileCounterMeta // -prof profile counter fn_names => fn counter name
|
||||
is_builtin_mod bool
|
||||
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)
|
||||
obf_table map[string]string
|
||||
// main_fn_decl_node ast.FnDecl
|
||||
expected_cast_type ast.Type // for match expr of sumtypes
|
||||
defer_vars []string
|
||||
anon_fn bool
|
||||
array_sort_fn map[string]bool
|
||||
nr_closures int
|
||||
nr_closures int
|
||||
array_sort_fn shared []string
|
||||
expected_cast_type ast.Type // for match expr of sumtypes
|
||||
defer_vars []string
|
||||
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 {
|
||||
|
@ -200,7 +208,7 @@ pub fn gen(files []&ast.File, table &ast.Table, pref &pref.Preferences) string {
|
|||
$if time_cgening ? {
|
||||
timers_should_print = true
|
||||
}
|
||||
mut g := Gen{
|
||||
mut global_g := Gen{
|
||||
file: 0
|
||||
out: strings.new_builder(512000)
|
||||
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)
|
||||
hotcode_definitions: strings.new_builder(100)
|
||||
embedded_data: strings.new_builder(1000)
|
||||
options_typedefs: strings.new_builder(100)
|
||||
options: strings.new_builder(100)
|
||||
shared_types: 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
|
||||
pref: pref
|
||||
fn_decl: 0
|
||||
is_autofree: true
|
||||
is_autofree: pref.autofree
|
||||
indent: -1
|
||||
module_built: module_built
|
||||
timers_should_print: timers_should_print
|
||||
timers: util.new_timers(timers_should_print)
|
||||
inner_loop: &ast.EmptyStmt{}
|
||||
field_data_type: ast.Type(table.find_type_idx('FieldData'))
|
||||
init: strings.new_builder(100)
|
||||
}
|
||||
g.timers.start('cgen init')
|
||||
for mod in g.table.modules {
|
||||
g.inits[mod] = strings.new_builder(100)
|
||||
g.global_inits[mod] = strings.new_builder(100)
|
||||
g.cleanups[mod] = strings.new_builder(100)
|
||||
// anon fn may include assert and thus this needs
|
||||
// to be included before any test contents are written
|
||||
if pref.is_test {
|
||||
global_g.write_tests_definitions()
|
||||
}
|
||||
g.init()
|
||||
g.timers.show('cgen init')
|
||||
mut tests_inited := false
|
||||
mut autofree_used := false
|
||||
for file in files {
|
||||
g.timers.start('cgen_file $file.path')
|
||||
g.file = file
|
||||
if g.pref.is_vlines {
|
||||
g.vlines_path = util.vlines_escape_path(file.path, g.pref.ccompiler)
|
||||
}
|
||||
// println('\ncgen "$g.file.path" nr_stmts=$file.stmts.len')
|
||||
// building_v := true && (g.file.path.contains('/vlib/') || g.file.path.contains('cmd/v'))
|
||||
g.is_test = g.pref.is_test
|
||||
if g.file.path == '' || !g.pref.autofree {
|
||||
// cgen test or building V
|
||||
// println('autofree=false')
|
||||
g.is_autofree = false
|
||||
} else {
|
||||
g.is_autofree = true
|
||||
autofree_used = true
|
||||
}
|
||||
// anon fn may include assert and thus this needs
|
||||
// to be included before any test contents are written
|
||||
if g.is_test && !tests_inited {
|
||||
g.write_tests_definitions()
|
||||
tests_inited = true
|
||||
}
|
||||
g.stmts(file.stmts)
|
||||
// Transfer embedded files
|
||||
if file.embedded_files.len > 0 {
|
||||
for path in file.embedded_files {
|
||||
if path !in g.embedded_files {
|
||||
g.embedded_files << path
|
||||
|
||||
global_g.timers.start('cgen init')
|
||||
for mod in global_g.table.modules {
|
||||
global_g.inits[mod] = strings.new_builder(200)
|
||||
global_g.global_inits[mod] = strings.new_builder(100)
|
||||
global_g.cleanups[mod] = strings.new_builder(100)
|
||||
}
|
||||
global_g.init()
|
||||
global_g.timers.show('cgen init')
|
||||
global_g.tests_inited = false
|
||||
if !pref.no_parallel {
|
||||
mut pp := pool.new_pool_processor(
|
||||
callback: fn (p &pool.PoolProcessor, idx int, wid int) &Gen {
|
||||
file := p.get_item<&ast.File>(idx)
|
||||
mut global_g := &Gen(p.get_shared_context())
|
||||
mut g := &Gen{
|
||||
file: file
|
||||
out: strings.new_builder(512000)
|
||||
cheaders: strings.new_builder(15000)
|
||||
includes: strings.new_builder(100)
|
||||
typedefs: strings.new_builder(100)
|
||||
typedefs2: strings.new_builder(100)
|
||||
type_definitions: strings.new_builder(100)
|
||||
definitions: strings.new_builder(100)
|
||||
gowrappers: strings.new_builder(100)
|
||||
stringliterals: strings.new_builder(100)
|
||||
auto_str_funcs: strings.new_builder(100)
|
||||
comptime_defines: strings.new_builder(100)
|
||||
pcs_declarations: strings.new_builder(100)
|
||||
hotcode_definitions: strings.new_builder(100)
|
||||
embedded_data: strings.new_builder(1000)
|
||||
options: strings.new_builder(100)
|
||||
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')
|
||||
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
|
||||
if g.pref.build_mode == .build_module {
|
||||
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
|
||||
g.gen_vlines_reset()
|
||||
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.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 {
|
||||
b.writeln('\n// V shared type functions:')
|
||||
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()
|
||||
}
|
||||
|
||||
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 {
|
||||
mut res := c_commit_hash_default.replace('@@@', version.vhash())
|
||||
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() {
|
||||
|
@ -610,20 +756,16 @@ pub fn (mut g Gen) write_typeof_functions() {
|
|||
|
||||
// V type to C typecc
|
||||
fn (mut g Gen) typ(t ast.Type) string {
|
||||
styp := g.base_type(t)
|
||||
if t.has_flag(.optional) {
|
||||
// Register an optional if it's not registered yet
|
||||
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 {
|
||||
// todo compile time if for perf?
|
||||
if t == ast.f32_type {
|
||||
|
@ -692,7 +834,7 @@ fn (mut g Gen) optional_type_name(t ast.Type) (string, string) {
|
|||
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
|
||||
size := if base == 'void' { 'byte' } else { base }
|
||||
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 {
|
||||
styp, base := g.optional_type_name(t)
|
||||
if styp !in g.optionals {
|
||||
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()
|
||||
}
|
||||
g.optionals[base] = styp
|
||||
return styp
|
||||
}
|
||||
|
||||
fn (mut g Gen) find_or_register_shared(t ast.Type, base string) string {
|
||||
sh_typ := '__shared__$base'
|
||||
t_idx := t.idx()
|
||||
if t_idx in g.shareds {
|
||||
return sh_typ
|
||||
fn (mut g Gen) write_optionals() {
|
||||
mut done := g.done_optionals.clone()
|
||||
for base, styp in g.optionals {
|
||||
if base in done {
|
||||
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 {
|
||||
|
@ -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) {
|
||||
if opt_el_type !in g.chan_pop_optionals {
|
||||
g.chan_pop_optionals << opt_el_type
|
||||
g.chan_pop_optionals[opt_el_type] = styp
|
||||
}
|
||||
|
||||
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('
|
||||
static inline $opt_el_type __Option_${styp}_popval($styp ch) {
|
||||
$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) {
|
||||
if styp !in g.chan_push_optionals {
|
||||
g.chan_push_optionals << styp
|
||||
fn (mut g Gen) register_chan_push_optional_fn(el_type string, styp string) {
|
||||
g.chan_push_optionals[styp] = el_type
|
||||
}
|
||||
|
||||
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.channel_definitions.writeln('
|
||||
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)
|
||||
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()
|
||||
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] {
|
||||
return
|
||||
return fn_name
|
||||
}
|
||||
g.sumtype_definitions[i] = true
|
||||
got_sym := g.table.get_type_symbol(got)
|
||||
exp_sym := g.table.get_type_symbol(exp)
|
||||
mut sb := strings.new_builder(128)
|
||||
g.sumtype_casting_fns << SumtypeCastingFn{
|
||||
fn_name: fn_name
|
||||
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
|
||||
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));')
|
||||
for embed_hierarchy in g.table.get_embeds(got_sym) {
|
||||
// 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) {
|
||||
got_type := g.table.mktyp(got_type_raw)
|
||||
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()
|
||||
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
|
||||
// TODO: temporary to allow people to migrate their code; remove soon
|
||||
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.expr(expr)
|
||||
} 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'
|
||||
g.call_cfn_for_casting_expr(fname, expr, expected_is_ptr, unwrapped_exp_sym.cname,
|
||||
got_is_ptr, got_styp)
|
||||
|
@ -2916,7 +3103,7 @@ fn (mut g Gen) gen_assign_stmt(assign_stmt ast.AssignStmt) {
|
|||
}
|
||||
mut cloned := false
|
||||
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
|
||||
}
|
||||
}
|
||||
|
@ -3092,28 +3279,38 @@ fn (mut g Gen) get_ternary_name(name string) string {
|
|||
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 {
|
||||
return false
|
||||
}
|
||||
if g.is_autofree && right_sym.kind == .array {
|
||||
// `arr1 = arr2` => `arr1 = arr2.clone()`
|
||||
right_sym := g.table.get_type_symbol(typ)
|
||||
if g.is_autofree {
|
||||
if add_eq {
|
||||
g.write('=')
|
||||
}
|
||||
g.write(' array_clone_static_to_depth(')
|
||||
g.expr(val)
|
||||
elem_type := (right_sym.info as ast.Array).elem_type
|
||||
array_depth := g.get_array_depth(elem_type)
|
||||
g.write(', $array_depth)')
|
||||
} else if g.is_autofree && right_sym.kind == .string {
|
||||
if add_eq {
|
||||
g.write('=')
|
||||
if right_sym.kind == .array {
|
||||
// `arr1 = arr2` => `arr1 = arr2.clone()`
|
||||
shared_styp := g.typ(typ.set_nr_muls(0))
|
||||
if typ.share() == .shared_t {
|
||||
g.write('($shared_styp*)__dup_shared_array(&($shared_styp){.mtx = {0}, .val =')
|
||||
}
|
||||
g.write(' array_clone_static_to_depth(')
|
||||
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
|
||||
}
|
||||
|
@ -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 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) {
|
||||
g.trace_autofree('// af parent scope:')
|
||||
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}')
|
||||
}
|
||||
// }
|
||||
free_fn := g.typ(v.typ.set_nr_muls(0)) + '_free'
|
||||
if sym.kind == .array {
|
||||
if sym.has_method('free') {
|
||||
free_method_name := g.typ(v.typ) + '_free'
|
||||
g.autofree_var_call(free_method_name, v)
|
||||
g.autofree_var_call(free_fn, v)
|
||||
return
|
||||
}
|
||||
g.autofree_var_call('array_free', v)
|
||||
|
@ -3251,7 +3448,7 @@ fn (mut g Gen) autofree_variable(v ast.Var) {
|
|||
return
|
||||
}
|
||||
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() {
|
||||
// Free user reference types
|
||||
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
|
||||
}
|
||||
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 {
|
||||
if v.typ == ast.error_type && !v.is_autofree_tmp {
|
||||
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 {
|
||||
.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.expr(expr)
|
||||
g.write(')')
|
||||
}
|
||||
.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.expr(expr)
|
||||
g.write(')')
|
||||
}
|
||||
.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.expr(expr)
|
||||
g.write(')')
|
||||
|
@ -4206,7 +4419,7 @@ fn (mut g Gen) match_expr_classic(node ast.MatchExpr, is_expr bool, cond_var str
|
|||
g.write(')')
|
||||
}
|
||||
.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.expr(expr)
|
||||
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,
|
||||
// so fall back to the delayed initialisation scheme:
|
||||
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 {
|
||||
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')
|
||||
if cname == '_const_os__args' {
|
||||
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 {
|
||||
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 {
|
||||
if unwrap_option {
|
||||
g.inits[mod].writeln(g.expr_string_surround('\t$cname = *($styp*)', expr,
|
||||
'.data;'))
|
||||
g.init.writeln(g.expr_string_surround('\t$cname = *($styp*)', expr, '.data;'))
|
||||
} 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 {
|
||||
sym := g.table.get_type_symbol(typ)
|
||||
if styp.starts_with('Array_') {
|
||||
g.cleanups[mod].writeln('\tarray_free(&$cname);')
|
||||
g.cleanup.writeln('\tarray_free(&$cname);')
|
||||
} else if styp == 'string' {
|
||||
g.cleanups[mod].writeln('\tstring_free(&$cname);')
|
||||
g.cleanup.writeln('\tstring_free(&$cname);')
|
||||
} else if sym.kind == .map {
|
||||
g.cleanups[mod].writeln('\tmap_free(&$cname);')
|
||||
g.cleanup.writeln('\tmap_free(&$cname);')
|
||||
} 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) {
|
||||
mod := if g.pref.build_mode == .build_module && g.is_builtin_mod { 'static ' } else { '' }
|
||||
key := node.mod // module name
|
||||
for field in node.fields {
|
||||
if g.pref.skip_unused {
|
||||
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')
|
||||
} else {
|
||||
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 {
|
||||
default_initializer := g.type_default(field.typ)
|
||||
|
@ -5323,7 +5534,7 @@ fn (mut g Gen) global_decl(node ast.GlobalDecl) {
|
|||
} else {
|
||||
g.definitions.writeln('$mod$styp $field.name; // global')
|
||||
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
|
||||
if g.is_autofree && !field.typ.is_ptr() && field_type_sym.kind in [.array, .string] {
|
||||
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
|
||||
}
|
||||
}
|
||||
|
@ -5498,7 +5709,7 @@ fn (mut g Gen) struct_init(struct_init ast.StructInit) {
|
|||
mut cloned := false
|
||||
if g.is_autofree && !sfield.typ.is_ptr() && field_type_sym.kind in [.array, .string] {
|
||||
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
|
||||
}
|
||||
}
|
||||
|
@ -5664,8 +5875,11 @@ fn (mut g Gen) write_init_function() {
|
|||
return
|
||||
}
|
||||
fn_vinit_start_pos := g.out.len
|
||||
|
||||
// ___argv is declared as voidptr here, because that unifies the windows/unix logic
|
||||
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 {
|
||||
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
|
||||
// buffer manip out in front of the struct
|
||||
// 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) {
|
||||
// Dont use g.typ() here becuase it will register
|
||||
// optional and we dont want that
|
||||
styp, base := g.optional_type_name(field.typ)
|
||||
if styp !in g.optionals {
|
||||
last_text := g.type_definitions.cut_to(start_pos).clone()
|
||||
g.optionals << styp
|
||||
g.typedefs2.writeln('typedef struct $styp $styp;')
|
||||
g.type_definitions.writeln('${g.optional_type_text(styp,
|
||||
base)};')
|
||||
g.type_definitions.write_string(last_text)
|
||||
lock g.done_optionals {
|
||||
if base !in g.done_optionals {
|
||||
g.done_optionals << base
|
||||
last_text := g.type_definitions.after(start_pos).clone()
|
||||
g.type_definitions.go_back_to(start_pos)
|
||||
g.typedefs2.writeln('typedef struct $styp $styp;')
|
||||
g.type_definitions.writeln('${g.optional_type_text(styp,
|
||||
base)};')
|
||||
g.type_definitions.write_string(last_text)
|
||||
}
|
||||
}
|
||||
}
|
||||
type_name := g.typ(field.typ)
|
||||
|
|
|
@ -23,14 +23,14 @@ const c_current_commit_hash_default = '
|
|||
|
||||
const c_concurrency_helpers = '
|
||||
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) {
|
||||
__shared_map* dest = memdup(src, sz);
|
||||
sync__RwMutex_init(&dest->mtx);
|
||||
return dest;
|
||||
}
|
||||
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) {
|
||||
__shared_array* dest = memdup(src, sz);
|
||||
sync__RwMutex_init(&dest->mtx);
|
||||
|
@ -451,6 +451,7 @@ voidptr memdup(voidptr src, int sz);
|
|||
|
||||
#include <io.h> // _waccess
|
||||
#include <direct.h> // _wgetcwd
|
||||
#include <signal.h> // signal and SIGSEGV for segmentation fault handler
|
||||
|
||||
#ifdef _MSC_VER
|
||||
// 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
|
||||
|
||||
is_sokol := 'sokol' in g.table.imports
|
||||
|
||||
if (g.pref.os == .android && g.pref.is_apk) || (g.pref.os == .ios && is_sokol) {
|
||||
g.gen_c_android_sokol_main()
|
||||
} 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'
|
||||
exp_type = g.comptime_var_type_map[name]
|
||||
} else if left is ast.TypeNode {
|
||||
name = left.str()
|
||||
// this is only allowed for generics currently, otherwise blocked by checker
|
||||
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_fns := strings.new_builder(100)
|
||||
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()
|
||||
ptr_asterisk := if is_ptr { '*' } else { '' }
|
||||
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') {
|
||||
// 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
|
||||
for concrete_types in g.table.fn_generic_types[node.name] {
|
||||
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(', ')
|
||||
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.table.cur_concrete_types = []
|
||||
g.cur_concrete_types = []
|
||||
return
|
||||
}
|
||||
cur_fn_save := g.table.cur_fn
|
||||
cur_fn_save := g.cur_fn
|
||||
defer {
|
||||
g.table.cur_fn = cur_fn_save
|
||||
g.cur_fn = cur_fn_save
|
||||
}
|
||||
unsafe {
|
||||
// TODO remove unsafe
|
||||
g.table.cur_fn = node
|
||||
g.cur_fn = node
|
||||
}
|
||||
fn_start_pos := g.out.len
|
||||
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)
|
||||
|
||||
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
|
||||
&& 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)
|
||||
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
|
||||
g.definitions.writeln(');') // // NO BODY')
|
||||
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)
|
||||
}
|
||||
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)
|
||||
} else { // in non-generic fn
|
||||
sym := g.table.get_type_symbol(node.receiver_type)
|
||||
match sym.info {
|
||||
ast.Struct, ast.Interface, ast.SumType {
|
||||
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)
|
||||
{
|
||||
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) {
|
||||
// Speaker_name_table[s._interface_idx].speak(s._object)
|
||||
$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.expr(node.left)
|
||||
|
@ -712,7 +714,7 @@ fn (mut g Gen) method_call(node ast.CallExpr) {
|
|||
return
|
||||
}
|
||||
'contains' {
|
||||
g.gen_array_contains(node)
|
||||
g.gen_array_contains(node.left_type, node.left, node.args[0].expr)
|
||||
return
|
||||
}
|
||||
'index' {
|
||||
|
@ -795,7 +797,7 @@ fn (mut g Gen) method_call(node ast.CallExpr) {
|
|||
if rec_type.has_flag(.shared_f) {
|
||||
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' {
|
||||
mut rec_type := node.receiver_type
|
||||
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
|
||||
if varg_type.has_flag(.generic) {
|
||||
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)
|
||||
{
|
||||
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)
|
||||
}
|
||||
if node.left_type.has_flag(.shared_f) {
|
||||
if left_is_ptr {
|
||||
g.write('->val')
|
||||
} else {
|
||||
g.write('.val')
|
||||
}
|
||||
g.write('->val')
|
||||
}
|
||||
g.write(', &($key_type_str[]){')
|
||||
g.expr(node.index)
|
||||
|
@ -374,10 +370,13 @@ fn (mut g Gen) index_of_map(node ast.IndexExpr, sym ast.TypeSymbol) {
|
|||
} else {
|
||||
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.expr(node.left)
|
||||
if node.left_type.has_flag(.shared_f) {
|
||||
g.write('->val')
|
||||
}
|
||||
g.write(', &($key_type_str[]){')
|
||||
g.expr(node.index)
|
||||
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 { '' }
|
||||
if gen_or {
|
||||
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(')
|
||||
} else {
|
||||
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] {
|
||||
match left.sym.kind {
|
||||
.alias {
|
||||
ptr_typ := g.gen_alias_equality_fn(left.typ)
|
||||
ptr_typ := g.equality_fn(left.typ)
|
||||
if node.op == .ne {
|
||||
g.write('!')
|
||||
}
|
||||
|
@ -131,7 +131,7 @@ fn (mut g Gen) infix_expr_eq_op(node ast.InfixExpr) {
|
|||
g.write(')')
|
||||
}
|
||||
.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 {
|
||||
g.write('!')
|
||||
}
|
||||
|
@ -141,11 +141,7 @@ fn (mut g Gen) infix_expr_eq_op(node ast.InfixExpr) {
|
|||
}
|
||||
g.expr(node.left)
|
||||
if left.typ.has_flag(.shared_f) {
|
||||
if left.typ.is_ptr() {
|
||||
g.write('->val')
|
||||
} else {
|
||||
g.write('.val')
|
||||
}
|
||||
g.write('->val')
|
||||
}
|
||||
g.write(', ')
|
||||
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)
|
||||
if right.typ.has_flag(.shared_f) {
|
||||
if right.typ.is_ptr() {
|
||||
g.write('->val')
|
||||
} else {
|
||||
g.write('.val')
|
||||
}
|
||||
g.write('->val')
|
||||
}
|
||||
g.write(')')
|
||||
}
|
||||
.array_fixed {
|
||||
ptr_typ := g.gen_fixed_array_equality_fn(left.unaliased)
|
||||
ptr_typ := g.equality_fn(left.unaliased)
|
||||
if node.op == .ne {
|
||||
g.write('!')
|
||||
}
|
||||
|
@ -184,7 +176,7 @@ fn (mut g Gen) infix_expr_eq_op(node ast.InfixExpr) {
|
|||
g.write(')')
|
||||
}
|
||||
.map {
|
||||
ptr_typ := g.gen_map_equality_fn(left.unaliased)
|
||||
ptr_typ := g.equality_fn(left.unaliased)
|
||||
if node.op == .ne {
|
||||
g.write('!')
|
||||
}
|
||||
|
@ -201,7 +193,7 @@ fn (mut g Gen) infix_expr_eq_op(node ast.InfixExpr) {
|
|||
g.write(')')
|
||||
}
|
||||
.struct_ {
|
||||
ptr_typ := g.gen_struct_equality_fn(left.unaliased)
|
||||
ptr_typ := g.equality_fn(left.unaliased)
|
||||
if node.op == .ne {
|
||||
g.write('!')
|
||||
}
|
||||
|
@ -218,7 +210,7 @@ fn (mut g Gen) infix_expr_eq_op(node ast.InfixExpr) {
|
|||
g.write(')')
|
||||
}
|
||||
.sum_type {
|
||||
ptr_typ := g.gen_sumtype_equality_fn(left.unaliased)
|
||||
ptr_typ := g.equality_fn(left.unaliased)
|
||||
if node.op == .ne {
|
||||
g.write('!')
|
||||
}
|
||||
|
@ -385,19 +377,7 @@ fn (mut g Gen) infix_expr_in_op(node ast.InfixExpr) {
|
|||
return
|
||||
}
|
||||
}
|
||||
fn_name := g.gen_array_contains_method(node.right_type)
|
||||
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
|
||||
g.gen_array_contains(node.right_type, node.right, node.left)
|
||||
} else if right.unaliased_sym.kind == .map {
|
||||
g.write('_IN_MAP(')
|
||||
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 {
|
||||
g.write('string__eq(')
|
||||
} 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.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_sym := g.table.get_type_symbol(array_info.elem_type)
|
||||
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.expr(node.left)
|
||||
if node.left_type.has_flag(.shared_f) {
|
||||
g.write('->val')
|
||||
}
|
||||
if elem_sym.kind == .function {
|
||||
g.write(', _MOV((voidptr[]){ ')
|
||||
} else {
|
||||
|
|
|
@ -19,29 +19,34 @@ import strings
|
|||
// }
|
||||
// Codegen json_decode/encode funcs
|
||||
fn (mut g Gen) gen_json_for_type(typ ast.Type) {
|
||||
utyp := g.unwrap_generic(typ)
|
||||
mut dec := strings.new_builder(100)
|
||||
mut enc := strings.new_builder(100)
|
||||
utyp := g.unwrap_generic(typ).set_nr_muls(0)
|
||||
sym := g.table.get_type_symbol(utyp)
|
||||
styp := g.typ(utyp)
|
||||
g.register_optional(utyp)
|
||||
if is_js_prim(sym.name) || sym.kind == .enum_ {
|
||||
return
|
||||
}
|
||||
if sym.kind == .array {
|
||||
// return
|
||||
}
|
||||
if sym.name in g.json_types {
|
||||
return
|
||||
}
|
||||
g.json_types << sym.name
|
||||
// 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('
|
||||
g.json_types << utyp
|
||||
}
|
||||
|
||||
fn (mut g Gen) gen_jsons() {
|
||||
mut done := []ast.Type{}
|
||||
for i := 0; i < g.json_types.len; i++ {
|
||||
utyp := g.json_types[i]
|
||||
if utyp in done {
|
||||
continue
|
||||
}
|
||||
done << utyp
|
||||
mut dec := strings.new_builder(100)
|
||||
mut enc := strings.new_builder(100)
|
||||
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 {
|
||||
$styp res;
|
||||
if (!root) {
|
||||
|
@ -53,69 +58,70 @@ $dec_fn_dec {
|
|||
}
|
||||
}
|
||||
')
|
||||
g.json_forward_decls.writeln('$dec_fn_dec;')
|
||||
// Code gen encoder
|
||||
// encode_TYPE funcs receive an object to encode
|
||||
enc_fn_name := js_enc_name(styp)
|
||||
enc_fn_dec := 'cJSON* ${enc_fn_name}($styp val)'
|
||||
g.json_forward_decls.writeln('$enc_fn_dec;\n')
|
||||
enc.writeln('
|
||||
g.json_forward_decls.writeln('$dec_fn_dec;')
|
||||
// Code gen encoder
|
||||
// encode_TYPE funcs receive an object to encode
|
||||
enc_fn_name := js_enc_name(styp)
|
||||
enc_fn_dec := 'cJSON* ${enc_fn_name}($styp val)'
|
||||
g.json_forward_decls.writeln('$enc_fn_dec;\n')
|
||||
enc.writeln('
|
||||
$enc_fn_dec {
|
||||
\tcJSON *o;')
|
||||
if sym.kind == .array {
|
||||
// Handle arrays
|
||||
value_type := g.table.value_type(utyp)
|
||||
// If we have `[]Profile`, have to register a Profile en(de)coder first
|
||||
g.gen_json_for_type(value_type)
|
||||
dec.writeln(g.decode_array(value_type))
|
||||
enc.writeln(g.encode_array(value_type))
|
||||
// enc += g.encode_array(t)
|
||||
} else if sym.kind == .map {
|
||||
// Handle maps
|
||||
m := sym.info as ast.Map
|
||||
g.gen_json_for_type(m.key_type)
|
||||
g.gen_json_for_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))
|
||||
} else if sym.kind == .alias {
|
||||
a := sym.info as ast.Alias
|
||||
parent_typ := a.parent_type
|
||||
psym := g.table.get_type_symbol(parent_typ)
|
||||
if is_js_prim(g.typ(parent_typ)) {
|
||||
g.gen_json_for_type(parent_typ)
|
||||
return
|
||||
}
|
||||
enc.writeln('\to = cJSON_CreateObject();')
|
||||
if psym.info is ast.Struct {
|
||||
g.gen_struct_enc_dec(psym.info, styp, mut enc, mut dec)
|
||||
} else if psym.kind == .sum_type {
|
||||
verror('json: $sym.name aliased sumtypes does not work at the moment')
|
||||
if sym.kind == .array {
|
||||
// Handle arrays
|
||||
value_type := g.table.value_type(utyp)
|
||||
// If we have `[]Profile`, have to register a Profile en(de)coder first
|
||||
g.gen_json_for_type(value_type)
|
||||
dec.writeln(g.decode_array(value_type))
|
||||
enc.writeln(g.encode_array(value_type))
|
||||
// enc += g.encode_array(t)
|
||||
} else if sym.kind == .map {
|
||||
// Handle maps
|
||||
m := sym.info as ast.Map
|
||||
g.gen_json_for_type(m.key_type)
|
||||
g.gen_json_for_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))
|
||||
} else if sym.kind == .alias {
|
||||
a := sym.info as ast.Alias
|
||||
parent_typ := a.parent_type
|
||||
psym := g.table.get_type_symbol(parent_typ)
|
||||
if is_js_prim(g.typ(parent_typ)) {
|
||||
g.gen_json_for_type(parent_typ)
|
||||
continue
|
||||
}
|
||||
enc.writeln('\to = cJSON_CreateObject();')
|
||||
if psym.info is ast.Struct {
|
||||
g.gen_struct_enc_dec(psym.info, styp, mut enc, mut dec)
|
||||
} else if psym.kind == .sum_type {
|
||||
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 {
|
||||
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 {
|
||||
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 {
|
||||
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())
|
||||
}
|
||||
// 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]
|
||||
|
@ -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)
|
||||
|
||||
// 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);')
|
||||
|
||||
// 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()
|
||||
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.expr(expr)
|
||||
g.write(')')
|
||||
|
@ -93,7 +93,7 @@ fn (mut g Gen) gen_expr_to_string(expr ast.Expr, etype ast.Type) {
|
|||
g.write('_SLIT("<none>")')
|
||||
} else if sym.kind == .enum_ {
|
||||
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.enum_expr(expr)
|
||||
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_] {
|
||||
is_ptr := typ.is_ptr()
|
||||
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 {
|
||||
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(')')
|
||||
}
|
||||
} else {
|
||||
str_fn_name := g.gen_str_method_for_type(typ)
|
||||
str_fn_name := g.get_str_fn(typ)
|
||||
g.write('${str_fn_name}(')
|
||||
if expr.is_auto_deref_var() {
|
||||
g.write('*')
|
||||
|
|
|
@ -7,8 +7,20 @@ import v.ast
|
|||
|
||||
fn (mut g Gen) unwrap_generic(typ ast.Type) ast.Type {
|
||||
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
|
||||
}
|
||||
|
|
|
@ -129,7 +129,6 @@ fn (mut g JsGen) comp_if_cond(cond ast.Expr, pkg_exist bool) bool {
|
|||
name = '${left.expr}.$left.field_name'
|
||||
exp_type = g.comptime_var_type_map[name]
|
||||
} else if left is ast.TypeNode {
|
||||
name = left.str()
|
||||
// this is only allowed for generics currently, otherwise blocked by checker
|
||||
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 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(paths)
|
||||
nr_cpus := runtime.nr_cpus()
|
||||
|
|
|
@ -136,6 +136,10 @@ pub fn (mut p Preferences) fill_with_defaults() {
|
|||
if p.bare_builtin_dir == '' {
|
||||
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'
|
||||
|
|
|
@ -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_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.
|
||||
is_parallel bool
|
||||
no_parallel bool
|
||||
is_vweb bool // skip _ var warning in templates
|
||||
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
|
||||
|
@ -474,8 +474,8 @@ pub fn parse_args(known_external_commands []string, args []string) (&Preferences
|
|||
res.prealloc = true
|
||||
res.build_options << arg
|
||||
}
|
||||
'-parallel' {
|
||||
res.is_parallel = true
|
||||
'-no-parallel' {
|
||||
res.no_parallel = true
|
||||
}
|
||||
'-native' {
|
||||
res.backend = .native
|
||||
|
|
|
@ -85,12 +85,10 @@ fn test_comptime_for_fields() {
|
|||
if field.name == 'f' {
|
||||
assert sizeof(field) == 8
|
||||
assert isreftype(field) == false
|
||||
// assert typeof(field) == 'u64'
|
||||
assert typeof(field).name == 'u64'
|
||||
fields_found++
|
||||
}
|
||||
if field.name == 'g' {
|
||||
// assert typeof(field) == 'string'
|
||||
assert typeof(field).name == 'string'
|
||||
assert isreftype(field) == true
|
||||
fields_found++
|
||||
|
|
|
@ -7,7 +7,7 @@ fn inc_array_elem(shared b []int, i int) {
|
|||
}
|
||||
|
||||
fn test_autolock_array() {
|
||||
shared a := &[1, 2, 7, 5]
|
||||
shared a := [1, 2, 7, 5]
|
||||
t := go inc_array_elem(shared a, 2)
|
||||
for _ in 0 .. iterations {
|
||||
a[2]++
|
||||
|
@ -23,7 +23,7 @@ fn inc_map_elem(shared b map[string]int, k string) {
|
|||
}
|
||||
|
||||
fn test_autolock_map() {
|
||||
shared m := &{
|
||||
shared m := {
|
||||
'xy': 1
|
||||
'qwe': 2
|
||||
'asd': 7
|
||||
|
|
Loading…
Reference in New Issue