scanner: cleanup, only v.parser now depends on v.scanner

pull/4624/head
Delyan Angelov 2020-04-27 16:08:04 +03:00
parent e9f764db4f
commit e67bf674e3
11 changed files with 81 additions and 90 deletions

View File

@ -112,6 +112,7 @@ fn parse_args(args []string) (&pref.Preferences, string) {
mut res := &pref.Preferences{} mut res := &pref.Preferences{}
mut command := '' mut command := ''
mut command_pos := 0 mut command_pos := 0
res.is_fmt = util.is_fmt()
// for i, arg in args { // for i, arg in args {
for i := 0; i < args.len; i++ { for i := 0; i < args.len; i++ {
arg := args[i] arg := args[i]

View File

@ -9,7 +9,7 @@ import v.util
import v.vmod import v.vmod
import v.checker import v.checker
import v.parser import v.parser
import v.scanner import v.errors
import v.gen import v.gen
import v.gen.js import v.gen.js
import v.gen.x64 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') 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 { for err in errors {
kind := if b.pref.is_verbose { '$err.reporter error #$b.checker.nr_errors:' } else { 'error:' } 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) ferror := util.formatted_error(kind, err.message, err.file_path, err.pos)

View File

@ -9,7 +9,7 @@ import v.table
import v.token import v.token
import v.pref import v.pref
import v.util import v.util
import v.scanner import v.errors
import os import os
const ( const (
@ -21,8 +21,8 @@ pub struct Checker {
mut: mut:
file ast.File file ast.File
nr_errors int nr_errors int
errors []scanner.Error errors []errors.Error
warnings []scanner.Warning warnings []errors.Warning
error_lines []int // to avoid printing multiple errors for the same line error_lines []int // to avoid printing multiple errors for the same line
expected_type table.Type expected_type table.Type
fn_return_type table.Type // current function's return 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 c.file = ast_file
for stmt in ast_file.stmts { for stmt in ast_file.stmts {
c.stmt(stmt) 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' // check variablename for beginning with capital letter 'Abc'
for ident in assign_stmt.left { for ident in assign_stmt.left {
is_decl := assign_stmt.op == .decl_assign 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', c.error('variable names cannot contain uppercase letters, use snake_case instead',
ident.pos) ident.pos)
} else if is_decl && ident.kind != .blank_ident { } 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() // print_backtrace()
// } // }
if warn { if warn {
c.warnings << scanner.Warning{ c.warnings << errors.Warning{
reporter: scanner.Reporter.checker reporter: errors.Reporter.checker
pos: pos pos: pos
file_path: c.file.path file_path: c.file.path
message: message message: message
@ -1939,8 +1939,8 @@ fn (mut c Checker) warn_or_error(message string, pos token.Position, warn bool)
} else { } else {
c.nr_errors++ c.nr_errors++
if pos.line_nr !in c.error_lines { if pos.line_nr !in c.error_lines {
c.errors << scanner.Error{ c.errors << errors.Error{
reporter: scanner.Reporter.checker reporter: errors.Reporter.checker
pos: pos pos: pos
file_path: c.file.path file_path: c.file.path
message: message message: message
@ -1951,6 +1951,6 @@ fn (mut c Checker) warn_or_error(message string, pos token.Position, warn bool)
} }
// for debugging only // for debugging only
fn (p Checker) fileis(s string) bool { fn (c &Checker) fileis(s string) bool {
return p.file.path.contains(s) return c.file.path.contains(s)
} }

View File

@ -1,4 +1,4 @@
module scanner module errors
import v.token import v.token
@ -16,3 +16,10 @@ pub struct Error {
reporter Reporter reporter Reporter
backtrace string backtrace string
} }
pub struct Warning {
message string
file_path string
pos token.Position
reporter Reporter
}

View File

@ -69,7 +69,7 @@ fn (mut p Parser) comp_if() ast.CompIf {
// `$if os {` for a different target, skip everything inside // `$if os {` for a different target, skip everything inside
// to avoid compilation errors (like including <windows.h> or calling WinAPI fns // to avoid compilation errors (like including <windows.h> or calling WinAPI fns
// on non-Windows systems) // 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 { !p.pref.output_cross_c {
skip_os = true skip_os = true
p.check(.lcbr) p.check(.lcbr)

View File

@ -5,7 +5,6 @@ module parser
import v.ast import v.ast
import v.table import v.table
import v.scanner
import v.token import v.token
import v.util import v.util
@ -136,7 +135,7 @@ fn (mut p Parser) fn_decl() ast.FnDecl {
if p.tok.kind == .name { if p.tok.kind == .name {
// TODO high order fn // TODO high order fn
name = p.check_name() 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') 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) { if is_method && p.table.get_type_symbol(rec_type).has_method(name) {

View File

@ -195,7 +195,7 @@ pub fn (mut p Parser) open_scope() {
} }
pub fn (mut p Parser) close_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() { for v in p.scope.unused_vars() {
if p.pref.is_prod { if p.pref.is_prod {
p.error_with_pos('Unused variable: $v.name', v.pos) p.error_with_pos('Unused variable: $v.name', v.pos)

View File

@ -64,7 +64,7 @@ pub mut:
// generating_vh bool // generating_vh bool
fast bool // use tcc/x64 codegen fast bool // use tcc/x64 codegen
enable_globals bool // allow __global for low level code enable_globals bool // allow __global for low level code
// is_fmt bool is_fmt bool
is_bare bool is_bare bool
lookup_path []string lookup_path []string
output_cross_c bool output_cross_c bool

View File

@ -11,8 +11,6 @@ import v.util
const ( const (
single_quote = `\'` single_quote = `\'`
double_quote = `"` double_quote = `"`
//is_fmt = os.getenv('VEXE').contains('vfmt')
is_fmt = os.executable().contains('vfmt')
// char used as number separator // char used as number separator
num_sep = `_` num_sep = `_`
) )
@ -66,14 +64,15 @@ pub fn new_scanner_file(file_path string, comments_mode CommentsMode) &Scanner {
// new scanner from string. // new scanner from string.
pub fn new_scanner(text string, comments_mode CommentsMode) &Scanner { pub fn new_scanner(text string, comments_mode CommentsMode) &Scanner {
return &Scanner{ s := &Scanner{
text: text text: text
is_print_line_on_error: true is_print_line_on_error: true
is_print_colored_error: true is_print_colored_error: true
is_print_rel_paths_on_error: true is_print_rel_paths_on_error: true
is_fmt: is_fmt is_fmt: util.is_fmt()
comments_mode: comments_mode comments_mode: comments_mode
} }
return s
} }
pub fn (s &Scanner) add_fn_main_and_rescan() { 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 { fn (s mut Scanner) ident_name() string {
start := s.pos start := s.pos
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++ s.pos++
} }
name := s.text[start..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() { fn (s mut Scanner) skip_whitespace() {
// if s.is_vh { println('vh') return } // if s.is_vh { println('vh') return }
for s.pos < s.text.len && s.text[s.pos].is_space() { 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 return
} }
// Count \r\n as one line // 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.inc_line_number()
} }
s.pos++ 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` } nextc := if s.pos + 1 < s.text.len { s.text[s.pos + 1] } else { `\0` }
// name or keyword // name or keyword
if is_name_char(c) { if util.is_name_char(c) {
name := s.ident_name() name := s.ident_name()
// tmp hack to detect . in ${} // tmp hack to detect . in ${}
// Check if not .eof to prevent panic // Check if not .eof to prevent panic
@ -595,10 +594,10 @@ pub fn (s mut Scanner) scan() token.Token {
} }
if name == 'VEXE' { if name == 'VEXE' {
vexe := pref.vexe_path() 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' { 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' { if name == 'LINE' {
return s.new_token(.string, (s.line_nr + 1).str(), 5) 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 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 mut count := 0
for i := p; i >= 0; i-- { for i := p; i >= 0; i-- {
if s.text[i] != sym { if s.text[i] != sym {
@ -879,7 +878,7 @@ fn (s mut Scanner) ident_string() string {
break break
} }
// $var // $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_inside_string = true
s.is_inter_start = true s.is_inter_start = true
s.pos -= 2 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) { pub fn (s &Scanner) error(msg string) {
pos := token.Position{ pos := token.Position{
line_nr: s.line_nr line_nr: s.line_nr
@ -1054,7 +1008,3 @@ pub fn (s &Scanner) error(msg string) {
pub fn verror(s string) { pub fn verror(s string) {
util.verror('scanner error', s) util.verror('scanner error', s)
} }
pub fn cescaped_path(s string) string {
return s.replace('\\', '\\\\')
}

View File

@ -1,10 +0,0 @@
module scanner
import v.token
pub struct Warning {
message string
file_path string
pos token.Position
reporter Reporter
}

View File

@ -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')
}