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 main() { | ||||
|       |    ~~~~ | ||||
|       | ~~~~~ | ||||
|     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 my_function() { | ||||
|       |    ~~~~~~~~~~~ | ||||
|     4 |     println(mynum) | ||||
|     5 | } | ||||
|     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