1
0
mirror of https://github.com/vlang/v.git synced 2023-08-10 21:13:21 +03:00

do not allow duplicate methods; fix os_win.v; minor fixes and docs

This commit is contained in:
Alexander Medvednikov 2019-09-29 00:21:10 +03:00
parent d482b1f824
commit a52662fca0
4 changed files with 82 additions and 43 deletions

View File

@ -146,7 +146,18 @@ fn (p mut Parser) fn_decl() {
p.clear_vars() // clear local vars every time a new fn is started p.clear_vars() // clear local vars every time a new fn is started
p.fgen('fn ') p.fgen('fn ')
//defer { p.fgenln('\n') } //defer { p.fgenln('\n') }
mut f := Fn { // If we are in the first pass, create a new function.
// In the second pass fetch the one we created.
/*
mut f := if p.first_pass {
Fn{
mod: p.mod
is_public: p.tok == .key_pub
}
else {
}
*/
mut f := Fn{
mod: p.mod mod: p.mod
is_public: p.tok == .key_pub is_public: p.tok == .key_pub
} }
@ -185,7 +196,7 @@ fn (p mut Parser) fn_decl() {
} }
// `(f *Foo)` instead of `(f mut Foo)` is a common mistake // `(f *Foo)` instead of `(f mut Foo)` is a common mistake
//if !p.builtin_mod && receiver_typ.contains('*') { //if !p.builtin_mod && receiver_typ.contains('*') {
if receiver_typ.contains('*') { if receiver_typ.ends_with('*') {
t := receiver_typ.replace('*', '') t := receiver_typ.replace('*', '')
p.error('use `($receiver_name mut $t)` instead of `($receiver_name *$t)`') p.error('use `($receiver_name mut $t)` instead of `($receiver_name *$t)`')
} }
@ -208,6 +219,7 @@ fn (p mut Parser) fn_decl() {
f.args << receiver f.args << receiver
p.register_var(receiver) p.register_var(receiver)
} }
// +-/* methods
if p.tok == .plus || p.tok == .minus || p.tok == .mul { if p.tok == .plus || p.tok == .minus || p.tok == .mul {
f.name = p.tok.str() f.name = p.tok.str()
p.next() p.next()
@ -398,28 +410,7 @@ fn (p mut Parser) fn_decl() {
// First pass? Skip the body for now // First pass? Skip the body for now
// Look for generic calls. // Look for generic calls.
if !is_sig && !is_fn_header { if !is_sig && !is_fn_header {
mut opened_scopes := 0 p.skip_fn_body()
mut closed_scopes := 0
for {
if p.tok == .lcbr {
opened_scopes++
}
if p.tok == .rcbr {
closed_scopes++
}
// find `foo<Bar>()` in function bodies and register generic types
// TODO
if p.tok.is_decl() {
break
}
// fn body ended, and a new fn attribute declaration like [live] is starting?
if closed_scopes > opened_scopes && p.prev_tok == .rcbr {
if p.tok == .lsbr {
break
}
}
p.next()
}
} }
// Live code reloading? Load all fns from .so // Live code reloading? Load all fns from .so
if is_live && p.first_pass() && p.mod == 'main' { if is_live && p.first_pass() && p.mod == 'main' {
@ -510,6 +501,35 @@ fn (p mut Parser) fn_decl() {
} }
} }
[inline]
// Skips the entire function's body in the first pass.
fn (p mut Parser) skip_fn_body() {
mut opened_scopes := 0
mut closed_scopes := 0
for {
if p.tok == .lcbr {
opened_scopes++
}
if p.tok == .rcbr {
closed_scopes++
}
// find `foo<Bar>()` in function bodies and register generic types
// TODO
// ...
// Reached a declaration token? (fn, struct, const etc) Stop.
if p.tok.is_decl() {
break
}
// fn body ended, and a new fn attribute declaration like [live] is starting?
if closed_scopes > opened_scopes && p.prev_tok == .rcbr {
if p.tok == .lsbr {
break
}
}
p.next()
}
}
fn (p mut Parser) check_unused_variables() { fn (p mut Parser) check_unused_variables() {
for var in p.local_vars { for var in p.local_vars {
if var.name == '' { if var.name == '' {
@ -894,6 +914,8 @@ fn (p mut Parser) fn_call_args(f mut Fn) &Fn {
} }
got := typ got := typ
expected := arg.typ expected := arg.typ
got_ptr := got.ends_with('*')
exp_ptr := expected.ends_with('*')
// println('fn arg got="$got" exp="$expected"') // println('fn arg got="$got" exp="$expected"')
if !p.check_types_no_throw(got, expected) { if !p.check_types_no_throw(got, expected) {
mut j := i mut j := i
@ -912,18 +934,23 @@ fn (p mut Parser) fn_call_args(f mut Fn) &Fn {
'argument to `$f.name()`') 'argument to `$f.name()`')
} }
is_interface := p.table.is_interface(arg.typ) is_interface := p.table.is_interface(arg.typ)
// Add `&` or `*` before an argument? // Automatically add `&` or `*` before an argument.
// V, unlike C and Go, simplifies this aspect:
// `foo(bar)` is allowed where `foo(&bar)` is expected.
// The argument is not mutable, so it won't be changed by the function.
// It doesn't matter whether it's passed by referencee or by value
// to the end user.
if !is_interface { if !is_interface {
// Dereference // Dereference
if got.ends_with('*') && !expected.ends_with('*') { if got_ptr && !exp_ptr {
p.cgen.set_placeholder(ph, '*') p.cgen.set_placeholder(ph, '*')
} }
// Reference // Reference
// TODO ptr hacks. DOOM hacks, fix please. // TODO ptr hacks. DOOM hacks, fix please.
if !got.ends_with('*') && expected.ends_with('*') && got != 'voidptr' { if !got_ptr && exp_ptr && got != 'voidptr' {
// Special case for mutable arrays. We can't `&` function results, // Special case for mutable arrays. We can't `&` function results,
// have to use `(array[]){ expr }` hack. // have to use `(array[]){ expr }` hack.
if expected.starts_with('array_') && expected.ends_with('*') { if expected.starts_with('array_') && exp_ptr {
p.cgen.set_placeholder(ph, '& /*111*/ (array[]){') p.cgen.set_placeholder(ph, '& /*111*/ (array[]){')
p.gen('}[0] ') p.gen('}[0] ')
} }
@ -937,9 +964,8 @@ fn (p mut Parser) fn_call_args(f mut Fn) &Fn {
} }
} }
} }
// interface? else if is_interface {
if is_interface { if !got_ptr {
if !got.contains('*') {
p.cgen.set_placeholder(ph, '&') p.cgen.set_placeholder(ph, '&')
} }
// Pass all interface methods // Pass all interface methods
@ -985,7 +1011,7 @@ fn (p mut Parser) fn_call_args(f mut Fn) &Fn {
} }
// "fn (int, string) int" // "fn (int, string) int"
fn (f Fn) typ_str() string { fn (f &Fn) typ_str() string {
mut sb := strings.new_builder(50) mut sb := strings.new_builder(50)
sb.write('fn (') sb.write('fn (')
for i, arg in f.args { for i, arg in f.args {
@ -1001,6 +1027,10 @@ fn (f Fn) typ_str() string {
return sb.str() return sb.str()
} }
fn (f &Fn) v_definition() string {
return 'todo'
}
// f.args => "int a, string b" // f.args => "int a, string b"
fn (f &Fn) str_args(table &Table) string { fn (f &Fn) str_args(table &Table) string {
mut s := '' mut s := ''
@ -1056,3 +1086,12 @@ fn (p &Parser) find_misspelled_local_var(name string, min_match f32) string {
} }
return if closest >= min_match { closest_var } else { '' } return if closest >= min_match { closest_var } else { '' }
} }
fn (fns []Fn) contains(f Fn) bool {
for ff in fns {
if ff.name == f.name {
return true
}
}
return false
}

View File

@ -126,6 +126,7 @@ struct TypeNode {
typ Type typ Type
} }
/*
// For debugging types // For debugging types
fn (t Type) str() string { fn (t Type) str() string {
mut s := 'type "$t.name" {' mut s := 'type "$t.name" {'
@ -146,6 +147,7 @@ fn (t Type) str() string {
s += '}\n' s += '}\n'
return s return s
} }
*/
const ( const (
CReserved = [ CReserved = [
@ -321,6 +323,8 @@ fn (p mut Parser) register_global(name, typ string) {
} }
} }
// Only for module functions, not methods.
// That's why searching by fn name works.
fn (t mut Table) register_fn(new_fn Fn) { fn (t mut Table) register_fn(new_fn Fn) {
t.fns[new_fn.name] = new_fn t.fns[new_fn.name] = new_fn
} }
@ -469,14 +473,10 @@ fn (p mut Parser) add_method(type_name string, f Fn) {
} }
// TODO table.typesmap[type_name].methods << f // TODO table.typesmap[type_name].methods << f
mut t := p.table.typesmap[type_name] mut t := p.table.typesmap[type_name]
if type_name == 'str' { if f.name != 'str' && f in t.methods {
println(t.methods.len) p.error('redefinition of method `${type_name}.$f.name`')
} }
t.methods << f t.methods << f
if type_name == 'str' {
println(t.methods.len)
}
p.table.typesmap[type_name] = t p.table.typesmap[type_name] = t
} }

View File

@ -12,7 +12,7 @@
- bring back vdoc and regenerate all module docs - bring back vdoc and regenerate all module docs
- optimize the parser (reduce map lookups) - optimize the parser (reduce map lookups)
- cache vlib (right now it's re-compiled every time) - cache vlib (right now it's re-compiled every time)
- fix openssl on older linux distros + fix openssl on older linux distros
- chat.vlang.io - chat.vlang.io
- rewrite objective c code in v (ui_mac.m) - rewrite objective c code in v (ui_mac.m)
- v ui for macos - v ui for macos

View File

@ -13,14 +13,14 @@ type HANDLE voidptr
// win: FILETIME // win: FILETIME
// https://docs.microsoft.com/en-us/windows/win32/api/minwinbase/ns-minwinbase-filetime // https://docs.microsoft.com/en-us/windows/win32/api/minwinbase/ns-minwinbase-filetime
struct filetime { struct Filetime {
dwLowDateTime u32 dwLowDateTime u32
dwHighDateTime u32 dwHighDateTime u32
} }
// win: WIN32_FIND_DATA // win: WIN32_FIND_DATA
// https://docs.microsoft.com/en-us/windows/win32/api/minwinbase/ns-minwinbase-_win32_find_dataw // https://docs.microsoft.com/en-us/windows/win32/api/minwinbase/ns-minwinbase-_win32_find_dataw
struct win32finddata { struct Win32finddata {
mut: mut:
dwFileAttributes u32 dwFileAttributes u32
ftCreationTime filetime ftCreationTime filetime
@ -52,7 +52,7 @@ fn init_os_args(argc int, argv &byteptr) []string {
pub fn ls(path string) []string { pub fn ls(path string) []string {
mut find_file_data := win32finddata{} mut find_file_data := Win32finddata{}
mut dir_files := []string mut dir_files := []string
// We can also check if the handle is valid. but using dir_exists instead // We can also check if the handle is valid. but using dir_exists instead
// h_find_dir := C.FindFirstFile(path.str, &find_file_data) // h_find_dir := C.FindFirstFile(path.str, &find_file_data)