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 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]

View File

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

View File

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

View File

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

View File

@ -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 <windows.h> 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)

View File

@ -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) {

View File

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

View File

@ -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

View File

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

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