parser: implement support for -Wimpure-v (#7195)
parent
90c1c639fe
commit
d5915bde7c
|
@ -126,7 +126,14 @@ The build flags are shared by the build and run commands:
|
|||
Treat all warnings as errors, even in development builds.
|
||||
|
||||
-Wfatal-errors
|
||||
Unconditionally exit with exit(1) after the first error. Useful for scripts/tooling that calls V.
|
||||
Unconditionally exit with exit(1) after the first error.
|
||||
Useful for scripts/tooling that calls V.
|
||||
|
||||
-Wimpure-v
|
||||
Warn about using C. or JS. symbols in plain .v files.
|
||||
These should be moved in .c.v and .js.v .
|
||||
NB: in the future, this will be turned on by default,
|
||||
and will become an error, after vlib is cleaned up.
|
||||
|
||||
For C-specific build flags, use `v help build-c`.
|
||||
|
||||
|
|
|
@ -20,6 +20,9 @@ pub fn (mut p Parser) call_expr(language table.Language, mod string) ast.CallExp
|
|||
} else {
|
||||
p.check_name()
|
||||
}
|
||||
if language != .v {
|
||||
p.check_for_impure_v(language, first_pos)
|
||||
}
|
||||
mut or_kind := ast.OrKind.absent
|
||||
if fn_name == 'json.decode' {
|
||||
p.expecting_type = true // Makes name_expr() parse the type `User` in `json.decode(User, txt)`
|
||||
|
@ -155,6 +158,7 @@ fn (mut p Parser) fn_decl() ast.FnDecl {
|
|||
if language != .v {
|
||||
p.next()
|
||||
p.check(.dot)
|
||||
p.check_for_impure_v(language, p.tok.position())
|
||||
}
|
||||
// Receiver?
|
||||
mut rec_name := ''
|
||||
|
|
|
@ -15,11 +15,12 @@ import runtime
|
|||
import time
|
||||
|
||||
pub struct Parser {
|
||||
pref &pref.Preferences
|
||||
mut:
|
||||
file_base string // "hello.v"
|
||||
file_name string // "/home/user/hello.v"
|
||||
file_name_dir string // "/home/user"
|
||||
pref &pref.Preferences
|
||||
mut:
|
||||
file_backend_mode table.Language // .c for .c.v|.c.vv|.c.vsh files; .js for .js.v files, .v otherwise.
|
||||
scanner &scanner.Scanner
|
||||
comments_mode scanner.CommentsMode = .skip_comments
|
||||
// see comment in parse_file
|
||||
|
@ -101,9 +102,6 @@ pub fn parse_text(text string, path string, table &table.Table, comments_mode sc
|
|||
mut p := Parser{
|
||||
scanner: s
|
||||
comments_mode: comments_mode
|
||||
file_name: path
|
||||
file_base: os.base(path)
|
||||
file_name_dir: os.dir(path)
|
||||
table: table
|
||||
pref: pref
|
||||
scope: &ast.Scope{
|
||||
|
@ -114,9 +112,23 @@ pub fn parse_text(text string, path string, table &table.Table, comments_mode sc
|
|||
warnings: []errors.Warning{}
|
||||
global_scope: global_scope
|
||||
}
|
||||
p.set_path(path)
|
||||
return p.parse()
|
||||
}
|
||||
|
||||
pub fn (mut p Parser) set_path(path string) {
|
||||
p.file_name = path
|
||||
p.file_base = os.base(path)
|
||||
p.file_name_dir = os.dir(path)
|
||||
p.file_backend_mode = .v
|
||||
if path.ends_with('.c.v') || path.ends_with('.c.vv') || path.ends_with('.c.vsh') {
|
||||
p.file_backend_mode = .c
|
||||
}
|
||||
if path.ends_with('.js.v') || path.ends_with('.js.vv') || path.ends_with('.js.vsh') {
|
||||
p.file_backend_mode = .js
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parse_file(path string, table &table.Table, comments_mode scanner.CommentsMode, pref &pref.Preferences, global_scope &ast.Scope) ast.File {
|
||||
// NB: when comments_mode == .toplevel_comments,
|
||||
// the parser gives feedback to the scanner about toplevel statements, so that the scanner can skip
|
||||
|
@ -130,9 +142,6 @@ pub fn parse_file(path string, table &table.Table, comments_mode scanner.Comment
|
|||
scanner: scanner.new_scanner_file(path, comments_mode, pref)
|
||||
comments_mode: comments_mode
|
||||
table: table
|
||||
file_name: path
|
||||
file_base: os.base(path)
|
||||
file_name_dir: os.dir(path)
|
||||
pref: pref
|
||||
scope: &ast.Scope{
|
||||
start_pos: 0
|
||||
|
@ -142,6 +151,7 @@ pub fn parse_file(path string, table &table.Table, comments_mode scanner.Comment
|
|||
warnings: []errors.Warning{}
|
||||
global_scope: global_scope
|
||||
}
|
||||
p.set_path(path)
|
||||
return p.parse()
|
||||
}
|
||||
|
||||
|
@ -153,9 +163,6 @@ pub fn parse_vet_file(path string, table_ &table.Table, pref &pref.Preferences)
|
|||
scanner: scanner.new_vet_scanner_file(path, .parse_comments, pref)
|
||||
comments_mode: .parse_comments
|
||||
table: table_
|
||||
file_name: path
|
||||
file_base: os.base(path)
|
||||
file_name_dir: os.dir(path)
|
||||
pref: pref
|
||||
scope: &ast.Scope{
|
||||
start_pos: 0
|
||||
|
@ -165,6 +172,7 @@ pub fn parse_vet_file(path string, table_ &table.Table, pref &pref.Preferences)
|
|||
warnings: []errors.Warning{}
|
||||
global_scope: global_scope
|
||||
}
|
||||
p.set_path(path)
|
||||
if p.scanner.text.contains('\n ') {
|
||||
source_lines := os.read_lines(path) or { []string{} }
|
||||
for lnumber, line in source_lines {
|
||||
|
@ -845,6 +853,29 @@ fn (mut p Parser) parse_attr() table.Attr {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn (mut p Parser) check_for_impure_v(language table.Language, pos token.Position) {
|
||||
if language == .v {
|
||||
// pure V code is always allowed everywhere
|
||||
return
|
||||
}
|
||||
if !p.pref.warn_impure_v {
|
||||
// the stricter mode is not ON yet => allow everything for now
|
||||
return
|
||||
}
|
||||
if p.file_backend_mode != language {
|
||||
upcase_language := language.str().to_upper()
|
||||
if p.file_backend_mode == .v {
|
||||
p.warn_with_pos('$upcase_language code will not be allowed in pure .v files, please move it to a .${language}.v file instead',
|
||||
pos)
|
||||
return
|
||||
} else {
|
||||
p.warn_with_pos('$upcase_language code is not allowed in .${p.file_backend_mode}.v files, please move it to a .${language}.v file',
|
||||
pos)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn (mut p Parser) error(s string) {
|
||||
p.error_with_pos(s, p.tok.position())
|
||||
}
|
||||
|
@ -1016,12 +1047,13 @@ pub fn (mut p Parser) name_expr() ast.Expr {
|
|||
pos: type_pos
|
||||
}
|
||||
}
|
||||
language := if p.tok.lit == 'C' {
|
||||
table.Language.c
|
||||
mut language := table.Language.v
|
||||
if p.tok.lit == 'C' {
|
||||
language = table.Language.c
|
||||
p.check_for_impure_v(language, p.tok.position())
|
||||
} else if p.tok.lit == 'JS' {
|
||||
table.Language.js
|
||||
} else {
|
||||
table.Language.v
|
||||
language = table.Language.js
|
||||
p.check_for_impure_v(language, p.tok.position())
|
||||
}
|
||||
mut mod := ''
|
||||
// p.warn('resetting')
|
||||
|
@ -2030,12 +2062,13 @@ fn (mut p Parser) type_decl() ast.TypeDecl {
|
|||
parent_type := first_type
|
||||
parent_name := p.table.get_type_symbol(parent_type).name
|
||||
pid := parent_type.idx()
|
||||
language := if parent_name.len > 2 && parent_name.starts_with('C.') {
|
||||
table.Language.c
|
||||
mut language := table.Language.v
|
||||
if parent_name.len > 2 && parent_name.starts_with('C.') {
|
||||
language = table.Language.c
|
||||
p.check_for_impure_v(language, decl_pos)
|
||||
} else if parent_name.len > 2 && parent_name.starts_with('JS.') {
|
||||
table.Language.js
|
||||
} else {
|
||||
table.Language.v
|
||||
language = table.Language.js
|
||||
p.check_for_impure_v(language, decl_pos)
|
||||
}
|
||||
prepend_mod_name := p.prepend_mod(name)
|
||||
p.table.register_type_symbol(table.TypeSymbol{
|
||||
|
|
|
@ -36,6 +36,7 @@ fn (mut p Parser) struct_decl() ast.StructDecl {
|
|||
p.next() // .
|
||||
}
|
||||
name_pos := p.tok.position()
|
||||
p.check_for_impure_v(language, name_pos)
|
||||
mut name := p.check_name()
|
||||
// defer {
|
||||
// if name.contains('App') {
|
||||
|
|
|
@ -121,7 +121,8 @@ pub mut:
|
|||
printfn_list []string // a list of generated function names, whose source should be shown, for debugging
|
||||
print_v_files bool // when true, just print the list of all parsed .v files then stop.
|
||||
skip_running bool // when true, do no try to run the produced file (set by b.cc(), when -o x.c or -o x.js)
|
||||
skip_warnings bool // like C's "-w"
|
||||
skip_warnings bool // like C's "-w", forces warnings to be ignored.
|
||||
warn_impure_v bool // -Wimpure-v, force a warning for JS.fn()/C.fn(), outside of .js.v/.c.v files. TODO: turn to an error by default
|
||||
warns_are_errors bool // -W, like C's "-Werror", treat *every* warning is an error
|
||||
fatal_errors bool // unconditionally exit after the first error with exit(1)
|
||||
reuse_tmpc bool // do not use random names for .tmp.c and .tmp.c.rsp files, and do not remove them
|
||||
|
@ -173,6 +174,9 @@ pub fn parse_args(args []string) (&Preferences, string) {
|
|||
'-progress' {
|
||||
// processed by testing tools in cmd/tools/modules/testing/common.v
|
||||
}
|
||||
'-Wimpure-v' {
|
||||
res.warn_impure_v = true
|
||||
}
|
||||
'-Wfatal-errors' {
|
||||
res.fatal_errors = true
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue