Skip to content

Commit a7ca051

Browse files
authored
v.gen.js: fix for array filter, add more tests and other fixes (#10999)
1 parent ab6ab51 commit a7ca051

File tree

7 files changed

+347
-17
lines changed

7 files changed

+347
-17
lines changed

vlib/builtin/js/array.js.v

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,7 @@ pub fn (a array) str() string {
138138
#array.prototype[Symbol.iterator] = function () { return this.arr[Symbol.iterator](); }
139139
#array.prototype.entries = function () { return this.arr.entries(); }
140140
#array.prototype.map = function(callback) { return this.arr.map(callback); }
141-
#array.prototype.filter = function(callback) { return this.arr.filter(callback); }
141+
#array.prototype.filter = function(callback) { return new array(this.arr.filter( function (it) { return (+callback(it)) != 0; } )); }
142142
#Object.defineProperty(array.prototype,'cap',{ get: function () { return this.len; } })
143143
// delete deletes array element at index `i`.
144144
pub fn (mut a array) delete(i int) {
@@ -160,3 +160,23 @@ pub fn (mut a array) prepend(val voidptr) {
160160
pub fn (mut a array) prepend_many(val voidptr, size int) {
161161
unsafe { a.insert_many(0, val, size) }
162162
}
163+
164+
pub fn (a array) reverse() array {
165+
mut res := array{}
166+
#res.arr = Array.from(a.arr).reverse()
167+
168+
return res
169+
}
170+
171+
#array.prototype.$includes = function (elem) { return this.arr.find(function(e) { return vEq(elem,e); }) !== undefined;}
172+
173+
// reduce executes a given reducer function on each element of the array,
174+
// resulting in a single output value.
175+
pub fn (a array) reduce(iter fn (int, int) int, accum_start int) int {
176+
mut accum_ := accum_start
177+
#for (let i of a) {
178+
#accum_ = iter(accum_, a.arr[i])
179+
#}
180+
181+
return accum_
182+
}

vlib/v/gen/js/builtin_types.v

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -263,6 +263,7 @@ struct BuiltinPrototypeConfig {
263263
value_of string = 'this.val'
264264
to_string string = 'this.val.toString()'
265265
eq string = 'this.val === other.val'
266+
to_jsval string = 'this'
266267
extras string
267268
has_strfn bool
268269
}
@@ -284,6 +285,7 @@ fn (mut g JsGen) gen_builtin_prototype(c BuiltinPrototypeConfig) {
284285
g.writeln('valueOf() { return $c.value_of },')
285286
g.writeln('toString() { return $c.to_string },')
286287
g.writeln('eq(other) { return $c.eq },')
288+
g.writeln('\$toJS() { return $c.to_jsval }, ')
287289
if c.has_strfn {
288290
g.writeln('str() { return new string(this.toString()) }')
289291
}
@@ -306,6 +308,7 @@ fn (mut g JsGen) gen_builtin_type_defs() {
306308
value_of: 'this.val | 0'
307309
to_string: 'this.valueOf().toString()'
308310
eq: 'this.valueOf() === other.valueOf()'
311+
to_jsval: '+this'
309312
)
310313
}
311314
'byte' {
@@ -316,18 +319,22 @@ fn (mut g JsGen) gen_builtin_type_defs() {
316319
value_of: 'this.val | 0'
317320
to_string: 'new string(this.val + "")'
318321
eq: 'this.valueOf() === other.valueOf()'
322+
to_jsval: '+this'
319323
)
320324
}
321325
'f32', 'f64', 'float_literal' {
322326
g.gen_builtin_prototype(
323327
typ_name: typ_name
324328
default_value: 'new Number(0)'
329+
to_jsval: '+this'
325330
)
326331
}
327332
'bool' {
328333
g.gen_builtin_prototype(
334+
constructor: 'this.val = +val !== 0'
329335
typ_name: typ_name
330336
default_value: 'new Boolean(false)'
337+
to_jsval: '+this != 0'
331338
)
332339
}
333340
'string' {
@@ -340,6 +347,7 @@ fn (mut g JsGen) gen_builtin_type_defs() {
340347
to_string: 'this.str'
341348
eq: 'this.str === other.str'
342349
has_strfn: false
350+
to_jsval: 'this.str'
343351
)
344352
}
345353
'map' {
@@ -348,9 +356,10 @@ fn (mut g JsGen) gen_builtin_type_defs() {
348356
val_name: 'map'
349357
default_value: 'new Map()'
350358
constructor: 'this.map = map'
351-
value_of: 'this.map'
359+
value_of: 'this'
352360
to_string: 'this.map.toString()'
353361
eq: 'vEq(this, other)'
362+
to_jsval: 'this.map'
354363
)
355364
}
356365
'array' {
@@ -359,9 +368,10 @@ fn (mut g JsGen) gen_builtin_type_defs() {
359368
val_name: 'arr'
360369
default_value: 'new Array()'
361370
constructor: 'this.arr = arr'
362-
value_of: 'this.arr'
371+
value_of: 'this'
363372
to_string: 'JSON.stringify(this.arr.map(it => it.valueOf()))'
364373
eq: 'vEq(this, other)'
374+
to_jsval: 'this.arr'
365375
)
366376
}
367377
'any' {
@@ -373,6 +383,7 @@ fn (mut g JsGen) gen_builtin_type_defs() {
373383
value_of: 'this.val'
374384
to_string: '"&" + this.val'
375385
eq: 'this == other' // compare by ptr
386+
to_jsval: 'this.val.\$toJS()'
376387
)
377388
}
378389
else {}

vlib/v/gen/js/fast_deep_equal.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ function vEq(a, b) {
55

66
if (a && b && typeof a == 'object' && typeof b == 'object') {
77
if (a.constructor !== b.constructor) return false;
8-
a = a.valueOf();
9-
b = b.valueOf();
8+
a = a.$toJS();
9+
b = b.$toJS();
1010
var length, i, keys;
1111
if (Array.isArray(a)) {
1212
length = a.length;

vlib/v/gen/js/js.v

Lines changed: 47 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1079,6 +1079,7 @@ fn (mut g JsGen) gen_for_c_stmt(it ast.ForCStmt) {
10791079
g.write('; ')
10801080
}
10811081
if it.has_cond {
1082+
g.write('+') // convert to number or boolean
10821083
g.expr(it.cond)
10831084
}
10841085
g.write('; ')
@@ -1174,6 +1175,7 @@ fn (mut g JsGen) gen_for_stmt(it ast.ForStmt) {
11741175
if it.is_inf {
11751176
g.write('true')
11761177
} else {
1178+
g.write('+') // convert expr to number or boolean
11771179
g.expr(it.cond)
11781180
}
11791181
g.writeln(') {')
@@ -1325,6 +1327,7 @@ fn (mut g JsGen) gen_array_init_expr(it ast.ArrayInit) {
13251327
// offering similar performance
13261328
g.write('new array(')
13271329
g.inc_indent()
1330+
13281331
if it.has_len {
13291332
t1 := g.new_tmp_var()
13301333
t2 := g.new_tmp_var()
@@ -1349,6 +1352,31 @@ fn (mut g JsGen) gen_array_init_expr(it ast.ArrayInit) {
13491352
g.writeln('return $t1;')
13501353
g.dec_indent()
13511354
g.write('})()')
1355+
} else if it.is_fixed && it.exprs.len == 1 {
1356+
// [100]byte codegen
1357+
t1 := g.new_tmp_var()
1358+
t2 := g.new_tmp_var()
1359+
g.writeln('(function() {')
1360+
g.inc_indent()
1361+
g.writeln('const $t1 = [];')
1362+
g.write('for (let $t2 = 0; $t2 < ')
1363+
g.expr(it.exprs[0])
1364+
g.writeln('; $t2++) {')
1365+
g.inc_indent()
1366+
g.write('${t1}.push(')
1367+
if it.has_default {
1368+
g.expr(it.default_expr)
1369+
} else {
1370+
// Fill the array with the default values for its type
1371+
t := g.to_js_typ_val(it.elem_type)
1372+
g.write(t)
1373+
}
1374+
g.writeln(');')
1375+
g.dec_indent()
1376+
g.writeln('};')
1377+
g.writeln('return $t1;')
1378+
g.dec_indent()
1379+
g.write('})()')
13521380
} else {
13531381
g.gen_array_init_values(it.exprs)
13541382
}
@@ -1549,7 +1577,9 @@ fn (mut g JsGen) gen_if_expr(node ast.IfExpr) {
15491577
g.write(' : ')
15501578
}
15511579
if i < node.branches.len - 1 || !node.has_else {
1580+
g.write('(')
15521581
g.expr(branch.cond)
1582+
g.write(')')
15531583
g.write('.valueOf()')
15541584
g.write(' ? ')
15551585
}
@@ -1570,15 +1600,19 @@ fn (mut g JsGen) gen_if_expr(node ast.IfExpr) {
15701600
if '$branch.cond' == 'js' {
15711601
g.write('true')
15721602
} else {
1603+
g.write('(')
15731604
g.expr(branch.cond)
1605+
g.write(')')
15741606
g.write('.valueOf()')
15751607
}
15761608
g.writeln(') {')
15771609
}
15781610
}
15791611
} else if i < node.branches.len - 1 || !node.has_else {
15801612
g.write('} else if (')
1613+
g.write('(')
15811614
g.expr(branch.cond)
1615+
g.write(')')
15821616
g.write('.valueOf()')
15831617
g.writeln(') {')
15841618
} else if i == node.branches.len - 1 && node.has_else {
@@ -1608,7 +1642,7 @@ fn (mut g JsGen) gen_index_expr(expr ast.IndexExpr) {
16081642
if expr.index is ast.RangeExpr {
16091643
g.expr(expr.left)
16101644
if expr.left_type.is_ptr() {
1611-
g.write('.val')
1645+
g.write('.valueOf()')
16121646
}
16131647
g.write('.slice(')
16141648
if expr.index.has_low {
@@ -1622,7 +1656,7 @@ fn (mut g JsGen) gen_index_expr(expr ast.IndexExpr) {
16221656
} else {
16231657
g.expr(expr.left)
16241658
if expr.left_type.is_ptr() {
1625-
g.write('.val')
1659+
g.write('.valueOf()')
16261660
}
16271661
g.write('.length')
16281662
}
@@ -1649,7 +1683,7 @@ fn (mut g JsGen) gen_index_expr(expr ast.IndexExpr) {
16491683
g.write('new byte(')
16501684
g.expr(expr.left)
16511685
if expr.left_type.is_ptr() {
1652-
g.write('.val')
1686+
g.write('.valueOf()')
16531687
}
16541688
g.write('.str.charCodeAt(')
16551689
g.expr(expr.index)
@@ -1659,10 +1693,10 @@ fn (mut g JsGen) gen_index_expr(expr ast.IndexExpr) {
16591693
// TODO Does this cover all cases?
16601694
g.expr(expr.left)
16611695
if expr.left_type.is_ptr() {
1662-
g.write('.val')
1696+
g.write('.valueOf()')
16631697
}
16641698
g.write('.arr')
1665-
g.write('[')
1699+
g.write('[+')
16661700
g.cast_stack << ast.int_type_idx
16671701
g.expr(expr.index)
16681702
g.cast_stack.delete_last()
@@ -1682,7 +1716,10 @@ fn (mut g JsGen) gen_infix_expr(it ast.InfixExpr) {
16821716
if it.op == .eq || it.op == .ne {
16831717
// Shallow equatables
16841718
if l_sym.kind in js.shallow_equatables && r_sym.kind in js.shallow_equatables {
1719+
// wrap left expr in parens so binary operations will work correctly.
1720+
g.write('(')
16851721
g.expr(it.left)
1722+
g.write(')')
16861723
g.write('.eq(')
16871724
g.cast_stack << int(l_sym.kind)
16881725
g.expr(it.right)
@@ -1713,7 +1750,7 @@ fn (mut g JsGen) gen_infix_expr(it ast.InfixExpr) {
17131750
} else if r_sym.kind == .string {
17141751
g.write('.str.includes(')
17151752
} else {
1716-
g.write('.arr.includes(')
1753+
g.write('.\$includes(')
17171754
}
17181755
g.expr(it.left)
17191756
if l_sym.kind == .string {
@@ -1728,14 +1765,15 @@ fn (mut g JsGen) gen_infix_expr(it ast.InfixExpr) {
17281765
is_arithmetic := it.op in [token.Kind.plus, .minus, .mul, .div, .mod]
17291766
mut needs_cast := is_arithmetic && it.left_type != it.right_type
17301767
mut greater_typ := 0
1731-
if needs_cast {
1768+
// todo(playX): looks like this cast is always required to perform .eq operation on types.
1769+
if true || needs_cast {
17321770
greater_typ = g.greater_typ(it.left_type, it.right_type)
17331771
if g.cast_stack.len > 0 {
17341772
needs_cast = g.cast_stack.last() != greater_typ
17351773
}
17361774
}
17371775

1738-
if needs_cast {
1776+
if true || needs_cast {
17391777
if g.ns.name == 'builtin' {
17401778
g.write('new ')
17411779
}
@@ -1746,7 +1784,7 @@ fn (mut g JsGen) gen_infix_expr(it ast.InfixExpr) {
17461784
g.write(' $it.op ')
17471785
g.expr(it.right)
17481786

1749-
if needs_cast {
1787+
if true || needs_cast {
17501788
g.cast_stack.delete_last()
17511789
g.write(')')
17521790
}

vlib/v/gen/js/temp_fast_deep_equal.v

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@ function vEq(a, b) {
99
1010
if (a && b && typeof a == 'object' && typeof b == 'object') {
1111
if (a.constructor !== b.constructor) return false;
12-
a = a.valueOf();
13-
b = b.valueOf();
12+
a = a.\$toJS();
13+
b = b.\$toJS();
1414
var length, i, keys;
1515
if (Array.isArray(a)) {
1616
length = a.length;

vlib/v/gen/js/tests/testdata/array.out

Lines changed: 54 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,4 +108,57 @@ abc
108108
6
109109
1
110110
4
111-
6
111+
6
112+
[4,3,2,1]
113+
true
114+
true
115+
true
116+
true
117+
true
118+
true
119+
true
120+
0
121+
[0,0,0,0]
122+
[0,7,0,0]
123+
0
124+
[2,4,6,8,10,12,14,16,18,20]
125+
[2,4,6,8,10,12,14,16,18,20]
126+
[2,4,6,8,10]
127+
2
128+
[1,2]
129+
0
130+
1
131+
-1
132+
0
133+
3
134+
-1
135+
0
136+
2
137+
-1
138+
1
139+
2
140+
-1
141+
2
142+
3
143+
1
144+
3
145+
6
146+
true
147+
true
148+
true
149+
true
150+
true
151+
true
152+
true
153+
true
154+
true
155+
0
156+
0
157+
0
158+
0
159+
0
160+
[2,4,6]
161+
["is","awesome"]
162+
[2,3,4,6,8,9,10]
163+
[4,5,6]
164+
[5,10]

0 commit comments

Comments
 (0)