From 6210984c97a3d6d1e99548cbd4a8499bcf89350e Mon Sep 17 00:00:00 2001 From: Alexander Medvednikov Date: Fri, 20 Dec 2019 00:29:37 +0300 Subject: [PATCH] run vfmt --- v.v | 23 +- vlib/benchmark/benchmark.v | 36 +-- vlib/compiler/asm.v | 14 +- vlib/compiler/cflags.v | 75 ++--- vlib/compiler/cgen.v | 8 +- vlib/compiler/cheaders.v | 19 +- vlib/compiler/compile_errors.v | 152 ++++----- vlib/compiler/compiler_options.v | 11 +- vlib/compiler/depgraph.v | 51 ++- vlib/compiler/enum.v | 12 +- vlib/compiler/expression.v | 3 +- vlib/compiler/for.v | 36 ++- vlib/compiler/gen_x64.v | 6 +- vlib/compiler/if_match.v | 1 + vlib/compiler/json_gen.v | 35 +-- vlib/compiler/live.v | 28 +- vlib/compiler/main.v | 502 +++++++++++++++--------------- vlib/compiler/module_header.v | 107 ++++--- vlib/compiler/modules.v | 54 ++-- vlib/compiler/msvc.v | 237 +++++--------- vlib/compiler/optimization.v | 10 +- vlib/compiler/parser.v | 10 +- vlib/compiler/query.v | 97 +++--- vlib/compiler/scanner.v | 17 +- vlib/compiler/string_expression.v | 3 +- vlib/compiler/struct.v | 78 +++-- vlib/compiler/table.v | 8 +- vlib/compiler/token.v | 41 +-- vlib/compiler/vfmt.v | 2 +- vlib/compiler/vhelp.v | 3 +- vlib/compiler/vtmp.v | 10 +- vlib/compiler/vtools.v | 26 +- vlib/compiler/x64/elf.v | 23 +- vlib/compiler/x64/elf_obj.v | 42 ++- vlib/compiler/x64/gen.v | 138 ++++---- vlib/filepath/filepath.v | 16 +- vlib/os/const.v | 4 - vlib/os/os.v | 465 +++++++++++++++------------ vlib/os/os_nix.v | 25 +- vlib/rand/pcg32.v | 35 ++- vlib/rand/rand.v | 16 +- vlib/rand/splitmix64.v | 27 +- vlib/strconv/atof.v | 348 ++++++++++----------- vlib/strconv/atofq.v | 238 ++------------ vlib/strconv/atoi.v | 100 +++--- vlib/strings/builder_c.v | 32 +- vlib/strings/similarity.v | 5 +- vlib/strings/strings.v | 2 +- vlib/term/can_show_color.v | 16 +- vlib/term/colors.v | 14 +- vlib/term/colors_nix.v | 1 - vlib/term/control.v | 66 ++-- vlib/time/time.v | 382 +++++++++++------------ vlib/vweb/tmpl/tmpl.v | 40 +-- 54 files changed, 1757 insertions(+), 1993 deletions(-) mode change 100755 => 100644 v.v diff --git a/v.v b/v.v old mode 100755 new mode 100644 index 189c4d350f..4e5c7dcea5 --- a/v.v +++ b/v.v @@ -1,7 +1,6 @@ // 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 ( @@ -9,20 +8,19 @@ import ( benchmark os filepath - //time + // time ) const ( known_commands = ['run', 'build', 'version', 'doc'] - simple_tools = ['up', 'create', 'test', 'test-compiler', 'build-tools', - 'build-examples', 'build-vbinaries'] + simple_tools = ['up', 'create', 'test', 'test-compiler', 'build-tools', 'build-examples', 'build-vbinaries'] ) fn main() { - //t := time.ticks() - //defer { println(time.ticks() - t) } + // 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) // external tool if command in simple_tools { compiler.launch_tool('v' + command) @@ -61,7 +59,8 @@ fn main() { mut tmark := benchmark.new_benchmark() if v.pref.x64 { v.compile_x64() - } else { + } + else { v.compile() } if v.pref.is_stats { @@ -76,7 +75,8 @@ fn main() { fn v_command(command string, args []string) { match command { - '', '.', 'run', 'build' { // handled later in vlib/compiler/main.v + '', '.', 'run', 'build' { + // handled later in vlib/compiler/main.v return } 'version' { @@ -109,7 +109,7 @@ 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 { + txt := os.read_file(filepath.join(compiler.v_modules_path,'vlib','${mod}.vh'))or{ panic(err) } println(txt) @@ -118,8 +118,7 @@ fn v_command(command string, args []string) { else { println('v $command: unknown command') println('Run "v help" for usage.') - } - } + }} exit(0) } diff --git a/vlib/benchmark/benchmark.v b/vlib/benchmark/benchmark.v index 82a941dd0a..e6070f4ca6 100644 --- a/vlib/benchmark/benchmark.v +++ b/vlib/benchmark/benchmark.v @@ -2,7 +2,6 @@ module benchmark import time import term - /* Example usage of this module: ``` @@ -26,19 +25,20 @@ println( bmark.total_message('remarks about the benchmark') ) ``` */ -pub struct Benchmark{ + +pub struct Benchmark { pub mut: bench_start_time i64 - bench_end_time i64 - step_start_time i64 - step_end_time i64 - ntotal int - nok int - nfail int - verbose bool + bench_end_time i64 + step_start_time i64 + step_end_time i64 + ntotal int + nok int + nfail int + verbose bool } -pub fn new_benchmark() Benchmark{ +pub fn new_benchmark() Benchmark { return Benchmark{ bench_start_time: benchmark.now() verbose: true @@ -67,14 +67,14 @@ pub fn (b mut Benchmark) ok() { pub fn (b mut Benchmark) fail_many(n int) { b.step_end_time = benchmark.now() - b.ntotal+=n - b.nfail+=n + b.ntotal += n + b.nfail += n } pub fn (b mut Benchmark) ok_many(n int) { b.step_end_time = benchmark.now() - b.ntotal+=n - b.nok+=n + b.ntotal += n + b.nok += n } pub fn (b mut Benchmark) neither_fail_nor_ok() { @@ -86,10 +86,7 @@ pub fn (b &Benchmark) step_message(msg string) string { } pub fn (b &Benchmark) total_message(msg string) string { - mut tmsg := '$msg \n ok, fail, total = ' + - term.ok_message('${b.nok:5d}') + ', ' + - if b.nfail > 0 { term.fail_message('${b.nfail:5d}') } else { '${b.nfail:5d}' } + ', ' + - '${b.ntotal:5d}' + mut tmsg := '$msg \n ok, fail, total = ' + term.ok_message('${b.nok:5d}') + ', ' + if b.nfail > 0 { term.fail_message('${b.nfail:5d}') } else { '${b.nfail:5d}' } + ', ' + '${b.ntotal:5d}' if b.verbose { tmsg = '<=== total time spent $tmsg' } @@ -99,8 +96,8 @@ pub fn (b &Benchmark) total_message(msg string) string { pub fn (b &Benchmark) total_duration() i64 { return (b.bench_end_time - b.bench_start_time) } -//////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// fn (b &Benchmark) tdiff_in_ms(s string, sticks i64, eticks i64) string { if b.verbose { tdiff := (eticks - sticks) @@ -112,3 +109,4 @@ fn (b &Benchmark) tdiff_in_ms(s string, sticks i64, eticks i64) string { fn now() i64 { return time.ticks() } + diff --git a/vlib/compiler/asm.v b/vlib/compiler/asm.v index f3e081463d..1be64f70d2 100644 --- a/vlib/compiler/asm.v +++ b/vlib/compiler/asm.v @@ -1,13 +1,12 @@ // 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 compiler fn (p mut Parser) inline_asm() { if !p.inside_unsafe { p.error('asm() needs to be run inside `unsafe {}`') - } + } p.next() p.check(.lcbr) s := p.check_string() @@ -15,7 +14,7 @@ fn (p mut Parser) inline_asm() { for p.tok == .str { p.genln('"$p.lit"') p.next() - } + } for p.tok == .colon { p.next() arg := p.check_string() @@ -25,11 +24,12 @@ fn (p mut Parser) inline_asm() { var_name := p.check_name() if !p.known_var(var_name) { p.error('unknown variable `$var_name`') - } + } p.check(.rpar) p.genln('($var_name)') - } - } + } + } p.genln(');') p.check(.rcbr) -} +} + diff --git a/vlib/compiler/cflags.v b/vlib/compiler/cflags.v index ea5bd29138..8648e803bf 100644 --- a/vlib/compiler/cflags.v +++ b/vlib/compiler/cflags.v @@ -1,13 +1,11 @@ // 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 compiler import os - // parsed cflag -struct CFlag{ +struct CFlag { mod string // the module in which the flag was given os string // eg. windows | darwin | linux name string // eg. -I @@ -22,11 +20,7 @@ pub fn (c &CFlag) str() string { fn (v &V) get_os_cflags() []CFlag { mut flags := []CFlag for flag in v.table.cflags { - if flag.os == '' - || (flag.os == 'linux' && v.os == .linux) - || (flag.os == 'darwin' && v.os == .mac) - || (flag.os == 'freebsd' && v.os == .freebsd) - || (flag.os == 'windows' && v.os == .windows) { + if flag.os == '' || (flag.os == 'linux' && v.os == .linux) || (flag.os == 'darwin' && v.os == .mac) || (flag.os == 'freebsd' && v.os == .freebsd) || (flag.os == 'windows' && v.os == .windows) { flags << flag } } @@ -38,7 +32,9 @@ fn (v &V) get_rest_of_module_cflags(c &CFlag) []CFlag { cflags := v.get_os_cflags() for flag in cflags { if c.mod == flag.mod { - if c.name == flag.name && c.value == flag.value && c.os == flag.os { continue } + if c.name == flag.name && c.value == flag.value && c.os == flag.os { + continue + } flags << flag } } @@ -48,12 +44,12 @@ fn (v &V) get_rest_of_module_cflags(c &CFlag) []CFlag { // format flag fn (cf &CFlag) format() string { mut value := cf.value - if cf.name in ['-l', '-Wa', '-Wl', '-Wp'] && value.len>0 { + if cf.name in ['-l', '-Wa', '-Wl', '-Wp'] && value.len > 0 { return '${cf.name}${value}'.trim_space() } // convert to absolute path if cf.name == '-I' || cf.name == '-L' || value.ends_with('.o') { - value = '"'+os.realpath(value)+'"' + value = '"' + os.realpath(value) + '"' } return '$cf.name $value'.trim_space() } @@ -71,12 +67,7 @@ fn (table &Table) has_cflag(cflag CFlag) bool { // parse the flags to (table.cflags) []CFlag // Note: clean up big time (joe-c) fn (table mut Table) parse_cflag(cflag string, mod string) ?bool { - allowed_flags := [ - 'framework', - 'library', - 'Wa', 'Wl', 'Wp', - 'I', 'l', 'L', - ] + allowed_flags := ['framework', 'library', 'Wa', 'Wl', 'Wp', 'I', 'l', 'L', ] flag_orig := cflag.trim_space() mut flag := flag_orig if flag == '' { @@ -84,7 +75,9 @@ fn (table mut Table) parse_cflag(cflag string, mod string) ?bool { } mut fos := '' if flag.starts_with('linux') || flag.starts_with('darwin') || flag.starts_with('freebsd') || flag.starts_with('windows') { - pos := flag.index(' ') or { return none } + pos := flag.index(' ') or { + return none + } fos = flag[..pos].trim_space() flag = flag[pos..].trim_space() } @@ -93,7 +86,7 @@ fn (table mut Table) parse_cflag(cflag string, mod string) ?bool { mut value := '' if flag[0] == `-` { for f in allowed_flags { - i := 1+f.len + i := 1 + f.len if i <= flag.len && f == flag[1..i] { name = flag[..i].trim_space() flag = flag[i..].trim_space() @@ -101,20 +94,24 @@ fn (table mut Table) parse_cflag(cflag string, mod string) ?bool { } } } - mut index := flag.index(' -') or { -1 } + mut index := flag.index(' -') or { + -1 + } for index > -1 { mut has_next := false for f in allowed_flags { - i := index+2+f.len - if i <= flag.len && f == flag[index+2..i] { - value = flag[..index+1].trim_space() - flag = flag[index+1..].trim_space() + i := index + 2 + f.len + if i <= flag.len && f == flag[index + 2..i] { + value = flag[..index + 1].trim_space() + flag = flag[index + 1..].trim_space() has_next = true break } } - if has_next { break } - index = flag.index_after(' -', index+1) + if has_next { + break + } + index = flag.index_after(' -', index + 1) } if index == -1 { value = flag.trim_space() @@ -124,9 +121,9 @@ fn (table mut Table) parse_cflag(cflag string, mod string) ?bool { return error('bad #flag `$flag_orig`: missing $hint after `$name`') } cf := CFlag{ - mod: mod, - os: fos, - name: name, + mod: mod + os: fos + name: name value: value } if !table.has_cflag(cf) { @@ -139,13 +136,18 @@ fn (table mut Table) parse_cflag(cflag string, mod string) ?bool { return true } -//TODO: implement msvc specific c_options_before_target and c_options_after_target ... -fn (cflags []CFlag) c_options_before_target_msvc() string { return '' } -fn (cflags []CFlag) c_options_after_target_msvc() string { return '' } +// TODO: implement msvc specific c_options_before_target and c_options_after_target ... +fn (cflags []CFlag) c_options_before_target_msvc() string { + return '' +} + +fn (cflags []CFlag) c_options_after_target_msvc() string { + return '' +} fn (cflags []CFlag) c_options_before_target() string { // -I flags, optimization flags and so on - mut args:=[]string + mut args := []string for flag in cflags { if flag.name != '-l' { args << flag.format() @@ -156,7 +158,7 @@ fn (cflags []CFlag) c_options_before_target() string { fn (cflags []CFlag) c_options_after_target() string { // -l flags (libs) - mut args:=[]string + mut args := []string for flag in cflags { if flag.name == '-l' { args << flag.format() @@ -166,7 +168,7 @@ fn (cflags []CFlag) c_options_after_target() string { } fn (cflags []CFlag) c_options_without_object_files() string { - mut args:=[]string + mut args := []string for flag in cflags { if flag.value.ends_with('.o') || flag.value.ends_with('.obj') { continue @@ -177,7 +179,7 @@ fn (cflags []CFlag) c_options_without_object_files() string { } fn (cflags []CFlag) c_options_only_object_files() string { - mut args:=[]string + mut args := []string for flag in cflags { if flag.value.ends_with('.o') || flag.value.ends_with('.obj') { args << flag.format() @@ -185,3 +187,4 @@ fn (cflags []CFlag) c_options_only_object_files() string { } return args.join(' ') } + diff --git a/vlib/compiler/cgen.v b/vlib/compiler/cgen.v index 42deff08ea..a9cbf6edfa 100644 --- a/vlib/compiler/cgen.v +++ b/vlib/compiler/cgen.v @@ -356,19 +356,19 @@ fn platform_postfix_to_ifdefguard(name string) string { '.v'{ '' } // no guard needed - '_win.v','_windows.v'{ + '_win.v', '_windows.v'{ '#ifdef _WIN32' } '_nix.v'{ '#ifndef _WIN32' } - '_lin.v','_linux.v'{ + '_lin.v', '_linux.v'{ '#ifdef __linux__' } - '_mac.v','_darwin.v'{ + '_mac.v', '_darwin.v'{ '#ifdef __APPLE__' } - '_bsd.v','_freebsd.v '{ + '_bsd.v', '_freebsd.v '{ '#ifdef __FreeBSD__' } '_solaris.v'{ diff --git a/vlib/compiler/cheaders.v b/vlib/compiler/cheaders.v index db86d3b511..a6b6024a74 100644 --- a/vlib/compiler/cheaders.v +++ b/vlib/compiler/cheaders.v @@ -1,8 +1,7 @@ module compiler const ( - -c_common_macros = ' + c_common_macros = ' #define EMPTY_STRUCT_DECLARATION #define EMPTY_STRUCT_INITIALIZATION 0 @@ -23,8 +22,7 @@ c_common_macros = ' #define OPTION_CAST(x) (x) ' - -c_headers = ' + c_headers = ' //#include // int64_t etc #include // TODO remove all these includes, define all function signatures and types manually @@ -91,7 +89,7 @@ c_headers = ' #include // os__wait uses wait on nix #endif -$c_common_macros +$c_common_macros #ifdef _WIN32 #define WINVER 0x0600 @@ -146,8 +144,7 @@ byteptr g_str_buf; int load_so(byteptr); void reload_so(); ' - -js_headers = ' + js_headers = ' var array_string = function() {} var array_byte = function() {} @@ -170,9 +167,7 @@ var map_string = function() {} var map_int = function() {} ' - - -c_builtin_types = ' + c_builtin_types = ' //#include // int64_t etc //#include // int64_t etc @@ -211,8 +206,7 @@ typedef map map_string; #define false 0 #endif ' - -bare_c_headers = ' + bare_c_headers = ' $c_common_macros @@ -223,4 +217,3 @@ void sys_exit (int); ' ) - diff --git a/vlib/compiler/compile_errors.v b/vlib/compiler/compile_errors.v index 28a18e1010..670771ff4e 100644 --- a/vlib/compiler/compile_errors.v +++ b/vlib/compiler/compile_errors.v @@ -4,49 +4,50 @@ import ( os term ) - -////////////////////////////////////////////////////////////////////////////////////////////////// +// //////////////////////////////////////////////////////////////////////////////////////////////// // NB: The code in this file is organized in layers (between the ///// lines). // This allows for easier keeping in sync of error/warn functions. // The functions in each of the layers, call the functions from the layers *below*. // The functions in each of the layers, also have more details about the warn/error situation, // so they can display more informative message, so please call the lowest level variant you can. -////////////////////////////////////////////////////////////////////////////////////////////////// +// //////////////////////////////////////////////////////////////////////////////////////////////// // TLDR: If you have a token index, call: -// p.error_with_token_index(msg, token_index) +// p.error_with_token_index(msg, token_index) // ... not just : -// p.error(msg) -////////////////////////////////////////////////////////////////////////////////////////////////// +// p.error(msg) +// //////////////////////////////////////////////////////////////////////////////////////////////// + fn (p mut Parser) error(s string) { // no positioning info, so just assume that the last token was the culprit: - p.error_with_token_index(s, p.token_idx-1 ) + p.error_with_token_index(s, p.token_idx - 1) } fn (p mut Parser) warn(s string) { - p.warn_with_token_index(s, p.token_idx-1 ) + p.warn_with_token_index(s, p.token_idx - 1) } fn (p mut Parser) production_error_with_token_index(e string, tokenindex int) { if p.pref.is_prod { - p.error_with_token_index( e, tokenindex ) - }else { - p.warn_with_token_index( e, tokenindex ) + p.error_with_token_index(e, tokenindex) + } + else { + p.warn_with_token_index(e, tokenindex) } } fn (p mut Parser) error_with_token_index(s string, tokenindex int) { - p.error_with_position(s, p.scanner.get_scanner_pos_of_token( p.tokens[ tokenindex ] ) ) + p.error_with_position(s, p.scanner.get_scanner_pos_of_token(p.tokens[tokenindex])) } fn (p mut Parser) warn_with_token_index(s string, tokenindex int) { - p.warn_with_position(s, p.scanner.get_scanner_pos_of_token( p.tokens[ tokenindex ] ) ) + p.warn_with_position(s, p.scanner.get_scanner_pos_of_token(p.tokens[tokenindex])) } fn (p mut Parser) error_with_position(s string, sp ScannerPos) { p.print_error_context() - e := normalized_error( s ) - p.scanner.goto_scanner_position( sp ) + e := normalized_error(s) + p.scanner.goto_scanner_position(sp) p.scanner.error_with_col(e, sp.pos - sp.last_nl_pos) } @@ -56,10 +57,10 @@ fn (p mut Parser) warn_with_position(s string, sp ScannerPos) { } // on a warning, restore the scanner state after printing the warning: cpos := p.scanner.get_scanner_pos() - e := normalized_error( s ) - p.scanner.goto_scanner_position( sp ) + e := normalized_error(s) + p.scanner.goto_scanner_position(sp) p.scanner.warn_with_col(e, sp.pos - sp.last_nl_pos) - p.scanner.goto_scanner_position( cpos ) + p.scanner.goto_scanner_position(cpos) } fn (s &Scanner) error(msg string) { @@ -73,14 +74,14 @@ fn (s &Scanner) warn(msg string) { fn (s &Scanner) warn_with_col(msg string, col int) { fullpath := s.get_error_filepath() color_on := s.is_color_output_on() - final_message := if color_on { term.bold(term.bright_blue( msg )) } else { msg } + final_message := if color_on { term.bold(term.bright_blue(msg)) } else { msg } eprintln('warning: ${fullpath}:${s.line_nr+1}:${col}: $final_message') } fn (s &Scanner) error_with_col(msg string, col int) { fullpath := s.get_error_filepath() color_on := s.is_color_output_on() - final_message := if color_on { term.red( term.bold( msg ) ) } else { msg } + final_message := if color_on { term.red(term.bold(msg)) } else { msg } // 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 @@ -88,65 +89,79 @@ fn (s &Scanner) error_with_col(msg string, col int) { // 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. eprintln('${fullpath}:${s.line_nr + 1}:${col}: $final_message') - if s.print_line_on_error && s.nlines > 0 { - context_start_line := imax(0, (s.line_nr - error_context_before )) - context_end_line := imin(s.nlines-1, (s.line_nr + error_context_after + 1 )) + context_start_line := imax(0, (s.line_nr - error_context_before)) + context_end_line := imin(s.nlines - 1, (s.line_nr + error_context_after + 1)) for cline := context_start_line; cline < context_end_line; cline++ { - line := '${(cline+1):5d}| ' + s.line( cline ) + line := '${(cline+1):5d}| ' + s.line(cline) coloredline := if cline == s.line_nr && color_on { term.red(line) } else { line } - eprintln( coloredline ) - if cline != s.line_nr { continue } + eprintln(coloredline) + if cline != s.line_nr { + continue + } // The pointerline should have the same spaces/tabs as the offending // line, so that it prints the ^ character exactly on the *same spot* // where it is needed. That is the reason we can not just // use strings.repeat(` `, col) to form it. mut pointerline := []string - for i , c in line { + for i, c in line { if i < col { x := if c.is_space() { c } else { ` ` } pointerline << x.str() continue } - pointerline << if color_on { term.bold( term.blue('^') ) } else { '^' } + pointerline << if color_on { term.bold(term.blue('^')) } else { '^' } break } - eprintln( ' ' + pointerline.join('') ) + eprintln(' ' + pointerline.join('')) } } exit(1) } -////////////////////////////////////////////////////////////////////////////////////////////////// +// //////////////////////////////////////////////////////////////////////////////////////////////// +// / Misc error helper functions, can be called by any of the functions above +[inline] +fn (p &Parser) cur_tok_index() int { + return p.token_idx - 1 +} -/// Misc error helper functions, can be called by any of the functions above +[inline] +fn imax(a, b int) int { + return if a > b { a } else { b } +} -[inline] fn (p &Parser) cur_tok_index() int { return p.token_idx - 1 } -[inline] fn imax(a,b int) int { return if a > b { a } else { b } } -[inline] fn imin(a,b int) int { return if a < b { a } else { b } } +[inline] +fn imin(a, b int) int { + return if a < b { a } else { b } +} fn (s &Scanner) get_error_filepath() string { verror_paths_override := os.getenv('VERROR_PATHS') use_relative_paths := match verror_paths_override { - 'relative' { true } - 'absolute' { false } - else { s.print_rel_paths_on_error } - } + 'relative'{ + true + } + 'absolute'{ + false + } + else { + s.print_rel_paths_on_error}} if use_relative_paths { workdir := os.getwd() + os.path_separator if s.file_path.starts_with(workdir) { - return s.file_path.replace( workdir, '') + return s.file_path.replace(workdir, '') } return s.file_path } - return os.realpath( s.file_path ) + return os.realpath(s.file_path) } fn (s &Scanner) is_color_output_on() bool { return s.print_colored_error && term.can_show_color_on_stderr() } -fn (p mut Parser) print_error_context(){ +fn (p mut Parser) print_error_context() { // Dump all vars and types for debugging if p.pref.is_debug { // os.write_to_file('/var/tmp/lang.types', '')//pes(p.table.types)) @@ -158,14 +173,14 @@ fn (p mut Parser) print_error_context(){ p.cgen.save() // V up hint cur_path := os.getwd() - if !p.pref.is_repl && !p.pref.is_test && ( p.file_path.contains('v/compiler') || cur_path.contains('v/compiler') ){ + if !p.pref.is_repl && !p.pref.is_test && (p.file_path.contains('v/compiler') || cur_path.contains('v/compiler')) { println('\n=========================') println('It looks like you are building V. It is being frequently updated every day.') - println('If you didn\'t modify V\'s code, most likely there was a change that ') + println("If you didn\'t modify V\'s code, most likely there was a change that ") println('lead to this error.') println('\nRun `v up`, that will most likely fix it.') - //println('\nIf this doesn\'t help, re-install V from source or download a precompiled' + ' binary from\nhttps://vlang.io.') - println('\nIf this doesn\'t help, please create a GitHub issue.') + // println('\nIf this doesn\'t help, re-install V from source or download a precompiled' + ' binary from\nhttps://vlang.io.') + println("\nIf this doesn\'t help, please create a GitHub issue.") println('=========================\n') } if p.pref.is_debug { @@ -176,30 +191,25 @@ fn (p mut Parser) print_error_context(){ fn normalized_error(s string) string { // Print `[]int` instead of `array_int` in errors - mut res := s.replace('array_', '[]') - .replace('__', '.') - .replace('Option_', '?') - .replace('main.', '') + mut res := s.replace('array_', '[]').replace('__', '.').replace('Option_', '?').replace('main.', '') if res.contains('_V_MulRet_') { res = res.replace('_V_MulRet_', '(').replace('_V_', ', ') - res = res[..res.len-1] + ')"' + res = res[..res.len - 1] + ')"' } return res } -////////////////////////////////////////////////////////////////////////////////////////////////// - +// //////////////////////////////////////////////////////////////////////////////////////////////// // The goal of ScannerPos is to track the current scanning position, // so that if there is an error found later, v could show a more accurate // position about where the error initially was. // NB: The fields of ScannerPos *should be kept synchronized* with the // corresponding fields in Scanner. - struct ScannerPos { mut: - pos int - line_nr int - last_nl_pos int + pos int + line_nr int + last_nl_pos int } pub fn (s ScannerPos) str() string { @@ -207,7 +217,11 @@ pub fn (s ScannerPos) str() string { } fn (s &Scanner) get_scanner_pos() ScannerPos { - return ScannerPos{ pos: s.pos line_nr: s.line_nr last_nl_pos: s.last_nl_pos } + return ScannerPos{ + pos: s.pos + line_nr: s.line_nr + last_nl_pos: s.last_nl_pos + } } fn (s mut Scanner) goto_scanner_position(scp ScannerPos) { @@ -217,7 +231,7 @@ fn (s mut Scanner) goto_scanner_position(scp ScannerPos) { } fn (s &Scanner) get_last_nl_from_pos(_pos int) int { - pos := if _pos >= s.text.len { s.text.len-1 } else { _pos } + pos := if _pos >= s.text.len { s.text.len - 1 } else { _pos } for i := pos; i >= 0; i-- { if s.text[i] == `\n` { return i @@ -234,33 +248,27 @@ fn (s &Scanner) get_scanner_pos_of_token(tok &Token) ScannerPos { } } -/////////////////////////////// - +// ///////////////////////////// fn (p mut Parser) mutable_arg_error(i int, arg Var, f Fn) { - mut dots_example := 'mut $p.lit' + mut dots_example := 'mut $p.lit' if i > 0 { dots_example = '.., ' + dots_example } if i < f.args.len - 1 { dots_example = dots_example + ',..' } - p.error('`$arg.name` is a mutable argument, you need to provide `mut`: ' + - '`$f.name ($dots_example)`') + p.error('`$arg.name` is a mutable argument, you need to provide `mut`: ' + '`$f.name ($dots_example)`') } const ( - warn_match_arrow = '=> is no longer needed in match statements, use\n' + -'match foo { + warn_match_arrow = '=> is no longer needed in match statements, use\n' + 'match foo { 1 { bar } 2 { baz } else { ... } }' - //make_receiver_mutable = - + // make_receiver_mutable = err_used_as_value = 'used as value' - - and_or_error = 'use `()` to make the boolean expression clear\n' + -'for example: `(a && b) || c` instead of `a && b || c`' - -err_modify_bitfield = 'to modify a bitfield flag use the methods: set, clear, toggle. and to check for flag use: has' + and_or_error = 'use `()` to make the boolean expression clear\n' + 'for example: `(a && b) || c` instead of `a && b || c`' + err_modify_bitfield = 'to modify a bitfield flag use the methods: set, clear, toggle. and to check for flag use: has' ) + diff --git a/vlib/compiler/compiler_options.v b/vlib/compiler/compiler_options.v index 58c64481c2..4c94d51c20 100644 --- a/vlib/compiler/compiler_options.v +++ b/vlib/compiler/compiler_options.v @@ -1,7 +1,6 @@ // 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 compiler pub fn get_v_options_and_main_command(args []string) ([]string,string) { @@ -12,12 +11,16 @@ pub fn get_v_options_and_main_command(args []string) ([]string,string) { if !a.starts_with('-') { potential_commands << a continue - }else{ + } + else { options << a - if a in ['-o', '-os', '-cc', '-cflags', '-d'] { i++ } + if a in ['-o', '-os', '-cc', '-cflags', '-d'] { + i++ + } } } // potential_commands[0] is always the executable itself, so ignore it command := if potential_commands.len > 1 { potential_commands[1] } else { '' } - return options, command + return options,command } + diff --git a/vlib/compiler/depgraph.v b/vlib/compiler/depgraph.v index 0d652e8cf7..4e92ac64c2 100644 --- a/vlib/compiler/depgraph.v +++ b/vlib/compiler/depgraph.v @@ -1,36 +1,35 @@ // 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. - // Directed acyclic graph // this implementation is specifically suited to ordering dependencies - module compiler -struct DepGraphNode { +struct DepGraphNode { mut: name string deps []string } struct DepGraph { -//pub: - mut: + // pub: +mut: acyclic bool nodes []DepGraphNode } struct DepSet { - mut: +mut: items []string } -pub fn(dset mut DepSet) add(item string) { +pub fn (dset mut DepSet) add(item string) { dset.items << item } -pub fn(dset &DepSet) diff(otherset DepSet) DepSet { - mut diff := DepSet{} +pub fn (dset &DepSet) diff(otherset DepSet) DepSet { + mut diff := DepSet{ + } for item in dset.items { if !item in otherset.items { diff.items << item @@ -39,7 +38,7 @@ pub fn(dset &DepSet) diff(otherset DepSet) DepSet { return diff } -pub fn(dset &DepSet) size() int { +pub fn (dset &DepSet) size() int { return dset.items.len } @@ -49,37 +48,34 @@ pub fn new_dep_graph() &DepGraph { } } - -pub fn(graph mut DepGraph) add(mod string, deps []string) { +pub fn (graph mut DepGraph) add(mod string, deps []string) { graph.nodes << DepGraphNode{ - name: mod, + name: mod deps: deps.clone() } } -pub fn(graph &DepGraph) resolve() &DepGraph { +pub fn (graph &DepGraph) resolve() &DepGraph { mut node_names := map[string]DepGraphNode mut node_deps := map[string]DepSet - for _, node in graph.nodes { node_names[node.name] = node - - mut dep_set := DepSet{} + mut dep_set := DepSet{ + } for _, dep in node.deps { dep_set.add(dep) } node_deps[node.name] = dep_set } - mut resolved := new_dep_graph() for node_deps.size != 0 { - mut ready_set := DepSet{} + mut ready_set := DepSet{ + } for name, deps in node_deps { if deps.size() == 0 { ready_set.add(name) } } - if ready_set.size() == 0 { mut g := new_dep_graph() g.acyclic = false @@ -88,25 +84,22 @@ pub fn(graph &DepGraph) resolve() &DepGraph { } return g } - for name in ready_set.items { node_deps.delete(name) resolved.nodes << node_names[name] } - for name, deps in node_deps { node_deps[name] = deps.diff(ready_set) } } - return resolved } -pub fn(graph &DepGraph) last_node() DepGraphNode { - return graph.nodes[graph.nodes.len-1] +pub fn (graph &DepGraph) last_node() DepGraphNode { + return graph.nodes[graph.nodes.len - 1] } -pub fn(graph &DepGraph) display() string { +pub fn (graph &DepGraph) display() string { mut out := '\n' for node in graph.nodes { for dep in node.deps { @@ -116,7 +109,7 @@ pub fn(graph &DepGraph) display() string { return out } -pub fn(graph &DepGraph) display_cycles() string { +pub fn (graph &DepGraph) display_cycles() string { mut node_names := map[string]DepGraphNode for node in graph.nodes { node_names[node.name] = node @@ -124,7 +117,9 @@ pub fn(graph &DepGraph) display_cycles() string { mut out := '\n' for node in graph.nodes { for dep in node.deps { - if !(dep in node_names) { continue } + if !(dep in node_names) { + continue + } dn := node_names[dep] if node.name in dn.deps { out += ' * $node.name -> $dep\n' diff --git a/vlib/compiler/enum.v b/vlib/compiler/enum.v index b3ebe72c87..c4ee8779d5 100644 --- a/vlib/compiler/enum.v +++ b/vlib/compiler/enum.v @@ -1,7 +1,6 @@ // 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 compiler fn (p mut Parser) enum_decl(no_name bool) { @@ -12,7 +11,7 @@ fn (p mut Parser) enum_decl(no_name bool) { } p.check(.key_enum) p.fspace() - mut enum_name := p.check_name() + mut enum_name := p.check_name() is_c := enum_name == 'C' && p.tok == .dot if is_c { p.check(.dot) @@ -44,7 +43,8 @@ fn (p mut Parser) enum_decl(no_name bool) { p.next() val = p.lit.int() p.next() - }else{ + } + else { p.next() enum_assign_tidx = p.cur_tok_index() p.error_with_token_index('only numbers are allowed in enum initializations', enum_assign_tidx) @@ -62,7 +62,7 @@ fn (p mut Parser) enum_decl(no_name bool) { if is_flag && fields.len > 32 { p.error('when an enum is used as bit field, it must have a max of 32 fields') } - mut T := Type { + mut T := Type{ name: enum_name mod: p.mod parent: 'int' @@ -89,9 +89,9 @@ fn (p mut Parser) check_enum_member_access() { p.error('enum `$T.name` does not have value `$val`') } p.gen(mod_gen_name(T.mod) + '__' + p.expected_type + '_' + val) - } else { + } + else { p.error('`$T.name` is not an enum') } } - diff --git a/vlib/compiler/expression.v b/vlib/compiler/expression.v index a338a858a6..796506d33d 100644 --- a/vlib/compiler/expression.v +++ b/vlib/compiler/expression.v @@ -718,7 +718,7 @@ fn (p mut Parser) factor() string { // p.fgen('$sizeof_typ)') return 'int' } - .amp,.dot,.mul { + .amp, .dot, .mul { // (dot is for enum vals: `.green`) return p.name_expr() } @@ -822,3 +822,4 @@ fn (p mut Parser) factor() string { } // { user | name: 'new name' } + diff --git a/vlib/compiler/for.v b/vlib/compiler/for.v index 286427abf6..0776065290 100644 --- a/vlib/compiler/for.v +++ b/vlib/compiler/for.v @@ -1,7 +1,6 @@ // 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 compiler fn (p mut Parser) for_st() { @@ -11,7 +10,7 @@ fn (p mut Parser) for_st() { if p.tok != .lcbr { p.fspace() } - //debug := p.scanner.file_path.contains('r_draw') + // debug := p.scanner.file_path.contains('r_draw') p.open_scope() mut label := 0 mut to := 0 @@ -70,18 +69,19 @@ fn (p mut Parser) for_st() { p.check(.key_in) p.fspace() tmp := p.get_tmp() - mut typ, expr := p.tmp_expr() + mut typ,expr := p.tmp_expr() is_arr := typ.starts_with('array_') is_map := typ.starts_with('map_') is_str := typ == 'string' - is_variadic_arg := typ.starts_with('varg_') + is_variadic_arg := typ.starts_with('varg_') if !is_arr && !is_str && !is_map && !is_variadic_arg { p.error('cannot range over type `$typ`') } if !is_variadic_arg { if p.is_js { p.genln('var $tmp = $expr;') - } else { + } + else { p.genln('$typ $tmp = $expr;') } } @@ -92,7 +92,7 @@ fn (p mut Parser) for_st() { p.gen_for_varg_header(i, expr, typ, val) } else if is_arr { - typ = typ[6..].replace('_ptr','*') + typ = typ[6..].replace('_ptr', '*') p.gen_for_header(i, tmp, typ, val) } else if is_map { @@ -109,7 +109,7 @@ fn (p mut Parser) for_st() { if p.known_var(i) { p.error('redefinition of `$i`') } - p.register_var(Var { + p.register_var(Var{ name: i typ: i_var_type is_mut: true @@ -120,7 +120,7 @@ fn (p mut Parser) for_st() { if p.known_var(val) { p.error('redefinition of `$val`') } - p.register_var(Var { + p.register_var(Var{ name: val typ: typ ptr: typ.contains('*') @@ -134,9 +134,9 @@ fn (p mut Parser) for_st() { p.check(.key_in) p.fspace() tmp := p.get_tmp() - mut typ, expr := p.tmp_expr() + mut typ,expr := p.tmp_expr() is_range := p.tok == .dotdot - is_variadic_arg := typ.starts_with('varg_') + is_variadic_arg := typ.starts_with('varg_') mut range_end := '' if is_range { p.check_types(typ, 'int') @@ -144,14 +144,13 @@ fn (p mut Parser) for_st() { if p.pref.x64 { to = p.lit.int() } - range_typ, range_expr := p.tmp_expr() + range_typ,range_expr := p.tmp_expr() p.check_types(range_typ, 'int') range_end = range_expr if p.pref.x64 { label = p.x64.gen_loop_start(expr.int()) - //to = range_expr.int() // TODO why empty? + // to = range_expr.int() // TODO why empty? } - } is_arr := typ.contains('array') is_fixed := typ.starts_with('[') @@ -162,7 +161,9 @@ fn (p mut Parser) for_st() { if !is_variadic_arg { if p.is_js { p.genln('var $tmp = $expr;') - } else if !is_fixed { // Don't copy if it's a fixed array + } + else if !is_fixed { + // Don't copy if it's a fixed array p.genln('$typ $tmp = $expr;') } } @@ -177,7 +178,7 @@ fn (p mut Parser) for_st() { p.gen_for_range_header(i, range_end, tmp, typ, val) } else if is_arr { - typ = typ[6..].replace('_ptr','*')// all after `array_` + typ = typ[6..].replace('_ptr', '*') // all after `array_` p.gen_for_header(i, tmp, typ, val) } else if is_str { @@ -194,7 +195,7 @@ fn (p mut Parser) for_st() { if p.known_var(val) { p.error('redefinition of `$val`') } - p.register_var(Var { + p.register_var(Var{ name: val typ: typ ptr: typ.contains('*') @@ -203,7 +204,8 @@ fn (p mut Parser) for_st() { is_for_var: true }) } - } else { + } + else { // `for a < b {` p.gen('while (') p.check_types(p.bool_expression(), 'bool') diff --git a/vlib/compiler/gen_x64.v b/vlib/compiler/gen_x64.v index 963863306d..5c65594aaa 100644 --- a/vlib/compiler/gen_x64.v +++ b/vlib/compiler/gen_x64.v @@ -1,6 +1,4 @@ module compiler - -//import filepath - -//import compiler.x64 +// import filepath +// import compiler.x64 diff --git a/vlib/compiler/if_match.v b/vlib/compiler/if_match.v index e5e1198d67..2da1ee58d0 100644 --- a/vlib/compiler/if_match.v +++ b/vlib/compiler/if_match.v @@ -138,6 +138,7 @@ fn (p mut Parser) match_statement(is_expr bool) string { break } p.check(.comma) + p.fspace() got_comma = true } p.gen(')') diff --git a/vlib/compiler/json_gen.v b/vlib/compiler/json_gen.v index 42b6057090..e42db24d45 100644 --- a/vlib/compiler/json_gen.v +++ b/vlib/compiler/json_gen.v @@ -1,9 +1,7 @@ // 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 compiler - // TODO replace with comptime code generation. // TODO remove cJSON dependency. // OLD: User decode_User(string js) { @@ -27,7 +25,7 @@ fn (p mut Parser) gen_json_for_type(typ Type) { } // println('gen_json_for_type( $typ.name )') // Register decoder fn - mut dec_fn := Fn { + mut dec_fn := Fn{ mod: p.mod typ: 'Option_$typ.name' name: js_dec_name(t) @@ -38,19 +36,19 @@ fn (p mut Parser) gen_json_for_type(typ Type) { } // decode_TYPE funcs receive an actual cJSON* object to decode // cJSON_Parse(str) call is added by the compiler - arg := Var { + arg := Var{ typ: 'cJSON*' } dec_fn.args << arg p.table.register_fn(dec_fn) // Register encoder fn - mut enc_fn := Fn { + mut enc_fn := Fn{ mod: p.mod typ: 'cJSON*' name: js_enc_name(t) } // encode_TYPE funcs receive an object to encode - enc_arg := Var { + enc_arg := Var{ typ: t } enc_fn.args << enc_arg @@ -85,28 +83,20 @@ string res = tos2(""); if field.attr == 'skip' { continue } - name := if field.attr.starts_with('json:') { - field.attr[5..] - } else { - field.name - } + name := if field.attr.starts_with('json:') { field.attr[5..] } else { field.name } field_type := p.table.find_type(field.typ) _typ := field.typ.replace('*', '') enc_name := js_enc_name(_typ) if field.attr == 'raw' { - dec += ' res->$field.name = tos2(cJSON_PrintUnformatted(' + - 'js_get(root, "$name")));\n' - - } else { + dec += ' res->$field.name = tos2(cJSON_PrintUnformatted(' + 'js_get(root, "$name")));\n' + } + else { // Now generate decoders for all field types in this struct // need to do it here so that these functions are generated first p.gen_json_for_type(field_type) - dec_name := js_dec_name(_typ) - if is_js_prim(_typ) { - dec += ' res->$field.name = $dec_name (js_get(' + - 'root, "$name"))' + dec += ' res->$field.name = $dec_name (js_get(' + 'root, "$name"))' } else { dec += ' $dec_name (js_get(root, "$name"), & (res->$field.name))' @@ -116,16 +106,13 @@ string res = tos2(""); enc += ' cJSON_AddItemToObject(o, "$name",$enc_name (val.$field.name)); \n' } // cJSON_delete - //p.cgen.fns << '$dec return opt_ok(res); \n}' + // p.cgen.fns << '$dec return opt_ok(res); \n}' p.cgen.fns << '$dec return opt_ok(res, sizeof(*res)); \n}' p.cgen.fns << '/*enc start*/ $enc return o;}' } fn is_js_prim(typ string) bool { - return typ == 'int' || typ == 'string' || - typ == 'bool' || typ == 'f32' || typ == 'f64' || - typ == 'i8' || typ == 'i16' || typ == 'i64' || - typ == 'u16' || typ == 'u32' || typ == 'u64' + return typ == 'int' || typ == 'string' || typ == 'bool' || typ == 'f32' || typ == 'f64' || typ == 'i8' || typ == 'i16' || typ == 'i64' || typ == 'u16' || typ == 'u32' || typ == 'u64' } fn (p mut Parser) decode_array(array_type string) string { diff --git a/vlib/compiler/live.v b/vlib/compiler/live.v index 53457cfb36..e953ea9dfa 100644 --- a/vlib/compiler/live.v +++ b/vlib/compiler/live.v @@ -7,10 +7,10 @@ fn (v &V) generate_hotcode_reloading_compiler_flags() []string { mut a := []string if v.pref.is_live || v.pref.is_so { // See 'man dlopen', and test running a GUI program compiled with -live - if (v.os == .linux || os.user_os() == 'linux'){ + if (v.os == .linux || os.user_os() == 'linux') { a << '-rdynamic' } - if (v.os == .mac || os.user_os() == 'mac'){ + if (v.os == .mac || os.user_os() == 'mac') { a << '-flat_namespace' } } @@ -26,7 +26,8 @@ fn (v &V) generate_hotcode_reloading_declarations() { if v.pref.is_live { cgen.genln('pthread_mutex_t live_fn_mutex = PTHREAD_MUTEX_INITIALIZER;') } - } else { + } + else { if v.pref.is_so { cgen.genln('HANDLE live_fn_mutex;') cgen.genln(' @@ -45,7 +46,9 @@ void pthread_mutex_unlock(HANDLE *m) { } fn (v &V) generate_hotcode_reloading_main_caller() { - if !v.pref.is_live { return } + if !v.pref.is_live { + return + } // We are in live code reload mode, so start the .so loader in the background mut cgen := v.cgen cgen.genln('') @@ -57,9 +60,10 @@ fn (v &V) generate_hotcode_reloading_main_caller() { cgen.genln(' load_so(live_library_name);') cgen.genln(' pthread_t _thread_so;') cgen.genln(' pthread_create(&_thread_so , NULL, (void *)&reload_so, live_library_name);') - } else { + } + else { // windows: - so_name := file_base + if v.pref.ccompiler == 'msvc' {'.dll'} else {'.so'} + so_name := file_base + if v.pref.ccompiler == 'msvc' { '.dll' } else { '.so' } cgen.genln(' char *live_library_name = "$so_name";') cgen.genln(' live_fn_mutex = CreateMutexA(0, 0, 0);') cgen.genln(' load_so(live_library_name);') @@ -70,7 +74,6 @@ fn (v &V) generate_hotcode_reloading_main_caller() { fn (v &V) generate_hot_reload_code() { mut cgen := v.cgen - // Hot code reloading if v.pref.is_live { mut file := os.realpath(v.dir) @@ -79,17 +82,14 @@ fn (v &V) generate_hot_reload_code() { // Need to build .so file before building the live application // The live app needs to load this .so file on initialization. mut vexe := os.args[0] - if os.user_os() == 'windows' { vexe = cescaped_path(vexe) file = cescaped_path(file) } - mut msvc := '' if v.pref.ccompiler == 'msvc' { msvc = '-cc msvc' } - so_debug_flag := if v.pref.is_debug { '-g' } else { '' } cmd_compile_shared_library := '$vexe $msvc $so_debug_flag -o $file_base -solive -shared $file' if v.pref.show_c_cmd { @@ -100,7 +100,6 @@ fn (v &V) generate_hot_reload_code() { diff := time.ticks() - ticks println('compiling shared library took $diff ms') println('=========\n') - cgen.genln(' void lfnmutex_print(char *s){ @@ -111,7 +110,6 @@ void lfnmutex_print(char *s){ } } ') - if v.os != .windows { cgen.genln(' void* live_lib=0; @@ -153,12 +151,10 @@ int load_so(byteptr path) { return 0; } ') - for so_fn in cgen.so_fns { cgen.genln('$so_fn = (void *)GetProcAddress(live_lib, "$so_fn"); ') } } - cgen.genln('return 1; } @@ -218,10 +214,10 @@ void reload_so() { time__sleep_ms(100); } } -' ) +') } - if v.pref.is_so { cgen.genln(' int load_so(byteptr path) { return 0; }') } } + diff --git a/vlib/compiler/main.v b/vlib/compiler/main.v index 0415a170e6..7b680b59cc 100644 --- a/vlib/compiler/main.v +++ b/vlib/compiler/main.v @@ -1,7 +1,6 @@ // 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 compiler import ( @@ -25,8 +24,7 @@ enum BuildMode { } const ( - supported_platforms = ['windows', 'mac', 'macos', 'linux', 'freebsd', - 'openbsd', 'netbsd', 'dragonfly', 'android', 'js', 'solaris', 'haiku'] + supported_platforms = ['windows', 'mac', 'macos', 'linux', 'freebsd', 'openbsd', 'netbsd', 'dragonfly', 'android', 'js', 'solaris', 'haiku'] ) enum OS { @@ -37,7 +35,7 @@ enum OS { openbsd netbsd dragonfly - js // TODO + js // TODO android solaris haiku @@ -59,84 +57,81 @@ enum Pass { struct V { pub mut: - os OS // the OS to build for - out_name_c string // name of the temporary C file - files []string // all V files that need to be parsed and compiled - dir string // directory (or file) being compiled (TODO rename to path?) - compiled_dir string // contains os.realpath() of the dir of the final file beeing compiled, or the dir itself when doing `v .` - table &Table // table with types, vars, functions etc - cgen &CGen // C code generator - x64 &x64.Gen - pref &Preferences // all the preferences and settings extracted to a struct for reusability - lang_dir string // "~/code/v" - out_name string // "program.exe" - vroot string - mod string // module being built with -lib - parsers []Parser // file parsers - vgen_buf strings.Builder // temporary buffer for generated V code (.str() etc) - file_parser_idx map[string]int // map absolute file path to v.parsers index - gen_parser_idx map[string]int - cached_mods []string + os OS // the OS to build for + out_name_c string // name of the temporary C file + files []string // all V files that need to be parsed and compiled + dir string // directory (or file) being compiled (TODO rename to path?) + compiled_dir string // contains os.realpath() of the dir of the final file beeing compiled, or the dir itself when doing `v .` + table &Table // table with types, vars, functions etc + cgen &CGen // C code generator + x64 &x64.Gen + pref &Preferences // all the preferences and settings extracted to a struct for reusability + lang_dir string // "~/code/v" + out_name string // "program.exe" + vroot string + mod string // module being built with -lib + parsers []Parser // file parsers + vgen_buf strings.Builder // temporary buffer for generated V code (.str() etc) + file_parser_idx map[string]int // map absolute file path to v.parsers index + gen_parser_idx map[string]int + cached_mods []string module_lookup_paths []string } struct Preferences { pub mut: - build_mode BuildMode - //nofmt bool // disable vfmt - is_test bool // `v test string_test.v` - is_script bool // single file mode (`v program.v`), main function can be skipped - is_live bool // main program that contains live/hot code - is_solive bool // a shared library, that will be used in a -live main program - is_so bool // an ordinary shared library, -shared, no matter if it is live or not - is_prof bool // benchmark every function - translated bool // `v translate doom.v` are we running V code translated from C? allow globals, ++ expressions, etc - is_prod bool // use "-O2" - is_verbose bool // print extra information with `v.log()` - obfuscate bool // `v -obf program.v`, renames functions to "f_XXX" - is_repl bool - is_run bool - show_c_cmd bool // `v -show_c_cmd` prints the C command to build program.v.c - sanitize bool // use Clang's new "-fsanitize" option - - is_debug bool // false by default, turned on by -g or -cg, it tells v to pass -g to the C backend compiler. - is_vlines bool // turned on by -g, false by default (it slows down .tmp.c generation slightly). - is_keep_c bool // -keep_c , tell v to leave the generated .tmp.c alone (since by default v will delete them after c backend finishes) + build_mode BuildMode + // nofmt bool // disable vfmt + is_test bool // `v test string_test.v` + is_script bool // single file mode (`v program.v`), main function can be skipped + is_live bool // main program that contains live/hot code + is_solive bool // a shared library, that will be used in a -live main program + is_so bool // an ordinary shared library, -shared, no matter if it is live or not + is_prof bool // benchmark every function + translated bool // `v translate doom.v` are we running V code translated from C? allow globals, ++ expressions, etc + is_prod bool // use "-O2" + is_verbose bool // print extra information with `v.log()` + obfuscate bool // `v -obf program.v`, renames functions to "f_XXX" + is_repl bool + is_run bool + show_c_cmd bool // `v -show_c_cmd` prints the C command to build program.v.c + sanitize bool // use Clang's new "-fsanitize" option + is_debug bool // false by default, turned on by -g or -cg, it tells v to pass -g to the C backend compiler. + is_vlines bool // turned on by -g, false by default (it slows down .tmp.c generation slightly). + is_keep_c bool // -keep_c , tell v to leave the generated .tmp.c alone (since by default v will delete them after c backend finishes) // NB: passing -cg instead of -g will set is_vlines to false and is_g to true, thus making v generate cleaner C files, // which are sometimes easier to debug / inspect manually than the .tmp.c files by plain -g (when/if v line number generation breaks). - is_cache bool // turns on v usage of the module cache to speed up compilation. - - is_stats bool // `v -stats file_test.v` will produce more detailed statistics for the tests that were run - no_auto_free bool // `v -nofree` disable automatic `free()` insertion for better performance in some applications (e.g. compilers) - cflags string // Additional options which will be passed to the C compiler. - // For example, passing -cflags -Os will cause the C compiler to optimize the generated binaries for size. - // You could pass several -cflags XXX arguments. They will be merged with each other. - // You can also quote several options at the same time: -cflags '-Os -fno-inline-small-functions'. - ccompiler string // the name of the used C compiler - building_v bool - autofree bool - compress bool - //skip_builtin bool // Skips re-compilation of the builtin module - // to increase compilation time. - // This is on by default, since a vast majority of users do not - // work on the builtin module itself. - //generating_vh bool - comptime_define string // -D vfmt for `if $vfmt {` - fast bool // use tcc/x64 codegen - enable_globals bool // allow __global for low level code - //is_fmt bool - is_bare bool - - user_mod_path string // `v -user_mod_path /Users/user/modules` adds a new lookup path for imported modules - vlib_path string - vpath string - x64 bool - output_cross_c bool - prealloc bool + is_cache bool // turns on v usage of the module cache to speed up compilation. + is_stats bool // `v -stats file_test.v` will produce more detailed statistics for the tests that were run + no_auto_free bool // `v -nofree` disable automatic `free()` insertion for better performance in some applications (e.g. compilers) + cflags string // Additional options which will be passed to the C compiler. + // For example, passing -cflags -Os will cause the C compiler to optimize the generated binaries for size. + // You could pass several -cflags XXX arguments. They will be merged with each other. + // You can also quote several options at the same time: -cflags '-Os -fno-inline-small-functions'. + ccompiler string // the name of the used C compiler + building_v bool + autofree bool + compress bool + // skip_builtin bool // Skips re-compilation of the builtin module + // to increase compilation time. + // This is on by default, since a vast majority of users do not + // work on the builtin module itself. + // generating_vh bool + comptime_define string // -D vfmt for `if $vfmt {` + fast bool // use tcc/x64 codegen + enable_globals bool // allow __global for low level code + // is_fmt bool + is_bare bool + user_mod_path string // `v -user_mod_path /Users/user/modules` adds a new lookup path for imported modules + vlib_path string + vpath string + x64 bool + output_cross_c bool + prealloc bool } // Should be called by main at the end of the compilation process, to cleanup -pub fn (v &V) finalize_compilation(){ +pub fn (v &V) finalize_compilation() { // TODO remove if v.pref.autofree { /* @@ -159,10 +154,10 @@ pub fn (v &V) finalize_compilation(){ } pub fn (v mut V) add_parser(parser Parser) int { - v.parsers << parser - pidx := v.parsers.len-1 - v.file_parser_idx[os.realpath(parser.file_path)] = pidx - return pidx + v.parsers << parser + pidx := v.parsers.len - 1 + v.file_parser_idx[os.realpath(parser.file_path)] = pidx + return pidx } pub fn (v &V) get_file_parser_index(file string) ?int { @@ -175,20 +170,19 @@ pub fn (v &V) get_file_parser_index(file string) ?int { // find existing parser or create new one. returns v.parsers index pub fn (v mut V) parse(file string, pass Pass) int { - //println('parse($file, $pass)') + // println('parse($file, $pass)') pidx := v.get_file_parser_index(file) or { mut p := v.new_parser_from_file(file) p.parse(pass) - //if p.pref.autofree { p.scanner.text.free() free(p.scanner) } + // if p.pref.autofree { p.scanner.text.free() free(p.scanner) } return v.add_parser(p) } // println('matched ' + v.parsers[pidx].file_path + ' with $file') v.parsers[pidx].parse(pass) - //if v.parsers[i].pref.autofree { v.parsers[i].scanner.text.free() free(v.parsers[i].scanner) } + // if v.parsers[i].pref.autofree { v.parsers[i].scanner.text.free() free(v.parsers[i].scanner) } return pidx } - pub fn (v mut V) compile() { // Emily: Stop people on linux from being able to build with msvc if os.user_os() != 'windows' && v.pref.ccompiler == 'msvc' { @@ -217,6 +211,7 @@ pub fn (v mut V) compile() { } } */ + // First pass (declarations) for file in v.files { v.parse(file, .decl) @@ -226,7 +221,7 @@ pub fn (v mut V) compile() { if v.pref.is_debug { $if js { cgen.genln('const VDEBUG = 1;\n') - } $else { + } $else { cgen.genln('#define VDEBUG (1)') } } @@ -236,7 +231,6 @@ pub fn (v mut V) compile() { if v.os == .js { cgen.genln('#define _VJS (1) ') } - v_hash := vhash() $if js { cgen.genln('const V_COMMIT_HASH = "$v_hash";\n') @@ -245,23 +239,22 @@ pub fn (v mut V) compile() { cgen.genln('#define V_COMMIT_HASH "$v_hash"') cgen.genln('#endif') } - q := cgen.nogen // TODO hack cgen.nogen = false $if js { cgen.genln(js_headers) } $else { if !v.pref.is_bare { - cgen.genln('#include ') // int64_t etc - } else { + cgen.genln('#include ') // int64_t etc + } + else { cgen.genln('#include ') } - cgen.genln(c_builtin_types) - if !v.pref.is_bare { cgen.genln(c_headers) - } else { + } + else { cgen.genln(bare_c_headers) } } @@ -293,7 +286,7 @@ pub fn (v mut V) compile() { if v.pref.is_live && v.os != .windows { cgen.includes << '#include ' } - //cgen.genln('/*================================== FNS =================================*/') + // cgen.genln('/*================================== FNS =================================*/') cgen.genln('// this line will be replaced with definitions') mut defs_pos := cgen.lines.len - 1 if defs_pos == -1 { @@ -302,13 +295,12 @@ pub fn (v mut V) compile() { cgen.nogen = q for i, file in v.files { v.parse(file, .main) - //if p.pref.autofree { p.scanner.text.free() free(p.scanner) } + // if p.pref.autofree { p.scanner.text.free() free(p.scanner) } // Format all files (don't format automatically generated vlib headers) - //if !v.pref.nofmt && !file.contains('/vlib/') { - // new vfmt is not ready yet - //} + // if !v.pref.nofmt && !file.contains('/vlib/') { + // new vfmt is not ready yet + // } } - // add parser generated V code (str() methods etc) mut vgen_parser := v.new_parser_from_string(v.vgen_buf.str()) // free the string builder which held the generated methods @@ -321,7 +313,7 @@ pub fn (v mut V) compile() { generate_vh(v.dir) } // All definitions - mut def := strings.new_builder(10000)// Avoid unnecessary allocations + mut def := strings.new_builder(10000) // Avoid unnecessary allocations def.writeln(cgen.const_defines.join_lines()) $if !js { def.writeln(cgen.includes.join_lines()) @@ -362,11 +354,9 @@ pub fn (v mut V) compile() { pub fn (v mut V) compile_x64() { $if !linux { println('v -x64 can only generate Linux binaries for now') - println('You are not on a Linux system, so you will not ' + - 'be able to run the resulting executable') + println('You are not on a Linux system, so you will not ' + 'be able to run the resulting executable') } - - v.files << v.v_files_from_dir(filepath.join(v.pref.vlib_path, 'builtin', 'bare')) + v.files << v.v_files_from_dir(filepath.join(v.pref.vlib_path,'builtin','bare')) v.files << v.dir v.x64.generate_elf_header() for f in v.files { @@ -379,7 +369,9 @@ pub fn (v mut V) compile_x64() { } fn (v mut V) generate_init() { - $if js { return } + $if js { + return + } if v.pref.build_mode == .build_module { nogen := v.cgen.nogen v.cgen.nogen = false @@ -406,10 +398,9 @@ fn (v mut V) generate_init() { } } consts_init_body := v.cgen.consts_init.join_lines() - - if v.pref.is_bare { - // vlib can't have init_consts() - v.cgen.genln(' + if v.pref.is_bare { + // vlib can't have init_consts() + v.cgen.genln(' void init() { $call_mod_init_consts $consts_init_body @@ -417,11 +408,10 @@ fn (v mut V) generate_init() { $call_mod_init } ') - } - + } if !v.pref.is_bare { - // vlib can't have `init_consts()` - v.cgen.genln('void init() { + // vlib can't have `init_consts()` + v.cgen.genln('void init() { g_str_buf=malloc(1000); #if VPREALLOC g_m2_buf = malloc(50 * 1000 * 1000); @@ -433,8 +423,8 @@ $consts_init_body builtin__init(); $call_mod_init }') - // _STR function can't be defined in vlib - v.cgen.genln(' + // _STR function can't be defined in vlib + v.cgen.genln(' string _STR(const char *fmt, ...) { va_list argptr; va_start(argptr, fmt); @@ -467,14 +457,15 @@ string _STR_TMP(const char *fmt, ...) { } ') - } + } } } pub fn (v mut V) generate_main() { mut cgen := v.cgen - $if js { return } - + $if js { + return + } if v.pref.is_vlines { // After this point, the v files are compiled. // The rest is auto generated code, which will not have @@ -485,7 +476,6 @@ pub fn (v mut V) generate_main() { cgen.lines << '#line $lines_so_far "${cescaped_path(os.realpath(cgen.out_path))}"' cgen.genln('') } - // Make sure the main function exists // Obviously we don't need it in libraries if v.pref.build_mode != .build_module { @@ -493,7 +483,7 @@ pub fn (v mut V) generate_main() { // It can be skipped in single file programs // But make sure that there's some code outside of main() if (v.pref.is_script && cgen.fn_main.trim_space() != '') || v.pref.is_repl { - //println('Generating main()...') + // println('Generating main()...') v.gen_main_start(true) cgen.genln('$cgen.fn_main;') v.gen_main_end('return 0') @@ -510,19 +500,23 @@ pub fn (v mut V) generate_main() { if test_fn_names.len == 0 { verror('test files need to have at least one test function') } - // Generate a C `main`, which calls every single test function v.gen_main_start(false) - if v.pref.is_stats { cgen.genln('BenchedTests bt = main__start_testing();') } for tfname in test_fn_names { - if v.pref.is_stats { cgen.genln('BenchedTests_testing_step_start(&bt, tos3("$tfname"));') } + if v.pref.is_stats { + cgen.genln('BenchedTests_testing_step_start(&bt, tos3("$tfname"));') + } cgen.genln('$tfname ();') - if v.pref.is_stats { cgen.genln('BenchedTests_testing_step_end(&bt);') } + if v.pref.is_stats { + cgen.genln('BenchedTests_testing_step_end(&bt);') + } + } + if v.pref.is_stats { + cgen.genln('BenchedTests_end_testing(&bt);') } - if v.pref.is_stats { cgen.genln('BenchedTests_end_testing(&bt);') } v.gen_main_end('return g_test_fails > 0') } else if v.table.main_exists() { @@ -540,18 +534,17 @@ pub fn (v mut V) generate_main() { } } -pub fn (v mut V) gen_main_start(add_os_args bool){ +pub fn (v mut V) gen_main_start(add_os_args bool) { v.cgen.genln('int main(int argc, char** argv) { ') - v.cgen.genln(' init();') - if add_os_args && 'os' in v.table.imports { v.cgen.genln(' os__args = os__init_os_args(argc, (byteptr*)argv);') } v.generate_hotcode_reloading_main_caller() v.cgen.genln('') } -pub fn (v mut V) gen_main_end(return_statement string){ + +pub fn (v mut V) gen_main_end(return_statement string) { v.cgen.genln('') v.cgen.genln(' $return_statement;') v.cgen.genln('}') @@ -561,12 +554,7 @@ pub fn final_target_out_name(out_name string) string { $if windows { return out_name.replace('/', '\\') + '.exe' } - return if out_name.starts_with('/') { - out_name - } - else { - './' + out_name - } + return if out_name.starts_with('/') { out_name } else { './' + out_name } } pub fn (v V) run_compiled_executable_and_exit() { @@ -574,19 +562,21 @@ pub fn (v V) run_compiled_executable_and_exit() { if v.pref.is_verbose { println('============ running $v.out_name ============') } - mut cmd := '"' + final_target_out_name(v.out_name).replace('.exe','') + '"' - + mut cmd := '"' + final_target_out_name(v.out_name).replace('.exe', '') + '"' 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[i+2..].join(' ') + for i, a in args { + if i == 0 { + continue + } + if a.starts_with('-') { + continue + } + if a in ['run', 'test'] { + args_after += args[i + 2..].join(' ') break } } cmd += args_after - if v.pref.is_test { ret := os.system(cmd) if ret != 0 { @@ -598,7 +588,7 @@ pub fn (v V) run_compiled_executable_and_exit() { // TODO: make the runner wrapping as transparent as possible // (i.e. use execve when implemented). For now though, the runner // just returns the same exit code as the child process. - exit( ret ) + exit(ret) } exit(0) } @@ -611,10 +601,13 @@ pub fn (v &V) v_files_from_dir(dir string) []string { println('use `v -o v v.v` instead of `v -o v compiler`') } verror("$dir doesn't exist") - } else if !os.is_dir(dir) { + } + else if !os.is_dir(dir) { verror("$dir isn't a directory") } - mut files := os.ls(dir) or { panic(err) } + mut files := os.ls(dir)or{ + panic(err) + } if v.pref.is_verbose { println('v_files_from_dir ("$dir")') } @@ -654,7 +647,7 @@ pub fn (v mut V) add_v_files_to_compile() { v.set_module_lookup_paths() mut builtin_files := v.get_builtin_files() if v.pref.is_bare { - //builtin_files = [] + // builtin_files = [] } // Builtin cache exists? Use it. if v.pref.is_cache { @@ -664,15 +657,16 @@ pub fn (v mut V) add_v_files_to_compile() { builtin_files = [builtin_vh] } } - if v.pref.is_verbose { v.log('v.add_v_files_to_compile > builtin_files: $builtin_files') } - + if v.pref.is_verbose { + v.log('v.add_v_files_to_compile > builtin_files: $builtin_files') + } // Parse builtin imports for file in builtin_files { // add builtins first v.files << file mut p := v.new_parser_from_file(file) p.parse(.imports) - //if p.pref.autofree { p.scanner.text.free() free(p.scanner) } + // if p.pref.autofree { p.scanner.text.free() free(p.scanner) } v.add_parser(p) } // Parse user imports @@ -687,7 +681,7 @@ pub fn (v mut V) add_v_files_to_compile() { p.table.imports << 'os' p.table.register_module('os') } - //if p.pref.autofree { p.scanner.text.free() free(p.scanner) } + // if p.pref.autofree { p.scanner.text.free() free(p.scanner) } v.add_parser(p) } // Parse lib imports @@ -723,8 +717,12 @@ pub fn (v mut V) add_v_files_to_compile() { } // add remaining main files last for p in v.parsers { - if p.mod != 'main' { continue } - if p.is_vgen { continue } + if p.mod != 'main' { + continue + } + if p.is_vgen { + continue + } v.files << p.file_path } } @@ -732,42 +730,40 @@ pub fn (v mut V) add_v_files_to_compile() { pub fn (v &V) get_builtin_files() []string { // .vh cache exists? Use it if v.pref.is_bare { - return v.v_files_from_dir(filepath.join(v.pref.vlib_path, 'builtin', 'bare')) + return v.v_files_from_dir(filepath.join(v.pref.vlib_path,'builtin','bare')) } $if js { - return v.v_files_from_dir(filepath.join(v.pref.vlib_path, 'builtin', 'js')) + return v.v_files_from_dir(filepath.join(v.pref.vlib_path,'builtin','js')) } - return v.v_files_from_dir(filepath.join(v.pref.vlib_path, 'builtin')) + return v.v_files_from_dir(filepath.join(v.pref.vlib_path,'builtin')) } // get user files -pub fn (v &V) get_user_files() []string { +pub fn (v &V) get_user_files() []string { mut dir := v.dir v.log('get_v_files($dir)') // Need to store user files separately, because they have to be added after // libs, but we dont know which libs need to be added yet mut user_files := []string - preludes_path := filepath.join(v.pref.vlib_path,'compiler','preludes') - if v.pref.is_live { user_files << filepath.join(preludes_path,'live_main.v') } if v.pref.is_solive { user_files << filepath.join(preludes_path,'live_shared.v') } - if v.pref.is_test { user_files << filepath.join(preludes_path,'tests_assertions.v') } if v.pref.is_test && v.pref.is_stats { user_files << filepath.join(preludes_path,'tests_with_stats.v') } - is_test := dir.ends_with('_test.v') mut is_internal_module_test := false if is_test { - tcontent := os.read_file( dir ) or { panic('$dir does not exist') } + tcontent := os.read_file(dir)or{ + panic('$dir does not exist') + } if tcontent.contains('module ') && !tcontent.contains('module main') { is_internal_module_test = true } @@ -780,17 +776,20 @@ pub fn (v &V) get_user_files() []string { v.log('> That brings in all other ordinary .v files in the same module too .') } user_files << single_test_v_file - dir = os.basedir( single_test_v_file ) + dir = os.basedir(single_test_v_file) } - if dir.ends_with('.v') || dir.ends_with('.vsh') { single_v_file := dir // Just compile one file and get parent dir user_files << single_v_file - if v.pref.is_verbose { v.log('> just compile one file: "${single_v_file}"') } + if v.pref.is_verbose { + v.log('> just compile one file: "${single_v_file}"') + } } else { - if v.pref.is_verbose { v.log('> add all .v files from directory "${dir}" ...') } + if v.pref.is_verbose { + v.log('> add all .v files from directory "${dir}" ...') + } // Add .v files from the directory being compiled files := v.v_files_from_dir(dir) for file in files { @@ -821,28 +820,25 @@ fn (v &V) get_imported_module_files(mod string) []string { // parse deps from already parsed builtin/user files pub fn (v mut V) parse_lib_imports() { mut done_imports := []string - for i in 0..v.parsers.len { + for i in 0 .. v.parsers.len { for _, mod in v.parsers[i].import_table.imports { - if mod in done_imports { continue } + if mod in done_imports { + continue + } import_path := v.find_module_path(mod) or { - v.parsers[i].error_with_token_index( - 'cannot import module "$mod" (not found)', - v.parsers[i].import_table.get_import_tok_idx(mod)) + v.parsers[i].error_with_token_index('cannot import module "$mod" (not found)', v.parsers[i].import_table.get_import_tok_idx(mod)) break } vfiles := v.v_files_from_dir(import_path) if vfiles.len == 0 { - v.parsers[i].error_with_token_index( - 'cannot import module "$mod" (no .v files in "$import_path")', - v.parsers[i].import_table.get_import_tok_idx(mod)) + v.parsers[i].error_with_token_index('cannot import module "$mod" (no .v files in "$import_path")', v.parsers[i].import_table.get_import_tok_idx(mod)) } // Add all imports referenced by these libs for file in vfiles { pidx := v.parse(file, .imports) p_mod := v.parsers[pidx].mod if p_mod != mod { - v.parsers[pidx].error_with_token_index( - 'bad module definition: ${v.parsers[pidx].file_path} imports module "$mod" but $file is defined as module `$p_mod`', 1) + v.parsers[pidx].error_with_token_index('bad module definition: ${v.parsers[pidx].file_path} imports module "$mod" but $file is defined as module `$p_mod`', 1) } } done_imports << mod @@ -870,15 +866,14 @@ pub fn get_param_after(joined_args, arg, def string) string { pub fn get_cmdline_option(args []string, param string, def string) string { mut found := false - for arg in args { if found { return arg - } else if param == arg { + } + else if param == arg { found = true } } - return def } @@ -889,31 +884,29 @@ pub fn (v &V) log(s string) { println(s) } -pub fn new_v(args[]string) &V { +pub fn new_v(args []string) &V { // Create modules dirs if they are missing if !os.is_dir(v_modules_path) { - os.mkdir(v_modules_path) or { panic(err) } - os.mkdir('$v_modules_path${os.path_separator}cache') or { panic(err) } + os.mkdir(v_modules_path)or{ + panic(err) + } + os.mkdir('$v_modules_path${os.path_separator}cache')or{ + panic(err) + } } - // optional, custom modules search path user_mod_path := get_cmdline_option(args, '-user_mod_path', '') - // Location of all vlib files vroot := os.dir(vexe_path()) - vlib_path := get_cmdline_option(args, '-vlib-path', filepath.join(vroot, 'vlib')) + vlib_path := get_cmdline_option(args, '-vlib-path', filepath.join(vroot,'vlib')) vpath := get_cmdline_option(args, '-vpath', v_modules_path) - mut vgen_buf := strings.new_builder(1000) vgen_buf.writeln('module vgen\nimport strings') - joined_args := args.join(' ') - target_os := get_arg(joined_args, 'os', '') comptime_define := get_arg(joined_args, 'd', '') - //println('comptimedefine=$comptime_define') + // println('comptimedefine=$comptime_define') mut out_name := get_arg(joined_args, 'o', 'a.out') - mut dir := args.last() if 'run' in args { dir = get_param_after(joined_args, 'run', '') @@ -927,7 +920,6 @@ pub fn new_v(args[]string) &V { if args.len < 2 { dir = '' } - // build mode mut build_mode := BuildMode.default_mode mut mod := '' @@ -935,20 +927,10 @@ pub fn new_v(args[]string) &V { build_mode = .build_module os.chdir(vroot) // v build module ~/v/os => os.o - mod_path := if dir.contains('vlib') { - dir.all_after('vlib'+os.path_separator) - } - else if dir.starts_with('.\\') || dir.starts_with('./') { - dir[2..] - } - else if dir.starts_with(os.path_separator) { - dir.all_after(os.path_separator) - } else { - dir - } + mod_path := if dir.contains('vlib') { dir.all_after('vlib' + os.path_separator) } else if dir.starts_with('.\\') || dir.starts_with('./') { dir[2..] } else if dir.starts_with(os.path_separator) { dir.all_after(os.path_separator) } else { dir } mod = mod_path.replace(os.path_separator, '.') println('Building module "${mod}" (dir="$dir")...') - //out_name = '$TmpPath/vlib/${base}.o' + // out_name = '$TmpPath/vlib/${base}.o' if !out_name.ends_with('.c') { out_name = mod } @@ -961,6 +943,7 @@ pub fn new_v(args[]string) &V { println('!Cross compiling $out_name') } */ + } is_test := dir.ends_with('_test.v') is_script := dir.ends_with('.v') || dir.ends_with('.vsh') @@ -976,8 +959,7 @@ pub fn new_v(args[]string) &V { // optimized. if out_name == 'v' && os.is_dir('vlib/compiler') { println('Saving the resulting V executable in `./v2`') - println('Use `v -o v v.v` if you want to replace current '+ - 'V executable.') + println('Use `v -o v v.v` if you want to replace current ' + 'V executable.') out_name = 'v2' } } @@ -991,7 +973,9 @@ pub fn new_v(args[]string) &V { d := out_name.all_before_last(os.path_separator) if !os.is_dir(d) { println('creating a new directory "$d"') - os.mkdir(d) or { panic(err) } + os.mkdir(d)or{ + panic(err) + } } } mut _os := OS.mac @@ -1028,10 +1012,10 @@ pub fn new_v(args[]string) &V { else { _os = os_from_string(target_os) } - //println('VROOT=$vroot') + // println('VROOT=$vroot') // v.exe's parent directory should contain vlib if !os.is_dir(vlib_path) || !os.is_dir(vlib_path + os.path_separator + 'builtin') { - //println('vlib not found, downloading it...') + // println('vlib not found, downloading it...') /* ret := os.system('git clone --depth=1 https://github.com/vlang/v .') if ret != 0 { @@ -1045,37 +1029,33 @@ pub fn new_v(args[]string) &V { println('(os.executable=${os.executable()} vlib_path=$vlib_path vexe_path=${vexe_path()}') exit(1) } - mut out_name_c := get_vtmp_filename(out_name, '.tmp.c') - cflags := get_cmdline_cflags(args) rdir := os.realpath(dir) rdir_name := os.filename(rdir) - if '-bare' in args { verror('use -freestanding instead of -bare') } - obfuscate := '-obf' in args is_repl := '-repl' in args - pref := &Preferences { + pref := &Preferences{ is_test: is_test is_script: is_script is_so: '-shared' in args is_solive: '-solive' in args is_prod: '-prod' in args is_verbose: '-verbose' in args || '--verbose' in args - - is_debug: '-g' in args || '-cg' in args - is_vlines: '-g' in args && !('-cg' in args) - is_keep_c: '-keep_c' in args - is_cache: '-cache' in args + is_debug: '-g' in args || '-cg' in args + is_vlines: '-g' in args && !('-cg' in args) + is_keep_c: '-keep_c' in args + is_cache: '-cache' in args is_stats: '-stats' in args obfuscate: obfuscate is_prof: '-prof' in args is_live: '-live' in args sanitize: '-sanitize' in args - //nofmt: '-nofmt' in args + // nofmt: '-nofmt' in args + show_c_cmd: '-show_c_cmd' in args translated: 'translated' in args is_run: 'run' in args @@ -1091,9 +1071,10 @@ pub fn new_v(args[]string) &V { build_mode: build_mode cflags: cflags ccompiler: find_c_compiler() - building_v: !is_repl && (rdir_name == 'compiler' || rdir_name == 'v.v' || dir.contains('vlib')) + building_v: !is_repl && (rdir_name == 'compiler' || rdir_name == 'v.v' || dir.contains('vlib')) comptime_define: comptime_define - //is_fmt: comptime_define == 'vfmt' + // is_fmt: comptime_define == 'vfmt' + user_mod_path: user_mod_path vlib_path: vlib_path vpath: vpath @@ -1102,7 +1083,7 @@ pub fn new_v(args[]string) &V { println('C compiler=$pref.ccompiler') } if pref.is_so { - out_name_c = get_vtmp_filename( out_name, '.tmp.so.c') + out_name_c = get_vtmp_filename(out_name, '.tmp.so.c') } $if !linux { if pref.is_bare && !out_name.ends_with('.c') { @@ -1113,7 +1094,7 @@ pub fn new_v(args[]string) &V { os: _os out_name: out_name dir: dir - compiled_dir: if os.is_dir( rdir ) { rdir } else { os.dir( rdir ) } + compiled_dir: if os.is_dir(rdir) { rdir } else { os.dir(rdir) } lang_dir: vroot table: new_table(obfuscate) out_name_c: out_name_c @@ -1132,8 +1113,9 @@ fn non_empty(a []string) []string { pub fn env_vflags_and_os_args() []string { vosargs := os.getenv('VOSARGS') - if '' != vosargs { return non_empty(vosargs.split(' ')) } - + if '' != vosargs { + return non_empty(vosargs.split(' ')) + } mut args := []string vflags := os.getenv('VFLAGS') if '' != vflags { @@ -1142,13 +1124,14 @@ pub fn env_vflags_and_os_args() []string { if os.args.len > 1 { args << os.args[1..] } - } else{ + } + else { args << os.args } return non_empty(args) } -pub fn vfmt(args[]string) { +pub fn vfmt(args []string) { println('running vfmt...') file := args.last() if !os.exists(file) { @@ -1173,23 +1156,29 @@ pub fn vfmt(args[]string) { os.exec('$vroot/tools/vfmt $file') or { panic(err) } //if !os.exists(' */ + } pub fn create_symlink() { - $if windows { return } + $if windows { + return + } vexe := vexe_path() link_path := '/usr/local/bin/v' ret := os.system('ln -sf $vexe $link_path') if ret == 0 { println('Symlink "$link_path" has been created') - } else { + } + else { println('Failed to create symlink "$link_path". Try again with sudo.') } } pub fn vexe_path() string { vexe := os.getenv('VEXE') - if '' != vexe { return vexe } + if '' != vexe { + return vexe + } real_vexe_path := os.realpath(os.executable()) os.setenv('VEXE', real_vexe_path, true) return real_vexe_path @@ -1204,46 +1193,70 @@ pub fn verror(s string) { pub fn vhash() string { mut buf := [50]byte buf[0] = 0 - C.snprintf(charptr(buf), 50, '%s', C.V_COMMIT_HASH ) + C.snprintf(charptr(buf), 50, '%s', C.V_COMMIT_HASH) return tos_clone(buf) } pub fn cescaped_path(s string) string { - return s.replace('\\','\\\\') + return s.replace('\\', '\\\\') } pub fn os_from_string(os string) OS { match os { - 'linux' { return .linux} - 'windows' { return .windows} - 'mac' { return .mac} - 'macos' { return .mac} - 'freebsd' { return .freebsd} - 'openbsd' { return .openbsd} - 'netbsd' { return .netbsd} - 'dragonfly' { return .dragonfly} - 'js' { return .js} - 'solaris' { return .solaris} - 'android' { return .android} + 'linux' { + return .linux + } + 'windows' { + return .windows + } + 'mac' { + return .mac + } + 'macos' { + return .mac + } + 'freebsd' { + return .freebsd + } + 'openbsd' { + return .openbsd + } + 'netbsd' { + return .netbsd + } + 'dragonfly' { + return .dragonfly + } + 'js' { + return .js + } + 'solaris' { + return .solaris + } + 'android' { + return .android + } 'msvc' { // notice that `-os msvc` became `-cc msvc` verror('use the flag `-cc msvc` to build using msvc') } - 'haiku' { return .haiku } - else { panic('bad os $os') } - } - //println('bad os $os') // todo panic? + 'haiku' { + return .haiku + } + else { + panic('bad os $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: vname := if os.user_os() == 'windows' { 'v.exe' } else { 'v' } - os.setenv('VEXE', os.realpath( [vroot_path, vname].join(os.path_separator) ), true) + os.setenv('VEXE', os.realpath([vroot_path, vname].join(os.path_separator)), true) } pub fn new_v_compiler_with_args(args []string) &V { @@ -1253,3 +1266,4 @@ pub fn new_v_compiler_with_args(args []string) &V { os.setenv('VOSARGS', allargs.join(' '), true) return new_v(allargs) } + diff --git a/vlib/compiler/module_header.v b/vlib/compiler/module_header.v index 8a0af95e64..c67e5a532f 100644 --- a/vlib/compiler/module_header.v +++ b/vlib/compiler/module_header.v @@ -1,7 +1,6 @@ // 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 compiler import ( @@ -9,28 +8,27 @@ import ( os filepath ) - /* .vh generation logic. .vh files contain only function signatures, consts, and types. They are used together with pre-compiled modules. */ + struct VhGen { mut: - i int // token index + i int // token index consts strings.Builder - fns strings.Builder - types strings.Builder + fns strings.Builder + types strings.Builder tokens []Token - } // `mod` == "vlib/os" fn generate_vh(mod string) { println('\n\n\n\nGenerating a V header file for module `$mod`') vexe := vexe_path() - full_mod_path := filepath.join(os.dir(vexe), mod) + full_mod_path := filepath.join(os.dir(vexe),mod) dir := if mod.starts_with('vlib') { '$compiler.v_modules_path${os.path_separator}$mod' } else { mod } path := dir + '.vh' pdir := dir.all_before_last(os.path_separator) @@ -38,32 +36,28 @@ fn generate_vh(mod string) { os.mkdir_all(pdir) // os.mkdir(os.realpath(dir)) or { panic(err) } } - mut out := os.create(path) or { panic(err) } - mod_path := mod.replace("\\", "/") + mut out := os.create(path)or{ + panic(err) + } + mod_path := mod.replace('\\', '/') out.writeln('// $mod_path module header\n') mod_def := if mod_path.contains('/') { mod_path.all_after('/') } else { mod_path } // "os" out.writeln('module $mod_def\n') // Consts println(full_mod_path) vfiles := os.walk_ext(full_mod_path, '.v') - //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.ends_with('_lin.v') && - !it.contains('${os.path_separator}examples') && - !it.contains('_js.v') && - !it.contains('_bare.v') && - !it.contains('${os.path_separator}js')) // TODO merge once filter allows it - //println('f:') - //println(filtered) + // 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.ends_with('_lin.v') && !it.contains('${os.path_separator}examples') && !it.contains('_js.v') && !it.contains('_bare.v') && !it.contains('${os.path_separator}js')) // TODO merge once filter allows it + // println('f:') + // println(filtered) mut v := new_v(['foo.v']) - //v.pref.generating_vh = true + // v.pref.generating_vh = true mut g := VhGen{ - consts : strings.new_builder(1000) - fns : strings.new_builder(1000) - types : strings.new_builder(1000) + consts: strings.new_builder(1000) + fns: strings.new_builder(1000) + types: strings.new_builder(1000) } for file in filtered { mut p := v.new_parser_from_file(file) @@ -76,19 +70,23 @@ fn generate_vh(mod string) { continue } match g.tokens[g.i].tok { - .key_fn { g.generate_fn() } - .key_const { g.generate_const() } - .key_struct { g.generate_type() } - .key_type { g.generate_alias() } - else {} - } + .key_fn { + g.generate_fn() + } + .key_const { + g.generate_const() + } + .key_struct { + g.generate_type() + } + .key_type { + g.generate_alias() + } + else { + }} } } - result := - g.types.str() + - g.consts.str() + - g.fns.str().replace('\n\n\n', '\n').replace('\n\n', '\n') - + result := g.types.str() + g.consts.str() + g.fns.str().replace('\n\n\n', '\n').replace('\n\n', '\n') out.writeln(result.replace('[ ] ', '[]').replace('? ', '?')) out.close() } @@ -97,23 +95,21 @@ fn (g mut VhGen) generate_fn() { if g.i >= g.tokens.len - 2 { return } - mut next := g.tokens[g.i+1] - if g.i > 0 && g.tokens[g.i-1].tok != .key_pub { + mut next := g.tokens[g.i + 1] + if g.i > 0 && g.tokens[g.i - 1].tok != .key_pub { // Skip private fns - //return '' + // return '' } - if next.tok == .name && next.lit == 'C' { - //println('skipping C') + // println('skipping C') return } - //out.write('pub ') + // out.write('pub ') mut tok := g.tokens[g.i] for g.i < g.tokens.len - 1 && tok.tok != .lcbr { - next = g.tokens[g.i+1] - + next = g.tokens[g.i + 1] g.fns.write(tok.str()) - if tok.tok != .lpar && !(next.tok in [.comma, .rpar]) { + if tok.tok != .lpar && !(next.tok in [.comma, .rpar]) { // No space after (), [], etc g.fns.write(' ') } @@ -121,22 +117,22 @@ fn (g mut VhGen) generate_fn() { tok = g.tokens[g.i] } g.fns.writeln('') - //g.i-- + // g.i-- } fn (g mut VhGen) generate_alias() { mut tok := g.tokens[g.i] - for g.i < g.tokens.len-1 { + for g.i < g.tokens.len - 1 { g.types.write(tok.str()) g.types.write(' ') - if tok.line_nr != g.tokens[g.i+1].line_nr { + if tok.line_nr != g.tokens[g.i + 1].line_nr { break } g.i++ tok = g.tokens[g.i] } g.types.writeln('\n') - //g.i-- + // g.i-- } fn (g mut VhGen) generate_const() { @@ -144,29 +140,30 @@ fn (g mut VhGen) generate_const() { for g.i < g.tokens.len && tok.tok != .rpar { g.consts.write(tok.str()) g.consts.write(' ') - if g.tokens[g.i+2].tok == .assign { + if g.tokens[g.i + 2].tok == .assign { g.consts.write('\n\t') } g.i++ tok = g.tokens[g.i] } g.consts.writeln('\n)') - //g.i-- + // g.i-- } fn (g mut VhGen) generate_type() { - //old := g.i + // old := g.i mut tok := g.tokens[g.i] for g.i < g.tokens.len && tok.tok != .rcbr { g.types.write(tok.str()) g.types.write(' ') - if g.tokens[g.i+1].line_nr != g.tokens[g.i].line_nr { + if g.tokens[g.i + 1].line_nr != g.tokens[g.i].line_nr { g.types.write('\n\t') } g.i++ tok = g.tokens[g.i] } g.types.writeln('\n}') - //g.i = old - //g.i-- + // g.i = old + // g.i-- } + diff --git a/vlib/compiler/modules.v b/vlib/compiler/modules.v index 4d5d25336e..518c6554c0 100644 --- a/vlib/compiler/modules.v +++ b/vlib/compiler/modules.v @@ -1,7 +1,6 @@ // 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 compiler import os @@ -10,15 +9,13 @@ import filepath pub const ( v_modules_path = os.home_dir() + '.vmodules' ) - // Holds import information scoped to the parsed file struct ImportTable { mut: imports map[string]string // alias => module - used_imports []string // alias - import_tok_idx map[string]int // module => idx + used_imports []string // alias + import_tok_idx map[string]int // module => idx } - // Once we have a module format we can read from module file instead // this is not optimal fn (table &Table) qualify_module(mod string, file_path string) string { @@ -26,7 +23,7 @@ fn (table &Table) qualify_module(mod string, file_path string) string { if m.contains('.') && m.contains(mod) { m_parts := m.split('.') m_path := m_parts.join(os.path_separator) - if mod == m_parts[m_parts.len-1] && file_path.contains(m_path) { + if mod == m_parts[m_parts.len - 1] && file_path.contains(m_path) { return m } } @@ -36,7 +33,7 @@ fn (table &Table) qualify_module(mod string, file_path string) string { fn new_import_table() ImportTable { return ImportTable{ - imports: map[string]string + imports: map[string]string } } @@ -54,7 +51,9 @@ fn (p mut Parser) register_import_alias(alias string, mod string, tok_idx int) { mod_parts := mod.split('.') mut internal_mod_parts := []string for part in mod_parts { - if part == 'internal' { break } + if part == 'internal' { + break + } internal_mod_parts << part } internal_parent := internal_mod_parts.join('.') @@ -121,7 +120,7 @@ pub fn (v &V) resolve_deps() &DepGraph { } // graph of all imported modules -pub fn(v &V) import_graph() &DepGraph { +pub fn (v &V) import_graph() &DepGraph { mut graph := new_dep_graph() for p in v.parsers { mut deps := []string @@ -134,7 +133,7 @@ pub fn(v &V) import_graph() &DepGraph { } // get ordered imports (module speficic dag method) -pub fn(graph &DepGraph) imports() []string { +pub fn (graph &DepGraph) imports() []string { mut mods := []string for node in graph.nodes { mods << node.name @@ -142,7 +141,8 @@ pub fn(graph &DepGraph) imports() []string { return mods } -[inline] fn (v &V) module_path(mod string) string { +[inline] +fn (v &V) module_path(mod string) string { // submodule support return mod.replace('.', os.path_separator) } @@ -150,33 +150,30 @@ pub fn(graph &DepGraph) imports() []string { // 'strings' => 'VROOT/vlib/strings' // 'installed_mod' => '~/.vmodules/installed_mod' // 'local_mod' => '/path/to/current/dir/local_mod' - -fn (v mut V) set_module_lookup_paths(){ - mlookup_path := if v.pref.vpath.len>0{ v.pref.vpath }else{ v_modules_path } +fn (v mut V) set_module_lookup_paths() { + mlookup_path := if v.pref.vpath.len > 0 { v.pref.vpath } else { v_modules_path } // Module search order: // 0) V test files are very commonly located right inside the folder of the // module, which they test. Adding the parent folder of the module folder // with the _test.v files, *guarantees* that the tested module can be found // without needing to set custom options/flags. - // 1) search in the *same* directory, as the compiled final v program source - // (i.e. the . in `v .` or file.v in `v file.v`) + // (i.e. the . in `v .` or file.v in `v file.v`) // 2) search in the modules/ in the same directory. // 3) search in vlib/ // 4.1) search in -vpath (if given) // 4.2) search in ~/.vmodules/ (i.e. modules installed with vpm) (no -vpath) - v.module_lookup_paths = [] + v.module_lookup_paths = [] if v.pref.is_test { v.module_lookup_paths << os.basedir(v.compiled_dir) // pdir of _test.v } v.module_lookup_paths << v.compiled_dir - v.module_lookup_paths << filepath.join(v.compiled_dir, 'modules') + v.module_lookup_paths << filepath.join(v.compiled_dir,'modules') v.module_lookup_paths << v.pref.vlib_path v.module_lookup_paths << mlookup_path if v.pref.user_mod_path.len > 0 { v.module_lookup_paths << v.pref.user_mod_path } - if v.pref.is_verbose { v.log('v.module_lookup_paths: $v.module_lookup_paths') } @@ -185,20 +182,27 @@ fn (v mut V) set_module_lookup_paths(){ fn (v &V) find_module_path(mod string) ?string { mod_path := v.module_path(mod) for lookup_path in v.module_lookup_paths { - try_path := filepath.join(lookup_path, mod_path) - if v.pref.is_verbose { println(' >> trying to find $mod in $try_path ...') } + try_path := filepath.join(lookup_path,mod_path) + if v.pref.is_verbose { + println(' >> trying to find $mod in $try_path ...') + } if os.is_dir(try_path) { - if v.pref.is_verbose { println(' << found $try_path .') } - return try_path + if v.pref.is_verbose { + println(' << found $try_path .') + } + return try_path } } return error('module "$mod" not found') } -[inline] fn mod_gen_name(mod string) string { +[inline] +fn mod_gen_name(mod string) string { return mod.replace('.', '_dot_') } -[inline] fn mod_gen_name_rev(mod string) string { +[inline] +fn mod_gen_name_rev(mod string) string { return mod.replace('_dot_', '.') } + diff --git a/vlib/compiler/msvc.v b/vlib/compiler/msvc.v index b18f0fe4c8..bf20c918df 100644 --- a/vlib/compiler/msvc.v +++ b/vlib/compiler/msvc.v @@ -3,27 +3,22 @@ module compiler import os #flag windows -l shell32 -#flag windows -l dbghelp -// RegOpenKeyExW etc +#flag windows -l dbghelp // RegOpenKeyExW etc #flag windows -l advapi32 - struct MsvcResult { - full_cl_exe_path string - exe_path string - - um_lib_path string - ucrt_lib_path string - vs_lib_path string - - um_include_path string - ucrt_include_path string - vs_include_path string + full_cl_exe_path string + exe_path string + um_lib_path string + ucrt_lib_path string + vs_lib_path string + um_include_path string + ucrt_include_path string + vs_include_path string shared_include_path string } // Mimics a HKEY type RegKey voidptr - // Taken from the windows SDK const ( HKEY_LOCAL_MACHINE = RegKey(0x80000002) @@ -31,39 +26,30 @@ const ( KEY_WOW64_32KEY = (0x0200) KEY_ENUMERATE_SUB_KEYS = (0x0008) ) - // Given a root key look for one of the subkeys in 'versions' and get the path fn find_windows_kit_internal(key RegKey, versions []string) ?string { $if windows { for version in versions { required_bytes := 0 // TODO mut result := C.RegQueryValueEx(key, version.to_wide(), 0, 0, 0, &required_bytes) - length := required_bytes / 2 - if result != 0 { continue } - alloc_length := (required_bytes + 2) - mut value := &u16(malloc(alloc_length)) if isnil(value) { continue } - result2 := C.RegQueryValueEx(key, version.to_wide(), 0, 0, value, &alloc_length) - if result2 != 0 { continue } - // We might need to manually null terminate this thing // So just make sure that we do that if (value[length - 1] != u16(0)) { value[length] = u16(0) } - return string_from_wide(value) } } @@ -71,11 +57,10 @@ fn find_windows_kit_internal(key RegKey, versions []string) ?string { } struct WindowsKit { - um_lib_path string - ucrt_lib_path string - - um_include_path string - ucrt_include_path string + um_lib_path string + ucrt_lib_path string + um_include_path string + ucrt_include_path string shared_include_path string } @@ -83,45 +68,38 @@ struct WindowsKit { fn find_windows_kit_root(host_arch string) ?WindowsKit { $if windows { root_key := RegKey(0) - rc := C.RegOpenKeyEx( - HKEY_LOCAL_MACHINE, 'SOFTWARE\\Microsoft\\Windows Kits\\Installed Roots'.to_wide(), 0, KEY_QUERY_VALUE | KEY_WOW64_32KEY | KEY_ENUMERATE_SUB_KEYS, &root_key) - - defer {C.RegCloseKey(root_key)} - + rc := C.RegOpenKeyEx(HKEY_LOCAL_MACHINE, 'SOFTWARE\\Microsoft\\Windows Kits\\Installed Roots'.to_wide(), 0, KEY_QUERY_VALUE | KEY_WOW64_32KEY | KEY_ENUMERATE_SUB_KEYS, &root_key) + defer { + C.RegCloseKey(root_key) + } if rc != 0 { return error('Unable to open root key') } // Try and find win10 kit - kit_root := find_windows_kit_internal(root_key, ['KitsRoot10', 'KitsRoot81']) or { + kit_root := find_windows_kit_internal(root_key, ['KitsRoot10', 'KitsRoot81'])or{ return error('Unable to find a windows kit') } - kit_lib := kit_root + 'Lib' - // println(kit_lib) - - files := os.ls(kit_lib) or { panic(err) } + files := os.ls(kit_lib)or{ + panic(err) + } mut highest_path := '' mut highest_int := 0 for f in files { no_dot := f.replace('.', '') v_int := no_dot.int() - if v_int > highest_int { highest_int = v_int highest_path = f } } - kit_lib_highest := kit_lib + '\\$highest_path' kit_include_highest := kit_lib_highest.replace('Lib', 'Include') - // println('$kit_lib_highest $kit_include_highest') - - return WindowsKit { + return WindowsKit{ um_lib_path: kit_lib_highest + '\\um\\$host_arch' ucrt_lib_path: kit_lib_highest + '\\ucrt\\$host_arch' - um_include_path: kit_include_highest + '\\um' ucrt_include_path: kit_include_highest + '\\ucrt' shared_include_path: kit_include_highest + '\\shared' @@ -132,8 +110,8 @@ fn find_windows_kit_root(host_arch string) ?WindowsKit { struct VsInstallation { include_path string - lib_path string - exe_path string + lib_path string + exe_path string } fn find_vs(vswhere_dir string, host_arch string) ?VsInstallation { @@ -144,40 +122,27 @@ fn find_vs(vswhere_dir string, host_arch string) ?VsInstallation { // VSWhere is guaranteed to be installed at this location now // If its not there then end user needs to update their visual studio // installation! - - res := os.exec('"$vswhere_dir\\Microsoft Visual Studio\\Installer\\vswhere.exe" -latest -prerelease -products * -requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64 -property installationPath') or { + res := os.exec('"$vswhere_dir\\Microsoft Visual Studio\\Installer\\vswhere.exe" -latest -prerelease -products * -requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64 -property installationPath')or{ return error(err) } // println('res: "$res"') - - version := os.read_file('$res.output\\VC\\Auxiliary\\Build\\Microsoft.VCToolsVersion.default.txt') or { + version := os.read_file('$res.output\\VC\\Auxiliary\\Build\\Microsoft.VCToolsVersion.default.txt')or{ println('Unable to find msvc version') return error('Unable to find vs installation') } - // println('version: $version') - - v := if version.ends_with('\n') { - version[..version.len - 2] - } else { - version - } - + v := if version.ends_with('\n') { version[..version.len - 2] } else { version } lib_path := '$res.output\\VC\\Tools\\MSVC\\$v\\lib\\$host_arch' include_path := '$res.output\\VC\\Tools\\MSVC\\$v\\include' - if os.exists('$lib_path\\vcruntime.lib') { p := '$res.output\\VC\\Tools\\MSVC\\$v\\bin\\Host$host_arch\\$host_arch' - // println('$lib_path $include_path') - return VsInstallation{ exe_path: p lib_path: lib_path include_path: include_path } } - println('Unable to find vs installation (attempted to use lib path "$lib_path")') return error('Unable to find vs exe folder') } @@ -185,45 +150,33 @@ fn find_vs(vswhere_dir string, host_arch string) ?VsInstallation { fn find_msvc() ?MsvcResult { $if windows { processor_architecture := os.getenv('PROCESSOR_ARCHITECTURE') - vswhere_dir := if processor_architecture == 'x86' { - '%ProgramFiles%' - } else { - '%ProgramFiles(x86)%' - } - host_arch := if processor_architecture == 'x86' { - 'X86' - } else { - 'X64' - } - wk := find_windows_kit_root(host_arch) or { + vswhere_dir := if processor_architecture == 'x86' { '%ProgramFiles%' } else { '%ProgramFiles(x86)%' } + host_arch := if processor_architecture == 'x86' { 'X86' } else { 'X64' } + wk := find_windows_kit_root(host_arch)or{ return error('Unable to find windows sdk') } - vs := find_vs(vswhere_dir, host_arch) or { + vs := find_vs(vswhere_dir, host_arch)or{ return error('Unable to find visual studio') } - - return MsvcResult { - full_cl_exe_path: os.realpath( vs.exe_path + os.path_separator + 'cl.exe' ) - exe_path: vs.exe_path, - - um_lib_path: wk.um_lib_path, - ucrt_lib_path: wk.ucrt_lib_path, - vs_lib_path: vs.lib_path, - - um_include_path: wk.um_include_path, - ucrt_include_path: wk.ucrt_include_path, - vs_include_path: vs.include_path, - shared_include_path: wk.shared_include_path, + return MsvcResult{ + full_cl_exe_path: os.realpath(vs.exe_path + os.path_separator + 'cl.exe') + exe_path: vs.exe_path + um_lib_path: wk.um_lib_path + ucrt_lib_path: wk.ucrt_lib_path + vs_lib_path: vs.lib_path + um_include_path: wk.um_include_path + ucrt_include_path: wk.ucrt_include_path + vs_include_path: vs.include_path + shared_include_path: wk.shared_include_path } - } - $else { + } $else { verror('Cannot find msvc on this OS') return error('msvc not found') } } pub fn (v mut V) cc_msvc() { - r := find_msvc() or { + r := find_msvc()or{ // TODO: code reuse if !v.pref.is_keep_c && v.out_name_c != 'v.c' && v.out_name_c != 'v_macos.c' { os.rm(v.out_name_c) @@ -231,41 +184,35 @@ pub fn (v mut V) cc_msvc() { verror('Cannot find MSVC on this OS') return } - - out_name_obj := os.realpath( v.out_name_c + '.obj' ) - + out_name_obj := os.realpath(v.out_name_c + '.obj') // Default arguments - // volatile:ms enables atomic volatile (gcc _Atomic) // -w: no warnings // 2 unicode defines // /Fo sets the object file name - needed so we can clean up after ourselves properly mut a := ['-w', '/we4013', '/volatile:ms', '/Fo"$out_name_obj"'] - if v.pref.is_prod { a << '/O2' a << '/MD' a << '/Zi' a << '/DNDEBUG' - } else { + } + else { a << '/Zi' a << '/MDd' } - if v.pref.is_so { if !v.out_name.ends_with('.dll') { v.out_name = v.out_name + '.dll' } - // Build dll a << '/LD' - } else if !v.out_name.ends_with('.exe') { + } + else if !v.out_name.ends_with('.exe') { v.out_name = v.out_name + '.exe' } - - v.out_name = os.realpath( v.out_name ) - - //alibs := []string // builtin.o os.o http.o etc + v.out_name = os.realpath(v.out_name) + // alibs := []string // builtin.o os.o http.o etc if v.pref.build_mode == .build_module { // Compile only a << '/c' @@ -286,52 +233,30 @@ pub fn (v mut V) cc_msvc() { } */ } - if v.pref.sanitize { println('Sanitize not supported on msvc.') } - // The C file we are compiling - //a << '"$TmpPath/$v.out_name_c"' - a << '"' + os.realpath( v.out_name_c ) + '"' - + // a << '"$TmpPath/$v.out_name_c"' + a << '"' + os.realpath(v.out_name_c) + '"' // Emily: // Not all of these are needed (but the compiler should discard them if they are not used) // these are the defaults used by msbuild and visual studio - mut real_libs := [ - 'kernel32.lib', - 'user32.lib', - 'gdi32.lib', - 'winspool.lib', - 'comdlg32.lib', - 'advapi32.lib', - 'shell32.lib', - 'ole32.lib', - 'oleaut32.lib', - 'uuid.lib', - 'odbc32.lib', - 'odbccp32.lib' - ] - + mut real_libs := ['kernel32.lib', 'user32.lib', 'gdi32.lib', 'winspool.lib', 'comdlg32.lib', 'advapi32.lib', 'shell32.lib', 'ole32.lib', 'oleaut32.lib', 'uuid.lib', 'odbc32.lib', 'odbccp32.lib'] sflags := v.get_os_cflags().msvc_string_flags() - real_libs << sflags.real_libs - inc_paths := sflags.inc_paths - lib_paths := sflags.lib_paths + real_libs << sflags.real_libs + inc_paths := sflags.inc_paths + lib_paths := sflags.lib_paths other_flags := sflags.other_flags - // Include the base paths a << '-I "$r.ucrt_include_path"' a << '-I "$r.vs_include_path"' a << '-I "$r.um_include_path"' a << '-I "$r.shared_include_path"' - a << inc_paths - a << other_flags - // Libs are passed to cl.exe which passes them to the linker a << real_libs.join(' ') - a << '/link' a << '/NOLOGO' a << '/OUT:"$v.out_name"' @@ -339,17 +264,13 @@ pub fn (v mut V) cc_msvc() { a << '/LIBPATH:"$r.um_lib_path"' a << '/LIBPATH:"$r.vs_lib_path"' a << '/DEBUG:FULL' // required for prod builds to generate PDB - if v.pref.is_prod { a << '/INCREMENTAL:NO' // Disable incremental linking a << '/OPT:REF' a << '/OPT:ICF' } - a << lib_paths - args := a.join(' ') - cmd := '"$r.full_cl_exe_path" $args' // It is hard to see it at first, but the quotes above ARE balanced :-| ... // Also the double quotes at the start ARE needed. @@ -358,10 +279,8 @@ pub fn (v mut V) cc_msvc() { println(cmd) println('==========\n') } - // println('$cmd') - - res := os.exec(cmd) or { + res := os.exec(cmd)or{ println(err) verror('msvc error') return @@ -371,51 +290,44 @@ pub fn (v mut V) cc_msvc() { } // println(res) // println('C OUTPUT:') - if !v.pref.is_keep_c && v.out_name_c != 'v.c' && v.out_name_c != 'v_macos.c' { os.rm(v.out_name_c) } - // Always remove the object file - it is completely unnecessary os.rm(out_name_obj) } + fn build_thirdparty_obj_file_with_msvc(path string, moduleflags []CFlag) { - msvc := find_msvc() or { + msvc := find_msvc()or{ println('Could not find visual studio') return } - // msvc expects .obj not .o mut obj_path := '${path}bj' - obj_path = os.realpath(obj_path) - if os.exists(obj_path) { println('$obj_path already build.') return } - println('$obj_path not found, building it (with msvc)...') parent := os.dir(obj_path) - files := os.ls(parent) or { panic(err) } - + files := os.ls(parent)or{ + panic(err) + } mut cfiles := '' for file in files { if file.ends_with('.c') { - cfiles += '"' + os.realpath( parent + os.path_separator + file ) + '" ' + cfiles += '"' + os.realpath(parent + os.path_separator + file) + '" ' } } - include_string := '-I "$msvc.ucrt_include_path" -I "$msvc.vs_include_path" -I "$msvc.um_include_path" -I "$msvc.shared_include_path"' - - //println('cfiles: $cfiles') - + // println('cfiles: $cfiles') btarget := moduleflags.c_options_before_target_msvc() atarget := moduleflags.c_options_after_target_msvc() cmd := '"$msvc.full_cl_exe_path" /volatile:ms /Zi /DNDEBUG $include_string /c $btarget $cfiles $atarget /Fo"$obj_path"' - //NB: the quotes above ARE balanced. + // NB: the quotes above ARE balanced. println('thirdparty cmd line: $cmd') - res := os.exec(cmd) or { + res := os.exec(cmd)or{ println('msvc: failed thirdparty object build cmd: $cmd') verror(err) return @@ -428,12 +340,11 @@ fn build_thirdparty_obj_file_with_msvc(path string, moduleflags []CFlag) { println(res.output) } - struct MsvcStringFlags { mut: - real_libs []string - inc_paths []string - lib_paths []string + real_libs []string + inc_paths []string + lib_paths []string other_flags []string } @@ -441,9 +352,9 @@ fn (cflags []CFlag) msvc_string_flags() MsvcStringFlags { mut real_libs := []string mut inc_paths := []string mut lib_paths := []string - mut other_flags := []string + mut other_flags := []string for flag in cflags { - //println('fl: $flag.name | flag arg: $flag.value') + // println('fl: $flag.name | flag arg: $flag.value') // We need to see if the flag contains -l // -l isnt recognised and these libs will be passed straight to the linker // by the compiler @@ -476,11 +387,11 @@ fn (cflags []CFlag) msvc_string_flags() MsvcStringFlags { other_flags << flag.value } } - mut lpaths := []string for l in lib_paths { lpaths << '/LIBPATH:"' + os.realpath(l) + '"' } - - return MsvcStringFlags{ real_libs, inc_paths, lpaths, other_flags } + return MsvcStringFlags{ + real_libs,inc_paths,lpaths,other_flags} } + diff --git a/vlib/compiler/optimization.v b/vlib/compiler/optimization.v index 8352cf7445..2c144c9790 100644 --- a/vlib/compiler/optimization.v +++ b/vlib/compiler/optimization.v @@ -1,5 +1,4 @@ module compiler - // `a in [1,2,3]` => `a == 1 || a == 2 || a == 3` // avoid allocation // `typ` is the type of `a` @@ -13,12 +12,13 @@ fn (p mut Parser) in_optimization(typ string, ph int) { // Get `a` expr value (can be a string literal, not a variable) expr := p.cgen.cur_line[ph..] is_str := typ == 'string' - //println('!! $p.expr_var.name => $name ($typ)') + // println('!! $p.expr_var.name => $name ($typ)') for p.tok != .rsbr && p.tok != .eof { if i > 0 { if is_str { p.gen(' || string_eq($expr, ') - } else { + } + else { p.gen(' || $expr == ') } } @@ -26,7 +26,8 @@ fn (p mut Parser) in_optimization(typ string, ph int) { if is_str { p.cgen.set_placeholder(ph, ' (string_eq(') p.gen(', ') - } else { + } + else { p.cgen.set_placeholder(ph, ' (') p.gen(' ==') } @@ -44,3 +45,4 @@ fn (p mut Parser) in_optimization(typ string, ph int) { p.gen(')') p.check(.rsbr) } + diff --git a/vlib/compiler/parser.v b/vlib/compiler/parser.v index 7eb692d3f3..f0b5648c3a 100644 --- a/vlib/compiler/parser.v +++ b/vlib/compiler/parser.v @@ -3,8 +3,6 @@ // that can be found in the LICENSE file. module compiler - - import ( os strings @@ -474,7 +472,7 @@ fn (p mut Parser) parse(pass Pass) { .key_const { p.const_decl() } - .key_struct,.key_union,.key_interface { + .key_struct, .key_union, .key_interface { p.struct_decl() } .key_enum { @@ -498,7 +496,7 @@ fn (p mut Parser) parse(pass Pass) { // or a struct definition p.attribute() } - .key_struct,.key_interface,.key_union,.lsbr { + .key_struct, .key_interface, .key_union, .lsbr { p.struct_decl() } .key_const { @@ -982,7 +980,7 @@ fn (p mut Parser) get_type() string { // Register anon fn type fn_typ := Type{ name: f.typ_str() // 'fn (int, int) string' - + mod: p.mod func: f } @@ -1364,7 +1362,7 @@ fn (p mut Parser) statement(add_semi bool) string { .key_match { p.match_statement(false) } - .key_mut,.key_static { + .key_mut, .key_static { p.var_decl() } .key_return { diff --git a/vlib/compiler/query.v b/vlib/compiler/query.v index 99d5cdd916..27c0081652 100644 --- a/vlib/compiler/query.v +++ b/vlib/compiler/query.v @@ -1,7 +1,6 @@ // 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 compiler import strings @@ -10,37 +9,41 @@ fn sql_params2params_gen(sql_params []string, sql_types []string, qprefix string mut params_gen := '' for i, mparam in sql_params { param := mparam.trim_space() - paramtype := sql_types[ i ] + paramtype := sql_types[i] if param[0].is_digit() { params_gen += '${qprefix}params[$i] = int_str($param).str;\n' - }else if param[0] == `\'` { - sparam := param.trim('\'') + } + else if param[0] == `\'` { + sparam := param.trim("\'") params_gen += '${qprefix}params[$i] = "$sparam";\n' - } else { + } + else { // A variable like q.nr_orders if paramtype == 'int' { params_gen += '${qprefix}params[$i] = int_str( $param ).str;\n' - }else if paramtype == 'string' { + } + else if paramtype == 'string' { params_gen += '${qprefix}params[$i] = ${param}.str;\n' - }else{ + } + else { verror('orm: only int and string variable types are supported in queries') } } } - //println('>>>>>>>> params_gen') - //println( params_gen ) + // println('>>>>>>>> params_gen') + // println( params_gen ) return params_gen } - // `db.select from User where id == 1 && nr_bookings > 0` fn (p mut Parser) select_query(fn_ph int) string { // NB: qprefix and { p.sql_i, p.sql_params, p.sql_types } SHOULD be reset for each query, // because we can have many queries in the _same_ scope. - qprefix := p.get_tmp().replace('tmp','sql') + '_' + qprefix := p.get_tmp().replace('tmp', 'sql') + '_' p.sql_i = 0 p.sql_params = [] - if false {} + if false { + } p.sql_types = [] mut q := 'select ' p.check(.key_select) @@ -56,7 +59,7 @@ fn (p mut Parser) select_query(fn_ph int) string { if typ.name == '' { p.error('unknown type `$table_name`') } - //fields := typ.fields.filter(typ == 'string' || typ == 'int') + // fields := typ.fields.filter(typ == 'string' || typ == 'int') // get only string and int fields mut fields := []Var for i, field in typ.fields { @@ -86,20 +89,24 @@ fn (p mut Parser) select_query(fn_ph int) string { q += ' from ' } for field in fields { - //println('registering sql field var $field.name') + // println('registering sql field var $field.name') if !(field.typ in ['string', 'int', 'bool']) { println('orm: skipping $field.name') continue } - - p.register_var({ field | is_mut: true, is_used:true, is_changed:true }) + p.register_var({ + field | + is_mut:true, + is_used:true, + is_changed:true + }) } q += table_name + 's' // `where` statement if p.tok == .name && p.lit == 'where' { p.next() p.is_sql = true - _, expr := p.tmp_expr() + _,expr := p.tmp_expr() p.is_sql = false q += ' where ' + expr } @@ -108,7 +115,7 @@ fn (p mut Parser) select_query(fn_ph int) string { if p.tok == .name && p.lit == 'limit' { p.next() p.is_sql = true - _, limit := p.tmp_expr() + _,limit := p.tmp_expr() p.is_sql = false q += ' limit ' + limit // `limit 1` means we are getting `?User`, not `[]User` @@ -118,11 +125,11 @@ fn (p mut Parser) select_query(fn_ph int) string { } println('sql query="$q"') p.cgen.insert_before('// DEBUG_SQL prefix: $qprefix | fn_ph: $fn_ph | query: "$q" ') - if n == 'count' { p.cgen.set_placeholder(fn_ph, 'pg__DB_q_int(') p.gen(', tos2("$q"))') - } else { + } + else { // Build an object, assign each field. tmp := p.get_tmp() mut obj_gen := strings.new_builder(300) @@ -134,12 +141,11 @@ fn (p mut Parser) select_query(fn_ph int) string { else if field.typ == 'bool' { cast = 'string_bool' } - obj_gen.writeln('${qprefix}${tmp}.$field.name = ' + - '${cast}(*(string*)array_get(${qprefix}row.vals, $i));') + obj_gen.writeln('${qprefix}${tmp}.$field.name = ' + '${cast}(*(string*)array_get(${qprefix}row.vals, $i));') } // One object if query_one { - mut params_gen := sql_params2params_gen( p.sql_params, p.sql_types, qprefix ) + mut params_gen := sql_params2params_gen(p.sql_params, p.sql_types, qprefix) p.cgen.insert_before(' char* ${qprefix}params[$p.sql_i]; @@ -164,7 +170,7 @@ ${obj_gen.str()} // Array else { q += ' order by id' - params_gen := sql_params2params_gen( p.sql_params, p.sql_types, qprefix ) + params_gen := sql_params2params_gen(p.sql_params, p.sql_types, qprefix) p.cgen.insert_before('char* ${qprefix}params[$p.sql_i]; $params_gen @@ -181,17 +187,18 @@ for (int i = 0; i < ${qprefix}rows.len; i++) { } ') p.cgen.resetln('${qprefix}arr_$tmp') -} - + } } if n == 'count' { return 'int' - } else if query_one { + } + else if query_one { opt_type := 'Option_$table_name' p.cgen.typedefs << 'typedef Option $opt_type;' - p.table.register_builtin( opt_type ) + p.table.register_builtin(opt_type) return opt_type - } else { + } + else { p.register_array('array_$table_name') return 'array_$table_name' } @@ -203,7 +210,9 @@ fn (p mut Parser) insert_query(fn_ph int) { p.check(.lpar) var_name := p.check_name() p.check(.rpar) - var := p.find_var(var_name) or { return } + var := p.find_var(var_name) or { + return + } typ := p.table.find_type(var.typ) mut fields := []Var for i, field in typ.fields { @@ -219,9 +228,9 @@ fn (p mut Parser) insert_query(fn_ph int) { p.error('V orm: `id int` must be the first field in `$var.typ`') } table_name := var.typ - mut sfields := '' // 'name, city, country' + mut sfields := '' // 'name, city, country' mut params := '' // params[0] = 'bob'; params[1] = 'Vienna'; - mut vals := '' // $1, $2, $3... + mut vals := '' // $1, $2, $3... mut nr_vals := 0 for i, field in fields { if field.name == 'id' { @@ -233,9 +242,11 @@ fn (p mut Parser) insert_query(fn_ph int) { params += 'params[${i-1}] = ' if field.typ == 'string' { params += '$var_name . $field.name .str;\n' - } else if field.typ == 'int' { + } + else if field.typ == 'int' { params += 'int_str($var_name . $field.name).str;\n' - } else { + } + else { p.error('V ORM: unsupported type `$field.typ`') } if i < fields.len - 1 { @@ -275,11 +286,16 @@ fn (p mut Parser) update_query(fn_ph int) { println('orm: skipping $f.name') continue } - p.register_var({ f | is_mut: true, is_used:true, is_changed:true }) + p.register_var({ + f | + is_mut:true, + is_used:true, + is_changed:true + }) } mut q := 'update ${typ.name}s set $field=' p.is_sql = true - set_typ, expr := p.tmp_expr() + set_typ,expr := p.tmp_expr() p.is_sql = false // TODO this hack should not be necessary if set_typ == 'bool' { @@ -289,21 +305,20 @@ fn (p mut Parser) update_query(fn_ph int) { else { q += 'false' } - } else { + } + else { q += expr } // where if p.tok == .name && p.lit == 'where' { p.next() p.is_sql = true - _, wexpr := p.tmp_expr() + _,wexpr := p.tmp_expr() p.is_sql = false q += ' where ' + wexpr } - - nr_vals := 0 - p.cgen.insert_before('char* params[$nr_vals];')// + params) + p.cgen.insert_before('char* params[$nr_vals];') // + params) p.cgen.set_placeholder(fn_ph, 'PQexecParams( ') println('update q="$q"') p.genln('.conn, "$q", $nr_vals, 0, params, 0, 0, 0)') diff --git a/vlib/compiler/scanner.v b/vlib/compiler/scanner.v index 84a2a31b80..d45036a26a 100644 --- a/vlib/compiler/scanner.v +++ b/vlib/compiler/scanner.v @@ -87,7 +87,7 @@ struct ScanRes { lit string } -fn scan_res(tok TokenKind,lit string) ScanRes { +fn scan_res(tok TokenKind, lit string) ScanRes { return ScanRes{ tok,lit} } @@ -271,7 +271,7 @@ fn (s mut Scanner) scan() ScanRes { name := s.ident_name() // tmp hack to detect . in ${} // Check if not .eof to prevent panic - next_char := if s.pos + 1 < s.text.len {s.text[s.pos + 1]}else {`\0`} + next_char := if s.pos + 1 < s.text.len { s.text[s.pos + 1] } else { `\0` } if is_key(name) { return scan_res(key_to_token(name), '') } @@ -306,7 +306,7 @@ fn (s mut Scanner) scan() ScanRes { if c == `)` && s.inter_start { s.inter_end = true s.inter_start = false - next_char := if s.pos + 1 < s.text.len {s.text[s.pos + 1]}else {`\0`} + next_char := if s.pos + 1 < s.text.len { s.text[s.pos + 1] } else { `\0` } if next_char == s.quote { s.inside_string = false } @@ -360,7 +360,7 @@ fn (s mut Scanner) scan() ScanRes { `?` { return scan_res(.question, '') } - single_quote,double_quote { + single_quote, double_quote { return scan_res(.str, s.ident_string()) } `\`` { @@ -659,7 +659,7 @@ fn (s &Scanner) current_column() int { return s.pos - s.last_nl_pos } -fn (s Scanner) count_symbol_before(p int,sym byte) int { +fn (s Scanner) count_symbol_before(p int, sym byte) int { mut count := 0 for i := p; i >= 0; i-- { if s.text[i] != sym { @@ -775,10 +775,10 @@ fn (s mut Scanner) ident_char() string { return '`' } // Escapes a `'` character - return if c == "\'" {'\\' + c}else {c} + return if c == "\'" { '\\' + c } else { c } } -fn (s &Scanner) expect(want string,start_pos int) bool { +fn (s &Scanner) expect(want string, start_pos int) bool { end_pos := start_pos + want.len if start_pos < 0 || start_pos >= s.text.len { return false @@ -841,7 +841,7 @@ fn (s mut Scanner) inc_line_number() { fn (s Scanner) line(n int) string { mut res := '' if n >= 0 && n < s.line_ends.len { - nline_start := if n == 0 {0}else {s.line_ends[n - 1]} + nline_start := if n == 0 { 0 } else { s.line_ends[n - 1] } nline_end := s.line_ends[n] if nline_start <= nline_end { res = s.text[nline_start..nline_end] @@ -889,3 +889,4 @@ fn (s &Scanner) validate_var_name(name string) { s.error('bad variable name `$name`\n' + 'looks like you have a multi-word name without separating them with `_`' + '\nfor example, use `registration_date` instead of `registrationdate` ') } } + diff --git a/vlib/compiler/string_expression.v b/vlib/compiler/string_expression.v index 369204e201..b11f8a1cb8 100644 --- a/vlib/compiler/string_expression.v +++ b/vlib/compiler/string_expression.v @@ -12,7 +12,7 @@ fn (p mut Parser) string_expr() { str := p.lit // No ${}, just return a simple string if p.peek() != .str_dollar || is_raw { - f := if is_raw {cescaped_path(str)}else {format_str(str)} + f := if is_raw { cescaped_path(str) } else { format_str(str) } // `C.puts('hi')` => `puts("hi");` /* Calling a C function sometimes requires a call to a string method @@ -152,3 +152,4 @@ fn (p mut Parser) string_expr() { p.gen('_STR($format$args)') } } + diff --git a/vlib/compiler/struct.v b/vlib/compiler/struct.v index 54584ccf70..dc229edb7e 100644 --- a/vlib/compiler/struct.v +++ b/vlib/compiler/struct.v @@ -1,14 +1,14 @@ // 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 compiler import ( strings ) - // also unions and interfaces + + fn (p mut Parser) struct_decl() { is_pub := p.tok == .key_pub if is_pub { @@ -67,18 +67,18 @@ fn (p mut Parser) struct_decl() { } mut typ := p.table.find_type(name) if p.pass == .decl && p.table.known_type_fast(typ) { - //if name in reserved_type_param_names { - //p.error('name `$name` is reserved for type parameters') - //} else { + // if name in reserved_type_param_names { + // p.error('name `$name` is reserved for type parameters') + // } else { p.error('type `$name` redeclared') - //} + // } } if is_objc { // Forward declaration of an Objective-C interface with `@class` :) p.gen_typedef('@class $name;') } else if !is_c { - kind := if is_union {'union'} else {'struct'} + kind := if is_union { 'union' } else { 'struct' } p.gen_typedef('typedef $kind $name $name;') } // Register the type @@ -96,7 +96,7 @@ fn (p mut Parser) struct_decl() { p.table.rewrite_type(typ) } else { - typ = Type { + typ = Type{ name: name mod: p.mod is_c: is_c @@ -114,14 +114,14 @@ fn (p mut Parser) struct_decl() { p.check(.lcbr) // Struct fields mut access_mod := AccessMod.private - //mut is_pub_field := false - //mut is_mut := false - mut names := []string// to avoid dup names TODO alloc perf + // mut is_pub_field := false + // mut is_mut := false + mut names := []string // to avoid dup names TODO alloc perf mut fmt_max_len := p.table.max_field_len[name] - //println('fmt max len = $max_len nrfields=$typ.fields.len pass=$p.pass') + // println('fmt max len = $max_len nrfields=$typ.fields.len pass=$p.pass') if !is_ph && p.first_pass() { p.table.register_type(typ) - //println('registering 1 nrfields=$typ.fields.len') + // println('registering 1 nrfields=$typ.fields.len') } mut did_gen_something := false mut used := []AccessMod @@ -136,7 +136,8 @@ fn (p mut Parser) struct_decl() { p.fspace() new_access_mod = .public_mut p.next() // skip `mut` - } else { + } + else { new_access_mod = .public } if new_access_mod in used { @@ -203,7 +204,7 @@ fn (p mut Parser) struct_decl() { continue } // `pub` access mod - //access_mod := if is_pub_field { AccessMod.public } else { AccessMod.private} + // access_mod := if is_pub_field { AccessMod.public } else { AccessMod.private} p.fspace() tt := p.get_type2() field_type := tt.name @@ -222,11 +223,11 @@ fn (p mut Parser) struct_decl() { // `a int = 4` if p.tok == .assign { p.next() - def_val_type, expr := p.tmp_expr() + def_val_type,expr := p.tmp_expr() if def_val_type != field_type { p.error('expected `$field_type` but got `$def_val_type`') } - //println('pass=$p.pass $typ.name ADDING field=$field_name "$def_val_type" "$expr"') + // println('pass=$p.pass $typ.name ADDING field=$field_name "$def_val_type" "$expr"') if !p.first_pass() { p.table.add_default_val(i, typ.name, expr) } @@ -241,12 +242,15 @@ fn (p mut Parser) struct_decl() { p.check(.colon) mut val := '' match p.tok { - .name { val = p.check_name() } - .str { val = p.check_string() } + .name { + val = p.check_name() + } + .str { + val = p.check_string() + } else { p.error('attribute value should be either name or string') - } - } + }} attr += ':' + val } p.check(.rsbr) @@ -257,24 +261,22 @@ fn (p mut Parser) struct_decl() { did_gen_something = true is_mut := access_mod in [.private_mut, .public_mut, .global] if p.first_pass() { - p.table.add_field(typ.name, field_name, field_type, is_mut, - attr, access_mod) + p.table.add_field(typ.name, field_name, field_type, is_mut, attr, access_mod) } p.fgen_nl() // newline between struct fields } if p.scanner.is_fmt && p.pass == .decl { p.table.max_field_len[typ.name] = fmt_max_len } - //p.fgen_require_nl() + // p.fgen_require_nl() p.check(.rcbr) if !is_c && !did_gen_something && p.first_pass() { p.table.add_field(typ.name, '', 'EMPTY_STRUCT_DECLARATION', false, '', .private) } p.fgen_nl() p.fgen_nl() - //p.fgenln('//kek') + // p.fgenln('//kek') } - // `User{ foo: bar }` fn (p mut Parser) struct_init(typ string) string { p.is_struct_init = true @@ -282,7 +284,9 @@ fn (p mut Parser) struct_init(typ string) string { if !t.is_public && t.mod != p.mod { p.warn('type `$t.name` is private') } - if p.gen_struct_init(typ, t) { return typ } + if p.gen_struct_init(typ, t) { + return typ + } ptr := typ.contains('*') mut did_gen_something := false // Loop thru all struct init keys and assign values @@ -292,7 +296,7 @@ fn (p mut Parser) struct_init(typ string) string { peek := p.peek() if peek == .colon || p.tok == .rcbr { for p.tok != .rcbr { - field := if typ != 'Option' { p.table.var_cgen_name( p.check_name() ) } else { p.check_name() } + field := if typ != 'Option' { p.table.var_cgen_name(p.check_name()) } else { p.check_name() } if !p.first_pass() && !t.has_field(field) { p.error('`$t.name` has no field `$field`') } @@ -312,7 +316,7 @@ fn (p mut Parser) struct_init(typ string) string { p.check(.colon) p.fspace() p.expected_type = f.typ - p.check_types(p.bool_expression(), f.typ) + p.check_types(p.bool_expression(), f.typ) if p.tok == .comma { p.next() p.fremove_last() @@ -330,18 +334,15 @@ fn (p mut Parser) struct_init(typ string) string { } // Zero values: init all fields (ints to 0, strings to '' etc) for i, field in t.fields { - sanitized_name := if typ != 'Option' { - p.table.var_cgen_name( field.name ) - } else { - field.name - } + sanitized_name := if typ != 'Option' { p.table.var_cgen_name(field.name) } else { field.name } // println('### field.name') // Skip if this field has already been assigned to if sanitized_name in inited_fields { continue } field_typ := field.typ - if !p.builtin_mod && field_typ.ends_with('*') && p.mod != 'os' { //&& + if !p.builtin_mod && field_typ.ends_with('*') && p.mod != 'os' { + // && p.warn('reference field `${typ}.${field.name}` must be initialized') } // init map fields @@ -357,11 +358,7 @@ fn (p mut Parser) struct_init(typ string) string { } // Did the user provide a default value for this struct field? // Use it. Otherwise zero it. - def_val := if t.default_vals.len > i && t.default_vals[i] != '' { - t.default_vals[i] - } else { - type_default(field_typ) - } + def_val := if t.default_vals.len > i && t.default_vals[i] != '' { t.default_vals[i] } else { type_default(field_typ) } if def_val != '' && def_val != '{0}' { p.gen_struct_field_init(sanitized_name) p.gen(def_val) @@ -419,4 +416,3 @@ fn (p mut Parser) struct_init(typ string) string { return typ } - diff --git a/vlib/compiler/table.v b/vlib/compiler/table.v index 3b51032cee..c0ac6d99c1 100644 --- a/vlib/compiler/table.v +++ b/vlib/compiler/table.v @@ -875,13 +875,13 @@ fn (p mut Parser) typ_to_fmt(typ string, level int) string { 'ustring' { return '%.*s' } - 'byte','bool','int','char','byte','i16','i8' { + 'byte', 'bool', 'int', 'char', 'byte', 'i16', 'i8' { return '%d' } - 'u16','u32' { + 'u16', 'u32' { return '%u' } - 'f64','f32' { + 'f64', 'f32' { return '%f' } 'i64' { @@ -890,7 +890,7 @@ fn (p mut Parser) typ_to_fmt(typ string, level int) string { 'u64' { return '%llu' } - 'byte*','byteptr' { + 'byte*', 'byteptr' { return '%s' } // case 'array_string': return '%s' diff --git a/vlib/compiler/token.v b/vlib/compiler/token.v index d8bfb4500e..4487b877a6 100644 --- a/vlib/compiler/token.v +++ b/vlib/compiler/token.v @@ -1,25 +1,23 @@ // 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 compiler struct Token { - tok TokenKind // the token number/enum; for quick comparisons + 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 pos int // the position of the token in scanner text } - enum TokenKind { eof - name // user - number // 123 - str // 'foo' - str_inter // 'name=$user.name' - chartoken // `A` + name // user + number // 123 + str // 'foo' + str_inter // 'name=$user.name' + chartoken // `A` plus minus mul @@ -44,7 +42,7 @@ enum TokenKind { str_dollar left_shift righ_shift - //at // @ + // at // @ assign // = decl_assign // := plus_assign // += @@ -102,7 +100,7 @@ enum TokenKind { key_import_const key_in key_interface - //key_it + // key_it key_match key_module key_mut @@ -114,7 +112,7 @@ enum TokenKind { key_switch key_true key_type - //typeof + // typeof key_orelse key_union key_pub @@ -125,6 +123,8 @@ enum TokenKind { // build_keys genereates a map with keywords' string values: // Keywords['return'] == .key_return + + fn build_keys() map[string]int { mut res := map[string]int for t := int(TokenKind.keyword_beg) + 1; t < int(TokenKind.keyword_end); t++ { @@ -163,7 +163,7 @@ fn build_token_str() []string { s[TokenKind.dotdot] = '..' s[TokenKind.ellipsis] = '...' s[TokenKind.comma] = ',' - //s[TokenKind.at] = '@' + // s[TokenKind.at] = '@' s[TokenKind.semicolon] = ';' s[TokenKind.colon] = ':' s[TokenKind.arrow] = '=>' @@ -202,7 +202,7 @@ fn build_token_str() []string { s[TokenKind.key_assert] = 'assert' s[TokenKind.key_struct] = 'struct' s[TokenKind.key_if] = 'if' - //s[TokenKind.key_it] = 'it' + // s[TokenKind.key_it] = 'it' s[TokenKind.key_else] = 'else' s[TokenKind.key_asm] = 'asm' s[TokenKind.key_return] = 'return' @@ -223,7 +223,7 @@ fn build_token_str() []string { s[TokenKind.key_import] = 'import' s[TokenKind.key_embed] = 'embed' s[TokenKind.key_unsafe] = 'unsafe' - //Tokens[key_typeof] = 'typeof' + // Tokens[key_typeof] = 'typeof' s[TokenKind.key_enum] = 'enum' s[TokenKind.key_interface] = 'interface' s[TokenKind.key_pub] = 'pub' @@ -262,19 +262,11 @@ pub fn (t TokenKind) str() string { } fn (t TokenKind) is_decl() bool { - return t in [.key_enum, .key_interface, .key_fn, - .key_struct ,.key_type, .key_const, .key_import_const, .key_pub, .eof] + return t in [.key_enum, .key_interface, .key_fn, .key_struct, .key_type, .key_const, .key_import_const, .key_pub, .eof] } const ( - AssignTokens = [ - TokenKind.assign, .plus_assign, .minus_assign, - .mult_assign, .div_assign, .xor_assign, - .mod_assign, - .or_assign, .and_assign, .righ_shift_assign, - .left_shift_assign - ] - + AssignTokens = [TokenKind.assign, .plus_assign, .minus_assign, .mult_assign, .div_assign, .xor_assign, .mod_assign, .or_assign, .and_assign, .righ_shift_assign, .left_shift_assign] ) fn (t TokenKind) is_assign() bool { @@ -293,7 +285,6 @@ fn (t []TokenKind) contains(val TokenKind) bool { pub fn (t Token) str() string { if t.tok == .number { return t.lit - } if t.tok == .chartoken { return '`$t.lit`' diff --git a/vlib/compiler/vfmt.v b/vlib/compiler/vfmt.v index cfef098de8..b7a7892257 100644 --- a/vlib/compiler/vfmt.v +++ b/vlib/compiler/vfmt.v @@ -251,7 +251,7 @@ fn (p &Parser) gen_fmt() { return } //files := ['get_type.v'] - if !p.file_path.contains('vlib/builtin') {return} + if p.file_path.contains('vfmt') {return} //if !(p.file_name in files) { return } path := os.tmpdir() + '/' + p.file_name println('generating ${path}') diff --git a/vlib/compiler/vhelp.v b/vlib/compiler/vhelp.v index 9f47d58a3c..1f39ce0faf 100644 --- a/vlib/compiler/vhelp.v +++ b/vlib/compiler/vhelp.v @@ -84,9 +84,8 @@ V package management commands: remove [module] Removes an installed module, or ALL installed modules at once, when no module name is given. ' ) - - /* - To disable automatic formatting: v -nofmt file.v */ + diff --git a/vlib/compiler/vtmp.v b/vlib/compiler/vtmp.v index 48158cb655..57f4c341a4 100644 --- a/vlib/compiler/vtmp.v +++ b/vlib/compiler/vtmp.v @@ -1,7 +1,6 @@ // 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 compiler import os @@ -9,13 +8,16 @@ import filepath pub fn get_vtmp_folder() string { vtmp := filepath.join(os.tmpdir(),'v') - if !os.is_dir( vtmp ) { - os.mkdir(vtmp) or { panic(err) } + if !os.is_dir(vtmp) { + os.mkdir(vtmp)or{ + panic(err) + } } return vtmp } pub fn get_vtmp_filename(base_file_name string, postfix string) string { vtmp := get_vtmp_folder() - return os.realpath( filepath.join(vtmp, os.filename( os.realpath(base_file_name) ) + postfix) ) + return os.realpath(filepath.join(vtmp,os.filename(os.realpath(base_file_name)) + postfix)) } + diff --git a/vlib/compiler/vtools.v b/vlib/compiler/vtools.v index 50777fcb18..2a8be006a8 100644 --- a/vlib/compiler/vtools.v +++ b/vlib/compiler/vtools.v @@ -2,41 +2,43 @@ module compiler import os -pub fn launch_tool(tname string){ +pub fn launch_tool(tname string) { vexe := vexe_path() vroot := os.dir(vexe) mut oargs := os.args oargs[0] = '"$vexe"' // make it more explicit 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" ...') - + // println('Launching: "$tool_command" ...') mut tool_should_be_recompiled := false - if !os.exists( tool_exe ) { + if !os.exists(tool_exe) { // fresh checkout tool_should_be_recompiled = true - }else{ - if os.file_last_mod_unix( tool_exe ) <= os.file_last_mod_unix( vexe ) { + } + 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 tool_should_be_recompiled = true } - if os.file_last_mod_unix( tool_exe ) <= os.file_last_mod_unix( tool_source ) { + if os.file_last_mod_unix(tool_exe) <= os.file_last_mod_unix(tool_source) { // the user changed the source code of the tool tool_should_be_recompiled = true } } - 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) } + // println('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) ) + exit(os.system(tool_command)) } + diff --git a/vlib/compiler/x64/elf.v b/vlib/compiler/x64/elf.v index 3a97ab46fe..ff018cb784 100644 --- a/vlib/compiler/x64/elf.v +++ b/vlib/compiler/x64/elf.v @@ -1,7 +1,6 @@ // 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 x64 import os @@ -14,19 +13,14 @@ const ( ei_class = 4 elfclass64 = 2 elfdata2lsb = 1 - ev_current = 1 elf_osabi = 0 - // ELF file types et_rel = 1 et_exec = 2 et_dyn = 3 - e_machine = 0x3e - shn_xindex = 0xffff - sht_null = 0 ) @@ -34,14 +28,13 @@ const ( segment_start = 0x400000 ) - pub fn (g mut Gen) generate_elf_header() { g.buf << [byte(mag0), mag1, mag2, mag3] g.buf << elfclass64 // file class g.buf << elfdata2lsb // data encoding g.buf << ev_current // file version - g.buf << 1//elf_osabi - g.write64(0)//et_rel) // et_rel for .o + g.buf << 1 // elf_osabi + g.write64(0) // et_rel) // et_rel for .o g.write16(2) // e_type g.write16(e_machine) // g.write32(ev_current) // e_version @@ -70,7 +63,7 @@ pub fn (g mut Gen) generate_elf_header() { // user code starts here at // address: 00070 and a half g.code_start_pos = g.buf.len - g.call(0)// call main function, it's not guaranteed to be the first + g.call(0) // call main function, it's not guaranteed to be the first } pub fn (g mut Gen) generate_elf_footer() { @@ -84,19 +77,21 @@ pub fn (g mut Gen) generate_elf_footer() { g.write64_at(segment_start + g.buf.len, int(g.str_pos[i])) g.write_string(s) g.write8(6) - } + } // Now we know the file size, set it file_size := g.buf.len g.write64_at(file_size, g.file_size_pos) // set file size 64 bit value - g.write64_at(file_size, g.file_size_pos+8) + g.write64_at(file_size, g.file_size_pos + 8) // call main function, it's not guaranteed to be the first // we generated call(0) ("e8 0") // no need to replace "0" with a relative address of the main function // +1 is for "e8" // -5 is for "e8 00 00 00 00" - g.write64_at(int(g.main_fn_addr - g.code_start_pos) - 5, g.code_start_pos+1) + g.write64_at(int(g.main_fn_addr - g.code_start_pos) - 5, g.code_start_pos + 1) // Create the binary - mut f := os.create(g.out_name) or { panic(err) } + mut f := os.create(g.out_name)or{ + panic(err) + } os.chmod(g.out_name, 0775) f.write_bytes(g.buf.data, g.buf.len) f.close() diff --git a/vlib/compiler/x64/elf_obj.v b/vlib/compiler/x64/elf_obj.v index 0491deeedb..832dc8a92f 100644 --- a/vlib/compiler/x64/elf_obj.v +++ b/vlib/compiler/x64/elf_obj.v @@ -1,9 +1,7 @@ // 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 x64 - /* This file is unused right now, since binaries without sections are generated. @@ -11,26 +9,27 @@ are generated. But it will be necessary once we have dynamic linking. */ + enum SectionType { - null = 0 - progbits = 1 - symtab = 2 - strtab = 3 - rela = 4 -} + null + =0progbits + =1symtab + =2strtab + =3rela + =4} struct SectionConfig { - name string - typ SectionType - flags i64 - data voidptr - is_saa bool + name string + typ SectionType + flags i64 + data voidptr + is_saa bool datalen i64 - link int - info int - align i64 + link int + info int + align i64 entsize i64 -} +} fn (g mut Gen) section_header(c SectionConfig) { g.write32(g.sect_header_name_pos) @@ -38,15 +37,14 @@ fn (g mut Gen) section_header(c SectionConfig) { g.write32(int(c.typ)) g.write64(c.flags) g.write64(0) // sh_addr - g.write64(g.offset)// offset - g.offset += c.datalen+1 + g.write64(g.offset) // offset + g.offset += c.datalen + 1 g.write64(c.datalen) g.write32(c.link) g.write32(c.info) g.write64(c.align) g.write64(c.entsize) -} - +} fn genobj() { /* @@ -158,4 +156,4 @@ fn genobj() { }) */ } - + diff --git a/vlib/compiler/x64/gen.v b/vlib/compiler/x64/gen.v index 5e21f54b01..ce531f7dff 100644 --- a/vlib/compiler/x64/gen.v +++ b/vlib/compiler/x64/gen.v @@ -1,22 +1,21 @@ // 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 x64 pub struct Gen { - out_name string + out_name string mut: - buf []byte + buf []byte sect_header_name_pos int - offset i64 - str_pos []i64 - strings []string // TODO use a map and don't duplicate strings - file_size_pos i64 - main_fn_addr i64 - code_start_pos i64 // location of the start of the assembly instructions - fn_addr map[string]i64 - //string_addr map[string]i64 + offset i64 + str_pos []i64 + strings []string // TODO use a map and don't duplicate strings + file_size_pos i64 + main_fn_addr i64 + code_start_pos i64 // location of the start of the assembly instructions + fn_addr map[string]i64 + // string_addr map[string]i64 } enum Register { @@ -39,7 +38,7 @@ enum Size { pub fn new_gen(out_name string) &Gen { return &Gen{ - sect_header_name_pos : 0 + sect_header_name_pos: 0 buf: [] out_name: out_name } @@ -49,7 +48,6 @@ pub fn (g &Gen) pos() i64 { return g.buf.len } - fn (g mut Gen) write8(n int) { // write 1 byte g.buf << byte(n) @@ -58,39 +56,39 @@ fn (g mut Gen) write8(n int) { fn (g mut Gen) write16(n int) { // write 2 bytes g.buf << byte(n) - g.buf << byte(n >> 8) + g.buf << byte(n>>8) } fn (g mut Gen) write32(n int) { // write 4 bytes g.buf << byte(n) - g.buf << byte(n >> 8) - g.buf << byte(n >> 16) - g.buf << byte(n >> 24) + g.buf << byte(n>>8) + g.buf << byte(n>>16) + g.buf << byte(n>>24) } fn (g mut Gen) write64(n i64) { // write 8 bytes g.buf << byte(n) - g.buf << byte(n >> 8) - g.buf << byte(n >> 16) - g.buf << byte(n >> 24) - g.buf << byte(n >> 32) - g.buf << byte(n >> 40) - g.buf << byte(n >> 48) - g.buf << byte(n >> 56) + g.buf << byte(n>>8) + g.buf << byte(n>>16) + g.buf << byte(n>>24) + g.buf << byte(n>>32) + g.buf << byte(n>>40) + g.buf << byte(n>>48) + g.buf << byte(n>>56) } fn (g mut Gen) write64_at(n i64, at i64) { // write 8 bytes g.buf[at] = byte(n) - g.buf[at+1] = byte(n >> 8) - g.buf[at+2] = byte(n >> 16) - g.buf[at+3] = byte(n >> 24) - g.buf[at+4] = byte(n >> 32) - g.buf[at+5] = byte(n >> 40) - g.buf[at+6] = byte(n >> 48) - g.buf[at+7] = byte(n >> 56) + g.buf[at + 1] = byte(n>>8) + g.buf[at + 2] = byte(n>>16) + g.buf[at + 3] = byte(n>>24) + g.buf[at + 4] = byte(n>>32) + g.buf[at + 5] = byte(n>>40) + g.buf[at + 6] = byte(n>>48) + g.buf[at + 7] = byte(n>>56) } fn (g mut Gen) write_string(s string) { @@ -102,48 +100,61 @@ fn (g mut Gen) write_string(s string) { fn (g mut Gen) inc(reg Register) { g.write16(0xff49) match reg { - .r12 { g.write8(0xc4) } - else { panic('unhandled inc $reg') } - } + .r12 { + g.write8(0xc4) + } + else { + panic('unhandled inc $reg') + }} } fn (g mut Gen) cmp(reg Register, size Size, val i64) { g.write8(0x49) // Second byte depends on the size of the value match size { - ._8 { g.write8(0x83) } - ._32 { g.write8(0x81) } - else { panic('unhandled cmp') } - } + ._8 { + g.write8(0x83) + } + ._32 { + g.write8(0x81) + } + else { + panic('unhandled cmp') + }} // Third byte depends on the register being compared to match reg { - .r12 { g.write8(0xfc) } - else { panic('unhandled cmp') } - } + .r12 { + g.write8(0xfc) + } + else { + panic('unhandled cmp') + }} g.write8(int(val)) } -fn abs(a i64) i64 { return if a < 0 { -a } else { a } } +fn abs(a i64) i64 { + return if a < 0 { -a } else { a } +} fn (g mut Gen) jle(addr i64) { // Calculate the relative offset to jump to // (`addr` is absolute address) - offset := 0xff - int(abs(addr - g.buf.len))-1 + offset := 0xff - int(abs(addr - g.buf.len)) - 1 g.write8(0x7e) g.write8(offset) } fn (g mut Gen) jl(addr i64) { - offset := 0xff - int(abs(addr - g.buf.len))-1 + offset := 0xff - int(abs(addr - g.buf.len)) - 1 g.write8(0x7c) g.write8(offset) } fn (g &Gen) abs_to_rel_addr(addr i64) int { - return int(abs(addr - g.buf.len))-1 + return int(abs(addr - g.buf.len)) - 1 } -fn (g mut Gen) jmp (addr i64) { +fn (g mut Gen) jmp(addr i64) { offset := 0xff - g.abs_to_rel_addr(addr) g.write8(0xe9) g.write8(offset) @@ -155,15 +166,15 @@ fn (g mut Gen) mov64(reg Register, val i64) { g.write8(0x48) g.write8(0xbe) } - else { println('unhandled mov $reg') } - } + else { + println('unhandled mov $reg') + }} g.write64(val) } fn (g mut Gen) call(addr int) { - //rel := g.abs_to_rel_addr(addr) - //rel := 0xffffffff - int(abs(addr - g.buf.len))-1 - + // rel := g.abs_to_rel_addr(addr) + // rel := 0xffffffff - int(abs(addr - g.buf.len))-1 println('call addr=$addr rel_addr=$addr pos=$g.buf.len') g.write8(0xe8) g.write32(addr) @@ -198,13 +209,13 @@ pub fn (g mut Gen) save_main_fn_addr() { pub fn (g mut Gen) gen_print(s string) { g.strings << s + '\n' - //g.string_addr[s] = str_pos + // g.string_addr[s] = str_pos g.mov(.eax, 1) g.mov(.edi, 1) str_pos := g.buf.len + 2 g.str_pos << str_pos - g.mov64(.rsi, 0) //segment_start + 0x9f) // str pos // PLACEHOLDER - g.mov(.edx, s.len+1) // len + g.mov64(.rsi, 0) // segment_start + 0x9f) // str pos // PLACEHOLDER + g.mov(.edx, s.len + 1) // len g.syscall() } @@ -217,22 +228,26 @@ pub fn (g mut Gen) gen_exit() { fn (g mut Gen) mov(reg Register, val int) { match reg { - .eax { g.write8(0xb8) } - .edi { g.write8(0xbf) } - .edx { g.write8(0xba) } + .eax { + g.write8(0xb8) + } + .edi { + g.write8(0xbf) + } + .edx { + g.write8(0xba) + } .rsi { g.write8(0x48) g.write8(0xbe) } .r12 { g.write8(0x41) - g.write8(0xbc) // r11 is 0xbb etc + g.write8(0xbc) // r11 is 0xbb etc } else { panic('unhandled mov $reg') - } - - } + }} g.write32(val) } @@ -251,4 +266,3 @@ pub fn (g mut Gen) call_fn(name string) { println('call $name $addr') } - diff --git a/vlib/filepath/filepath.v b/vlib/filepath/filepath.v index 61ed5c79fb..a0c5f10cd7 100644 --- a/vlib/filepath/filepath.v +++ b/vlib/filepath/filepath.v @@ -1,10 +1,11 @@ module filepath -import( +import ( os ) - // return the extension in the file `path` + + pub fn ext(path string) string { pos := path.last_index_byte(`.`) if pos != -1 { @@ -17,16 +18,19 @@ pub fn ext(path string) string { pub fn is_abs(path string) bool { $if windows { return path[0] == `/` || // incase we're in MingGW bash - (path[0].is_letter() && path[1] == `:`) + (path[0].is_letter() && path[1] == `:`) } return path[0] == `/` } -// pass directories as parameters, returns path as string +// pass directories as parameters, returns path as string // TODO use []string.join once ...string becomes "[]string" pub fn join(base string, dirs ...string) string { mut result := []string result << base.trim_right('\\/') - for d in dirs { result << d } - return result.join( os.path_separator ) + for d in dirs { + result << d + } + return result.join(os.path_separator) } + diff --git a/vlib/os/const.v b/vlib/os/const.v index 3e4470c131..df82478df6 100644 --- a/vlib/os/const.v +++ b/vlib/os/const.v @@ -1,10 +1,6 @@ module os // (Must be realized in Syscall) (Must be specified) // File modes. - - - - const ( O_RDONLY = 1 // open the file read-only. O_WRONLY = 2 // open the file write-only. diff --git a/vlib/os/os.v b/vlib/os/os.v index 47b4c846dd..5ae373af80 100644 --- a/vlib/os/os.v +++ b/vlib/os/os.v @@ -1,15 +1,12 @@ // 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 os import filepath -#include -//#include +#include // #include #include - /* struct dirent { d_ino int @@ -26,13 +23,14 @@ struct C.dirent { fn C.readdir(voidptr) C.dirent + pub const ( args = []string MAX_PATH = 4096 ) pub struct File { - cfile voidptr // Using void* instead of FILE* + cfile voidptr // Using void* instead of FILE* mut: opened bool } @@ -43,30 +41,33 @@ struct FileInfo { } struct C.stat { - st_size int - st_mode u32 + st_size int + st_mode u32 st_mtime int } struct C.DIR { - } -//struct C.dirent { - //d_name byteptr - -//} - +// struct C.dirent { +// d_name byteptr +// } struct C.sigaction { mut: - sa_mask int + sa_mask int sa_sigaction int - sa_flags int + sa_flags int } fn C.getline(voidptr, voidptr, voidptr) int + + fn C.ftell(fp voidptr) int + + fn C.getenv(byteptr) &char + + fn C.sigaction(int, voidptr, int) @@ -81,7 +82,7 @@ pub fn (f mut File) read_bytes(size int) []byte { // read_bytes_at reads an amount of bytes at the given position in the file pub fn (f mut File) read_bytes_at(size, pos int) []byte { - mut arr := [`0`].repeat(size) + mut arr := [`0`].repeat(size) C.fseek(f.cfile, pos, C.SEEK_SET) nreadbytes := C.fread(arr.data, 1, size, f.cfile) C.fseek(f.cfile, 0, C.SEEK_SET) @@ -96,8 +97,7 @@ pub fn read_bytes(path string) ?[]byte { C.fseek(fp, 0, C.SEEK_END) fsize := C.ftell(fp) C.rewind(fp) - - mut res := [`0`].repeat(fsize) + mut res := [`0`].repeat(fsize) nr_read_elements := C.fread(res.data, fsize, 1, fp) C.fclose(fp) return res[0..nr_read_elements * fsize] @@ -118,12 +118,13 @@ pub fn read_file(path string) ?string { C.fread(str, fsize, 1, fp) C.fclose(fp) str[fsize] = 0 - return string(str, fsize) + return string(str,fsize) } // file_size returns the size of the file located in `path`. pub fn file_size(path string) int { - mut s := C.stat{} + mut s := C.stat{ + } $if windows { C._wstat(path.to_wide(), voidptr(&s)) } $else { @@ -141,18 +142,17 @@ pub fn mv(old, new string) { } fn C.CopyFile(&u32, &u32, int) int - // TODO implement actual cp for linux pub fn cp(old, new string) ?bool { $if windows { _old := old.replace('/', '\\') _new := new.replace('/', '\\') C.CopyFile(_old.to_wide(), _new.to_wide(), false) - result := C.GetLastError() if result == 0 { return true - } else { + } + else { return error_with_code('failed to copy $old to $new', int(result)) } } $else { @@ -161,19 +161,15 @@ pub fn cp(old, new string) ?bool { } } -pub fn cp_r(osource_path, odest_path string, overwrite bool) ?bool{ - source_path := os.realpath( osource_path ) - dest_path := os.realpath( odest_path ) +pub fn cp_r(osource_path, odest_path string, overwrite bool) ?bool { + source_path := os.realpath(osource_path) + dest_path := os.realpath(odest_path) if !os.exists(source_path) { - return error('Source path doesn\'t exist') + return error("Source path doesn\'t exist") } - //single file copy + // single file copy if !os.is_dir(source_path) { - adjasted_path := if os.is_dir(dest_path) { - filepath.join(dest_path, os.filename(source_path)) - } else { - dest_path - } + adjasted_path := if os.is_dir(dest_path) { filepath.join(dest_path,os.filename(source_path)) } else { dest_path } if os.exists(adjasted_path) { if overwrite { os.rm(adjasted_path) @@ -182,20 +178,26 @@ pub fn cp_r(osource_path, odest_path string, overwrite bool) ?bool{ return error('Destination file path already exist') } } - os.cp(source_path, adjasted_path) or { return error(err) } + os.cp(source_path, adjasted_path)or{ + return error(err) + } return true } if !os.is_dir(dest_path) { return error('Destination path is not a valid directory') } - files := os.ls(source_path) or { return error(err) } + files := os.ls(source_path)or{ + return error(err) + } for file in files { - sp := filepath.join(source_path, file) - dp := filepath.join(dest_path, file) + sp := filepath.join(source_path,file) + dp := filepath.join(dest_path,file) if os.is_dir(sp) { - os.mkdir(dp) or { panic(err) } + os.mkdir(dp)or{ + panic(err) + } } - cp_r(sp, dp, overwrite) or { + cp_r(sp, dp, overwrite)or{ os.rmdir(dp) panic(err) } @@ -206,7 +208,9 @@ pub fn cp_r(osource_path, odest_path string, overwrite bool) ?bool{ // mv_by_cp first copies the source file, and if it is copied successfully, deletes the source file. // mv_by_cp may be used when you are not sure that the source and target are on the same mount/partition. pub fn mv_by_cp(source string, target string) ?bool { - os.cp(source, target) or { return error(err) } + os.cp(source, target)or{ + return error(err) + } os.rm(source) return true } @@ -224,13 +228,11 @@ pub fn read_lines(path string) ?[]string { mut res := []string mut buf_len := 1024 mut buf := malloc(buf_len) - mode := 'rb' mut fp := vfopen(path, mode) if isnil(fp) { return error('read_lines() failed to open file "$path"') } - mut buf_index := 0 for C.fgets(buf + buf_index, buf_len - buf_index, fp) != 0 { len := vstrlen(buf) @@ -257,7 +259,7 @@ pub fn read_lines(path string) ?[]string { } fn read_ulines(path string) ?[]ustring { - lines := read_lines(path) or { + lines := read_lines(path)or{ return err } // mut ulines := new_array(0, lines.len, sizeof(ustring)) @@ -270,16 +272,17 @@ fn read_ulines(path string) ?[]ustring { } pub fn open(path string) ?File { - mut file := File{} + mut file := File{ + } $if windows { wpath := path.to_wide() mode := 'rb' - file = File { + file = File{ cfile: C._wfopen(wpath, mode.to_wide()) } } $else { cpath := path.str - file = File { + file = File{ cfile: C.fopen(charptr(cpath), 'rb') } } @@ -292,16 +295,17 @@ pub fn open(path string) ?File { // create creates a file at a specified location and returns a writable `File` object. pub fn create(path string) ?File { - mut file := File{} + mut file := File{ + } $if windows { wpath := path.replace('/', '\\').to_wide() mode := 'wb' - file = File { + file = File{ cfile: C._wfopen(wpath, mode.to_wide()) } } $else { cpath := path.str - file = File { + file = File{ cfile: C.fopen(charptr(cpath), 'wb') } } @@ -313,16 +317,17 @@ pub fn create(path string) ?File { } pub fn open_append(path string) ?File { - mut file := File{} + mut file := File{ + } $if windows { wpath := path.replace('/', '\\').to_wide() mode := 'ab' - file = File { + file = File{ cfile: C._wfopen(wpath, mode.to_wide()) } } $else { cpath := path.str - file = File { + file = File{ cfile: C.fopen(charptr(cpath), 'ab') } } @@ -337,7 +342,6 @@ pub fn (f mut File) write(s string) { C.fputs(s.str, f.cfile) // C.fwrite(s.str, 1, s.len, f.cfile) } - // convert any value to []byte (LittleEndian) and write it // for example if we have write(7, 4), "07 00 00 00" gets written // write(0x1234, 2) => "34 12" @@ -352,7 +356,9 @@ pub fn (f mut File) write_bytes_at(data voidptr, size, pos int) { } pub fn (f mut File) writeln(s string) { - if !f.opened { return } + if !f.opened { + return + } // C.fwrite(s.str, 1, s.len, f.cfile) // ss := s.clone() // TODO perf @@ -362,25 +368,29 @@ pub fn (f mut File) writeln(s string) { } pub fn (f mut File) flush() { - if !f.opened { return } + if !f.opened { + return + } C.fflush(f.cfile) } pub fn (f mut File) close() { - if !f.opened { return } + if !f.opened { + return + } f.opened = false C.fflush(f.cfile) C.fclose(f.cfile) } // system starts the specified command, waits for it to complete, and returns its code. -fn vpopen(path string) voidptr {//*C.FILE { +fn vpopen(path string) voidptr { + // *C.FILE { $if windows { mode := 'rb' wpath := path.to_wide() return C._wpopen(wpath, mode.to_wide()) - } - $else { + } $else { cpath := path.str return C.popen(cpath, 'r') } @@ -388,29 +398,28 @@ fn vpopen(path string) voidptr {//*C.FILE { fn posix_wait4_to_exit_status(waitret int) (int,bool) { $if windows { - return waitret, false - } - $else { + return waitret,false + } $else { mut ret := 0 mut is_signaled := true // (see man system, man 2 waitpid: C macro WEXITSTATUS section) - if C.WIFEXITED( waitret ) { - ret = C.WEXITSTATUS( waitret ) + if C.WIFEXITED(waitret) { + ret = C.WEXITSTATUS(waitret) is_signaled = false - } else if C.WIFSIGNALED( waitret ){ - ret = C.WTERMSIG( waitret ) + } + else if C.WIFSIGNALED(waitret) { + ret = C.WTERMSIG(waitret) is_signaled = true } - return ret , is_signaled + return ret,is_signaled } } fn vpclose(f voidptr) int { $if windows { return C._pclose(f) - } - $else { - ret , _ := posix_wait4_to_exit_status(C.pclose(f)) + } $else { + ret,_ := posix_wait4_to_exit_status(C.pclose(f)) return ret } } @@ -418,16 +427,15 @@ fn vpclose(f voidptr) int { pub struct Result { pub: exit_code int - output string - //stderr string // TODO + output string + // stderr string // TODO } - // `system` works like `exec()`, but only returns a return code. pub fn system(cmd string) int { - //if cmd.contains(';') || cmd.contains('&&') || cmd.contains('||') || cmd.contains('\n') { - // TODO remove panic - //panic(';, &&, || and \\n are not allowed in shell commands') - //} + // if cmd.contains(';') || cmd.contains('&&') || cmd.contains('||') || cmd.contains('\n') { + // TODO remove panic + // panic(';, &&, || and \\n are not allowed in shell commands') + // } mut ret := 0 $if windows { // overcome bug in system & _wsystem (cmd) when first char is quote `"` @@ -439,11 +447,10 @@ pub fn system(cmd string) int { if ret == -1 { print_c_errno() } - $if !windows { - pret , is_signaled := posix_wait4_to_exit_status( ret ) + pret,is_signaled := posix_wait4_to_exit_status(ret) if is_signaled { - println('Terminated by signal ${ret:2d} (' + sigint_to_signal_name(pret) + ')' ) + println('Terminated by signal ${ret:2d} (' + sigint_to_signal_name(pret) + ')') } ret = pret } @@ -453,35 +460,77 @@ pub fn system(cmd string) int { pub fn sigint_to_signal_name(si int) string { // POSIX signals: match si { - 1 {return 'SIGHUP'} - 2 {return 'SIGINT'} - 3 {return 'SIGQUIT'} - 4 {return 'SIGILL'} - 6 {return 'SIGABRT'} - 8 {return 'SIGFPE'} - 9 {return 'SIGKILL'} - 11 {return 'SIGSEGV'} - 13 {return 'SIGPIPE'} - 14 {return 'SIGALRM'} - 15 {return 'SIGTERM'} - else { } - } + 1 { + return 'SIGHUP' + } + 2 { + return 'SIGINT' + } + 3 { + return 'SIGQUIT' + } + 4 { + return 'SIGILL' + } + 6 { + return 'SIGABRT' + } + 8 { + return 'SIGFPE' + } + 9 { + return 'SIGKILL' + } + 11 { + return 'SIGSEGV' + } + 13 { + return 'SIGPIPE' + } + 14 { + return 'SIGALRM' + } + 15 { + return 'SIGTERM' + } + else { + }} $if linux { // From `man 7 signal` on linux: match si { - 30,10,16{ return 'SIGUSR1'} - 31,12,17{ return 'SIGUSR2'} - 20,17,18{ return 'SIGCHLD'} - 19,18,25{ return 'SIGCONT'} - 17,19,23{ return 'SIGSTOP'} - 18,20,24{ return 'SIGTSTP'} - 21,21,26{ return 'SIGTTIN'} - 22,22,27{ return 'SIGTTOU'} - /////////////////////////////// - 5{ return 'SIGTRAP'} - 7{ return 'SIGBUS' } - else {} - } + 30, 10, 16 { + return 'SIGUSR1' + } + 31, 12, 17 { + return 'SIGUSR2' + } + 20, 17, 18 { + return 'SIGCHLD' + } + 19, 18, 25 { + return 'SIGCONT' + } + 17, 19, 23 { + return 'SIGSTOP' + } + 18, 20, 24 { + return 'SIGTSTP' + } + 21, 21, 26 { + return 'SIGTTIN' + } + 22, 22, 27 { + return 'SIGTTOU' + } + // ///////////////////////////// + 5 { + return 'SIGTRAP' + } + 7 { + return 'SIGBUS' + } + else { + }} } return 'unknown' } @@ -500,7 +549,7 @@ pub fn getenv(key string) string { return '' } // NB: C.getenv *requires* that the result be copied. - return cstring_to_vstring( byteptr(s) ) + return cstring_to_vstring(byteptr(s)) } } @@ -531,7 +580,7 @@ pub fn exists(path string) bool { p := path.replace('/', '\\') return C._waccess(p.to_wide(), 0) != -1 } $else { - return C.access(path.str, 0 ) != -1 + return C.access(path.str, 0) != -1 } } @@ -544,30 +593,24 @@ pub fn file_exists(_path string) bool { pub fn rm(path string) { $if windows { C._wremove(path.to_wide()) - } - $else { + } $else { C.remove(path.str) } // C.unlink(path.cstr()) } - - // rmdir removes a specified directory. pub fn rmdir(path string) { $if !windows { C.rmdir(path.str) - } - $else { + } $else { C.RemoveDirectory(path.to_wide()) } } - fn print_c_errno() { - //C.printf('errno=%d err="%s"\n', C.errno, C.strerror(C.errno)) + // C.printf('errno=%d err="%s"\n', C.errno, C.strerror(C.errno)) } - pub fn ext(path string) string { pos := path.last_index('.') or { return '' @@ -575,7 +618,6 @@ pub fn ext(path string) string { return path[pos..] } - // dir returns all but the last element of path, typically the path's directory. pub fn dir(path string) string { if path == '.' { @@ -594,12 +636,11 @@ fn path_sans_ext(path string) string { return path[..pos] } - pub fn basedir(path string) string { pos := path.last_index(path_separator) or { return path } - return path[..pos ] // NB: *without* terminating / + return path[..pos] // NB: *without* terminating / } pub fn filename(path string) string { @@ -608,53 +649,54 @@ pub fn filename(path string) string { // get_line returns a one-line string from stdin pub fn get_line() string { - str := get_raw_line() + str := get_raw_line() $if windows { return str.trim_right('\r\n') - } - $else { + } $else { return str.trim_right('\n') } } // get_raw_line returns a one-line string from stdin along with '\n' if there is any pub fn get_raw_line() string { - $if windows { - max_line_chars := 256 - buf := malloc(max_line_chars*2) - if is_atty(0) > 0 { - h_input := C.GetStdHandle(STD_INPUT_HANDLE) - mut nr_chars := u32(0) - C.ReadConsole(h_input, buf, max_line_chars * 2, voidptr(&nr_chars), 0) - return string_from_wide2(&u16(buf), int(nr_chars)) - } - res := C.fgetws(&u16(buf), max_line_chars, C.stdin ) - len := C.wcslen(&u16(buf)) - if !isnil(res) { return string_from_wide2( &u16(buf), len ) } - return '' - } $else { - max := size_t(256) - buf := charptr(malloc(int(max))) - nr_chars := C.getline(&buf, &max, stdin) - if nr_chars == 0 { - return '' - } - return string(byteptr(buf), nr_chars) - } + $if windows { + max_line_chars := 256 + buf := malloc(max_line_chars * 2) + if is_atty(0) > 0 { + h_input := C.GetStdHandle(STD_INPUT_HANDLE) + mut nr_chars := u32(0) + C.ReadConsole(h_input, buf, max_line_chars * 2, voidptr(&nr_chars), 0) + return string_from_wide2(&u16(buf), int(nr_chars)) + } + res := C.fgetws(&u16(buf), max_line_chars, C.stdin) + len := C.wcslen(&u16(buf)) + if !isnil(res) { + return string_from_wide2(&u16(buf), len) + } + return '' + } $else { + max := size_t(256) + buf := charptr(malloc(int(max))) + nr_chars := C.getline(&buf, &max, stdin) + if nr_chars == 0 { + return '' + } + return string(byteptr(buf),nr_chars) + } } pub fn get_lines() []string { - mut line := '' - mut inputstr := []string - for { - line = get_line() - if(line.len <= 0) { - break - } - line = line.trim_space() - inputstr << line - } - return inputstr + mut line := '' + mut inputstr := []string + for { + line = get_line() + if (line.len <= 0) { + break + } + line = line.trim_space() + inputstr << line + } + return inputstr } pub fn get_lines_joined() string { @@ -694,7 +736,7 @@ pub fn user_os() string { $if dragonfly { return 'dragonfly' } - $if android{ + $if android { return 'android' } $if solaris { @@ -726,7 +768,7 @@ pub fn home_dir() string { // write_file writes `text` data to a file in `path`. pub fn write_file(path, text string) { - mut f := os.create(path) or { + mut f := os.create(path)or{ return } f.write(text) @@ -746,7 +788,8 @@ pub fn on_segfault(f voidptr) { return } $if macos { - mut sa := C.sigaction{} + mut sa := C.sigaction{ + } C.memset(&sa, 0, sizeof(sigaction)) C.sigemptyset(&sa.sa_mask) sa.sa_sigaction = f @@ -756,10 +799,12 @@ pub fn on_segfault(f voidptr) { } fn C.getpid() int -fn C.proc_pidpath (int, byteptr, int) int + + +fn C.proc_pidpath(int, byteptr, int) int + + fn C.readlink() int - - // executable returns the path name of the executable that started the current // process. pub fn executable() string { @@ -774,15 +819,15 @@ pub fn executable() string { } $if windows { max := 512 - mut result := &u16(calloc(max*2)) // MAX_PATH * sizeof(wchar_t) - len := C.GetModuleFileName( 0, result, max ) + mut result := &u16(calloc(max * 2)) // MAX_PATH * sizeof(wchar_t) + len := C.GetModuleFileName(0, result, max) return string_from_wide2(result, len) } $if macos { mut result := calloc(MAX_PATH) pid := C.getpid() - ret := proc_pidpath (pid, result, MAX_PATH) - if ret <= 0 { + ret := proc_pidpath(pid, result, MAX_PATH) + if ret <= 0 { eprintln('os.executable() failed at calling proc_pidpath with pid: $pid . proc_pidpath returned $ret ') return os.args[0] } @@ -790,7 +835,7 @@ pub fn executable() string { } $if freebsd { mut result := calloc(MAX_PATH) - mib := [1 /* CTL_KERN */, 14 /* KERN_PROC */, 12 /* KERN_PROC_PATHNAME */, -1] + mib := [1/* CTL_KERN */, 14/* KERN_PROC */, 12/* KERN_PROC_PATHNAME */, -1] size := MAX_PATH C.sysctl(mib.data, 4, result, &size, 0, 0) return string(result) @@ -806,21 +851,21 @@ pub fn executable() string { } $if netbsd { mut result := calloc(MAX_PATH) - count := int(C.readlink('/proc/curproc/exe', result, MAX_PATH )) + count := int(C.readlink('/proc/curproc/exe', result, MAX_PATH)) if count < 0 { eprintln('os.executable() failed at reading /proc/curproc/exe to get exe path') return os.args[0] } - return string(result, count) + return string(result,count) } $if dragonfly { mut result := calloc(MAX_PATH) - count := int(C.readlink('/proc/curproc/file', result, MAX_PATH )) + count := int(C.readlink('/proc/curproc/file', result, MAX_PATH)) if count < 0 { eprintln('os.executable() failed at reading /proc/curproc/file to get exe path') return os.args[0] } - return string(result, count) + return string(result,count) } return os.args[0] } @@ -828,9 +873,8 @@ pub fn executable() string { [deprecated] pub fn dir_exists(path string) bool { panic('use os.is_dir()') - //return false + // return false } - // is_dir returns a boolean indicating whether the given path is a directory. pub fn is_dir(path string) bool { $if windows { @@ -843,9 +887,9 @@ pub fn is_dir(path string) bool { return true } return false - } - $else { - statbuf := C.stat{} + } $else { + statbuf := C.stat{ + } if C.stat(path.str, &statbuf) != 0 { return false } @@ -859,7 +903,8 @@ pub fn is_link(path string) bool { $if windows { return false // TODO } $else { - statbuf := C.stat{} + statbuf := C.stat{ + } if C.lstat(path.str, &statbuf) != 0 { return false } @@ -871,8 +916,7 @@ pub fn is_link(path string) bool { pub fn chdir(path string) { $if windows { C._wchdir(path.to_wide()) - } - $else { + } $else { C.chdir(path.str) } } @@ -881,13 +925,12 @@ pub fn chdir(path string) { pub fn getwd() string { $if windows { max := 512 // MAX_PATH * sizeof(wchar_t) - buf := &u16(calloc(max*2)) + buf := &u16(calloc(max * 2)) if C._wgetcwd(buf, max) == 0 { return '' } return string_from_wide(buf) - } - $else { + } $else { buf := calloc(512) if C.getcwd(buf, 512) == 0 { return '' @@ -899,7 +942,7 @@ pub fn getwd() string { // Returns the full absolute path for fpath, with all relative ../../, symlinks and so on resolved. // See http://pubs.opengroup.org/onlinepubs/9699919799/functions/realpath.html // Also https://insanecoding.blogspot.com/2007/11/pathmax-simply-isnt.html -// and https://insanecoding.blogspot.com/2007/11/implementing-realpath-in-c.html +// and https://insanecoding.blogspot.com/2007/11/implementing-realpath-in-c.html // NB: this particular rabbit hole is *deep* ... pub fn realpath(fpath string) string { mut fullpath := calloc(MAX_PATH) @@ -923,9 +966,11 @@ pub fn walk_ext(path, ext string) []string { if !os.is_dir(path) { return [] } - mut files := os.ls(path) or { panic(err) } + mut files := os.ls(path)or{ + panic(err) + } mut res := []string - separator := if path.ends_with(path_separator) { '' } else { path_separator} + separator := if path.ends_with(path_separator) { '' } else { path_separator } for i, file in files { if file.starts_with('.') { continue @@ -947,7 +992,9 @@ pub fn walk(path string, fnc fn(path string)) { if !os.is_dir(path) { return } - mut files := os.ls(path) or { panic(err) } + mut files := os.ls(path)or{ + panic(err) + } for file in files { p := path + os.path_separator + file if os.is_dir(p) { @@ -964,10 +1011,12 @@ pub fn signal(signum int, handler voidptr) { C.signal(signum, handler) } - fn C.fork() int + + fn C.wait() int + pub fn fork() int { mut pid := -1 $if !windows { @@ -991,15 +1040,15 @@ pub fn wait() int { } pub fn file_last_mod_unix(path string) int { - attr := C.stat{} - //# struct stat attr; + attr := C.stat{ + } + // # struct stat attr; C.stat(path.str, &attr) - //# stat(path.str, &attr); + // # stat(path.str, &attr); return attr.st_mtime - //# return attr.st_mtime ; + // # return attr.st_mtime ; } - pub fn log(s string) { println('os.log: ' + s) } @@ -1009,7 +1058,7 @@ pub fn flush_stdout() { } pub fn print_backtrace() { -/* + /* # void *buffer[100]; nptrs := 0 # nptrs = backtrace(buffer, 100); @@ -1023,24 +1072,30 @@ pub fn mkdir_all(path string) { for subdir in path.split(os.path_separator) { p += subdir + os.path_separator if !os.is_dir(p) { - os.mkdir(p) or { panic(err) } + os.mkdir(p)or{ + panic(err) + } } } } pub fn join(base string, dirs ...string) string { println('use filepath.join') - return filepath.join(base, dirs) + return filepath.join(base,dirs) } // tmpdir returns the path to a folder, that is suitable for storing temporary files pub fn tmpdir() string { mut path := os.getenv('TMPDIR') $if linux { - if path == '' { path = '/tmp' } + if path == '' { + path = '/tmp' + } } $if freebsd { - if path == '' { path = '/tmp' } + if path == '' { + path = '/tmp' + } } $if macos { /* @@ -1049,7 +1104,9 @@ pub fn tmpdir() string { path = C.NSTemporaryDirectory() } */ - if path == '' { path = '/tmp' } + if path == '' { + path = '/tmp' + } } $if windows { if path == '' { @@ -1057,18 +1114,22 @@ pub fn tmpdir() string { // https://doc.qt.io/qt-5/qdir.html#tempPath // https://github.com/qt/qtbase/blob/e164d61ca8263fc4b46fdd916e1ea77c7dd2b735/src/corelib/io/qfilesystemengine_win.cpp#L1275 path = os.getenv('TEMP') - if path == '' { path = os.getenv('TMP') } - if path == '' { path = 'C:/tmp' } + if path == '' { + path = os.getenv('TMP') + } + if path == '' { + path = 'C:/tmp' + } } } return path } - pub fn chmod(path string, mode int) { C.chmod(path.str, mode) } pub const ( - wd_at_startup = getwd() + wd_at_startup = getwd() ) + diff --git a/vlib/os/os_nix.v b/vlib/os/os_nix.v index d9165a2cfe..68f8108831 100644 --- a/vlib/os/os_nix.v +++ b/vlib/os/os_nix.v @@ -2,7 +2,6 @@ module os #include #include - pub const ( path_separator = '/' ) @@ -15,7 +14,6 @@ pub fn init_os_args(argc int, argv &byteptr) []string { return args } - // get_error_msg return error code representation in string. pub fn get_error_msg(code int) string { ptr_text := C.strerror(code) // voidptr? @@ -32,7 +30,7 @@ pub fn ls(path string) ?[]string { return error('ls() couldnt open dir "$path"') } mut ent := &C.dirent(0) - //mut ent := &C.dirent{!} + // mut ent := &C.dirent{!} for { ent = C.readdir(dir) if isnil(ent) { @@ -63,8 +61,10 @@ pub fn is_dir(path string) bool { // mkdir creates a new directory with the specified path. pub fn mkdir(path string) ?bool { - if path == '.' { return true } - apath := os.realpath( path ) + if path == '.' { + return true + } + apath := os.realpath(path) r := C.mkdir(apath.str, 511) if r == -1 { return error(get_error_msg(C.errno)) @@ -74,9 +74,9 @@ pub fn mkdir(path string) ?bool { // exec starts the specified command, waits for it to complete, and returns its output. pub fn exec(cmd string) ?Result { - //if cmd.contains(';') || cmd.contains('&&') || cmd.contains('||') || cmd.contains('\n') { - //return error(';, &&, || and \\n are not allowed in shell commands') - //} + // if cmd.contains(';') || cmd.contains('&&') || cmd.contains('||') || cmd.contains('\n') { + // return error(';, &&, || and \\n are not allowed in shell commands') + // } pcmd := '$cmd 2>&1' f := vpopen(pcmd) if isnil(f) { @@ -89,11 +89,12 @@ pub fn exec(cmd string) ?Result { } res = res.trim_space() exit_code := vpclose(f) - //if exit_code != 0 { - //return error(res) - //} - return Result { + // if exit_code != 0 { + // return error(res) + // } + return Result{ output: res exit_code: exit_code } } + diff --git a/vlib/rand/pcg32.v b/vlib/rand/pcg32.v index 513e97b368..d7e008e4cf 100644 --- a/vlib/rand/pcg32.v +++ b/vlib/rand/pcg32.v @@ -1,48 +1,58 @@ module rand - // Ported from http://www.pcg-random.org/download.html // and https://github.com/imneme/pcg-c-basic/blob/master/pcg_basic.c - pub struct Pcg32 { mut: state u64 - inc u64 + inc u64 } + /** * new_pcg32 - a Pcg32 PRNG generator * @param initstate - the initial state of the PRNG. * @param initseq - the stream/step of the PRNG. * @return a new Pcg32 PRNG instance */ + + pub fn new_pcg32(initstate u64, initseq u64) Pcg32 { - mut rng := Pcg32{} + mut rng := Pcg32{ + } rng.state = u64(0) - rng.inc = (initseq << u64(1)) | u64(1) + rng.inc = (initseq<> u64(18)) ^ oldstate) >> u64(27) ) - rot := u32( oldstate >> u64(59) ) - return ( (xorshifted >> rot) | (xorshifted << ((-rot) & u32(31))) ) + xorshifted := u32(((oldstate>>u64(18)) ^ oldstate)>>u64(27)) + rot := u32(oldstate>>u64(59)) + return ((xorshifted>>rot) | (xorshifted<<((-rot) & u32(31)))) } + /** * Pcg32.bounded_next - update the PRNG state. Get the next number < bound * @param bound - the returned random number will be < bound * @return the generated pseudo random number */ -[inline] pub fn (rng mut Pcg32) bounded_next(bound u32) u32 { + + +[inline] +pub fn (rng mut Pcg32) bounded_next(bound u32) u32 { // To avoid bias, we need to make the range of the RNG a multiple of // bound, which we do by dropping output less than a threshold. - threshold := ( -bound % bound ) + threshold := (-bound % bound) // Uniformity guarantees that loop below will terminate. In practice, it // should usually terminate quickly; on average (assuming all bounds are // equally likely), 82.25% of the time, we can expect it to require just @@ -51,8 +61,9 @@ pub fn new_pcg32(initstate u64, initseq u64) Pcg32 { for { r := rng.next() if r >= threshold { - return ( r % bound ) + return (r % bound) } } return u32(0) } + diff --git a/vlib/rand/rand.v b/vlib/rand/rand.v index 7f451f09a7..5ae1f8208f 100644 --- a/vlib/rand/rand.v +++ b/vlib/rand/rand.v @@ -1,7 +1,6 @@ // 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 rand pub fn seed(s int) { @@ -13,7 +12,6 @@ pub fn next(max int) int { } fn C.rand() int - /** * rand_r - reentrant pseudo-random number generator * @@ -21,11 +19,15 @@ fn C.rand() int * * @return a value between 0 and C.RAND_MAX (inclusive) */ + + + pub fn rand_r(seed &int) int { - unsafe { - mut rs := seed - ns := ( *rs * 1103515245 + 12345 ) - *rs = ns - return ns & 0x7fffffff + unsafe{ + mut rs := seed + ns := (*rs * 1103515245 + 12345) + *rs = ns + return ns & 0x7fffffff } } + diff --git a/vlib/rand/splitmix64.v b/vlib/rand/splitmix64.v index 825bb2d949..f5c8145750 100644 --- a/vlib/rand/splitmix64.v +++ b/vlib/rand/splitmix64.v @@ -1,36 +1,46 @@ module rand - // Ported from http://xoshiro.di.unimi.it/splitmix64.c - struct Splitmix64 { mut: state u64 } + /** * new_splitmix64 - a Splitmix64 PRNG generator * @param seed the initial seed of the PRNG. * @return a new Splitmix64 PRNG instance */ + + pub fn new_splitmix64(seed u64) Splitmix64 { - return Splitmix64{ seed } + return Splitmix64{ + seed} } + /** * Splitmix64.next - update the PRNG state and get back the next random number * @return the generated pseudo random number */ -[inline] pub fn (rng mut Splitmix64) next() u64 { + + +[inline] +pub fn (rng mut Splitmix64) next() u64 { rng.state += (0x9e3779b97f4a7c15) mut z := rng.state - z = (z ^ ((z >> u64(30)))) * (0xbf58476d1ce4e5b9) - z = (z ^ ((z >> u64(27)))) * (0x94d049bb133111eb) - return z ^ (z >> (31)) + z = (z ^ ((z>>u64(30)))) * (0xbf58476d1ce4e5b9) + z = (z ^ ((z>>u64(27)))) * (0x94d049bb133111eb) + return z ^ (z>>(31)) } + /** * Splitmix64.bounded_next - Get the next random number < bound * @param bound - the returned random number will be < bound * @return the generated pseudo random number */ -[inline] pub fn (rng mut Splitmix64) bounded_next(bound u64) u64 { + + +[inline] +pub fn (rng mut Splitmix64) bounded_next(bound u64) u64 { threshold := -bound % bound for { r := rng.next() @@ -40,3 +50,4 @@ pub fn new_splitmix64(seed u64) Splitmix64 { } return u64(0) } + diff --git a/vlib/strconv/atof.v b/vlib/strconv/atof.v index 9ad466d73e..2a194b8aaf 100644 --- a/vlib/strconv/atof.v +++ b/vlib/strconv/atof.v @@ -19,38 +19,38 @@ * **********************************************************************/ module strconv - /********************************************************************** * * 96 bit operation utilities * Note: when u128 will be available these function can be refactored * **********************************************************************/ + // right logical shift 96 bit -fn lsr96(s2 u32, s1 u32, s0 u32) (u32, u32, u32) { +fn lsr96(s2 u32, s1 u32, s0 u32) (u32,u32,u32) { mut r0 := u32(0) mut r1 := u32(0) mut r2 := u32(0) - r0 = (s0 >> 1) | ((s1 & u32(1)) << 31) - r1 = (s1 >> 1) | ((s2 & u32(1)) << 31) - r2 = s2 >> 1 + r0 = (s0>>1) | ((s1 & u32(1))<<31) + r1 = (s1>>1) | ((s2 & u32(1))<<31) + r2 = s2>>1 return r2,r1,r0 } // left logical shift 96 bit -fn lsl96(s2 u32, s1 u32, s0 u32) (u32, u32, u32) { +fn lsl96(s2 u32, s1 u32, s0 u32) (u32,u32,u32) { mut r0 := u32(0) mut r1 := u32(0) mut r2 := u32(0) - r2 = (s2 << 1) | ((s1 & (u32(1) << 31)) >> 31) - r1 = (s1 << 1) | ((s0 & (u32(1) << 31)) >> 31) - r0 = s0 << 1 + r2 = (s2<<1) | ((s1 & (u32(1)<<31))>>31) + r1 = (s1<<1) | ((s0 & (u32(1)<<31))>>31) + r0 = s0<<1 return r2,r1,r0 } // sum on 96 bit -fn add96(s2 u32, s1 u32, s0 u32, d2 u32, d1 u32, d0 u32) (u32, u32, u32) { - mut w := u64(0) +fn add96(s2 u32, s1 u32, s0 u32, d2 u32, d1 u32, d0 u32) (u32,u32,u32) { + mut w := u64(0) mut r0 := u32(0) mut r1 := u32(0) mut r2 := u32(0) @@ -66,8 +66,8 @@ fn add96(s2 u32, s1 u32, s0 u32, d2 u32, d1 u32, d0 u32) (u32, u32, u32) { } // subtraction on 96 bit -fn sub96(s2 u32, s1 u32, s0 u32, d2 u32, d1 u32, d0 u32) (u32, u32, u32) { - mut w := u64(0) +fn sub96(s2 u32, s1 u32, s0 u32, d2 u32, d1 u32, d0 u32) (u32,u32,u32) { + mut w := u64(0) mut r0 := u32(0) mut r1 := u32(0) mut r2 := u32(0) @@ -87,62 +87,58 @@ fn sub96(s2 u32, s1 u32, s0 u32, d2 u32, d1 u32, d0 u32) (u32, u32, u32) { * Constants * **********************************************************************/ -const ( - // - // f64 constants - // - DIGITS = 18 - DOUBLE_PLUS_ZERO = u64(0x0000000000000000) - DOUBLE_MINUS_ZERO = 0x8000000000000000 - DOUBLE_PLUS_INFINITY = 0x7FF0000000000000 - DOUBLE_MINUS_INFINITY = 0xFFF0000000000000 + +const ( +// +// f64 constants +// + DIGITS = 18 + DOUBLE_PLUS_ZERO = u64(0x0000000000000000) + DOUBLE_MINUS_ZERO = 0x8000000000000000 + DOUBLE_PLUS_INFINITY = 0x7FF0000000000000 + DOUBLE_MINUS_INFINITY = 0xFFF0000000000000 // // parser state machine states // - FSM_A = 0 - FSM_B = 1 - FSM_C = 2 - FSM_D = 3 - FSM_E = 4 - FSM_F = 5 - FSM_G = 6 - FSM_H = 7 - FSM_I = 8 + FSM_A = 0 + FSM_B = 1 + FSM_C = 2 + FSM_D = 3 + FSM_E = 4 + FSM_F = 5 + FSM_G = 6 + FSM_H = 7 + FSM_I = 8 FSM_STOP = 9 - // // Possible parser return values. // - PARSER_OK = 0 // parser finished OK - PARSER_PZERO = 1 // no digits or number is smaller than +-2^-1022 - PARSER_MZERO = 2 // number is negative, module smaller - PARSER_PINF = 3 // number is higher than +HUGE_VAL - PARSER_MINF = 4 // number is lower than -HUGE_VAL - + PARSER_OK = 0 // parser finished OK + PARSER_PZERO = 1 // no digits or number is smaller than +-2^-1022 + PARSER_MZERO = 2 // number is negative, module smaller + PARSER_PINF = 3 // number is higher than +HUGE_VAL + PARSER_MINF = 4 // number is lower than -HUGE_VAL // // char constants // Note: Modify these if working with non-ASCII encoding // - DPOINT =`.` - PLUS =`+` - MINUS =`-` - ZERO =`0` - NINE =`9` - - TEN = u32(10) + DPOINT = `.` + PLUS = `+` + MINUS = `-` + ZERO = `0` + NINE = `9` + TEN = u32(10) ) - - /********************************************************************** * * Utility * **********************************************************************/ -// NOTE: Modify these if working with non-ASCII encoding +// NOTE: Modify these if working with non-ASCII encoding fn is_digit(x byte) bool { - return (x >= ZERO && x <=NINE) == true + return (x >= ZERO && x <= NINE) == true } fn is_space(x byte) bool { @@ -177,97 +173,98 @@ pub fn strlong(x f64) string { * Support struct * **********************************************************************/ + // The structure is filled by parser, then given to converter. -pub struct PrepNumber -{ +pub struct PrepNumber { pub mut: - negative bool = false // 0 if positive number, 1 if negative - exponent int = 0 // power of 10 exponent - mantissa u64 = u64(0) // integer mantissa + negative bool=false // 0 if positive number, 1 if negative + exponent int=0 // power of 10 exponent + mantissa u64=u64(0) // integer mantissa } - - /********************************************************************** * * String parser * NOTE: #TOFIX need one char after the last char of the number * **********************************************************************/ + // parser return a support struct with all the parsing information for the converter -fn parser(s string ) (int,PrepNumber) { - mut state := FSM_A - mut digx := 0 - mut c := ` ` // initial value for kicking off the state machine - mut result := PARSER_OK - mut expneg := false - mut expexp := 0 - mut i := 0 - - mut pn := PrepNumber{} - +fn parser(s string) (int,PrepNumber) { + mut state := FSM_A + mut digx := 0 + mut c := ` ` // initial value for kicking off the state machine + mut result := PARSER_OK + mut expneg := false + mut expexp := 0 + mut i := 0 + mut pn := PrepNumber{ + } for state != FSM_STOP { - - match state { - + match state { // skip starting spaces FSM_A { - if is_space(c)==true { + if is_space(c) == true { c = s[i++] - } else { - state = FSM_B + } + else { + state = FSM_B } } - // check for the sign or point FSM_B { state = FSM_C - if c == PLUS { c = s[i++] - } else if c == MINUS { + } + else if c == MINUS { pn.negative = true c = s[i++] - } else if is_digit(c) {} - else if c == DPOINT {} + } + else if is_digit(c) { + } + else if c == DPOINT { + } else { state = FSM_STOP } } - // skip the inital zeros FSM_C { - if c == ZERO { c = s[i++] } + if c == ZERO { + c = s[i++] + } else if c == DPOINT { c = s[i++] state = FSM_D - } else { + } + else { state = FSM_E } } - // reading leading zeros in the fractional part of mantissa FSM_D { if c == ZERO { c = s[i++] - if pn.exponent > -2147483647 { pn.exponent-- } + if pn.exponent > -2147483647 { + pn.exponent-- + } } else { state = FSM_F } } - // reading integer part of mantissa FSM_E { if is_digit(c) { if digx < DIGITS { pn.mantissa *= 10 - pn.mantissa += u64( c - ZERO ) + pn.mantissa += u64(c - ZERO) digx++ } - else if pn.exponent < 2147483647 { pn.exponent++ } - + else if pn.exponent < 2147483647 { + pn.exponent++ + } c = s[i++] - } else if c == DPOINT { c = s[i++] @@ -277,7 +274,6 @@ fn parser(s string ) (int,PrepNumber) { state = FSM_F } } - // reading fractional part of mantissa FSM_F { if is_digit(c) { @@ -287,7 +283,6 @@ fn parser(s string ) (int,PrepNumber) { pn.exponent-- digx++ } - c = s[i++] } else if is_exp(c) { @@ -298,18 +293,17 @@ fn parser(s string ) (int,PrepNumber) { state = FSM_G } } - // reading sign of exponent FSM_G { if c == PLUS { c = s[i++] - } else if c == MINUS { + } + else if c == MINUS { expneg = true c = s[i++] } state = FSM_H } - // skipping leading zeros of exponent FSM_H { if c == ZERO { @@ -319,7 +313,6 @@ fn parser(s string ) (int,PrepNumber) { state = FSM_I } } - // reading exponent digits FSM_I { if is_digit(c) { @@ -327,144 +320,125 @@ fn parser(s string ) (int,PrepNumber) { expexp *= 10 expexp += int(c - ZERO) } - c = s[i++] } else { state = FSM_STOP } } - - else {} - } - - //C.printf("len: %d i: %d str: %s \n",s.len,i,s[..i]) - if i>=s.len { + else { + }} + // C.printf("len: %d i: %d str: %s \n",s.len,i,s[..i]) + if i >= s.len { state = FSM_STOP } } - if expneg { expexp = -expexp } pn.exponent += expexp - if pn.mantissa == 0 { if pn.negative { result = PARSER_MZERO - } else { + } + else { result = PARSER_PZERO } } - else if (pn.exponent > 309){ + else if (pn.exponent > 309) { if pn.negative { result = PARSER_MINF - } else { + } + else { result = PARSER_PINF } } else if pn.exponent < -328 { if pn.negative { result = PARSER_MZERO - } else { + } + else { result = PARSER_PZERO } } - return result,pn } - /********************************************************************** * * Converter to the bit form of the f64 number * **********************************************************************/ + // converter return a u64 with the bit image of the f64 number fn converter(pn mut PrepNumber) u64 { mut binexp := 92 - - mut s2:=u32(0) // 96-bit precision integer - mut s1:=u32(0) - mut s0:=u32(0) - mut q2:=u32(0) // 96-bit precision integer - mut q1:=u32(0) - mut q0:=u32(0) - mut r2:=u32(0) // 96-bit precision integer - mut r1:=u32(0) - mut r0:=u32(0) - - mask28 := u32(0xF << 28) - + mut s2 := u32(0) // 96-bit precision integer + mut s1 := u32(0) + mut s0 := u32(0) + mut q2 := u32(0) // 96-bit precision integer + mut q1 := u32(0) + mut q0 := u32(0) + mut r2 := u32(0) // 96-bit precision integer + mut r1 := u32(0) + mut r0 := u32(0) + mask28 := u32(0xF<<28) mut result := u64(0) - // working on 3 u32 to have 96 bit precision s0 = u32(pn.mantissa & u64(0x00000000FFFFFFFF)) - s1 = u32(pn.mantissa >> 32) + s1 = u32(pn.mantissa>>32) s2 = u32(0) - // so we take the decimal exponent off for pn.exponent > 0 { - q2, q1, q0 = lsl96(s2, s1, s0) // q = s * 2 - r2, r1, r0 = lsl96(q2, q1, q0) // r = s * 4 <=> q * 2 - s2, s1, s0 = lsl96(r2, r1, r0) // s = s * 8 <=> r * 2 - s2, s1, s0 = add96(s2, s1, s0, q2, q1, q0) // s = (s * 8) + (s * 2) <=> s*10 - + q2,q1,q0 = lsl96(s2, s1, s0) // q = s * 2 + r2,r1,r0 = lsl96(q2, q1, q0) // r = s * 4 <=> q * 2 + s2,s1,s0 = lsl96(r2, r1, r0) // s = s * 8 <=> r * 2 + s2,s1,s0 = add96(s2, s1, s0, q2, q1, q0) // s = (s * 8) + (s * 2) <=> s*10 pn.exponent-- - for (s2 & mask28) != 0 { - q2, q1, q0 = lsr96(s2, s1, s0) + q2,q1,q0 = lsr96(s2, s1, s0) binexp++ s2 = q2 s1 = q1 s0 = q0 } - } - for pn.exponent < 0 { - for !((s2 & (u32(1) << 31)) !=0) { - q2, q1, q0 = lsl96(s2, s1, s0) + for !((s2 & (u32(1)<<31)) != 0) { + q2,q1,q0 = lsl96(s2, s1, s0) binexp-- s2 = q2 s1 = q1 s0 = q0 - } - q2 = s2 / TEN r1 = s2 % TEN - r2 = (s1 >> 8) | (r1 << 24) + r2 = (s1>>8) | (r1<<24) q1 = r2 / TEN r1 = r2 % TEN - r2 = ((s1 & u32(0xFF)) << 16) | (s0 >> 16) | (r1 << 24) + r2 = ((s1 & u32(0xFF))<<16) | (s0>>16) | (r1<<24) r0 = r2 / TEN r1 = r2 % TEN - q1 = (q1 << 8) | ((r0 & u32(0x00FF0000)) >> 16) - q0 = r0 << 16 - r2 = (s0 & u32(0xFFFF)) | (r1 << 16) + q1 = (q1<<8) | ((r0 & u32(0x00FF0000))>>16) + q0 = r0<<16 + r2 = (s0 & u32(0xFFFF)) | (r1<<16) q0 |= r2 / TEN s2 = q2 s1 = q1 s0 = q0 - pn.exponent++ - } - - //C.printf("mantissa before normalization: %08x%08x%08x binexp: %d \n", s2,s1,s0,binexp) - + // C.printf("mantissa before normalization: %08x%08x%08x binexp: %d \n", s2,s1,s0,binexp) // normalization, the 28 bit in s2 must the leftest one in the variable - if s2 != 0 || s1 != 0|| s0 != 0 { + if s2 != 0 || s1 != 0 || s0 != 0 { for (s2 & mask28) == 0 { - q2, q1, q0 = lsl96(s2, s1, s0) + q2,q1,q0 = lsl96(s2, s1, s0) binexp-- s2 = q2 s1 = q1 s0 = q0 } } - // rounding if needed /* * "round half to even" algorithm @@ -477,7 +451,6 @@ fn converter(pn mut PrepNumber) u64 { * If bit 53 is 0, round down * If bit 53 is 1, round up */ - /* test case 1 complete s2=0x1FFFFFFF s1=0xFFFFFF80 @@ -496,52 +469,47 @@ fn converter(pn mut PrepNumber) u64 { s0=0x0 */ - //C.printf("mantissa before rounding: %08x%08x%08x binexp: %d \n", s2,s1,s0,binexp) - + // C.printf("mantissa before rounding: %08x%08x%08x binexp: %d \n", s2,s1,s0,binexp) // s1 => 0xFFFFFFxx only F are rapresented nbit := 7 - check_round_bit := u32(1) << u32(nbit) - check_round_mask := u32(0xFFFFFFFF) << u32(nbit) - + check_round_bit := u32(1)<> 8) - //C.printf("mantissa after rounding : %08x%08x%08x binexp: %d \n", s2,s1,s0,binexp) - //C.printf("Tmp result: %016x\n",tmp) - + // tmp := ( u64(s2 & ~mask28) << 24) | ((u64(s1) + u64(128)) >> 8) + // C.printf("mantissa after rounding : %08x%08x%08x binexp: %d \n", s2,s1,s0,binexp) + // C.printf("Tmp result: %016x\n",tmp) // end rounding - // offset the binary exponent IEEE 754 binexp += 1023 - if binexp > 2046 { if pn.negative { result = DOUBLE_MINUS_INFINITY - } else { + } + else { result = DOUBLE_PLUS_INFINITY } } @@ -552,15 +520,13 @@ fn converter(pn mut PrepNumber) u64 { } else if s2 != 0 { mut q := u64(0) - binexs2 := u64(binexp) << 52 - - q = ( u64(s2 & ~mask28) << 24) | ((u64(s1) + u64(128)) >> 8) | binexs2 + binexs2 := u64(binexp)<<52 + q = (u64(s2 & ~mask28)<<24) | ((u64(s1) + u64(128))>>8) | binexs2 if pn.negative { - q |= (u64(1) << 63) + q |= (u64(1)<<63) } result = q } - return result } @@ -569,21 +535,20 @@ fn converter(pn mut PrepNumber) u64 { * Public functions * **********************************************************************/ + // atof64 return a f64 from a string doing a parsing operation pub fn atof64(s string) f64 { - mut pn := PrepNumber{} + mut pn := PrepNumber{ + } mut res_parsing := 0 - mut result := f64(0) - result=f64(0.0) + result = f64(0.0) mut res_ptr := *u64(&result) - - res_parsing, pn = parser(s+' ') // TODO: need an extra char for now - //println(pn) - + res_parsing,pn = parser(s + ' ') // TODO: need an extra char for now + // println(pn) match res_parsing { PARSER_OK { - *res_ptr = converter( mut pn) + *res_ptr = converter(mut pn) } PARSER_PZERO { *res_ptr = DOUBLE_PLUS_ZERO @@ -597,7 +562,8 @@ pub fn atof64(s string) f64 { PARSER_MINF { *res_ptr = DOUBLE_MINUS_INFINITY } - else {} - } + else { + }} return result } + diff --git a/vlib/strconv/atofq.v b/vlib/strconv/atofq.v index 8e50f95d97..dfe925359e 100644 --- a/vlib/strconv/atofq.v +++ b/vlib/strconv/atofq.v @@ -16,112 +16,104 @@ * **********************************************************************/ module strconv - // same used in atof, here only for references -//const( -// DOUBLE_PLUS_ZERO = u64(0x0000000000000000) -// DOUBLE_MINUS_ZERO = 0x8000000000000000 -// DOUBLE_PLUS_INFINITY = 0x7FF0000000000000 -// DOUBLE_MINUS_INFINITY = 0xFFF0000000000000 - +// const( +// DOUBLE_PLUS_ZERO = u64(0x0000000000000000) +// DOUBLE_MINUS_ZERO = 0x8000000000000000 +// DOUBLE_PLUS_INFINITY = 0x7FF0000000000000 +// DOUBLE_MINUS_INFINITY = 0xFFF0000000000000 // atof_quick return a f64 number from a string in a quick way pub fn atof_quick(s string) f64 { - mut f := f64(0.0) // result - mut sign := f64(1.0) // result sign - mut i :=0 // index - + mut f := f64(0.0) // result + mut sign := f64(1.0) // result sign + mut i := 0 // index // skip white spaces for i < s.len && s[i] == ` ` { i++ } - - //check sign + // check sign if i < s.len { if s[i] == `-` { sign = -1.0 i++ - }else if s[i] == `+` { + } + else if s[i] == `+` { i++ } } - // infinite - if s[i] == `i` && i+2 < s.len && s[i+1] == `n` && s[i+2] == `f` { + if s[i] == `i` && i + 2 < s.len && s[i + 1] == `n` && s[i + 2] == `f` { mut d := *u64(&f) if sign > 0.0 { *d = DOUBLE_PLUS_INFINITY - }else{ + } + else { *d = DOUBLE_MINUS_INFINITY } return f } - // skip zeros - for i= s.len { mut d := *u64(&f) if sign > 0.0 { *d = DOUBLE_PLUS_ZERO - }else{ + } + else { *d = DOUBLE_MINUS_ZERO } return f } } - // integer part for i < s.len && (s[i] >= `0` && s[i] <= `9`) { f *= f64(10.0) f += f64(s[i] - `0`) i++ } - // decimal point if i < s.len && s[i] == `.` { i++ mut frac_mul := f64(0.1) for i < s.len && (s[i] >= `0` && s[i] <= `9`) { - f += f64(s[i] - `0`) * frac_mul + f += f64(s[i] - `0`) * frac_mul frac_mul *= f64(0.1) i++ } } - - // exponent management + // exponent management if i < s.len && (s[i] == `e` || s[i] == `E`) { i++ mut exp := 0 mut exp_sign := 1 - // negative exponent if i < s.len { if s[i] == `-` { exp_sign = -1 i++ - }else if s[i] == `+` { + } + else if s[i] == `+` { i++ } } - // skip zeros for i < s.len && s[i] == `0` { i++ } - for i < s.len && (s[i] >= `0` && s[i] <= `9`) { exp *= 10 exp += int(s[i] - `0`) i++ } - if exp_sign == 1 { if exp > pos_exp.len { mut d := *u64(&f) if sign > 0 { *d = DOUBLE_PLUS_INFINITY - }else{ + } + else { *d = DOUBLE_MINUS_INFINITY } return f @@ -129,14 +121,16 @@ pub fn atof_quick(s string) f64 { tmp_mul := f64(0.0) mut ptr_d := *u64(&tmp_mul) *ptr_d = pos_exp[exp] - //C.printf("exp: %d [0x%016llx] %f,",exp,pos_exp[exp],tmp_mul) + // C.printf("exp: %d [0x%016llx] %f,",exp,pos_exp[exp],tmp_mul) f = f * tmp_mul - } else { + } + else { if exp > neg_exp.len { mut d := *u64(&f) if (sign > 0) { *d = DOUBLE_PLUS_ZERO - }else{ + } + else { *d = DOUBLE_MINUS_ZERO } return f @@ -144,182 +138,18 @@ pub fn atof_quick(s string) f64 { tmp_mul := f64(0.0) mut ptr_d := *u64(&tmp_mul) *ptr_d = neg_exp[exp] - //C.printf("exp: %d [0x%016llx] %f,",exp,pos_exp[exp],tmp_mul) + // C.printf("exp: %d [0x%016llx] %f,",exp,pos_exp[exp],tmp_mul) f = f * tmp_mul } - } - f = f * sign return f } -const( +const ( // positive exp of 10 binary form -pos_exp = [ -0x3ff0000000000000, -0x4024000000000000,0x4059000000000000,0x408f400000000000,0x40c3880000000000, -0x40f86a0000000000,0x412e848000000000,0x416312d000000000,0x4197d78400000000, -0x41cdcd6500000000,0x4202a05f20000000,0x42374876e8000000,0x426d1a94a2000000, -0x42a2309ce5400000,0x42d6bcc41e900000,0x430c6bf526340000,0x4341c37937e08000, -0x4376345785d8a000,0x43abc16d674ec800,0x43e158e460913d00,0x4415af1d78b58c40, -0x444b1ae4d6e2ef50,0x4480f0cf064dd592,0x44b52d02c7e14af6,0x44ea784379d99db4, -0x45208b2a2c280291,0x4554adf4b7320335,0x4589d971e4fe8402,0x45c027e72f1f1281, -0x45f431e0fae6d721,0x46293e5939a08cea,0x465f8def8808b024,0x4693b8b5b5056e17, -0x46c8a6e32246c99c,0x46fed09bead87c03,0x4733426172c74d82,0x476812f9cf7920e3, -0x479e17b84357691b,0x47d2ced32a16a1b1,0x48078287f49c4a1d,0x483d6329f1c35ca5, -0x48725dfa371a19e7,0x48a6f578c4e0a061,0x48dcb2d6f618c879,0x4911efc659cf7d4c, -0x49466bb7f0435c9e,0x497c06a5ec5433c6,0x49b18427b3b4a05c,0x49e5e531a0a1c873, -0x4a1b5e7e08ca3a8f,0x4a511b0ec57e649a,0x4a8561d276ddfdc0,0x4ababa4714957d30, -0x4af0b46c6cdd6e3e,0x4b24e1878814c9ce,0x4b5a19e96a19fc41,0x4b905031e2503da9, -0x4bc4643e5ae44d13,0x4bf97d4df19d6057,0x4c2fdca16e04b86d,0x4c63e9e4e4c2f344, -0x4c98e45e1df3b015,0x4ccf1d75a5709c1b,0x4d03726987666191,0x4d384f03e93ff9f5, -0x4d6e62c4e38ff872,0x4da2fdbb0e39fb47,0x4dd7bd29d1c87a19,0x4e0dac74463a989f, -0x4e428bc8abe49f64,0x4e772ebad6ddc73d,0x4eacfa698c95390c,0x4ee21c81f7dd43a7, -0x4f16a3a275d49491,0x4f4c4c8b1349b9b5,0x4f81afd6ec0e1411,0x4fb61bcca7119916, -0x4feba2bfd0d5ff5b,0x502145b7e285bf99,0x50559725db272f7f,0x508afcef51f0fb5f, -0x50c0de1593369d1b,0x50f5159af8044462,0x512a5b01b605557b,0x516078e111c3556d, -0x5194971956342ac8,0x51c9bcdfabc1357a,0x5200160bcb58c16c,0x52341b8ebe2ef1c7, -0x526922726dbaae39,0x529f6b0f092959c7,0x52d3a2e965b9d81d,0x53088ba3bf284e24, -0x533eae8caef261ad,0x53732d17ed577d0c,0x53a7f85de8ad5c4f,0x53ddf67562d8b363, -0x5412ba095dc7701e,0x5447688bb5394c25,0x547d42aea2879f2e,0x54b249ad2594c37d, -0x54e6dc186ef9f45c,0x551c931e8ab87173,0x5551dbf316b346e8,0x558652efdc6018a2, -0x55bbe7abd3781eca,0x55f170cb642b133f,0x5625ccfe3d35d80e,0x565b403dcc834e12, -0x569108269fd210cb,0x56c54a3047c694fe,0x56fa9cbc59b83a3d,0x5730a1f5b8132466, -0x5764ca732617ed80,0x5799fd0fef9de8e0,0x57d03e29f5c2b18c,0x58044db473335def, -0x583961219000356b,0x586fb969f40042c5,0x58a3d3e2388029bb,0x58d8c8dac6a0342a, -0x590efb1178484135,0x59435ceaeb2d28c1,0x59783425a5f872f1,0x59ae412f0f768fad, -0x59e2e8bd69aa19cc,0x5a17a2ecc414a03f,0x5a4d8ba7f519c84f,0x5a827748f9301d32, -0x5ab7151b377c247e,0x5aecda62055b2d9e,0x5b22087d4358fc82,0x5b568a9c942f3ba3, -0x5b8c2d43b93b0a8c,0x5bc19c4a53c4e697,0x5bf6035ce8b6203d,0x5c2b843422e3a84d, -0x5c6132a095ce4930,0x5c957f48bb41db7c,0x5ccadf1aea12525b,0x5d00cb70d24b7379, -0x5d34fe4d06de5057,0x5d6a3de04895e46d,0x5da066ac2d5daec4,0x5dd4805738b51a75, -0x5e09a06d06e26112,0x5e400444244d7cab,0x5e7405552d60dbd6,0x5ea906aa78b912cc, -0x5edf485516e7577f,0x5f138d352e5096af,0x5f48708279e4bc5b,0x5f7e8ca3185deb72, -0x5fb317e5ef3ab327,0x5fe7dddf6b095ff1,0x601dd55745cbb7ed,0x6052a5568b9f52f4, -0x60874eac2e8727b1,0x60bd22573a28f19d,0x60f2357684599702,0x6126c2d4256ffcc3, -0x615c73892ecbfbf4,0x6191c835bd3f7d78,0x61c63a432c8f5cd6,0x61fbc8d3f7b3340c, -0x62315d847ad00087,0x6265b4e5998400a9,0x629b221effe500d4,0x62d0f5535fef2084, -0x630532a837eae8a5,0x633a7f5245e5a2cf,0x63708f936baf85c1,0x63a4b378469b6732, -0x63d9e056584240fe,0x64102c35f729689f,0x6444374374f3c2c6,0x647945145230b378, -0x64af965966bce056,0x64e3bdf7e0360c36,0x6518ad75d8438f43,0x654ed8d34e547314, -0x6583478410f4c7ec,0x65b819651531f9e8,0x65ee1fbe5a7e7861,0x6622d3d6f88f0b3d, -0x665788ccb6b2ce0c,0x668d6affe45f818f,0x66c262dfeebbb0f9,0x66f6fb97ea6a9d38, -0x672cba7de5054486,0x6761f48eaf234ad4,0x679671b25aec1d89,0x67cc0e1ef1a724eb, -0x680188d357087713,0x6835eb082cca94d7,0x686b65ca37fd3a0d,0x68a11f9e62fe4448, -0x68d56785fbbdd55a,0x690ac1677aad4ab1,0x6940b8e0acac4eaf,0x6974e718d7d7625a, -0x69aa20df0dcd3af1,0x69e0548b68a044d6,0x6a1469ae42c8560c,0x6a498419d37a6b8f, -0x6a7fe52048590673,0x6ab3ef342d37a408,0x6ae8eb0138858d0a,0x6b1f25c186a6f04c, -0x6b537798f4285630,0x6b88557f31326bbb,0x6bbe6adefd7f06aa,0x6bf302cb5e6f642a, -0x6c27c37e360b3d35,0x6c5db45dc38e0c82,0x6c9290ba9a38c7d1,0x6cc734e940c6f9c6, -0x6cfd022390f8b837,0x6d3221563a9b7323,0x6d66a9abc9424feb,0x6d9c5416bb92e3e6, -0x6dd1b48e353bce70,0x6e0621b1c28ac20c,0x6e3baa1e332d728f,0x6e714a52dffc6799, -0x6ea59ce797fb817f,0x6edb04217dfa61df,0x6f10e294eebc7d2c,0x6f451b3a2a6b9c76, -0x6f7a6208b5068394,0x6fb07d457124123d,0x6fe49c96cd6d16cc,0x7019c3bc80c85c7f, -0x70501a55d07d39cf,0x708420eb449c8843,0x70b9292615c3aa54,0x70ef736f9b3494e9, -0x7123a825c100dd11,0x7158922f31411456,0x718eb6bafd91596b,0x71c33234de7ad7e3, -0x71f7fec216198ddc,0x722dfe729b9ff153,0x7262bf07a143f6d4,0x72976ec98994f489, -0x72cd4a7bebfa31ab,0x73024e8d737c5f0b,0x7336e230d05b76cd,0x736c9abd04725481, -0x73a1e0b622c774d0,0x73d658e3ab795204,0x740bef1c9657a686,0x74417571ddf6c814, -0x7475d2ce55747a18,0x74ab4781ead1989e,0x74e10cb132c2ff63,0x75154fdd7f73bf3c, -0x754aa3d4df50af0b,0x7580a6650b926d67,0x75b4cffe4e7708c0,0x75ea03fde214caf1, -0x7620427ead4cfed6,0x7654531e58a03e8c,0x768967e5eec84e2f,0x76bfc1df6a7a61bb, -0x76f3d92ba28c7d15,0x7728cf768b2f9c5a,0x775f03542dfb8370,0x779362149cbd3226, -0x77c83a99c3ec7eb0,0x77fe494034e79e5c,0x7832edc82110c2f9,0x7867a93a2954f3b8, -0x789d9388b3aa30a5,0x78d27c35704a5e67,0x79071b42cc5cf601,0x793ce2137f743382, -0x79720d4c2fa8a031,0x79a6909f3b92c83d,0x79dc34c70a777a4d,0x7a11a0fc668aac70, -0x7a46093b802d578c,0x7a7b8b8a6038ad6f,0x7ab137367c236c65,0x7ae585041b2c477f, -0x7b1ae64521f7595e,0x7b50cfeb353a97db,0x7b8503e602893dd2,0x7bba44df832b8d46, -0x7bf06b0bb1fb384c,0x7c2485ce9e7a065f,0x7c59a742461887f6,0x7c9008896bcf54fa, -0x7cc40aabc6c32a38,0x7cf90d56b873f4c7,0x7d2f50ac6690f1f8,0x7d63926bc01a973b, -0x7d987706b0213d0a,0x7dce94c85c298c4c,0x7e031cfd3999f7b0,0x7e37e43c8800759c, -0x7e6ddd4baa009303,0x7ea2aa4f4a405be2,0x7ed754e31cd072da,0x7f0d2a1be4048f90, -0x7f423a516e82d9ba,0x7f76c8e5ca239029,0x7fac7b1f3cac7433,0x7fe1ccf385ebc8a0 -] - -// negative exp of 10 binary form -neg_exp = [ -0x3ff0000000000000, -0x3fb999999999999a,0x3f847ae147ae147b,0x3f50624dd2f1a9fc,0x3f1a36e2eb1c432d, -0x3ee4f8b588e368f1,0x3eb0c6f7a0b5ed8d,0x3e7ad7f29abcaf48,0x3e45798ee2308c3a, -0x3e112e0be826d695,0x3ddb7cdfd9d7bdbb,0x3da5fd7fe1796495,0x3d719799812dea11, -0x3d3c25c268497682,0x3d06849b86a12b9b,0x3cd203af9ee75616,0x3c9cd2b297d889bc, -0x3c670ef54646d497,0x3c32725dd1d243ac,0x3bfd83c94fb6d2ac,0x3bc79ca10c924223, -0x3b92e3b40a0e9b4f,0x3b5e392010175ee6,0x3b282db34012b251,0x3af357c299a88ea7, -0x3abef2d0f5da7dd9,0x3a88c240c4aecb14,0x3a53ce9a36f23c10,0x3a1fb0f6be506019, -0x39e95a5efea6b347,0x39b4484bfeebc2a0,0x398039d665896880,0x3949f623d5a8a733, -0x3914c4e977ba1f5c,0x38e09d8792fb4c49,0x38aa95a5b7f87a0f,0x38754484932d2e72, -0x3841039d428a8b8f,0x380b38fb9daa78e4,0x37d5c72fb1552d83,0x37a16c262777579c, -0x376be03d0bf225c7,0x37364cfda3281e39,0x3701d7314f534b61,0x36cc8b8218854567, -0x3696d601ad376ab9,0x366244ce242c5561,0x362d3ae36d13bbce,0x35f7624f8a762fd8, -0x35c2b50c6ec4f313,0x358dee7a4ad4b81f,0x3557f1fb6f10934c,0x352327fc58da0f70, -0x34eea6608e29b24d,0x34b8851a0b548ea4,0x34839dae6f76d883,0x344f62b0b257c0d2, -0x34191bc08eac9a41,0x33e41633a556e1ce,0x33b011c2eaabe7d8,0x3379b604aaaca626, -0x3344919d5556eb52,0x3310747ddddf22a8,0x32da53fc9631d10d,0x32a50ffd44f4a73d, -0x3270d9976a5d5297,0x323af5bf109550f2,0x32059165a6ddda5b,0x31d1411e1f17e1e3, -0x319b9b6364f30304,0x316615e91d8f359d,0x3131ab20e472914a,0x30fc45016d841baa, -0x30c69d9abe034955,0x309217aefe690777,0x305cf2b1970e7258,0x3027288e1271f513, -0x2ff286d80ec190dc,0x2fbda48ce468e7c7,0x2f87b6d71d20b96c,0x2f52f8ac174d6123, -0x2f1e5aacf2156838,0x2ee8488a5b445360,0x2eb36d3b7c36a91a,0x2e7f152bf9f10e90, -0x2e48ddbcc7f40ba6,0x2e13e497065cd61f,0x2ddfd424d6faf031,0x2da97683df2f268d, -0x2d745ecfe5bf520b,0x2d404bd984990e6f,0x2d0a12f5a0f4e3e5,0x2cd4dbf7b3f71cb7, -0x2ca0aff95cc5b092,0x2c6ab328946f80ea,0x2c355c2076bf9a55,0x2c0116805effaeaa, -0x2bcb5733cb32b111,0x2b95df5ca28ef40d,0x2b617f7d4ed8c33e,0x2b2bff2ee48e0530, -0x2af665bf1d3e6a8d,0x2ac1eaff4a98553d,0x2a8cab3210f3bb95,0x2a56ef5b40c2fc77, -0x2a225915cd68c9f9,0x29ed5b561574765b,0x29b77c44ddf6c516,0x2982c9d0b1923745, -0x294e0fb44f50586e,0x29180c903f7379f2,0x28e33d4032c2c7f5,0x28aec866b79e0cba, -0x2878a0522c7e7095,0x2843b374f06526de,0x280f8587e7083e30,0x27d9379fec069826, -0x27a42c7ff0054685,0x277023998cd10537,0x2739d28f47b4d525,0x2704a8729fc3ddb7, -0x26d086c219697e2c,0x269a71368f0f3047,0x2665275ed8d8f36c,0x2630ec4be0ad8f89, -0x25fb13ac9aaf4c0f,0x25c5a956e225d672,0x2591544581b7dec2,0x255bba08cf8c979d, -0x25262e6d72d6dfb0,0x24f1bebdf578b2f4,0x24bc6463225ab7ec,0x2486b6b5b5155ff0, -0x24522bc490dde65a,0x241d12d41afca3c3,0x23e7424348ca1c9c,0x23b29b69070816e3, -0x237dc574d80cf16b,0x2347d12a4670c123,0x23130dbb6b8d674f,0x22de7c5f127bd87e, -0x22a8637f41fcad32,0x227382cc34ca2428,0x223f37ad21436d0c,0x2208f9574dcf8a70, -0x21d3faac3e3fa1f3,0x219ff779fd329cb9,0x216992c7fdc216fa,0x2134756ccb01abfb, -0x21005df0a267bcc9,0x20ca2fe76a3f9475,0x2094f31f8832dd2a,0x2060c27fa028b0ef, -0x202ad0cc33744e4b,0x1ff573d68f903ea2,0x1fc1297872d9cbb5,0x1f8b758d848fac55, -0x1f55f7a46a0c89dd,0x1f2192e9ee706e4b,0x1eec1e43171a4a11,0x1eb67e9c127b6e74, -0x1e81fee341fc585d,0x1e4ccb0536608d61,0x1e1708d0f84d3de7,0x1de26d73f9d764b9, -0x1dad7becc2f23ac2,0x1d779657025b6235,0x1d42deac01e2b4f7,0x1d0e3113363787f2, -0x1cd8274291c6065b,0x1ca3529ba7d19eaf,0x1c6eea92a61c3118,0x1c38bba884e35a7a, -0x1c03c9539d82aec8,0x1bcfa885c8d117a6,0x1b99539e3a40dfb8,0x1b6442e4fb671960, -0x1b303583fc527ab3,0x1af9ef3993b72ab8,0x1ac4bf6142f8eefa,0x1a90991a9bfa58c8, -0x1a5a8e90f9908e0d,0x1a253eda614071a4,0x19f0ff151a99f483,0x19bb31bb5dc320d2, -0x1985c162b168e70e,0x1951678227871f3e,0x191bd8d03f3e9864,0x18e6470cff6546b6, -0x18b1d270cc51055f,0x187c83e7ad4e6efe,0x1846cfec8aa52598,0x18123ff06eea847a, -0x17dd331a4b10d3f6,0x17a75c1508da432b,0x1772b010d3e1cf56,0x173de6815302e556, -0x1707eb9aa8cf1dde,0x16d322e220a5b17e,0x169e9e369aa2b597,0x16687e92154ef7ac, -0x16339874ddd8c623,0x15ff5a549627a36c,0x15c91510781fb5f0,0x159410d9f9b2f7f3, -0x15600d7b2e28c65c,0x1529af2b7d0e0a2d,0x14f48c22ca71a1bd,0x14c0701bd527b498, -0x148a4cf9550c5426,0x14550a6110d6a9b8,0x1420d51a73deee2d,0x13eaee90b964b047, -0x13b58ba6fab6f36c,0x13813c85955f2923,0x134b9408eefea839,0x1316100725988694, -0x12e1a66c1e139edd,0x12ac3d79c9b8fe2e,0x12769794a160cb58,0x124212dd4de70913, -0x120ceafbafd80e85,0x11d72262f3133ed1,0x11a281e8c275cbda,0x116d9ca79d89462a, -0x1137b08617a104ee,0x1102f39e794d9d8b,0x10ce5297287c2f45,0x1098421286c9bf6b, -0x1063680ed23aff89,0x102f0ce4839198db,0x0ff8d71d360e13e2,0x0fc3df4a91a4dcb5, -0x0f8fcbaa82a16121,0x0f596fbb9bb44db4,0x0f245962e2f6a490,0x0ef047824f2bb6da, -0x0eba0c03b1df8af6,0x0e84d6695b193bf8,0x0e50ab877c142ffa,0x0e1aac0bf9b9e65c, -0x0de5566ffafb1eb0,0x0db111f32f2f4bc0,0x0d7b4feb7eb212cd,0x0d45d98932280f0a, -0x0d117ad428200c08,0x0cdbf7b9d9cce00d,0x0ca65fc7e170b33e,0x0c71e6398126f5cb, -0x0c3ca38f350b22df,0x0c06e93f5da2824c,0x0bd25432b14ecea3,0x0b9d53844ee47dd1, -0x0b677603725064a8,0x0b32c4cf8ea6b6ec,0x0afe07b27dd78b14,0x0ac8062864ac6f43, -0x0a9338205089f29c,0x0a5ec033b40fea93,0x0a2899c2f6732210,0x09f3ae3591f5b4d9, -0x09bf7d228322baf5,0x098930e868e89591,0x0954272053ed4474,0x09201f4d0ff10390, -0x08e9cbae7fe805b3,0x08b4a2f1ffecd15c,0x0880825b3323dab0,0x084a6a2b85062ab3, -0x081521bc6a6b555c,0x07e0e7c9eebc444a,0x07ab0c764ac6d3a9,0x0775a391d56bdc87, -0x07414fa7ddefe3a0,0x070bb2a62fe638ff,0x06d62884f31e93ff,0x06a1ba03f5b21000, -0x066c5cd322b67fff,0x0636b0a8e891ffff,0x060226ed86db3333,0x05cd0b15a491eb84, -0x05973c115074bc6a,0x05629674405d6388,0x052dbd86cd6238d9,0x04f7cad23de82d7b, -0x04c308a831868ac9,0x048e74404f3daadb,0x04585d003f6488af,0x04237d99cc506d59, -0x03ef2f5c7a1a488e,0x03b8f2b061aea072,0x0383f559e7bee6c1,0x034feef63f97d79c, -0x03198bf832dfdfb0,0x02e46ff9c24cb2f3,0x02b059949b708f29,0x027a28edc580e50e, -0x0244ed8b04671da5,0x0210be08d0527e1d,0x01dac9a7b3b7302f,0x01a56e1fc2f8f359, -0x017124e63593f5e1,0x013b6e3d22865634,0x0105f1ca820511c3,0x00d18e3b9b374169, -0x009c16c5c5253575,0x0066789e3750f791,0x0031fa182c40c60d,0x000730d67819e8d2, -0x0000b8157268fdaf,0x000012688b70e62b,0x000001d74124e3d1,0x0000002f201d49fb, -0x00000004b6695433,0x0000000078a42205,0x000000000c1069cd,0x000000000134d761, -0x00000000001ee257,0x00000000000316a2,0x0000000000004f10,0x00000000000007e8, -0x00000000000000ca,0x0000000000000014,0x0000000000000002 -] + pos_exp = [0x3ff0000000000000, 0x4024000000000000, 0x4059000000000000, 0x408f400000000000, 0x40c3880000000000, 0x40f86a0000000000, 0x412e848000000000, 0x416312d000000000, 0x4197d78400000000, 0x41cdcd6500000000, 0x4202a05f20000000, 0x42374876e8000000, 0x426d1a94a2000000, 0x42a2309ce5400000, 0x42d6bcc41e900000, 0x430c6bf526340000, 0x4341c37937e08000, 0x4376345785d8a000, 0x43abc16d674ec800, 0x43e158e460913d00, 0x4415af1d78b58c40, 0x444b1ae4d6e2ef50, 0x4480f0cf064dd592, 0x44b52d02c7e14af6, 0x44ea784379d99db4, 0x45208b2a2c280291, 0x4554adf4b7320335, 0x4589d971e4fe8402, 0x45c027e72f1f1281, 0x45f431e0fae6d721, 0x46293e5939a08cea, 0x465f8def8808b024, 0x4693b8b5b5056e17, 0x46c8a6e32246c99c, 0x46fed09bead87c03, 0x4733426172c74d82, 0x476812f9cf7920e3, 0x479e17b84357691b, 0x47d2ced32a16a1b1, 0x48078287f49c4a1d, 0x483d6329f1c35ca5, 0x48725dfa371a19e7, 0x48a6f578c4e0a061, 0x48dcb2d6f618c879, 0x4911efc659cf7d4c, 0x49466bb7f0435c9e, 0x497c06a5ec5433c6, 0x49b18427b3b4a05c, 0x49e5e531a0a1c873, 0x4a1b5e7e08ca3a8f, 0x4a511b0ec57e649a, 0x4a8561d276ddfdc0, 0x4ababa4714957d30, 0x4af0b46c6cdd6e3e, 0x4b24e1878814c9ce, 0x4b5a19e96a19fc41, 0x4b905031e2503da9, 0x4bc4643e5ae44d13, 0x4bf97d4df19d6057, 0x4c2fdca16e04b86d, 0x4c63e9e4e4c2f344, 0x4c98e45e1df3b015, 0x4ccf1d75a5709c1b, 0x4d03726987666191, 0x4d384f03e93ff9f5, 0x4d6e62c4e38ff872, 0x4da2fdbb0e39fb47, 0x4dd7bd29d1c87a19, 0x4e0dac74463a989f, 0x4e428bc8abe49f64, 0x4e772ebad6ddc73d, 0x4eacfa698c95390c, 0x4ee21c81f7dd43a7, 0x4f16a3a275d49491, 0x4f4c4c8b1349b9b5, 0x4f81afd6ec0e1411, 0x4fb61bcca7119916, 0x4feba2bfd0d5ff5b, 0x502145b7e285bf99, 0x50559725db272f7f, 0x508afcef51f0fb5f, 0x50c0de1593369d1b, 0x50f5159af8044462, 0x512a5b01b605557b, 0x516078e111c3556d, 0x5194971956342ac8, 0x51c9bcdfabc1357a, 0x5200160bcb58c16c, 0x52341b8ebe2ef1c7, 0x526922726dbaae39, 0x529f6b0f092959c7, 0x52d3a2e965b9d81d, 0x53088ba3bf284e24, 0x533eae8caef261ad, 0x53732d17ed577d0c, 0x53a7f85de8ad5c4f, 0x53ddf67562d8b363, 0x5412ba095dc7701e, 0x5447688bb5394c25, 0x547d42aea2879f2e, 0x54b249ad2594c37d, 0x54e6dc186ef9f45c, 0x551c931e8ab87173, 0x5551dbf316b346e8, 0x558652efdc6018a2, 0x55bbe7abd3781eca, 0x55f170cb642b133f, 0x5625ccfe3d35d80e, 0x565b403dcc834e12, 0x569108269fd210cb, 0x56c54a3047c694fe, 0x56fa9cbc59b83a3d, 0x5730a1f5b8132466, 0x5764ca732617ed80, 0x5799fd0fef9de8e0, 0x57d03e29f5c2b18c, 0x58044db473335def, 0x583961219000356b, 0x586fb969f40042c5, 0x58a3d3e2388029bb, 0x58d8c8dac6a0342a, 0x590efb1178484135, 0x59435ceaeb2d28c1, 0x59783425a5f872f1, 0x59ae412f0f768fad, 0x59e2e8bd69aa19cc, 0x5a17a2ecc414a03f, 0x5a4d8ba7f519c84f, 0x5a827748f9301d32, 0x5ab7151b377c247e, 0x5aecda62055b2d9e, 0x5b22087d4358fc82, 0x5b568a9c942f3ba3, 0x5b8c2d43b93b0a8c, 0x5bc19c4a53c4e697, 0x5bf6035ce8b6203d, 0x5c2b843422e3a84d, 0x5c6132a095ce4930, 0x5c957f48bb41db7c, 0x5ccadf1aea12525b, 0x5d00cb70d24b7379, 0x5d34fe4d06de5057, 0x5d6a3de04895e46d, 0x5da066ac2d5daec4, 0x5dd4805738b51a75, 0x5e09a06d06e26112, 0x5e400444244d7cab, 0x5e7405552d60dbd6, 0x5ea906aa78b912cc, 0x5edf485516e7577f, 0x5f138d352e5096af, 0x5f48708279e4bc5b, 0x5f7e8ca3185deb72, 0x5fb317e5ef3ab327, 0x5fe7dddf6b095ff1, 0x601dd55745cbb7ed, 0x6052a5568b9f52f4, 0x60874eac2e8727b1, 0x60bd22573a28f19d, 0x60f2357684599702, 0x6126c2d4256ffcc3, 0x615c73892ecbfbf4, 0x6191c835bd3f7d78, 0x61c63a432c8f5cd6, 0x61fbc8d3f7b3340c, 0x62315d847ad00087, 0x6265b4e5998400a9, 0x629b221effe500d4, 0x62d0f5535fef2084, 0x630532a837eae8a5, 0x633a7f5245e5a2cf, 0x63708f936baf85c1, 0x63a4b378469b6732, 0x63d9e056584240fe, 0x64102c35f729689f, 0x6444374374f3c2c6, 0x647945145230b378, 0x64af965966bce056, 0x64e3bdf7e0360c36, 0x6518ad75d8438f43, 0x654ed8d34e547314, 0x6583478410f4c7ec, 0x65b819651531f9e8, 0x65ee1fbe5a7e7861, 0x6622d3d6f88f0b3d, 0x665788ccb6b2ce0c, 0x668d6affe45f818f, 0x66c262dfeebbb0f9, 0x66f6fb97ea6a9d38, 0x672cba7de5054486, 0x6761f48eaf234ad4, 0x679671b25aec1d89, 0x67cc0e1ef1a724eb, 0x680188d357087713, 0x6835eb082cca94d7, 0x686b65ca37fd3a0d, 0x68a11f9e62fe4448, 0x68d56785fbbdd55a, 0x690ac1677aad4ab1, 0x6940b8e0acac4eaf, 0x6974e718d7d7625a, 0x69aa20df0dcd3af1, 0x69e0548b68a044d6, 0x6a1469ae42c8560c, 0x6a498419d37a6b8f, 0x6a7fe52048590673, 0x6ab3ef342d37a408, 0x6ae8eb0138858d0a, 0x6b1f25c186a6f04c, 0x6b537798f4285630, 0x6b88557f31326bbb, 0x6bbe6adefd7f06aa, 0x6bf302cb5e6f642a, 0x6c27c37e360b3d35, 0x6c5db45dc38e0c82, 0x6c9290ba9a38c7d1, 0x6cc734e940c6f9c6, 0x6cfd022390f8b837, 0x6d3221563a9b7323, 0x6d66a9abc9424feb, 0x6d9c5416bb92e3e6, 0x6dd1b48e353bce70, 0x6e0621b1c28ac20c, 0x6e3baa1e332d728f, 0x6e714a52dffc6799, 0x6ea59ce797fb817f, 0x6edb04217dfa61df, 0x6f10e294eebc7d2c, 0x6f451b3a2a6b9c76, 0x6f7a6208b5068394, 0x6fb07d457124123d, 0x6fe49c96cd6d16cc, 0x7019c3bc80c85c7f, 0x70501a55d07d39cf, 0x708420eb449c8843, 0x70b9292615c3aa54, 0x70ef736f9b3494e9, 0x7123a825c100dd11, 0x7158922f31411456, 0x718eb6bafd91596b, 0x71c33234de7ad7e3, 0x71f7fec216198ddc, 0x722dfe729b9ff153, 0x7262bf07a143f6d4, 0x72976ec98994f489, 0x72cd4a7bebfa31ab, 0x73024e8d737c5f0b, 0x7336e230d05b76cd, 0x736c9abd04725481, 0x73a1e0b622c774d0, 0x73d658e3ab795204, 0x740bef1c9657a686, 0x74417571ddf6c814, 0x7475d2ce55747a18, 0x74ab4781ead1989e, 0x74e10cb132c2ff63, 0x75154fdd7f73bf3c, 0x754aa3d4df50af0b, 0x7580a6650b926d67, 0x75b4cffe4e7708c0, 0x75ea03fde214caf1, 0x7620427ead4cfed6, 0x7654531e58a03e8c, 0x768967e5eec84e2f, 0x76bfc1df6a7a61bb, 0x76f3d92ba28c7d15, 0x7728cf768b2f9c5a, 0x775f03542dfb8370, 0x779362149cbd3226, 0x77c83a99c3ec7eb0, 0x77fe494034e79e5c, 0x7832edc82110c2f9, 0x7867a93a2954f3b8, 0x789d9388b3aa30a5, 0x78d27c35704a5e67, 0x79071b42cc5cf601, 0x793ce2137f743382, 0x79720d4c2fa8a031, 0x79a6909f3b92c83d, 0x79dc34c70a777a4d, 0x7a11a0fc668aac70, 0x7a46093b802d578c, 0x7a7b8b8a6038ad6f, 0x7ab137367c236c65, 0x7ae585041b2c477f, 0x7b1ae64521f7595e, 0x7b50cfeb353a97db, 0x7b8503e602893dd2, 0x7bba44df832b8d46, 0x7bf06b0bb1fb384c, 0x7c2485ce9e7a065f, 0x7c59a742461887f6, 0x7c9008896bcf54fa, 0x7cc40aabc6c32a38, 0x7cf90d56b873f4c7, 0x7d2f50ac6690f1f8, 0x7d63926bc01a973b, 0x7d987706b0213d0a, 0x7dce94c85c298c4c, 0x7e031cfd3999f7b0, 0x7e37e43c8800759c, 0x7e6ddd4baa009303, 0x7ea2aa4f4a405be2, 0x7ed754e31cd072da, 0x7f0d2a1be4048f90, 0x7f423a516e82d9ba, 0x7f76c8e5ca239029, 0x7fac7b1f3cac7433, 0x7fe1ccf385ebc8a0] + // negative exp of 10 binary form + neg_exp = [0x3ff0000000000000, 0x3fb999999999999a, 0x3f847ae147ae147b, 0x3f50624dd2f1a9fc, 0x3f1a36e2eb1c432d, 0x3ee4f8b588e368f1, 0x3eb0c6f7a0b5ed8d, 0x3e7ad7f29abcaf48, 0x3e45798ee2308c3a, 0x3e112e0be826d695, 0x3ddb7cdfd9d7bdbb, 0x3da5fd7fe1796495, 0x3d719799812dea11, 0x3d3c25c268497682, 0x3d06849b86a12b9b, 0x3cd203af9ee75616, 0x3c9cd2b297d889bc, 0x3c670ef54646d497, 0x3c32725dd1d243ac, 0x3bfd83c94fb6d2ac, 0x3bc79ca10c924223, 0x3b92e3b40a0e9b4f, 0x3b5e392010175ee6, 0x3b282db34012b251, 0x3af357c299a88ea7, 0x3abef2d0f5da7dd9, 0x3a88c240c4aecb14, 0x3a53ce9a36f23c10, 0x3a1fb0f6be506019, 0x39e95a5efea6b347, 0x39b4484bfeebc2a0, 0x398039d665896880, 0x3949f623d5a8a733, 0x3914c4e977ba1f5c, 0x38e09d8792fb4c49, 0x38aa95a5b7f87a0f, 0x38754484932d2e72, 0x3841039d428a8b8f, 0x380b38fb9daa78e4, 0x37d5c72fb1552d83, 0x37a16c262777579c, 0x376be03d0bf225c7, 0x37364cfda3281e39, 0x3701d7314f534b61, 0x36cc8b8218854567, 0x3696d601ad376ab9, 0x366244ce242c5561, 0x362d3ae36d13bbce, 0x35f7624f8a762fd8, 0x35c2b50c6ec4f313, 0x358dee7a4ad4b81f, 0x3557f1fb6f10934c, 0x352327fc58da0f70, 0x34eea6608e29b24d, 0x34b8851a0b548ea4, 0x34839dae6f76d883, 0x344f62b0b257c0d2, 0x34191bc08eac9a41, 0x33e41633a556e1ce, 0x33b011c2eaabe7d8, 0x3379b604aaaca626, 0x3344919d5556eb52, 0x3310747ddddf22a8, 0x32da53fc9631d10d, 0x32a50ffd44f4a73d, 0x3270d9976a5d5297, 0x323af5bf109550f2, 0x32059165a6ddda5b, 0x31d1411e1f17e1e3, 0x319b9b6364f30304, 0x316615e91d8f359d, 0x3131ab20e472914a, 0x30fc45016d841baa, 0x30c69d9abe034955, 0x309217aefe690777, 0x305cf2b1970e7258, 0x3027288e1271f513, 0x2ff286d80ec190dc, 0x2fbda48ce468e7c7, 0x2f87b6d71d20b96c, 0x2f52f8ac174d6123, 0x2f1e5aacf2156838, 0x2ee8488a5b445360, 0x2eb36d3b7c36a91a, 0x2e7f152bf9f10e90, 0x2e48ddbcc7f40ba6, 0x2e13e497065cd61f, 0x2ddfd424d6faf031, 0x2da97683df2f268d, 0x2d745ecfe5bf520b, 0x2d404bd984990e6f, 0x2d0a12f5a0f4e3e5, 0x2cd4dbf7b3f71cb7, 0x2ca0aff95cc5b092, 0x2c6ab328946f80ea, 0x2c355c2076bf9a55, 0x2c0116805effaeaa, 0x2bcb5733cb32b111, 0x2b95df5ca28ef40d, 0x2b617f7d4ed8c33e, 0x2b2bff2ee48e0530, 0x2af665bf1d3e6a8d, 0x2ac1eaff4a98553d, 0x2a8cab3210f3bb95, 0x2a56ef5b40c2fc77, 0x2a225915cd68c9f9, 0x29ed5b561574765b, 0x29b77c44ddf6c516, 0x2982c9d0b1923745, 0x294e0fb44f50586e, 0x29180c903f7379f2, 0x28e33d4032c2c7f5, 0x28aec866b79e0cba, 0x2878a0522c7e7095, 0x2843b374f06526de, 0x280f8587e7083e30, 0x27d9379fec069826, 0x27a42c7ff0054685, 0x277023998cd10537, 0x2739d28f47b4d525, 0x2704a8729fc3ddb7, 0x26d086c219697e2c, 0x269a71368f0f3047, 0x2665275ed8d8f36c, 0x2630ec4be0ad8f89, 0x25fb13ac9aaf4c0f, 0x25c5a956e225d672, 0x2591544581b7dec2, 0x255bba08cf8c979d, 0x25262e6d72d6dfb0, 0x24f1bebdf578b2f4, 0x24bc6463225ab7ec, 0x2486b6b5b5155ff0, 0x24522bc490dde65a, 0x241d12d41afca3c3, 0x23e7424348ca1c9c, 0x23b29b69070816e3, 0x237dc574d80cf16b, 0x2347d12a4670c123, 0x23130dbb6b8d674f, 0x22de7c5f127bd87e, 0x22a8637f41fcad32, 0x227382cc34ca2428, 0x223f37ad21436d0c, 0x2208f9574dcf8a70, 0x21d3faac3e3fa1f3, 0x219ff779fd329cb9, 0x216992c7fdc216fa, 0x2134756ccb01abfb, 0x21005df0a267bcc9, 0x20ca2fe76a3f9475, 0x2094f31f8832dd2a, 0x2060c27fa028b0ef, 0x202ad0cc33744e4b, 0x1ff573d68f903ea2, 0x1fc1297872d9cbb5, 0x1f8b758d848fac55, 0x1f55f7a46a0c89dd, 0x1f2192e9ee706e4b, 0x1eec1e43171a4a11, 0x1eb67e9c127b6e74, 0x1e81fee341fc585d, 0x1e4ccb0536608d61, 0x1e1708d0f84d3de7, 0x1de26d73f9d764b9, 0x1dad7becc2f23ac2, 0x1d779657025b6235, 0x1d42deac01e2b4f7, 0x1d0e3113363787f2, 0x1cd8274291c6065b, 0x1ca3529ba7d19eaf, 0x1c6eea92a61c3118, 0x1c38bba884e35a7a, 0x1c03c9539d82aec8, 0x1bcfa885c8d117a6, 0x1b99539e3a40dfb8, 0x1b6442e4fb671960, 0x1b303583fc527ab3, 0x1af9ef3993b72ab8, 0x1ac4bf6142f8eefa, 0x1a90991a9bfa58c8, 0x1a5a8e90f9908e0d, 0x1a253eda614071a4, 0x19f0ff151a99f483, 0x19bb31bb5dc320d2, 0x1985c162b168e70e, 0x1951678227871f3e, 0x191bd8d03f3e9864, 0x18e6470cff6546b6, 0x18b1d270cc51055f, 0x187c83e7ad4e6efe, 0x1846cfec8aa52598, 0x18123ff06eea847a, 0x17dd331a4b10d3f6, 0x17a75c1508da432b, 0x1772b010d3e1cf56, 0x173de6815302e556, 0x1707eb9aa8cf1dde, 0x16d322e220a5b17e, 0x169e9e369aa2b597, 0x16687e92154ef7ac, 0x16339874ddd8c623, 0x15ff5a549627a36c, 0x15c91510781fb5f0, 0x159410d9f9b2f7f3, 0x15600d7b2e28c65c, 0x1529af2b7d0e0a2d, 0x14f48c22ca71a1bd, 0x14c0701bd527b498, 0x148a4cf9550c5426, 0x14550a6110d6a9b8, 0x1420d51a73deee2d, 0x13eaee90b964b047, 0x13b58ba6fab6f36c, 0x13813c85955f2923, 0x134b9408eefea839, 0x1316100725988694, 0x12e1a66c1e139edd, 0x12ac3d79c9b8fe2e, 0x12769794a160cb58, 0x124212dd4de70913, 0x120ceafbafd80e85, 0x11d72262f3133ed1, 0x11a281e8c275cbda, 0x116d9ca79d89462a, 0x1137b08617a104ee, 0x1102f39e794d9d8b, 0x10ce5297287c2f45, 0x1098421286c9bf6b, 0x1063680ed23aff89, 0x102f0ce4839198db, 0x0ff8d71d360e13e2, 0x0fc3df4a91a4dcb5, 0x0f8fcbaa82a16121, 0x0f596fbb9bb44db4, 0x0f245962e2f6a490, 0x0ef047824f2bb6da, 0x0eba0c03b1df8af6, 0x0e84d6695b193bf8, 0x0e50ab877c142ffa, 0x0e1aac0bf9b9e65c, 0x0de5566ffafb1eb0, 0x0db111f32f2f4bc0, 0x0d7b4feb7eb212cd, 0x0d45d98932280f0a, 0x0d117ad428200c08, 0x0cdbf7b9d9cce00d, 0x0ca65fc7e170b33e, 0x0c71e6398126f5cb, 0x0c3ca38f350b22df, 0x0c06e93f5da2824c, 0x0bd25432b14ecea3, 0x0b9d53844ee47dd1, 0x0b677603725064a8, 0x0b32c4cf8ea6b6ec, 0x0afe07b27dd78b14, 0x0ac8062864ac6f43, 0x0a9338205089f29c, 0x0a5ec033b40fea93, 0x0a2899c2f6732210, 0x09f3ae3591f5b4d9, 0x09bf7d228322baf5, 0x098930e868e89591, 0x0954272053ed4474, 0x09201f4d0ff10390, 0x08e9cbae7fe805b3, 0x08b4a2f1ffecd15c, 0x0880825b3323dab0, 0x084a6a2b85062ab3, 0x081521bc6a6b555c, 0x07e0e7c9eebc444a, 0x07ab0c764ac6d3a9, 0x0775a391d56bdc87, 0x07414fa7ddefe3a0, 0x070bb2a62fe638ff, 0x06d62884f31e93ff, 0x06a1ba03f5b21000, 0x066c5cd322b67fff, 0x0636b0a8e891ffff, 0x060226ed86db3333, 0x05cd0b15a491eb84, 0x05973c115074bc6a, 0x05629674405d6388, 0x052dbd86cd6238d9, 0x04f7cad23de82d7b, 0x04c308a831868ac9, 0x048e74404f3daadb, 0x04585d003f6488af, 0x04237d99cc506d59, 0x03ef2f5c7a1a488e, 0x03b8f2b061aea072, 0x0383f559e7bee6c1, 0x034feef63f97d79c, 0x03198bf832dfdfb0, 0x02e46ff9c24cb2f3, 0x02b059949b708f29, 0x027a28edc580e50e, 0x0244ed8b04671da5, 0x0210be08d0527e1d, 0x01dac9a7b3b7302f, 0x01a56e1fc2f8f359, 0x017124e63593f5e1, 0x013b6e3d22865634, 0x0105f1ca820511c3, 0x00d18e3b9b374169, 0x009c16c5c5253575, 0x0066789e3750f791, 0x0031fa182c40c60d, 0x000730d67819e8d2, 0x0000b8157268fdaf, 0x000012688b70e62b, 0x000001d74124e3d1, 0x0000002f201d49fb, 0x00000004b6695433, 0x0000000078a42205, 0x000000000c1069cd, 0x000000000134d761, 0x00000000001ee257, 0x00000000000316a2, 0x0000000000004f10, 0x00000000000007e8, 0x00000000000000ca, 0x0000000000000014, 0x0000000000000002] ) + diff --git a/vlib/strconv/atoi.v b/vlib/strconv/atoi.v index da8c20f87e..942445229e 100644 --- a/vlib/strconv/atoi.v +++ b/vlib/strconv/atoi.v @@ -1,18 +1,15 @@ // 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. - // TODO: use optionals, or some way to return default with error. - module strconv - -const( - // int_size is the size in bits of an int or uint value. - // int_size = 32 << (~u32(0) >> 63) - // max_u64 = u64(u64(1 << 63) - 1) +const ( +// int_size is the size in bits of an int or uint value. +// int_size = 32 << (~u32(0) >> 63) +// max_u64 = u64(u64(1 << 63) - 1) int_size = 32 - max_u64 = u64(C.UINT64_MAX) // use this until we add support + max_u64 = u64(C.UINT64_MAX) // use this until we add support ) fn byte_to_lower(c byte) byte { @@ -24,17 +21,16 @@ fn byte_to_lower(c byte) byte { pub fn common_parse_uint(s string, _base int, _bit_size int, error_on_non_digit bool, error_on_high_digit bool) u64 { mut bit_size := _bit_size mut base := _base - if s.len < 1 || !underscore_ok(s) { // return error('parse_uint: syntax error $s') return u64(0) } - base0 := base == 0 mut start_index := 0 if 2 <= base && base <= 36 { // valid base; nothing to do - } else if base == 0 { + } + else if base == 0 { // Look for octal, hex prefix. base = 10 if s[0] == `0` { @@ -51,39 +47,34 @@ pub fn common_parse_uint(s string, _base int, _bit_size int, error_on_non_digit start_index += 2 } // manage leading zeros in decimal base's numbers - else if s.len >=2 && ( s[1] >= `0` && s[1] <= `9`) { - base = 10 - start_index ++ + else if s.len >= 2 && (s[1] >= `0` && s[1] <= `9`) { + base = 10 + start_index++ } else { base = 8 start_index++ } } - } else { + } + else { // return error('parse_uint: base error $s - $base') return u64(0) } - if bit_size == 0 { bit_size = int_size - } else if bit_size < 0 || bit_size > 64 { + } + else if bit_size < 0 || bit_size > 64 { // return error('parse_uint: bitsize error $s - $bit_size') return u64(0) } - // Cutoff is the smallest number such that cutoff*base > maxUint64. // Use compile-time constants for common cases. - cutoff := max_u64/u64(base) + u64(1) - max_val := if bit_size == 64 { - max_u64 - } else { - (u64(1)<= cutoff { // return error('parse_int: range error $s0') - return i64(cutoff - u64(1)) + return i64(cutoff - u64(1)) } if neg && un > cutoff { // return error('parse_int: range error $s0') return -i64(cutoff) } - return if neg { -i64(un) } else { i64(un) } } + // parse_int interprets a string s in the given base (0, 2 to 36) and // bit size (0 to 64) and returns the corresponding value i. // @@ -199,34 +193,29 @@ pub fn parse_int(_s string, base int, _bit_size int) i64 { // atoi is equivalent to parse_int(s, 10, 0), converted to type int. pub fn atoi(s string) int { - if (int_size == 32 && (0 < s.len && s.len < 10)) || - (int_size == 64 && (0 < s.len && s.len < 19)) { + if (int_size == 32 && (0 < s.len && s.len < 10)) || (int_size == 64 && (0 < s.len && s.len < 19)) { // Fast path for small integers that fit int type. mut start_idx := 0 if s[0] == `-` || s[0] == `+` { start_idx++ - if s.len-start_idx < 1 { + if s.len - start_idx < 1 { // return 0, &NumError{fnAtoi, s0, ErrSyntax} return 0 } } - mut n := 0 - for i in start_idx..s.len { - ch := s[i] - `0` + for i in start_idx .. s.len { + ch := s[i] - `0` if ch > 9 { // return 0, &NumError{fnAtoi, s0, ErrSyntax} return 0 } - n = n*10 + int(ch) + n = n * 10 + int(ch) } - return if s[0] == `-` { -n } else { n } } - // Slow path for invalid, big, or underscored integers. int64 := parse_int(s, 10, 0) - return int(int64) } @@ -241,26 +230,21 @@ fn underscore_ok(s string) bool { // ! for none of the above. mut saw := `^` mut i := 0 - // Optional sign. if s.len >= 1 && (s[0] == `-` || s[0] == `+`) { i++ } - // Optional base prefix. mut hex := false - if s.len-i >= 2 && s[i] == `0` && - (byte_to_lower(s[i+1]) == `b` || byte_to_lower(s[i+1]) == `o` || byte_to_lower(s[i+1]) == `x`) { + if s.len - i >= 2 && s[i] == `0` && (byte_to_lower(s[i + 1]) == `b` || byte_to_lower(s[i + 1]) == `o` || byte_to_lower(s[i + 1]) == `x`) { saw = `0` // base prefix counts as a digit for "underscore as digit separator" - hex = byte_to_lower(s[i+1]) == `x` - i+=2 + hex = byte_to_lower(s[i + 1]) == `x` + i += 2 } - // Number proper. for ; i < s.len; i++ { // Digits are always okay. - if (`0` <= s[i] && s[i] <= `9`) || - (hex && `a` <= byte_to_lower(s[i]) && byte_to_lower(s[i]) <= `f`) { + if (`0` <= s[i] && s[i] <= `9`) || (hex && `a` <= byte_to_lower(s[i]) && byte_to_lower(s[i]) <= `f`) { saw = `0` continue } diff --git a/vlib/strings/builder_c.v b/vlib/strings/builder_c.v index 5356fa05a3..9c7fad81c7 100644 --- a/vlib/strings/builder_c.v +++ b/vlib/strings/builder_c.v @@ -1,19 +1,18 @@ // 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 strings pub struct Builder { mut: - buf []byte + buf []byte pub mut: - len int - initial_size int = 1 + len int + initial_size int=1 } pub fn new_builder(initial_size int) Builder { - return Builder { + return Builder{ buf: make(0, initial_size, 1) initial_size: initial_size } @@ -31,30 +30,33 @@ pub fn (b mut Builder) write_b(data byte) { pub fn (b mut Builder) write(s string) { b.buf.push_many(s.str, s.len) - //for c in s { - //b.buf << c - //} - //b.buf << []byte(s) // TODO + // for c in s { + // b.buf << c + // } + // b.buf << []byte(s) // TODO b.len += s.len } pub fn (b mut Builder) writeln(s string) { - //for c in s { - //b.buf << c - //} + // for c in s { + // b.buf << c + // } b.buf.push_many(s.str, s.len) - //b.buf << []byte(s) // TODO + // b.buf << []byte(s) // TODO b.buf << `\n` b.len += s.len + 1 } pub fn (b mut Builder) str() string { b.buf << `\0` - return string(b.buf, b.len) + return string(b.buf,b.len) } pub fn (b mut Builder) free() { - unsafe{ free(b.buf.data) } + unsafe{ + free(b.buf.data) + } b.buf = make(0, b.initial_size, 1) b.len = 0 } + diff --git a/vlib/strings/similarity.v b/vlib/strings/similarity.v index 9e19b506c7..30c5730db0 100644 --- a/vlib/strings/similarity.v +++ b/vlib/strings/similarity.v @@ -1,7 +1,5 @@ module strings - -//#-js - +// #-js // use levenshtein distance algorithm to calculate // the distance between between two strings (lower is closer) pub fn levenshtein_distance(a, b string) int { @@ -66,3 +64,4 @@ pub fn dice_coefficient(s1, s2 string) f32 { } return (2.0 * intersection_size) / (f32(a.len) + f32(b.len) - 2) } + diff --git a/vlib/strings/strings.v b/vlib/strings/strings.v index d0507142ea..71f450865c 100644 --- a/vlib/strings/strings.v +++ b/vlib/strings/strings.v @@ -6,6 +6,6 @@ pub fn repeat(c byte, n int) string { } mut arr := [c].repeat(n + 1) arr[n] = `\0` - return string(arr, n) + return string(arr,n) } diff --git a/vlib/term/can_show_color.v b/vlib/term/can_show_color.v index 568280a981..0d9701760d 100644 --- a/vlib/term/can_show_color.v +++ b/vlib/term/can_show_color.v @@ -18,20 +18,12 @@ fn supports_escape_sequences(fd int) bool { } } -////////////////////////////////////////////// - +// //////////////////////////////////////////// pub fn ok_message(s string) string { - return if can_show_color_on_stdout() { - green( s ) - }else{ - s - } + return if can_show_color_on_stdout() { green(s) } else { s } } pub fn fail_message(s string) string { - return if can_show_color_on_stdout() { - red( s ) - }else{ - s - } + return if can_show_color_on_stdout() { red(s) } else { s } } + diff --git a/vlib/term/colors.v b/vlib/term/colors.v index 5639e6bb42..7feb84abd2 100644 --- a/vlib/term/colors.v +++ b/vlib/term/colors.v @@ -1,7 +1,6 @@ // 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 term pub fn format(msg, open, close string) string { @@ -21,19 +20,11 @@ pub fn bg_rgb(r, g, b int, msg string) string { } pub fn hex(hex int, msg string) string { - return format_rgb( - hex >> 16, - hex >> 8 & 0xFF, - hex & 0xFF, - msg, '38', '39') + return format_rgb(hex>>16, hex>>8 & 0xFF, hex & 0xFF, msg, '38', '39') } pub fn bg_hex(hex int, msg string) string { - return format_rgb( - hex >> 16, - hex >> 8 & 0xFF, - hex & 0xFF, - msg, '48', '49') + return format_rgb(hex>>16, hex>>8 & 0xFF, hex & 0xFF, msg, '48', '49') } pub fn bg_black(msg string) string { @@ -199,3 +190,4 @@ pub fn yellow(msg string) string { pub fn bright_yellow(msg string) string { return format(msg, '93', '39') } + diff --git a/vlib/term/colors_nix.v b/vlib/term/colors_nix.v index 37274c1957..c0989f34f8 100644 --- a/vlib/term/colors_nix.v +++ b/vlib/term/colors_nix.v @@ -1,6 +1,5 @@ // 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 term diff --git a/vlib/term/control.v b/vlib/term/control.v index 0f34b845b0..c19ec2e2e0 100644 --- a/vlib/term/control.v +++ b/vlib/term/control.v @@ -1,24 +1,20 @@ // 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 term - // Sources for ANSI Control Sequences // https://github.com/RajeshPatkarInstitute/Panim // https://www.gnu.org/software/screen/manual/html_node/Control-Sequences.html // https://en.wikipedia.org/wiki/ANSI_escape_code - // Support for Windows // https://en.wikipedia.org/wiki/ANSI.SYS // #include // C.SetConsoleMode(ENABLE_VIRTUAL_TERMINAL_INPUT) - // Setting cursor to the given position // x is the x coordinate // y is the y coordinate -pub fn set_cursor_position(x int,y int) { - print('\x1b[$y;$x'+'H') +pub fn set_cursor_position(x int, y int) { + print('\x1b[$y;$x' + 'H') } // n is number of cells @@ -26,24 +22,24 @@ pub fn set_cursor_position(x int,y int) { // direction: B is down / South // direction: C is forward / East // direction: D is backward / West -pub fn move(n int,direction string) { - print('\x1b[$n$direction') +pub fn move(n int, direction string) { + print('\x1b[$n$direction') } pub fn cursor_up(n int) { - move(n,'A') + move(n, 'A') } pub fn cursor_down(n int) { - move(n,'B') + move(n, 'B') } pub fn cursor_forward(n int) { - move(n,'C') + move(n, 'C') } pub fn cursor_back(n int) { - move(n,'D') + move(n, 'D') } // type: 0 -> current cursor position to end of the screen @@ -51,27 +47,23 @@ pub fn cursor_back(n int) { // type: 2 -> clears entire screen // type: 3 -> clears entire screen and also delete scrollback buffer pub fn erase_display(t string) { - print('\x1b[' + t + 'J') + print('\x1b[' + t + 'J') } -pub fn erase_toend() -{ - erase_display('0') +pub fn erase_toend() { + erase_display('0') } -pub fn erase_tobeg() -{ - erase_display('1') +pub fn erase_tobeg() { + erase_display('1') } -pub fn erase_clear() -{ - erase_display('2') +pub fn erase_clear() { + erase_display('2') } -pub fn erase_del_clear() -{ - erase_display('3') +pub fn erase_del_clear() { + erase_display('3') } // type: 0 -> current cursor position to end of the line @@ -79,32 +71,28 @@ pub fn erase_del_clear() // type: 2 -> clears entire line // Note: Cursor position does not change pub fn erase_line(t string) { - print('\x1b[' + t + 'K') + print('\x1b[' + t + 'K') } -pub fn erase_line_toend() -{ - erase_line('0') +pub fn erase_line_toend() { + erase_line('0') } -pub fn erase_line_tobeg() -{ - erase_line('1') +pub fn erase_line_tobeg() { + erase_line('1') } -pub fn erase_line_clear() -{ - erase_line('2') +pub fn erase_line_clear() { + erase_line('2') } // Will make cursor appear if not visible -pub fn show_cursor() -{ +pub fn show_cursor() { print('\x1b[?25h') } // Will make cursor invisible -pub fn hide_cursor() -{ +pub fn hide_cursor() { print('\x1b[?25l') } + diff --git a/vlib/time/time.v b/vlib/time/time.v index 3237de615e..a19fa35ca9 100644 --- a/vlib/time/time.v +++ b/vlib/time/time.v @@ -1,49 +1,29 @@ // 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 time import rand const ( - days_string = 'MonTueWedThuFriSatSun' - - month_days = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31] - months_string = 'JanFebMarAprMayJunJulAugSepOctNovDec' - - // The unsigned zero year for internal calculations. - // Must be 1 mod 400, and times before it will not compute correctly, - // but otherwise can be changed at will. - absolute_zero_year = i64(-292277022399) - - seconds_per_minute = 60 - seconds_per_hour = 60 * seconds_per_minute - seconds_per_day = 24 * seconds_per_hour - seconds_per_week = 7 * seconds_per_day - days_per_400_years = 365*400 + 97 - days_per_100_years = 365*100 + 24 - days_per_4_years = 365*4 + 1 - - days_before = [ - 0, - 31, - 31 + 28, - 31 + 28 + 31, - 31 + 28 + 31 + 30, - 31 + 28 + 31 + 30 + 31, - 31 + 28 + 31 + 30 + 31 + 30, - 31 + 28 + 31 + 30 + 31 + 30 + 31, - 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31, - 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30, - 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31, - 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30, - 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30 + 31, - ] + days_string = 'MonTueWedThuFriSatSun' + month_days = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31] + months_string = 'JanFebMarAprMayJunJulAugSepOctNovDec' + // The unsigned zero year for internal calculations. + // Must be 1 mod 400, and times before it will not compute correctly, + // but otherwise can be changed at will. + absolute_zero_year = i64(-292277022399) + seconds_per_minute = 60 + seconds_per_hour = 60 * seconds_per_minute + seconds_per_day = 24 * seconds_per_hour + seconds_per_week = 7 * seconds_per_day + days_per_400_years = 365 * 400 + 97 + days_per_100_years = 365 * 100 + 24 + days_per_4_years = 365 * 4 + 1 + days_before = [0, 31, 31 + 28, 31 + 28 + 31, 31 + 28 + 31 + 30, 31 + 28 + 31 + 30 + 31, 31 + 28 + 31 + 30 + 31 + 30, 31 + 28 + 31 + 30 + 31 + 30 + 31, 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31, 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30, 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31, 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30, 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30 + 31, ] ) #include - pub struct Time { pub: year int @@ -56,38 +36,41 @@ pub: } pub enum FormatTime { - hhmm12 - hhmm24 - hhmmss12 - hhmmss24 - no_time + hhmm12 + hhmm24 + hhmmss12 + hhmmss24 + no_time } pub enum FormatDate { - ddmmyy - ddmmyyyy - mmddyy - mmddyyyy - mmmd - mmmdd - mmmddyyyy - no_date - yyyymmdd + ddmmyy + ddmmyyyy + mmddyy + mmddyyyy + mmmd + mmmdd + mmmddyyyy + no_date + yyyymmdd } pub enum FormatDelimiter { - dot - hyphen - slash - space + dot + hyphen + slash + space } fn C.localtime(int) &C.tm -fn remove_me_when_c_bug_is_fixed() { // TODO + +fn remove_me_when_c_bug_is_fixed() { + // TODO } -pub struct C.time_t {} +pub struct C.time_t { +} struct C.tm { tm_year int @@ -100,6 +83,7 @@ struct C.tm { fn C.time(int) C.time_t + pub fn now() Time { t := C.time(0) mut now := &C.tm(0) @@ -113,82 +97,81 @@ pub fn random() Time { return time.unix(rand_unix) } - // Based on Go's time package. // Copyright 2009 The Go Authors. pub fn unix(abs int) Time { // Split into time and day. mut d := abs / seconds_per_day - // Account for 400 year cycles. mut n := d / days_per_400_years mut y := 400 * n d -= days_per_400_years * n - // Cut off 100-year cycles. // The last cycle has one extra leap year, so on the last day // of that year, day / days_per_100_years will be 4 instead of 3. // Cut it back down to 3 by subtracting n>>2. n = d / days_per_100_years - n -= n >> 2 + n -= n>>2 y += 100 * n d -= days_per_100_years * n - // Cut off 4-year cycles. // The last cycle has a missing leap year, which does not // affect the computation. n = d / days_per_4_years y += 4 * n d -= days_per_4_years * n - // Cut off years within a 4-year cycle. // The last year is a leap year, so on the last day of that year, // day / 365 will be 4 instead of 3. Cut it back down to 3 // by subtracting n>>2. n = d / 365 - n -= n >> 2 + n -= n>>2 y += n d -= 365 * n - yday := d mut day := yday - - year := abs / int(3.154e+7) + 1970 //int(i64(y) + absolute_zero_year) - hour := (abs%seconds_per_day) / seconds_per_hour + year := abs / int(3.154e+7) + 1970 // int(i64(y) + absolute_zero_year) + hour := (abs % seconds_per_day) / seconds_per_hour minute := (abs % seconds_per_hour) / seconds_per_minute second := (abs % seconds_per_minute) - if is_leap_year(year) { // Leap year - if day > 31+29-1 { + if day > 31 + 29 - 1 { // After leap day; pretend it wasn't there. day-- - } else if day == 31+29-1 { + } + else if day == 31 + 29 - 1 { // Leap day. day = 29 - return Time{year:year, month:2, day:day, hour:hour, minute: minute, second: second} + return Time{ + year: year + month: 2 + day: day + hour: hour + minute: minute + second: second + } } } - // Estimate month on assumption that every month has 31 days. // The estimate may be too low by at most one month, so adjust. mut month := day / 31 mut begin := 0 - end := (days_before[month+1]) + end := (days_before[month + 1]) if day >= end { month++ begin = end - } else { + } + else { begin = (days_before[month]) } - month++ // because January is 1 day = day - begin + 1 return Time{ - year:year + year: year month: month - day:day - hour:hour + day: day + hour: hour minute: minute second: second uni: abs @@ -196,7 +179,7 @@ pub fn unix(abs int) Time { } pub fn convert_ctime(t tm) Time { - return Time { + return Time{ year: t.tm_year + 1900 month: t.tm_mon + 1 day: t.tm_mday @@ -208,24 +191,23 @@ pub fn convert_ctime(t tm) Time { } // format_ss returns a string for t in a given format YYYY-MM-DD HH:MM:SS in -// 24h notation +// 24h notation // @param // @return string // @example 1980-07-11 21:23:42 pub fn (t Time) format_ss() string { - return t.get_fmt_str(.hyphen, .hhmmss24, .yyyymmdd) + return t.get_fmt_str(.hyphen, .hhmmss24, .yyyymmdd) } // format_ss returns a string for t in a given format YYYY-MM-DD HH:MM in 24h -// notation +// notation // @param // @return string // @example 1980-07-11 21:23 pub fn (t Time) format() string { - return t.get_fmt_str(.hyphen, .hhmm24, .yyyymmdd) + return t.get_fmt_str(.hyphen, .hhmm24, .yyyymmdd) } - pub fn (t Time) smonth() string { i := t.month - 1 return months_string[i * 3..(i + 1) * 3] @@ -234,7 +216,7 @@ pub fn (t Time) smonth() string { // hhmm returns a string for t in the given format HH:MM in 24h notation // @example 21:04 pub fn (t Time) hhmm() string { - return t.get_fmt_time_str(.hhmm24) + return t.get_fmt_time_str(.hhmm24) } /* @@ -245,27 +227,27 @@ fn (t Time) hhmm_tmp() string { // hhmm12 returns a string for t in the given format HH:MM in 12h notation pub fn (t Time) hhmm12() string { - return t.get_fmt_time_str(.hhmm12) + return t.get_fmt_time_str(.hhmm12) } // hhmmss returns a string for t in the given format HH:MM:SS in 24h notation pub fn (t Time) hhmmss() string { - return t.get_fmt_time_str(.hhmmss24) + return t.get_fmt_time_str(.hhmmss24) } // ymmdd returns a string for t in the given format YYYY-MM-DD pub fn (t Time) ymmdd() string { - return t.get_fmt_date_str(.hyphen, .yyyymmdd) + return t.get_fmt_date_str(.hyphen, .yyyymmdd) } // ddmmy returns a string for t in the given format DD.MM.YYYY pub fn (t Time) ddmmy() string { - return t.get_fmt_date_str(.dot, .ddmmyyyy) + return t.get_fmt_date_str(.dot, .ddmmyyyy) } // md returns a string for t in the given format MMM D pub fn (t Time) md() string { - return t.get_fmt_date_str(.space, .mmmd) + return t.get_fmt_date_str(.space, .mmmd) } pub fn (t Time) clean() string { @@ -275,7 +257,7 @@ pub fn (t Time) clean() string { // } // Today if t.month == nowe.month && t.year == nowe.year && t.day == nowe.day { - return t.get_fmt_time_str(.hhmm24) + return t.get_fmt_time_str(.hhmm24) } // This week // if time.Since(t) < 24*7*time.Hour { @@ -283,7 +265,7 @@ pub fn (t Time) clean() string { // } // This year if t.year == nowe.year { - return t.get_fmt_str(.space, .hhmm24, .mmmd) + return t.get_fmt_str(.space, .hhmm24, .mmmd) } return t.format() // return fmt.Sprintf("%4d/%02d/%02d", t.Year(), t.Month(), t.Day()) + " " + hm @@ -296,7 +278,7 @@ pub fn (t Time) clean12() string { // } // Today if t.month == nowe.month && t.year == nowe.year && t.day == nowe.day { - return t.get_fmt_time_str(.hhmm12) + return t.get_fmt_time_str(.hhmm12) } // This week // if time.Since(t) < 24*7*time.Hour { @@ -304,12 +286,11 @@ pub fn (t Time) clean12() string { // } // This year if t.year == nowe.year { - return t.get_fmt_str(.space, .hhmm12, .mmmd) + return t.get_fmt_str(.space, .hhmm12, .mmmd) } return t.format() // return fmt.Sprintf("%4d/%02d/%02d", t.Year(), t.Month(), t.Day()) + " " + hm } - // `parse` parses time in the following format: "2018-01-27 12:48:34" pub fn parse(s string) Time { // println('parse="$s"') @@ -329,7 +310,7 @@ pub fn parse(s string) Time { minute := hms[1] second := hms[2] // ////////// - return new_time(Time { + return new_time(Time{ year: ymd[0].int() month: ymd[1].int() day: ymd[2].int() @@ -340,20 +321,23 @@ pub fn parse(s string) Time { } pub fn new_time(t Time) Time { - return{t | uni: t.calc_unix()} + return { + t | + uni:t.calc_unix() + } } pub fn (t &Time) calc_unix() int { - if t.uni != 0 { + if t.uni != 0 { return t.uni } tt := C.tm{ - tm_sec : t.second - tm_min : t.minute - tm_hour : t.hour - tm_mday : t.day - tm_mon : t.month-1 - tm_year : t.year - 1900 + tm_sec: t.second + tm_min: t.minute + tm_hour: t.hour + tm_mday: t.day + tm_mon: t.month - 1 + tm_year: t.year - 1900 } return C.mktime(&tt) } @@ -406,7 +390,7 @@ pub fn day_of_week(y, m, d int) int { if (m < 3) { sy = sy - 1 } - return ( sy + sy/4 - sy/100 + sy/400 + t[m-1] + d - 1) % 7 + 1 + return (sy + sy / 4 - sy / 100 + sy / 400 + t[m - 1] + d - 1) % 7 + 1 } pub fn (t Time) day_of_week() int { @@ -419,8 +403,8 @@ pub fn (t Time) weekday_str() string { return days_string[i * 3..(i + 1) * 3] } -pub struct C.timeval { - tv_sec u64 +pub struct C.timeval { + tv_sec u64 tv_usec u64 } @@ -428,50 +412,47 @@ pub struct C.timeval { pub fn ticks() i64 { $if windows { return C.GetTickCount() - } - $else { - ts := C.timeval{} - C.gettimeofday(&ts,0) + } $else { + ts := C.timeval{ + } + C.gettimeofday(&ts, 0) return i64(ts.tv_sec * u64(1000) + (ts.tv_usec / u64(1000))) } - -/* + /* t := i64(C.mach_absolute_time()) # Nanoseconds elapsedNano = AbsoluteToNanoseconds( *(AbsoluteTime *) &t ); # return (double)(* (uint64_t *) &elapsedNano) / 1000000; */ + } pub fn sleep(seconds int) { $if windows { C.Sleep(seconds * 1000) - } - $else { + } $else { C.sleep(seconds) } } pub fn usleep(n int) { -$if windows { - //C._usleep(n) -} -$else { - C.usleep(n) -} + $if windows { + // C._usleep(n) + } $else { + C.usleep(n) + } } pub fn sleep_ms(n int) { $if windows { C.Sleep(n) - } - $else { + } $else { C.usleep(n * 1000) } } // Determine whether a year is a leap year. pub fn is_leap_year(year int) bool { - return (year%4 == 0) && (year%100 != 0 || year%400 == 0) + return (year % 4 == 0) && (year % 100 != 0 || year % 400 == 0) } // Returns number of days in month @@ -479,8 +460,8 @@ pub fn days_in_month(month, year int) ?int { if month > 12 || month < 1 { return error('Invalid month: $month') } - extra := if month == 2 && is_leap_year(year) {1} else {0} - res := month_days[month-1] + extra + extra := if month == 2 && is_leap_year(year) { 1 } else { 0 } + res := month_days[month - 1] + extra return res } @@ -489,31 +470,26 @@ pub fn days_in_month(month, year int) ?int { // @return string // @example 21:23:42 pub fn (t Time) get_fmt_time_str(fmt_time FormatTime) string { - if fmt_time == .no_time { - return '' - } - - tp := if t.hour > 11 { - 'p.m.' - } else { - 'a.m.' - } - - hour := if t.hour > 12 { - t.hour - 12 - } else if t.hour == 0 { - 12 - } else { - t.hour - } - - return match fmt_time { - .hhmm12 { '$hour:${t.minute:02d} $tp' } - .hhmm24 { '${t.hour:02d}:${t.minute:02d}' } - .hhmmss12 { '$hour:${t.minute:02d}:${t.second:02d} $tp' } - .hhmmss24 { '${t.hour:02d}:${t.minute:02d}:${t.second:02d}' } - else { 'unknown enumeration $fmt_time' } - } + if fmt_time == .no_time { + return '' + } + tp := if t.hour > 11 { 'p.m.' } else { 'a.m.' } + hour := if t.hour > 12 { t.hour - 12 } else if t.hour == 0 { 12 } else { t.hour } + return match fmt_time { + .hhmm12{ + '$hour:${t.minute:02d} $tp' + } + .hhmm24{ + '${t.hour:02d}:${t.minute:02d}' + } + .hhmmss12{ + '$hour:${t.minute:02d}:${t.second:02d} $tp' + } + .hhmmss24{ + '${t.hour:02d}:${t.minute:02d}:${t.second:02d}' + } + else { + 'unknown enumeration $fmt_time'}} } // get_fmt_date_str returns a string for t in a given date format @@ -521,30 +497,52 @@ pub fn (t Time) get_fmt_time_str(fmt_time FormatTime) string { // @return string // @example 11.07.1980 pub fn (t Time) get_fmt_date_str(fmt_dlmtr FormatDelimiter, fmt_date FormatDate) string { - if fmt_date == .no_date { - return '' - } - - month := '${t.smonth()}' - year := t.year.str()[2..] - - return match fmt_date { - .ddmmyy { '${t.day:02d}|${t.month:02d}|$year' } - .ddmmyyyy { '${t.day:02d}|${t.month:02d}|${t.year}' } - .mmddyy { '${t.month:02d}|${t.day:02d}|$year' } - .mmddyyyy { '${t.month:02d}|${t.day:02d}|${t.year}' } - .mmmd { '$month|${t.day}' } - .mmmdd { '$month|${t.day:02d}' } - .mmmddyyyy { '$month|${t.day:02d}|${t.year}' } - .yyyymmdd { '${t.year}|${t.month:02d}|${t.day:02d}' } - else { 'unknown enumeration $fmt_date' } - }.replace('|', match fmt_dlmtr { - .dot { '.' } - .hyphen { '-' } - .slash { '/' } - .space { ' ' } - else { 'unknown enumeration $fmt_dlmtr' } - }) + if fmt_date == .no_date { + return '' + } + month := '${t.smonth()}' + year := t.year.str()[2..] + return match fmt_date { + .ddmmyy{ + '${t.day:02d}|${t.month:02d}|$year' + } + .ddmmyyyy{ + '${t.day:02d}|${t.month:02d}|${t.year}' + } + .mmddyy{ + '${t.month:02d}|${t.day:02d}|$year' + } + .mmddyyyy{ + '${t.month:02d}|${t.day:02d}|${t.year}' + } + .mmmd{ + '$month|${t.day}' + } + .mmmdd{ + '$month|${t.day:02d}' + } + .mmmddyyyy{ + '$month|${t.day:02d}|${t.year}' + } + .yyyymmdd{ + '${t.year}|${t.month:02d}|${t.day:02d}' + } + else { + 'unknown enumeration $fmt_date'}}.replace('|', match fmt_dlmtr { + .dot{ + '.' + } + .hyphen{ + '-' + } + .slash{ + '/' + } + .space{ + ' ' + } + else { + 'unknown enumeration $fmt_dlmtr'}}) } // get_fmt_str returns a string for t in a given format for time and date @@ -552,21 +550,23 @@ pub fn (t Time) get_fmt_date_str(fmt_dlmtr FormatDelimiter, fmt_date FormatDate) // @return string // @example 11.07.1980 21:23:42 pub fn (t Time) get_fmt_str(fmt_dlmtr FormatDelimiter, fmt_time FormatTime, fmt_date FormatDate) string { - if fmt_date == .no_date { - if fmt_time == .no_time { - // saving one function call although it's checked in - // t.get_fmt_time_str(fmt_time) in the beginning - return '' - } else { - return t.get_fmt_time_str(fmt_time) - } - } else { - if fmt_time != .no_time { - return t.get_fmt_date_str(fmt_dlmtr, fmt_date) - + ' ' - + t.get_fmt_time_str(fmt_time) - } else { - return t.get_fmt_date_str(fmt_dlmtr, fmt_date) - } - } + if fmt_date == .no_date { + if fmt_time == .no_time { + // saving one function call although it's checked in + // t.get_fmt_time_str(fmt_time) in the beginning + return '' + } + else { + return t.get_fmt_time_str(fmt_time) + } + } + else { + if fmt_time != .no_time { + return t.get_fmt_date_str(fmt_dlmtr, fmt_date) + ' ' + t.get_fmt_time_str(fmt_time) + } + else { + return t.get_fmt_date_str(fmt_dlmtr, fmt_date) + } + } } + diff --git a/vlib/vweb/tmpl/tmpl.v b/vlib/vweb/tmpl/tmpl.v index 61ecb34484..8ef94f404e 100644 --- a/vlib/vweb/tmpl/tmpl.v +++ b/vlib/vweb/tmpl/tmpl.v @@ -1,54 +1,54 @@ // 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 tmpl import os import strings const ( - STR_START = 'sb.write(\'' - STR_END = '\' ) ' + STR_START = "sb.write(\'" + STR_END = "\' ) " ) - pub fn compile_template(path string) string { - //lines := os.read_lines(path) - mut html := os.read_file(path) or { + // lines := os.read_lines(path) + mut html := os.read_file(path)or{ panic('html failed') } - mut header := '' + mut header := '' if os.exists('header.html') { - h := os.read_file('header.html') or { + h := os.read_file('header.html')or{ panic('html failed') } - header = h.replace('\'', '"') + header = h.replace("\'", '"') html = header + html } lines := html.split_into_lines() mut s := strings.new_builder(1000) - //base := path.all_after('/').replace('.html', '') - s.writeln(' + // base := path.all_after('/').replace('.html', '') + s.writeln(" mut sb := strings.new_builder(${lines.len * 30}) header := \' \' // TODO remove _ = header //footer := \'footer\' -') +") s.writeln(STR_START) - mut in_css :=true// false + mut in_css := true // false for _line in lines { line := _line.trim_space() if line == '' { - //in_css = false + // in_css = false } if line.contains('@if ') { s.writeln(STR_END) - pos := line.index('@if') or { continue } - s.writeln('if ' + line[pos+4..] + '{') + pos := line.index('@if') or { + continue + } + s.writeln('if ' + line[pos + 4..] + '{') s.writeln(STR_START) } else if line.contains('@end') { @@ -63,8 +63,10 @@ _ = header } else if line.contains('@for') { s.writeln(STR_END) - pos := line.index('@for') or { continue } - s.writeln('for ' + line[pos+4..] + '{') + pos := line.index('@for') or { + continue + } + s.writeln('for ' + line[pos + 4..] + '{') s.writeln(STR_START) } else if !in_css && line.contains('.') && line.ends_with('{') { @@ -76,7 +78,7 @@ _ = header } // HTML, may include `@var` else { - s.writeln(line.replace('@', '\x24').replace("'", '"') ) + s.writeln(line.replace('@', '\x24').replace("'", '"')) } } s.writeln(STR_END)