parser: make script mode errors more informative, when a top level declaration is encountered, after script mode had already started
parent
20139ad756
commit
668d1b04d2
|
@ -9,6 +9,9 @@ import v.token
|
|||
|
||||
pub fn (mut p Parser) expr(precedence int) ast.Expr {
|
||||
return p.check_expr(precedence) or {
|
||||
if token.is_decl(p.tok.kind) && p.disallow_declarations_in_script_mode() {
|
||||
return ast.empty_expr()
|
||||
}
|
||||
p.error_with_pos('invalid expression: unexpected $p.tok', p.tok.pos())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -673,10 +673,10 @@ fn (mut p Parser) fn_receiver(mut params []ast.Param, mut rec ReceiverParsingInf
|
|||
fn (mut p Parser) anon_fn() ast.AnonFn {
|
||||
pos := p.tok.pos()
|
||||
p.check(.key_fn)
|
||||
if p.pref.is_script && p.tok.kind == .name {
|
||||
p.error_with_pos('function declarations in script mode should be before all script statements',
|
||||
p.tok.pos())
|
||||
return ast.AnonFn{}
|
||||
if p.tok.kind == .name {
|
||||
if p.disallow_declarations_in_script_mode() {
|
||||
return ast.AnonFn{}
|
||||
}
|
||||
}
|
||||
old_inside_defer := p.inside_defer
|
||||
p.inside_defer = false
|
||||
|
|
|
@ -93,6 +93,8 @@ mut:
|
|||
codegen_text string
|
||||
struct_init_generic_types []ast.Type
|
||||
if_cond_comments []ast.Comment
|
||||
script_mode bool
|
||||
script_mode_start_token token.Token
|
||||
}
|
||||
|
||||
__global codegen_files = []&ast.File{}
|
||||
|
@ -685,12 +687,17 @@ pub fn (mut p Parser) top_stmt() ast.Stmt {
|
|||
else {
|
||||
p.inside_fn = true
|
||||
if p.pref.is_script && !p.pref.is_test {
|
||||
p.script_mode = true
|
||||
p.script_mode_start_token = p.tok
|
||||
|
||||
p.open_scope()
|
||||
mut stmts := []ast.Stmt{}
|
||||
for p.tok.kind != .eof {
|
||||
stmts << p.stmt(false)
|
||||
}
|
||||
p.close_scope()
|
||||
|
||||
p.script_mode = false
|
||||
return ast.FnDecl{
|
||||
name: 'main.main'
|
||||
short_name: 'main'
|
||||
|
@ -3276,6 +3283,9 @@ fn (mut p Parser) const_decl() ast.ConstDecl {
|
|||
p.next()
|
||||
}
|
||||
const_pos := p.tok.pos()
|
||||
if p.disallow_declarations_in_script_mode() {
|
||||
return ast.ConstDecl{}
|
||||
}
|
||||
p.check(.key_const)
|
||||
is_block := p.tok.kind == .lpar
|
||||
if is_block {
|
||||
|
@ -3390,6 +3400,9 @@ fn (mut p Parser) global_decl() ast.GlobalDecl {
|
|||
}
|
||||
start_pos := p.tok.pos()
|
||||
p.check(.key_global)
|
||||
if p.disallow_declarations_in_script_mode() {
|
||||
return ast.GlobalDecl{}
|
||||
}
|
||||
is_block := p.tok.kind == .lpar
|
||||
if is_block {
|
||||
p.next() // (
|
||||
|
@ -3485,6 +3498,9 @@ fn (mut p Parser) enum_decl() ast.EnumDecl {
|
|||
}
|
||||
p.check(.key_enum)
|
||||
end_pos := p.tok.pos()
|
||||
if p.disallow_declarations_in_script_mode() {
|
||||
return ast.EnumDecl{}
|
||||
}
|
||||
enum_name := p.check_name()
|
||||
if enum_name.len == 1 {
|
||||
p.error_with_pos('single letter capital names are reserved for generic template types.',
|
||||
|
@ -3597,6 +3613,9 @@ fn (mut p Parser) type_decl() ast.TypeDecl {
|
|||
end_pos := p.tok.pos()
|
||||
decl_pos := start_pos.extend(end_pos)
|
||||
name_pos := p.tok.pos()
|
||||
if p.disallow_declarations_in_script_mode() {
|
||||
return ast.SumTypeDecl{}
|
||||
}
|
||||
name := p.check_name()
|
||||
if name.len == 1 && name[0].is_capital() {
|
||||
p.error_with_pos('single letter capital names are reserved for generic template types.',
|
||||
|
@ -3889,6 +3908,15 @@ fn (mut p Parser) unsafe_stmt() ast.Stmt {
|
|||
}
|
||||
}
|
||||
|
||||
fn (mut p Parser) disallow_declarations_in_script_mode() bool {
|
||||
if p.script_mode {
|
||||
p.note_with_pos('script mode started here', p.script_mode_start_token.pos())
|
||||
p.error_with_pos('all definitions must occur before code in script mode', p.tok.pos())
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
fn (mut p Parser) trace(fbase string, message string) {
|
||||
if p.file_base == fbase {
|
||||
println('> p.trace | ${fbase:-10s} | $message')
|
||||
|
|
|
@ -36,6 +36,9 @@ fn (mut p Parser) struct_decl() ast.StructDecl {
|
|||
}
|
||||
name_pos := p.tok.pos()
|
||||
p.check_for_impure_v(language, name_pos)
|
||||
if p.disallow_declarations_in_script_mode() {
|
||||
return ast.StructDecl{}
|
||||
}
|
||||
mut name := p.check_name()
|
||||
// defer {
|
||||
// if name.contains('App') {
|
||||
|
@ -471,6 +474,9 @@ fn (mut p Parser) interface_decl() ast.InterfaceDecl {
|
|||
}
|
||||
name_pos := p.tok.pos()
|
||||
p.check_for_impure_v(language, name_pos)
|
||||
if p.disallow_declarations_in_script_mode() {
|
||||
return ast.InterfaceDecl{}
|
||||
}
|
||||
modless_name := p.check_name()
|
||||
if modless_name == 'IError' && p.mod != 'builtin' {
|
||||
p.error_with_pos('cannot register interface `IError`, it is builtin interface type',
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
vlib/v/parser/tests/invalid_enum_decl_script_err.vv:1:1: notice: script mode started here
|
||||
1 | mynum := 10
|
||||
| ~~~~~
|
||||
2 |
|
||||
3 | enum MyEnum {
|
||||
vlib/v/parser/tests/invalid_enum_decl_script_err.vv:3:1: error: all definitions must occur before code in script mode
|
||||
1 | mynum := 10
|
||||
2 |
|
||||
3 | enum MyEnum {
|
||||
| ~~~~
|
||||
4 | aa
|
||||
5 | bb
|
|
@ -0,0 +1,7 @@
|
|||
mynum := 10
|
||||
|
||||
enum MyEnum {
|
||||
aa
|
||||
bb
|
||||
cc
|
||||
}
|
|
@ -1,7 +1,12 @@
|
|||
vlib/v/parser/tests/invalid_fn_decl_script_err.vv:3:4: error: function declarations in script mode should be before all script statements
|
||||
vlib/v/parser/tests/invalid_fn_decl_script_err.vv:1:1: notice: script mode started here
|
||||
1 | mynum := 10
|
||||
| ~~~~~
|
||||
2 |
|
||||
3 | fn my_function() {
|
||||
vlib/v/parser/tests/invalid_fn_decl_script_err.vv:3:4: error: all definitions must occur before code in script mode
|
||||
1 | mynum := 10
|
||||
2 |
|
||||
3 | fn main() {
|
||||
| ~~~~
|
||||
3 | fn my_function() {
|
||||
| ~~~~~~~~~~~
|
||||
4 | println(mynum)
|
||||
5 | }
|
|
@ -1,5 +1,5 @@
|
|||
mynum := 10
|
||||
|
||||
fn main() {
|
||||
fn my_function() {
|
||||
println(mynum)
|
||||
}
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
vlib/v/parser/tests/invalid_interface_decl_script_err.vv:1:1: notice: script mode started here
|
||||
1 | mynum := 10
|
||||
| ~~~~~
|
||||
2 |
|
||||
3 | interface IUniversal {
|
||||
vlib/v/parser/tests/invalid_interface_decl_script_err.vv:3:1: error: all definitions must occur before code in script mode
|
||||
1 | mynum := 10
|
||||
2 |
|
||||
3 | interface IUniversal {
|
||||
| ~~~~~~~~~
|
||||
4 | }
|
|
@ -0,0 +1,4 @@
|
|||
mynum := 10
|
||||
|
||||
interface IUniversal {
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
vlib/v/parser/tests/invalid_struct_decl_script_err.vv:1:1: notice: script mode started here
|
||||
1 | mynum := 10
|
||||
| ~~~~~
|
||||
2 |
|
||||
3 | struct Abc {
|
||||
vlib/v/parser/tests/invalid_struct_decl_script_err.vv:3:1: error: all definitions must occur before code in script mode
|
||||
1 | mynum := 10
|
||||
2 |
|
||||
3 | struct Abc {
|
||||
| ~~~~~~
|
||||
4 | x int
|
||||
5 | }
|
|
@ -0,0 +1,5 @@
|
|||
mynum := 10
|
||||
|
||||
struct Abc {
|
||||
x int
|
||||
}
|
Loading…
Reference in New Issue