parser: make script mode errors more informative, when a top level declaration is encountered, after script mode had already started
parent
b1b10f48ad
commit
b9ee4204df
|
@ -9,6 +9,9 @@ import v.token
|
||||||
|
|
||||||
pub fn (mut p Parser) expr(precedence int) ast.Expr {
|
pub fn (mut p Parser) expr(precedence int) ast.Expr {
|
||||||
return p.check_expr(precedence) or {
|
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())
|
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 {
|
fn (mut p Parser) anon_fn() ast.AnonFn {
|
||||||
pos := p.tok.pos()
|
pos := p.tok.pos()
|
||||||
p.check(.key_fn)
|
p.check(.key_fn)
|
||||||
if p.pref.is_script && p.tok.kind == .name {
|
if p.tok.kind == .name {
|
||||||
p.error_with_pos('function declarations in script mode should be before all script statements',
|
if p.disallow_declarations_in_script_mode() {
|
||||||
p.tok.pos())
|
return ast.AnonFn{}
|
||||||
return ast.AnonFn{}
|
}
|
||||||
}
|
}
|
||||||
old_inside_defer := p.inside_defer
|
old_inside_defer := p.inside_defer
|
||||||
p.inside_defer = false
|
p.inside_defer = false
|
||||||
|
|
|
@ -93,6 +93,8 @@ mut:
|
||||||
codegen_text string
|
codegen_text string
|
||||||
struct_init_generic_types []ast.Type
|
struct_init_generic_types []ast.Type
|
||||||
if_cond_comments []ast.Comment
|
if_cond_comments []ast.Comment
|
||||||
|
script_mode bool
|
||||||
|
script_mode_start_token token.Token
|
||||||
}
|
}
|
||||||
|
|
||||||
__global codegen_files = []&ast.File{}
|
__global codegen_files = []&ast.File{}
|
||||||
|
@ -685,12 +687,17 @@ pub fn (mut p Parser) top_stmt() ast.Stmt {
|
||||||
else {
|
else {
|
||||||
p.inside_fn = true
|
p.inside_fn = true
|
||||||
if p.pref.is_script && !p.pref.is_test {
|
if p.pref.is_script && !p.pref.is_test {
|
||||||
|
p.script_mode = true
|
||||||
|
p.script_mode_start_token = p.tok
|
||||||
|
|
||||||
p.open_scope()
|
p.open_scope()
|
||||||
mut stmts := []ast.Stmt{}
|
mut stmts := []ast.Stmt{}
|
||||||
for p.tok.kind != .eof {
|
for p.tok.kind != .eof {
|
||||||
stmts << p.stmt(false)
|
stmts << p.stmt(false)
|
||||||
}
|
}
|
||||||
p.close_scope()
|
p.close_scope()
|
||||||
|
|
||||||
|
p.script_mode = false
|
||||||
return ast.FnDecl{
|
return ast.FnDecl{
|
||||||
name: 'main.main'
|
name: 'main.main'
|
||||||
short_name: 'main'
|
short_name: 'main'
|
||||||
|
@ -3276,6 +3283,9 @@ fn (mut p Parser) const_decl() ast.ConstDecl {
|
||||||
p.next()
|
p.next()
|
||||||
}
|
}
|
||||||
const_pos := p.tok.pos()
|
const_pos := p.tok.pos()
|
||||||
|
if p.disallow_declarations_in_script_mode() {
|
||||||
|
return ast.ConstDecl{}
|
||||||
|
}
|
||||||
p.check(.key_const)
|
p.check(.key_const)
|
||||||
is_block := p.tok.kind == .lpar
|
is_block := p.tok.kind == .lpar
|
||||||
if is_block {
|
if is_block {
|
||||||
|
@ -3390,6 +3400,9 @@ fn (mut p Parser) global_decl() ast.GlobalDecl {
|
||||||
}
|
}
|
||||||
start_pos := p.tok.pos()
|
start_pos := p.tok.pos()
|
||||||
p.check(.key_global)
|
p.check(.key_global)
|
||||||
|
if p.disallow_declarations_in_script_mode() {
|
||||||
|
return ast.GlobalDecl{}
|
||||||
|
}
|
||||||
is_block := p.tok.kind == .lpar
|
is_block := p.tok.kind == .lpar
|
||||||
if is_block {
|
if is_block {
|
||||||
p.next() // (
|
p.next() // (
|
||||||
|
@ -3485,6 +3498,9 @@ fn (mut p Parser) enum_decl() ast.EnumDecl {
|
||||||
}
|
}
|
||||||
p.check(.key_enum)
|
p.check(.key_enum)
|
||||||
end_pos := p.tok.pos()
|
end_pos := p.tok.pos()
|
||||||
|
if p.disallow_declarations_in_script_mode() {
|
||||||
|
return ast.EnumDecl{}
|
||||||
|
}
|
||||||
enum_name := p.check_name()
|
enum_name := p.check_name()
|
||||||
if enum_name.len == 1 {
|
if enum_name.len == 1 {
|
||||||
p.error_with_pos('single letter capital names are reserved for generic template types.',
|
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()
|
end_pos := p.tok.pos()
|
||||||
decl_pos := start_pos.extend(end_pos)
|
decl_pos := start_pos.extend(end_pos)
|
||||||
name_pos := p.tok.pos()
|
name_pos := p.tok.pos()
|
||||||
|
if p.disallow_declarations_in_script_mode() {
|
||||||
|
return ast.SumTypeDecl{}
|
||||||
|
}
|
||||||
name := p.check_name()
|
name := p.check_name()
|
||||||
if name.len == 1 && name[0].is_capital() {
|
if name.len == 1 && name[0].is_capital() {
|
||||||
p.error_with_pos('single letter capital names are reserved for generic template types.',
|
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) {
|
fn (mut p Parser) trace(fbase string, message string) {
|
||||||
if p.file_base == fbase {
|
if p.file_base == fbase {
|
||||||
println('> p.trace | ${fbase:-10s} | $message')
|
println('> p.trace | ${fbase:-10s} | $message')
|
||||||
|
|
|
@ -36,6 +36,9 @@ fn (mut p Parser) struct_decl() ast.StructDecl {
|
||||||
}
|
}
|
||||||
name_pos := p.tok.pos()
|
name_pos := p.tok.pos()
|
||||||
p.check_for_impure_v(language, name_pos)
|
p.check_for_impure_v(language, name_pos)
|
||||||
|
if p.disallow_declarations_in_script_mode() {
|
||||||
|
return ast.StructDecl{}
|
||||||
|
}
|
||||||
mut name := p.check_name()
|
mut name := p.check_name()
|
||||||
// defer {
|
// defer {
|
||||||
// if name.contains('App') {
|
// if name.contains('App') {
|
||||||
|
@ -471,6 +474,9 @@ fn (mut p Parser) interface_decl() ast.InterfaceDecl {
|
||||||
}
|
}
|
||||||
name_pos := p.tok.pos()
|
name_pos := p.tok.pos()
|
||||||
p.check_for_impure_v(language, name_pos)
|
p.check_for_impure_v(language, name_pos)
|
||||||
|
if p.disallow_declarations_in_script_mode() {
|
||||||
|
return ast.InterfaceDecl{}
|
||||||
|
}
|
||||||
modless_name := p.check_name()
|
modless_name := p.check_name()
|
||||||
if modless_name == 'IError' && p.mod != 'builtin' {
|
if modless_name == 'IError' && p.mod != 'builtin' {
|
||||||
p.error_with_pos('cannot register interface `IError`, it is builtin interface type',
|
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
|
1 | mynum := 10
|
||||||
2 |
|
2 |
|
||||||
3 | fn main() {
|
3 | fn my_function() {
|
||||||
| ~~~~
|
| ~~~~~~~~~~~
|
||||||
4 | println(mynum)
|
4 | println(mynum)
|
||||||
5 | }
|
5 | }
|
|
@ -1,5 +1,5 @@
|
||||||
mynum := 10
|
mynum := 10
|
||||||
|
|
||||||
fn main() {
|
fn my_function() {
|
||||||
println(mynum)
|
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