diff --git a/vlib/builtin/builtin_nix.c.v b/vlib/builtin/builtin_nix.c.v index eb38d53b6b..6648e3e3f6 100644 --- a/vlib/builtin/builtin_nix.c.v +++ b/vlib/builtin/builtin_nix.c.v @@ -88,7 +88,7 @@ fn print_backtrace_skipping_top_frames_linux(skipframes int) bool { return false } buffer := [100]byteptr{} - nr_ptrs := C.backtrace(buffer, 100) + nr_ptrs := C.backtrace(voidptr(buffer), 100) if nr_ptrs < 2 { eprintln('C.backtrace returned less than 2 frames') return false @@ -96,7 +96,7 @@ fn print_backtrace_skipping_top_frames_linux(skipframes int) bool { nr_actual_frames := nr_ptrs - skipframes mut sframes := []string{} //////csymbols := backtrace_symbols(*voidptr(&buffer[skipframes]), nr_actual_frames) - csymbols := C.backtrace_symbols(&buffer[skipframes], nr_actual_frames) + csymbols := C.backtrace_symbols(voidptr(&buffer[skipframes]), nr_actual_frames) for i in 0 .. nr_actual_frames { sframes << unsafe {tos2( byteptr(csymbols[i]) )} } diff --git a/vlib/builtin/map.v b/vlib/builtin/map.v index 89416b0c68..33bb510151 100644 --- a/vlib/builtin/map.v +++ b/vlib/builtin/map.v @@ -153,7 +153,7 @@ fn (d DenseArray) get(i int) voidptr { fn (mut d DenseArray) zeros_to_end() { mut tmp_value := malloc(d.value_bytes) mut count := u32(0) - for i in 0 .. d.len { + for i in 0 .. int(d.len) { if unsafe {d.keys[i]}.str != 0 { // swap keys unsafe { diff --git a/vlib/builtin/option.v b/vlib/builtin/option.v index 3c33c850d3..95f0c01945 100644 --- a/vlib/builtin/option.v +++ b/vlib/builtin/option.v @@ -19,7 +19,7 @@ struct OptionBase { ecode int // Data is trailing after ecode - // and is not included in here but in the + // and is not included in here but in the // derived Option_xxx types } @@ -51,13 +51,11 @@ struct Option { is_none bool error string ecode int - - data [400]byte } pub fn (o Option) str() string { if o.ok && !o.is_none { - return 'Option{ data: ' + o.data[0..32].hex() + ' }' + return 'Option{ ok }' } if o.is_none { return 'Option{ none }' @@ -65,20 +63,6 @@ pub fn (o Option) str() string { return 'Option{ error: "${o.error}" }' } -// `fn foo() ?Foo { return foo }` => `fn foo() ?Foo { return opt_ok(foo); }` -fn opt_ok(data voidptr, size int) Option { - if size >= 400 { - panic('option size too big: $size (max is 400), this is a temporary limit') - } - res := Option{ - ok: true - } - unsafe { - C.memcpy(res.data, data, size) - } - return res -} - // used internally when returning `none` fn opt_none() Option { return Option{ diff --git a/vlib/os/file.v b/vlib/os/file.v index 6ba940dcc0..08ac6a4970 100644 --- a/vlib/os/file.v +++ b/vlib/os/file.v @@ -142,7 +142,7 @@ pub fn (mut f File) get_line() ?string { mut zblen := size_t(0) mut zx := 0 unsafe { - zx = C.getline(&zbuf, &zblen, f.cfile) + zx = C.getline(&charptr(&zbuf), &zblen, f.cfile) if zx == -1 { C.free(zbuf) if C.errno == 0 { @@ -160,7 +160,7 @@ pub fn (mut f File) get_line() ?string { // buf := [4096]byte{} mut res := strings.new_builder(1024) - mut x := 0 + mut x := charptr(0) for { unsafe { x = C.fgets(charptr(buf), 4096, f.cfile) diff --git a/vlib/os/os_nix.c.v b/vlib/os/os_nix.c.v index 97cbdd758d..7c44662ea6 100644 --- a/vlib/os/os_nix.c.v +++ b/vlib/os/os_nix.c.v @@ -252,7 +252,7 @@ pub fn is_writable_folder(folder string) ?bool { } tmp_perm_check := os.join_path(folder, 'XXXXXX') unsafe { - x := C.mkstemp(tmp_perm_check.str) + x := C.mkstemp(charptr(tmp_perm_check.str)) if -1 == x { return error('folder `$folder` is not writable') } diff --git a/vlib/strconv/format.v b/vlib/strconv/format.v index 7af346a90b..2f2cffbccf 100644 --- a/vlib/strconv/format.v +++ b/vlib/strconv/format.v @@ -439,7 +439,6 @@ pub fn v_sprintf(str string, pt ... voidptr) string{ mut len1 := -1 // decimal part for floats def_len1 := 6 // default value for len1 mut pad_ch := byte(` `) // pad char - mut th_separator := false // thousands separator flag // prefix chars for Length field mut ch1 := `0` // +1 char if present else `0` @@ -453,7 +452,6 @@ pub fn v_sprintf(str string, pt ... voidptr) string{ len0 = -1 len1 = -1 pad_ch = ` ` - th_separator = false status = .norm_char ch1 = `0` ch2 = `0` @@ -518,7 +516,6 @@ pub fn v_sprintf(str string, pt ... voidptr) string{ i++ continue } else if ch == `'` { - th_separator = true i++ continue } else if ch == `.` && fc_ch1 >= `1` && fc_ch1 <= `9` { diff --git a/vlib/time/parse.v b/vlib/time/parse.v index 55fba7c77c..1bdf74074e 100644 --- a/vlib/time/parse.v +++ b/vlib/time/parse.v @@ -66,7 +66,7 @@ pub fn parse_iso8601(s string) ?Time { offset_hour := 0 offset_min := 0 count := unsafe {C.sscanf(charptr(s.str), '%4d-%2d-%2d%c%2d:%2d:%2d.%6d%c%2d:%2d', - &year, &month, &day, &time_char, &hour, &minute, &second, &mic_second, &plus_min, &offset_hour, + &year, &month, &day, charptr(&time_char), &hour, &minute, &second, &mic_second, charptr(&plus_min), &offset_hour, &offset_min)} if count != 11 { return error('Invalid 8601 format') diff --git a/vlib/v/builder/cc.v b/vlib/v/builder/cc.v index b847a6999e..f23f8858b6 100644 --- a/vlib/v/builder/cc.v +++ b/vlib/v/builder/cc.v @@ -76,6 +76,12 @@ fn (mut v Builder) find_win_cc() ? { v.pref.ccompiler_type = pref.cc_from_string(v.pref.ccompiler) } +fn (mut v Builder) show_c_compiler_output(res os.Result) { + println('======== C Compiler output ========') + println(res.output) + println('=================================') +} + fn (mut v Builder) post_process_c_compiler_output(res os.Result) { if res.exit_code == 0 { if v.pref.reuse_tmpc { @@ -545,6 +551,9 @@ fn (mut v Builder) cc() { } diff := time.ticks() - ticks v.timing_message('C ${ccompiler:3}', diff) + if v.pref.show_c_output { + v.show_c_compiler_output(res) + } if res.exit_code == 127 { // the command could not be found by the system $if linux { @@ -559,7 +568,9 @@ fn (mut v Builder) cc() { '-----------------------------------------------------------\n' + 'Probably your C compiler is missing. \n' + 'Please reinstall it, or make it available in your PATH.\n\n' + missing_compiler_info()) } - v.post_process_c_compiler_output(res) + if !v.pref.show_c_output { + v.post_process_c_compiler_output(res) + } // Print the C command if v.pref.is_verbose { println('$ccompiler took $diff ms') diff --git a/vlib/v/builder/msvc.v b/vlib/v/builder/msvc.v index 0ffe671353..a7bcf1b239 100644 --- a/vlib/v/builder/msvc.v +++ b/vlib/v/builder/msvc.v @@ -303,7 +303,11 @@ pub fn (mut v Builder) cc_msvc() { } diff := time.ticks() - ticks v.timing_message('C msvc', diff) - v.post_process_c_compiler_output(res) + if v.pref.show_c_output { + v.show_c_compiler_output(res) + } else { + v.post_process_c_compiler_output(res) + } // println(res) // println('C OUTPUT:') // Always remove the object file - it is completely unnecessary diff --git a/vlib/v/gen/cgen.v b/vlib/v/gen/cgen.v index 976c4c6523..4eae5c7169 100644 --- a/vlib/v/gen/cgen.v +++ b/vlib/v/gen/cgen.v @@ -1440,7 +1440,6 @@ fn (mut g Gen) gen_assign_stmt(assign_stmt ast.AssignStmt) { // return; // } // int pos = *(int*)_t190.data; - mut gen_or := false mut tmp_opt := '' is_optional := g.pref.autofree && (assign_stmt.op in [.decl_assign, .assign]) && assign_stmt.left_types.len == 1 && assign_stmt.right[0] is @@ -1453,7 +1452,6 @@ fn (mut g Gen) gen_assign_stmt(assign_stmt ast.AssignStmt) { tmp_opt = g.new_tmp_var() g.write('/*AF opt*/$styp $tmp_opt = ') g.expr(assign_stmt.right[0]) - gen_or = true g.or_block(tmp_opt, call_expr.or_block, call_expr.return_type) g.writeln('/*=============ret*/') // if af && is_optional { @@ -2128,7 +2126,11 @@ fn (mut g Gen) expr(node ast.Expr) { g.write('))') } ast.CharLiteral { - g.write("'$node.val'") + if node.val == r'\`' { + g.write("'`'") + } else { + g.write("'$node.val'") + } } ast.AtExpr { g.comp_at(node) @@ -4662,7 +4664,7 @@ fn (mut g Gen) gen_array_sort(node ast.CallExpr) { g.expr(node.left) g.write('${deref}len, ') g.expr(node.left) - g.writeln('${deref}element_size, $compare_fn);') + g.writeln('${deref}element_size, (int (*)(const void *, const void *))&$compare_fn);') } // `nums.filter(it % 2 == 0)` @@ -5060,7 +5062,15 @@ fn c_name(name_ string) string { return name } -fn (mut g Gen) type_default(typ table.Type) string { +fn (mut g Gen) type_default(typ_ table.Type) string { + typ := g.unwrap_generic(typ_) + if typ.has_flag(.optional) { + return '{0}' + } + // Always set pointers to 0 + if typ.is_ptr() { + return '0' + } sym := g.table.get_type_symbol(typ) if sym.kind == .array { elem_sym := g.typ(sym.array_info().elem_type) @@ -5074,10 +5084,6 @@ fn (mut g Gen) type_default(typ table.Type) string { value_type_str := g.typ(sym.map_info().value_type) return 'new_map_1(sizeof($value_type_str))' } - // Always set pointers to 0 - if typ.is_ptr() { - return '0' - } // User struct defined in another module. // if typ.contains('__') { if sym.kind == .struct_ { @@ -5105,7 +5111,8 @@ fn (mut g Gen) type_default(typ table.Type) string { else {} } return match sym.kind { - .interface_, .sum_type, .array_fixed { '{0}' } + .interface_, .sum_type, .array_fixed, .multi_return { '{0}' } + .alias { g.type_default((sym.info as table.Alias).parent_type) } else { '0' } } // TODO this results in diff --git a/vlib/v/gen/cheaders.v b/vlib/v/gen/cheaders.v index 135519fc52..c572d75229 100644 --- a/vlib/v/gen/cheaders.v +++ b/vlib/v/gen/cheaders.v @@ -67,6 +67,10 @@ const ( #undef TCCSKIP #define TCCSKIP(x) // #include + #ifndef _WIN32 + #include + int tcc_backtrace(const char *fmt, ...); + #endif #endif // for __offset_of @@ -431,20 +435,7 @@ typedef double any_float; typedef unsigned char* byteptr; typedef void* voidptr; typedef char* charptr; -typedef struct array array; -typedef struct map map; -typedef array array_int; -typedef array array_f32; -typedef array array_f64; -typedef array array_u16; -typedef array array_u32; -typedef array array_u64; -//typedef map map_int; -//typedef map map_string; -//typedef array array_string; -//typedef array array_byte; typedef byte array_fixed_byte_300 [300]; -typedef byte array_fixed_byte_400 [400]; typedef struct sync__Channel* chan; diff --git a/vlib/v/gen/fn.v b/vlib/v/gen/fn.v index 56f9914ee0..317df8e33e 100644 --- a/vlib/v/gen/fn.v +++ b/vlib/v/gen/fn.v @@ -158,6 +158,15 @@ fn (mut g Gen) gen_fn_decl(it ast.FnDecl, skip bool) { // TODO: remove this, when g.write_autofree_stmts_when_needed works properly g.autofree_scope_vars(it.body_pos.pos) } + if it.return_type != table.void_type { + mut default_expr := g.type_default(it.return_type) + // TODO: perf? + if default_expr == '{0}' { + g.writeln('\treturn ($type_name)$default_expr;') + } else { + g.writeln('\treturn $default_expr;') + } + } g.writeln('}') g.defer_stmts = [] if g.pref.printfn_list.len > 0 && g.last_fn_c_name in g.pref.printfn_list { @@ -240,15 +249,7 @@ fn (mut g Gen) fn_args(args []table.Param, is_variadic bool) ([]string, []string g.definitions.write(')') } } else { - mut nr_muls := arg.typ.nr_muls() s := arg_type_name + ' ' + caname - if arg.is_mut { - // mut arg needs one * - nr_muls = 1 - } - // if nr_muls > 0 && !is_varg { - // s = arg_type_name + strings.repeat(`*`, nr_muls) + ' ' + caname - // } g.write(s) g.definitions.write(s) fargs << caname diff --git a/vlib/v/gen/str.v b/vlib/v/gen/str.v index 34d81abcde..b72185bbfd 100644 --- a/vlib/v/gen/str.v +++ b/vlib/v/gen/str.v @@ -6,6 +6,10 @@ import v.ast import v.table import strings +const ( + invalid_escapes = ['(', '{', '$', '`', '.'] +) + fn smart_quote(str string, raw bool) string { len := str.len if len == 0 { @@ -14,6 +18,7 @@ fn smart_quote(str string, raw bool) string { mut result := strings.new_builder(0) mut pos := -1 mut last := '' + // TODO: This should be a single char? mut next := '' mut skip_next := false for { @@ -43,45 +48,43 @@ fn smart_quote(str string, raw bool) string { toadd = '\\"' current = '' } - if raw && current == '\\' { - toadd = '\\\\' - } - // keep newlines in string - if current == '\n' { - toadd = '\\n' - current = '' - } - if current == '\r' && next == '\n' { - toadd = '\r\n' - current = '' - skip_next = true - } - // backslash - if !raw && current == '\\' { - // escaped backslash - keep as is - if next == '\\' { + if current == '\\' { + if raw { toadd = '\\\\' - skip_next = true - } - // keep raw escape squence - else { - if next != '' { + } else { + // escaped backslash - keep as is + if next == '\\' { + toadd = '\\\\' + skip_next = true + } else if next != '' { if raw { toadd = '\\\\' + next skip_next = true } - // escape it - else { + // keep all valid escape sequences + else if next !in invalid_escapes { toadd = '\\' + next skip_next = true + } else { + toadd = next + skip_next = true } } } } + // keep newlines in string + if current == '\n' { + toadd = '\\n' + current = '' + } else if current == '\r' && next == '\n' { + toadd = '\r\n' + current = '' + skip_next = true + } // Dolar sign if !raw && current == '$' { if last == '\\' { - toadd = '\\$' + toadd = r'\$' } } // Windows style new line \r\n diff --git a/vlib/v/parser/parser.v b/vlib/v/parser/parser.v index 4eee4d451d..5cb75b82bb 100644 --- a/vlib/v/parser/parser.v +++ b/vlib/v/parser/parser.v @@ -922,6 +922,7 @@ pub fn (mut p Parser) parse_ident(language table.Language) ast.Ident { } else { p.error('unexpected token `$p.tok.lit`') } + return ast.Ident{} } pub fn (mut p Parser) name_expr() ast.Expr { diff --git a/vlib/v/pref/pref.v b/vlib/v/pref/pref.v index b110438003..419ad90b06 100644 --- a/vlib/v/pref/pref.v +++ b/vlib/v/pref/pref.v @@ -73,6 +73,7 @@ pub mut: is_debug bool // false by default, turned on by -g or -cg, it tells v to pass -g to the C backend compiler. is_vlines bool // turned on by -g, false by default (it slows down .tmp.c generation slightly). show_cc bool // -showcc, print cc command + show_c_output bool // -show-c-output, print all cc output even if the code was compiled correctly // NB: passing -cg instead of -g will set is_vlines to false and is_debug to true, thus making v generate cleaner C files, // which are sometimes easier to debug / inspect manually than the .tmp.c files by plain -g (when/if v line number generation breaks). use_cache bool // turns on v usage of the module cache to speed up compilation. @@ -243,6 +244,9 @@ pub fn parse_args(args []string) (&Preferences, string) { '-showcc' { res.show_cc = true } + '-show-c-output' { + res.show_c_output = true + } '-experimental' { res.experimental = true } @@ -253,9 +257,6 @@ pub fn parse_args(args []string) (&Preferences, string) { res.prealloc = true res.build_options << arg } - '-keepc' { - eprintln('-keepc is deprecated. V always keeps the generated .tmp.c files now.') - } '-parallel' { res.is_parallel = true } diff --git a/vlib/v/table/atypes.v b/vlib/v/table/atypes.v index 83928c9482..5b2703d142 100644 --- a/vlib/v/table/atypes.v +++ b/vlib/v/table/atypes.v @@ -865,7 +865,6 @@ pub fn (table &Table) type_to_str(t Type) string { res += table.type_to_str(typ) } res += ')' - res = res } .void { if t.has_flag(.optional) {