diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ed20a4667d..b9cf028bcd 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -11,7 +11,7 @@ jobs: - name: Install dependencies run: sudo rm -f /etc/apt/sources.list.d/dotnetdev.list /etc/apt/sources.list.d/microsoft-prod.list; sudo apt-get update; sudo apt-get install --quiet -y libglfw3 libglfw3-dev libfreetype6-dev libssl-dev sqlite3 libsqlite3-dev libsdl2-dev libsdl2-ttf-dev libsdl2-mixer-dev libsdl2-image-dev - name: Build v - run: echo $VFLAGS && make -j4 && ./v -o v v.v + run: echo $VFLAGS && make -j4 && ./v -cg -o v v.v - name: Test v->c run: | sudo ln -s /var/tmp/tcc/bin/tcc /usr/local/bin/tcc @@ -54,7 +54,7 @@ jobs: brew install freetype glfw openssl postgres sdl2 sdl2_ttf sdl2_mixer sdl2_image export LIBRARY_PATH="$LIBRARY_PATH:/usr/local/opt/openssl/lib/" - name: Build V - run: make -j4 && ./v -o v v.v + run: make -j4 && ./v -cg -o v v.v - name: Build V using V run: ./v -o v2 v.v && ./v2 -o v3 v.v - name: Test symlink @@ -152,7 +152,7 @@ jobs: - name: Install dependencies run: sudo rm -f /etc/apt/sources.list.d/dotnetdev.list /etc/apt/sources.list.d/microsoft-prod.list; sudo apt-get update; sudo apt-get install --quiet -y musl musl-tools libsdl2-dev libsdl2-ttf-dev libsdl2-mixer-dev libsdl2-image-dev - name: Build v - run: echo $VFLAGS && make -j4 && ./v -o v v.v + run: echo $VFLAGS && make -j4 && ./v -cg -o v v.v - name: Test v binaries run: ./v build-vbinaries # - name: Test v->js diff --git a/.gitignore b/.gitignore index 3efe00f795..08c7c39ea8 100644 --- a/.gitignore +++ b/.gitignore @@ -12,6 +12,7 @@ fns.txt /tools/vrepl /tools/vtest /tools/vtest-compiler +/tools/vfmt /tools/vup /tools/vpm /tools/vcreate diff --git a/Makefile b/Makefile index b734e8b4e5..4e76b25a8e 100644 --- a/Makefile +++ b/Makefile @@ -88,7 +88,7 @@ $(TMPVC)/.git/config: $(MAKE) fresh_vc selfcompile: - ./v -o v v.v + ./v -cg -o v v.v modules: module_builtin module_strings module_strconv module_builtin: diff --git a/tools/modules/testing/common.v b/tools/modules/testing/common.v index d479d33d71..0a6671c310 100644 --- a/tools/modules/testing/common.v +++ b/tools/modules/testing/common.v @@ -27,11 +27,11 @@ pub fn new_test_session(vargs string) TestSession { } pub fn vexe_path() string { - // NB: tools extracted from v require that the first - // argument to them to be the v executable location. + // NB: tools extracted from v require that the VEXE + // environment variable contains the path to the v executable location. // They are usually launched by vlib/compiler/vtools.v, // launch_tool/1 , which provides it. - return os.args[1] + return os.getenv('VEXE') } diff --git a/tools/vfmt.v b/tools/vfmt.v new file mode 100644 index 0000000000..b02ec3dea8 --- /dev/null +++ b/tools/vfmt.v @@ -0,0 +1,101 @@ +// Copyright (c) 2019 Alexander Medvednikov. All rights reserved. +// Use of this source code is governed by an MIT license +// that can be found in the LICENSE file. +module main + +import ( + os + compiler +) + +struct FormatOptions { + is_w bool + is_diff bool + is_verbose bool + is_all bool +} + +fn main() { + foptions := FormatOptions{ + is_w: '-w' in os.args + is_diff: '-diff' in os.args + is_verbose: '-verbose' in os.args || '--verbose' in os.args + is_all: '-all' in os.args || '--all' in os.args + } + toolexe := os.executable() + compiler.set_vroot_folder(os.dir(os.dir(toolexe))) + args := compiler.env_vflags_and_os_args() + if foptions.is_verbose { + eprintln('vfmt toolexe: $toolexe') + eprintln('vfmt args: ' + os.args.str()) + eprintln('vfmt env_vflags_and_os_args: ' + args.str()) + } + mut files := []string + for i := 1; i < args.len; i++ { + a := args[i] + if a == 'fmt' { + continue + } + if !a.starts_with('-') { + file := a + if !os.exists(file) { + compiler.verror('"$file" does not exist.') + } + if !file.ends_with('.v') { + compiler.verror('v fmt can only be used on .v files.\nOffending file: "$file" .') + } + files << a + } + } + if files.len == 0 { + usage() + exit(0) + } + if foptions.is_all { + os.setenv('VFMT_OPTION_ALL', 'yes', true) + } + for file in files { + format_file(file, foptions) + } +} + +fn format_file(file string, foptions FormatOptions) { + mut v := compiler.new_v_compiler_with_args([file]) + if foptions.is_verbose { + eprintln('vfmt format_file: $file | v.dir: $v.dir') + } + v.compile() + formatted_file_path := os.getenv('VFMT_FILE_RESULT') + // eprintln('File: $file .') + // eprintln('Formatted file is: $formatted_file_path .') + if foptions.is_diff { + if find_diff:=os.exec('diff -v'){ + os.system('diff "$formatted_file_path" "$file" ') + return + } + eprintln('No working "diff" CLI command found.') + return + } + if foptions.is_w { + os.mv_by_cp(formatted_file_path, file) or { + panic(err) + } + eprintln('Reformatted file in place: $file .') + } + else { + content := os.read_file(formatted_file_path) or { + panic(err) + } + print(content) + } +} + +fn usage() { + print('Usage: tools/vfmt [flags] path_to_source.v [path_to_other_source.v] +Formats the given V source files, and prints their formatted source to stdout. +Options: + -diff display only diffs between the formatted source and the original source. + -w write result to (source) file(s) instead of to stdout. +') +} + diff --git a/tools/vpm.v b/tools/vpm.v index d1906207a7..71bf30dec7 100644 --- a/tools/vpm.v +++ b/tools/vpm.v @@ -7,15 +7,15 @@ import ( ) const ( - //url = 'http://localhost:8089' +// url = 'http://localhost:8089' url = 'https://vpm.best' valid_vpm_commands = ['help', 'search', 'install', 'update', 'remove'] ) struct Mod { - id int - name string - url string + id int + name string + url string nr_downloads int } @@ -23,21 +23,31 @@ fn main() { ensure_vmodules_dir_exist() change_to_vmodules_dir() // This tool is intended to be launched by the v frontend, - // so its first argument is the path to the v frontend executable. - args := os.args // args are: vpm vexepath SUBCOMMAND module names - if args.len < 3 { + // which provides the path to V inside os.getenv('VEXE') + args := os.args // args are: vpm SUBCOMMAND module names + if args.len < 2 { vpm_help([]) exit(5) } - vpm_command := args[2] - module_names := args[3..] - //println('module names: ') println(module_names) + vpm_command := args[1] + module_names := args[2..] + // println('module names: ') println(module_names) match vpm_command { - 'help' { vpm_help(module_names) } - 'search' { vpm_search(module_names) } - 'install' { vpm_install(module_names) } - 'update' { vpm_update(module_names) } - 'remove' { vpm_remove(module_names) } + 'help' { + vpm_help(module_names) + } + 'search' { + vpm_search(module_names) + } + 'install' { + vpm_install(module_names) + } + 'update' { + vpm_update(module_names) + } + 'remove' { + vpm_remove(module_names) + } else { println('Error: you tried to run "v $vpm_command"') println('... but the v package management tool vpm only knows about these commands:') @@ -45,11 +55,10 @@ fn main() { println(' v $validcmd') } exit(3) - } - } + }} } -fn vpm_search(module_names []string){ +fn vpm_search(module_names []string) { if user_asks_for_help(module_names) { println('Usage:') println(' v search keyword1 [keyword2] [...]') @@ -64,7 +73,7 @@ fn vpm_search(module_names []string){ todo('search') } -fn vpm_install(module_names []string){ +fn vpm_install(module_names []string) { if user_asks_for_help(module_names) { println('Usage:') println(' v install module [module] [module] [...]') @@ -75,40 +84,35 @@ fn vpm_install(module_names []string){ println(' v install requires *at least one* module name') exit(2) } - mut errors := 0 for name in module_names { modurl := url + '/jsmod/$name' - r := http.get(modurl) or { panic(err) } - + r := http.get(modurl) or { + panic(err) + } if r.status_code == 404 { println('Skipping module "$name", since $url reported that "$name" does not exist.') errors++ continue } - if r.status_code != 200 { println('Skipping module "$name", since $url responded with $r.status_code http status code. Please try again later.') errors++ continue } - s := r.text - mod := json.decode(Mod, s) or { + mod := json.decode(Mod,s) or { errors++ println('Skipping module "$name", since its information is not in json format.') continue } - - if( '' == mod.url || '' == mod.name ){ + if ('' == mod.url || '' == mod.name) { errors++ // a possible 404 error, which means a missing module? println('Skipping module "$name", since it is missing name or url information.') continue } - final_module_path := get_vmodules_dir_path() + '/' + mod.name.replace('.', '/') - println('Installing module "$name" from $mod.url to $final_module_path ...') _ = os.exec('git clone --depth=1 $mod.url $final_module_path') or { errors++ @@ -122,7 +126,7 @@ fn vpm_install(module_names []string){ } } -fn vpm_update(module_names []string){ +fn vpm_update(module_names []string) { if user_asks_for_help(module_names) { println('Usage: ') println(' a) v update module [module] [module] [...]') @@ -134,7 +138,7 @@ fn vpm_update(module_names []string){ todo('update') } -fn vpm_remove(module_names []string){ +fn vpm_remove(module_names []string) { if user_asks_for_help(module_names) { println('Usage: ') println(' a) v remove module [module] [module] [...]') @@ -152,9 +156,11 @@ fn get_vmodules_dir_path() string { fn ensure_vmodules_dir_exist() { home_vmodules := get_vmodules_dir_path() - if !os.is_dir( home_vmodules ) { + if !os.is_dir(home_vmodules) { println('Creating $home_vmodules/ ...') - os.mkdir(home_vmodules) or { panic(err) } + os.mkdir(home_vmodules) or { + panic(err) + } } } @@ -162,7 +168,7 @@ fn change_to_vmodules_dir() { os.chdir(get_vmodules_dir_path()) } -fn todo(vpm_command string){ +fn todo(vpm_command string) { println('TODO: v $vpm_command') exit(4) } @@ -171,12 +177,13 @@ fn user_asks_for_help(module_names []string) bool { return ('-h' in module_names) || ('--help' in module_names) || ('help' in module_names) } -fn vpm_help(module_names []string){ +fn vpm_help(module_names []string) { println('Usage:') - println(' b) v search keyword1 [keyword2] [...]') - println(' c) v install module [module] [module] [...]') - println(' d) v update [module] [...]') - println(' e) v remove [module] [...]') + println(' a) v install module [module] [module] [...]') + println(' b) v update [module] [...]') + println(' c) v remove [module] [...]') + println(' d) v search keyword1 [keyword2] [...]') println('') println(' You can also pass -h or --help after each vpm command from the above, to see more details about it.') } + diff --git a/tools/vrepl.v b/tools/vrepl.v index b1b8c02e0b..5749c54087 100644 --- a/tools/vrepl.v +++ b/tools/vrepl.v @@ -86,7 +86,7 @@ pub fn run_repl() []string { } mut r := Repl{} mut readline := readline.Readline{} - vexe := os.args[1] + vexe := os.getenv('VEXE') for { if r.indent == 0 { prompt = '>>> ' @@ -200,9 +200,9 @@ fn print_output(s os.Result) { } fn main() { - if os.args.len < 2 || !os.exists(os.args[1]) { + if !os.exists(os.getenv('VEXE')) { println('Usage:') - println(' vrepl vexepath\n') + println(' VEXE=vexepath vrepl\n') println(' ... where vexepath is the full path to the v executable file') return } @@ -216,7 +216,7 @@ pub fn rerror(s string) { } fn v_version() string { - vexe := os.args[1] + vexe := os.getenv('VEXE') vversion_res := os.exec('$vexe --version') or { panic('"$vexe --version" is not working') } return vversion_res.output } diff --git a/tools/vup.v b/tools/vup.v index 8369b39573..86a9680dc3 100644 --- a/tools/vup.v +++ b/tools/vup.v @@ -2,7 +2,7 @@ import os fn main() { println('Updating V...') - vroot := os.dir(os.args[1]) + vroot := os.getenv('VEXE') os.chdir(vroot) s := os.exec('git -C "$vroot" pull --rebase origin master') or { panic(err) } println(s.output) diff --git a/v.v b/v.v index 4e5c7dcea5..b34568a2d4 100644 --- a/v.v +++ b/v.v @@ -13,14 +13,21 @@ import ( const ( known_commands = ['run', 'build', 'version', 'doc'] - simple_tools = ['up', 'create', 'test', 'test-compiler', 'build-tools', 'build-examples', 'build-vbinaries'] + simple_tools = ['fmt', 'up', 'create', 'test', 'test-compiler', 'build-tools', 'build-examples', 'build-vbinaries'] ) fn main() { + is_verbose := '-verbose' in os.args || '--verbose' in os.args // t := time.ticks() // defer { println(time.ticks() - t) } args := compiler.env_vflags_and_os_args() - options,command := compiler.get_v_options_and_main_command(args) + options, command := compiler.get_v_options_and_main_command( args ) + if is_verbose { + eprintln('v args: $args') + eprintln('v command: $command') + eprintln('v options: $options') + } + // external tool if command in simple_tools { compiler.launch_tool('v' + command) @@ -88,7 +95,7 @@ fn v_command(command string, args []string) { 'translate' { println('Translating C to V will be available in V 0.3 (January)') } - 'search', 'install', 'update' { + 'search', 'install', 'update', 'remove' { compiler.launch_tool('vpm') } 'get' { @@ -97,9 +104,6 @@ fn v_command(command string, args []string) { 'symlink' { compiler.create_symlink() } - 'fmt' { - compiler.vfmt(args) - } 'runrepl' { compiler.launch_tool('vrepl') } @@ -109,16 +113,15 @@ fn v_command(command string, args []string) { os.chdir(vdir) mod := args.last() os.system('$vexe build module vlib$os.path_separator' + args.last()) - txt := os.read_file(filepath.join(compiler.v_modules_path,'vlib','${mod}.vh'))or{ - panic(err) - } + vhfile := filepath.join(compiler.v_modules_path,'vlib','${mod}.vh') + txt := os.read_file(vhfile) or { panic(err) } println(txt) // v.gen_doc_html_for_module(args.last()) } else { println('v $command: unknown command') println('Run "v help" for usage.') - }} + } + } exit(0) } - diff --git a/vlib/compiler/main.v b/vlib/compiler/main.v index 504b1a9c80..96c8ef9b1f 100644 --- a/vlib/compiler/main.v +++ b/vlib/compiler/main.v @@ -1132,32 +1132,6 @@ pub fn env_vflags_and_os_args() []string { return non_empty(args) } -pub fn vfmt(args []string) { - file := args.last() - if !os.exists(file) { - println('"$file" does not exist') - exit(1) - } - if !file.ends_with('.v') { - println('v fmt can only be used on .v files') - exit(1) - } - vexe := vexe_path() - // launch_tool('vfmt', '-d vfmt') - vroot := os.dir(vexe) - os.chdir(vroot) - println('building vfmt... (it will be cached soon)') - ret := os.system('$vexe -o $vroot/tools/vfmt -d vfmt v.v') - if ret != 0 { - println('err') - return - } - println('running vfmt...') - os.exec('$vroot/tools/vfmt $file')or{ - panic(err) - } - // if !os.exists(' -} pub fn create_symlink() { $if windows { diff --git a/vlib/compiler/vfmt.v b/vlib/compiler/vfmt.v index 726bae588a..8f8dcbd844 100644 --- a/vlib/compiler/vfmt.v +++ b/vlib/compiler/vfmt.v @@ -240,7 +240,6 @@ fn (p mut Parser) fremove_last() { } - [if vfmt] fn (p &Parser) gen_fmt() { if p.pass != .main { @@ -250,6 +249,11 @@ fn (p &Parser) gen_fmt() { if p.file_name == '' { return } + is_all := os.getenv('VFMT_OPTION_ALL') == 'yes' + if p.file_path != p.v.dir && !is_all { + // skip everything except the last file (given by the CLI argument) + return + } //s := p.scanner.fmt_out.str().replace('\n\n\n', '\n').trim_space() //s := p.scanner.fmt_out.str().trim_space() //p.scanner.fgenln('// nice') @@ -260,29 +264,40 @@ fn (p &Parser) gen_fmt() { ') or{', ') or {', ]) */ - //.replace('\n\n\n\n', '\n\n') - .replace_each([ - ' \n', '\n', - ') or{', ') or {', - ')or{', ') or {', - ] ) - + //.replace('\n\n\n\n', '\n\n') + .replace_each([ + ' \n', '\n', + ') or{', ') or {', + ')or{', ') or {', + ]) + if s == '' { return } //files := ['get_type.v'] - if p.file_path.contains('vfmt') {return} + if p.file_path.contains('compiler/vfmt.v') {return} //if !(p.file_name in files) { return } - path := os.tmpdir() + '/' + p.file_name - println('generating ${path}') - mut out := os.create(path) or { - verror('failed to create os_nix.v') - return + if is_all { + if p.file_path.len > 0 { + path := write_formatted_source( p.file_name, s ) + os.cp( path, p.file_path ) or { panic(err) } + eprintln('Written fmt file to: $p.file_path') + } + } + if p.file_path == p.v.dir { + res_path := write_formatted_source( p.file_name, s ) + os.setenv('VFMT_FILE_RESULT', res_path, true ) } - println('replacing ${p.file_path}...\n') - out.writeln(s.trim_space())//p.scanner.fmt_out.str().trim_space()) - out.writeln('') - out.close() - os.mv(path, p.file_path) } +fn write_formatted_source(file_name string, s string) string { + path := os.tmpdir() + '/' + file_name + mut out := os.create(path) or { + verror('failed to create file $path') + return '' + } + //eprintln('replacing ${p.file_path} ...\n') + out.writeln(s.trim_space())//p.scanner.fmt_out.str().trim_space()) + out.close() + return path +} diff --git a/vlib/compiler/vtools.v b/vlib/compiler/vtools.v index 2a8be006a8..d56f69630b 100644 --- a/vlib/compiler/vtools.v +++ b/vlib/compiler/vtools.v @@ -3,22 +3,25 @@ module compiler import os pub fn launch_tool(tname string) { + is_verbose := '-verbose' in os.args || '--verbose' in os.args vexe := vexe_path() vroot := os.dir(vexe) - mut oargs := os.args - oargs[0] = '"$vexe"' // make it more explicit + set_vroot_folder( vroot ) // needed by tools to find back v + tool_args := os.args[1..].join(' ') tool_exe := os.realpath('$vroot/tools/$tname') tool_source := os.realpath('$vroot/tools/${tname}.v') - // //////////////////////////////////////////////////// - tool_args := oargs.join(' ') tool_command := '"$tool_exe" $tool_args' - // println('Launching: "$tool_command" ...') + if is_verbose { + eprintln('launch_tool vexe : $vroot') + eprintln('launch_tool vroot : $vroot') + eprintln('launch_tool tool_args : $tool_args') + eprintln('launch_tool tool_command: $tool_command') + } mut tool_should_be_recompiled := false if !os.exists(tool_exe) { // fresh checkout tool_should_be_recompiled = true - } - else { + } else { if os.file_last_mod_unix(tool_exe) <= os.file_last_mod_unix(vexe) { // v was recompiled, maybe after v up ... // rebuild the tool too just in case @@ -29,16 +32,26 @@ pub fn launch_tool(tname string) { tool_should_be_recompiled = true } } + + if is_verbose { + eprintln('launch_tool tool_should_be_recompiled: $tool_should_be_recompiled') + } + if tool_should_be_recompiled { - compilation_command := '"$vexe" "$tool_source"' - // println('Compiling $tname with: "$compilation_command"') - tool_compilation := os.exec(compilation_command)or{ - panic(err) + mut compilation_options := '' + if tname == 'vfmt' { compilation_options = '-d vfmt' } + compilation_command := '"$vexe" $compilation_options "$tool_source"' + if is_verbose { + eprintln('Compiling $tname with: "$compilation_command"') } + tool_compilation := os.exec(compilation_command) or { panic(err) } if tool_compilation.exit_code != 0 { panic('V tool "$tool_source" could not be compiled\n' + tool_compilation.output) } } - exit(os.system(tool_command)) + if is_verbose { + eprintln('launch_tool running tool command: $tool_command ...') + } + + exit( os.system(tool_command) ) } -