js: add more tests for array, support array insert_many, minor fixes for references (#10983)

pull/10986/head
playX 2021-07-28 13:01:00 +03:00 committed by GitHub
parent 66bc8bc0cb
commit e3cf95b058
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 342 additions and 10 deletions

View File

@ -4,6 +4,7 @@ struct array {
arr JS.Array
pub:
len int
cap int
}
#function flatIntoArray(target, source, sourceLength, targetIndex, depth) {
@ -50,6 +51,14 @@ pub fn (a array) repeat_to_depth(count int, depth int) array {
return arr
}
// last returns the last element of the array.
pub fn (a array) last() voidptr {
mut res := voidptr(0)
#res = a.arr[a.len-1];
return res
}
fn (a array) get(ix int) voidptr {
mut result := voidptr(0)
#result = a.arr[ix]
@ -104,6 +113,10 @@ pub fn (mut a array) insert(i int, val voidptr) {
#a.arr.splice(i,0,val)
}
pub fn (mut a array) insert_many(i int, val voidptr, size int) {
#a.arr.splice(i,0,...val.slice(0,+size))
}
pub fn (mut a array) join(separator string) string {
mut res := ''
#res = new builtin.string(a.arr.join(separator +''));
@ -115,7 +128,24 @@ fn (a array) push(val voidptr) {
#a.arr.push(val)
}
pub fn (a array) str() string {
mut res := ''
#res = new builtin.string(a + '')
return res
}
#array.prototype[Symbol.iterator] = function () { return this.arr[Symbol.iterator](); }
#array.prototype.entries = function () { return this.arr.entries(); }
#array.prototype.map = function(callback) { return this.arr.map(callback); }
#array.prototype.filter = function(callback) { return this.arr.filter(callback); }
#Object.defineProperty(array.prototype,'cap',{ get: function () { return this.len; } })
// delete deletes array element at index `i`.
pub fn (mut a array) delete(i int) {
a.delete_many(i, 1)
}
// delete_many deletes `size` elements beginning with index `i`
pub fn (mut a array) delete_many(i int, size int) {
#a.arr.splice(i.valueOf(),size.valueOf())
}

View File

@ -38,6 +38,9 @@ fn (mut g JsGen) to_js_typ_val(t ast.Type) string {
.struct_ {
styp = 'new ${g.js_name(sym.name)}(${g.to_js_typ_def_val(sym.name)})'
}
.voidptr {
styp = 'null'
}
else {
// TODO
styp = 'undefined'
@ -100,6 +103,9 @@ fn (mut g JsGen) sym_to_js_typ(sym ast.TypeSymbol) string {
.array {
styp = 'array'
}
.voidptr {
styp = 'any'
}
else {
// TODO
styp = 'undefined'
@ -358,6 +364,17 @@ fn (mut g JsGen) gen_builtin_type_defs() {
eq: 'vEq(this, other)'
)
}
'any' {
g.gen_builtin_prototype(
typ_name: typ_name
val_name: 'any'
default_value: 'null'
constructor: 'this.val = any'
value_of: 'this.val'
to_string: '"&" + this.val'
eq: 'this == other' // compare by ptr
)
}
else {}
}
}

View File

@ -5,7 +5,8 @@ function vEq(a, b) {
if (a && b && typeof a == 'object' && typeof b == 'object') {
if (a.constructor !== b.constructor) return false;
a = a.valueOf();
b = b.valueOf();
var length, i, keys;
if (Array.isArray(a)) {
length = a.length;
@ -62,5 +63,5 @@ function vEq(a, b) {
}
// true if both NaN, false otherwise
return a!==a && b!==b;
return a !== a && b !== b;
};

View File

@ -25,7 +25,7 @@ const (
'Array', 'Map']
// used to generate type structs
v_types = ['i8', 'i16', 'int', 'i64', 'byte', 'u16', 'u32', 'u64', 'f32', 'f64',
'int_literal', 'float_literal', 'size_t', 'bool', 'string', 'map', 'array']
'int_literal', 'float_literal', 'size_t', 'bool', 'string', 'map', 'array', 'any']
shallow_equatables = [ast.Kind.i8, .i16, .int, .i64, .byte, .u16, .u32, .u64, .f32, .f64,
.int_literal, .float_literal, .size_t, .bool, .string]
)
@ -682,9 +682,7 @@ fn (mut g JsGen) expr(node ast.Expr) {
if node.op in [.amp, .mul] {
// C pointers/references: ignore them
if node.op == .amp {
type_sym := g.table.get_type_symbol(node.right_type)
if !type_sym.is_primitive() && !node.right_type.is_pointer() {
if !node.right_type.is_pointer() {
// kind of weird way to handle references but it allows us to access type methods easily.
g.write('(function(x) {')
g.write(' return { val: x, __proto__: Object.getPrototypeOf(x), valueOf: function() { return this.val; } }})( ')
@ -696,12 +694,14 @@ fn (mut g JsGen) expr(node ast.Expr) {
} else {
g.write('(')
g.expr(node.right)
g.write(').val')
g.write(').valueOf()')
}
} else {
g.write(node.op.str())
g.write('(')
g.expr(node.right)
g.write('.valueOf()')
g.write(')')
}
}
ast.RangeExpr {
@ -1103,7 +1103,7 @@ fn (mut g JsGen) gen_for_in_stmt(it ast.ForInStmt) {
g.expr(it.cond)
g.write('; $i < ')
g.expr(it.high)
g.writeln('; ++$i) {')
g.writeln('; $i = new builtin.int($i + 1)) {')
g.inside_loop = false
g.stmts(it.stmts)
g.writeln('}')
@ -1379,6 +1379,7 @@ fn (mut g JsGen) gen_call_expr(it ast.CallExpr) {
g.write('return builtin.unwrap(')
}
g.expr(it.left)
if it.is_method { // foo.bar.baz()
sym := g.table.get_type_symbol(it.receiver_type)
g.write('.')
@ -1410,11 +1411,42 @@ fn (mut g JsGen) gen_call_expr(it ast.CallExpr) {
}
else {}
}
g.write('it => ')
g.expr(node.args[0].expr)
g.write(')')
return
}
left_sym := g.table.get_type_symbol(it.left_type)
if left_sym.kind == .array {
node := it
match node.name {
'insert' {
arg2_sym := g.table.get_type_symbol(node.args[1].typ)
is_arg2_array := arg2_sym.kind == .array && node.args[1].typ == node.left_type
if is_arg2_array {
g.write('insert_many(')
} else {
g.write('insert(')
}
g.expr(node.args[0].expr)
g.write(',')
if is_arg2_array {
g.expr(node.args[1].expr)
g.write('.arr,')
g.expr(node.args[1].expr)
g.write('.len')
} else {
g.expr(node.args[1].expr)
}
g.write(')')
return
}
else {}
}
}
} else {
if name in g.builtin_fns {
g.write('builtin.')
@ -1647,8 +1679,9 @@ fn (mut g JsGen) gen_infix_expr(it ast.InfixExpr) {
g.write('Array.prototype.push.call(')
g.expr(it.left)
g.write('.arr,')
array_info := l_sym.info as ast.Array
// arr << [1, 2]
if r_sym.kind == .array {
if r_sym.kind == .array && array_info.elem_type != it.right_type {
g.write('...')
}
g.expr(it.right)

View File

@ -9,7 +9,8 @@ function vEq(a, b) {
if (a && b && typeof a == 'object' && typeof b == 'object') {
if (a.constructor !== b.constructor) return false;
a = a.valueOf();
b = b.valueOf();
var length, i, keys;
if (Array.isArray(a)) {
length = a.length;

View File

@ -0,0 +1,64 @@
3
1
2
4
255
256
2
4
131
4
1
2
3
5
4
4
[1,5,2,3,4]
5
4
5
[1,5,2,3,4]
[5,2,3,4]
4
[5,3,4]
3
[5,3]
2
[2.5,3.25,4.5,5.75]
true
true
true
true
true
true
true
true
true
true
true
1
2
3
10000
234
0
1
0
1
3
[1,3]
3
2
3
4
1
4
5
2
5
0
1
1.1
[1,2,3,4]
[1,5,6,2,3,4]

View File

@ -0,0 +1,186 @@
struct Chunk {
val string
}
struct Kkk {
q []Chunk
}
fn main() {
{
// test pointer
mut arr := []&int{}
a := 1
b := 2
c := 3
arr << &a
arr << &b
arr << &c
assert *arr[0] == 1
arr[1] = &c
assert *arr[1] == 3
mut d_arr := [arr] // [][]&int
d_arr << arr
println(*d_arr[0][1]) // 3
println(*d_arr[1][0]) // 1
}
{
// test assign
mut arr := [2, 4, 8, 16, 32, 64, 128]
arr[0] = 2
arr[1] &= 255
arr[2] |= 255
arr[3] <<= 4
arr[4] >>= 4
arr[5] %= 5
arr[6] ^= 3
println(arr[0])
println(arr[1])
println(arr[2])
println(arr[3])
println(arr[4])
println(arr[5])
println(arr[6])
}
{
// test ints
mut a := [1, 5, 2, 3]
println(a.len) // 4
println(a[0])
println(a[2])
println(a.last())
a << 4
println(a.len)
println(a[4])
println(a.last())
s := a.str()
println(s)
println(a[1])
println(a.last())
}
{
// test deleting
mut a := [1, 5, 2, 3, 4]
println(a.len)
println(a.str())
a.delete(0)
println(a.str())
println(a.len) // 4
a.delete(1)
println(a.str())
println(a.len)
a.delete(a.len - 1)
println(a.str())
println(a.len)
}
{
// test slice delete
mut a := [1.5, 2.5, 3.25, 4.5, 5.75]
b := a[2..4]
a.delete(0)
// assert a == [2.5, 3.25, 4.5, 5.75]
// assert b == [3.25, 4.5]
println(a)
println(a == [2.5, 3.25, 4.5, 5.75])
println(b == [3.25, 4.5])
a = [3.75, 4.25, -1.5, 2.25, 6.0]
c := a[..3]
a.delete(2)
println(a == [3.75, 4.25, 2.25, 6.0])
println(c == [3.75, 4.25, -1.5])
}
{
// test delete many
mut a := [1, 2, 3, 4, 5, 6, 7, 8, 9]
b := a[2..6]
a.delete_many(4, 3)
println(a == [1, 2, 3, 4, 8, 9])
println(b == [3, 4, 5, 6])
c := a[..a.len]
a.delete_many(2, 0) // this should just clone
a[1] = 17
println(a == [1, 17, 3, 4, 8, 9])
println(c == [1, 2, 3, 4, 8, 9])
a.delete_many(0, a.len)
println(a == []int{})
}
{
// test short
a := [1, 2, 3]
println(a.len == 3)
println(a.cap == 3)
println(a[0])
println(a[1])
println(a[2])
}
{
// test large
mut a := [0].repeat(0)
for i in 0 .. 10000 {
a << i
}
println(a.len)
println(a[234])
}
{
// test empty
mut chunks := []Chunk{}
a := Chunk{}
println(chunks.len)
chunks << a
println(chunks.len)
chunks = []
println(chunks.len)
chunks << a
println(chunks.len)
}
{
// test push
mut a := []int{}
a << 1
a << 3
println(a[1])
println(a.str())
}
{
// test insert
mut a := [1, 2]
a.insert(0, 3)
println(a[0])
println(a[2])
println(a.len)
a.insert(1, 4)
println(a[1])
println(a[2])
println(a.len)
a.insert(4, 5)
println(a[4])
println(a[3])
println(a.len)
mut b := []f64{}
println(b.len)
b.insert(0, f64(1.1))
println(b.len)
println(b[0])
}
{
// test insert many
mut a := [3, 4]
a.insert(0, [1, 2])
println(a)
b := [5, 6]
a.insert(1, b)
println(a)
}
}