parser: cleanup fn_decl (#8700)
							parent
							
								
									848295cdea
								
							
						
					
					
						commit
						70a30374b9
					
				|  | @ -161,6 +161,16 @@ pub fn (mut p Parser) call_args() []ast.CallArg { | |||
| 	return args | ||||
| } | ||||
| 
 | ||||
| struct ReceiverParsingInfo { | ||||
| mut: | ||||
| 	name     string | ||||
| 	pos      token.Position | ||||
| 	typ      table.Type | ||||
| 	type_pos token.Position | ||||
| 	is_mut   bool | ||||
| 	language table.Language | ||||
| } | ||||
| 
 | ||||
| fn (mut p Parser) fn_decl() ast.FnDecl { | ||||
| 	p.top_level_statement_start() | ||||
| 	start_pos := p.tok.position() | ||||
|  | @ -188,73 +198,21 @@ fn (mut p Parser) fn_decl() ast.FnDecl { | |||
| 		p.check_for_impure_v(language, p.tok.position()) | ||||
| 	} | ||||
| 	// Receiver?
 | ||||
| 	mut rec_name := '' | ||||
| 	mut rec := ReceiverParsingInfo{ | ||||
| 		typ: table.void_type | ||||
| 		language: language | ||||
| 	} | ||||
| 	mut is_method := false | ||||
| 	mut receiver_pos := token.Position{} | ||||
| 	mut rec_type_pos := token.Position{} | ||||
| 	mut rec_type := table.void_type | ||||
| 	mut rec_mut := false | ||||
| 	mut params := []table.Param{} | ||||
| 	if p.tok.kind == .lpar { | ||||
| 		lpar_pos := p.tok.position() | ||||
| 		p.next() // (
 | ||||
| 		is_method = true | ||||
| 		is_shared := p.tok.kind == .key_shared | ||||
| 		is_atomic := p.tok.kind == .key_atomic | ||||
| 		rec_mut = p.tok.kind == .key_mut || is_shared || is_atomic | ||||
| 		if rec_mut { | ||||
| 			p.next() // `mut`
 | ||||
| 		} | ||||
| 		rec_start_pos := p.tok.position() | ||||
| 		rec_name = p.check_name() | ||||
| 		if !rec_mut { | ||||
| 			rec_mut = p.tok.kind == .key_mut | ||||
| 			if rec_mut { | ||||
| 				p.warn_with_pos('use `(mut f Foo)` instead of `(f mut Foo)`', lpar_pos.extend(p.peek_tok2.position())) | ||||
| 			} | ||||
| 		} | ||||
| 		if p.tok.kind == .key_shared { | ||||
| 			p.error_with_pos('use `(shared f Foo)` instead of `(f shared Foo)`', lpar_pos.extend(p.peek_tok2.position())) | ||||
| 		} | ||||
| 		receiver_pos = rec_start_pos.extend(p.tok.position()) | ||||
| 		is_amp := p.tok.kind == .amp | ||||
| 		if p.tok.kind == .name && p.tok.lit == 'JS' { | ||||
| 			language = table.Language.js | ||||
| 		} | ||||
| 		// if rec_mut {
 | ||||
| 		// p.check(.key_mut)
 | ||||
| 		// }
 | ||||
| 		// TODO: talk to alex, should mut be parsed with the type like this?
 | ||||
| 		// or should it be a property of the arg, like this ptr/mut becomes indistinguishable
 | ||||
| 		rec_type_pos = p.tok.position() | ||||
| 		rec_type = p.parse_type_with_mut(rec_mut) | ||||
| 		if rec_type.idx() == 0 { | ||||
| 			// error is set in parse_type
 | ||||
| 			return ast.FnDecl{ | ||||
| 				scope: 0 | ||||
| 			} | ||||
| 		} | ||||
| 		rec_type_pos = rec_type_pos.extend(p.prev_tok.position()) | ||||
| 		if is_amp && rec_mut { | ||||
| 			p.error_with_pos('use `(mut f Foo)` or `(f &Foo)` instead of `(mut f &Foo)`', | ||||
| 				lpar_pos.extend(p.tok.position())) | ||||
| 			return ast.FnDecl{ | ||||
| 				scope: 0 | ||||
| 			} | ||||
| 		} | ||||
| 		if is_shared { | ||||
| 			rec_type = rec_type.set_flag(.shared_f) | ||||
| 		} | ||||
| 		if is_atomic { | ||||
| 			rec_type = rec_type.set_flag(.atomic_f) | ||||
| 		} | ||||
| 		params << table.Param{ | ||||
| 			pos: rec_start_pos | ||||
| 			name: rec_name | ||||
| 			is_mut: rec_mut | ||||
| 			typ: rec_type | ||||
| 		} | ||||
| 		p.check(.rpar) | ||||
| 		p.fn_receiver(mut params, mut rec) or { return ast.FnDecl{ | ||||
| 			scope: 0 | ||||
| 		} } | ||||
| 
 | ||||
| 		// rec.language was initialized with language variable.
 | ||||
| 		// So language is changed only if rec.language has been changed.
 | ||||
| 		language = rec.language | ||||
| 	} | ||||
| 	mut name := '' | ||||
| 	if p.tok.kind == .name { | ||||
|  | @ -268,7 +226,7 @@ fn (mut p Parser) fn_decl() ast.FnDecl { | |||
| 				scope: 0 | ||||
| 			} | ||||
| 		} | ||||
| 		type_sym := p.table.get_type_symbol(rec_type) | ||||
| 		type_sym := p.table.get_type_symbol(rec.typ) | ||||
| 		// interfaces are handled in the checker, methods can not be defined on them this way
 | ||||
| 		if is_method && (type_sym.has_method(name) && type_sym.kind != .interface_) { | ||||
| 			p.error_with_pos('duplicate method `$name`', pos) | ||||
|  | @ -285,7 +243,7 @@ fn (mut p Parser) fn_decl() ast.FnDecl { | |||
| 		} | ||||
| 	} else if p.tok.kind in [.plus, .minus, .mul, .div, .mod, .lt, .eq] && p.peek_tok.kind == .lpar { | ||||
| 		name = p.tok.kind.str() // op_to_fn_name()
 | ||||
| 		if rec_type == table.void_type { | ||||
| 		if rec.typ == table.void_type { | ||||
| 			p.error_with_pos('cannot use operator overloading with normal functions', | ||||
| 				p.tok.position()) | ||||
| 		} | ||||
|  | @ -337,20 +295,20 @@ fn (mut p Parser) fn_decl() ast.FnDecl { | |||
| 	no_body := p.tok.kind != .lcbr | ||||
| 	// Register
 | ||||
| 	if is_method { | ||||
| 		mut type_sym := p.table.get_type_symbol(rec_type) | ||||
| 		mut type_sym := p.table.get_type_symbol(rec.typ) | ||||
| 		// Do not allow to modify / add methods to types from other modules
 | ||||
| 		// arrays/maps dont belong to a module only their element types do
 | ||||
| 		// we could also check if kind is .array,  .array_fixed, .map instead of mod.len
 | ||||
| 		mut is_non_local := type_sym.mod.len > 0 && type_sym.mod != p.mod && type_sym.language == .v | ||||
| 		// check maps & arrays, must be defined in same module as the elem type
 | ||||
| 		if !is_non_local && type_sym.kind in [.array, .map] { | ||||
| 			elem_type_sym := p.table.get_type_symbol(p.table.value_type(rec_type)) | ||||
| 			elem_type_sym := p.table.get_type_symbol(p.table.value_type(rec.typ)) | ||||
| 			is_non_local = elem_type_sym.mod.len > 0 && elem_type_sym.mod != p.mod | ||||
| 				&& elem_type_sym.language == .v | ||||
| 		} | ||||
| 		if is_non_local { | ||||
| 			p.error_with_pos('cannot define new methods on non-local type $type_sym.name', | ||||
| 				rec_type_pos) | ||||
| 				rec.type_pos) | ||||
| 			return ast.FnDecl{ | ||||
| 				scope: 0 | ||||
| 			} | ||||
|  | @ -427,15 +385,15 @@ fn (mut p Parser) fn_decl() ast.FnDecl { | |||
| 		is_pub: is_pub | ||||
| 		is_variadic: is_variadic | ||||
| 		receiver: ast.Field{ | ||||
| 			name: rec_name | ||||
| 			typ: rec_type | ||||
| 			name: rec.name | ||||
| 			typ: rec.typ | ||||
| 		} | ||||
| 		generic_params: generic_params | ||||
| 		receiver_pos: receiver_pos | ||||
| 		receiver_pos: rec.pos | ||||
| 		is_method: is_method | ||||
| 		method_type_pos: rec_type_pos | ||||
| 		method_type_pos: rec.type_pos | ||||
| 		method_idx: type_sym_method_idx | ||||
| 		rec_mut: rec_mut | ||||
| 		rec_mut: rec.is_mut | ||||
| 		language: language | ||||
| 		no_body: no_body | ||||
| 		pos: start_pos.extend_with_last_line(end_pos, p.prev_tok.line_nr) | ||||
|  | @ -451,6 +409,65 @@ fn (mut p Parser) fn_decl() ast.FnDecl { | |||
| 	return fn_decl | ||||
| } | ||||
| 
 | ||||
| fn (mut p Parser) fn_receiver(mut params []table.Param, mut rec ReceiverParsingInfo) ? { | ||||
| 	lpar_pos := p.tok.position() | ||||
| 	p.next() // (
 | ||||
| 	is_shared := p.tok.kind == .key_shared | ||||
| 	is_atomic := p.tok.kind == .key_atomic | ||||
| 	rec.is_mut = p.tok.kind == .key_mut || is_shared || is_atomic | ||||
| 	if rec.is_mut { | ||||
| 		p.next() // `mut`
 | ||||
| 	} | ||||
| 	rec_start_pos := p.tok.position() | ||||
| 	rec.name = p.check_name() | ||||
| 	if !rec.is_mut { | ||||
| 		rec.is_mut = p.tok.kind == .key_mut | ||||
| 		if rec.is_mut { | ||||
| 			p.warn_with_pos('use `(mut f Foo)` instead of `(f mut Foo)`', lpar_pos.extend(p.peek_tok2.position())) | ||||
| 		} | ||||
| 	} | ||||
| 	if p.tok.kind == .key_shared { | ||||
| 		p.error_with_pos('use `(shared f Foo)` instead of `(f shared Foo)`', lpar_pos.extend(p.peek_tok2.position())) | ||||
| 	} | ||||
| 	rec.pos = rec_start_pos.extend(p.tok.position()) | ||||
| 	is_amp := p.tok.kind == .amp | ||||
| 	if p.tok.kind == .name && p.tok.lit == 'JS' { | ||||
| 		rec.language = table.Language.js | ||||
| 	} | ||||
| 	// if rec.is_mut {
 | ||||
| 	// p.check(.key_mut)
 | ||||
| 	// }
 | ||||
| 	// TODO: talk to alex, should mut be parsed with the type like this?
 | ||||
| 	// or should it be a property of the arg, like this ptr/mut becomes indistinguishable
 | ||||
| 	rec.type_pos = p.tok.position() | ||||
| 	rec.typ = p.parse_type_with_mut(rec.is_mut) | ||||
| 	if rec.typ.idx() == 0 { | ||||
| 		// error is set in parse_type
 | ||||
| 		return none | ||||
| 	} | ||||
| 	rec.type_pos = rec.type_pos.extend(p.prev_tok.position()) | ||||
| 	if is_amp && rec.is_mut { | ||||
| 		p.error_with_pos('use `(mut f Foo)` or `(f &Foo)` instead of `(mut f &Foo)`', | ||||
| 			lpar_pos.extend(p.tok.position())) | ||||
| 		return none | ||||
| 	} | ||||
| 	if is_shared { | ||||
| 		rec.typ = rec.typ.set_flag(.shared_f) | ||||
| 	} | ||||
| 	if is_atomic { | ||||
| 		rec.typ = rec.typ.set_flag(.atomic_f) | ||||
| 	} | ||||
| 	params << table.Param{ | ||||
| 		pos: rec_start_pos | ||||
| 		name: rec.name | ||||
| 		is_mut: rec.is_mut | ||||
| 		typ: rec.typ | ||||
| 	} | ||||
| 	p.check(.rpar) | ||||
| 
 | ||||
| 	return | ||||
| } | ||||
| 
 | ||||
| fn (mut p Parser) parse_generic_params() []ast.GenericParam { | ||||
| 	mut param_names := []string{} | ||||
| 	if p.tok.kind != .lt { | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue