checker: disallow pub in main
parent
de9f302412
commit
57c142b993
|
@ -235,7 +235,7 @@ fn find_working_diff_command() ?string {
|
|||
return error('no working diff command found')
|
||||
}
|
||||
|
||||
pub fn (f FormatOptions) str() string {
|
||||
fn (f FormatOptions) str() string {
|
||||
return 'FormatOptions{ is_l: $f.is_l' + ' is_w: $f.is_w' + ' is_diff: $f.is_diff' + ' is_verbose: $f.is_verbose' +
|
||||
' is_all: $f.is_all' + ' is_worker: $f.is_worker' + ' is_debug: $f.is_debug' + ' }'
|
||||
}
|
||||
|
|
|
@ -3,10 +3,8 @@
|
|||
// that can be found in the LICENSE file.
|
||||
module ast
|
||||
|
||||
import (
|
||||
v.token
|
||||
v.table
|
||||
)
|
||||
import v.token
|
||||
import v.table
|
||||
|
||||
pub type TypeDecl = AliasTypeDecl | SumTypeDecl | FnTypeDecl
|
||||
|
||||
|
@ -95,9 +93,9 @@ mut:
|
|||
// module declaration
|
||||
pub struct Module {
|
||||
pub:
|
||||
name string
|
||||
path string
|
||||
expr Expr
|
||||
name string
|
||||
path string
|
||||
expr Expr
|
||||
is_skipped bool // module main can be skipped in single file programs
|
||||
}
|
||||
|
||||
|
@ -162,7 +160,7 @@ pub struct StructInitField {
|
|||
pub:
|
||||
name string
|
||||
expr Expr
|
||||
pos token.Position
|
||||
pos token.Position
|
||||
mut:
|
||||
typ table.Type
|
||||
expected_type table.Type
|
||||
|
@ -189,7 +187,7 @@ pub struct AnonFn {
|
|||
pub:
|
||||
decl FnDecl
|
||||
mut:
|
||||
typ table.Type
|
||||
typ table.Type
|
||||
}
|
||||
|
||||
pub struct FnDecl {
|
||||
|
@ -228,7 +226,7 @@ mut:
|
|||
args []CallArg
|
||||
expected_arg_types []table.Type
|
||||
is_c bool
|
||||
is_js bool
|
||||
is_js bool
|
||||
or_block OrExpr
|
||||
left_type table.Type // type of `user`
|
||||
receiver_type table.Type // User
|
||||
|
@ -326,7 +324,7 @@ pub:
|
|||
tok_kind token.Kind
|
||||
mod string
|
||||
pos token.Position
|
||||
is_mut bool
|
||||
is_mut bool
|
||||
mut:
|
||||
name string
|
||||
kind IdentKind
|
||||
|
@ -537,11 +535,11 @@ pub struct EnumField {
|
|||
|
||||
pub struct EnumDecl {
|
||||
pub:
|
||||
name string
|
||||
is_pub bool
|
||||
fields []EnumField
|
||||
// vals []string
|
||||
name string
|
||||
is_pub bool
|
||||
fields []EnumField
|
||||
// default_exprs []Expr
|
||||
pos token.Position
|
||||
}
|
||||
|
||||
pub struct AliasTypeDecl {
|
||||
|
@ -549,6 +547,7 @@ pub:
|
|||
name string
|
||||
is_pub bool
|
||||
parent_type table.Type
|
||||
pos token.Position
|
||||
}
|
||||
|
||||
pub struct SumTypeDecl {
|
||||
|
@ -556,6 +555,7 @@ pub:
|
|||
name string
|
||||
is_pub bool
|
||||
sub_types []table.Type
|
||||
pos token.Position
|
||||
}
|
||||
|
||||
pub struct FnTypeDecl {
|
||||
|
@ -563,6 +563,7 @@ pub:
|
|||
name string
|
||||
is_pub bool
|
||||
typ table.Type
|
||||
pos token.Position
|
||||
}
|
||||
|
||||
// TODO: handle this differently
|
||||
|
@ -720,30 +721,22 @@ pub:
|
|||
[inline]
|
||||
pub fn expr_is_blank_ident(expr Expr) bool {
|
||||
match expr {
|
||||
Ident {
|
||||
return it.kind == .blank_ident
|
||||
}
|
||||
else {
|
||||
return false
|
||||
}
|
||||
Ident { return it.kind == .blank_ident }
|
||||
else { return false }
|
||||
}
|
||||
}
|
||||
|
||||
[inline]
|
||||
pub fn expr_is_call(expr Expr) bool {
|
||||
return match expr {
|
||||
CallExpr {
|
||||
true
|
||||
}
|
||||
else {
|
||||
false
|
||||
}
|
||||
CallExpr { true }
|
||||
else { false }
|
||||
}
|
||||
}
|
||||
|
||||
fn (expr Expr) position() token.Position {
|
||||
// all uncommented have to be implemented
|
||||
match mut expr {
|
||||
match var expr {
|
||||
ArrayInit {
|
||||
return it.pos
|
||||
}
|
||||
|
|
|
@ -66,11 +66,8 @@ pub fn (c mut Checker) check_files(ast_files []ast.File) {
|
|||
for file in ast_files {
|
||||
c.check(file)
|
||||
if file.mod.name == 'main' {
|
||||
if fn_decl := get_main_fn_decl(file) {
|
||||
if c.check_file_in_main(file) {
|
||||
has_main_fn = true
|
||||
if fn_decl.is_pub {
|
||||
c.error('function `main` cannot be declared public', fn_decl.pos)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -87,16 +84,71 @@ pub fn (c mut Checker) check_files(ast_files []ast.File) {
|
|||
}
|
||||
}
|
||||
|
||||
fn get_main_fn_decl(file ast.File) ?ast.FnDecl {
|
||||
const (
|
||||
no_pub_in_main_warning = 'in module main cannot be declared public'
|
||||
)
|
||||
|
||||
// do checks specific to files in main module
|
||||
// returns `true` if a main function is in the file
|
||||
fn (c mut Checker) check_file_in_main(file ast.File) bool {
|
||||
mut has_main_fn := false
|
||||
for stmt in file.stmts {
|
||||
if stmt is ast.FnDecl {
|
||||
fn_decl := stmt as ast.FnDecl
|
||||
if fn_decl.name == 'main' {
|
||||
return fn_decl
|
||||
match stmt {
|
||||
ast.ConstDecl {
|
||||
if it.is_pub {
|
||||
c.warn('const $no_pub_in_main_warning', it.pos)
|
||||
}
|
||||
}
|
||||
ast.ConstField {
|
||||
if it.is_pub {
|
||||
c.warn('const field `$it.name` $no_pub_in_main_warning', it.pos)
|
||||
}
|
||||
}
|
||||
ast.EnumDecl {
|
||||
if it.is_pub {
|
||||
c.warn('enum `$it.name` $no_pub_in_main_warning', it.pos)
|
||||
}
|
||||
}
|
||||
ast.FnDecl {
|
||||
if it.name == 'main' {
|
||||
has_main_fn = true
|
||||
if it.is_pub {
|
||||
c.error('function `main` cannot be declared public', it.pos)
|
||||
}
|
||||
} else {
|
||||
if it.is_pub {
|
||||
c.warn('function `$it.name` $no_pub_in_main_warning', it.pos)
|
||||
}
|
||||
}
|
||||
}
|
||||
ast.StructDecl {
|
||||
if it.is_pub {
|
||||
c.warn('struct `$it.name` $no_pub_in_main_warning', it.pos)
|
||||
}
|
||||
}
|
||||
ast.TypeDecl {
|
||||
type_decl := stmt as ast.TypeDecl
|
||||
if type_decl is ast.AliasTypeDecl {
|
||||
alias_decl := type_decl as ast.AliasTypeDecl
|
||||
if alias_decl.is_pub {
|
||||
c.warn('type alias `$alias_decl.name` $no_pub_in_main_warning', alias_decl.pos)
|
||||
}
|
||||
} else if type_decl is ast.SumTypeDecl {
|
||||
sum_decl := type_decl as ast.SumTypeDecl
|
||||
if sum_decl.is_pub {
|
||||
c.warn('sum type `$sum_decl.name` $no_pub_in_main_warning', sum_decl.pos)
|
||||
}
|
||||
} else if type_decl is ast.FnTypeDecl {
|
||||
fn_decl := type_decl as ast.FnTypeDecl
|
||||
if fn_decl.is_pub {
|
||||
c.warn('type alias `$fn_decl.name` $no_pub_in_main_warning', fn_decl.pos)
|
||||
}
|
||||
}
|
||||
}
|
||||
else {}
|
||||
}
|
||||
}
|
||||
return none
|
||||
return has_main_fn
|
||||
}
|
||||
|
||||
pub fn (c mut Checker) struct_decl(decl ast.StructDecl) {
|
||||
|
|
|
@ -24,7 +24,8 @@ fn test_all() {
|
|||
os.cp(path, program) or {
|
||||
panic(err)
|
||||
}
|
||||
res := os.exec('$vexe $program') or {
|
||||
// -prod so that warn are errors
|
||||
res := os.exec('$vexe -prod $program') or {
|
||||
panic(err)
|
||||
}
|
||||
mut expected := os.read_file(program.replace('.v', '') + '.out') or {
|
||||
|
|
|
@ -0,0 +1,49 @@
|
|||
vlib/v/checker/tests/inout/no_pub_in_main.v:3:1: error: type alias `Integer` in module main cannot be declared public
|
||||
1| module main
|
||||
2|
|
||||
3| pub type Integer = int
|
||||
~~~~~~~~~~~~~~~~
|
||||
4|
|
||||
5| pub type Float = f32 | f64
|
||||
vlib/v/checker/tests/inout/no_pub_in_main.v:5:1: error: sum type `Float` in module main cannot be declared public
|
||||
3| pub type Integer = int
|
||||
4|
|
||||
5| pub type Float = f32 | f64
|
||||
~~~~~~~~~~~~~~
|
||||
6|
|
||||
7| // Buggy ATM
|
||||
vlib/v/checker/tests/inout/no_pub_in_main.v:10:1: error: enum `Color` in module main cannot be declared public
|
||||
8| // pub type Fn = fn () int
|
||||
9|
|
||||
10| pub enum Color {
|
||||
~~~~~~~~~~~~~~
|
||||
11| red
|
||||
12| green
|
||||
vlib/v/checker/tests/inout/no_pub_in_main.v:16:1: error: const in module main cannot be declared public
|
||||
14| }
|
||||
15|
|
||||
16| pub const (
|
||||
~~~~~~~~~
|
||||
17| w = 'world'
|
||||
18| )
|
||||
vlib/v/checker/tests/inout/no_pub_in_main.v:20:1: error: function `my_fn` in module main cannot be declared public
|
||||
18| )
|
||||
19|
|
||||
20| pub fn my_fn() int {
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
21| return 1
|
||||
22| }
|
||||
vlib/v/checker/tests/inout/no_pub_in_main.v:24:1: error: function `main` cannot be declared public
|
||||
22| }
|
||||
23|
|
||||
24| pub fn main() {
|
||||
~~~~~~~~~~~~~
|
||||
25| println('main')
|
||||
26| }
|
||||
vlib/v/checker/tests/inout/no_pub_in_main.v:28:1: error: struct `MyStruct` in module main cannot be declared public
|
||||
26| }
|
||||
27|
|
||||
28| pub struct MyStruct {
|
||||
~~~~~~~~~~~~~~~~~~~
|
||||
29| field int
|
||||
30| }
|
|
@ -0,0 +1,30 @@
|
|||
module main
|
||||
|
||||
pub type Integer = int
|
||||
|
||||
pub type Float = f32 | f64
|
||||
|
||||
// Buggy ATM
|
||||
// pub type Fn = fn () int
|
||||
|
||||
pub enum Color {
|
||||
red
|
||||
green
|
||||
blue
|
||||
}
|
||||
|
||||
pub const (
|
||||
w = 'world'
|
||||
)
|
||||
|
||||
pub fn my_fn() int {
|
||||
return 1
|
||||
}
|
||||
|
||||
pub fn main() {
|
||||
println('main')
|
||||
}
|
||||
|
||||
pub struct MyStruct {
|
||||
field int
|
||||
}
|
|
@ -1,5 +0,0 @@
|
|||
vlib/v/checker/tests/inout/pub_fn_main.v:1:1: error: function `main` cannot be declared public
|
||||
1| pub fn main() {
|
||||
~~~
|
||||
2| println('Hello world !')
|
||||
3| }
|
|
@ -1,3 +0,0 @@
|
|||
pub fn main() {
|
||||
println('Hello world !')
|
||||
}
|
|
@ -85,7 +85,7 @@ pub fn (var p Parser) call_args() []ast.CallArg {
|
|||
|
||||
fn (var p Parser) fn_decl() ast.FnDecl {
|
||||
// p.table.clear_vars()
|
||||
pos := p.tok.position()
|
||||
start_pos := p.tok.position()
|
||||
p.open_scope()
|
||||
is_deprecated := p.attr == 'deprecated'
|
||||
is_pub := p.tok.kind == .key_pub
|
||||
|
@ -165,9 +165,11 @@ fn (var p Parser) fn_decl() ast.FnDecl {
|
|||
typ: arg.typ
|
||||
})
|
||||
}
|
||||
var end_pos := p.prev_tok.position()
|
||||
// Return type
|
||||
var return_type := table.void_type
|
||||
if p.tok.kind.is_start_of_type() {
|
||||
end_pos = p.tok.position()
|
||||
return_type = p.parse_type()
|
||||
}
|
||||
// Register
|
||||
|
@ -229,7 +231,7 @@ fn (var p Parser) fn_decl() ast.FnDecl {
|
|||
is_c: is_c
|
||||
is_js: is_js
|
||||
no_body: no_body
|
||||
pos: pos
|
||||
pos: start_pos.extend(end_pos)
|
||||
is_builtin: p.builtin_mod || p.mod in util.builtin_module_parts
|
||||
}
|
||||
}
|
||||
|
|
|
@ -945,11 +945,12 @@ fn (var p Parser) import_stmt() []ast.Import {
|
|||
}
|
||||
|
||||
fn (var p Parser) const_decl() ast.ConstDecl {
|
||||
start_pos := p.tok.position()
|
||||
is_pub := p.tok.kind == .key_pub
|
||||
if is_pub {
|
||||
p.next()
|
||||
}
|
||||
pos := p.tok.position()
|
||||
end_pos := p.tok.position()
|
||||
p.check(.key_const)
|
||||
if p.tok.kind != .lpar {
|
||||
p.error('consts must be grouped, e.g.\nconst (\n\ta = 1\n)')
|
||||
|
@ -975,7 +976,7 @@ fn (var p Parser) const_decl() ast.ConstDecl {
|
|||
}
|
||||
p.check(.rpar)
|
||||
return ast.ConstDecl{
|
||||
pos: pos
|
||||
pos: start_pos.extend(end_pos)
|
||||
fields: fields
|
||||
is_pub: is_pub
|
||||
}
|
||||
|
@ -1000,14 +1001,10 @@ fn (var p Parser) return_stmt() ast.Return {
|
|||
break
|
||||
}
|
||||
}
|
||||
last_pos := exprs.last().position()
|
||||
end_pos := exprs.last().position()
|
||||
return ast.Return{
|
||||
exprs: exprs
|
||||
pos: token.Position{
|
||||
line_nr: first_pos.line_nr
|
||||
pos: first_pos.pos
|
||||
len: last_pos.pos - first_pos.pos + last_pos.len
|
||||
}
|
||||
pos: first_pos.extend(end_pos)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1054,10 +1051,12 @@ fn (var p Parser) global_decl() ast.GlobalDecl {
|
|||
|
||||
fn (var p Parser) enum_decl() ast.EnumDecl {
|
||||
is_pub := p.tok.kind == .key_pub
|
||||
start_pos := p.tok.position()
|
||||
if is_pub {
|
||||
p.next()
|
||||
}
|
||||
p.check(.key_enum)
|
||||
end_pos := p.tok.position()
|
||||
name := p.prepend_mod(p.check_name())
|
||||
p.check(.lcbr)
|
||||
var vals := []string
|
||||
|
@ -1101,15 +1100,19 @@ fn (var p Parser) enum_decl() ast.EnumDecl {
|
|||
name: name
|
||||
is_pub: is_pub
|
||||
fields: fields
|
||||
pos: start_pos.extend(end_pos)
|
||||
}
|
||||
}
|
||||
|
||||
fn (var p Parser) type_decl() ast.TypeDecl {
|
||||
start_pos := p.tok.position()
|
||||
is_pub := p.tok.kind == .key_pub
|
||||
if is_pub {
|
||||
p.next()
|
||||
}
|
||||
p.check(.key_type)
|
||||
end_pos := p.tok.position()
|
||||
decl_pos := start_pos.extend(end_pos)
|
||||
name := p.check_name()
|
||||
var sum_variants := []table.Type
|
||||
if p.tok.kind == .assign {
|
||||
|
@ -1123,6 +1126,7 @@ fn (var p Parser) type_decl() ast.TypeDecl {
|
|||
name: fn_name
|
||||
is_pub: is_pub
|
||||
typ: fn_type
|
||||
pos: decl_pos
|
||||
}
|
||||
}
|
||||
first_type := p.parse_type() // need to parse the first type before we can check if it's `type A = X | Y`
|
||||
|
@ -1149,6 +1153,7 @@ fn (var p Parser) type_decl() ast.TypeDecl {
|
|||
name: name
|
||||
is_pub: is_pub
|
||||
sub_types: sum_variants
|
||||
pos: decl_pos
|
||||
}
|
||||
}
|
||||
// type MyType int
|
||||
|
@ -1166,6 +1171,7 @@ fn (var p Parser) type_decl() ast.TypeDecl {
|
|||
name: name
|
||||
is_pub: is_pub
|
||||
parent_type: parent_type
|
||||
pos: decl_pos
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@ import v.table
|
|||
import v.token
|
||||
|
||||
fn (var p Parser) struct_decl() ast.StructDecl {
|
||||
first_pos := p.tok.position()
|
||||
start_pos := p.tok.position()
|
||||
is_pub := p.tok.kind == .key_pub
|
||||
if is_pub {
|
||||
p.next()
|
||||
|
@ -30,6 +30,7 @@ fn (var p Parser) struct_decl() ast.StructDecl {
|
|||
if !is_c && !is_js && no_body {
|
||||
p.error('`$p.tok.lit` lacks body')
|
||||
}
|
||||
end_pos := p.tok.position()
|
||||
var name := p.check_name()
|
||||
// println('struct decl $name')
|
||||
var ast_fields := []ast.StructField
|
||||
|
@ -37,7 +38,6 @@ fn (var p Parser) struct_decl() ast.StructDecl {
|
|||
var mut_pos := -1
|
||||
var pub_pos := -1
|
||||
var pub_mut_pos := -1
|
||||
var last_pos := token.Position{}
|
||||
if !no_body {
|
||||
p.check(.lcbr)
|
||||
for p.tok.kind != .rcbr {
|
||||
|
@ -113,7 +113,6 @@ fn (var p Parser) struct_decl() ast.StructDecl {
|
|||
}
|
||||
// println('struct field $ti.name $field_name')
|
||||
}
|
||||
last_pos = p.tok.position()
|
||||
p.check(.rcbr)
|
||||
}
|
||||
if is_c {
|
||||
|
@ -145,16 +144,11 @@ fn (var p Parser) struct_decl() ast.StructDecl {
|
|||
p.error('cannot register type `$name`, another type with this name exists')
|
||||
}
|
||||
p.expr_mod = ''
|
||||
pos := token.Position{
|
||||
line_nr: first_pos.line_nr
|
||||
pos: first_pos.pos
|
||||
len: last_pos.pos - first_pos.pos + last_pos.len
|
||||
}
|
||||
return ast.StructDecl{
|
||||
name: name
|
||||
is_pub: is_pub
|
||||
fields: ast_fields
|
||||
pos: pos
|
||||
pos: start_pos.extend(end_pos)
|
||||
mut_pos: mut_pos
|
||||
pub_pos: pub_pos
|
||||
pub_mut_pos: pub_mut_pos
|
||||
|
|
|
@ -14,6 +14,13 @@ pub fn (pos Position) str() string {
|
|||
return 'Position{ line_nr: $pos.line_nr, pos: $pos.pos, len: $pos.len }'
|
||||
}
|
||||
|
||||
pub fn (pos Position) extend(end Position) Position {
|
||||
return {
|
||||
pos |
|
||||
len: end.pos - pos.pos + end.len
|
||||
}
|
||||
}
|
||||
|
||||
[inline]
|
||||
pub fn (tok &Token) position() Position {
|
||||
return Position{
|
||||
|
|
Loading…
Reference in New Issue