From 77b31de117cbb0f642b18a1155dfc7e29a97fdbe Mon Sep 17 00:00:00 2001 From: Delyan Angelov Date: Thu, 22 Aug 2019 14:15:11 +0300 Subject: [PATCH] compiler: produce errors in C "filepath:line:column:" format --- compiler/scanner.v | 27 ++++++++++++++++++++++----- compiler/tests/repl/error.repl | 2 +- compiler/tests/repl/error_nosave.repl | 2 +- compiler/tests/repl/repl_test.v | 6 +++--- vlib/os/os.v | 20 ++++++++++++++++++++ 5 files changed, 47 insertions(+), 10 deletions(-) diff --git a/compiler/scanner.v b/compiler/scanner.v index 2088ba555f..6f58f1a4a5 100644 --- a/compiler/scanner.v +++ b/compiler/scanner.v @@ -332,7 +332,7 @@ fn (s mut Scanner) scan() ScanRes { // TODO allow double quotes // case QUOTE: // return scan_res(.str, s.ident_string()) - case `\``: + case `\``: // ` // apostrophe balance comment. do not remove return scan_res(.chartoken, s.ident_char()) case `(`: return scan_res(.lpar, '') @@ -563,9 +563,26 @@ fn (s mut Scanner) scan() ScanRes { return scan_res(.eof, '') } +fn (s &Scanner) find_current_line_start_position() int { + mut linestart := s.pos + for { + if linestart <= 0 {break} + if s.text[linestart] == 10 || s.text[linestart] == 13 { break } + linestart-- + } + return linestart +} + fn (s &Scanner) error(msg string) { - file := s.file_path.all_after('/') - println('$file:${s.line_nr + 1} $msg') + fullpath := os.realpath( s.file_path ) + column := s.pos - s.find_current_line_start_position() + // The filepath:line:col: format is the default C compiler + // error output format. It allows editors and IDE's like + // emacs to quickly find the errors in the output + // and jump to their source with a keyboard shortcut. + // Using only the filename leads to inability of IDE/editors + // to find the source file, when it is in another folder. + println('${fullpath}:${s.line_nr + 1}:$column: $msg') exit(1) } @@ -655,7 +672,7 @@ fn (s mut Scanner) ident_char() string { len++ } double_slash := s.expect('\\\\', s.pos - 2) - if s.text[s.pos] == `\`` && (s.text[s.pos - 1] != slash || double_slash) { + if s.text[s.pos] == `\`` && (s.text[s.pos - 1] != slash || double_slash) { // ` // apostrophe balance comment. do not remove if double_slash { len++ } @@ -754,7 +771,7 @@ fn (s mut Scanner) get_opening_bracket() int { if s.text[pos] == `(` && !inside_string { parentheses-- } - if s.text[pos] == `\'` && s.text[pos - 1] != `\\` && s.text[pos - 1] != `\`` { + if s.text[pos] == `\'` && s.text[pos - 1] != `\\` && s.text[pos - 1] != `\`` { // ` // apostrophe balance comment. do not remove inside_string = !inside_string } if parentheses == 0 { diff --git a/compiler/tests/repl/error.repl b/compiler/tests/repl/error.repl index bb86f558e9..715b2e07de 100644 --- a/compiler/tests/repl/error.repl +++ b/compiler/tests/repl/error.repl @@ -1,3 +1,3 @@ println(a) ===output=== -.vrepl.v:2 undefined: `a` +.vrepl.v:2:9: undefined: `a` diff --git a/compiler/tests/repl/error_nosave.repl b/compiler/tests/repl/error_nosave.repl index 6d197193d1..974539c4ec 100644 --- a/compiler/tests/repl/error_nosave.repl +++ b/compiler/tests/repl/error_nosave.repl @@ -1,5 +1,5 @@ a 33 ===output=== -.vrepl_temp.v:2 undefined: `a` +.vrepl_temp.v:2:9: undefined: `a` 33 diff --git a/compiler/tests/repl/repl_test.v b/compiler/tests/repl/repl_test.v index 00fb5e7b15..db1daf42fa 100644 --- a/compiler/tests/repl/repl_test.v +++ b/compiler/tests/repl/repl_test.v @@ -2,7 +2,7 @@ import os fn test_repl() { test_files := os.walk_ext('.', '.repl') - + wd := os.getwd() + '/' for file in test_files { content := os.read_file(file) or { assert false @@ -19,7 +19,7 @@ fn test_repl() { assert false break } - result := r.output.replace('>>> ', '').replace('>>>', '').replace('... ', '').all_after('Use Ctrl-C or `exit` to exit\n') + result := r.output.replace('>>> ', '').replace('>>>', '').replace('... ', '').all_after('Use Ctrl-C or `exit` to exit\n').replace( wd, '' ) assert result == output if result != output { println(file) @@ -27,4 +27,4 @@ fn test_repl() { println('Expected : $output') } } -} \ No newline at end of file +} diff --git a/vlib/os/os.v b/vlib/os/os.v index 1ca717fb50..1fdf835cda 100644 --- a/vlib/os/os.v +++ b/vlib/os/os.v @@ -739,6 +739,26 @@ pub fn getwd() string { } } +// Returns the full absolute path for fpath, with all relative ../../, symlinks and so on resolved. +// See http://pubs.opengroup.org/onlinepubs/9699919799/functions/realpath.html +// Also https://insanecoding.blogspot.com/2007/11/pathmax-simply-isnt.html +// and https://insanecoding.blogspot.com/2007/11/implementing-realpath-in-c.html +// NB: this particular rabbit hole is *deep* ... +pub fn realpath(fpath string) string { + mut fullpath := malloc( MAX_PATH ) + mut res := 0 + $if windows { + res = int( C._fullpath( fullpath, fpath.str, MAX_PATH ) ) + } + $else{ + res = int( C.realpath( fpath.str, fullpath ) ) + } + if res != 0 { + return string(fullpath, strlen(fullpath)) + } + return fpath +} + // walk_ext returns a recursive list of all file paths ending with `ext`. pub fn walk_ext(path, ext string) []string { if !os.is_dir(path) {