From e67bf674e3765688b4b416e301c5cb3acd65a150 Mon Sep 17 00:00:00 2001 From: Delyan Angelov Date: Mon, 27 Apr 2020 16:08:04 +0300 Subject: [PATCH] scanner: cleanup, only v.parser now depends on v.scanner --- cmd/v/v.v | 1 + vlib/v/builder/builder.v | 4 +- vlib/v/checker/checker.v | 22 +++---- vlib/v/{scanner/error.v => errors/errors.v} | 9 ++- vlib/v/parser/comptime.v | 2 +- vlib/v/parser/fn.v | 3 +- vlib/v/parser/parser.v | 2 +- vlib/v/pref/pref.v | 2 +- vlib/v/scanner/scanner.v | 72 ++++----------------- vlib/v/scanner/warning.v | 10 --- vlib/v/util/scanning.v | 44 +++++++++++++ 11 files changed, 81 insertions(+), 90 deletions(-) rename vlib/v/{scanner/error.v => errors/errors.v} (61%) delete mode 100644 vlib/v/scanner/warning.v create mode 100644 vlib/v/util/scanning.v diff --git a/cmd/v/v.v b/cmd/v/v.v index 8d99096370..bcc60f3b22 100644 --- a/cmd/v/v.v +++ b/cmd/v/v.v @@ -112,6 +112,7 @@ fn parse_args(args []string) (&pref.Preferences, string) { mut res := &pref.Preferences{} mut command := '' mut command_pos := 0 + res.is_fmt = util.is_fmt() // for i, arg in args { for i := 0; i < args.len; i++ { arg := args[i] diff --git a/vlib/v/builder/builder.v b/vlib/v/builder/builder.v index 4fc93f8c3f..f9e243adcd 100644 --- a/vlib/v/builder/builder.v +++ b/vlib/v/builder/builder.v @@ -9,7 +9,7 @@ import v.util import v.vmod import v.checker import v.parser -import v.scanner +import v.errors import v.gen import v.gen.js import v.gen.x64 @@ -267,7 +267,7 @@ pub fn (b Builder) find_module_path(mod, fpath string) ?string { return error('module "$mod" not found in:\n$smodule_lookup_paths') } -fn (b &Builder) print_errors(errors []scanner.Error) { +fn (b &Builder) print_errors(errors []errors.Error) { for err in errors { kind := if b.pref.is_verbose { '$err.reporter error #$b.checker.nr_errors:' } else { 'error:' } ferror := util.formatted_error(kind, err.message, err.file_path, err.pos) diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v index 4da082752c..fae1791ffc 100644 --- a/vlib/v/checker/checker.v +++ b/vlib/v/checker/checker.v @@ -9,7 +9,7 @@ import v.table import v.token import v.pref import v.util -import v.scanner +import v.errors import os const ( @@ -21,8 +21,8 @@ pub struct Checker { mut: file ast.File nr_errors int - errors []scanner.Error - warnings []scanner.Warning + errors []errors.Error + warnings []errors.Warning error_lines []int // to avoid printing multiple errors for the same line expected_type table.Type fn_return_type table.Type // current function's return type @@ -51,7 +51,7 @@ pub fn (mut c Checker) check(ast_file ast.File) { } } -pub fn (mut c Checker) check2(ast_file ast.File) []scanner.Error { +pub fn (mut c Checker) check2(ast_file ast.File) []errors.Error { c.file = ast_file for stmt in ast_file.stmts { c.stmt(stmt) @@ -944,7 +944,7 @@ pub fn (mut c Checker) assign_stmt(assign_stmt mut ast.AssignStmt) { // check variablename for beginning with capital letter 'Abc' for ident in assign_stmt.left { is_decl := assign_stmt.op == .decl_assign - if is_decl && scanner.contains_capital(ident.name) { + if is_decl && util.contains_capital(ident.name) { c.error('variable names cannot contain uppercase letters, use snake_case instead', ident.pos) } else if is_decl && ident.kind != .blank_ident { @@ -1930,8 +1930,8 @@ fn (mut c Checker) warn_or_error(message string, pos token.Position, warn bool) // print_backtrace() // } if warn { - c.warnings << scanner.Warning{ - reporter: scanner.Reporter.checker + c.warnings << errors.Warning{ + reporter: errors.Reporter.checker pos: pos file_path: c.file.path message: message @@ -1939,8 +1939,8 @@ fn (mut c Checker) warn_or_error(message string, pos token.Position, warn bool) } else { c.nr_errors++ if pos.line_nr !in c.error_lines { - c.errors << scanner.Error{ - reporter: scanner.Reporter.checker + c.errors << errors.Error{ + reporter: errors.Reporter.checker pos: pos file_path: c.file.path message: message @@ -1951,6 +1951,6 @@ fn (mut c Checker) warn_or_error(message string, pos token.Position, warn bool) } // for debugging only -fn (p Checker) fileis(s string) bool { - return p.file.path.contains(s) +fn (c &Checker) fileis(s string) bool { + return c.file.path.contains(s) } diff --git a/vlib/v/scanner/error.v b/vlib/v/errors/errors.v similarity index 61% rename from vlib/v/scanner/error.v rename to vlib/v/errors/errors.v index 49a963aef3..26d56cf287 100644 --- a/vlib/v/scanner/error.v +++ b/vlib/v/errors/errors.v @@ -1,4 +1,4 @@ -module scanner +module errors import v.token @@ -16,3 +16,10 @@ pub struct Error { reporter Reporter backtrace string } + +pub struct Warning { + message string + file_path string + pos token.Position + reporter Reporter +} diff --git a/vlib/v/parser/comptime.v b/vlib/v/parser/comptime.v index 6e4bac929a..c95606c69d 100644 --- a/vlib/v/parser/comptime.v +++ b/vlib/v/parser/comptime.v @@ -69,7 +69,7 @@ fn (mut p Parser) comp_if() ast.CompIf { // `$if os {` for a different target, skip everything inside // to avoid compilation errors (like including or calling WinAPI fns // on non-Windows systems) - if !p.scanner.is_fmt && ((!is_not && os != p.pref.os) || (is_not && os == p.pref.os)) && + if !p.pref.is_fmt && ((!is_not && os != p.pref.os) || (is_not && os == p.pref.os)) && !p.pref.output_cross_c { skip_os = true p.check(.lcbr) diff --git a/vlib/v/parser/fn.v b/vlib/v/parser/fn.v index 8317f1ade6..e6707f66d8 100644 --- a/vlib/v/parser/fn.v +++ b/vlib/v/parser/fn.v @@ -5,7 +5,6 @@ module parser import v.ast import v.table -import v.scanner import v.token import v.util @@ -136,7 +135,7 @@ fn (mut p Parser) fn_decl() ast.FnDecl { if p.tok.kind == .name { // TODO high order fn name = p.check_name() - if !is_js && !is_c && !p.pref.translated && scanner.contains_capital(name) { + if !is_js && !is_c && !p.pref.translated && util.contains_capital(name) { p.error('function names cannot contain uppercase letters, use snake_case instead') } if is_method && p.table.get_type_symbol(rec_type).has_method(name) { diff --git a/vlib/v/parser/parser.v b/vlib/v/parser/parser.v index 4a0e9edc3d..66582c02cb 100644 --- a/vlib/v/parser/parser.v +++ b/vlib/v/parser/parser.v @@ -195,7 +195,7 @@ pub fn (mut p Parser) open_scope() { } pub fn (mut p Parser) close_scope() { - if !p.pref.is_repl && !p.scanner.is_fmt { + if !p.pref.is_repl && !p.pref.is_fmt { for v in p.scope.unused_vars() { if p.pref.is_prod { p.error_with_pos('Unused variable: $v.name', v.pos) diff --git a/vlib/v/pref/pref.v b/vlib/v/pref/pref.v index 9463c05ce6..a8b92034d7 100644 --- a/vlib/v/pref/pref.v +++ b/vlib/v/pref/pref.v @@ -64,7 +64,7 @@ pub mut: // generating_vh bool fast bool // use tcc/x64 codegen enable_globals bool // allow __global for low level code - // is_fmt bool + is_fmt bool is_bare bool lookup_path []string output_cross_c bool diff --git a/vlib/v/scanner/scanner.v b/vlib/v/scanner/scanner.v index 3604da620a..44c72efdae 100644 --- a/vlib/v/scanner/scanner.v +++ b/vlib/v/scanner/scanner.v @@ -11,8 +11,6 @@ import v.util const ( single_quote = `\'` double_quote = `"` - //is_fmt = os.getenv('VEXE').contains('vfmt') - is_fmt = os.executable().contains('vfmt') // char used as number separator num_sep = `_` ) @@ -66,14 +64,15 @@ pub fn new_scanner_file(file_path string, comments_mode CommentsMode) &Scanner { // new scanner from string. pub fn new_scanner(text string, comments_mode CommentsMode) &Scanner { - return &Scanner{ + s := &Scanner{ text: text is_print_line_on_error: true is_print_colored_error: true is_print_rel_paths_on_error: true - is_fmt: is_fmt + is_fmt: util.is_fmt() comments_mode: comments_mode } + return s } pub fn (s &Scanner) add_fn_main_and_rescan() { @@ -97,7 +96,7 @@ fn (s &Scanner) new_token(tok_kind token.Kind, lit string, len int) token.Token fn (s mut Scanner) ident_name() string { start := s.pos s.pos++ - for s.pos < s.text.len && (is_name_char(s.text[s.pos]) || s.text[s.pos].is_digit()) { + for s.pos < s.text.len && (util.is_name_char(s.text[s.pos]) || s.text[s.pos].is_digit()) { s.pos++ } name := s.text[start..s.pos] @@ -340,11 +339,11 @@ fn (s mut Scanner) ident_number() string { fn (s mut Scanner) skip_whitespace() { // if s.is_vh { println('vh') return } for s.pos < s.text.len && s.text[s.pos].is_space() { - if is_nl(s.text[s.pos]) && s.is_vh { + if util.is_nl(s.text[s.pos]) && s.is_vh { return } // Count \r\n as one line - if is_nl(s.text[s.pos]) && !s.expect('\r\n', s.pos - 1) { + if util.is_nl(s.text[s.pos]) && !s.expect('\r\n', s.pos - 1) { s.inc_line_number() } s.pos++ @@ -395,7 +394,7 @@ pub fn (s mut Scanner) scan() token.Token { nextc := if s.pos + 1 < s.text.len { s.text[s.pos + 1] } else { `\0` } // name or keyword - if is_name_char(c) { + if util.is_name_char(c) { name := s.ident_name() // tmp hack to detect . in ${} // Check if not .eof to prevent panic @@ -595,10 +594,10 @@ pub fn (s mut Scanner) scan() token.Token { } if name == 'VEXE' { vexe := pref.vexe_path() - return s.new_token(.string, cescaped_path(vexe), 5) + return s.new_token(.string, util.cescaped_path(vexe), 5) } if name == 'FILE' { - return s.new_token(.string, cescaped_path(os.real_path(s.file_path)), 5) + return s.new_token(.string, util.cescaped_path(os.real_path(s.file_path)), 5) } if name == 'LINE' { return s.new_token(.string, (s.line_nr + 1).str(), 5) @@ -820,7 +819,7 @@ fn (s &Scanner) current_column() int { return s.pos - s.last_nl_pos } -fn (s Scanner) count_symbol_before(p int, sym byte) int { +fn (s &Scanner) count_symbol_before(p int, sym byte) int { mut count := 0 for i := p; i >= 0; i-- { if s.text[i] != sym { @@ -879,7 +878,7 @@ fn (s mut Scanner) ident_string() string { break } // $var - if is_name_char(c) && prevc == `$` && !s.is_fmt && !is_raw && s.count_symbol_before(s.pos - 2, slash) % 2 == 0 { + if util.is_name_char(c) && prevc == `$` && !s.is_fmt && !is_raw && s.count_symbol_before(s.pos - 2, slash) % 2 == 0 { s.is_inside_string = true s.is_inter_start = true s.pos -= 2 @@ -997,51 +996,6 @@ fn (s mut Scanner) inc_line_number() { } } -fn (s Scanner) line(n int) string { - mut res := '' - if n >= 0 && n < s.line_ends.len { - nline_start := if n == 0 { 0 } else { s.line_ends[n - 1] } - nline_end := s.line_ends[n] - if nline_start <= nline_end { - res = s.text[nline_start..nline_end] - } - } - return res.trim_right('\r\n').trim_left('\r\n') -} - -[inline] -fn is_name_char(c byte) bool { - return (c >= `a` && c <= `z`) || (c >= `A` && c <= `Z`) || c == `_` -} - -[inline] -fn is_nl(c byte) bool { - return c == `\r` || c == `\n` -} - -fn contains_capital(s string) bool { - for c in s { - if c >= `A` && c <= `Z` { - return true - } - } - return false -} - -// HTTPRequest bad -// HttpRequest good -fn good_type_name(s string) bool { - if s.len < 4 { - return true - } - for i in 2 .. s.len { - if s[i].is_capital() && s[i - 1].is_capital() && s[i - 2].is_capital() { - return false - } - } - return true -} - pub fn (s &Scanner) error(msg string) { pos := token.Position{ line_nr: s.line_nr @@ -1054,7 +1008,3 @@ pub fn (s &Scanner) error(msg string) { pub fn verror(s string) { util.verror('scanner error', s) } - -pub fn cescaped_path(s string) string { - return s.replace('\\', '\\\\') -} diff --git a/vlib/v/scanner/warning.v b/vlib/v/scanner/warning.v deleted file mode 100644 index 273ca4b93b..0000000000 --- a/vlib/v/scanner/warning.v +++ /dev/null @@ -1,10 +0,0 @@ -module scanner - -import v.token - -pub struct Warning { - message string - file_path string - pos token.Position - reporter Reporter -} diff --git a/vlib/v/util/scanning.v b/vlib/v/util/scanning.v new file mode 100644 index 0000000000..0981cfab67 --- /dev/null +++ b/vlib/v/util/scanning.v @@ -0,0 +1,44 @@ +module util + +import os + +[inline] +fn is_name_char(c byte) bool { + return (c >= `a` && c <= `z`) || (c >= `A` && c <= `Z`) || c == `_` +} + +[inline] +fn is_nl(c byte) bool { + return c == `\r` || c == `\n` +} + +fn contains_capital(s string) bool { + for c in s { + if c >= `A` && c <= `Z` { + return true + } + } + return false +} + +// HTTPRequest bad +// HttpRequest good +fn good_type_name(s string) bool { + if s.len < 4 { + return true + } + for i in 2 .. s.len { + if s[i].is_capital() && s[i - 1].is_capital() && s[i - 2].is_capital() { + return false + } + } + return true +} + +pub fn cescaped_path(s string) string { + return s.replace('\\', '\\\\') +} + +pub fn is_fmt() bool { + return os.executable().contains('vfmt') +}