From eef73eea22b00b795c5fd39d012d55a3793d70df Mon Sep 17 00:00:00 2001 From: Delyan Angelov Date: Mon, 21 Oct 2019 14:14:28 +0300 Subject: [PATCH] tools: new tool to extracts function names declared in V files --- tools/vnames.v | 76 +++++++++++++++++++++++++++++++ vlib/builtin/array.v | 2 +- vlib/builtin/array_test.v | 14 ++++++ vlib/compiler/cc.v | 2 +- vlib/compiler/fn.v | 7 +++ vlib/compiler/main.v | 82 +++++++++++++++++++++++++--------- vlib/compiler/parser.v | 10 ++--- vlib/compiler/table.v | 15 +++++-- vlib/compiler/tests/repl/run.v | 2 +- vlib/compiler/vtest.v | 6 +-- vlib/hash/hash.v | 6 +-- vlib/vweb/assets/assets.v | 2 +- 12 files changed, 184 insertions(+), 40 deletions(-) create mode 100644 tools/vnames.v diff --git a/tools/vnames.v b/tools/vnames.v new file mode 100644 index 0000000000..5c0781c524 --- /dev/null +++ b/tools/vnames.v @@ -0,0 +1,76 @@ +module main + +import os +import flag +import compiler + +const ( + tool_version = '0.0.1' + tool_description = ' Extracts the function names declared in a v file.' +) + +fn f_to_string(fmod string, f compiler.Fn) ?string { + svisibility := if f.is_public { + 'public' + }else{ + 'private' + } + if fmod != f.v_fn_module() { return none } + if fmod == 'builtin' { + return '$svisibility\t' + f.v_fn_name() + } + return '$svisibility\t' + f.v_fn_module() + '.' + f.v_fn_name() +} + +fn analyze_v_file(file string) { + println('') + println('###################### $file ######################') + + // main work: + mut v := compiler.new_v_compiler_with_args([file]) + v.add_v_files_to_compile() + for f in v.files { v.parse(f, .decl) } + fi := v.get_file_parser_index( file ) or { panic(err) } + fmod := v.parsers[fi].mod + + // output: + mut fns :=[]string + for _, f in v.table.fns { + fname := f_to_string(fmod, f) or { continue } + fns << fname + } + fns.sort() + for f in fns { println(f) } + +} + +fn main(){ + toolexe := os.executable() + compiler.set_vroot_folder( os.dir(os.dir(toolexe)) ) + + mut fp := flag.new_flag_parser(os.args) + fp.application(os.filename(toolexe)) + fp.version( tool_version ) + fp.description( tool_description ) + fp.arguments_description('FILE.v/FOLDER [FILE.v/FOLDER]...') + fp.limit_free_args_to_at_least(1) + fp.skip_executable() + show_help:=fp.bool_('help', `h`, false, 'Show this help screen\n') + if( show_help ){ + println( fp.usage() ) + exit(0) + } + + mut files := []string + locations := fp.finalize() or { eprintln('Error: ' + err) exit(1) } + for xloc in locations { + loc := os.realpath(xloc) + xfiles := if os.is_dir(loc){ os.walk_ext(loc,'.v') } else { [loc] } + filtered_files := xfiles.filter(!it.ends_with('_js.v')) + files << filtered_files + } + + for file in files { + analyze_v_file(file) + } +} diff --git a/vlib/builtin/array.v b/vlib/builtin/array.v index bdf73ed750..e733dc4021 100644 --- a/vlib/builtin/array.v +++ b/vlib/builtin/array.v @@ -141,7 +141,7 @@ pub fn (s array) left(n int) array { pub fn (s array) right(n int) array { if n >= s.len { - return s + return new_array(0, 0, s.element_size) } return s.slice(n, s.len) } diff --git a/vlib/builtin/array_test.v b/vlib/builtin/array_test.v index 78cd42454a..9a0af6409d 100644 --- a/vlib/builtin/array_test.v +++ b/vlib/builtin/array_test.v @@ -121,6 +121,20 @@ fn test_right() { assert b[1] == 3 } +fn test_right_with_n_bigger_than_array_size() { + a := [1, 2, 3, 4] + mut b := a.right(10) + assert b.len == 0 + + // also check that the result of a.right + // is an array of the same type/element size as a: + b << 5 + b << 6 + assert b.len == 2 + assert b[0] == 5 + assert b[1] == 6 +} + fn test_left() { a := [1, 2, 3] b := a.left(2) diff --git a/vlib/compiler/cc.v b/vlib/compiler/cc.v index 34f63fd778..2f46fb56f7 100644 --- a/vlib/compiler/cc.v +++ b/vlib/compiler/cc.v @@ -11,7 +11,7 @@ import ( fn (v mut V) cc() { v.build_thirdparty_obj_files() - vexe := os.executable() + vexe := vexe_path() // Just create a C/JavaScript file and exit // for example: `v -o v.c compiler` if v.out_name.ends_with('.c') || v.out_name.ends_with('.js') { diff --git a/vlib/compiler/fn.v b/vlib/compiler/fn.v index 6c91b1d280..6e7f61aaff 100644 --- a/vlib/compiler/fn.v +++ b/vlib/compiler/fn.v @@ -12,8 +12,10 @@ const ( MaxLocalVars = 50 ) + struct Fn { // addr int +pub: mut: name string mod string @@ -49,6 +51,11 @@ mut: done bool } +const ( + EmptyFn = Fn{} + MainFn = Fn{ name: 'main' } +) + fn (a []TypeInst) str() string { mut r := []string for t in a { diff --git a/vlib/compiler/main.v b/vlib/compiler/main.v index 8b73397fce..5ab914cc2e 100644 --- a/vlib/compiler/main.v +++ b/vlib/compiler/main.v @@ -211,11 +211,15 @@ pub fn (v mut V) compile() { cgen.genln('#define _VJS (1) ') } - if v.pref.building_v { + v_hash := vhash() + $if js { + cgen.genln('const V_COMMIT_HASH = "$v_hash";\n') + } $else { cgen.genln('#ifndef V_COMMIT_HASH') - cgen.genln('#define V_COMMIT_HASH "' + vhash() + '"') + cgen.genln('#define V_COMMIT_HASH "$v_hash"') cgen.genln('#endif') } + q := cgen.nogen // TODO hack cgen.nogen = false $if js { @@ -471,13 +475,24 @@ pub fn final_target_out_name(out_name string) string { } pub fn (v V) run_compiled_executable_and_exit() { + args := env_vflags_and_os_args() + if v.pref.is_verbose { println('============ running $v.out_name ============') } mut cmd := '"' + final_target_out_name(v.out_name).replace('.exe','') + '"' - if os.args.len > 3 { - cmd += ' ' + os.args.right(3).join(' ') + + mut args_after := ' ' + for i,a in args { + if i == 0 { continue } + if a.starts_with('-') { continue } + if a in ['run','test'] { + args_after += args.right(i+2).join(' ') + break + } } + cmd += args_after + if v.pref.is_test { ret := os.system(cmd) if ret != 0 { @@ -855,7 +870,7 @@ pub fn new_v(args[]string) &V { _os = os_from_string(target_os) } // Location of all vlib files - vroot := os.dir(os.executable()) + vroot := os.dir(vexe_path()) //println('VROOT=$vroot') // v.exe's parent directory should contain vlib if !os.dir_exists(vroot) || !os.dir_exists(vroot + '/vlib/builtin') { @@ -933,23 +948,26 @@ pub fn new_v(args[]string) &V { } pub fn env_vflags_and_os_args() []string { - mut args := []string - vflags := os.getenv('VFLAGS') - if '' != vflags { - args << os.args[0] - args << vflags.split(' ') - if os.args.len > 1 { - args << os.args.right(1) - } - } else{ - args << os.args - } - return args + vosargs := os.getenv('VOSARGS') + if '' != vosargs { return vosargs.split(' ') } + + mut args := []string + vflags := os.getenv('VFLAGS') + if '' != vflags { + args << os.args[0] + args << vflags.split(' ') + if os.args.len > 1 { + args << os.args.right(1) + } + } else{ + args << os.args + } + return args } pub fn update_v() { println('Updating V...') - vroot := os.dir(os.executable()) + vroot := os.dir(vexe_path()) s := os.exec('git -C "$vroot" pull --rebase origin master') or { verror(err) return @@ -994,7 +1012,7 @@ pub fn install_v(args[]string) { return } names := args.slice(2, args.len) - vexec := os.executable() + vexec := vexe_path() vroot := os.dir(vexec) vget := '$vroot/tools/vget' if true { @@ -1020,7 +1038,7 @@ pub fn install_v(args[]string) { } pub fn create_symlink() { - vexe := os.executable() + vexe := vexe_path() link_path := '/usr/local/bin/v' ret := os.system('ln -sf $vexe $link_path') if ret == 0 { @@ -1031,6 +1049,12 @@ pub fn create_symlink() { } } +pub fn vexe_path() string { + vexe := os.getenv('VEXE') + if '' != vexe { return vexe } + return os.executable() +} + pub fn verror(s string) { println('V error: $s') os.flush_stdout() @@ -1067,3 +1091,21 @@ pub fn os_from_string(os string) OS { println('bad os $os') // todo panic? return .linux } + +// + +pub fn set_vroot_folder(vroot_path string) { + // Preparation for the compiler module: + // VEXE env variable is needed so that compiler.vexe_path() + // can return it later to whoever needs it: + mut vname := if os.user_os() == 'windows' { 'v.exe' } else { 'v' } + os.setenv('VEXE', os.realpath( [vroot_path, vname].join(os.path_separator) ), true) +} + +pub fn new_v_compiler_with_args(args []string) &V { + vexe := vexe_path() + mut allargs := [vexe] + allargs << args + os.setenv('VOSARGS', allargs.join(' '), true) + return new_v(allargs) +} diff --git a/vlib/compiler/parser.v b/vlib/compiler/parser.v index c3153dfaa4..aaf0b7c14c 100644 --- a/vlib/compiler/parser.v +++ b/vlib/compiler/parser.v @@ -40,7 +40,6 @@ mut: import_table FileImportTable // Holds imports for just the file being parsed pass Pass os OS - mod string inside_const bool expr_var Var has_immutable_field bool @@ -80,13 +79,10 @@ mut: sql_params []string // ("select * from users where id = $1", ***"100"***) sql_types []string // int, string and so on; see sql_params is_vh bool // parsing .vh file (for example `const (a int)` is allowed) +pub: + mod string } -const ( - EmptyFn = Fn{} - MainFn= Fn{name:'main'} -) - const ( MaxModuleDepth = 4 ) @@ -1421,7 +1417,7 @@ fn ($v.name mut $v.typ) $p.cur_fn.name (...) { if p.assigned_type != p.expected_type { p.error_with_token_index( 'incompatible types: $p.assigned_type != $p.expected_type', errtok) } - p.cgen.resetln('memcpy(& $left, $etype{$expr}, sizeof( $left ) );') + p.cgen.resetln('memcpy( (& $left), ($etype{$expr}), sizeof( $left ) );') } else if !p.builtin_mod && !p.check_types_no_throw(expr_type, p.assigned_type) { p.error_with_token_index( 'cannot use type `$expr_type` as type `$p.assigned_type` in assignment', errtok) diff --git a/vlib/compiler/table.v b/vlib/compiler/table.v index 5e44f92330..5f5baf6223 100644 --- a/vlib/compiler/table.v +++ b/vlib/compiler/table.v @@ -8,7 +8,7 @@ import os import strings struct Table { -mut: +pub mut: typesmap map[string]Type consts []Var fns map[string]Fn @@ -39,7 +39,7 @@ enum NameCategory { struct Name { cat NameCategory idx int // e.g. typ := types[name.idx] -} +} // Holds import information scoped to the parsed file struct FileImportTable { @@ -74,6 +74,7 @@ enum TypeCategory { } struct Var { +pub: mut: typ string name string @@ -102,6 +103,7 @@ mut: } struct Type { +pub: mut: mod string name string @@ -198,7 +200,14 @@ fn (f Fn) str() string { return '$f.name($str_args) $f.typ' } -fn (t &Table) debug_fns() string { +pub fn (f Fn) v_fn_module() string { + return f.mod +} +pub fn (f Fn) v_fn_name() string { + return f.name.replace('${f.mod}__', '') +} + +pub fn (t &Table) debug_fns() string { mut s := strings.new_builder(1000) for _, f in t.fns { s.writeln(f.name) diff --git a/vlib/compiler/tests/repl/run.v b/vlib/compiler/tests/repl/run.v index 6eb06ef60b..6578e359c5 100644 --- a/vlib/compiler/tests/repl/run.v +++ b/vlib/compiler/tests/repl/run.v @@ -1,6 +1,6 @@ module main -import vcompiler.tests.repl.runner +import compiler.tests.repl.runner import log import benchmark diff --git a/vlib/compiler/vtest.v b/vlib/compiler/vtest.v index a122dcc900..3bd1dd8ba8 100644 --- a/vlib/compiler/vtest.v +++ b/vlib/compiler/vtest.v @@ -17,7 +17,7 @@ mut: pub fn new_test_sesion(vargs string) TestSession { return TestSession{ - vexe: os.executable() + vexe: vexe_path() vargs: vargs } } @@ -118,7 +118,7 @@ pub fn (ts mut TestSession) test() { } pub fn v_test_v(args_before_test string){ - vexe := os.executable() + vexe := vexe_path() parent_dir := os.dir(vexe) // Changing the current directory is needed for some of the compiler tests, // compiler/tests/local_test.v and compiler/tests/repl/repl_test.v @@ -163,7 +163,7 @@ pub fn v_test_v(args_before_test string){ pub fn test_vget() { /* - vexe := os.executable() + vexe := vexe_path() ret := os.system('$vexe install nedpals.args') if ret != 0 { println('failed to run v install') diff --git a/vlib/hash/hash.v b/vlib/hash/hash.v index 747fc0e7c9..19d72168fe 100644 --- a/vlib/hash/hash.v +++ b/vlib/hash/hash.v @@ -4,7 +4,7 @@ module hash -interface Hash { +interface Hasher { // Sum appends the current hash to b and returns the resulting array. // It does not change the underlying hash state. sum(b []byte) []byte @@ -12,10 +12,10 @@ interface Hash { block_size() int } -interface Hash32 { +interface Hash32er { sum32() u32 } -interface Hash64 { +interface Hash64er { sum64() u64 } diff --git a/vlib/vweb/assets/assets.v b/vlib/vweb/assets/assets.v index c830558fea..28bb46587b 100644 --- a/vlib/vweb/assets/assets.v +++ b/vlib/vweb/assets/assets.v @@ -30,7 +30,7 @@ struct Asset { } // new_manager returns a new AssetManager -pub fn new_manager() *AssetManager { +pub fn new_manager() &AssetManager { return &AssetManager{} }