diff --git a/vlib/compiler/cc.v b/vlib/compiler/cc.v index 2f46fb56f7..8c4c8da7dd 100644 --- a/vlib/compiler/cc.v +++ b/vlib/compiler/cc.v @@ -71,7 +71,7 @@ fn (v mut V) cc() { } if v.pref.ccompiler == 'cc' && os.file_exists(tcc_path) { // TODO tcc bug, needs an empty libtcc1.a fila - //os.mkdir('/var/tmp/tcc/lib/tcc/') + //os.mkdir('/var/tmp/tcc/lib/tcc/') //os.create('/var/tmp/tcc/lib/tcc/libtcc1.a') v.pref.ccompiler = tcc_path } @@ -253,7 +253,7 @@ fn (v mut V) cc() { } } verror('C error. This should never happen. ' + - 'Please create a GitHub issue: https://github.com/vlang/v/issues/new/choose') + '\nPlease create a GitHub issue: https://github.com/vlang/v/issues/new/choose') } diff := time.ticks() - ticks // Print the C command diff --git a/vlib/compiler/fn.v b/vlib/compiler/fn.v index 28d2083fa5..88f58bcd3f 100644 --- a/vlib/compiler/fn.v +++ b/vlib/compiler/fn.v @@ -193,7 +193,7 @@ fn (p mut Parser) fn_decl() { */ mut f := Fn{ mod: p.mod - is_public: p.tok == .key_pub + is_public: p.tok == .key_pub || p.is_vh // functions defined in .vh are always public is_unsafe: p.attr == 'unsafe_fn' is_deprecated: p.attr == 'deprecated' } @@ -219,22 +219,25 @@ fn (p mut Parser) fn_decl() { p.check_space(p.tok) } receiver_typ = p.get_type() - T := p.table.find_type(receiver_typ) - if T.cat == .interface_ { + t := p.table.find_type(receiver_typ) + if (t.name == '' || t.is_placeholder) && !p.first_pass() { + p.error('unknown receiver type `$receiver_typ`') + } + if t.cat == .interface_ { p.error('invalid receiver type `$receiver_typ` (`$receiver_typ` is an interface)') } // Don't allow modifying types from a different module - if !p.first_pass() && !p.builtin_mod && T.mod != p.mod && - p.file_path_id != 'vgen' { // allow .str() on builtin arrays - println('T.mod=$T.mod') - println('p.mod=$p.mod') + if !p.first_pass() && !p.builtin_mod && t.mod != p.mod && + p.file_path_id != 'vgen' // allow .str() on builtin arrays + { + //println('T.mod=$T.mod') + //println('p.mod=$p.mod') p.error('cannot define new methods on non-local type `$receiver_typ`') } // `(f *Foo)` instead of `(f mut Foo)` is a common mistake - //if !p.builtin_mod && receiver_typ.contains('*') { if receiver_typ.ends_with('*') { - t := receiver_typ.replace('*', '') - p.error('use `($receiver_name mut $t)` instead of `($receiver_name *$t)`') + tt := receiver_typ.replace('*', '') + p.error('use `($receiver_name mut $tt)` instead of `($receiver_name *$tt)`') } f.receiver_typ = receiver_typ if is_mut || is_amp { @@ -281,6 +284,7 @@ fn (p mut Parser) fn_decl() { } else if !p.pref.translated { if contains_capital(f.name) && !p.fileis('view.v') { + println('`$f.name`') p.error('function names cannot contain uppercase letters, use snake_case instead') } if f.name[0] == `_` { diff --git a/vlib/compiler/module_header.v b/vlib/compiler/module_header.v index 73d67c79c6..4239f7fd97 100644 --- a/vlib/compiler/module_header.v +++ b/vlib/compiler/module_header.v @@ -37,13 +37,18 @@ fn generate_vh(mod string) { // Consts println(full_mod_path) mut vfiles := os.walk_ext(full_mod_path, '.v') - filtered := vfiles.filter(!it.ends_with('test.v') && - !it.ends_with('_windows.v') && !it.ends_with('_win.v')) // TODO merge once filter allows it + //mut vfiles := os.ls(full_mod_path) or { + //exit(1) + //} + filtered := vfiles.filter(it.ends_with('.v') && !it.ends_with('test.v') && + !it.ends_with('_windows.v') && !it.ends_with('_win.v') && + !it.contains('/js')) // TODO merge once filter allows it println(filtered) mut v := new_v(['foo.v']) //v.pref.generating_vh = true mut consts := strings.new_builder(100) mut fns := strings.new_builder(100) + mut types := strings.new_builder(100) for file in filtered { mut p := v.new_parser_from_file(file) p.scanner.is_vh = true @@ -55,10 +60,13 @@ fn generate_vh(mod string) { match tok.tok { TokenKind.key_fn { fns.writeln(generate_fn(p.tokens, i)) } TokenKind.key_const { consts.writeln(generate_const(p.tokens, i)) } + TokenKind.key_struct { types.writeln(generate_type(p.tokens, i)) } } } } - result := consts.str() + fns.str().replace('\n\n\n', '\n').replace('\n\n', '\n') + result := consts.str() + types.str() + + fns.str().replace('\n\n\n', '\n').replace('\n\n', '\n') + out.writeln(result.replace('[ ] ', '[]').replace('? ', '?')) out.close() } @@ -107,6 +115,22 @@ fn generate_const(tokens []Token, i int) string { return out.str() } +fn generate_type(tokens []Token, i int) string { + mut out := strings.new_builder(100) + mut tok := tokens[i] + for i < tokens.len && tok.tok != .rcbr { + out.write(tok.str()) + out.write(' ') + if tokens[i+1].line_nr != tokens[i].line_nr { + out.write('\n\t') + } + i++ + tok = tokens[i] + } + out.writeln('\n}') + return out.str() +} + /* fn (v &V) generate_vh_old() { println('\n\n\n\nGenerating a V header file for module `$v.mod`') diff --git a/vlib/compiler/parser.v b/vlib/compiler/parser.v index 323f219836..d7297c9163 100644 --- a/vlib/compiler/parser.v +++ b/vlib/compiler/parser.v @@ -9,14 +9,6 @@ import ( strings ) -struct Token { - tok TokenKind // the token number/enum; for quick comparisons - lit string // literal representation of the token - line_nr int // the line number in the source where the token occured - name_idx int // name table index for O(1) lookup - col int // the column where the token ends -} - struct Parser { file_path_id string // unique id. if parsing file will be path eg, "/home/user/hello.v" file_name string // "hello.v" @@ -532,7 +524,12 @@ fn (p mut Parser) const_decl() { mut typ := '' if p.is_vh { // .vh files don't have const values, just types: `const (a int)` - typ = p.get_type() + if p.tok == .assign { + p.next() + typ = p.expression() + } else { + typ = p.get_type() + } p.table.register_const(name, typ, p.mod) p.cgen.consts << ('extern ' + p.table.cgen_name_type_pair(name, typ)) + ';' diff --git a/vlib/compiler/token.v b/vlib/compiler/token.v index d102841ede..66e477159c 100644 --- a/vlib/compiler/token.v +++ b/vlib/compiler/token.v @@ -4,6 +4,15 @@ module compiler +struct Token { + tok TokenKind // the token number/enum; for quick comparisons + lit string // literal representation of the token + line_nr int // the line number in the source where the token occured + name_idx int // name table index for O(1) lookup + col int // the column where the token ends +} + + enum TokenKind { eof name // user @@ -281,6 +290,9 @@ fn (t []TokenKind) contains(val TokenKind) bool { } fn (t Token) str() string { + if t.tok == .str { + return "'$t.lit'" + } if t.tok < .plus { return t.lit // string, number etc }