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

pull/2159/head
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.fgen('fn ')
//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
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
//if !p.builtin_mod && receiver_typ.contains('*') {
if receiver_typ.contains('*') {
if receiver_typ.ends_with('*') {
t := receiver_typ.replace('*', '')
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
p.register_var(receiver)
}
// +-/* methods
if p.tok == .plus || p.tok == .minus || p.tok == .mul {
f.name = p.tok.str()
p.next()
@ -398,28 +410,7 @@ fn (p mut Parser) fn_decl() {
// First pass? Skip the body for now
// Look for generic calls.
if !is_sig && !is_fn_header {
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
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()
}
p.skip_fn_body()
}
// Live code reloading? Load all fns from .so
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() {
for var in p.local_vars {
if var.name == '' {
@ -894,6 +914,8 @@ fn (p mut Parser) fn_call_args(f mut Fn) &Fn {
}
got := typ
expected := arg.typ
got_ptr := got.ends_with('*')
exp_ptr := expected.ends_with('*')
// println('fn arg got="$got" exp="$expected"')
if !p.check_types_no_throw(got, expected) {
mut j := i
@ -912,18 +934,23 @@ fn (p mut Parser) fn_call_args(f mut Fn) &Fn {
'argument to `$f.name()`')
}
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 {
// Dereference
if got.ends_with('*') && !expected.ends_with('*') {
if got_ptr && !exp_ptr {
p.cgen.set_placeholder(ph, '*')
}
// Reference
// 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,
// 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.gen('}[0] ')
}
@ -937,9 +964,8 @@ fn (p mut Parser) fn_call_args(f mut Fn) &Fn {
}
}
}
// interface?
if is_interface {
if !got.contains('*') {
else if is_interface {
if !got_ptr {
p.cgen.set_placeholder(ph, '&')
}
// Pass all interface methods
@ -985,7 +1011,7 @@ fn (p mut Parser) fn_call_args(f mut Fn) &Fn {
}
// "fn (int, string) int"
fn (f Fn) typ_str() string {
fn (f &Fn) typ_str() string {
mut sb := strings.new_builder(50)
sb.write('fn (')
for i, arg in f.args {
@ -1001,6 +1027,10 @@ fn (f Fn) typ_str() string {
return sb.str()
}
fn (f &Fn) v_definition() string {
return 'todo'
}
// f.args => "int a, string b"
fn (f &Fn) str_args(table &Table) string {
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 { '' }
}
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
}
/*
// For debugging types
fn (t Type) str() string {
mut s := 'type "$t.name" {'
@ -146,6 +147,7 @@ fn (t Type) str() string {
s += '}\n'
return s
}
*/
const (
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) {
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
mut t := p.table.typesmap[type_name]
if type_name == 'str' {
println(t.methods.len)
if f.name != 'str' && f in t.methods {
p.error('redefinition of method `${type_name}.$f.name`')
}
t.methods << f
if type_name == 'str' {
println(t.methods.len)
}
p.table.typesmap[type_name] = t
}

View File

@ -12,7 +12,7 @@
- bring back vdoc and regenerate all module docs
- optimize the parser (reduce map lookups)
- 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
- rewrite objective c code in v (ui_mac.m)
- v ui for macos

View File

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