diff --git a/vlib/builtin/array.v b/vlib/builtin/array.v index 7c8ea72107..3526a2e58b 100644 --- a/vlib/builtin/array.v +++ b/vlib/builtin/array.v @@ -17,7 +17,7 @@ pub: } // Private function, used by V (`nums := []int`) -fn new_array(mylen, cap, elm_size int) array { +pub fn new_array(mylen, cap, elm_size int) array { arr := array { len: mylen cap: cap @@ -379,23 +379,23 @@ fn array_eq(a1, a2 []T) bool { return true } -pub fn (a []int) eq(a2 []int) bool { - return array_eq(a, a2) +pub fn (a []int) eq(a2 []int) bool { + return array_eq(a, a2) } -pub fn (a []i64) eq(a2 []i64) bool { - return array_eq(a, a2) +pub fn (a []i64) eq(a2 []i64) bool { + return array_eq(a, a2) } -pub fn (a []string) eq(a2 []string) bool { - return array_eq(a, a2) +pub fn (a []string) eq(a2 []string) bool { + return array_eq(a, a2) } -pub fn (a []byte) eq(a2 []byte) bool { - return array_eq(a, a2) +pub fn (a []byte) eq(a2 []byte) bool { + return array_eq(a, a2) } -pub fn (a []f32) eq(a2 []f32) bool { - return array_eq(a, a2) +pub fn (a []f32) eq(a2 []f32) bool { + return array_eq(a, a2) } diff --git a/vlib/builtin/builtin.v b/vlib/builtin/builtin.v index 56229667ce..743ac360e0 100644 --- a/vlib/builtin/builtin.v +++ b/vlib/builtin/builtin.v @@ -186,7 +186,7 @@ pub fn free(ptr voidptr) { C.free(ptr) } -fn memdup(src voidptr, sz int) voidptr { +pub fn memdup(src voidptr, sz int) voidptr { mem := malloc(sz) return C.memcpy(mem, src, sz) } diff --git a/vlib/builtin/string.v b/vlib/builtin/string.v index 4613891e7a..54d271f577 100644 --- a/vlib/builtin/string.v +++ b/vlib/builtin/string.v @@ -41,7 +41,7 @@ NB: A V string should be/is immutable from the point of view of when used with modules using C functions (for example os and so on). */ -import strconv +//import strconv pub struct string { //mut: @@ -84,7 +84,7 @@ pub fn tos_clone(s byteptr) string { // Same as `tos`, but calculates the length. Called by `string(bytes)` casts. // Used only internally. -fn tos2(s byteptr) string { +pub fn tos2(s byteptr) string { if s == 0 { panic('tos2: nil string') } @@ -94,7 +94,7 @@ fn tos2(s byteptr) string { } } -fn tos3(s *C.char) string { +pub fn tos3(s *C.char) string { if s == 0 { panic('tos3: nil string') } @@ -202,7 +202,8 @@ pub fn (s string) int() int { pub fn (s string) i64() i64 { - return strconv.parse_int(s, 0, 64) + //return strconv.parse_int(s, 0, 64) + return C.atoll(*char(s.str)) } pub fn (s string) f32() f32 { @@ -214,11 +215,13 @@ pub fn (s string) f64() f64 { } pub fn (s string) u32() u32 { - return strconv.parse_uint(s, 0, 32) + return C.atol(*char(s.str)) + //return strconv.parse_uint(s, 0, 32) } pub fn (s string) u64() u64 { - return strconv.parse_uint(s, 0, 64) + return C.atoll(*char(s.str)) + //return strconv.parse_uint(s, 0, 64) } // == diff --git a/vlib/compiler/fn.v b/vlib/compiler/fn.v index 6ee84c2ef1..773fb06b64 100644 --- a/vlib/compiler/fn.v +++ b/vlib/compiler/fn.v @@ -44,6 +44,7 @@ mut: body_idx int // idx of the first body statement fn_name_token_idx int // used by error reporting comptime_define string + is_used bool // so that we can skip unused fns in resulting C code } struct TypeInst { @@ -193,9 +194,10 @@ fn (p mut Parser) fn_decl() { else { } */ + is_pub := p.tok == .key_pub mut f := Fn{ mod: p.mod - is_public: p.tok == .key_pub || p.is_vh // functions defined in .vh are always public + is_public: is_pub || p.is_vh // functions defined in .vh are always public is_unsafe: p.attr == 'unsafe_fn' is_deprecated: p.attr == 'deprecated' comptime_define: if p.attr.starts_with('if ') { p.attr.right(3) } else { '' } @@ -204,12 +206,13 @@ fn (p mut Parser) fn_decl() { if p.attr == 'live' && p.first_pass() && !p.pref.is_live && !p.pref.is_so { println('INFO: run `v -live program.v` if you want to use [live] functions') } - if f.is_public { + if is_pub { p.next() } p.returns = false //p.gen('/* returns $p.returns */') p.next() + // Method receiver mut receiver_typ := '' if p.tok == .lpar { @@ -277,9 +280,9 @@ fn (p mut Parser) fn_decl() { // C function header def? (fn C.NSMakeRect(int,int,int,int)) is_c := f.name == 'C' && p.tok == .dot // Just fn signature? only builtin.v + default build mode - //if p.pref.is_verbose { + if p.is_vh { //println('\n\nfn_decl() name=$f.name receiver_typ=$receiver_typ nogen=$p.cgen.nogen') - //} + } if is_c { p.check(.dot) f.name = p.check_name() @@ -691,6 +694,7 @@ fn (p mut Parser) fn_call(f mut Fn, method_ph int, receiver_var, receiver_type s p.error('use `malloc()` instead of `C.malloc()`') } } + f.is_used = true cgen_name := p.table.fn_gen_name(f) p.next() // fn name if p.tok == .lt { diff --git a/vlib/compiler/module_header.v b/vlib/compiler/module_header.v index a4d10ca941..9c4733ff3a 100644 --- a/vlib/compiler/module_header.v +++ b/vlib/compiler/module_header.v @@ -20,8 +20,6 @@ fn generate_vh(mod string) { println('\n\n\n\nGenerating a V header file for module `$mod`') vexe := os.executable() full_mod_path := os.dir(vexe) + '/' + mod - - mod_path := mod.replace('.', os.path_separator) dir := if mod.starts_with('vlib') { '$compiler.v_modules_path${os.path_separator}$mod' @@ -64,9 +62,10 @@ fn generate_vh(mod string) { continue } match tok.tok { - .key_fn { fns.writeln(generate_fn(p.tokens, i)) } - .key_const { consts.writeln(generate_const(p.tokens, i)) } + .key_fn { fns.writeln(generate_fn(p.tokens, i)) } + .key_const { consts.writeln(generate_const(p.tokens, i)) } .key_struct { types.writeln(generate_type(p.tokens, i)) } + .key_type { types.writeln(generate_alias(p.tokens, i)) } } } } @@ -105,6 +104,22 @@ fn generate_fn(tokens []Token, i int) string { return out.str() } +fn generate_alias(tokens []Token, i int) string { + mut out := strings.new_builder(100) + mut tok := tokens[i] + for i < tokens.len-1 { + out.write(tok.str()) + out.write(' ') + if tok.line_nr != tokens[i+1].line_nr { + break + } + i++ + tok = tokens[i] + } + out.writeln('\n') + return out.str() +} + fn generate_const(tokens []Token, i int) string { mut out := strings.new_builder(100) mut tok := tokens[i] @@ -137,148 +152,4 @@ fn generate_type(tokens []Token, i int) string { return out.str() } -/* -fn (v &V) generate_vh_old() { - println('\n\n\n\nGenerating a V header file for module `$v.mod`') - mod_path := v.mod.replace('.', os.path_separator) - dir := if v.dir.starts_with('vlib') { - '$v_modules_path${os.path_separator}$v.dir' - } else { - '$v_modules_path${os.path_separator}$mod_path' - } - path := dir + '.vh' - pdir := dir.all_before_last(os.path_separator) - if !os.dir_exists(pdir) { - os.mkdir_all(pdir) - // os.mkdir(os.realpath(dir)) - } - file := os.create(path) or { panic(err) } - // Consts - mod_def := if v.mod.contains('.') { v.mod.all_after('.') } else { v.mod } - file.writeln('// $v.mod module header \n') - file.writeln('module $mod_def') - file.writeln('// Consts') - if v.table.consts.len > 0 { - file.writeln('const (') - for i, c in v.table.consts { - if c.mod != v.mod { - continue - } - // println('$i $c.name') - //if !c.name.contains('__') { - //continue - //} - name := c.name.all_after('__') - typ := v_type_str(c.typ) - file.writeln('\t$name $typ') - } - file.writeln(')\n') - // Globals - for var in v.table.consts { - if var.mod != v.mod { - continue - } - if !var.is_global { - continue - } - name := var.name.all_after('__') - typ := v_type_str(var.typ) - file.writeln('__global $name $typ') - } - file.writeln('\n') - } - // Types - file.writeln('// Types') - for _, typ in v.table.typesmap { - //println(typ.name) - if typ.mod != v.mod && typ.mod != ''{ // int, string etc mod == '' - // println('skipping type "$typ.name"') - continue - } - if typ.name.contains('_V_MulRet') { - continue - } - mut name := typ.name - if typ.name.contains('__') { - name = typ.name.all_after('__') - } - // type alias - if typ.parent != '' && typ.cat == .alias { - parent := v_type_str(typ.parent) - file.writeln('type $typ.name $parent') - } - if typ.cat in [TypeCategory.struct_, .c_struct] { - c := if typ.is_c { 'C.' } else { '' } - file.writeln('struct ${c}$name {') - // Private fields - for field in typ.fields { - if field.access_mod == .public { - continue - } - field_type := v_type_str(field.typ).replace('*', '&') - file.writeln('\t$field.name $field_type') - } - //file.writeln('pub:') - mut public_str := '' - for field in typ.fields { - if field.access_mod == .private { - continue - } - field_type := v_type_str(field.typ).replace('*', '&') - public_str += '\t$field.name $field_type\n' - //file.writeln('\t$field.name $field_type') - } - if public_str != '' { - file.writeln('pub:' + public_str) - } - file.writeln('}\n') - } - } - // Functions & methods - file.writeln('// Functions') - // Public first - mut fns := []Fn - // TODO fns := v.table.fns.filter(.mod == v.mod) - for _, f in v.table.fns { - if f.mod == v.mod || f.mod == ''{ - fns << f - } else { - //println('skipping fn $f.name mod=$f.mod') - } - } - for _, f in fns { - if !f.is_public { - continue - } - file.writeln(f.v_definition()) - } - // Private - for _, f in fns { - if f.is_public { - continue - } - file.writeln(f.v_definition()) - } - // Methods - file.writeln('\n// Methods //////////////////') - for _, typ in v.table.typesmap { - if typ.mod != v.mod && !(v.mod == 'builtin' && typ.mod == '') { - // println('skipping method typ $typ.name mod=$typ.mod') - continue - } - for method in typ.methods { - file.writeln(method.v_definition()) - } - } - file.close() - - /* - for i, p in v.parsers { - if v.parsers[i].vh_lines.len > 0 { - os.write_file(p.file_name +'.vh', v.parsers[i].vh_lines.join('\n')) - } - } - */ -} -*/ diff --git a/vlib/compiler/parser.v b/vlib/compiler/parser.v index 805d4a49fd..cd97ba80eb 100644 --- a/vlib/compiler/parser.v +++ b/vlib/compiler/parser.v @@ -508,6 +508,7 @@ fn (p mut Parser) import_statement() { } fn (p mut Parser) const_decl() { + //println('const decl $p.file_path') is_pub := p.tok == .key_pub if is_pub { p.next() @@ -534,10 +535,16 @@ fn (p mut Parser) const_decl() { name = p.prepend_mod(name) mut typ := '' if p.is_vh { - // .vh files don't have const values, just types: `const (a int)` + //println('CONST VH $p.file_path') + // .vh files may not have const values, just types: `const (a int)` if p.tok == .assign { p.next() + // Otherwise parse the expression to get its type, + // but don't generate it. Const's value is generated + // in "module.o". + p.cgen.nogen = true typ = p.expression() + p.cgen.nogen = false } else { typ = p.get_type() } @@ -566,6 +573,13 @@ fn (p mut Parser) const_decl() { } } } + if p.pass == .main && p.cgen.nogen && p.pref.build_mode == .build_module { + // We are building module `ui`, but are parsing `gx` right now + // (because of nogen). We need to import gx constants with `extern`. + //println('extern const mod=$p.mod name=$name') + p.cgen.consts << ('extern ' + + p.table.cgen_name_type_pair(name, typ)) + ';' + } if p.pass == .main && !p.cgen.nogen { // TODO hack // cur_line has const's value right now. if it's just a number, then optimize generation: @@ -584,6 +598,7 @@ fn (p mut Parser) const_decl() { } else { p.cgen.consts << p.table.cgen_name_type_pair(name, typ) + ';' + //println('adding to init "$name"') p.cgen.consts_init << '$name = $p.cgen.cur_line;' } p.cgen.resetln('') diff --git a/vlib/compiler/struct.v b/vlib/compiler/struct.v index 43bca03257..2326b0e70e 100644 --- a/vlib/compiler/struct.v +++ b/vlib/compiler/struct.v @@ -81,7 +81,7 @@ fn (p mut Parser) struct_decl() { typ.is_placeholder = false typ.cat = cat typ.parent = objc_parent - typ.is_public = is_pub + typ.is_public = is_pub || p.is_vh p.table.rewrite_type(typ) } else { @@ -91,7 +91,7 @@ fn (p mut Parser) struct_decl() { is_c: is_c cat: cat parent: objc_parent - is_public: is_pub + is_public: is_pub || p.is_vh } } // Struct `C.Foo` declaration, no body diff --git a/vlib/compiler/vhelp.v b/vlib/compiler/vhelp.v index 27c9cd7f14..047b330b98 100644 --- a/vlib/compiler/vhelp.v +++ b/vlib/compiler/vhelp.v @@ -65,12 +65,12 @@ Commands: run Build and execute the V program in file.v. You can add arguments for the V program *after* the file name. build Compile a module into an object file. runrepl Run the V REPL. If V is running in a tty terminal, the REPL is interactive, otherwise it just reads from stdin. - symlink Useful on unix systems. Symlinks the current V executable to /usr/local/bin/v, so that V is globally available. + symlink Useful on Unix systems. Symlinks the current V executable to /usr/local/bin/v, so that V is globally available. install Install a user module from https://vpm.vlang.io/. test v Run all V test files, and compile all V examples. test folder/ Run all V test files located in the folder and its subfolders. You can also pass individual _test.v files too. fmt Run vfmt to format the source code. [wip] - doc Run vdoc over the source code and produce documentation. [wip] + doc Run vdoc over the source code and produce documentation. translate Translates C to V. [wip, will be available in V 0.3] ' ) diff --git a/vlib/darwin/darwin.v b/vlib/darwin/darwin.v index 1ca5ee8a3a..b99c84db74 100644 --- a/vlib/darwin/darwin.v +++ b/vlib/darwin/darwin.v @@ -4,6 +4,7 @@ module darwin #include #flag -framework Cocoa +#flag -framework Carbon struct C.NSString { } diff --git a/vlib/os/os_nix.v b/vlib/os/os_nix.v index 4bae3d3361..47c2949428 100644 --- a/vlib/os/os_nix.v +++ b/vlib/os/os_nix.v @@ -7,7 +7,7 @@ pub const ( path_separator = '/' ) -fn init_os_args(argc int, argv &byteptr) []string { +pub fn init_os_args(argc int, argv &byteptr) []string { mut args := []string for i in 0 .. argc { args << string(argv[i]) diff --git a/vlib/ui/examples/users_gui/users.v b/vlib/ui/examples/users_gui/users.v index eb26a3aa86..fb3b629cb9 100644 --- a/vlib/ui/examples/users_gui/users.v +++ b/vlib/ui/examples/users_gui/users.v @@ -1,3 +1,5 @@ +module main + import ( ui gx