v.gen.js: implement `u64` and `i64` with BigInt (#11174)

pull/11176/head
playX 2021-08-13 21:24:10 +03:00 committed by GitHub
parent 34d39ccb64
commit b72d1e5e86
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 75 additions and 5 deletions

View File

@ -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

View File

@ -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
}
}

View File

@ -286,7 +286,7 @@ true
true
true
true
true
false
true
true
true

View File

@ -0,0 +1,4 @@
18446744073709551615
0
true
25600000

View File

@ -0,0 +1,7 @@
fn main() {
println(u64(18446744073709551615))
println(u64(18446744073709551615) + 1)
println(u64(42) == u64(42))
println(u64(100000) * 256)
}