diff --git a/cmd/tools/vfmt.v b/cmd/tools/vfmt.v index d7aad0d6e8..923c8b2e34 100644 --- a/cmd/tools/vfmt.v +++ b/cmd/tools/vfmt.v @@ -6,9 +6,9 @@ module main import ( os os.cmdline - compiler v.pref v.fmt + v.util v.parser v.table vhelp @@ -43,7 +43,7 @@ const ( fn main() { toolexe := os.executable() - compiler.set_vroot_folder(os.dir(os.dir(os.dir(toolexe)))) + util.set_vroot_folder(os.dir(os.dir(os.dir(toolexe)))) args := join_flags_and_argument() foptions := FormatOptions{ is_2: '-2' in args @@ -81,17 +81,17 @@ fn main() { for file in possible_files { if foptions.is_2 { if !file.ends_with('.v') && !file.ends_with('.vv') { - compiler.verror('v fmt -2 can only be used on .v or .vv files.\nOffending file: "$file" .') + verror('v fmt -2 can only be used on .v or .vv files.\nOffending file: "$file" .') continue } } else { if !file.ends_with('.v') { - compiler.verror('v fmt can only be used on .v files.\nOffending file: "$file" .') + verror('v fmt can only be used on .v files.\nOffending file: "$file" .') continue } } if !os.exists(file) { - compiler.verror('"$file" does not exist.') + verror('"$file" does not exist.') continue } files << file @@ -151,89 +151,20 @@ fn main() { } fn (foptions &FormatOptions) format_file(file string) { - if foptions.is_2 { - if foptions.is_verbose { - eprintln('vfmt2 running fmt.fmt over file: $file') - } - table := table.new_table() - file_ast := parser.parse_file(file, table, .parse_comments, &pref.Preferences{}) - formatted_content := fmt.fmt(file_ast, table) - file_name := os.file_name(file) - vfmt_output_path := os.join_path(os.temp_dir(), 'vfmt_' + file_name) - os.write_file(vfmt_output_path, formatted_content ) - if foptions.is_verbose { - eprintln('vfmt2 fmt.fmt worked and ${formatted_content.len} bytes were written to ${vfmt_output_path} .') - } - eprintln('${FORMATTED_FILE_TOKEN}${vfmt_output_path}') - return - } - tmpfolder := os.temp_dir() - mut compiler_params := &pref.Preferences{} - target_os := file_to_target_os(file) - if target_os != '' { - //TODO Remove temporary variable once it compiles correctly in C - tmp := pref.os_from_string(target_os) or { - eprintln('unknown operating system $target_os') - return - } - compiler_params.os = tmp - } - mut cfile := file - mut mod_folder_parent := tmpfolder - is_test_file := file.ends_with('_test.v') - mod_name,is_module_file := file_to_mod_name_and_is_module_file(file) - use_tmp_main_program := is_module_file && !is_test_file - mod_folder := os.base_dir(file) - if use_tmp_main_program { - // TODO: remove the need for this - // This makes a small program that imports the module, - // so that the module files will get processed by the - // vfmt implementation. - mod_folder_parent = os.base_dir(mod_folder) - mut main_program_content := if mod_name == 'builtin' || mod_name == 'main' { 'fn main(){}\n' } else { 'import ${mod_name}\n' + 'fn main(){}\n' } - main_program_file := os.join_path(tmpfolder,'vfmt_tmp_${mod_name}_program.v') - if os.exists(main_program_file) { - os.rm(main_program_file) - } - os.write_file(main_program_file, main_program_content) - cfile = main_program_file - compiler_params.lookup_path = [mod_folder_parent, '@vlib', '@vmodule'] - } - if !is_test_file && mod_name == 'main' { - // NB: here, file is guaranteed to be a main. We do not know however - // whether it is a standalone v program, or is it a part of a bigger - // project, like vorum or vid. - cfile = get_compile_name_of_potential_v_project(cfile) - } - compiler_params.path = cfile - compiler_params.mod = mod_name - compiler_params.is_test = is_test_file - compiler_params.is_script = file.ends_with('.v') || file.ends_with('.vsh') + prefs := pref.new_preferences() if foptions.is_verbose { - eprintln('vfmt format_file: file: $file') - eprintln('vfmt format_file: cfile: $cfile') - eprintln('vfmt format_file: is_test_file: $is_test_file') - eprintln('vfmt format_file: is_module_file: $is_module_file') - eprintln('vfmt format_file: mod_name: $mod_name') - eprintln('vfmt format_file: mod_folder: $mod_folder') - eprintln('vfmt format_file: mod_folder_parent: $mod_folder_parent') - eprintln('vfmt format_file: use_tmp_main_program: $use_tmp_main_program') - eprintln('vfmt format_file: compiler_params: ') - print_compiler_options( compiler_params ) - eprintln('-------------------------------------------') + eprintln('vfmt2 running fmt.fmt over file: $file') } - compiler_params.fill_with_defaults() + table := table.new_table() + file_ast := parser.parse_file(file, table, .parse_comments, prefs) + formatted_content := fmt.fmt(file_ast, table) + file_name := os.file_name(file) + vfmt_output_path := os.join_path(os.temp_dir(), 'vfmt_' + file_name) + os.write_file(vfmt_output_path, formatted_content ) if foptions.is_verbose { - eprintln('vfmt format_file: compiler_params: AFTER fill_with_defaults() ') - print_compiler_options( compiler_params ) + eprintln('vfmt2 fmt.fmt worked and ${formatted_content.len} bytes were written to ${vfmt_output_path} .') } - formatted_file_path := foptions.compile_file(file, compiler_params) - if use_tmp_main_program { - if !foptions.is_debug { - os.rm(cfile) - } - } - eprintln('${FORMATTED_FILE_TOKEN}${formatted_file_path}') + eprintln('${FORMATTED_FILE_TOKEN}${vfmt_output_path}') } fn print_compiler_options( compiler_params &pref.Preferences ) { @@ -311,21 +242,6 @@ fn find_working_diff_command() ?string { return error('no working diff command found') } -fn (foptions &FormatOptions) compile_file(file string, compiler_params &pref.Preferences) string { - if foptions.is_verbose { - eprintln('> new_v_compiler_with_args file: $file') - eprintln('> new_v_compiler_with_args compiler_params:') - print_compiler_options( compiler_params ) - } - mut v := compiler.new_v(compiler_params) - v.v_fmt_file = file - if foptions.is_all { - v.v_fmt_all = true - } - v.compile() - return v.v_fmt_file_result -} - pub fn (f FormatOptions) str() string { return 'FormatOptions{ ' + ' is_2: $f.is_2' + ' is_l: $f.is_l' + ' is_w: $f.is_w' + ' is_diff: $f.is_diff' + ' is_verbose: $f.is_verbose' + ' is_all: $f.is_all' + ' is_worker: $f.is_worker' + ' is_debug: $f.is_debug' + ' }' } @@ -435,3 +351,7 @@ fn join_flags_and_argument() []string { fn non_empty(arg []string) []string { return arg.filter(it != '') } + +fn verror(s string){ + util.verror('vfmt error', s) +} diff --git a/cmd/tools/vtest-compiler.v b/cmd/tools/vtest-compiler.v index 4d7cfa8157..82edca4fcf 100644 --- a/cmd/tools/vtest-compiler.v +++ b/cmd/tools/vtest-compiler.v @@ -7,10 +7,6 @@ import ( v.pref ) -pub const ( - v_modules_path = os.home_dir() + '.vmodules' -) - fn main() { args := os.args args_string := args[1..].join(' ') @@ -62,7 +58,8 @@ fn v_test_compiler(vargs string) { if ret != 0 { eprintln('failed to run v install') } - if !os.exists(v_modules_path + '/nedpals/args') { + desired_path := os.join_path(pref.default_module_path, 'nedpals', 'args') + if !(os.exists( desired_path ) && os.is_dir( desired_path )) { eprintln('v failed to install a test module') } vmark.stop() diff --git a/cmd/v/internal/compile/cc.v b/cmd/v/internal/compile/cc.v index 347b98179c..fd40288b88 100644 --- a/cmd/v/internal/compile/cc.v +++ b/cmd/v/internal/compile/cc.v @@ -11,10 +11,6 @@ import ( term ) -const ( - v_modules_path = pref.default_module_path -) - fn todo() { } @@ -157,7 +153,7 @@ fn (v mut V) cc() { } if v.pref.build_mode == .build_module { // Create the modules & out directory if it's not there. - mut out_dir := if v.pref.path.starts_with('vlib') { '$v_modules_path${os.path_separator}cache${os.path_separator}$v.pref.path' } else { '$v_modules_path${os.path_separator}$v.pref.path' } + mut out_dir := if v.pref.path.starts_with('vlib') { '${pref.default_module_path}${os.path_separator}cache${os.path_separator}$v.pref.path' } else { '${pref.default_module_path}${os.path_separator}$v.pref.path' } pdir := out_dir.all_before_last(os.path_separator) if !os.is_dir(pdir) { os.mkdir_all(pdir) @@ -226,7 +222,7 @@ fn (v mut V) cc() { else if v.pref.is_cache { /* QTODO - builtin_o_path := os.join_path(v_modules_path, 'cache', 'vlib', 'builtin.o') + builtin_o_path := os.join_path(pref.default_module_path, 'cache', 'vlib', 'builtin.o') a << builtin_o_path.replace('builtin.o', 'strconv.o') // TODO hack no idea why this is needed if os.exists(builtin_o_path) { libs = builtin_o_path @@ -243,7 +239,7 @@ fn (v mut V) cc() { continue } imp_path := imp.replace('.', os.path_separator) - path := '$v_modules_path${os.path_separator}cache${os.path_separator}vlib${os.path_separator}${imp_path}.o' + path := '${pref.default_module_path}${os.path_separator}cache${os.path_separator}vlib${os.path_separator}${imp_path}.o' // println('adding ${imp_path}.o') if os.exists(path) { libs += ' ' + path @@ -255,7 +251,7 @@ fn (v mut V) cc() { os.cp('$vdir/thirdparty/ui/ui.o', path)or{ panic('error copying ui files') } - os.cp('$vdir/thirdparty/ui/ui.vh', v_modules_path + '/vlib/ui.vh')or{ + os.cp('$vdir/thirdparty/ui/ui.vh', pref.default_module_path + '/vlib/ui.vh')or{ panic('error copying ui files') } } @@ -484,13 +480,13 @@ fn (c mut V) cc_windows_cross() { args += if c.pref.ccompiler == 'msvc' { cflags.c_options_before_target_msvc() } else { cflags.c_options_before_target() } mut libs := '' if false && c.pref.build_mode == .default_mode { - libs = '"$v_modules_path/vlib/builtin.o"' + libs = '"${pref.default_module_path}/vlib/builtin.o"' if !os.exists(libs) { println('`$libs` not found') exit(1) } for imp in c.table.imports { - libs += ' "$v_modules_path/vlib/${imp}.o"' + libs += ' "${pref.default_module_path}/vlib/${imp}.o"' } } args += ' $c.out_name_c ' @@ -498,11 +494,11 @@ fn (c mut V) cc_windows_cross() { args += if c.pref.ccompiler == 'msvc' { cflags.c_options_after_target_msvc() } else { cflags.c_options_after_target() } /* - winroot := '$v_modules_path/winroot' + winroot := '${pref.default_module_path}/winroot' if !os.is_dir(winroot) { winroot_url := 'https://github.com/vlang/v/releases/download/v0.1.10/winroot.zip' println('"$winroot" not found.') - println('Download it from $winroot_url and save it in $v_modules_path') + println('Download it from $winroot_url and save it in ${pref.default_module_path}') println('Unzip it afterwards.\n') println('winroot.zip contains all library and header files needed ' + 'to cross-compile for Windows.') exit(1) @@ -522,7 +518,7 @@ fn (c mut V) cc_windows_cross() { } println(cmd) - //cmd := 'clang -o $obj_name -w $include -m32 -c -target x86_64-win32 $v_modules_path/$c.out_name_c' + //cmd := 'clang -o $obj_name -w $include -m32 -c -target x86_64-win32 ${pref.default_module_path}/$c.out_name_c' if c.pref.verbosity.is_higher_or_equal(.level_one) { println(cmd) } diff --git a/cmd/v/internal/compile/compile.v b/cmd/v/internal/compile/compile.v index 46b31303f8..069e5cf636 100644 --- a/cmd/v/internal/compile/compile.v +++ b/cmd/v/internal/compile/compile.v @@ -8,6 +8,7 @@ import ( os v.builder v.pref + v.util strings ) @@ -216,13 +217,6 @@ fn (v mut V) set_module_lookup_paths() { } } - - pub fn verror(s string) { - println('V error: $s') - os.flush() - exit(1) - } - pub fn (v &V) get_builtin_files() []string { // Lookup for built-in folder in lookup path. // Assumption: `builtin/` folder implies usable implementation of builtin @@ -405,4 +399,6 @@ pub fn (v &V) v_files_from_dir(dir string) []string { return res } - +pub fn verror(s string) { + util.verror('compiler error', s) +} diff --git a/cmd/v/internal/compile/compile_options.v b/cmd/v/internal/compile/compile_options.v index 16f85030f5..982592da5e 100644 --- a/cmd/v/internal/compile/compile_options.v +++ b/cmd/v/internal/compile/compile_options.v @@ -7,6 +7,7 @@ import ( internal.flag os.cmdline v.pref + v.util ) fn parse_arguments(args []string) (pref.Preferences, []string) { @@ -72,6 +73,14 @@ fn parse_arguments(args []string) (pref.Preferences, []string) { fn parse_options(flag string, f mut flag.Instance, prefs mut pref.Preferences) { match flag { + 'color' { + f.is_equivalent_to(['color','nocolor']) + util.emanager.set_support_color(true) + } + 'nocolor' { + f.is_equivalent_to(['color','nocolor']) + util.emanager.set_support_color(false) + } 'path' { // -path path_str := f.string() or { diff --git a/cmd/v/internal/compile/msvc.v b/cmd/v/internal/compile/msvc.v index 9a2572efbb..b882e3c818 100644 --- a/cmd/v/internal/compile/msvc.v +++ b/cmd/v/internal/compile/msvc.v @@ -1,6 +1,7 @@ module compile import os +import v.pref #flag windows -l shell32 #flag windows -l dbghelp @@ -225,7 +226,7 @@ pub fn (v mut V) cc_msvc() { } else if v.pref.build_mode == .default_mode { /* - b := os.real_path( '$v_modules_path/vlib/builtin.obj' ) + b := os.real_path( '${pref.default_module_path}/vlib/builtin.obj' ) alibs << '"$b"' if !os.exists(b) { println('`builtin.obj` not found') @@ -235,7 +236,7 @@ pub fn (v mut V) cc_msvc() { if imp == 'webview' { continue } - alibs << '"' + os.real_path( '$v_modules_path/vlib/${imp}.obj' ) + '"' + alibs << '"' + os.real_path( '${pref.default_module_path}/vlib/${imp}.obj' ) + '"' } */ } diff --git a/cmd/v/simple_tool.v b/cmd/v/simple_tool.v deleted file mode 100644 index 10b30d39a4..0000000000 --- a/cmd/v/simple_tool.v +++ /dev/null @@ -1,91 +0,0 @@ -// Copyright (c) 2019-2020 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 - v.pref -) - -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: - vname := if os.user_os() == 'windows' { 'v.exe' } else { 'v' } - os.setenv('VEXE', os.real_path([vroot_path, vname].join(os.path_separator)), true) -} - - -fn launch_tool(is_verbose bool, tool_name string) { - vexe := pref.vexe_path() - vroot := os.dir(vexe) - set_vroot_folder(vroot) - - tool_args := os.args[1..].join(' ') - tool_exe := path_of_executable(os.real_path('$vroot/cmd/tools/$tool_name')) - tool_source := os.real_path('$vroot/cmd/tools/${tool_name}.v') - tool_command := '"$tool_exe" $tool_args' - 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') - } - - // TODO Caching should be done on the `vlib/v` level. - mut should_compile := false - if !os.exists(tool_exe) { - should_compile = true - } 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 - should_compile = true - - if tool_name == 'vself' || tool_name == 'vup' { - // The purpose of vself/up is to update and recompile v itself. - // After the first 'v self' execution, v will be modified, so - // then a second 'v self' will detect, that v is newer than the - // vself executable, and try to recompile vself/up again, which - // will slow down the next v recompilation needlessly. - should_compile = false - } - } - if os.file_last_mod_unix(tool_exe) <= os.file_last_mod_unix(tool_source) { - // the user changed the source code of the tool, or git updated it: - should_compile = true - } - } - if is_verbose { - eprintln('launch_tool should_compile: $should_compile') - } - - if should_compile { - mut compilation_command := '"$vexe" ' - if tool_name == 'vfmt' { - // TODO Remove when it's no longer required by fmt - compilation_command += '-d vfmt ' - } - compilation_command += '"$tool_source"' - if is_verbose { - eprintln('Compiling $tool_name 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) - } - } - if is_verbose { - eprintln('launch_tool running tool command: $tool_command ...') - } - - exit(os.system(tool_command)) -} - -fn path_of_executable(path string) string { - $if windows { - return path + '.exe' - } - return path -} diff --git a/cmd/v/v.v b/cmd/v/v.v index eeeab99d21..b0efa46df0 100644 --- a/cmd/v/v.v +++ b/cmd/v/v.v @@ -30,7 +30,7 @@ fn main() { if args.len == 0 || args[0] in ['-', 'repl'] { // Running `./v` without args launches repl println('For usage information, quit V REPL using `exit` and use `v help`') - launch_tool(false, 'vrepl') + util.launch_tool(false, 'vrepl') return } if args.len > 0 && (args[0] in ['version', '-V', '-version', '--version'] || (args[0] == '-v' && args.len == 1) ) { @@ -53,7 +53,7 @@ fn main() { // Note for future contributors: Please add new subcommands in the `match` block below. if command in simple_cmd { // External tools - launch_tool(prefs2.is_verbose, 'v' + command) + util.launch_tool(prefs2.is_verbose, 'v' + command) return } match command { @@ -61,7 +61,7 @@ fn main() { invoke_help_and_exit(args) } 'create', 'init' { - launch_tool(prefs2.is_verbose, 'vcreate') + util.launch_tool(prefs2.is_verbose, 'vcreate') return } 'translate' { @@ -69,7 +69,7 @@ fn main() { return } 'search', 'install', 'update', 'remove' { - launch_tool(prefs2.is_verbose, 'vpm') + util.launch_tool(prefs2.is_verbose, 'vpm') return } 'get' { diff --git a/vlib/v/builder/builder.v b/vlib/v/builder/builder.v index 76b071766f..d69ca8f8dc 100644 --- a/vlib/v/builder/builder.v +++ b/vlib/v/builder/builder.v @@ -6,6 +6,7 @@ import ( v.ast v.table v.pref + v.util v.checker v.parser v.gen @@ -195,10 +196,6 @@ pub fn (b &Builder) v_files_from_dir(dir string) []string { return res } -fn verror(err string) { - panic('v error: $err') -} - pub fn (b &Builder) log(s string) { if b.pref.verbosity.is_higher_or_equal(.level_two) { println(s) @@ -233,3 +230,7 @@ pub fn (b &Builder) find_module_path(mod string) ?string { } return error('module "$mod" not found') } + +fn verror(s string) { + util.verror('builder error', s) +} diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v index c0dde923ae..1e9a725536 100644 --- a/vlib/v/checker/checker.v +++ b/vlib/v/checker/checker.v @@ -8,6 +8,7 @@ import ( v.table v.token v.pref + v.util os ) @@ -922,15 +923,6 @@ pub fn (c mut Checker) ident(ident mut ast.Ident) table.Type { if !name.contains('.') && !(c.file.mod.name in ['builtin', 'main']) { name = '${c.file.mod.name}.$ident.name' } - // hack - const until consts are fixed properly - if ident.name == 'v_modules_path' { - ident.name = name - ident.kind = .constant - ident.info = ast.IdentVar{ - typ: table.string_type - } - return table.string_type - } // constant if constant := c.table.find_const(name) { ident.name = name @@ -1180,28 +1172,17 @@ pub fn (c mut Checker) error(s string, pos token.Position) { if c.pref.verbosity.is_higher_or_equal(.level_one) { print_backtrace() } - mut path := c.file.path - // Get relative path - workdir := os.getwd() + os.path_separator - if path.starts_with(workdir) { - path = path.replace(workdir, '') + kind := if c.pref.verbosity.is_higher_or_equal(.level_one) { + 'checker error #$c.nr_errors:' + } else { + 'error:' } - mut final_msg_line := '$path:$pos.line_nr: $s' - if c.pref.verbosity.is_higher_or_equal(.level_one) { - final_msg_line = '$path:$pos.line_nr: checker error #$c.nr_errors: $s' - } - c.errors << final_msg_line + ferror := util.formated_error(kind, s, c.file.path, pos) + c.errors << ferror if !(pos.line_nr in c.error_lines) { - eprintln(final_msg_line) + eprintln(ferror) } c.error_lines << pos.line_nr - /* - if colored_output { - eprintln(term.bold(term.red(final_msg_line))) - }else{ - eprintln(final_msg_line) - } - */ if c.pref.verbosity.is_higher_or_equal(.level_one) { println('\n\n') } diff --git a/vlib/v/gen/cgen.v b/vlib/v/gen/cgen.v index eddef7814e..e9bc06b1d1 100644 --- a/vlib/v/gen/cgen.v +++ b/vlib/v/gen/cgen.v @@ -2022,8 +2022,7 @@ fn (g mut Gen) ref_or_deref_arg(arg ast.CallArg, expected_type table.Type) { } fn verror(s string) { - println('cgen error: $s') - exit(1) + util.verror('cgen error', s) } fn (g mut Gen) write_init_function() { diff --git a/vlib/v/gen/x64/gen.v b/vlib/v/gen/x64/gen.v index 64ce718dec..f914ca6fd3 100644 --- a/vlib/v/gen/x64/gen.v +++ b/vlib/v/gen/x64/gen.v @@ -5,6 +5,7 @@ module x64 import ( v.ast + v.util // term ) @@ -387,11 +388,10 @@ fn (g mut Gen) expr(node ast.Expr) { ast.IfExpr {} else { // println(term.red('x64.expr(): bad node')) - } - } + } } +} - fn verror(s string) { - println(s) - exit(1) - } +fn verror(s string) { + util.verror('x64 gen error', s) +} diff --git a/vlib/v/parser/parser.v b/vlib/v/parser/parser.v index baf11d29f5..1945c9696f 100644 --- a/vlib/v/parser/parser.v +++ b/vlib/v/parser/parser.v @@ -9,6 +9,7 @@ import ( v.token v.table v.pref + v.util term os // runtime @@ -16,10 +17,6 @@ import ( // time ) -const ( - colored_output = term.can_show_color_on_stderr() -) - struct Parser { scanner &scanner.Scanner file_name string @@ -235,7 +232,7 @@ fn (p mut Parser) check(expected token.Kind) { // p.next() // } if p.tok.kind != expected { - s := 'syntax error: unexpected `${p.tok.kind.str()}`, expecting `${expected.str()}`' + s := 'unexpected `${p.tok.kind.str()}`, expecting `${expected.str()}`' p.error(s) } p.next() @@ -328,7 +325,7 @@ pub fn (p mut Parser) top_stmt() ast.Stmt { } else { // #printf(""); - p.error('parser: bad top level statement ' + p.tok.str()) + p.error('bad top level statement ' + p.tok.str()) return ast.Stmt{} } } @@ -499,42 +496,19 @@ fn (p mut Parser) range_expr(low ast.Expr) ast.Expr { pub fn (p &Parser) error(s string) { - print_backtrace() - mut path := p.file_name - // Get relative path - workdir := os.getwd() + os.path_separator - if path.starts_with(workdir) { - path = path.replace(workdir, '') - } - final_msg_line := '$path:$p.tok.line_nr: error: $s' - if colored_output { - eprintln(term.bold(term.red(final_msg_line))) - } - else { - eprintln(final_msg_line) - } - exit(1) -} - -pub fn (p &Parser) error_at_line(s string, line_nr int) { - final_msg_line := '$p.file_name:$line_nr: error: $s' - if colored_output { - eprintln(term.bold(term.red(final_msg_line))) - } - else { - eprintln(final_msg_line) + mut kind := 'error:' + if p.pref.verbosity.is_higher_or_equal(.level_one) { + print_backtrace() + kind = 'parser error:' } + ferror := util.formated_error(kind, s, p.file_name, p.tok.position()) + eprintln(ferror) exit(1) } pub fn (p &Parser) warn(s string) { - final_msg_line := '$p.file_name:$p.tok.line_nr: warning: $s' - if colored_output { - eprintln(term.bold(term.blue(final_msg_line))) - } - else { - eprintln(final_msg_line) - } + ferror := util.formated_error('warning:', s, p.file_name, p.tok.position()) + eprintln(ferror) } pub fn (p mut Parser) parse_ident(is_c bool) ast.Ident { @@ -839,7 +813,7 @@ pub fn (p mut Parser) expr(precedence int) ast.Expr { p.check(.rcbr) } else { - p.error('parser: expr(): bad token `$p.tok.str()`') + p.error('expr(): bad token `$p.tok.str()`') } } // Infix @@ -2003,6 +1977,5 @@ fn (p &Parser) new_true_expr() ast.Expr { } fn verror(s string) { - println(s) - exit(1) + util.verror('parser error', s) } diff --git a/vlib/v/pref/default.v b/vlib/v/pref/default.v index a79cbb6cd9..71e82f5e56 100644 --- a/vlib/v/pref/default.v +++ b/vlib/v/pref/default.v @@ -4,11 +4,22 @@ module pref import os +import term pub const ( - default_module_path = os.home_dir() + '.vmodules' + default_module_path = mpath() ) +fn mpath() string { + return os.home_dir() + '.vmodules' +} + +pub fn new_preferences() Preferences { + p := Preferences{} + p.fill_with_defaults() + return p +} + pub fn (p mut Preferences) fill_with_defaults() { if p.vroot == '' { // Location of all vlib files @@ -22,7 +33,7 @@ pub fn (p mut Preferences) fill_with_defaults() { p.lookup_path[i] = path.replace('@vlib', vlib_path).replace('@vmodules', default_module_path) } rpath := os.real_path(p.path) - if p.out_name == ''{ + if p.out_name == '' { filename := os.file_name(rpath).trim_space() mut base := filename.all_before_last('.') if base == '' { @@ -60,6 +71,7 @@ pub fn (p mut Preferences) fill_with_defaults() { } } } + p.enable_globals = true } fn default_c_compiler() string { diff --git a/vlib/v/scanner/scanner.v b/vlib/v/scanner/scanner.v index 39b7a335a6..36c0cbe31e 100644 --- a/vlib/v/scanner/scanner.v +++ b/vlib/v/scanner/scanner.v @@ -13,8 +13,6 @@ import ( const ( single_quote = `\'` double_quote = `"` - error_context_before = 2 // how many lines of source context to print before the pointer line - error_context_after = 2 // ^^^ same, but after is_fmt = os.getenv('VEXE').contains('vfmt') num_sep = `_` // char used as number separator ) @@ -1027,9 +1025,7 @@ pub fn (s &Scanner) error(msg string) { } pub fn verror(s string) { - println('V error: $s') - os.flush() - exit(1) + util.verror('scanner error', s) } pub fn cescaped_path(s string) string { diff --git a/vlib/v/util/errors.v b/vlib/v/util/errors.v new file mode 100644 index 0000000000..eabd54dcc4 --- /dev/null +++ b/vlib/v/util/errors.v @@ -0,0 +1,88 @@ +// Copyright (c) 2019-2020 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 util + +import os +import term +import v.token +import v.util + +// The filepath:line:col: format is the default C compiler error output format. +// It allows editors and IDE's like emacs to quickly find the errors in the +// output and jump to their source with a keyboard shortcut. +// NB: using only the filename may lead to inability of IDE/editors +// to find the source file, when the IDE has a different working folder than +// v itself. + +const ( + error_context_before = 2 // how many lines of source context to print before the pointer line + error_context_after = 2 // ^^^ same, but after +) + +pub const ( + emanager = new_error_manager() +) + +// + +pub struct EManager { +pub mut: + support_color bool // should the error and other messages + // have ANSI terminal escape color codes in them. + // By default, v tries to autodetect, if the terminal supports colors. + // Use -color and -nocolor options to override the detection decision. +} + +pub fn (e &EManager) set_support_color(b bool) { + e.support_color = b +} + +pub fn new_error_manager() &EManager { + return &EManager{ support_color: term.can_show_color_on_stderr() } +} + +pub fn formated_error(kind string /*error or warn*/, emsg string, filepath string, pos token.Position) string { + mut path := filepath + verror_paths_override := os.getenv('VERROR_PATHS') + if verror_paths_override == 'absolute' { + path = os.real_path( path ) + }else{ + // Get relative path + workdir := os.getwd() + os.path_separator + if path.starts_with(workdir) { + path = path.replace(workdir, '') + } + } + column := 0 + position := '${path}:${pos.line_nr+1}:$column:' + // QTODO: retrieve source lines around pos.line_nr and add them here + mut source_context := '' + // + final_position := if emanager.support_color { + term.bold(term.white(position)) + } else { + position + } + mut final_kind := kind + if emanager.support_color { + final_kind = if kind.contains('error') { + term.bold(term.red(kind)) + }else{ + term.bold(term.bright_blue(kind)) + } + } + final_msg := emsg + final_context := if source_context.len > 0 { '\n$source_context' } else { '' } + // + return '$final_position $final_kind $final_msg $final_context'.trim_space() +} + +pub fn verror(kind string, s string) { + if emanager.support_color { + eprintln( term.bold(term.red(kind)) + ': $s' ) + }else{ + eprintln('${kind}: $s') + } + exit(1) +} diff --git a/vlib/v/util/util.v b/vlib/v/util/util.v index e0ee866be4..af49f7fa15 100644 --- a/vlib/v/util/util.v +++ b/vlib/v/util/util.v @@ -4,6 +4,7 @@ module util import os +import v.pref pub const ( v_version = '0.1.26' @@ -75,3 +76,82 @@ pub fn githash(should_get_from_filesystem bool) string { C.snprintf(charptr(buf), 50, '%s', C.V_CURRENT_COMMIT_HASH) return tos_clone(buf) } + +// + +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: + vname := if os.user_os() == 'windows' { 'v.exe' } else { 'v' } + os.setenv('VEXE', os.real_path(os.join_path( vroot_path, vname)), true) +} + +pub fn launch_tool(is_verbose bool, tool_name string) { + vexe := pref.vexe_path() + vroot := os.dir(vexe) + set_vroot_folder(vroot) + + tool_args := os.args[1..].join(' ') + tool_exe := path_of_executable(os.real_path('$vroot/cmd/tools/$tool_name')) + tool_source := os.real_path('$vroot/cmd/tools/${tool_name}.v') + tool_command := '"$tool_exe" $tool_args' + 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') + } + + // TODO Caching should be done on the `vlib/v` level. + mut should_compile := false + if !os.exists(tool_exe) { + should_compile = true + } 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 + should_compile = true + + if tool_name == 'vself' || tool_name == 'vup' { + // The purpose of vself/up is to update and recompile v itself. + // After the first 'v self' execution, v will be modified, so + // then a second 'v self' will detect, that v is newer than the + // vself executable, and try to recompile vself/up again, which + // will slow down the next v recompilation needlessly. + should_compile = false + } + } + if os.file_last_mod_unix(tool_exe) <= os.file_last_mod_unix(tool_source) { + // the user changed the source code of the tool, or git updated it: + should_compile = true + } + } + if is_verbose { + eprintln('launch_tool should_compile: $should_compile') + } + + if should_compile { + mut compilation_command := '"$vexe" ' + compilation_command += '"$tool_source"' + if is_verbose { + eprintln('Compiling $tool_name 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) + } + } + if is_verbose { + eprintln('launch_tool running tool command: $tool_command ...') + } + + exit(os.system(tool_command)) +} + +pub fn path_of_executable(path string) string { + $if windows { + return path + '.exe' + } + return path +}