diff --git a/vlib/compiler/compile_errors.v b/vlib/compiler/compile_errors.v index a14ac77506..8e270b3e24 100644 --- a/vlib/compiler/compile_errors.v +++ b/vlib/compiler/compile_errors.v @@ -51,6 +51,9 @@ fn (p mut Parser) error_with_position(s string, sp ScannerPos) { } fn (p mut Parser) warn_with_position(s string, sp ScannerPos) { + if p.scanner.is_fmt { + return + } // on a warning, restore the scanner state after printing the warning: cpos := p.scanner.get_scanner_pos() e := normalized_error( s ) diff --git a/vlib/compiler/fn.v b/vlib/compiler/fn.v index 7c2bae4dff..a626b30679 100644 --- a/vlib/compiler/fn.v +++ b/vlib/compiler/fn.v @@ -195,7 +195,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.fgen_nl() p.fgen_nl() } fn_start_idx := p.cur_tok_index() // If we are in the first pass, create a new function. // In the second pass fetch the one we created. @@ -477,7 +477,7 @@ fn (p mut Parser) fn_decl() { p.fgen_nl() } if is_c { - p.fgenln('\n') + p.fgen_nl() } // Register the method if receiver_typ != '' { diff --git a/vlib/compiler/for.v b/vlib/compiler/for.v index 5ba2dfaa16..97316d2890 100644 --- a/vlib/compiler/for.v +++ b/vlib/compiler/for.v @@ -6,9 +6,11 @@ module compiler fn (p mut Parser) for_st() { p.check(.key_for) - p.fspace() p.for_expr_cnt++ next_tok := p.peek() + if p.tok != .lcbr { + p.fspace() + } //debug := p.scanner.file_path.contains('r_draw') p.open_scope() mut label := 0 diff --git a/vlib/compiler/parser.v b/vlib/compiler/parser.v index 26ed66a4cd..77e69e2e52 100644 --- a/vlib/compiler/parser.v +++ b/vlib/compiler/parser.v @@ -20,7 +20,6 @@ struct Parser { file_pcguard string v &V pref &Preferences // Preferences shared from V struct - kek string mut: scanner &Scanner tokens []Token @@ -44,7 +43,7 @@ mut: tmp_cnt int builtin_mod bool inside_if_expr bool - inside_unwrapping_match_statement bool + //inside_unwrapping_match bool inside_return_expr bool inside_unsafe bool is_struct_init bool @@ -60,7 +59,7 @@ mut: returns bool vroot string is_c_struct_init bool - is_empty_c_struct_init bool + is_empty_c_struct_init bool // for `foo := C.Foo{}` => `Foo foo;` is_c_fn_call bool can_chash bool attr string @@ -112,9 +111,11 @@ struct ParserState { // new parser from string. unique id specified in `id`. // tip: use a hashing function to auto generate `id` from `text` eg. sha1.hexhash(text) fn (v mut V) new_parser_from_string(text string) Parser { + // line comment 1 mut p := v.new_parser(new_scanner(text)) - p.scan_tokens() + p.scan_tokens() // same line comment return p + // final comment } fn (v mut V) reset_cgen_file_line_parameters(){ @@ -277,6 +278,7 @@ fn (p &Parser) peek() TokenKind { } fn (p &Parser) log(s string) { + 123 // vfmt /* if !p.pref.is_verbose { return @@ -738,6 +740,8 @@ fn (p mut Parser) const_decl() { p.fmt_dec() p.check(.rpar) p.inside_const = false + p.fgen_nl() + p.fgen_nl() } // `type myint int` @@ -1131,6 +1135,7 @@ fn (p mut Parser) statements_no_rcbr() string { // println('last st typ=$last_st_typ') if !p.inside_if_expr { //p.genln('')// // end st tok= ${p.strtok()}') + //p.fgenln('// ST') p.fgen_nl() } i++ diff --git a/vlib/compiler/scanner.v b/vlib/compiler/scanner.v index 460ee3cd29..c7c6f4d96e 100644 --- a/vlib/compiler/scanner.v +++ b/vlib/compiler/scanner.v @@ -6,7 +6,7 @@ module compiler import ( os - strings + //strings ) const ( @@ -29,10 +29,13 @@ mut: debug bool line_comment string started bool - // vfmt fields - fmt_out strings.Builder + // vfmt fields TODO move to a separate struct + //fmt_out strings.Builder + fmt_lines []string + //fmt_line string fmt_indent int fmt_line_empty bool + //fmt_needs_nl bool prev_tok TokenKind fn_name string // needed for @FN should_print_line_on_error bool @@ -79,7 +82,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(1000) should_print_line_on_error: true should_print_errors_in_color: true should_print_relative_paths_on_error: true diff --git a/vlib/compiler/struct.v b/vlib/compiler/struct.v index dd8264b86b..9ea2725858 100644 --- a/vlib/compiler/struct.v +++ b/vlib/compiler/struct.v @@ -4,6 +4,10 @@ module compiler +import ( + strings +) + // also unions and interfaces fn (p mut Parser) struct_decl() { is_pub := p.tok == .key_pub @@ -113,16 +117,7 @@ fn (p mut Parser) struct_decl() { //mut is_pub_field := false //mut is_mut := false mut names := []string// to avoid dup names TODO alloc perf - mut fmt_max_len := 0 - // TODO why is typ.fields == 0? - if p.scanner.is_fmt && p.pass == .main { - for field in typ.fields { - println(field.name) - if field.name.len > fmt_max_len { - fmt_max_len = field.name.len - } - } - } + mut fmt_max_len := p.table.max_field_len[name] //println('fmt max len = $max_len nrfields=$typ.fields.len pass=$p.pass') if !is_ph && p.first_pass() { p.table.register_type(typ) @@ -135,8 +130,10 @@ fn (p mut Parser) struct_decl() { i++ mut new_access_mod := access_mod if p.tok == .key_pub { + p.fmt_dec() p.check(.key_pub) if p.tok == .key_mut { + p.fspace() new_access_mod = .public_mut p.next() // skip `mut` } else { @@ -145,7 +142,6 @@ fn (p mut Parser) struct_decl() { if new_access_mod in used { p.error('structs can only have one `pub:`/`pub mut:`, all public fields have to be grouped') } - p.fmt_dec() p.check(.colon) p.fmt_inc() p.fgen_nl() @@ -183,15 +179,16 @@ fn (p mut Parser) struct_decl() { // Check if reserved name field_name_token_idx := p.cur_tok_index() field_name := if name != 'Option' && !is_interface { p.table.var_cgen_name(p.check_name()) } else { p.check_name() } - /* - if !p.first_pass() { + if p.pass == .main { p.fgen(strings.repeat(` `, fmt_max_len - field_name.len)) } - */ // Check dups if field_name in names { p.error('duplicate field `$field_name`') } + if p.scanner.is_fmt && p.pass == .decl && field_name.len > fmt_max_len { + fmt_max_len = field_name.len + } if !is_c && p.mod != 'os' && contains_capital(field_name) { p.error('struct fields cannot contain uppercase letters, use snake_case instead') } @@ -265,11 +262,17 @@ fn (p mut Parser) struct_decl() { } p.fgen_nl() // newline between struct fields } + if p.scanner.is_fmt && p.pass == .decl { + p.table.max_field_len[typ.name] = fmt_max_len + } + //p.fgen_require_nl() p.check(.rcbr) if !is_c && !did_gen_something && p.first_pass() { p.table.add_field(typ.name, '', 'EMPTY_STRUCT_DECLARATION', false, '', .private) } - p.fgenln('\n') + p.fgen_nl() + p.fgen_nl() + //p.fgenln('//kek') } // `User{ foo: bar }` diff --git a/vlib/compiler/table.v b/vlib/compiler/table.v index bf57554cf1..9013e259b7 100644 --- a/vlib/compiler/table.v +++ b/vlib/compiler/table.v @@ -20,6 +20,7 @@ pub mut: varg_access []VargAccess //enum_vals map[string][]string //names []Name + max_field_len map[string]int // for vfmt: max_field_len['Parser'] == 12 } struct VargAccess { @@ -120,6 +121,7 @@ pub mut: is_placeholder bool gen_str bool // needs `.str()` method generation is_flag bool // enum bitfield flag + //max_field_len int } struct TypeNode { diff --git a/vlib/compiler/vfmt.v b/vlib/compiler/vfmt.v index bed40074ef..31c96e216d 100644 --- a/vlib/compiler/vfmt.v +++ b/vlib/compiler/vfmt.v @@ -11,11 +11,12 @@ import os fn (scanner mut Scanner) fgen(s_ string) { mut s := s_ if scanner.fmt_line_empty { - s = strings.repeat(`\t`, scanner.fmt_indent) + s + s = strings.repeat(`\t`, scanner.fmt_indent) + s.trim_left(' ') } + scanner.fmt_lines << s //scanner.fmt_out << s - scanner.fmt_out.write(s) + //scanner.fmt_out.write(s) scanner.fmt_line_empty = false } @@ -25,19 +26,13 @@ fn (scanner mut Scanner) fgenln(s_ string) { if scanner.fmt_line_empty && scanner.fmt_indent > 0 { s = strings.repeat(`\t`, scanner.fmt_indent) + s } - //scanner.fmt_out << s - //scanner.fmt_out << '\n' - scanner.fmt_out.writeln(s) + scanner.fmt_lines << s + //scanner.fmt_lines << '//!' + scanner.fmt_lines << '\n' + //scanner.fmt_out.writeln(s) scanner.fmt_line_empty = true } -[if vfmt] -fn (scanner mut Scanner) fgen_nl() { - scanner.fmt_out.writeln('') - scanner.fmt_line_empty = true -} - - [if vfmt] fn (p mut Parser) fgen(s string) { if p.pass != .main { @@ -68,13 +63,41 @@ fn (p mut Parser) fgen_nl() { if p.pass != .main { return } - println(p.tok) - if p.prev_tok == .line_comment { + + //println(p.tok) + // Don't insert a newline after a comment + /* + if p.token_idx>0 && p.tokens[p.token_idx-1].tok == .line_comment && + p.tokens[p.token_idx].tok != .line_comment { + p.scanner.fgenln('notin') return } + */ + + ///if p.token_idx > 0 && p.token_idx < p.tokens.len && + // Previous token is a comment, and NL has already been generated? + // Don't generate a second NL. + if p.scanner.fmt_lines.len > 0 && p.scanner.fmt_lines.last() == '\n' && + p.tokens[p.token_idx-2].tok == .line_comment + { + //if p.fileis('parser.v') { + //println(p.scanner.line_nr.str() + ' ' +p.tokens[p.token_idx-2].str()) + //} + return + } + p.scanner.fgen_nl() } +[if vfmt] +fn (scanner mut Scanner) fgen_nl() { + //scanner.fmt_lines << ' fgen_nl' + //scanner.fmt_lines << '//fgen_nl\n' + scanner.fmt_lines << '\n' + //scanner.fmt_out.writeln('') + scanner.fmt_line_empty = true +} + /* fn (p mut Parser) peek() TokenKind { for { @@ -146,16 +169,22 @@ fn (p mut Parser) fnext() { if tok != .line_comment && tok != .mline_comment { break } - comment_token := p.tokens[p.token_idx] - next := p.tokens[p.token_idx+1] - comment_on_new_line := p.token_idx == 0 || - comment_token.line_nr > p.tokens[p.token_idx - 1].line_nr + comment_token := p.tokens[i] + next := p.tokens[i+1] + comment_on_new_line := i == 0 || + comment_token.line_nr > p.tokens[i-1].line_nr //prev_token := p.tokens[p.token_idx - 1] comment := comment_token.lit + // Newline before the comment, but not between two // comments, + // and not right after `{`, there's already a newline there if i > 0 && p.tokens[i-1].tok != .line_comment && + p.tokens[i-1].tok != .lcbr && comment_token.line_nr > p.tokens[i-1].line_nr { p.fgen_nl() } + if i > 0 && p.tokens[i-1].tok == .rcbr && p.scanner.fmt_indent == 0 { + p.fgen_nl() + } if tok == .line_comment { if !comment_on_new_line { //prev_token.line_nr < comment_token.line_nr { p.fgen(' ') @@ -170,9 +199,12 @@ fn (p mut Parser) fnext() { */ } else { + // /**/ comment p.fgen(comment) } - if next.tok == .line_comment && comment_token.line_nr < next.line_nr { + //if next.tok == .line_comment && comment_token.line_nr < next.line_nr { + if comment_token.line_nr < next.line_nr { + //p.fgenln('nextcm') p.fgen_nl() } p.token_idx++ @@ -186,7 +218,7 @@ fn (p mut Parser) fnext() { [if vfmt] -fn (p mut Parser) gen_fmt() { +fn (p &Parser) gen_fmt() { if p.pass != .main { return } @@ -194,12 +226,13 @@ fn (p mut Parser) gen_fmt() { return } //s := p.scanner.fmt_out.str().replace('\n\n\n', '\n').trim_space() - s := p.scanner.fmt_out.str().trim_space() - //s := p.scanner.fmt_out.join('').trim_space() + //s := p.scanner.fmt_out.str().trim_space() + s := p.scanner.fmt_lines.join('').trim_space() if s == '' { return } - println('generating ${p.file_name}.v') + //if !p.file_name.contains('parser.v') {return} + println('generating ${p.file_name}') mut out := os.create('/var/tmp/fmt/' + p.file_name) or { verror('failed to create fmt.v') return