From 144b57c4b79e69409e15dbcdb5d7e4161c954e0d Mon Sep 17 00:00:00 2001 From: kbkpbot Date: Mon, 13 Oct 2025 03:56:23 +0800 Subject: [PATCH] ast,token,scanner,parser,checker,cgen: add file_idx to token.Pos (#25490) --- cmd/tools/measure/fmt_speed.v | 2 +- cmd/tools/measure/parser_speed.v | 2 +- cmd/tools/measure/scanner_speed.v | 2 +- vlib/v/ast/ast.v | 2 +- vlib/v/ast/table.v | 1 + vlib/v/checker/errors.v | 19 ++-- vlib/v/checker/str.v | 2 +- vlib/v/gen/c/cgen.v | 3 +- vlib/v/parser/fn.v | 2 +- vlib/v/parser/messages.v | 17 ++-- vlib/v/parser/parser.v | 9 +- vlib/v/parser/tmpl.v | 6 +- vlib/v/scanner/scanner.v | 98 +++++++++++-------- .../scanner/tests/shebang_outside_vsh_err.out | 2 +- vlib/v/token/pos.v | 14 +-- vlib/v/token/token.v | 16 +-- 16 files changed, 114 insertions(+), 83 deletions(-) diff --git a/cmd/tools/measure/fmt_speed.v b/cmd/tools/measure/fmt_speed.v index 49a222daf..4a9ba57a6 100644 --- a/cmd/tools/measure/fmt_speed.v +++ b/cmd/tools/measure/fmt_speed.v @@ -89,7 +89,7 @@ fn process_files(files []string) ! { fn new_parser(path string, comments_mode scanner.CommentsMode, table &ast.Table, pref_ &pref.Preferences) &parser.Parser { mut p := &parser.Parser{ - scanner: scanner.new_scanner_file(path, comments_mode, pref_) or { panic(err) } + scanner: scanner.new_scanner_file(path, -1, comments_mode, pref_) or { panic(err) } table: table pref: pref_ scope: &ast.Scope{ diff --git a/cmd/tools/measure/parser_speed.v b/cmd/tools/measure/parser_speed.v index dd60cdb7d..5d894aaa8 100644 --- a/cmd/tools/measure/parser_speed.v +++ b/cmd/tools/measure/parser_speed.v @@ -87,7 +87,7 @@ fn process_files(files []string) ! { fn new_parser(path string, comments_mode scanner.CommentsMode, table &ast.Table, pref_ &pref.Preferences) &parser.Parser { mut p := &parser.Parser{ - scanner: scanner.new_scanner_file(path, comments_mode, pref_) or { panic(err) } + scanner: scanner.new_scanner_file(path, -1, comments_mode, pref_) or { panic(err) } table: table pref: pref_ scope: &ast.Scope{ diff --git a/cmd/tools/measure/scanner_speed.v b/cmd/tools/measure/scanner_speed.v index 1b91c17c7..9bef10a45 100644 --- a/cmd/tools/measure/scanner_speed.v +++ b/cmd/tools/measure/scanner_speed.v @@ -55,7 +55,7 @@ fn process_files(files []string) ! { } total_files++ sw.restart() - s := scanner.new_scanner_file(f, comments_mode, pref_)! + s := scanner.new_scanner_file(f, -1, comments_mode, pref_)! f_us := sw.elapsed().microseconds() total_us += f_us total_bytes += s.text.len diff --git a/vlib/v/ast/ast.v b/vlib/v/ast/ast.v index dd72cfbc1..4afc895ea 100644 --- a/vlib/v/ast/ast.v +++ b/vlib/v/ast/ast.v @@ -2478,7 +2478,7 @@ pub fn (node Node) pos() token.Pos { line_nr: -1 pos: -1 last_line: -1 - col: -1 + col: 0 } } } diff --git a/vlib/v/ast/table.v b/vlib/v/ast/table.v index 83370ecb2..31a24e534 100644 --- a/vlib/v/ast/table.v +++ b/vlib/v/ast/table.v @@ -102,6 +102,7 @@ pub mut: new_int bool // use 64bit/32bit platform dependent `int` new_int_fmt_fix bool // vfmt will fix `int` to `i32` export_names map[string]string // @[export] names + filelist []string // all files list } pub struct ComptTimeCondResult { diff --git a/vlib/v/checker/errors.v b/vlib/v/checker/errors.v index 2d0df6d5a..bf73cf52e 100644 --- a/vlib/v/checker/errors.v +++ b/vlib/v/checker/errors.v @@ -14,7 +14,8 @@ fn (mut c Checker) add_error_detail(s string) { } fn (mut c Checker) add_error_detail_with_pos(msg string, pos token.Pos) { - c.add_error_detail(util.formatted_error('details:', msg, c.file.path, pos)) + file_path := if pos.file_idx < 0 { c.file.path } else { c.table.filelist[pos.file_idx] } + c.add_error_detail(util.formatted_error('details:', msg, file_path, pos)) } fn (mut c Checker) add_instruction_for_option_type() { @@ -90,13 +91,14 @@ fn (mut c Checker) note(message string, pos token.Pos) { c.error_details = [] } // deduplicate notices for the same line - kpos := '${c.file.path}:${pos.line_nr}:${message}' + file_path := if pos.file_idx < 0 { c.file.path } else { c.table.filelist[pos.file_idx] } + kpos := '${file_path}:${pos.line_nr}:${message}' if kpos !in c.notice_lines { c.notice_lines[kpos] = true note := errors.Notice{ reporter: errors.Reporter.checker pos: pos - file_path: c.file.path + file_path: file_path message: message details: details } @@ -122,6 +124,7 @@ fn (mut c Checker) warn_or_error(message string, pos token.Pos, warn bool) { details = c.error_details.join('\n') c.error_details = [] } + file_path := if pos.file_idx < 0 { c.file.path } else { c.table.filelist[pos.file_idx] } if warn && !c.pref.skip_warnings { c.nr_warnings++ if c.pref.message_limit >= 0 && c.nr_warnings >= c.pref.message_limit { @@ -129,13 +132,13 @@ fn (mut c Checker) warn_or_error(message string, pos token.Pos, warn bool) { return } // deduplicate warnings for the same line - kpos := '${c.file.path}:${pos.line_nr}:${message}' + kpos := '${file_path}:${pos.line_nr}:${message}' if kpos !in c.warning_lines { c.warning_lines[kpos] = true wrn := errors.Warning{ reporter: errors.Reporter.checker pos: pos - file_path: c.file.path + file_path: file_path message: message details: details } @@ -148,7 +151,7 @@ fn (mut c Checker) warn_or_error(message string, pos token.Pos, warn bool) { if c.pref.fatal_errors { util.show_compiler_message('error:', errors.CompilerMessage{ pos: pos - file_path: c.file.path + file_path: file_path message: message details: details }) @@ -160,13 +163,13 @@ fn (mut c Checker) warn_or_error(message string, pos token.Pos, warn bool) { return } // deduplicate errors for the same line - kpos := '${c.file.path}:${pos.line_nr}:${message}' + kpos := '${file_path}:${pos.line_nr}:${message}' if kpos !in c.error_lines { c.error_lines[kpos] = true err := errors.Error{ reporter: errors.Reporter.checker pos: pos - file_path: c.file.path + file_path: file_path message: message details: details } diff --git a/vlib/v/checker/str.v b/vlib/v/checker/str.v index 45a174bd0..69a6c5e07 100644 --- a/vlib/v/checker/str.v +++ b/vlib/v/checker/str.v @@ -145,7 +145,7 @@ fn (mut c Checker) string_lit(mut node ast.StringLiteral) ast.Type { `\\` { mut start_pos := token.Pos{ ...node.pos - col: node.pos.col + 1 + idx + col: u16(node.pos.col + 1 + idx) } start_idx := idx idx++ diff --git a/vlib/v/gen/c/cgen.v b/vlib/v/gen/c/cgen.v index fae415418..bef0bc094 100644 --- a/vlib/v/gen/c/cgen.v +++ b/vlib/v/gen/c/cgen.v @@ -6609,7 +6609,8 @@ fn verror(s string) { @[noreturn] fn (g &Gen) error(s string, pos token.Pos) { - util.show_compiler_message('cgen error:', pos: pos, file_path: g.file.path, message: s) + file_path := if pos.file_idx < 0 { g.file.path } else { g.table.filelist[pos.file_idx] } + util.show_compiler_message('cgen error:', pos: pos, file_path: file_path, message: s) exit(1) } diff --git a/vlib/v/parser/fn.v b/vlib/v/parser/fn.v index ac7b32fdc..716591ed9 100644 --- a/vlib/v/parser/fn.v +++ b/vlib/v/parser/fn.v @@ -61,7 +61,7 @@ fn (mut p Parser) call_expr(language ast.Language, mod string) ast.CallExpr { ok_arg_pos := (args[params.len - 1] or { args[0] }).pos pos := token.Pos{ ...ok_arg_pos - col: ok_arg_pos.col + ok_arg_pos.len + col: u16(ok_arg_pos.col + ok_arg_pos.len) } p.unexpected_with_pos(pos.extend(p.tok.pos()), expecting: '`)`') } else { diff --git a/vlib/v/parser/messages.v b/vlib/v/parser/messages.v index 5ee4f7825..8997f7188 100644 --- a/vlib/v/parser/messages.v +++ b/vlib/v/parser/messages.v @@ -68,8 +68,9 @@ fn (mut p Parser) note(s string) { fn (mut p Parser) error_with_pos(s string, pos token.Pos) ast.NodeError { // print_backtrace() mut kind := 'error:' + file_path := if pos.file_idx < 0 { p.file_path } else { p.table.filelist[pos.file_idx] } if p.pref.fatal_errors { - util.show_compiler_message(kind, pos: pos, file_path: p.file_path, message: s) + util.show_compiler_message(kind, pos: pos, file_path: file_path, message: s) exit(1) } if p.pref.output_mode == .stdout && !p.pref.check_only && !p.is_vls { @@ -77,11 +78,11 @@ fn (mut p Parser) error_with_pos(s string, pos token.Pos) ast.NodeError { print_backtrace() kind = 'parser error:' } - util.show_compiler_message(kind, pos: pos, file_path: p.file_path, message: s) + util.show_compiler_message(kind, pos: pos, file_path: file_path, message: s) exit(1) } else { p.errors << errors.Error{ - file_path: p.file_path + file_path: file_path pos: pos reporter: .parser message: s @@ -145,15 +146,16 @@ fn (mut p Parser) warn_with_pos(s string, pos token.Pos) { if p.pref.skip_warnings { return } + file_path := if pos.file_idx < 0 { p.file_path } else { p.table.filelist[pos.file_idx] } if p.pref.output_mode == .stdout && !p.pref.check_only { - util.show_compiler_message('warning:', pos: pos, file_path: p.file_path, message: s) + util.show_compiler_message('warning:', pos: pos, file_path: file_path, message: s) } else { if p.pref.message_limit >= 0 && p.warnings.len >= p.pref.message_limit { p.should_abort = true return } p.warnings << errors.Warning{ - file_path: p.file_path + file_path: file_path pos: pos reporter: .parser message: s @@ -175,11 +177,12 @@ fn (mut p Parser) note_with_pos(s string, pos token.Pos) { p.error_with_pos(s, pos) return } + file_path := if pos.file_idx < 0 { p.file_path } else { p.table.filelist[pos.file_idx] } if p.pref.output_mode == .stdout && !p.pref.check_only { - util.show_compiler_message('notice:', pos: pos, file_path: p.file_path, message: s) + util.show_compiler_message('notice:', pos: pos, file_path: file_path, message: s) } else { p.notices << errors.Notice{ - file_path: p.file_path + file_path: file_path pos: pos reporter: .parser message: s diff --git a/vlib/v/parser/parser.v b/vlib/v/parser/parser.v index 413ee9b38..679887c83 100644 --- a/vlib/v/parser/parser.v +++ b/vlib/v/parser/parser.v @@ -19,6 +19,7 @@ pub: mut: file_base string // "hello.v" file_path string // "/home/user/hello.v" + file_idx i16 // file idx in the global table `filelist` file_display_path string // just "hello.v", when your current folder for the compilation is "/home/user/", otherwise the full path "/home/user/hello.v" unique_prefix string // a hash of p.file_path, used for making anon fn generation unique file_backend_mode ast.Language // .c for .c.v|.c.vv|.c.vsh files; .js for .js.v files, .amd64/.rv32/other arches for .amd64.v/.rv32.v/etc. files, .v otherwise. @@ -255,8 +256,13 @@ pub fn parse_file(path string, mut table ast.Table, comments_mode scanner.Commen $if trace_parse_file ? { eprintln('> ${@MOD}.${@FN} comments_mode: ${comments_mode:-20} | path: ${path}') } + mut file_idx := i16(table.filelist.index(path)) + if file_idx == -1 { + file_idx = i16(table.filelist.len) + table.filelist << path + } mut p := Parser{ - scanner: scanner.new_scanner_file(path, comments_mode, pref_) or { panic(err) } + scanner: scanner.new_scanner_file(path, file_idx, comments_mode, pref_) or { panic(err) } table: table pref: pref_ // Only set vls mode if it's the file the user requested via `v -vls-mode file.v` @@ -268,6 +274,7 @@ pub fn parse_file(path string, mut table ast.Table, comments_mode scanner.Commen } errors: []errors.Error{} warnings: []errors.Warning{} + file_idx: file_idx } p.set_path(path) res := p.parse() diff --git a/vlib/v/parser/tmpl.v b/vlib/v/parser/tmpl.v index b90eb709e..7dfad5166 100644 --- a/vlib/v/parser/tmpl.v +++ b/vlib/v/parser/tmpl.v @@ -103,7 +103,7 @@ pub: calling_file string line_nr int position int - col int + col u16 message string } @@ -123,7 +123,7 @@ fn (err IncludeError) calling_file() string { return err.calling_file } -fn (err IncludeError) col() int { +fn (err IncludeError) col() u16 { return err.col } @@ -140,7 +140,7 @@ fn (mut p Parser) process_includes(calling_file string, line_number int, line st calling_file: calling_file line_nr: tline_number // line_number position: position + '@include '.len - col: position + '@include '.len + col: u16(position + '@include '.len) message: 'path for @include must be quoted with \' or "' } } diff --git a/vlib/v/scanner/scanner.v b/vlib/v/scanner/scanner.v index 5dbe196b2..83864f60c 100644 --- a/vlib/v/scanner/scanner.v +++ b/vlib/v/scanner/scanner.v @@ -24,6 +24,7 @@ pub struct Scanner { pub mut: file_path string // '/path/to/file.v' file_base string // 'file.v' + file_idx i16 = -1 // file idx in the global table `filelist` text string // the whole text of the file pos int = -1 // current position in the file, first character is s.text[0] line_nr int // current line number @@ -107,7 +108,7 @@ pub enum CommentsMode { } // new scanner from file. -pub fn new_scanner_file(file_path string, comments_mode CommentsMode, pref_ &pref.Preferences) !&Scanner { +pub fn new_scanner_file(file_path string, file_idx i16, comments_mode CommentsMode, pref_ &pref.Preferences) !&Scanner { if !os.is_file(file_path) { return error('${file_path} is not a .v file') } @@ -123,6 +124,7 @@ pub fn new_scanner_file(file_path string, comments_mode CommentsMode, pref_ &pre comments_mode: comments_mode file_path: file_path file_base: os.base(file_path) + file_idx: file_idx } s.scan_all_tokens_in_buffer() return s @@ -186,26 +188,28 @@ fn (mut s Scanner) new_token(tok_kind token.Kind, lit string, len int) token.Tok max_column = 1 } return token.Token{ - kind: tok_kind - lit: lit - line_nr: s.line_nr + line_offset - col: max_column - pos: s.pos - len + 1 - len: len - tidx: cidx + kind: tok_kind + lit: lit + line_nr: s.line_nr + line_offset + col: u16(max_column) + pos: s.pos - len + 1 + len: len + tidx: cidx + file_idx: s.file_idx } } @[inline] fn (s &Scanner) new_eof_token() token.Token { return token.Token{ - kind: .eof - lit: '' - line_nr: s.line_nr + 1 - col: s.current_column() - pos: s.pos - len: 1 - tidx: s.tidx + kind: .eof + lit: '' + line_nr: s.line_nr + 1 + col: u16(s.current_column()) + pos: s.pos + len: 1 + tidx: s.tidx + file_idx: s.file_idx } } @@ -218,13 +222,14 @@ fn (mut s Scanner) new_multiline_token(tok_kind token.Kind, lit string, len int, max_column = 1 } return token.Token{ - kind: tok_kind - lit: lit - line_nr: start_line + 1 - col: max_column - pos: s.pos - len + 1 - len: len - tidx: cidx + kind: tok_kind + lit: lit + line_nr: start_line + 1 + col: u16(max_column) + pos: s.pos - len + 1 + len: len + tidx: cidx + file_idx: s.file_idx } } @@ -945,10 +950,11 @@ pub fn (mut s Scanner) text_scan() token.Token { comment := s.text[start - 1..s.pos].trim_space() if s.line_nr != 1 { comment_pos := token.Pos{ - line_nr: s.line_nr - 1 - len: comment.len - pos: start - col: s.current_column() - comment.len + line_nr: s.line_nr - 1 + len: comment.len + pos: start + col: u16_col(s.current_column() - comment.len) + file_idx: s.file_idx } s.error_with_pos('a shebang is only valid at the top of the file', comment_pos) @@ -1122,10 +1128,11 @@ pub fn (mut s Scanner) text_scan() token.Token { mut comment := s.text[start..(s.pos - 1)] if !comment.contains('\n') { comment_pos := token.Pos{ - line_nr: start_line - len: comment.len + 4 - pos: start - col: s.current_column() - comment.len - 4 + line_nr: start_line + len: comment.len + 4 + pos: start + col: u16_col(s.current_column() - comment.len - 4) + file_idx: s.file_idx } s.error_with_pos('inline comment is deprecated, please use line comment', comment_pos) @@ -1193,9 +1200,10 @@ pub fn (mut s Scanner) ident_string() string { s.is_nested_string = false } lspos := token.Pos{ - line_nr: s.line_nr - pos: s.pos - col: s.pos - s.last_nl_pos - 1 + line_nr: s.line_nr + pos: s.pos + col: u16(s.pos - s.last_nl_pos - 1) + file_idx: s.file_idx } q := s.text[s.pos] is_quote := q in [single_quote, double_quote] @@ -1511,9 +1519,10 @@ fn trim_slash_line_break(s string) string { /// escaped utf8 runes in octal like `\342\230\205` => (★) pub fn (mut s Scanner) ident_char() string { lspos := token.Pos{ - line_nr: s.line_nr - pos: s.pos - col: s.pos - s.last_nl_pos - 1 + line_nr: s.line_nr + pos: s.pos + col: u16(s.pos - s.last_nl_pos - 1) + file_idx: s.file_idx } start := s.pos // the string position of the first backtick char @@ -1669,9 +1678,10 @@ fn (mut s Scanner) inc_line_number() { pub fn (mut s Scanner) current_pos() token.Pos { return token.Pos{ - line_nr: s.line_nr - pos: s.pos - col: s.current_column() - 1 + line_nr: s.line_nr + pos: s.pos + col: u16_col(s.current_column() - 1) + file_idx: s.file_idx } } @@ -1681,8 +1691,9 @@ pub fn (mut s Scanner) note(msg string) { return } pos := token.Pos{ - line_nr: s.line_nr - pos: s.pos + line_nr: s.line_nr + pos: s.pos + file_idx: s.file_idx } if s.pref.output_mode == .stdout && !s.pref.check_only { util.show_compiler_message('notice:', pos: pos, file_path: s.file_path, message: msg) @@ -1845,3 +1856,8 @@ fn (s Scanner) str_quote() u8 { } return 255 } + +@[inline] +fn u16_col(col int) u16 { + return if col < 0 { u16(0) } else { u16(col) } +} diff --git a/vlib/v/scanner/tests/shebang_outside_vsh_err.out b/vlib/v/scanner/tests/shebang_outside_vsh_err.out index 5f35b996f..423d45208 100644 --- a/vlib/v/scanner/tests/shebang_outside_vsh_err.out +++ b/vlib/v/scanner/tests/shebang_outside_vsh_err.out @@ -2,6 +2,6 @@ vlib/v/scanner/tests/shebang_outside_vsh_err.vv:3:1: error: a shebang is only va 1 | module foo 2 | 3 | #!/usr/bin/env -S v - | ^ + | ~~~~~~~~~~~~~~~~~~~ 4 | 5 | import os diff --git a/vlib/v/token/pos.v b/vlib/v/token/pos.v index 05dfdd126..a89cb15f4 100644 --- a/vlib/v/token/pos.v +++ b/vlib/v/token/pos.v @@ -5,10 +5,11 @@ module token pub struct Pos { pub: - len int // length of the literal in the source - line_nr int // the line number in the source where the token occurred - pos int // the position of the token in scanner text - col int // the column in the source where the token occurred + len int // length of the literal in the source + line_nr int // the line number in the source where the token occurred + pos int // the position of the token in scanner text + col u16 // the column in the source where the token occurred + file_idx i16 = -1 // file idx in the global table `filelist` pub mut: last_line int // the line number where the ast object ends (used by vfmt) } @@ -31,10 +32,8 @@ pub fn (pos Pos) extend(end Pos) Pos { pub fn (pos Pos) extend_with_last_line(end Pos, last_line int) Pos { return Pos{ + ...pos len: end.pos - pos.pos + end.len - line_nr: pos.line_nr - pos: pos.pos - col: pos.col last_line: last_line - 1 } } @@ -46,6 +45,7 @@ pub fn (mut pos Pos) update_last_line(last_line int) { @[inline] pub fn (tok &Token) pos() Pos { return Pos{ + file_idx: tok.file_idx len: tok.len line_nr: tok.line_nr - 1 pos: tok.pos diff --git a/vlib/v/token/token.v b/vlib/v/token/token.v index d4b6be3f2..1e3b08a77 100644 --- a/vlib/v/token/token.v +++ b/vlib/v/token/token.v @@ -8,14 +8,14 @@ const orm_custom_operators = ['like', 'ilike'] @[minify] pub struct Token { pub: - kind Kind // the token number/enum; for quick comparisons - lit string // literal representation of the token - line_nr int // the line number in the source where the token occurred - col int // the column in the source where the token occurred - // name_idx int // name table index for O(1) lookup - pos int // the position of the token in scanner text - len int // length of the literal - tidx int // the index of the token + kind Kind // the token number/enum; for quick comparisons + lit string // literal representation of the token + line_nr int // the line number in the source where the token occurred + col u16 // the column in the source where the token occurred + file_idx i16 // file idx in the global table `filelist` + pos int // the position of the token in scanner text + len int // length of the literal + tidx int // the index of the token } pub enum Kind { -- 2.39.5