scanner: cleanup, only v.parser now depends on v.scanner
parent
e9f764db4f
commit
e67bf674e3
|
@ -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]
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
}
|
|
@ -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)
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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('\\', '\\\\')
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,10 +0,0 @@
|
||||||
module scanner
|
|
||||||
|
|
||||||
import v.token
|
|
||||||
|
|
||||||
pub struct Warning {
|
|
||||||
message string
|
|
||||||
file_path string
|
|
||||||
pos token.Position
|
|
||||||
reporter Reporter
|
|
||||||
}
|
|
|
@ -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')
|
||||||
|
}
|
Loading…
Reference in New Issue