diff --git a/vlib/compiler/comptime.v b/vlib/compiler/comptime.v index 5d353a011c..b12a6b185b 100644 --- a/vlib/compiler/comptime.v +++ b/vlib/compiler/comptime.v @@ -89,8 +89,10 @@ fn (p mut Parser) comp_time() { p.returns = false //p.gen('/* returns $p.returns */') if p.tok == .dollar && p.peek() == .key_else { + p.fspace() p.next() p.next() + p.fspace() // spaces before and after $else p.check(.lcbr) p.genln('#else') p.statements_no_rcbr() diff --git a/vlib/compiler/expression.v b/vlib/compiler/expression.v index f0f37df7a4..08326b3a06 100644 --- a/vlib/compiler/expression.v +++ b/vlib/compiler/expression.v @@ -58,10 +58,11 @@ fn (p mut Parser) bterm() string { if tok in [.eq, .gt, .lt, .le, .ge, .ne] { //TODO: remove when array comparing is supported if is_array { - p.error('Array comparing is not supported yet') + p.error('array comparing is not supported yet') } - p.fgen(' ${p.tok.str()} ') + p.fspace() + //p.fgen(' ${p.tok.str()} ') if (is_float || is_str || is_ustr) && !p.is_js { p.gen(',') } @@ -72,6 +73,7 @@ fn (p mut Parser) bterm() string { p.gen(tok.str()) } p.next() + p.fspace() // `id == user.id` => `id == $1`, `user.id` if p.is_sql { p.sql_i++ @@ -140,7 +142,6 @@ fn (p mut Parser) name_expr() string { p.string_expr() return 'string' } - p.fgen(name) // known_type := p.table.known_type(name) orig_name := name is_c := name == 'C' && p.peek() == .dot @@ -190,7 +191,6 @@ fn (p mut Parser) name_expr() string { p.next() p.check(.dot) name = p.lit - p.fgen(name) name = prepend_mod(mod_gen_name(mod), name) } // Unknown name, try prepending the module name to it @@ -463,7 +463,7 @@ fn (p mut Parser) handle_operator(op string, typ string, cpostfix string, ph int else { p.error('operator $op not defined on `$typ`') } -} +} fn (p mut Parser) term() string { line_nr := p.scanner.line_nr @@ -484,10 +484,11 @@ fn (p mut Parser) term() string { is_mul := tok == .mul is_div := tok == .div is_mod := tok == .mod + p.fspace() p.next() p.gen(tok.str())// + ' /*op2*/ ') oph := p.cgen.add_placeholder() - p.fgen(' ' + tok.str() + ' ') + p.fspace() if (is_div || is_mod) && p.tok == .number && p.lit == '0' { p.error('division or modulo by zero') } @@ -575,11 +576,9 @@ fn (p mut Parser) factor() string { p.error('constant `$p.lit` overflows `$p.expected_type`') } p.gen(p.lit) - p.fgen(p.lit) } .minus { p.gen('-') - p.fgen('-') p.next() return p.factor() // Variable diff --git a/vlib/compiler/fn.v b/vlib/compiler/fn.v index bbed6297d9..c367ec6ce1 100644 --- a/vlib/compiler/fn.v +++ b/vlib/compiler/fn.v @@ -179,8 +179,7 @@ fn (p mut Parser) clear_vars() { // Function signatures are added to the top of the .c file in the first run. fn (p mut Parser) fn_decl() { p.clear_vars() // clear local vars every time a new fn is started - - //defer { p.fgenln('\n') } + defer { p.fgenln2('\n') } // If we are in the first pass, create a new function. // In the second pass fetch the one we created. /* @@ -206,6 +205,7 @@ fn (p mut Parser) fn_decl() { } if is_pub { p.next() + p.fspace() } p.returns = false //p.gen('/* returns $p.returns */') @@ -218,10 +218,12 @@ fn (p mut Parser) fn_decl() { f.is_method = true p.check(.lpar) receiver_name := p.check_name() + p.fspace() is_mut := p.tok == .key_mut is_amp := p.tok == .amp if is_mut || is_amp { - p.check_space(p.tok) + p.check(p.tok) + p.fspace() } receiver_typ = p.get_type() t := p.table.find_type(receiver_typ) @@ -350,7 +352,7 @@ fn (p mut Parser) fn_decl() { // Returns a type? mut typ := 'void' if p.tok in [.name, .mul, .amp, .lsbr, .question, .lpar] { - p.fgen(' ') + p.fspace() typ = p.get_type() } // V allows empty functions (just definitions) @@ -1568,9 +1570,9 @@ pub fn (f &Fn) v_fn_name() string { pub fn (f &Fn) str_for_error() string { // Build the args for the error - mut s := '' - for i, a in f.args { - if i == 0 { + mut s := '' + for i, a in f.args { + if i == 0 { if f.is_method { s += a.typ + '.' + f.name + '(' continue @@ -1581,7 +1583,7 @@ pub fn (f &Fn) str_for_error() string { if i < f.args.len - 1 { s += ', ' } - } + } return s + ')' } diff --git a/vlib/compiler/for.v b/vlib/compiler/for.v index e884666eef..fddbf8946d 100644 --- a/vlib/compiler/for.v +++ b/vlib/compiler/for.v @@ -6,7 +6,7 @@ module compiler fn (p mut Parser) for_st() { p.check(.key_for) - p.fgen(' ') + p.fspace() p.for_expr_cnt++ next_tok := p.peek() //debug := p.scanner.file_path.contains('r_draw') @@ -32,13 +32,13 @@ fn (p mut Parser) for_st() { } p.check(.semicolon) p.gen(' ; ') - p.fgen(' ') + p.fspace() if p.tok != .semicolon { p.bool_expression() } p.check(.semicolon) p.gen(' ; ') - p.fgen(' ') + p.fspace() if p.tok != .lcbr { p.statement(false) } @@ -61,9 +61,9 @@ fn (p mut Parser) for_st() { if i == '_' && val == '_' { p.error('no new variables on the left side of `in`') } - p.fgen(' ') + p.fspace() p.check(.key_in) - p.fgen(' ') + p.fspace() tmp := p.get_tmp() p.cgen.start_tmp() mut typ := p.bool_expression() @@ -121,7 +121,7 @@ fn (p mut Parser) for_st() { // `for val in vals` else if p.peek() == .key_in { val := p.check_name() - p.fgen(' ') + p.fspace() p.check(.key_in) p.fspace() tmp := p.get_tmp() diff --git a/vlib/compiler/main.v b/vlib/compiler/main.v index a2922f4530..55152f6bc5 100644 --- a/vlib/compiler/main.v +++ b/vlib/compiler/main.v @@ -117,6 +117,7 @@ pub mut: comptime_define string // -D vfmt for `if $vfmt {` fast bool // use tcc/x64 codegen enable_globals bool // allow __global for low level code + is_fmt bool } // Should be called by main at the end of the compilation process, to cleanup @@ -946,6 +947,7 @@ pub fn new_v(args[]string) &V { ccompiler: find_c_compiler() building_v: !is_repl && (rdir_name == 'compiler' || rdir_name == 'v.v' || dir.contains('vlib')) comptime_define: comptime_define + is_fmt: comptime_define == 'vfmt' } if pref.is_verbose || pref.is_debug { println('C compiler=$pref.ccompiler') diff --git a/vlib/compiler/parser.v b/vlib/compiler/parser.v index a5ea3dcb84..b32c1fb40a 100644 --- a/vlib/compiler/parser.v +++ b/vlib/compiler/parser.v @@ -279,6 +279,7 @@ fn (p mut Parser) parse(pass Pass) { p.mod = p.check_name() } // + p.fgenln2('\n') p.cgen.nogen = false if p.pref.build_mode == .build_module && p.mod != p.v.mod { @@ -392,6 +393,7 @@ fn (p mut Parser) parse(pass Pass) { //p.error('__global is only allowed in translated code') } p.next() + p.fspace() name := p.check_name() typ := p.get_type() p.register_global(name, typ) @@ -408,6 +410,11 @@ fn (p mut Parser) parse(pass Pass) { if !p.cgen.nogen { p.cgen.consts << g } + p.fgenln2('') + if p.tok != .key_global { + // An extra empty line to separate a block of globals + p.fgenln2('') + } } .eof { //p.log('end of parse()') @@ -420,19 +427,7 @@ fn (p mut Parser) parse(pass Pass) { if !p.first_pass() && !p.pref.is_repl { p.check_unused_imports() } - if !p.first_pass() && p.fileis('main.v') { - s := p.scanner.fmt_out.str().trim_space() - if s.len > 0 { - println('GENERATING MAIN.V') - out := os.create('/var/tmp/fmt.v') or { - verror('failed to create fmt.v') - return - } - //println(p.scanner.fmt_out.str()) - out.writeln(p.scanner.fmt_out.str().trim_space()) - out.close() - } - } + p.gen_fmt() // not generated unless `-d vfmt` is provided return } else { @@ -720,8 +715,15 @@ fn (p &Parser) strtok() string { if p.tok == .name { return p.lit } + if p.tok == .number { + return p.lit + } if p.tok == .str { - return '"$p.lit"' + if p.lit.contains("'") { + return '"$p.lit"' + } else { + return "'$p.lit'" + } } res := p.tok.str() if res == '' { @@ -782,6 +784,8 @@ fn (p mut Parser) get_type() string { mut typ := '' // multiple returns if p.tok == .lpar { + //p.warn('`()` are no longer necessary in multiple returns' + + //'\nuse `fn foo() int, int {` instead of `fn foo() (int, int) {`') // if p.inside_tuple {p.error('unexpected (')} // p.inside_tuple = true p.check(.lpar) @@ -1270,9 +1274,8 @@ fn ($v.name mut $v.typ) $p.cur_fn.name (...) { } } p.fspace() - p.fgen(tok.str()) - p.fspace() p.next() + p.fspace() pos := p.cgen.cur_line.len expr_type := p.bool_expression() //if p.expected_type.starts_with('array_') { @@ -1633,7 +1636,6 @@ fn (p mut Parser) var_expr(v Var) string { } } p.gen(p.tok.str()) - p.fgen(p.tok.str()) p.next()// ++/-- // allow `a := c++` in translated code TODO remove once c2v handles this if p.pref.translated { @@ -2541,9 +2543,10 @@ fn (p mut Parser) if_st(is_expr bool, elif_depth int) string { } if_returns := p.returns p.returns = false - // println('IF TYp=$typ') if p.tok == .key_else { - p.fgenln2('') + if !p.inside_if_expr { + p.fgenln2('') + } p.check(.key_else) p.fspace() if p.tok == .key_if { @@ -2730,6 +2733,7 @@ fn (p mut Parser) return_st() { p.gen('return') } } + p.fgenln('//ret') p.returns = true } @@ -2876,6 +2880,7 @@ fn (p mut Parser) attribute() { p.attr = p.attr + ':' + p.check_name() } p.check(.rsbr) + p.fgenln2('') if p.tok == .key_fn || (p.tok == .key_pub && p.peek() == .key_fn) { p.fn_decl() p.attr = '' diff --git a/vlib/compiler/scanner.v b/vlib/compiler/scanner.v index 432a6266d1..7c1ccf2eee 100644 --- a/vlib/compiler/scanner.v +++ b/vlib/compiler/scanner.v @@ -76,7 +76,7 @@ fn new_scanner_file(file_path string) &Scanner { fn new_scanner(text string) &Scanner { return &Scanner { text: text - fmt_out: strings.new_builder(1000) + fmt_out: strings.new_builder(10000) should_print_line_on_error: true should_print_errors_in_color: true should_print_relative_paths_on_error: true @@ -481,7 +481,7 @@ fn (s mut Scanner) scan() ScanRes { if nextc == `!` { // treat shebang line (#!) as a comment s.line_comment = s.text[start + 1..s.pos].trim_space() - s.fgenln('// shebang line "$s.line_comment"') + //s.fgenln('// shebang line "$s.line_comment"') return s.scan() } hash := s.text[start..s.pos] @@ -585,7 +585,7 @@ fn (s mut Scanner) scan() ScanRes { s.ignore_line() s.line_comment = s.text[start + 1..s.pos] s.line_comment = s.line_comment.trim_space() - s.fgenln('// ${s.prev_tok.str()} "$s.line_comment"') + //s.fgenln('// ${s.prev_tok.str()} "$s.line_comment"') // Skip the comment (return the next token) return s.scan() } @@ -810,7 +810,7 @@ fn (s mut Scanner) inc_line_number() { s.last_nl_pos = s.pos s.line_nr++ s.line_ends << s.pos - if s.line_nr > s.nlines { + if s.line_nr > s.nlines { s.nlines = s.line_nr } } diff --git a/vlib/compiler/struct.v b/vlib/compiler/struct.v index fc914ea891..cf12ce48a4 100644 --- a/vlib/compiler/struct.v +++ b/vlib/compiler/struct.v @@ -9,6 +9,7 @@ fn (p mut Parser) struct_decl() { is_pub := p.tok == .key_pub if is_pub { p.next() + p.fspace() } // V can generate Objective C for integration with Cocoa // `[objc_interface:ParentInterface]` @@ -220,7 +221,7 @@ fn (p mut Parser) struct_decl() { if p.first_pass() { p.table.add_field(typ.name, field_name, field_type, is_mut, attr, access_mod) } - p.fgenln2('') + p.fgenln2('') // newline between struct fields } p.check(.rcbr) if !is_c && !did_gen_something && p.first_pass() { @@ -272,6 +273,7 @@ fn (p mut Parser) struct_init(typ string) string { } p.fspace() did_gen_something = true + p.fgenln2('') // newline between struct fields } // If we already set some fields, need to prepend a comma if t.fields.len != inited_fields.len && inited_fields.len > 0 { @@ -308,6 +310,7 @@ fn (p mut Parser) struct_init(typ string) string { p.gen(',') } did_gen_something = true + p.fgenln2('') // newline between struct fields } } } diff --git a/vlib/compiler/token.v b/vlib/compiler/token.v index e28e0e2c25..fd39635c92 100644 --- a/vlib/compiler/token.v +++ b/vlib/compiler/token.v @@ -286,6 +286,10 @@ fn (t []TokenKind) contains(val TokenKind) bool { } fn (t Token) str() string { + if t.tok == .number { + return t.lit + + } if t.tok == .str { return "'$t.lit'" } diff --git a/vlib/compiler/vfmt.v b/vlib/compiler/vfmt.v index 1316b0bb29..c4c996d357 100644 --- a/vlib/compiler/vfmt.v +++ b/vlib/compiler/vfmt.v @@ -5,6 +5,7 @@ module compiler import strings +import os [if vfmt] fn (scanner mut Scanner) fgen(s_ string) { @@ -93,14 +94,37 @@ fn (p mut Parser) fnext() { if p.tok == .eof { return } - if p.tok == .rcbr { + if p.tok == .rcbr && !p.inside_if_expr { p.fmt_dec() } p.fgen2(p.strtok()) // vfmt: increase indentation on `{` unless it's `{}` - if p.tok == .lcbr { //&& p.scanner.pos + 1 < p.scanner.text.len && p.scanner.text[p.scanner.pos + 1] != `}` { + if p.tok == .lcbr && !p.inside_if_expr { //&& p.scanner.pos + 1 < p.scanner.text.len && p.scanner.text[p.scanner.pos + 1] != `}` { p.fgenln2('') p.fmt_inc() } } + +[if vfmt] +fn (p mut Parser) gen_fmt() { + if p.pass != .main { + return + } + if p.file_name == '' { + return + } + s := p.scanner.fmt_out.str().trim_space() + if s == '' { + return + } + println('GENERATING ${p.file_name}.V') + out := os.create('/var/tmp/fmt/' + p.file_name) or { + verror('failed to create fmt.v') + return + } + //println(p.scanner.fmt_out.str()) + out.writeln(p.scanner.fmt_out.str().trim_space()) + out.close() +} + diff --git a/vlib/os/os.v b/vlib/os/os.v index 84778806d5..a44a6b498d 100644 --- a/vlib/os/os.v +++ b/vlib/os/os.v @@ -157,7 +157,7 @@ pub fn cp_r(source_path, dest_path string, overwrite bool) ?bool{ } //single file copy if !os.is_dir(source_path) { - adjasted_path := if os.is_dir(dest_path) { + adjasted_path := if os.is_dir(dest_path) { filepath.join(dest_path, os.basedir(source_path)) } else { dest_path } if os.file_exists(adjasted_path) { if overwrite { os.rm(adjasted_path) } @@ -178,7 +178,7 @@ pub fn cp_r(source_path, dest_path string, overwrite bool) ?bool{ } cp_r(sp, dp, overwrite) or { os.rmdir(dp) - panic(err) + panic(err) } } return true