parser: cleanup fn_decl (#8700)
parent
848295cdea
commit
70a30374b9
|
@ -161,6 +161,16 @@ pub fn (mut p Parser) call_args() []ast.CallArg {
|
||||||
return args
|
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 {
|
fn (mut p Parser) fn_decl() ast.FnDecl {
|
||||||
p.top_level_statement_start()
|
p.top_level_statement_start()
|
||||||
start_pos := p.tok.position()
|
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())
|
p.check_for_impure_v(language, p.tok.position())
|
||||||
}
|
}
|
||||||
// Receiver?
|
// Receiver?
|
||||||
mut rec_name := ''
|
mut rec := ReceiverParsingInfo{
|
||||||
|
typ: table.void_type
|
||||||
|
language: language
|
||||||
|
}
|
||||||
mut is_method := false
|
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{}
|
mut params := []table.Param{}
|
||||||
if p.tok.kind == .lpar {
|
if p.tok.kind == .lpar {
|
||||||
lpar_pos := p.tok.position()
|
|
||||||
p.next() // (
|
|
||||||
is_method = true
|
is_method = true
|
||||||
is_shared := p.tok.kind == .key_shared
|
p.fn_receiver(mut params, mut rec) or { return ast.FnDecl{
|
||||||
is_atomic := p.tok.kind == .key_atomic
|
scope: 0
|
||||||
rec_mut = p.tok.kind == .key_mut || is_shared || is_atomic
|
} }
|
||||||
if rec_mut {
|
|
||||||
p.next() // `mut`
|
// rec.language was initialized with language variable.
|
||||||
}
|
// So language is changed only if rec.language has been changed.
|
||||||
rec_start_pos := p.tok.position()
|
language = rec.language
|
||||||
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)
|
|
||||||
}
|
}
|
||||||
mut name := ''
|
mut name := ''
|
||||||
if p.tok.kind == .name {
|
if p.tok.kind == .name {
|
||||||
|
@ -268,7 +226,7 @@ fn (mut p Parser) fn_decl() ast.FnDecl {
|
||||||
scope: 0
|
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
|
// 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_) {
|
if is_method && (type_sym.has_method(name) && type_sym.kind != .interface_) {
|
||||||
p.error_with_pos('duplicate method `$name`', pos)
|
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 {
|
} 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()
|
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.error_with_pos('cannot use operator overloading with normal functions',
|
||||||
p.tok.position())
|
p.tok.position())
|
||||||
}
|
}
|
||||||
|
@ -337,20 +295,20 @@ fn (mut p Parser) fn_decl() ast.FnDecl {
|
||||||
no_body := p.tok.kind != .lcbr
|
no_body := p.tok.kind != .lcbr
|
||||||
// Register
|
// Register
|
||||||
if is_method {
|
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
|
// Do not allow to modify / add methods to types from other modules
|
||||||
// arrays/maps dont belong to a module only their element types do
|
// 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
|
// 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
|
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
|
// check maps & arrays, must be defined in same module as the elem type
|
||||||
if !is_non_local && type_sym.kind in [.array, .map] {
|
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
|
is_non_local = elem_type_sym.mod.len > 0 && elem_type_sym.mod != p.mod
|
||||||
&& elem_type_sym.language == .v
|
&& elem_type_sym.language == .v
|
||||||
}
|
}
|
||||||
if is_non_local {
|
if is_non_local {
|
||||||
p.error_with_pos('cannot define new methods on non-local type $type_sym.name',
|
p.error_with_pos('cannot define new methods on non-local type $type_sym.name',
|
||||||
rec_type_pos)
|
rec.type_pos)
|
||||||
return ast.FnDecl{
|
return ast.FnDecl{
|
||||||
scope: 0
|
scope: 0
|
||||||
}
|
}
|
||||||
|
@ -427,15 +385,15 @@ fn (mut p Parser) fn_decl() ast.FnDecl {
|
||||||
is_pub: is_pub
|
is_pub: is_pub
|
||||||
is_variadic: is_variadic
|
is_variadic: is_variadic
|
||||||
receiver: ast.Field{
|
receiver: ast.Field{
|
||||||
name: rec_name
|
name: rec.name
|
||||||
typ: rec_type
|
typ: rec.typ
|
||||||
}
|
}
|
||||||
generic_params: generic_params
|
generic_params: generic_params
|
||||||
receiver_pos: receiver_pos
|
receiver_pos: rec.pos
|
||||||
is_method: is_method
|
is_method: is_method
|
||||||
method_type_pos: rec_type_pos
|
method_type_pos: rec.type_pos
|
||||||
method_idx: type_sym_method_idx
|
method_idx: type_sym_method_idx
|
||||||
rec_mut: rec_mut
|
rec_mut: rec.is_mut
|
||||||
language: language
|
language: language
|
||||||
no_body: no_body
|
no_body: no_body
|
||||||
pos: start_pos.extend_with_last_line(end_pos, p.prev_tok.line_nr)
|
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
|
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 {
|
fn (mut p Parser) parse_generic_params() []ast.GenericParam {
|
||||||
mut param_names := []string{}
|
mut param_names := []string{}
|
||||||
if p.tok.kind != .lt {
|
if p.tok.kind != .lt {
|
||||||
|
|
Loading…
Reference in New Issue