From b72d1e5e869b5b7f238951b6c9172cf313a71fed Mon Sep 17 00:00:00 2001 From: playX Date: Fri, 13 Aug 2021 21:24:10 +0300 Subject: [PATCH] v.gen.js: implement `u64` and `i64` with BigInt (#11174) --- vlib/v/gen/js/builtin_types.v | 25 ++++++++++++++- vlib/v/gen/js/js.v | 42 ++++++++++++++++++++++++-- vlib/v/gen/js/tests/testdata/array.out | 2 +- vlib/v/gen/js/tests/testdata/u64.out | 4 +++ vlib/v/gen/js/tests/testdata/u64.v | 7 +++++ 5 files changed, 75 insertions(+), 5 deletions(-) create mode 100644 vlib/v/gen/js/tests/testdata/u64.out create mode 100644 vlib/v/gen/js/tests/testdata/u64.v diff --git a/vlib/v/gen/js/builtin_types.v b/vlib/v/gen/js/builtin_types.v index 69158dd568..10bfa334c9 100644 --- a/vlib/v/gen/js/builtin_types.v +++ b/vlib/v/gen/js/builtin_types.v @@ -299,7 +299,7 @@ fn (mut g JsGen) gen_builtin_type_defs() { for typ_name in v_types { // TODO: JsDoc match typ_name { - 'i8', 'i16', 'int', 'i64', 'u16', 'u32', 'u64', 'int_literal', 'size_t' { + 'i8', 'i16', 'int', 'u16', 'u32', 'int_literal', 'size_t' { // TODO: Bounds checking g.gen_builtin_prototype( typ_name: typ_name @@ -311,6 +311,29 @@ fn (mut g JsGen) gen_builtin_type_defs() { to_jsval: '+this' ) } + // u64 and i64 are so big that their values do not fit into JS number so we use BigInt. + 'u64' { + g.gen_builtin_prototype( + typ_name: typ_name + default_value: 'BigInt(0)' + constructor: 'this.val = BigInt.asUintN(64,BigInt(val))' + value_of: 'this.val' + to_string: 'this.val.toString()' + eq: 'this.valueOf() === other.valueOf()' + to_jsval: 'this.val' + ) + } + 'i64' { + g.gen_builtin_prototype( + typ_name: typ_name + default_value: 'BigInt(0)' + constructor: 'this.val = BigInt.asIntN(64,BigInt(val))' + value_of: 'this.val' + to_string: 'this.val.toString()' + eq: 'this.valueOf() === other.valueOf()' + to_jsval: 'this.val' + ) + } 'byte' { g.gen_builtin_prototype( typ_name: typ_name diff --git a/vlib/v/gen/js/js.v b/vlib/v/gen/js/js.v index d86e34e382..b1852ea81d 100644 --- a/vlib/v/gen/js/js.v +++ b/vlib/v/gen/js/js.v @@ -1770,7 +1770,30 @@ fn (mut g JsGen) gen_infix_expr(it ast.InfixExpr) { if is_not { g.write('!(') } - + is_arithmetic := it.op in [token.Kind.plus, .minus, .mul, .div, .mod] + if is_arithmetic && ((l_sym.kind == .i64 || l_sym.kind == .u64) + || (r_sym.kind == .i64 || r_sym.kind == .u64)) { + // if left or right is i64 or u64 we convert them to bigint to perform operation. + greater_typ := g.greater_typ(it.left_type, it.right_type) + if g.ns.name == 'builtin' { + g.write('new ') + } + g.write('${g.typ(greater_typ)}(') + g.cast_stack << greater_typ + g.write('BigInt((') + g.expr(it.left) + g.write(').\$toJS())') + g.write(' $it.op ') + g.write('BigInt((') + g.expr(it.right) + g.write(').\$toJS())') + g.cast_stack.delete_last() + g.write(')') + if is_not { + g.write(')') + } + return + } if it.op == .eq || it.op == .ne { has_operator_overloading := g.table.type_has_method(l_sym, '==') if has_operator_overloading { @@ -1842,7 +1865,6 @@ fn (mut g JsGen) gen_infix_expr(it ast.InfixExpr) { g.write(')') } } else { - is_arithmetic := it.op in [token.Kind.plus, .minus, .mul, .div, .mod] has_operator_overloading := g.table.type_has_method(l_sym, it.op.str()) if has_operator_overloading { g.expr(it.left) @@ -1926,7 +1948,9 @@ fn (mut g JsGen) greater_typ(left ast.Type, right ast.Type) ast.Type { } should_int := (l in ast.integer_type_idxs && r in ast.integer_type_idxs) if should_int { - // cant add to u64 - if (ast.u64_type_idx in lr) { return ast.Type(ast.u64_type_idx) } + if ast.u64_type_idx in lr { + return ast.Type(ast.u64_type_idx) + } // just guessing this order if ast.i64_type_idx in lr { return ast.Type(ast.i64_type_idx) @@ -2099,8 +2123,20 @@ fn (mut g JsGen) gen_type_cast_expr(it ast.CastExpr) { is_literal := ((it.expr is ast.IntegerLiteral && it.typ in ast.integer_type_idxs) || (it.expr is ast.FloatLiteral && it.typ in ast.float_type_idxs)) // Skip cast if type is the same as the parrent caster + tsym := g.table.get_type_symbol(it.typ) + if it.expr is ast.IntegerLiteral && (tsym.kind == .i64 || tsym.kind == .u64) { + if g.ns.name == 'builtin' { + g.write('new ') + } + g.write(tsym.kind.str()) + g.write('(BigInt(') + g.write(it.expr.val) + g.write('n))') + return + } if g.cast_stack.len > 0 && is_literal { if it.typ == g.cast_stack[g.cast_stack.len - 1] { + g.expr(it.expr) return } } diff --git a/vlib/v/gen/js/tests/testdata/array.out b/vlib/v/gen/js/tests/testdata/array.out index c152476d81..4b7cad7a95 100644 --- a/vlib/v/gen/js/tests/testdata/array.out +++ b/vlib/v/gen/js/tests/testdata/array.out @@ -286,7 +286,7 @@ true true true true -true +false true true true diff --git a/vlib/v/gen/js/tests/testdata/u64.out b/vlib/v/gen/js/tests/testdata/u64.out new file mode 100644 index 0000000000..99738c474d --- /dev/null +++ b/vlib/v/gen/js/tests/testdata/u64.out @@ -0,0 +1,4 @@ +18446744073709551615 +0 +true +25600000 \ No newline at end of file diff --git a/vlib/v/gen/js/tests/testdata/u64.v b/vlib/v/gen/js/tests/testdata/u64.v new file mode 100644 index 0000000000..2f9e0f00a6 --- /dev/null +++ b/vlib/v/gen/js/tests/testdata/u64.v @@ -0,0 +1,7 @@ +fn main() { + println(u64(18446744073709551615)) + println(u64(18446744073709551615) + 1) + + println(u64(42) == u64(42)) + println(u64(100000) * 256) +}