From a08e64f37fb03200dfb24fc6bfe291da26a62cc6 Mon Sep 17 00:00:00 2001 From: Alexander Medvednikov Date: Wed, 8 Apr 2020 22:12:42 +0200 Subject: [PATCH] cgen: operator overloading --- vlib/math/bits/bits.v | 4 +- vlib/math/bits/bits_test.v | 36 +++++++++--------- vlib/math/complex/complex.v | 8 ++-- vlib/math/complex/complex_test.v | 2 + vlib/v/gen/cgen.v | 17 +++++++-- vlib/v/util/util.v | 63 +++++++++++++++++++++++--------- 6 files changed, 85 insertions(+), 45 deletions(-) diff --git a/vlib/math/bits/bits.v b/vlib/math/bits/bits.v index 88d999465c..66d89b30dc 100644 --- a/vlib/math/bits/bits.v +++ b/vlib/math/bits/bits.v @@ -271,11 +271,11 @@ pub fn len_16(x u16) int { pub fn len_32(x u32) int { mut y := x mut n := 0 - if y >= 1<<16 { + if y >= (1<<16) { y >>= 16 n = 16 } - if y >= 1<<8 { + if y >= (1<<8) { y >>= 8 n += 8 } diff --git a/vlib/math/bits/bits_test.v b/vlib/math/bits/bits_test.v index e2b59007ec..9b74d9d9f7 100644 --- a/vlib/math/bits/bits_test.v +++ b/vlib/math/bits/bits_test.v @@ -6,32 +6,32 @@ module bits fn test_bits(){ mut i := 0 mut i1:= u64(0) - + // // --- LeadingZeros --- // - + // 8 bit i = 1 for x in 0..8 { //C.printf("x:%02x lz: %d cmp: %d\n", i << x, leading_zeros_8(i << x), 7-x) assert leading_zeros_8(byte(i << x)) == 7 - x } - + // 16 bit i = 1 for x in 0..16 { //C.printf("x:%04x lz: %d cmp: %d\n", u16(i) << x, leading_zeros_16(u16(i) << x), 15-x) assert leading_zeros_16(u16(i) << x) == 15 - x } - + // 32 bit i = 1 for x in 0..32 { //C.printf("x:%08x lz: %d cmp: %d\n", u32(i) << x, leading_zeros_32(u32(i) << x), 31-x) assert leading_zeros_32(u32(i) << x) == 31 - x } - + // 64 bit i = 1 for x in 0..64 { @@ -50,7 +50,7 @@ fn test_bits(){ assert ones_count_8(byte(i)) == x i = (i << 1) + 1 } - + // 16 bit i = 0 for x in 0..17 { @@ -58,7 +58,7 @@ fn test_bits(){ assert ones_count_16(u16(i)) == x i = (i << 1) + 1 } - + // 32 bit i = 0 for x in 0..33 { @@ -66,7 +66,7 @@ fn test_bits(){ assert ones_count_32(u32(i)) == x i = (i << 1) + 1 } - + // 64 bit i1 = 0 for x in 0..65 { @@ -76,7 +76,7 @@ fn test_bits(){ } // - // --- rotate_left/right --- + // --- rotate_left/right --- // assert rotate_left_8( 0x12 , 4) == 0x21 assert rotate_left_16( 0x1234 , 8) == 0x3412 @@ -86,7 +86,7 @@ fn test_bits(){ // // --- reverse --- // - + // 8 bit i = 0 for x in 0..9 { @@ -102,7 +102,7 @@ fn test_bits(){ assert reverse_8(byte(i)) == rv i = (i << 1) + 1 } - + // 16 bit i = 0 for x in 0..17 { @@ -118,7 +118,7 @@ fn test_bits(){ assert reverse_16(u16(i)) == rv i = (i << 1) + 1 } - + // 32 bit i = 0 for x in 0..33 { @@ -134,7 +134,7 @@ fn test_bits(){ assert reverse_32(u32(i)) == rv i = (i << 1) + 1 } - + // 64 bit i1 = 0 for x in 0..64 { @@ -190,7 +190,7 @@ fn test_bits(){ // // --- sub --- // - + // 32 bit i = 1 for x in 1..32 { @@ -202,7 +202,7 @@ fn test_bits(){ diff, borrow_out = sub_32(v0, v1, u32(1)) //C.printf("x:%08x [%llu,%llu] %08x\n", u32(i) << x, diff, borrow_out, v0 - v1) - assert diff == (v1 - 1) + assert diff == (v1 - 1) assert borrow_out == u32(0) diff, borrow_out = sub_32(v1, v0, u32(1)) @@ -221,7 +221,7 @@ fn test_bits(){ diff, borrow_out = sub_64(v0, v1, u64(1)) //C.printf("x:%08x [%llu,%llu] %08x\n", u64(i) << x, diff, borrow_out, v0 - v1) - assert diff == (v1 - 1) + assert diff == (v1 - 1) assert borrow_out == u64(0) diff, borrow_out = sub_64(v1, v0, u64(1)) @@ -236,7 +236,7 @@ fn test_bits(){ // 32 bit i = 1 for x in 0..32 { - v0 := u32(i) << x + v0 := (u32(i) << x) v1 := v0 - 1 hi, lo := mul_32(v0, v1) //C.printf("x:%08x [%llu,%llu] %llu\n", v0, hi, lo, u64(v0 * v1)) @@ -285,5 +285,5 @@ fn test_bits(){ assert rem == rem1 assert rem == rem_64(hi, lo, y) } - + } diff --git a/vlib/math/complex/complex.v b/vlib/math/complex/complex.v index 3dd52ed6bc..c4602a014c 100644 --- a/vlib/math/complex/complex.v +++ b/vlib/math/complex/complex.v @@ -366,7 +366,7 @@ pub fn (c Complex) asinh() Complex { // Based on // http://www.suitcaseofdreams.net/Inverse__Hyperbolic_Functions.htm pub fn (c Complex) acosh() Complex { - if(c.re > 1) { + if c.re > 1 { return c.add( c.pow(2) .subtract(complex(1,0)) @@ -391,7 +391,7 @@ pub fn (c Complex) acosh() Complex { // http://www.suitcaseofdreams.net/Inverse__Hyperbolic_Functions.htm pub fn (c Complex) atanh() Complex { one := complex(1,0) - if(c.re < 1) { + if c.re < 1 { return complex(1.0/2,0).multiply( one .add(c) @@ -421,7 +421,7 @@ pub fn (c Complex) atanh() Complex { // http://www.suitcaseofdreams.net/Inverse__Hyperbolic_Functions.htm pub fn (c Complex) acoth() Complex { one := complex(1,0) - if(c.re < 0 || c.re > 1) { + if c.re < 0 || c.re > 1 { return complex(1.0/2,0).multiply( c .add(one) @@ -479,7 +479,7 @@ pub fn (c Complex) acoth() Complex { // http://www.suitcaseofdreams.net/Inverse__Hyperbolic_Functions.htm pub fn (c Complex) acsch() Complex { one := complex(1,0) - if(c.re < 0) { + if c.re < 0 { return one.subtract( one.add( c.pow(2) diff --git a/vlib/math/complex/complex_test.v b/vlib/math/complex/complex_test.v index 4e91083daf..b74c66998e 100644 --- a/vlib/math/complex/complex_test.v +++ b/vlib/math/complex/complex_test.v @@ -168,6 +168,8 @@ fn test_complex_mulinv() { mut c2 := cmplx.complex(0.067568,-0.094595) mut result := c1.mulinv() // Some issue with precision comparison in f64 using == operator hence serializing to string + println(c2.str()) + println(result.str()) assert result.str().eq(c2.str()) c1 = cmplx.complex(-3,4) c2 = cmplx.complex(-0.12,-0.16) diff --git a/vlib/v/gen/cgen.v b/vlib/v/gen/cgen.v index 94ddcdcb47..0a700337a1 100644 --- a/vlib/v/gen/cgen.v +++ b/vlib/v/gen/cgen.v @@ -788,6 +788,10 @@ fn (g mut Gen) gen_fn_decl(it ast.FnDecl) { } } else { mut name := it.name + c := name[0] + if c in [`+`, `-`, `*`, `/`] { + name = util.replace_op(name) + } if it.is_method { name = g.table.get_type_symbol(it.receiver.typ).name + '_' + name } @@ -796,9 +800,6 @@ fn (g mut Gen) gen_fn_decl(it ast.FnDecl) { } else { name = c_name(name) } - if name.starts_with('_op_') { - name = op_to_fn_name(name) - } // type_name := g.table.Type_to_str(it.return_type) type_name := g.typ(it.return_type) g.write('$type_name ${name}(') @@ -1295,6 +1296,7 @@ fn (g mut Gen) assign_expr(node ast.AssignExpr) { } fn (g mut Gen) infix_expr(node ast.InfixExpr) { + left_sym := g.table.get_type_symbol(node.left_type) // println('infix_expr() op="$node.op.str()" line_nr=$node.pos.line_nr') // g.write('/*infix*/') // if it.left_type == table.string_type_idx { @@ -1412,6 +1414,15 @@ fn (g mut Gen) infix_expr(node ast.InfixExpr) { g.write(',') g.expr(node.right) g.write(')') + } else if node.op in [.plus, .minus, .mul, .div] && (left_sym.name[0].is_capital() || left_sym.name.contains('.')) { + g.write(g.typ(node.left_type)) + g.write('_') + g.write(util.replace_op(node.op.str())) + g.write('(') + g.expr(node.left) + g.write(', ') + g.expr(node.right) + g.write(')') } else { need_par := node.op in [.amp, .pipe, .xor] // `x & y == 0` => `(x & y) == 0` in C if need_par { diff --git a/vlib/v/util/util.v b/vlib/v/util/util.v index b142757899..fef61901a3 100644 --- a/vlib/v/util/util.v +++ b/vlib/v/util/util.v @@ -3,8 +3,10 @@ // that can be found in the LICENSE file. module util -import os -import v.pref +import ( + os + v.pref +) pub const ( v_version = '0.1.26' @@ -22,7 +24,7 @@ pub fn full_hash() string { build_hash := vhash() current_hash := githash(false) if build_hash == current_hash { - return build_hash + return build_hash } return '${build_hash}.${current_hash}' } @@ -41,7 +43,7 @@ pub fn full_v_version() string { // NB: githash(true) must be called only when v detects that it builds itself. // For all other programs, githash(false) should be used. pub fn githash(should_get_from_filesystem bool) string { - for { + for { // The `for` construct here is used as a goto substitute. // The code in this function will break out of the `for` // if it detects an error and can not continue. @@ -50,7 +52,7 @@ pub fn githash(should_get_from_filesystem bool) string { vroot := os.dir(vexe) // .git/HEAD git_head_file := os.join_path(vroot, '.git', 'HEAD') - if !os.exists( git_head_file ) { + if !os.exists(git_head_file) { break } // 'ref: refs/heads/master' ... the current branch name @@ -60,11 +62,11 @@ pub fn githash(should_get_from_filesystem bool) string { gcbranch_rel_path := head_content.replace('ref: ', '').trim_space() gcbranch_file := os.join_path(vroot, '.git', gcbranch_rel_path) // .git/refs/heads/master - if !os.exists( gcbranch_file ) { + if !os.exists(gcbranch_file) { break } // get the full commit hash contained in the ref heads file - current_branch_hash := os.read_file( gcbranch_file ) or { + current_branch_hash := os.read_file(gcbranch_file) or { break } desired_hash_length := 7 @@ -81,20 +83,18 @@ pub fn githash(should_get_from_filesystem bool) string { } // - fn set_vroot_folder(vroot_path string) { // Preparation for the compiler module: // VEXE env variable is needed so that compiler.vexe_path() // can return it later to whoever needs it: vname := if os.user_os() == 'windows' { 'v.exe' } else { 'v' } - os.setenv('VEXE', os.real_path(os.join_path( vroot_path, vname)), true) + os.setenv('VEXE', os.real_path(os.join_path(vroot_path, vname)), true) } pub fn launch_tool(is_verbose bool, tool_name string) { vexe := pref.vexe_path() vroot := os.dir(vexe) set_vroot_folder(vroot) - tool_args := os.args[1..].join(' ') tool_exe := path_of_executable(os.real_path('$vroot/cmd/tools/$tool_name')) tool_source := os.real_path('$vroot/cmd/tools/${tool_name}.v') @@ -105,7 +105,6 @@ pub fn launch_tool(is_verbose bool, tool_name string) { println('launch_tool tool_args : $tool_args') println('launch_tool tool_command: $tool_command') } - // TODO Caching should be done on the `vlib/v` level. mut should_compile := false if !os.exists(tool_exe) { @@ -115,7 +114,6 @@ pub fn launch_tool(is_verbose bool, tool_name string) { // v was recompiled, maybe after v up ... // rebuild the tool too just in case should_compile = true - if tool_name == 'vself' || tool_name == 'vup' { // The purpose of vself/up is to update and recompile v itself. // After the first 'v self' execution, v will be modified, so @@ -133,14 +131,15 @@ pub fn launch_tool(is_verbose bool, tool_name string) { if is_verbose { println('launch_tool should_compile: $should_compile') } - if should_compile { mut compilation_command := '"$vexe" ' compilation_command += '"$tool_source"' if is_verbose { println('Compiling $tool_name with: "$compilation_command"') } - tool_compilation := os.exec(compilation_command) or { panic(err) } + tool_compilation := os.exec(compilation_command) or { + panic(err) + } if tool_compilation.exit_code != 0 { mut err := 'Permission denied' if !tool_compilation.output.contains('Permission denied') { @@ -153,7 +152,6 @@ pub fn launch_tool(is_verbose bool, tool_name string) { if is_verbose { println('launch_tool running tool command: $tool_command ...') } - exit(os.system(tool_command)) } @@ -180,13 +178,42 @@ pub fn read_file(file_path string) ?string { return raw_text } - [inline] fn imin(a, b int) int { - return if a < b { a } else { b } + return if a < b { + a + } else { + b + } } [inline] fn imax(a, b int) int { - return if a > b { a } else { b } + return if a > b { + a + } else { + b + } +} + +fn replace_op(s string) string { + last_char := s[s.len - 1] + suffix := match last_char { + `+` { + '_plus' + } + `-` { + '_minus' + } + `*` { + '_mult' + } + `/` { + '_div' + } + else { + '' + } + } + return s[..s.len - 1] + suffix }