mirror of
https://github.com/vlang/v.git
synced 2023-08-10 21:13:21 +03:00
all: static type methods
This commit is contained in:
parent
aacdd61e67
commit
a9f8b5dadc
@ -105,7 +105,7 @@ fn (app App) gen_api_for_module_in_os(mod_name string, os_name string) string {
|
|||||||
for s in f.stmts {
|
for s in f.stmts {
|
||||||
if s is ast.FnDecl {
|
if s is ast.FnDecl {
|
||||||
if s.is_pub {
|
if s.is_pub {
|
||||||
fn_signature := s.stringify(b.table, mod_name, map[string]string{})
|
fn_signature := s.stringify_fn_decl(b.table, mod_name, map[string]string{})
|
||||||
fn_mod := s.modname()
|
fn_mod := s.modname()
|
||||||
if fn_mod == mod_name {
|
if fn_mod == mod_name {
|
||||||
fline := '${fn_mod}: ${fn_signature}'
|
fline := '${fn_mod}: ${fn_signature}'
|
||||||
|
108
vlib/v/ast/ast.v
108
vlib/v/ast/ast.v
@ -505,40 +505,41 @@ pub mut:
|
|||||||
[minify]
|
[minify]
|
||||||
pub struct FnDecl {
|
pub struct FnDecl {
|
||||||
pub:
|
pub:
|
||||||
name string // 'math.bits.normalize'
|
name string // 'math.bits.normalize'
|
||||||
short_name string // 'normalize'
|
short_name string // 'normalize'
|
||||||
mod string // 'math.bits'
|
mod string // 'math.bits'
|
||||||
is_deprecated bool
|
is_deprecated bool
|
||||||
is_pub bool
|
is_pub bool
|
||||||
is_variadic bool
|
is_variadic bool
|
||||||
is_anon bool
|
is_anon bool
|
||||||
is_noreturn bool // true, when [noreturn] is used on a fn
|
is_noreturn bool // true, when [noreturn] is used on a fn
|
||||||
is_manualfree bool // true, when [manualfree] is used on a fn
|
is_manualfree bool // true, when [manualfree] is used on a fn
|
||||||
is_main bool // true for `fn main()`
|
is_main bool // true for `fn main()`
|
||||||
is_test bool // true for `fn test_abcde() {}`, false for `fn test_abc(x int) {}`, or for fns that do not start with test_
|
is_test bool // true for `fn test_abcde() {}`, false for `fn test_abc(x int) {}`, or for fns that do not start with test_
|
||||||
is_conditional bool // true for `[if abc] fn abc(){}`
|
is_conditional bool // true for `[if abc] fn abc(){}`
|
||||||
is_exported bool // true for `[export: 'exact_C_name']`
|
is_exported bool // true for `[export: 'exact_C_name']`
|
||||||
is_keep_alive bool // passed memory must not be freed (by GC) before function returns
|
is_keep_alive bool // passed memory must not be freed (by GC) before function returns
|
||||||
is_unsafe bool // true, when [unsafe] is used on a fn
|
is_unsafe bool // true, when [unsafe] is used on a fn
|
||||||
is_markused bool // true, when an explicit `[markused]` tag was put on a fn; `-skip-unused` will not remove that fn
|
is_markused bool // true, when an explicit `[markused]` tag was put on a fn; `-skip-unused` will not remove that fn
|
||||||
is_file_translated bool // true, when the file it resides in is `[translated]`
|
is_file_translated bool // true, when the file it resides in is `[translated]`
|
||||||
receiver StructField // TODO this is not a struct field
|
receiver StructField // TODO this is not a struct field
|
||||||
receiver_pos token.Pos // `(u User)` in `fn (u User) name()` position
|
receiver_pos token.Pos // `(u User)` in `fn (u User) name()` position
|
||||||
is_method bool
|
is_method bool
|
||||||
method_type_pos token.Pos // `User` in ` fn (u User)` position
|
is_static_type_method bool // true for `fn Foo.bar() {}`
|
||||||
method_idx int
|
method_type_pos token.Pos // `User` in ` fn (u User)` position
|
||||||
rec_mut bool // is receiver mutable
|
method_idx int
|
||||||
rec_share ShareType
|
rec_mut bool // is receiver mutable
|
||||||
language Language // V, C, JS
|
rec_share ShareType
|
||||||
file_mode Language // whether *the file*, where a function was a '.c.v', '.js.v' etc.
|
language Language // V, C, JS
|
||||||
no_body bool // just a definition `fn C.malloc()`
|
file_mode Language // whether *the file*, where a function was a '.c.v', '.js.v' etc.
|
||||||
is_builtin bool // this function is defined in builtin/strconv
|
no_body bool // just a definition `fn C.malloc()`
|
||||||
body_pos token.Pos // function bodys position
|
is_builtin bool // this function is defined in builtin/strconv
|
||||||
file string
|
body_pos token.Pos // function bodys position
|
||||||
generic_names []string
|
file string
|
||||||
is_direct_arr bool // direct array access
|
generic_names []string
|
||||||
attrs []Attr
|
is_direct_arr bool // direct array access
|
||||||
ctdefine_idx int = -1 // the index in fn.attrs of `[if xyz]`, when such attribute exists
|
attrs []Attr
|
||||||
|
ctdefine_idx int = -1 // the index in fn.attrs of `[if xyz]`, when such attribute exists
|
||||||
pub mut:
|
pub mut:
|
||||||
idx int // index in an external container; can be used to refer to the function in a more efficient way, just by its integer index
|
idx int // index in an external container; can be used to refer to the function in a more efficient way, just by its integer index
|
||||||
params []Param
|
params []Param
|
||||||
@ -578,25 +579,26 @@ pub fn (f &FnDecl) new_method_with_receiver_type(new_type Type) FnDecl {
|
|||||||
[minify]
|
[minify]
|
||||||
pub struct Fn {
|
pub struct Fn {
|
||||||
pub:
|
pub:
|
||||||
is_variadic bool
|
is_variadic bool
|
||||||
language Language
|
language Language
|
||||||
is_pub bool
|
is_pub bool
|
||||||
is_ctor_new bool // `[use_new] fn JS.Array.prototype.constructor()`
|
is_ctor_new bool // `[use_new] fn JS.Array.prototype.constructor()`
|
||||||
is_deprecated bool // `[deprecated] fn abc(){}`
|
is_deprecated bool // `[deprecated] fn abc(){}`
|
||||||
is_noreturn bool // `[noreturn] fn abc(){}`
|
is_noreturn bool // `[noreturn] fn abc(){}`
|
||||||
is_unsafe bool // `[unsafe] fn abc(){}`
|
is_unsafe bool // `[unsafe] fn abc(){}`
|
||||||
is_placeholder bool
|
is_placeholder bool
|
||||||
is_main bool // `fn main(){}`
|
is_main bool // `fn main(){}`
|
||||||
is_test bool // `fn test_abc(){}`
|
is_test bool // `fn test_abc(){}`
|
||||||
is_keep_alive bool // passed memory must not be freed (by GC) before function returns
|
is_keep_alive bool // passed memory must not be freed (by GC) before function returns
|
||||||
is_method bool // true for `fn (x T) name()`, and for interface declarations (which are also for methods)
|
is_method bool // true for `fn (x T) name()`, and for interface declarations (which are also for methods)
|
||||||
no_body bool // a pure declaration like `fn abc(x int)`; used in .vh files, C./JS. fns.
|
is_static_type_method bool // true for `fn Foo.bar() {}`
|
||||||
is_file_translated bool // true, when the file it resides in is `[translated]`
|
no_body bool // a pure declaration like `fn abc(x int)`; used in .vh files, C./JS. fns.
|
||||||
mod string
|
is_file_translated bool // true, when the file it resides in is `[translated]`
|
||||||
file string
|
mod string
|
||||||
file_mode Language
|
file string
|
||||||
pos token.Pos
|
file_mode Language
|
||||||
return_type_pos token.Pos
|
pos token.Pos
|
||||||
|
return_type_pos token.Pos
|
||||||
pub mut:
|
pub mut:
|
||||||
return_type Type
|
return_type Type
|
||||||
receiver_type Type // != 0, when .is_method == true
|
receiver_type Type // != 0, when .is_method == true
|
||||||
|
@ -41,7 +41,7 @@ pub fn (node &CallExpr) fkey() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// These methods are used only by vfmt, vdoc, and for debugging.
|
// These methods are used only by vfmt, vdoc, and for debugging.
|
||||||
pub fn (node &AnonFn) stringify(t &Table, cur_mod string, m2a map[string]string) string {
|
pub fn (node &AnonFn) stringify_anon_decl(t &Table, cur_mod string, m2a map[string]string) string {
|
||||||
mut f := strings.new_builder(30)
|
mut f := strings.new_builder(30)
|
||||||
f.write_string('fn ')
|
f.write_string('fn ')
|
||||||
if node.inherited_vars.len > 0 {
|
if node.inherited_vars.len > 0 {
|
||||||
@ -65,7 +65,7 @@ pub fn (node &AnonFn) stringify(t &Table, cur_mod string, m2a map[string]string)
|
|||||||
return f.str()
|
return f.str()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (node &FnDecl) stringify(t &Table, cur_mod string, m2a map[string]string) string {
|
pub fn (node &FnDecl) stringify_fn_decl(t &Table, cur_mod string, m2a map[string]string) string {
|
||||||
mut f := strings.new_builder(30)
|
mut f := strings.new_builder(30)
|
||||||
if node.is_pub {
|
if node.is_pub {
|
||||||
f.write_string('pub ')
|
f.write_string('pub ')
|
||||||
@ -85,12 +85,19 @@ pub fn (node &FnDecl) stringify(t &Table, cur_mod string, m2a map[string]string)
|
|||||||
styp = styp.trim('&')
|
styp = styp.trim('&')
|
||||||
}
|
}
|
||||||
f.write_string(styp + ') ')
|
f.write_string(styp + ') ')
|
||||||
|
} else if node.is_static_type_method {
|
||||||
|
mut styp := util.no_cur_mod(t.type_to_code(node.receiver.typ.clear_flag(.shared_f)),
|
||||||
|
cur_mod)
|
||||||
|
f.write_string(styp + '.')
|
||||||
}
|
}
|
||||||
name := if !node.is_method && node.language == .v {
|
mut name := if !node.is_method && node.language == .v {
|
||||||
node.name.all_after_last('.')
|
node.name.all_after_last('.')
|
||||||
} else {
|
} else {
|
||||||
node.name
|
node.name
|
||||||
}
|
}
|
||||||
|
if node.is_static_type_method {
|
||||||
|
name = name.after('__static__')
|
||||||
|
}
|
||||||
f.write_string(name)
|
f.write_string(name)
|
||||||
if name in ['+', '-', '*', '/', '%', '<', '>', '==', '!=', '>=', '<='] {
|
if name in ['+', '-', '*', '/', '%', '<', '>', '==', '!=', '>=', '<='] {
|
||||||
f.write_string(' ')
|
f.write_string(' ')
|
||||||
@ -374,6 +381,9 @@ pub fn (x Expr) str() string {
|
|||||||
if x.name.contains('.') {
|
if x.name.contains('.') {
|
||||||
return '${x.name}(${sargs})${propagate_suffix}'
|
return '${x.name}(${sargs})${propagate_suffix}'
|
||||||
}
|
}
|
||||||
|
if x.name.contains('__static__') {
|
||||||
|
return '${x.mod}.${x.name}(${sargs})${propagate_suffix}1'
|
||||||
|
}
|
||||||
return '${x.mod}.${x.name}(${sargs})${propagate_suffix}'
|
return '${x.mod}.${x.name}(${sargs})${propagate_suffix}'
|
||||||
}
|
}
|
||||||
CharLiteral {
|
CharLiteral {
|
||||||
|
@ -590,7 +590,7 @@ pub fn (mut b Builder) print_warnings_and_errors() {
|
|||||||
for stmt in file.stmts {
|
for stmt in file.stmts {
|
||||||
if stmt is ast.FnDecl {
|
if stmt is ast.FnDecl {
|
||||||
if stmt.name == fn_name {
|
if stmt.name == fn_name {
|
||||||
fheader := stmt.stringify(b.table, 'main', map[string]string{})
|
fheader := stmt.stringify_fn_decl(b.table, 'main', map[string]string{})
|
||||||
redefines << FunctionRedefinition{
|
redefines << FunctionRedefinition{
|
||||||
fpath: file.path
|
fpath: file.path
|
||||||
fline: stmt.pos.line_nr
|
fline: stmt.pos.line_nr
|
||||||
|
@ -118,7 +118,7 @@ pub fn (mut d Doc) stmt_signature(stmt ast.Stmt) string {
|
|||||||
return 'module ${stmt.name}'
|
return 'module ${stmt.name}'
|
||||||
}
|
}
|
||||||
ast.FnDecl {
|
ast.FnDecl {
|
||||||
return stmt.stringify(d.table, d.fmt.cur_mod, d.fmt.mod2alias)
|
return stmt.stringify_fn_decl(d.table, d.fmt.cur_mod, d.fmt.mod2alias)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
d.fmt.out = strings.new_builder(1000)
|
d.fmt.out = strings.new_builder(1000)
|
||||||
|
@ -1007,7 +1007,7 @@ pub fn (mut f Fmt) enum_decl(node ast.EnumDecl) {
|
|||||||
|
|
||||||
pub fn (mut f Fmt) fn_decl(node ast.FnDecl) {
|
pub fn (mut f Fmt) fn_decl(node ast.FnDecl) {
|
||||||
f.attrs(node.attrs)
|
f.attrs(node.attrs)
|
||||||
f.write(node.stringify(f.table, f.cur_mod, f.mod2alias)) // `Expr` instead of `ast.Expr` in mod ast
|
f.write(node.stringify_fn_decl(f.table, f.cur_mod, f.mod2alias)) // `Expr` instead of `ast.Expr` in mod ast
|
||||||
// Handle trailing comments after fn header declarations
|
// Handle trailing comments after fn header declarations
|
||||||
if node.no_body && node.end_comments.len > 0 {
|
if node.no_body && node.end_comments.len > 0 {
|
||||||
first_comment := node.end_comments[0]
|
first_comment := node.end_comments[0]
|
||||||
@ -1032,7 +1032,7 @@ pub fn (mut f Fmt) fn_decl(node ast.FnDecl) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn (mut f Fmt) anon_fn(node ast.AnonFn) {
|
pub fn (mut f Fmt) anon_fn(node ast.AnonFn) {
|
||||||
f.write(node.stringify(f.table, f.cur_mod, f.mod2alias)) // `Expr` instead of `ast.Expr` in mod ast
|
f.write(node.stringify_anon_decl(f.table, f.cur_mod, f.mod2alias)) // `Expr` instead of `ast.Expr` in mod ast
|
||||||
f.fn_body(node.decl)
|
f.fn_body(node.decl)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1305,7 +1305,7 @@ pub fn (mut f Fmt) interface_field(field ast.StructField) {
|
|||||||
|
|
||||||
pub fn (mut f Fmt) interface_method(method ast.FnDecl) {
|
pub fn (mut f Fmt) interface_method(method ast.FnDecl) {
|
||||||
f.write('\t')
|
f.write('\t')
|
||||||
f.write(method.stringify(f.table, f.cur_mod, f.mod2alias).all_after_first('fn '))
|
f.write(method.stringify_fn_decl(f.table, f.cur_mod, f.mod2alias).all_after_first('fn '))
|
||||||
f.comments(method.comments, inline: true, has_nl: false, level: .indent)
|
f.comments(method.comments, inline: true, has_nl: false, level: .indent)
|
||||||
f.writeln('')
|
f.writeln('')
|
||||||
f.comments(method.next_comments, inline: false, has_nl: true, level: .indent)
|
f.comments(method.next_comments, inline: false, has_nl: true, level: .indent)
|
||||||
@ -1790,6 +1790,7 @@ pub fn (mut f Fmt) call_expr(node ast.CallExpr) {
|
|||||||
for arg in node.args {
|
for arg in node.args {
|
||||||
f.comments(arg.comments)
|
f.comments(arg.comments)
|
||||||
}
|
}
|
||||||
|
|
||||||
mut is_method_newline := false
|
mut is_method_newline := false
|
||||||
if node.is_method {
|
if node.is_method {
|
||||||
if node.name in ['map', 'filter', 'all', 'any'] {
|
if node.name in ['map', 'filter', 'all', 'any'] {
|
||||||
@ -1826,7 +1827,11 @@ pub fn (mut f Fmt) call_expr(node ast.CallExpr) {
|
|||||||
} else {
|
} else {
|
||||||
name := f.short_module(node.name)
|
name := f.short_module(node.name)
|
||||||
f.mark_import_as_used(name)
|
f.mark_import_as_used(name)
|
||||||
f.write('${name}')
|
if node.name.contains('__static__') {
|
||||||
|
f.write(name.replace('__static__', '.').capitalize())
|
||||||
|
} else {
|
||||||
|
f.write(name)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if node.mod == '' && node.name == '' {
|
if node.mod == '' && node.name == '' {
|
||||||
|
@ -893,12 +893,12 @@ pub fn (mut f Gen) enum_decl(node ast.EnumDecl) {
|
|||||||
|
|
||||||
pub fn (mut f Gen) fn_decl(node ast.FnDecl) {
|
pub fn (mut f Gen) fn_decl(node ast.FnDecl) {
|
||||||
f.attrs(node.attrs)
|
f.attrs(node.attrs)
|
||||||
f.write(node.stringify(f.table, f.cur_mod, f.mod2alias).replace('fn ', 'func '))
|
f.write(node.stringify_fn_decl(f.table, f.cur_mod, f.mod2alias).replace('fn ', 'func '))
|
||||||
f.fn_body(node)
|
f.fn_body(node)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (mut f Gen) anon_fn(node ast.AnonFn) {
|
pub fn (mut f Gen) anon_fn(node ast.AnonFn) {
|
||||||
f.write(node.stringify(f.table, f.cur_mod, f.mod2alias)) // `Expr` instead of `ast.Expr` in mod ast
|
f.write(node.stringify_fn_decl(f.table, f.cur_mod, f.mod2alias)) // `Expr` instead of `ast.Expr` in mod ast
|
||||||
f.fn_body(node.decl)
|
f.fn_body(node.decl)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1123,7 +1123,7 @@ pub fn (mut f Gen) interface_field(field ast.StructField) {
|
|||||||
|
|
||||||
pub fn (mut f Gen) interface_method(method ast.FnDecl) {
|
pub fn (mut f Gen) interface_method(method ast.FnDecl) {
|
||||||
f.write('\t')
|
f.write('\t')
|
||||||
f.write(method.stringify(f.table, f.cur_mod, f.mod2alias).after('fn '))
|
f.write(method.stringify_fn_decl(f.table, f.cur_mod, f.mod2alias).after('fn '))
|
||||||
f.writeln('')
|
f.writeln('')
|
||||||
for param in method.params {
|
for param in method.params {
|
||||||
f.mark_types_import_as_used(param.typ)
|
f.mark_types_import_as_used(param.typ)
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
// Copyright (c) 2019-2023 Alexander Medvednikov. All rights reserved.
|
// Copyright (c) 2019-2023 Alexander Medvednikov. All rights reserved.
|
||||||
// Use of this source code is governed by an MIT license
|
// Use of this source code is governed by an MIT license
|
||||||
// that can be found in the LICENSE file.
|
// that ca be found in the LICENSE file.
|
||||||
module parser
|
module parser
|
||||||
|
|
||||||
import v.ast
|
import v.ast
|
||||||
@ -10,16 +10,22 @@ import os
|
|||||||
|
|
||||||
fn (mut p Parser) call_expr(language ast.Language, mod string) ast.CallExpr {
|
fn (mut p Parser) call_expr(language ast.Language, mod string) ast.CallExpr {
|
||||||
first_pos := p.tok.pos()
|
first_pos := p.tok.pos()
|
||||||
|
mut name := if language == .js { p.check_js_name() } else { p.check_name() }
|
||||||
|
mut is_static_type_method := language == .v && name[0].is_capital() && p.tok.kind == .dot
|
||||||
|
if is_static_type_method {
|
||||||
|
p.check(.dot)
|
||||||
|
name = name.to_lower() + '__static__' + p.check_name()
|
||||||
|
}
|
||||||
mut fn_name := if language == .c {
|
mut fn_name := if language == .c {
|
||||||
'C.${p.check_name()}'
|
'C.${name}'
|
||||||
} else if language == .js {
|
} else if language == .js {
|
||||||
'JS.${p.check_js_name()}'
|
'JS.${name}'
|
||||||
} else if language == .wasm {
|
} else if language == .wasm {
|
||||||
'WASM.${p.check_name()}'
|
'WASM.${name}'
|
||||||
} else if mod.len > 0 {
|
} else if mod.len > 0 {
|
||||||
'${mod}.${p.check_name()}'
|
'${mod}.${name}'
|
||||||
} else {
|
} else {
|
||||||
p.check_name()
|
name
|
||||||
}
|
}
|
||||||
if language != .v {
|
if language != .v {
|
||||||
p.check_for_impure_v(language, first_pos)
|
p.check_for_impure_v(language, first_pos)
|
||||||
@ -271,6 +277,7 @@ fn (mut p Parser) fn_decl() ast.FnDecl {
|
|||||||
language: language
|
language: language
|
||||||
}
|
}
|
||||||
mut is_method := false
|
mut is_method := false
|
||||||
|
mut is_static_type_method := false
|
||||||
mut params := []ast.Param{}
|
mut params := []ast.Param{}
|
||||||
if p.tok.kind == .lpar {
|
if p.tok.kind == .lpar {
|
||||||
is_method = true
|
is_method = true
|
||||||
@ -288,7 +295,16 @@ fn (mut p Parser) fn_decl() ast.FnDecl {
|
|||||||
name_pos := p.tok.pos()
|
name_pos := p.tok.pos()
|
||||||
if p.tok.kind == .name {
|
if p.tok.kind == .name {
|
||||||
// TODO high order fn
|
// TODO high order fn
|
||||||
name = if language == .js { p.check_js_name() } else { p.check_name() }
|
is_static_type_method = p.tok.lit.len > 0 && p.tok.lit[0].is_capital()
|
||||||
|
&& p.peek_tok.kind == .dot && language == .v // `fn Foo.bar() {}`
|
||||||
|
if is_static_type_method {
|
||||||
|
type_name := p.tok.lit // "Foo"
|
||||||
|
rec.typ = p.parse_type() //_with_mut(false) // ast.Type(p.table.find_type_idx(name))
|
||||||
|
p.check(.dot)
|
||||||
|
name = type_name.to_lower() + '__static__' + p.check_name() // "foo__bar"
|
||||||
|
} else {
|
||||||
|
name = if language == .js { p.check_js_name() } else { p.check_name() }
|
||||||
|
}
|
||||||
if language == .v && !p.pref.translated && !p.is_translated && util.contains_capital(name)
|
if language == .v && !p.pref.translated && !p.is_translated && util.contains_capital(name)
|
||||||
&& !p.builtin_mod {
|
&& !p.builtin_mod {
|
||||||
p.error_with_pos('function names cannot contain uppercase letters, use snake_case instead',
|
p.error_with_pos('function names cannot contain uppercase letters, use snake_case instead',
|
||||||
@ -519,6 +535,8 @@ run them via `v file.v` instead',
|
|||||||
is_test: is_test
|
is_test: is_test
|
||||||
is_keep_alive: is_keep_alive
|
is_keep_alive: is_keep_alive
|
||||||
is_method: false
|
is_method: false
|
||||||
|
is_static_type_method: is_static_type_method
|
||||||
|
receiver_type: rec.typ // used only if is static type method
|
||||||
is_file_translated: p.is_translated
|
is_file_translated: p.is_translated
|
||||||
//
|
//
|
||||||
attrs: p.attrs
|
attrs: p.attrs
|
||||||
@ -588,6 +606,7 @@ run them via `v file.v` instead',
|
|||||||
generic_names: generic_names
|
generic_names: generic_names
|
||||||
receiver_pos: rec.pos
|
receiver_pos: rec.pos
|
||||||
is_method: is_method
|
is_method: is_method
|
||||||
|
is_static_type_method: is_static_type_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.is_mut
|
rec_mut: rec.is_mut
|
||||||
|
@ -515,7 +515,7 @@ fn (mut p Parser) parse_any_type(language ast.Language, is_ptr bool, check_dot b
|
|||||||
name = 'C.${name}'
|
name = 'C.${name}'
|
||||||
} else if language == .js {
|
} else if language == .js {
|
||||||
name = 'JS.${name}'
|
name = 'JS.${name}'
|
||||||
} else if p.peek_tok.kind == .dot && check_dot {
|
} else if p.peek_tok.kind == .dot && check_dot && !name[0].is_capital() {
|
||||||
// `module.Type`
|
// `module.Type`
|
||||||
mut mod := name
|
mut mod := name
|
||||||
mut mod_pos := p.tok.pos()
|
mut mod_pos := p.tok.pos()
|
||||||
|
@ -1941,6 +1941,7 @@ fn (mut p Parser) note(s string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn (mut p Parser) error_with_pos(s string, pos token.Pos) ast.NodeError {
|
fn (mut p Parser) error_with_pos(s string, pos token.Pos) ast.NodeError {
|
||||||
|
// print_backtrace()
|
||||||
mut kind := 'error:'
|
mut kind := 'error:'
|
||||||
if p.pref.fatal_errors {
|
if p.pref.fatal_errors {
|
||||||
util.show_compiler_message(kind, pos: pos, file_path: p.file_name, message: s)
|
util.show_compiler_message(kind, pos: pos, file_path: p.file_name, message: s)
|
||||||
@ -2592,6 +2593,7 @@ fn (mut p Parser) name_expr() ast.Expr {
|
|||||||
is_generic_call := p.is_generic_call()
|
is_generic_call := p.is_generic_call()
|
||||||
is_generic_cast := p.is_generic_cast()
|
is_generic_cast := p.is_generic_cast()
|
||||||
is_generic_struct_init := p.is_generic_struct_init()
|
is_generic_struct_init := p.is_generic_struct_init()
|
||||||
|
// mut is_static_type_method := false
|
||||||
// p.warn('name expr $p.tok.lit $p.peek_tok.str()')
|
// p.warn('name expr $p.tok.lit $p.peek_tok.str()')
|
||||||
same_line := p.tok.line_nr == p.peek_tok.line_nr
|
same_line := p.tok.line_nr == p.peek_tok.line_nr
|
||||||
// `(` must be on same line as name token otherwise it's a ParExpr
|
// `(` must be on same line as name token otherwise it's a ParExpr
|
||||||
@ -2673,6 +2675,7 @@ fn (mut p Parser) name_expr() ast.Expr {
|
|||||||
return node
|
return node
|
||||||
} else {
|
} else {
|
||||||
// fn call
|
// fn call
|
||||||
|
// fn_call:
|
||||||
if is_option {
|
if is_option {
|
||||||
p.unexpected_with_pos(p.prev_tok.pos(),
|
p.unexpected_with_pos(p.prev_tok.pos(),
|
||||||
got: '${p.prev_tok}'
|
got: '${p.prev_tok}'
|
||||||
@ -2745,8 +2748,14 @@ fn (mut p Parser) name_expr() ast.Expr {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if p.peek_token(2).kind == .name && p.peek_token(3).kind == .lpar && !known_var {
|
if p.peek_token(2).kind == .name && p.peek_token(3).kind == .lpar && !known_var {
|
||||||
p.error_with_pos('the receiver of the method call must be an instantiated object, e.g. `foo.bar()`',
|
if lit0_is_capital && p.peek_tok.kind == .dot && language == .v {
|
||||||
p.tok.pos())
|
// New static method call
|
||||||
|
p.expr_mod = ''
|
||||||
|
return p.call_expr(language, mod)
|
||||||
|
} else {
|
||||||
|
p.error_with_pos('${lit0_is_capital} the receiver of the method call must be an instantiated object, e.g. `foo.bar()`',
|
||||||
|
p.tok.pos())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// `Color.green`
|
// `Color.green`
|
||||||
mut enum_name := p.check_name()
|
mut enum_name := p.check_name()
|
||||||
|
@ -1,7 +1,21 @@
|
|||||||
vlib/v/parser/tests/method_call_receiver_err.vv:9:11: error: the receiver of the method call must be an instantiated object, e.g. `foo.bar()`
|
vlib/v/parser/tests/method_call_receiver_err.vv:6:2: warning: unused variable: `s1`
|
||||||
|
4 |
|
||||||
|
5 | fn main() {
|
||||||
|
6 | s1 := S1{}
|
||||||
|
| ~~
|
||||||
|
7 |
|
||||||
|
8 | $for method in S1.methods {
|
||||||
|
vlib/v/parser/tests/method_call_receiver_err.vv:8:7: warning: unused variable: `method`
|
||||||
|
6 | s1 := S1{}
|
||||||
|
7 |
|
||||||
|
8 | $for method in S1.methods {
|
||||||
|
| ~~~~~~
|
||||||
|
9 | println(S1.method_hello('yo'))
|
||||||
|
10 | }
|
||||||
|
vlib/v/parser/tests/method_call_receiver_err.vv:9:11: error: unknown function: s1__static__method_hello
|
||||||
7 |
|
7 |
|
||||||
8 | $for method in S1.methods {
|
8 | $for method in S1.methods {
|
||||||
9 | println(S1.method_hello('yo'))
|
9 | println(S1.method_hello('yo'))
|
||||||
| ~~
|
| ~~~~~~~~~~~~~~~~~~~~~
|
||||||
10 | }
|
10 | }
|
||||||
11 | }
|
11 | }
|
||||||
|
@ -172,3 +172,31 @@ fn test_fn_return_fn() {
|
|||||||
f := ff()
|
f := ff()
|
||||||
assert f() == 22
|
assert f() == 22
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Test new static methods
|
||||||
|
|
||||||
|
struct Foo {
|
||||||
|
x int
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Foo2 {
|
||||||
|
x int
|
||||||
|
}
|
||||||
|
|
||||||
|
fn (f Foo) normal_method() {
|
||||||
|
}
|
||||||
|
|
||||||
|
fn Foo.static_method() int {
|
||||||
|
return 7
|
||||||
|
}
|
||||||
|
|
||||||
|
fn Foo2.static_method() int {
|
||||||
|
return 8
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_static_method() {
|
||||||
|
x := Foo.static_method()
|
||||||
|
assert x == 7
|
||||||
|
x2 := Foo2.static_method()
|
||||||
|
assert x2 == 8
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user