cgen: operator overloading

pull/4301/head
Alexander Medvednikov 2020-04-08 22:12:42 +02:00
parent 3521b7ff89
commit a08e64f37f
6 changed files with 85 additions and 45 deletions

View File

@ -271,11 +271,11 @@ pub fn len_16(x u16) int {
pub fn len_32(x u32) int { pub fn len_32(x u32) int {
mut y := x mut y := x
mut n := 0 mut n := 0
if y >= 1<<16 { if y >= (1<<16) {
y >>= 16 y >>= 16
n = 16 n = 16
} }
if y >= 1<<8 { if y >= (1<<8) {
y >>= 8 y >>= 8
n += 8 n += 8
} }

View File

@ -236,7 +236,7 @@ fn test_bits(){
// 32 bit // 32 bit
i = 1 i = 1
for x in 0..32 { for x in 0..32 {
v0 := u32(i) << x v0 := (u32(i) << x)
v1 := v0 - 1 v1 := v0 - 1
hi, lo := mul_32(v0, v1) hi, lo := mul_32(v0, v1)
//C.printf("x:%08x [%llu,%llu] %llu\n", v0, hi, lo, u64(v0 * v1)) //C.printf("x:%08x [%llu,%llu] %llu\n", v0, hi, lo, u64(v0 * v1))

View File

@ -366,7 +366,7 @@ pub fn (c Complex) asinh() Complex {
// Based on // Based on
// http://www.suitcaseofdreams.net/Inverse__Hyperbolic_Functions.htm // http://www.suitcaseofdreams.net/Inverse__Hyperbolic_Functions.htm
pub fn (c Complex) acosh() Complex { pub fn (c Complex) acosh() Complex {
if(c.re > 1) { if c.re > 1 {
return c.add( return c.add(
c.pow(2) c.pow(2)
.subtract(complex(1,0)) .subtract(complex(1,0))
@ -391,7 +391,7 @@ pub fn (c Complex) acosh() Complex {
// http://www.suitcaseofdreams.net/Inverse__Hyperbolic_Functions.htm // http://www.suitcaseofdreams.net/Inverse__Hyperbolic_Functions.htm
pub fn (c Complex) atanh() Complex { pub fn (c Complex) atanh() Complex {
one := complex(1,0) one := complex(1,0)
if(c.re < 1) { if c.re < 1 {
return complex(1.0/2,0).multiply( return complex(1.0/2,0).multiply(
one one
.add(c) .add(c)
@ -421,7 +421,7 @@ pub fn (c Complex) atanh() Complex {
// http://www.suitcaseofdreams.net/Inverse__Hyperbolic_Functions.htm // http://www.suitcaseofdreams.net/Inverse__Hyperbolic_Functions.htm
pub fn (c Complex) acoth() Complex { pub fn (c Complex) acoth() Complex {
one := complex(1,0) 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( return complex(1.0/2,0).multiply(
c c
.add(one) .add(one)
@ -479,7 +479,7 @@ pub fn (c Complex) acoth() Complex {
// http://www.suitcaseofdreams.net/Inverse__Hyperbolic_Functions.htm // http://www.suitcaseofdreams.net/Inverse__Hyperbolic_Functions.htm
pub fn (c Complex) acsch() Complex { pub fn (c Complex) acsch() Complex {
one := complex(1,0) one := complex(1,0)
if(c.re < 0) { if c.re < 0 {
return one.subtract( return one.subtract(
one.add( one.add(
c.pow(2) c.pow(2)

View File

@ -168,6 +168,8 @@ fn test_complex_mulinv() {
mut c2 := cmplx.complex(0.067568,-0.094595) mut c2 := cmplx.complex(0.067568,-0.094595)
mut result := c1.mulinv() mut result := c1.mulinv()
// Some issue with precision comparison in f64 using == operator hence serializing to string // 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()) assert result.str().eq(c2.str())
c1 = cmplx.complex(-3,4) c1 = cmplx.complex(-3,4)
c2 = cmplx.complex(-0.12,-0.16) c2 = cmplx.complex(-0.12,-0.16)

View File

@ -788,6 +788,10 @@ fn (g mut Gen) gen_fn_decl(it ast.FnDecl) {
} }
} else { } else {
mut name := it.name mut name := it.name
c := name[0]
if c in [`+`, `-`, `*`, `/`] {
name = util.replace_op(name)
}
if it.is_method { if it.is_method {
name = g.table.get_type_symbol(it.receiver.typ).name + '_' + name 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 { } else {
name = c_name(name) 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.table.Type_to_str(it.return_type)
type_name := g.typ(it.return_type) type_name := g.typ(it.return_type)
g.write('$type_name ${name}(') 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) { 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') // println('infix_expr() op="$node.op.str()" line_nr=$node.pos.line_nr')
// g.write('/*infix*/') // g.write('/*infix*/')
// if it.left_type == table.string_type_idx { // if it.left_type == table.string_type_idx {
@ -1412,6 +1414,15 @@ fn (g mut Gen) infix_expr(node ast.InfixExpr) {
g.write(',') g.write(',')
g.expr(node.right) g.expr(node.right)
g.write(')') 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 { } else {
need_par := node.op in [.amp, .pipe, .xor] // `x & y == 0` => `(x & y) == 0` in C need_par := node.op in [.amp, .pipe, .xor] // `x & y == 0` => `(x & y) == 0` in C
if need_par { if need_par {

View File

@ -3,8 +3,10 @@
// that can be found in the LICENSE file. // that can be found in the LICENSE file.
module util module util
import os import (
import v.pref os
v.pref
)
pub const ( pub const (
v_version = '0.1.26' v_version = '0.1.26'
@ -50,7 +52,7 @@ pub fn githash(should_get_from_filesystem bool) string {
vroot := os.dir(vexe) vroot := os.dir(vexe)
// .git/HEAD // .git/HEAD
git_head_file := os.join_path(vroot, '.git', 'HEAD') git_head_file := os.join_path(vroot, '.git', 'HEAD')
if !os.exists( git_head_file ) { if !os.exists(git_head_file) {
break break
} }
// 'ref: refs/heads/master' ... the current branch name // '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_rel_path := head_content.replace('ref: ', '').trim_space()
gcbranch_file := os.join_path(vroot, '.git', gcbranch_rel_path) gcbranch_file := os.join_path(vroot, '.git', gcbranch_rel_path)
// .git/refs/heads/master // .git/refs/heads/master
if !os.exists( gcbranch_file ) { if !os.exists(gcbranch_file) {
break break
} }
// get the full commit hash contained in the ref heads file // 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 break
} }
desired_hash_length := 7 desired_hash_length := 7
@ -81,20 +83,18 @@ pub fn githash(should_get_from_filesystem bool) string {
} }
// //
fn set_vroot_folder(vroot_path string) { fn set_vroot_folder(vroot_path string) {
// Preparation for the compiler module: // Preparation for the compiler module:
// VEXE env variable is needed so that compiler.vexe_path() // VEXE env variable is needed so that compiler.vexe_path()
// can return it later to whoever needs it: // can return it later to whoever needs it:
vname := if os.user_os() == 'windows' { 'v.exe' } else { 'v' } 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) { pub fn launch_tool(is_verbose bool, tool_name string) {
vexe := pref.vexe_path() vexe := pref.vexe_path()
vroot := os.dir(vexe) vroot := os.dir(vexe)
set_vroot_folder(vroot) set_vroot_folder(vroot)
tool_args := os.args[1..].join(' ') tool_args := os.args[1..].join(' ')
tool_exe := path_of_executable(os.real_path('$vroot/cmd/tools/$tool_name')) tool_exe := path_of_executable(os.real_path('$vroot/cmd/tools/$tool_name'))
tool_source := os.real_path('$vroot/cmd/tools/${tool_name}.v') tool_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_args : $tool_args')
println('launch_tool tool_command: $tool_command') println('launch_tool tool_command: $tool_command')
} }
// TODO Caching should be done on the `vlib/v` level. // TODO Caching should be done on the `vlib/v` level.
mut should_compile := false mut should_compile := false
if !os.exists(tool_exe) { 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 ... // v was recompiled, maybe after v up ...
// rebuild the tool too just in case // rebuild the tool too just in case
should_compile = true should_compile = true
if tool_name == 'vself' || tool_name == 'vup' { if tool_name == 'vself' || tool_name == 'vup' {
// The purpose of vself/up is to update and recompile v itself. // The purpose of vself/up is to update and recompile v itself.
// After the first 'v self' execution, v will be modified, so // 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 { if is_verbose {
println('launch_tool should_compile: $should_compile') println('launch_tool should_compile: $should_compile')
} }
if should_compile { if should_compile {
mut compilation_command := '"$vexe" ' mut compilation_command := '"$vexe" '
compilation_command += '"$tool_source"' compilation_command += '"$tool_source"'
if is_verbose { if is_verbose {
println('Compiling $tool_name with: "$compilation_command"') 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 { if tool_compilation.exit_code != 0 {
mut err := 'Permission denied' mut err := 'Permission denied'
if !tool_compilation.output.contains('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 { if is_verbose {
println('launch_tool running tool command: $tool_command ...') println('launch_tool running tool command: $tool_command ...')
} }
exit(os.system(tool_command)) exit(os.system(tool_command))
} }
@ -180,13 +178,42 @@ pub fn read_file(file_path string) ?string {
return raw_text return raw_text
} }
[inline] [inline]
fn imin(a, b int) int { fn imin(a, b int) int {
return if a < b { a } else { b } return if a < b {
a
} else {
b
}
} }
[inline] [inline]
fn imax(a, b int) int { 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
} }