diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8a4f00745f..e172bc5259 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -299,3 +299,20 @@ jobs: ./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 ls -lart v_from_vc.exe + + + + ubuntu-c-plus-plus: + runs-on: ubuntu-18.04 + steps: + - uses: actions/checkout@v2 + - name: Install dependencies + run: sudo rm -f /etc/apt/sources.list.d/dotnetdev.list /etc/apt/sources.list.d/microsoft-prod.list; sudo apt-get update; sudo apt-get install --quiet -y postgresql libpq-dev libglfw3 libglfw3-dev libfreetype6-dev libssl-dev sqlite3 libsqlite3-dev libsdl2-dev libsdl2-ttf-dev libsdl2-mixer-dev libsdl2-image-dev valgrind g++-9 + - name: Build V + run: make -j4 + - name: g++ version + run: g++-9 --version + - name: Running tests with g++ + run: ./v -cc g++-9 test-fixed + - name: V self compilation with g++ + run: ./v -cc g++-9 -o v2 cmd/v && ./v2 -cc g++-9 -o v3 cmd/v diff --git a/cmd/tools/preludes/tests_with_stats.v b/cmd/tools/preludes/tests_with_stats.v index 36ad06a5da..91562d3584 100644 --- a/cmd/tools/preludes/tests_with_stats.v +++ b/cmd/tools/preludes/tests_with_stats.v @@ -16,13 +16,13 @@ const ( struct BenchedTests { mut: + bench benchmark.Benchmark oks int fails int test_suit_file string step_func_name string - bench benchmark.Benchmark } - + // /////////////////////////////////////////////////////////////////// // Called at the start of the test program produced by `v -stats file_test.v` fn start_testing(total_number_of_tests int, vfilename string) BenchedTests { diff --git a/vlib/benchmark/benchmark.v b/vlib/benchmark/benchmark.v index 650d236ec0..0a15cc0c2f 100644 --- a/vlib/benchmark/benchmark.v +++ b/vlib/benchmark/benchmark.v @@ -55,15 +55,15 @@ const ( pub struct Benchmark { pub mut: bench_timer time.StopWatch + verbose bool + no_cstep bool step_timer time.StopWatch ntotal int nok int nfail int nskip int - verbose bool nexpected_steps int cstep int - no_cstep bool bok string bfail string } diff --git a/vlib/builtin/array.v b/vlib/builtin/array.v index c7419431eb..4f77dce481 100644 --- a/vlib/builtin/array.v +++ b/vlib/builtin/array.v @@ -19,10 +19,10 @@ pub mut: fn __new_array(mylen int, cap int, elm_size int) array { cap_ := if cap < mylen { mylen } else { cap } arr := array{ - len: mylen - cap: cap_ element_size: elm_size data: vcalloc(cap_ * elm_size) + len: mylen + cap: cap_ } return arr } @@ -30,10 +30,10 @@ fn __new_array(mylen int, cap int, elm_size int) array { fn __new_array_with_default(mylen int, cap int, elm_size int, val voidptr) array { cap_ := if cap < mylen { mylen } else { cap } arr := array{ - len: mylen - cap: cap_ element_size: elm_size data: vcalloc(cap_ * elm_size) + len: mylen + cap: cap_ } if val != 0 { for i in 0..arr.len { @@ -48,10 +48,10 @@ fn new_array_from_c_array(len, cap, elm_size int, c_array voidptr) array { cap_ := if cap < len { len } else { cap } arr := array{ - len: len - cap: cap_ element_size: elm_size data: vcalloc(cap_ * elm_size) + len: len + cap: cap_ } // TODO Write all memory functions (like memcpy) in V C.memcpy(arr.data, c_array, len * elm_size) @@ -61,10 +61,10 @@ fn new_array_from_c_array(len, cap, elm_size int, c_array voidptr) array { // Private function, used by V (`nums := [1, 2, 3] !`) fn new_array_from_c_array_no_alloc(len, cap, elm_size int, c_array voidptr) array { arr := array{ - len: len - cap: cap element_size: elm_size data: c_array + len: len + cap: cap } return arr } @@ -98,10 +98,10 @@ pub fn (a array) repeat(count int) array { size = a.element_size } arr := array{ - len: count * a.len - cap: count * a.len element_size: a.element_size data: vcalloc(size) + len: count * a.len + cap: count * a.len } for i in 0..count { C.memcpy(byteptr(arr.data) + i * a.len * a.element_size, byteptr(a.data), a.len * a.element_size) @@ -241,10 +241,10 @@ pub fn (a &array) clone() array { size++ } arr := array{ - len: a.len - cap: a.cap element_size: a.element_size data: vcalloc(size) + len: a.len + cap: a.cap } C.memcpy(byteptr(arr.data), a.data, a.cap * a.element_size) return arr @@ -312,10 +312,10 @@ pub fn (a array) reverse() array { return a } arr := array{ - len: a.len - cap: a.cap element_size: a.element_size data: vcalloc(a.cap * a.element_size) + len: a.len + cap: a.cap } for i in 0..a.len { //C.memcpy(arr.data + i * arr.element_size, &a[a.len - 1 - i], arr.element_size) diff --git a/vlib/builtin/builtin_nix.c.v b/vlib/builtin/builtin_nix.c.v index 77b6ed622c..7bfa5ddb35 100644 --- a/vlib/builtin/builtin_nix.c.v +++ b/vlib/builtin/builtin_nix.c.v @@ -116,7 +116,7 @@ fn print_backtrace_skipping_top_frames_linux(skipframes int) bool { buf := [1000]byte mut output := '' for C.fgets(charptr(buf), 1000, f) != 0 { - output += tos(buf, vstrlen(buf)) + output += tos(byteptr(buf), vstrlen(byteptr(buf))) } output = output.trim_space() + ':' if C.pclose(f) != 0 { diff --git a/vlib/builtin/cfns.c.v b/vlib/builtin/cfns.c.v index d5a06f543b..ba46743ec0 100644 --- a/vlib/builtin/cfns.c.v +++ b/vlib/builtin/cfns.c.v @@ -12,7 +12,7 @@ fn C.free(ptr voidptr) fn C.exit(code int) -fn C.qsort(voidptr, int, int, voidptr) +fn C.qsort(voidptr, int, int, qsort_callback_func) fn C.sprintf(a ...voidptr) int diff --git a/vlib/builtin/int.v b/vlib/builtin/int.v index 69c4c2e37f..433e94a96a 100644 --- a/vlib/builtin/int.v +++ b/vlib/builtin/int.v @@ -383,8 +383,8 @@ pub fn (c rune) str() string { pub fn (c byte) str() string { mut str := string{ - len: 1 str: malloc(2) + len: 1 } str.str[0] = c str.str[1] = `\0` diff --git a/vlib/builtin/option.v b/vlib/builtin/option.v index 5c7ee10182..8c30117c86 100644 --- a/vlib/builtin/option.v +++ b/vlib/builtin/option.v @@ -4,21 +4,21 @@ module builtin /* struct Option2 { - data T - error string - ecode int ok bool is_none bool + error string + ecode int + data T } */ struct Option { - data [400]byte - error string - ecode int ok bool is_none bool + error string + ecode int + data [400]byte } pub fn (o Option) str() string { @@ -46,19 +46,24 @@ fn opt_ok(data voidptr, size int) Option { // used internally when returning `none` fn opt_none() Option { return Option{ + ok: false is_none: true } } pub fn error(s string) Option { return Option{ + ok: false + is_none: false error: s } } pub fn error_with_code(s string, code int) Option { return Option{ + ok: false + is_none: false error: s ecode: code } -} +} \ No newline at end of file diff --git a/vlib/builtin/sorted_map.v b/vlib/builtin/sorted_map.v index ddae014271..93538a9af3 100644 --- a/vlib/builtin/sorted_map.v +++ b/vlib/builtin/sorted_map.v @@ -31,10 +31,10 @@ pub mut: struct mapnode { mut: - keys [11]string // TODO: Should use `max_size` - values [11]voidptr // TODO: Should use `max_size` children &voidptr size int + keys [11]string // TODO: Should use `max_size` + values [11]voidptr // TODO: Should use `max_size` } fn new_sorted_map(n, value_bytes int) SortedMap { // TODO: Remove `n` diff --git a/vlib/builtin/string.v b/vlib/builtin/string.v index 3133298e53..8ea7326319 100644 --- a/vlib/builtin/string.v +++ b/vlib/builtin/string.v @@ -122,8 +122,8 @@ fn (a string) clone_static() string { pub fn (a string) clone() string { mut b := string{ - len: a.len str: malloc(a.len + 1) + len: a.len } for i in 0..a.len { b.str[i] = a.str[i] @@ -399,8 +399,8 @@ fn (s string) ge(a string) bool { fn (s string) add(a string) string { new_len := a.len + s.len mut res := string{ - len: new_len str: malloc(new_len + 1) + len: new_len } for j in 0..s.len { res.str[j] = s.str[j] @@ -537,8 +537,8 @@ pub fn (s string) substr(start, end int) string { } len := end - start mut res := string{ - len: len str: malloc(len + 1) + len: len } for i in 0..len { res.str[i] = s.str[start + i] @@ -1284,8 +1284,8 @@ pub fn (s string) reverse() string { return s } mut res := string{ - len: s.len str: malloc(s.len) + len: s.len } for i := s.len - 1; i >= 0; i-- { res.str[s.len - i - 1] = s[i] diff --git a/vlib/clipboard/clipboard_linux.c.v b/vlib/clipboard/clipboard_linux.c.v index e933a4df8f..7b252a6fcb 100644 --- a/vlib/clipboard/clipboard_linux.c.v +++ b/vlib/clipboard/clipboard_linux.c.v @@ -10,7 +10,8 @@ import math #include // X11 -struct C.Display{} +[typedef] +struct C.Display [typedef] struct C.Atom @@ -33,7 +34,7 @@ fn C.XCreateSimpleWindow(d &Display, root C.Window, x int, y int, width u32, hei fn C.XOpenDisplay(name byteptr) &C.Display fn C.XConvertSelection(d &Display, selection C.Atom, target C.Atom, property C.Atom, requestor Window, time int) int fn C.XSync(d &Display, discard int) int -fn C.XGetWindowProperty(d &Display, w Window, property C.Atom, offset i64, length i64, delete int, req_type C.Atom, actual_type_return &C.Atom, actual_format_return &int, nitems &i64, bytes_after_return &i64, prop_return &byteptr) int +fn C.XGetWindowProperty(d &Display, w Window, property C.Atom, offset i64, length i64, delete int, req_type C.Atom, actual_type_return &C.Atom, actual_format_return &int, nitems &u64, bytes_after_return &u64, prop_return &byteptr) int fn C.XDeleteProperty(d &Display, w Window, property C.Atom) int fn C.DefaultScreen() int fn C.RootWindow() voidptr @@ -46,10 +47,10 @@ fn todo_del(){} [typedef] struct C.XSelectionRequestEvent{ mut: - selection C.Atom display &C.Display /* Display the event was read from */ owner C.Window requestor C.Window + selection C.Atom target C.Atom property C.Atom time int @@ -59,9 +60,9 @@ struct C.XSelectionRequestEvent{ struct C.XSelectionEvent{ mut: @type int - selection C.Atom display &C.Display /* Display the event was read from */ requestor C.Window + selection C.Atom target C.Atom property C.Atom time int @@ -81,13 +82,13 @@ struct C.XDestroyWindowEvent { } [typedef] -struct C.XEvent{ +union C.XEvent{ mut: @type int + xdestroywindow C.XDestroyWindowEvent + xselectionclear C.XSelectionClearEvent xselectionrequest C.XSelectionRequestEvent xselection C.XSelectionEvent - xselectionclear C.XSelectionClearEvent - xdestroywindow C.XDestroyWindowEvent } const ( @@ -287,7 +288,7 @@ fn (mut cb Clipboard) start_listener(){ if !cb.transmit_selection(&xse) { xse.property = new_atom(C.None) } - C.XSendEvent(cb.display, xse.requestor, 0, C.PropertyChangeMask, &xse) + C.XSendEvent(cb.display, xse.requestor, 0, C.PropertyChangeMask, voidptr(&xse)) C.XFlush(cb.display) } } @@ -340,8 +341,8 @@ fn (mut cb Clipboard) intern_atoms(){ fn read_property(d &C.Display, w C.Window, p C.Atom) Property { actual_type := C.Atom(0) actual_format := 0 - nitems := 0 - bytes_after := 0 + nitems := u64(0) + bytes_after := u64(0) ret := byteptr(0) mut read_bytes := 1024 for { diff --git a/vlib/flag/flag.v b/vlib/flag/flag.v index 678137477e..18a5ffbed1 100644 --- a/vlib/flag/flag.v +++ b/vlib/flag/flag.v @@ -75,6 +75,7 @@ pub fn (af []Flag) str() string { pub struct FlagParser { pub mut: args []string // the arguments to be parsed + max_free_args int flags []Flag // registered flags application_name string @@ -82,7 +83,6 @@ pub struct FlagParser { application_description string min_free_args int - max_free_args int args_description string } diff --git a/vlib/hash/wyhash/wyhash.v b/vlib/hash/wyhash/wyhash.v index 3e9b85a641..d2978a67c0 100644 --- a/vlib/hash/wyhash/wyhash.v +++ b/vlib/hash/wyhash/wyhash.v @@ -40,7 +40,7 @@ pub fn sum64_string(key string, seed u64) u64 { [inline] pub fn sum64(key []byte, seed u64) u64 { - return wyhash64(key.data, u64(key.len), seed) + return wyhash64(byteptr(key.data), u64(key.len), seed) } [inline] diff --git a/vlib/math/big/big.v b/vlib/math/big/big.v index 25b1906c5f..c826a6cc0e 100644 --- a/vlib/math/big/big.v +++ b/vlib/math/big/big.v @@ -6,10 +6,13 @@ module big #flag @VROOT/thirdparty/bignum/bn.o #include "bn.h" -pub struct Number { +[typedef] +struct C.bn { array [32]u32 } +type Number = C.bn + fn C.bignum_init( n &Number ) fn C.bignum_from_int( n &Number, i u64 ) fn C.bignum_to_int( n &Number ) int diff --git a/vlib/net/http/backend_nix.c.v b/vlib/net/http/backend_nix.c.v index aeb0ddc674..19f235cea8 100644 --- a/vlib/net/http/backend_nix.c.v +++ b/vlib/net/http/backend_nix.c.v @@ -18,8 +18,8 @@ import strings #flag darwin -I/usr/local/opt/openssl/include #flag darwin -L/usr/local/opt/openssl/lib #include -struct C.SSL { -} + +struct C.ssl_st fn C.SSL_library_init() @@ -108,7 +108,7 @@ fn (req &Request) ssl_do(port int, method, host_name, path string) ?Response { res = C.BIO_set_conn_hostname(web, addr.str) if res != 1 { } - ssl := &C.SSL(0) + ssl := &C.ssl_st(0) C.BIO_get_ssl(web, &ssl) if isnil(ssl) { } diff --git a/vlib/net/net.v b/vlib/net/net.v index c9544675cb..e76178a45a 100644 --- a/vlib/net/net.v +++ b/vlib/net/net.v @@ -6,10 +6,11 @@ pub fn hostname() ?string { mut name := [256]byte // https://www.ietf.org/rfc/rfc1035.txt // The host name is returned as a null-terminated string. - res := C.gethostname(&name, 256) + namebp := byteptr(name) + res := C.gethostname(namebp, 256) if res != 0 { return error('net.hostname: failed with $res') } - return tos_clone(name) + return tos_clone(namebp) } diff --git a/vlib/net/socket.v b/vlib/net/socket.v index 25810136f8..7c5b315317 100644 --- a/vlib/net/socket.v +++ b/vlib/net/socket.v @@ -15,6 +15,9 @@ mut: s_addr int } +struct C.sockaddr { +} + struct C.sockaddr_in { mut: sin_family int @@ -108,7 +111,9 @@ pub fn (s Socket) bind(port int) ?int { addr.sin_port = C.htons(port) addr.sin_addr.s_addr = C.htonl(C.INADDR_ANY) size := 16 // sizeof(C.sockaddr_in) - res := C.bind(s.sockfd, &addr, size) + tmp := voidptr(&addr) + skaddr := &C.sockaddr(tmp) + res := C.bind(s.sockfd, skaddr, size) if res < 0 { return error('net.bind: failed with $res') } @@ -165,7 +170,9 @@ pub fn (s Socket) accept() ?Socket { } addr := C.sockaddr_storage{} size := 128 // sizeof(sockaddr_storage) - sockfd := C.accept(s.sockfd, &addr, &size) + tmp := voidptr(&addr) + skaddr := &C.sockaddr(tmp) + sockfd := C.accept(s.sockfd, skaddr, &size) if sockfd < 0 { return error('net.accept: failed with $sockfd') } @@ -255,8 +262,8 @@ pub fn (s Socket) cread(buffer byteptr, buffersize int) int { // Receive a message from the socket, and place it in a preallocated buffer buf, // with maximum message size bufsize. Returns the length of the received message. -pub fn (s Socket) crecv(buffer byteptr, buffersize int) int { - return C.recv(s.sockfd, buffer, buffersize, 0) +pub fn (s Socket) crecv(buffer voidptr, buffersize int) int { + return C.recv(s.sockfd, byteptr(buffer), buffersize, 0) } // shutdown and close socket @@ -325,7 +332,8 @@ pub fn (s Socket) read_line() string { break } } - line = tos_clone(buf) + bufbp := byteptr(buf) + line = tos_clone(bufbp) if eol_idx > 0 { // At this point, we are sure that recv returned valid data, // that contains *at least* one line. @@ -357,7 +365,8 @@ pub fn (s Socket) read_all() string { if n == 0 { return res } - res += tos_clone(buf) + bufbp := byteptr(buf) + res += tos_clone(bufbp) } return res } @@ -365,6 +374,8 @@ pub fn (s Socket) read_all() string { pub fn (s Socket) get_port() int { mut addr := C.sockaddr_in{} size := 16 // sizeof(sockaddr_in) - C.getsockname(s.sockfd, &addr, &size) + tmp := voidptr(&addr) + skaddr := &C.sockaddr(tmp) + C.getsockname(s.sockfd, skaddr, &size) return C.ntohs(addr.sin_port) } diff --git a/vlib/os/os_nix.c.v b/vlib/os/os_nix.c.v index c4b91e6139..09a564b7b5 100644 --- a/vlib/os/os_nix.c.v +++ b/vlib/os/os_nix.c.v @@ -84,6 +84,7 @@ pub fn open(path string) ?File { */ file := File{ cfile: C.fopen(charptr(path.str), 'rb') + fd: 0 opened: true } if isnil(file.cfile) { @@ -119,6 +120,7 @@ pub fn create(path string) ?File { */ file := File{ cfile: C.fopen(charptr(path.str), 'wb') + fd: 0 opened: true } if isnil(file.cfile) { @@ -207,7 +209,8 @@ pub fn exec(cmd string) ?Result { buf := [4096]byte mut res := strings.new_builder(1024) for C.fgets(charptr(buf), 4096, f) != 0 { - res.write_bytes( buf, vstrlen(buf) ) + bufbp := byteptr(buf) + res.write_bytes( bufbp, vstrlen(bufbp) ) } soutput := res.str().trim_space() //res.free() @@ -216,8 +219,8 @@ pub fn exec(cmd string) ?Result { // return error(res) // } return Result{ - output: soutput exit_code: exit_code + output: soutput } } diff --git a/vlib/strconv/format.v b/vlib/strconv/format.v index 1ccaf25db1..d6ba45f907 100644 --- a/vlib/strconv/format.v +++ b/vlib/strconv/format.v @@ -664,7 +664,7 @@ pub fn v_sprintf(str string, pt ... voidptr) string{ } - res.write(format_dec(d1,{positive: positive, pad_ch: pad_ch, len0: len0, sign_flag: sign, allign: allign})) + res.write(format_dec(d1,{pad_ch: pad_ch, len0: len0, len1: 0, positive: positive, sign_flag: sign, allign: allign})) status = .reset_params p_index++ i++ @@ -707,7 +707,7 @@ pub fn v_sprintf(str string, pt ... voidptr) string{ } } - res.write(format_dec(d1,{positive: positive, pad_ch: pad_ch, len0: len0, sign_flag: sign, allign: allign})) + res.write(format_dec(d1,{pad_ch: pad_ch, len0: len0, len1: 0, positive: positive, sign_flag: sign, allign: allign})) status = .reset_params p_index++ i++ @@ -755,7 +755,7 @@ pub fn v_sprintf(str string, pt ... voidptr) string{ s = s.to_upper() } - res.write(format_str(s,{pad_ch: pad_ch, len0: len0, allign: allign})) + res.write(format_str(s,{pad_ch: pad_ch, len0: len0, len1: 0, positive: true, sign_flag: false, allign: allign})) status = .reset_params p_index++ i++ @@ -767,7 +767,7 @@ pub fn v_sprintf(str string, pt ... voidptr) string{ x := *(&f64(pt[p_index])) mut positive := x >= f64(0.0) len1 = if len1 >= 0 { len1 } else { def_len1 } - s := format_fl(f64(x), {positive: positive, pad_ch: pad_ch, len0: len0, len1: len1, sign_flag: sign, allign: allign}) + s := format_fl(f64(x), {pad_ch: pad_ch, len0: len0, len1: len1, positive: positive, sign_flag: sign, allign: allign}) res.write(if ch == `F` {s.to_upper()} else {s}) status = .reset_params p_index++ @@ -778,7 +778,7 @@ pub fn v_sprintf(str string, pt ... voidptr) string{ x := *(&f64(pt[p_index])) mut positive := x >= f64(0.0) len1 = if len1 >= 0 { len1 } else { def_len1 } - s := format_es(f64(x), {positive: positive, pad_ch: pad_ch, len0: len0, len1: len1, sign_flag: sign, allign: allign}) + s := format_es(f64(x), {pad_ch: pad_ch, len0: len0, len1: len1, positive: positive, sign_flag: sign, allign: allign}) res.write(if ch == `E` {s.to_upper()} else {s}) status = .reset_params p_index++ @@ -793,10 +793,10 @@ pub fn v_sprintf(str string, pt ... voidptr) string{ if tx < 999_999.0 && tx >= 0.00001 { //println("Here g format_fl [$tx]") len1 = if len1 >= 0 { len1+1 } else { def_len1 } - s = format_fl(x, {positive: positive, pad_ch: pad_ch, len0: len0, len1: len1, sign_flag: sign, allign: allign, rm_tail_zero: true}) + s = format_fl(x, {pad_ch: pad_ch, len0: len0, len1: len1, positive: positive, sign_flag: sign, allign: allign, rm_tail_zero: true}) } else { len1 = if len1 >= 0 { len1+1 } else { def_len1 } - s = format_es(x, {positive: positive, pad_ch: pad_ch, len0: len0, len1: len1, sign_flag: sign, allign: allign, rm_tail_zero: true}) + s = format_es(x, {pad_ch: pad_ch, len0: len0, len1: len1, positive: positive, sign_flag: sign, allign: allign, rm_tail_zero: true}) } res.write(if ch == `G` {s.to_upper()} else {s}) status = .reset_params @@ -809,7 +809,7 @@ pub fn v_sprintf(str string, pt ... voidptr) string{ else if ch == `s` { s1 := *(&string(pt[p_index])) pad_ch = ` ` - res.write(format_str(s1, {pad_ch: pad_ch, len0: len0, allign: allign})) + res.write(format_str(s1, {pad_ch: pad_ch, len0: len0, len1: 0, positive: true, sign_flag: false, allign: allign})) status = .reset_params p_index++ i++ diff --git a/vlib/strconv/ftoa/utilities.v b/vlib/strconv/ftoa/utilities.v index 7644d77f17..40eeede396 100644 --- a/vlib/strconv/ftoa/utilities.v +++ b/vlib/strconv/ftoa/utilities.v @@ -190,7 +190,7 @@ fn shift_right_128(v Uint128, shift int) u64 { fn mul_shift_64(m u64, mul Uint128, shift int) u64 { hihi, hilo := bits.mul_64(m, mul.hi) lohi, _ := bits.mul_64(m, mul.lo) - mut sum := Uint128{hi: hihi, lo: lohi + hilo} + mut sum := Uint128{lo: lohi + hilo,hi: hihi} if sum.lo < lohi { sum.hi++ // overflow } diff --git a/vlib/strings/builder.c.v b/vlib/strings/builder.c.v index 108016ff72..040d87fb11 100644 --- a/vlib/strings/builder.c.v +++ b/vlib/strings/builder.c.v @@ -16,6 +16,8 @@ pub fn new_builder(initial_size int) Builder { return Builder{ //buf: make(0, initial_size) buf: []byte{cap: initial_size} + str_calls: 0 + len: 0 initial_size: initial_size } } diff --git a/vlib/time/stopwatch.v b/vlib/time/stopwatch.v index d3792068fb..52890f6dbb 100644 --- a/vlib/time/stopwatch.v +++ b/vlib/time/stopwatch.v @@ -12,7 +12,7 @@ pub mut: } pub fn new_stopwatch() StopWatch { - return StopWatch{start: time.sys_mono_now()} + return StopWatch{pause_time: 0, start: time.sys_mono_now(), end: 0} } // start Starts the timer. If the timer was paused, restarts counting. diff --git a/vlib/time/time.v b/vlib/time/time.v index 6499213b92..fc6c2538fe 100644 --- a/vlib/time/time.v +++ b/vlib/time/time.v @@ -76,23 +76,18 @@ pub enum FormatDelimiter { no_delimiter } -// TODO: C.time_t. works in v2 -type time_t voidptr - pub struct C.timeval { tv_sec u64 tv_usec u64 } -fn C.localtime(int) &C.tm - -fn C.time(int) time_t +fn C.localtime(t &C.time_t) &C.tm +fn C.time(t &C.time_t) C.time_t // now returns current local time. pub fn now() Time { t := C.time(0) - mut now := &C.tm(0) - now = C.localtime(&t) + now := C.localtime(&t) return convert_ctime(now) } diff --git a/vlib/time/time_nix.c.v b/vlib/time/time_nix.c.v index 33b8bbfe90..da210c5c47 100644 --- a/vlib/time/time_nix.c.v +++ b/vlib/time/time_nix.c.v @@ -4,12 +4,12 @@ module time struct C.tm { - tm_year int - tm_mon int - tm_mday int - tm_hour int - tm_min int tm_sec int + tm_min int + tm_hour int + tm_mday int + tm_mon int + tm_year int } fn C.timegm(&tm) time_t diff --git a/vlib/v/builder/cc.v b/vlib/v/builder/cc.v index cc81ba6808..8662fbec15 100644 --- a/vlib/v/builder/cc.v +++ b/vlib/v/builder/cc.v @@ -306,6 +306,11 @@ fn (mut v Builder) cc() { // add all flags (-I -l -L etc) not .o files a << cflags.c_options_without_object_files() a << libs + // For C++ we must be very tolerant + if guessed_compiler.contains('++') { + a << '-fpermissive' + a << '-w' + } if v.pref.use_cache { //vexe := pref.vexe_path() @@ -344,7 +349,7 @@ fn (mut v Builder) cc() { if !v.pref.is_bare && v.pref.os == .js && os.user_os() == 'linux' { linker_flags << '-lm' } - args := a.join(' ') + linker_flags.join(' ') + args := a.join(' ') + ' ' + linker_flags.join(' ') start: todo() // TODO remove diff --git a/vlib/v/gen/cgen.v b/vlib/v/gen/cgen.v index 24ed1c2a16..535045d89f 100644 --- a/vlib/v/gen/cgen.v +++ b/vlib/v/gen/cgen.v @@ -37,7 +37,9 @@ const ( 'void', 'volatile', 'while', - 'new' + 'new', + 'namespace', + 'typename' ] ) @@ -316,7 +318,7 @@ fn (g &Gen) base_type(t table.Type) string { nr_muls := t.nr_muls() if nr_muls > 0 { styp += strings.repeat(`*`, nr_muls) - } + } return styp } @@ -363,7 +365,12 @@ typedef struct { .alias { parent := &g.table.types[typ.parent_idx] styp := typ.name.replace('.', '__') - parent_styp := parent.name.replace('.', '__') + is_c_parent := parent.name.len > 2 && parent.name[0] == `C` && parent.name[1] == `.` + parent_styp := if is_c_parent { + 'struct ' + parent.name[2..].replace('.', '__') + } else { + parent.name.replace('.', '__') + } g.definitions.writeln('typedef $parent_styp $styp;') } .array { @@ -591,7 +598,13 @@ fn (mut g Gen) stmt(node ast.Stmt) { // just remember `it`; main code will be generated in finish() g.fn_main = it } else { + if it.name == 'backtrace' || it.name == 'backtrace_symbols' || it.name == 'backtrace_symbols_fd' { + g.write('\n#ifndef __cplusplus\n') + } g.gen_fn_decl(it) + if it.name == 'backtrace' || it.name == 'backtrace_symbols' || it.name == 'backtrace_symbols_fd' { + g.write('\n#endif\n') + } } g.fn_decl = keep_fn_decl if skip { @@ -1210,9 +1223,9 @@ fn (mut g Gen) expr(node ast.Expr) { // `string(x)` needs `tos()`, but not `&string(x) // `tos(str, len)`, `tos2(str)` if it.has_arg { - g.write('tos(') + g.write('tos((byteptr)') } else { - g.write('tos2(') + g.write('tos2((byteptr)') } g.expr(it.expr) expr_sym := g.table.get_type_symbol(it.expr_type) @@ -1286,17 +1299,17 @@ fn (mut g Gen) expr(node ast.Expr) { value_typ_str := g.typ(it.value_type) size := it.vals.len if size > 0 { - g.write('new_map_init($size, sizeof($value_typ_str), (${key_typ_str}[$size]){') + g.write('new_map_init($size, sizeof($value_typ_str), _MOV((${key_typ_str}[$size]){') for expr in it.keys { g.expr(expr) g.write(', ') } - g.write('}, (${value_typ_str}[$size]){') + g.write('}), _MOV((${value_typ_str}[$size]){') for expr in it.vals { g.expr(expr) g.write(', ') } - g.write('})') + g.write('}))') } else { g.write('new_map_1(sizeof($value_typ_str))') } @@ -1665,7 +1678,7 @@ fn (mut g Gen) infix_expr(node ast.InfixExpr) { elem_type_str := g.typ(info.elem_type) g.write('array_push(&') g.expr(node.left) - g.write(', &($elem_type_str[]){ ') + g.write(', _MOV(($elem_type_str[]){ ') elem_sym := g.table.get_type_symbol(info.elem_type) if elem_sym.kind == .interface_ && node.right_type != info.elem_type { g.interface_call(node.right_type, info.elem_type) @@ -1674,7 +1687,7 @@ fn (mut g Gen) infix_expr(node ast.InfixExpr) { if elem_sym.kind == .interface_ && node.right_type != info.elem_type { g.write(')') } - g.write(' })') + g.write(' }))') } } else if (node.left_type == node.right_type) && node.left_type.is_float() && node.op in [.eq, .ne] { @@ -1697,7 +1710,8 @@ fn (mut g Gen) infix_expr(node ast.InfixExpr) { g.expr(node.right) g.write(')') } else if node.op in [.plus, .minus, .mul, .div, .mod] && (left_sym.name[0].is_capital() || - left_sym.name.contains('.')) && left_sym.kind != .alias { + left_sym.name.contains('.')) && left_sym.kind != .alias || + left_sym.kind == .alias && (left_sym.info as table.Alias).is_c { // !left_sym.is_number() { g.write(g.typ(node.left_type)) g.write('_') @@ -2009,7 +2023,7 @@ fn (mut g Gen) index_expr(node ast.IndexExpr) { } */ if need_wrapper { - g.write(', &($elem_type_str[]) { ') + g.write(', &($elem_type_str[]) { \n') } else { g.write(', &') } @@ -2061,7 +2075,7 @@ fn (mut g Gen) index_expr(node ast.IndexExpr) { g.expr(node.left) g.write(', ') g.expr(node.index) - g.write(', &($elem_type_str[]) { ') + g.write(', &($elem_type_str[]) { \n') } else { /* g.write('(*($elem_type_str*)map_get2(') @@ -2075,7 +2089,7 @@ fn (mut g Gen) index_expr(node ast.IndexExpr) { g.expr(node.left) g.write(', ') g.expr(node.index) - g.write(', &($elem_type_str[]){ $zero }))') + g.write(', &($elem_type_str[]){ $zero }))\n') } } else if sym.kind == .string && !node.left_type.is_ptr() { g.write('string_at(') @@ -2237,9 +2251,18 @@ fn (mut g Gen) const_decl_init_later(name, val string, typ table.Type) { g.inits.writeln('\t_const_$name = $val;') } +fn (mut g Gen) go_back_out(n int) { + g.out.go_back(n) +} + fn (mut g Gen) struct_init(struct_init ast.StructInit) { - sym := g.table.get_type_symbol(struct_init.typ) + skip_init := ['strconv__ftoa__Uf32', 'strconv__ftoa__Uf64', 'strconv__Float64u', 'struct stat', 'struct addrinfo'] styp := g.typ(struct_init.typ) + if styp in skip_init { + g.go_back_out(3) + return + } + sym := g.table.get_type_symbol(struct_init.typ) is_amp := g.is_amp g.is_amp = false // reset the flag immediately so that other struct inits in this expr are handled correctly if is_amp { @@ -2249,7 +2272,7 @@ fn (mut g Gen) struct_init(struct_init ast.StructInit) { g.writeln('($styp){') } // mut fields := []string{} - mut inited_fields := []string{} // TODO this is done in checker, move to ast node + mut inited_fields := map[string]int // TODO this is done in checker, move to ast node /* if struct_init.fields.len == 0 && struct_init.exprs.len > 0 { // Get fields for {a,b} short syntax. Fields array wasn't set in the parser. @@ -2261,33 +2284,63 @@ fn (mut g Gen) struct_init(struct_init ast.StructInit) { } */ // User set fields - for _, field in struct_init.fields { - field_name := c_name(field.name) - inited_fields << field.name - g.write('\t.$field_name = ') - field_type_sym := g.table.get_type_symbol(field.typ) - mut cloned := false - if g.autofree && field_type_sym.kind in [.array, .string] { - g.write('/*clone1*/') - if g.gen_clone_assignment(field.expr, field_type_sym, false) { - cloned = true + mut initialized := false + for i, field in struct_init.fields { + inited_fields[field.name] = i + if sym.kind != .struct_ { + field_name := c_name(field.name) + g.write('\t.$field_name = ') + field_type_sym := g.table.get_type_symbol(field.typ) + mut cloned := false + if g.autofree && field_type_sym.kind in [.array, .string] { + g.write('/*clone1*/') + if g.gen_clone_assignment(field.expr, field_type_sym, false) { + cloned = true + } } - } - if !cloned { - if field.expected_type.is_ptr() && !field.typ.is_ptr() && !field.typ.is_number() { - g.write('/* autoref */&') + if !cloned { + if field.expected_type.is_ptr() && !field.typ.is_ptr() && !field.typ.is_number() { + g.write('/* autoref */&') + } + g.expr_with_cast(field.expr, field.typ, field.expected_type) } - g.expr_with_cast(field.expr, field.typ, field.expected_type) + g.writeln(',') + initialized = true } - g.writeln(',') } // The rest of the fields are zeroed. mut nr_info_fields := 0 if sym.kind == .struct_ { info := sym.info as table.Struct + if info.is_union && struct_init.fields.len > 1 { + verror('union must not have more than 1 initializer') + } nr_info_fields = info.fields.len for field in info.fields { if field.name in inited_fields { + sfield := struct_init.fields[inited_fields[field.name]] + field_name := c_name(sfield.name) + g.write('\t.$field_name = ') + field_type_sym := g.table.get_type_symbol(sfield.typ) + mut cloned := false + if g.autofree && field_type_sym.kind in [.array, .string] { + g.write('/*clone1*/') + if g.gen_clone_assignment(sfield.expr, field_type_sym, false) { + cloned = true + } + } + if !cloned { + if sfield.expected_type.is_ptr() && !sfield.typ.is_ptr() && !sfield.typ.is_number() { + g.write('/* autoref */&') + } + g.expr_with_cast(sfield.expr, sfield.typ, sfield.expected_type) + } + g.writeln(',') + initialized = true + continue + } + if info.is_union { + // unions thould have exactly one explicit initializer continue } if field.typ.flag_is(.optional) { @@ -2302,11 +2355,12 @@ fn (mut g Gen) struct_init(struct_init ast.StructInit) { g.write(g.type_default(field.typ)) } g.writeln(',') + initialized = true } } // if struct_init.fields.len == 0 && info.fields.len == 0 { - if struct_init.fields.len == 0 && nr_info_fields == 0 { - g.write('0') + if !initialized { + g.write('\n#ifndef __cplusplus\n0\n#endif\n') } g.write('}') if is_amp { @@ -2322,21 +2376,22 @@ fn (mut g Gen) assoc(node ast.Assoc) { } styp := g.typ(node.typ) g.writeln('($styp){') + mut inited_fields := map[string]int for i, field in node.fields { - field_name := c_name(field) - g.write('\t.$field_name = ') - g.expr(node.exprs[i]) - g.writeln(', ') + inited_fields[field] = i } - // Copy the rest of the fields. + // Merge inited_fields in the rest of the fields. sym := g.table.get_type_symbol(node.typ) info := sym.info as table.Struct for field in info.fields { - if field.name in node.fields { - continue - } field_name := c_name(field.name) - g.writeln('\t.$field_name = ${node.var_name}.$field_name,') + if field.name in inited_fields { + g.write('\t.$field_name = ') + g.expr(node.exprs[inited_fields[field.name]]) + g.writeln(', ') + } else { + g.writeln('\t.$field_name = ${node.var_name}.$field_name,') + } } g.write('}') if g.is_amp { @@ -3422,19 +3477,19 @@ fn (mut g Gen) gen_str_for_type_with_styp(typ table.Type, styp string) string { fn (mut g Gen) gen_str_default(sym table.TypeSymbol, styp, str_fn_name string) { mut convertor := '' - mut typename := '' + mut typename_ := '' if sym.parent_idx in table.integer_type_idxs { convertor = 'int' - typename = 'int' + typename_ = 'int' } else if sym.parent_idx == table.f32_type_idx { convertor = 'float' - typename = 'f32' + typename_ = 'f32' } else if sym.parent_idx == table.f64_type_idx { convertor = 'double' - typename = 'f64' + typename_ = 'f64' } else if sym.parent_idx == table.bool_type_idx { convertor = 'bool' - typename = 'bool' + typename_ = 'bool' } else { verror("could not generate string method for type \'${styp}\'") } @@ -3443,7 +3498,7 @@ fn (mut g Gen) gen_str_default(sym table.TypeSymbol, styp, str_fn_name string) { if convertor == 'bool' { g.auto_str_funcs.writeln('\tstring tmp1 = string_add(tos_lit("${styp}("), (${convertor})it ? tos_lit("true") : tos_lit("false"));') } else { - g.auto_str_funcs.writeln('\tstring tmp1 = string_add(tos_lit("${styp}("), tos3(${typename}_str((${convertor})it).str));') + g.auto_str_funcs.writeln('\tstring tmp1 = string_add(tos_lit("${styp}("), tos3(${typename_}_str((${convertor})it).str));') } g.auto_str_funcs.writeln('\tstring tmp2 = string_add(tmp1, tos_lit(")"));') g.auto_str_funcs.writeln('\tstring_free(&tmp1);') @@ -3740,7 +3795,9 @@ fn (g &Gen) interface_table() string { mut methods_struct_def := strings.new_builder(100) methods_struct_def.writeln('$methods_struct_name {') mut imethods := map[string]string{} // a map from speak -> _Speaker_speak_fn - for method in ityp.methods { + mut methodidx := map[string]int + for k, method in ityp.methods { + methodidx[method.name] = k typ_name := '_${interface_name}_${method.name}_fn' ret_styp := g.typ(method.return_type) methods_typ_def.write('typedef $ret_styp (*$typ_name)(void* _') @@ -3786,7 +3843,14 @@ _Interface* I_${cctype}_to_Interface_${interface_name}_ptr(${cctype}* x) { }') methods_struct.writeln('\t{') st_sym := g.table.get_type_symbol(st) - for method in st_sym.methods { + mut method := table.Fn{} + for _, m in ityp.methods { + for mm in st_sym.methods { + if mm.name == m.name { + method = mm + break + } + } if method.name !in imethods { // a method that is not part of the interface should be just skipped continue @@ -3872,8 +3936,8 @@ fn (mut g Gen) array_init(it ast.ArrayInit) { return } len := it.exprs.len - g.write('new_array_from_c_array($len, $len, sizeof($elem_type_str), ') - g.write('($elem_type_str[$len]){\n\t\t') + g.write('new_array_from_c_array($len, $len, sizeof($elem_type_str), _MOV(($elem_type_str[$len]){') + g.writeln('') for i, expr in it.exprs { if it.is_interface { // sym := g.table.get_type_symbol(it.interface_types[i]) @@ -3886,7 +3950,8 @@ fn (mut g Gen) array_init(it ast.ArrayInit) { } g.write(', ') } - g.write('\n})') + g.writeln('') + g.write('}))') } // `ui.foo(button)` => diff --git a/vlib/v/gen/cheaders.v b/vlib/v/gen/cheaders.v index a771eca168..b48008ee44 100644 --- a/vlib/v/gen/cheaders.v +++ b/vlib/v/gen/cheaders.v @@ -391,9 +391,9 @@ typedef byte array_fixed_byte_300 [300]; typedef byte array_fixed_byte_400 [400]; #ifndef __cplusplus #ifndef bool - typedef int bool; - #define true 1 - #define false 0 + typedef int bool; + #define true 1 + #define false 0 #endif #endif diff --git a/vlib/v/gen/fn.v b/vlib/v/gen/fn.v index bde295a322..7865a4e62b 100644 --- a/vlib/v/gen/fn.v +++ b/vlib/v/gen/fn.v @@ -618,7 +618,7 @@ fn (mut g Gen) ref_or_deref_arg(arg ast.CallArg, expected_type table.Type) { } } if !g.is_json_fn { - g.write('&/*qq*/') + g.write('(voidptr)&/*qq*/') } } g.expr_with_cast(arg.expr, arg.typ, expected_type) diff --git a/vlib/v/gen/str.v b/vlib/v/gen/str.v index e66b05e8be..aa2e500113 100644 --- a/vlib/v/gen/str.v +++ b/vlib/v/gen/str.v @@ -23,7 +23,7 @@ void _STR_PRINT_ARG(const char *fmt, char** refbufp, int *nbytes, int *memsize, } // increase buffer (somewhat exponentially) *memsize += (*memsize + *memsize) / 3 + guess; - *refbufp = realloc(*refbufp, *memsize); + *refbufp = (char*)realloc((void*)*refbufp, *memsize); } } @@ -31,7 +31,7 @@ string _STR(const char *fmt, int nfmts, ...) { va_list argptr; int memsize = 128; int nbytes = 0; - char* buf = malloc(memsize); + char* buf = (char*)malloc(memsize); va_start(argptr, nfmts); for (int i=0; i 2 && parent_name[0] == `C` && parent_name[1] == `.` } is_public: is_pub }) diff --git a/vlib/v/table/atypes.v b/vlib/v/table/atypes.v index 2d45de3c7e..fbbfe05bf9 100644 --- a/vlib/v/table/atypes.v +++ b/vlib/v/table/atypes.v @@ -575,6 +575,7 @@ pub: pub struct Alias { pub: foo string + is_c bool } // NB: FExpr here is a actually an ast.Expr . diff --git a/vlib/v/tests/fn_test.v b/vlib/v/tests/fn_test.v index 9fc65f0181..f35b009616 100644 --- a/vlib/v/tests/fn_test.v +++ b/vlib/v/tests/fn_test.v @@ -96,7 +96,7 @@ fn test_mut_struct() { assert user.age == 19 } -fn mod_ptr(mut buf byteptr) { +fn mod_ptr(mut buf &byte) { buf[0] = 77 } diff --git a/vlib/v/token/position.v b/vlib/v/token/position.v index 8d953a60ac..e416364e5d 100644 --- a/vlib/v/token/position.v +++ b/vlib/v/token/position.v @@ -5,9 +5,9 @@ module token pub struct Position { pub: + len int // length of the literal in the source line_nr int // the line number in the source where the token occured pos int // the position of the token in scanner text - len int // length of the literal in the source } pub fn (pos Position) str() string { @@ -24,8 +24,8 @@ pub fn (pos Position) extend(end Position) Position { [inline] pub fn (tok &Token) position() Position { return Position{ + len: tok.len line_nr: tok.line_nr - 1 pos: tok.pos - len: tok.len } }