diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 35efcccbb2..4fcf4664db 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -103,7 +103,7 @@ jobs: run: | ./v tutorials/building_a_simple_web_blog_with_vweb/code/blog - name: Build cmd/tools/fast - run: cd cmd/tools/fast && v fast.v #&& ./fast + run: cd cmd/tools/fast && ../../../v fast.v && ./fast ubuntu-tcc-boehm-gc: runs-on: ubuntu-20.04 diff --git a/vlib/math/big/big.v b/vlib/math/big/big.v index 4a182e2134..6e9ac668ed 100644 --- a/vlib/math/big/big.v +++ b/vlib/math/big/big.v @@ -119,8 +119,8 @@ pub fn from_string(input string) Number { } // .int() converts (a small) big.Number `n` to an ordinary integer. -pub fn (n Number) int() int { - r := C.bignum_to_int(&n) +pub fn (n &Number) int() int { + r := C.bignum_to_int(n) return r } @@ -129,7 +129,7 @@ const ( ) // .str returns a decimal representation of the big unsigned integer number n. -pub fn (n Number) str() string { +pub fn (n &Number) str() string { if n.is_zero() { return '0' } @@ -145,13 +145,13 @@ pub fn (n Number) str() string { } // .hexstr returns a hexadecimal representation of the bignum `n` -pub fn (n Number) hexstr() string { +pub fn (n &Number) hexstr() string { mut buf := [8192]byte{} mut s := '' unsafe { bp := &buf[0] // NB: C.bignum_to_string(), returns the HEXADECIMAL representation of the bignum n - C.bignum_to_string(&n, &char(bp), 8192) + C.bignum_to_string(n, &char(bp), 8192) s = tos_clone(bp) } if s.len == 0 { @@ -162,33 +162,33 @@ pub fn (n Number) hexstr() string { // ////////////////////////////////////////////////////////// // overloaded ops for the numbers: -pub fn (a Number) + (b Number) Number { +pub fn (a &Number) + (b &Number) Number { c := Number{} - C.bignum_add(&a, &b, &c) + C.bignum_add(a, b, &c) return c } -pub fn (a Number) - (b Number) Number { +pub fn (a &Number) - (b &Number) Number { c := Number{} - C.bignum_sub(&a, &b, &c) + C.bignum_sub(a, b, &c) return c } -pub fn (a Number) * (b Number) Number { +pub fn (a &Number) * (b &Number) Number { c := Number{} - C.bignum_mul(&a, &b, &c) + C.bignum_mul(a, b, &c) return c } -pub fn (a Number) / (b Number) Number { +pub fn (a &Number) / (b &Number) Number { c := Number{} - C.bignum_div(&a, &b, &c) + C.bignum_div(a, b, &c) return c } -pub fn (a Number) % (b Number) Number { +pub fn (a &Number) % (b &Number) Number { c := Number{} - C.bignum_mod(&a, &b, &c) + C.bignum_mod(a, b, &c) return c } @@ -199,73 +199,73 @@ pub fn divmod(a &Number, b &Number, c &Number) Number { } // ////////////////////////////////////////////////////////// -pub fn cmp(a Number, b Number) int { - return C.bignum_cmp(&a, &b) +pub fn cmp(a &Number, b &Number) int { + return C.bignum_cmp(a, b) } -pub fn (a Number) is_zero() bool { - return C.bignum_is_zero(&a) != 0 +pub fn (a &Number) is_zero() bool { + return C.bignum_is_zero(a) != 0 } pub fn (mut a Number) inc() { - C.bignum_inc(a) + C.bignum_inc(&a) } pub fn (mut a Number) dec() { - C.bignum_dec(a) + C.bignum_dec(&a) } -pub fn pow(a Number, b Number) Number { +pub fn pow(a &Number, b &Number) Number { c := Number{} - C.bignum_pow(&a, &b, &c) + C.bignum_pow(a, b, &c) return c } -pub fn (a Number) isqrt() Number { +pub fn (a &Number) isqrt() Number { b := Number{} - C.bignum_isqrt(&a, &b) + C.bignum_isqrt(a, &b) return b } // ////////////////////////////////////////////////////////// -pub fn b_and(a Number, b Number) Number { +pub fn b_and(a &Number, b &Number) Number { c := Number{} - C.bignum_and(&a, &b, &c) + C.bignum_and(a, b, &c) return c } -pub fn b_or(a Number, b Number) Number { +pub fn b_or(a &Number, b &Number) Number { c := Number{} - C.bignum_or(&a, &b, &c) + C.bignum_or(a, b, &c) return c } -pub fn b_xor(a Number, b Number) Number { +pub fn b_xor(a &Number, b &Number) Number { c := Number{} - C.bignum_xor(&a, &b, &c) + C.bignum_xor(a, b, &c) return c } -pub fn (a Number) lshift(nbits int) Number { +pub fn (a &Number) lshift(nbits int) Number { b := Number{} - C.bignum_lshift(&a, &b, nbits) + C.bignum_lshift(a, &b, nbits) return b } -pub fn (a Number) rshift(nbits int) Number { +pub fn (a &Number) rshift(nbits int) Number { b := Number{} - C.bignum_rshift(&a, &b, nbits) + C.bignum_rshift(a, &b, nbits) return b } -pub fn (a Number) clone() Number { +pub fn (a &Number) clone() Number { b := Number{} - C.bignum_assign(&b, &a) + C.bignum_assign(&b, a) return b } // ////////////////////////////////////////////////////////// -pub fn factorial(nn Number) Number { +pub fn factorial(nn &Number) Number { mut n := nn.clone() mut a := nn.clone() n.dec() @@ -291,9 +291,9 @@ pub fn fact(n int) Number { // Example: assert big.from_int(1).bytes()[0] == byte(0x01) // Example: assert big.from_int(1024).bytes()[1] == byte(0x04) // Example: assert big.from_int(1048576).bytes()[2] == byte(0x10) -pub fn (n Number) bytes() []byte { +pub fn (n &Number) bytes() []byte { mut res := []byte{len: 128, init: 0} - unsafe { C.memcpy(res.data, &n, 128) } + unsafe { C.memcpy(res.data, n, 128) } return res } @@ -304,9 +304,9 @@ pub fn (n Number) bytes() []byte { // Example: assert big.from_int(1).bytes_trimmed() == [byte(0x01)] // Example: assert big.from_int(1024).bytes_trimmed() == [byte(0x00), 0x04] // Example: assert big.from_int(1048576).bytes_trimmed() == [byte(0x00), 0x00, 0x10] -pub fn (n Number) bytes_trimmed() []byte { +pub fn (n &Number) bytes_trimmed() []byte { mut res := []byte{len: 128, init: 0} - unsafe { C.memcpy(res.data, &n, 128) } + unsafe { C.memcpy(res.data, n, 128) } mut non_zero_idx := 127 for ; non_zero_idx >= 0; non_zero_idx-- { if res[non_zero_idx] != 0 { diff --git a/vlib/math/big/big_test.v b/vlib/math/big/big_test.v index 63982cadcc..c2b3cc6cc5 100644 --- a/vlib/math/big/big_test.v +++ b/vlib/math/big/big_test.v @@ -31,6 +31,11 @@ fn test_plus() { assert (big.from_u64(1024) + big.from_u64(1024)).hexstr() == '800' a += b assert a.hexstr() == '5' + a.inc() + assert a.hexstr() == '6' + a.dec() + a.dec() + assert a.hexstr() == '4' } fn test_minus() { diff --git a/vlib/v/gen/c/cgen.v b/vlib/v/gen/c/cgen.v index 155f2b4057..b0691f9bf3 100644 --- a/vlib/v/gen/c/cgen.v +++ b/vlib/v/gen/c/cgen.v @@ -2606,6 +2606,8 @@ fn (mut g Gen) gen_assign_stmt(assign_stmt ast.AssignStmt) { } mut str_add := false mut op_overloaded := false + mut op_expected_left := ast.Type(0) + mut op_expected_right := ast.Type(0) if var_type == ast.string_type_idx && assign_stmt.op == .plus_assign { if left is ast.IndexExpr { // a[0] += str => `array_set(&a, 0, &(string[]) {string__plus(...))})` @@ -2633,6 +2635,14 @@ fn (mut g Gen) gen_assign_stmt(assign_stmt ast.AssignStmt) { } g.expr(left) g.write(' = ${styp}_${util.replace_op(extracted_op)}(') + method := g.table.type_find_method(left_sym, extracted_op) or { + // the checker will most likely have found this, already... + g.error('assignemnt operator `$extracted_op=` used but no `$extracted_op` method defined', + assign_stmt.pos) + ast.Fn{} + } + op_expected_left = method.params[0].typ + op_expected_right = method.params[1].typ op_overloaded = true } if right_sym.kind == .function && is_decl { @@ -2681,10 +2691,14 @@ fn (mut g Gen) gen_assign_stmt(assign_stmt ast.AssignStmt) { g.prevent_sum_type_unwrapping_once = true } if !is_fixed_array_var || is_decl { - if !is_decl && left.is_auto_deref_var() { - g.write('*') + if op_overloaded { + g.op_arg(left, op_expected_left, var_type) + } else { + if !is_decl && left.is_auto_deref_var() { + g.write('*') + } + g.expr(left) } - g.expr(left) } } if is_inside_ternary && is_decl { @@ -2770,7 +2784,11 @@ fn (mut g Gen) gen_assign_stmt(assign_stmt ast.AssignStmt) { if assign_stmt.has_cross_var { g.gen_cross_tmp_variable(assign_stmt.left, val) } else { - g.expr_with_cast(val, val_type, var_type) + if op_overloaded { + g.op_arg(val, op_expected_right, val_type) + } else { + g.expr_with_cast(val, val_type, var_type) + } } } } diff --git a/vlib/v/gen/c/fn.v b/vlib/v/gen/c/fn.v index 189bcac634..c408f210a3 100644 --- a/vlib/v/gen/c/fn.v +++ b/vlib/v/gen/c/fn.v @@ -1272,6 +1272,7 @@ fn (mut g Gen) ref_or_deref_arg(arg ast.CallArg, expected_type ast.Type, lang as g.checker_bug('ref_or_deref_arg expected_type is 0', arg.pos) } exp_sym := g.table.get_type_symbol(expected_type) + mut needs_closing := false if arg.is_mut && !arg_is_ptr { g.write('&/*mut*/') } else if arg_is_ptr && !expr_is_ptr { @@ -1303,7 +1304,12 @@ fn (mut g Gen) ref_or_deref_arg(arg ast.CallArg, expected_type ast.Type, lang as deref_sym := g.table.get_type_symbol(expected_deref_type) if !((arg_typ_sym.kind == .function) || deref_sym.kind in [.sum_type, .interface_]) && lang != .c { - g.write('(voidptr)&/*qq*/') + if arg.expr.is_lvalue() { + g.write('(voidptr)&/*qq*/') + } else { + needs_closing = true + g.write('ADDR(${g.typ(expected_deref_type)}/*qq*/, ') + } } } } else if arg.typ.has_flag(.shared_f) && !expected_type.has_flag(.shared_f) { @@ -1315,6 +1321,9 @@ fn (mut g Gen) ref_or_deref_arg(arg ast.CallArg, expected_type ast.Type, lang as return } g.expr_with_cast(arg.expr, arg.typ, expected_type) + if needs_closing { + g.write(')') + } } fn (mut g Gen) is_gui_app() bool { diff --git a/vlib/v/gen/c/infix_expr.v b/vlib/v/gen/c/infix_expr.v index e457df27c4..901e604bb6 100644 --- a/vlib/v/gen/c/infix_expr.v +++ b/vlib/v/gen/c/infix_expr.v @@ -425,21 +425,19 @@ fn (mut g Gen) infix_expr_is_op(node ast.InfixExpr) { fn (mut g Gen) infix_expr_arithmetic_op(node ast.InfixExpr) { left := g.unwrap(node.left_type) right := g.unwrap(node.right_type) - has_operator_overloading := g.table.type_has_method(left.sym, node.op.str()) - if left.sym.kind == right.sym.kind && has_operator_overloading { - g.write(g.typ(left.typ.set_nr_muls(0))) - g.write('_') - g.write(util.replace_op(node.op.str())) - g.write('(') - g.write('*'.repeat(left.typ.nr_muls())) - g.expr(node.left) - g.write(', ') - g.write('*'.repeat(right.typ.nr_muls())) - g.expr(node.right) - g.write(')') - } else { + method := g.table.type_find_method(left.sym, node.op.str()) or { g.gen_plain_infix_expr(node) + return } + left_styp := g.typ(left.typ.set_nr_muls(0)) + g.write(left_styp) + g.write('_') + g.write(util.replace_op(node.op.str())) + g.write('(') + g.op_arg(node.left, method.params[0].typ, left.typ) + g.write(', ') + g.op_arg(node.right, method.params[1].typ, right.typ) + g.write(')') } // infix_expr_left_shift_op generates code for the `<<` operator @@ -515,6 +513,29 @@ fn (mut g Gen) gen_plain_infix_expr(node ast.InfixExpr) { g.expr_with_cast(node.right, node.right_type, node.left_type) } +fn (mut g Gen) op_arg(expr ast.Expr, expected ast.Type, got ast.Type) { + mut needs_closing := false + mut nr_muls := got.nr_muls() + if expected.is_ptr() { + if nr_muls > 0 { + nr_muls-- + } else { + if expr.is_lvalue() { + g.write('&') + } else { + styp := g.typ(got.set_nr_muls(0)) + g.write('ADDR($styp, ') + needs_closing = true + } + } + } + g.write('*'.repeat(nr_muls)) + g.expr(expr) + if needs_closing { + g.write(')') + } +} + struct GenSafeIntegerCfg { op token.Kind reverse bool