cgen: properly support reference args in receivers and arithmetic op methods (#10873)
parent
05d0288e8d
commit
f457b94fe4
|
@ -103,7 +103,7 @@ jobs:
|
||||||
run: |
|
run: |
|
||||||
./v tutorials/building_a_simple_web_blog_with_vweb/code/blog
|
./v tutorials/building_a_simple_web_blog_with_vweb/code/blog
|
||||||
- name: Build cmd/tools/fast
|
- 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:
|
ubuntu-tcc-boehm-gc:
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-20.04
|
||||||
|
|
|
@ -119,8 +119,8 @@ pub fn from_string(input string) Number {
|
||||||
}
|
}
|
||||||
|
|
||||||
// .int() converts (a small) big.Number `n` to an ordinary integer.
|
// .int() converts (a small) big.Number `n` to an ordinary integer.
|
||||||
pub fn (n Number) int() int {
|
pub fn (n &Number) int() int {
|
||||||
r := C.bignum_to_int(&n)
|
r := C.bignum_to_int(n)
|
||||||
return r
|
return r
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -129,7 +129,7 @@ const (
|
||||||
)
|
)
|
||||||
|
|
||||||
// .str returns a decimal representation of the big unsigned integer number n.
|
// .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() {
|
if n.is_zero() {
|
||||||
return '0'
|
return '0'
|
||||||
}
|
}
|
||||||
|
@ -145,13 +145,13 @@ pub fn (n Number) str() string {
|
||||||
}
|
}
|
||||||
|
|
||||||
// .hexstr returns a hexadecimal representation of the bignum `n`
|
// .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 buf := [8192]byte{}
|
||||||
mut s := ''
|
mut s := ''
|
||||||
unsafe {
|
unsafe {
|
||||||
bp := &buf[0]
|
bp := &buf[0]
|
||||||
// NB: C.bignum_to_string(), returns the HEXADECIMAL representation of the bignum n
|
// 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)
|
s = tos_clone(bp)
|
||||||
}
|
}
|
||||||
if s.len == 0 {
|
if s.len == 0 {
|
||||||
|
@ -162,33 +162,33 @@ pub fn (n Number) hexstr() string {
|
||||||
|
|
||||||
// //////////////////////////////////////////////////////////
|
// //////////////////////////////////////////////////////////
|
||||||
// overloaded ops for the numbers:
|
// overloaded ops for the numbers:
|
||||||
pub fn (a Number) + (b Number) Number {
|
pub fn (a &Number) + (b &Number) Number {
|
||||||
c := Number{}
|
c := Number{}
|
||||||
C.bignum_add(&a, &b, &c)
|
C.bignum_add(a, b, &c)
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (a Number) - (b Number) Number {
|
pub fn (a &Number) - (b &Number) Number {
|
||||||
c := Number{}
|
c := Number{}
|
||||||
C.bignum_sub(&a, &b, &c)
|
C.bignum_sub(a, b, &c)
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (a Number) * (b Number) Number {
|
pub fn (a &Number) * (b &Number) Number {
|
||||||
c := Number{}
|
c := Number{}
|
||||||
C.bignum_mul(&a, &b, &c)
|
C.bignum_mul(a, b, &c)
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (a Number) / (b Number) Number {
|
pub fn (a &Number) / (b &Number) Number {
|
||||||
c := Number{}
|
c := Number{}
|
||||||
C.bignum_div(&a, &b, &c)
|
C.bignum_div(a, b, &c)
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (a Number) % (b Number) Number {
|
pub fn (a &Number) % (b &Number) Number {
|
||||||
c := Number{}
|
c := Number{}
|
||||||
C.bignum_mod(&a, &b, &c)
|
C.bignum_mod(a, b, &c)
|
||||||
return 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 {
|
pub fn cmp(a &Number, b &Number) int {
|
||||||
return C.bignum_cmp(&a, &b)
|
return C.bignum_cmp(a, b)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (a Number) is_zero() bool {
|
pub fn (a &Number) is_zero() bool {
|
||||||
return C.bignum_is_zero(&a) != 0
|
return C.bignum_is_zero(a) != 0
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (mut a Number) inc() {
|
pub fn (mut a Number) inc() {
|
||||||
C.bignum_inc(a)
|
C.bignum_inc(&a)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (mut a Number) dec() {
|
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 := Number{}
|
||||||
C.bignum_pow(&a, &b, &c)
|
C.bignum_pow(a, b, &c)
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (a Number) isqrt() Number {
|
pub fn (a &Number) isqrt() Number {
|
||||||
b := Number{}
|
b := Number{}
|
||||||
C.bignum_isqrt(&a, &b)
|
C.bignum_isqrt(a, &b)
|
||||||
return b
|
return b
|
||||||
}
|
}
|
||||||
|
|
||||||
// //////////////////////////////////////////////////////////
|
// //////////////////////////////////////////////////////////
|
||||||
pub fn b_and(a Number, b Number) Number {
|
pub fn b_and(a &Number, b &Number) Number {
|
||||||
c := Number{}
|
c := Number{}
|
||||||
C.bignum_and(&a, &b, &c)
|
C.bignum_and(a, b, &c)
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn b_or(a Number, b Number) Number {
|
pub fn b_or(a &Number, b &Number) Number {
|
||||||
c := Number{}
|
c := Number{}
|
||||||
C.bignum_or(&a, &b, &c)
|
C.bignum_or(a, b, &c)
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn b_xor(a Number, b Number) Number {
|
pub fn b_xor(a &Number, b &Number) Number {
|
||||||
c := Number{}
|
c := Number{}
|
||||||
C.bignum_xor(&a, &b, &c)
|
C.bignum_xor(a, b, &c)
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (a Number) lshift(nbits int) Number {
|
pub fn (a &Number) lshift(nbits int) Number {
|
||||||
b := Number{}
|
b := Number{}
|
||||||
C.bignum_lshift(&a, &b, nbits)
|
C.bignum_lshift(a, &b, nbits)
|
||||||
return b
|
return b
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (a Number) rshift(nbits int) Number {
|
pub fn (a &Number) rshift(nbits int) Number {
|
||||||
b := Number{}
|
b := Number{}
|
||||||
C.bignum_rshift(&a, &b, nbits)
|
C.bignum_rshift(a, &b, nbits)
|
||||||
return b
|
return b
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (a Number) clone() Number {
|
pub fn (a &Number) clone() Number {
|
||||||
b := Number{}
|
b := Number{}
|
||||||
C.bignum_assign(&b, &a)
|
C.bignum_assign(&b, a)
|
||||||
return b
|
return b
|
||||||
}
|
}
|
||||||
|
|
||||||
// //////////////////////////////////////////////////////////
|
// //////////////////////////////////////////////////////////
|
||||||
pub fn factorial(nn Number) Number {
|
pub fn factorial(nn &Number) Number {
|
||||||
mut n := nn.clone()
|
mut n := nn.clone()
|
||||||
mut a := nn.clone()
|
mut a := nn.clone()
|
||||||
n.dec()
|
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(1).bytes()[0] == byte(0x01)
|
||||||
// Example: assert big.from_int(1024).bytes()[1] == byte(0x04)
|
// Example: assert big.from_int(1024).bytes()[1] == byte(0x04)
|
||||||
// Example: assert big.from_int(1048576).bytes()[2] == byte(0x10)
|
// 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}
|
mut res := []byte{len: 128, init: 0}
|
||||||
unsafe { C.memcpy(res.data, &n, 128) }
|
unsafe { C.memcpy(res.data, n, 128) }
|
||||||
return res
|
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(1).bytes_trimmed() == [byte(0x01)]
|
||||||
// Example: assert big.from_int(1024).bytes_trimmed() == [byte(0x00), 0x04]
|
// Example: assert big.from_int(1024).bytes_trimmed() == [byte(0x00), 0x04]
|
||||||
// Example: assert big.from_int(1048576).bytes_trimmed() == [byte(0x00), 0x00, 0x10]
|
// 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}
|
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
|
mut non_zero_idx := 127
|
||||||
for ; non_zero_idx >= 0; non_zero_idx-- {
|
for ; non_zero_idx >= 0; non_zero_idx-- {
|
||||||
if res[non_zero_idx] != 0 {
|
if res[non_zero_idx] != 0 {
|
||||||
|
|
|
@ -31,6 +31,11 @@ fn test_plus() {
|
||||||
assert (big.from_u64(1024) + big.from_u64(1024)).hexstr() == '800'
|
assert (big.from_u64(1024) + big.from_u64(1024)).hexstr() == '800'
|
||||||
a += b
|
a += b
|
||||||
assert a.hexstr() == '5'
|
assert a.hexstr() == '5'
|
||||||
|
a.inc()
|
||||||
|
assert a.hexstr() == '6'
|
||||||
|
a.dec()
|
||||||
|
a.dec()
|
||||||
|
assert a.hexstr() == '4'
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_minus() {
|
fn test_minus() {
|
||||||
|
|
|
@ -2606,6 +2606,8 @@ fn (mut g Gen) gen_assign_stmt(assign_stmt ast.AssignStmt) {
|
||||||
}
|
}
|
||||||
mut str_add := false
|
mut str_add := false
|
||||||
mut op_overloaded := 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 var_type == ast.string_type_idx && assign_stmt.op == .plus_assign {
|
||||||
if left is ast.IndexExpr {
|
if left is ast.IndexExpr {
|
||||||
// a[0] += str => `array_set(&a, 0, &(string[]) {string__plus(...))})`
|
// 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.expr(left)
|
||||||
g.write(' = ${styp}_${util.replace_op(extracted_op)}(')
|
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
|
op_overloaded = true
|
||||||
}
|
}
|
||||||
if right_sym.kind == .function && is_decl {
|
if right_sym.kind == .function && is_decl {
|
||||||
|
@ -2681,12 +2691,16 @@ fn (mut g Gen) gen_assign_stmt(assign_stmt ast.AssignStmt) {
|
||||||
g.prevent_sum_type_unwrapping_once = true
|
g.prevent_sum_type_unwrapping_once = true
|
||||||
}
|
}
|
||||||
if !is_fixed_array_var || is_decl {
|
if !is_fixed_array_var || is_decl {
|
||||||
|
if op_overloaded {
|
||||||
|
g.op_arg(left, op_expected_left, var_type)
|
||||||
|
} else {
|
||||||
if !is_decl && left.is_auto_deref_var() {
|
if !is_decl && left.is_auto_deref_var() {
|
||||||
g.write('*')
|
g.write('*')
|
||||||
}
|
}
|
||||||
g.expr(left)
|
g.expr(left)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if is_inside_ternary && is_decl {
|
if is_inside_ternary && is_decl {
|
||||||
g.write(';\n$cur_line')
|
g.write(';\n$cur_line')
|
||||||
g.out.write_string(util.tabs(g.indent))
|
g.out.write_string(util.tabs(g.indent))
|
||||||
|
@ -2769,11 +2783,15 @@ fn (mut g Gen) gen_assign_stmt(assign_stmt ast.AssignStmt) {
|
||||||
} else {
|
} else {
|
||||||
if assign_stmt.has_cross_var {
|
if assign_stmt.has_cross_var {
|
||||||
g.gen_cross_tmp_variable(assign_stmt.left, val)
|
g.gen_cross_tmp_variable(assign_stmt.left, val)
|
||||||
|
} else {
|
||||||
|
if op_overloaded {
|
||||||
|
g.op_arg(val, op_expected_right, val_type)
|
||||||
} else {
|
} else {
|
||||||
g.expr_with_cast(val, val_type, var_type)
|
g.expr_with_cast(val, val_type, var_type)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if str_add || op_overloaded {
|
if str_add || op_overloaded {
|
||||||
g.write(')')
|
g.write(')')
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)
|
g.checker_bug('ref_or_deref_arg expected_type is 0', arg.pos)
|
||||||
}
|
}
|
||||||
exp_sym := g.table.get_type_symbol(expected_type)
|
exp_sym := g.table.get_type_symbol(expected_type)
|
||||||
|
mut needs_closing := false
|
||||||
if arg.is_mut && !arg_is_ptr {
|
if arg.is_mut && !arg_is_ptr {
|
||||||
g.write('&/*mut*/')
|
g.write('&/*mut*/')
|
||||||
} else if arg_is_ptr && !expr_is_ptr {
|
} 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)
|
deref_sym := g.table.get_type_symbol(expected_deref_type)
|
||||||
if !((arg_typ_sym.kind == .function)
|
if !((arg_typ_sym.kind == .function)
|
||||||
|| deref_sym.kind in [.sum_type, .interface_]) && lang != .c {
|
|| deref_sym.kind in [.sum_type, .interface_]) && lang != .c {
|
||||||
|
if arg.expr.is_lvalue() {
|
||||||
g.write('(voidptr)&/*qq*/')
|
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) {
|
} 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
|
return
|
||||||
}
|
}
|
||||||
g.expr_with_cast(arg.expr, arg.typ, expected_type)
|
g.expr_with_cast(arg.expr, arg.typ, expected_type)
|
||||||
|
if needs_closing {
|
||||||
|
g.write(')')
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (mut g Gen) is_gui_app() bool {
|
fn (mut g Gen) is_gui_app() bool {
|
||||||
|
|
|
@ -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) {
|
fn (mut g Gen) infix_expr_arithmetic_op(node ast.InfixExpr) {
|
||||||
left := g.unwrap(node.left_type)
|
left := g.unwrap(node.left_type)
|
||||||
right := g.unwrap(node.right_type)
|
right := g.unwrap(node.right_type)
|
||||||
has_operator_overloading := g.table.type_has_method(left.sym, node.op.str())
|
method := g.table.type_find_method(left.sym, node.op.str()) or {
|
||||||
if left.sym.kind == right.sym.kind && has_operator_overloading {
|
g.gen_plain_infix_expr(node)
|
||||||
g.write(g.typ(left.typ.set_nr_muls(0)))
|
return
|
||||||
|
}
|
||||||
|
left_styp := g.typ(left.typ.set_nr_muls(0))
|
||||||
|
g.write(left_styp)
|
||||||
g.write('_')
|
g.write('_')
|
||||||
g.write(util.replace_op(node.op.str()))
|
g.write(util.replace_op(node.op.str()))
|
||||||
g.write('(')
|
g.write('(')
|
||||||
g.write('*'.repeat(left.typ.nr_muls()))
|
g.op_arg(node.left, method.params[0].typ, left.typ)
|
||||||
g.expr(node.left)
|
|
||||||
g.write(', ')
|
g.write(', ')
|
||||||
g.write('*'.repeat(right.typ.nr_muls()))
|
g.op_arg(node.right, method.params[1].typ, right.typ)
|
||||||
g.expr(node.right)
|
|
||||||
g.write(')')
|
g.write(')')
|
||||||
} else {
|
|
||||||
g.gen_plain_infix_expr(node)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// infix_expr_left_shift_op generates code for the `<<` operator
|
// 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)
|
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 {
|
struct GenSafeIntegerCfg {
|
||||||
op token.Kind
|
op token.Kind
|
||||||
reverse bool
|
reverse bool
|
||||||
|
|
Loading…
Reference in New Issue