v.gen.js: fix for array filter, add more tests and other fixes (#10999)

pull/11002/head
playX 2021-07-30 11:17:11 +03:00 committed by GitHub
parent ab6ab519e6
commit a7ca051016
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 347 additions and 17 deletions

View File

@ -138,7 +138,7 @@ pub fn (a array) str() string {
#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); }
#array.prototype.filter = function(callback) { return new array(this.arr.filter( function (it) { return (+callback(it)) != 0; } )); }
#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) {
@ -160,3 +160,23 @@ pub fn (mut a array) prepend(val voidptr) {
pub fn (mut a array) prepend_many(val voidptr, size int) {
unsafe { a.insert_many(0, val, size) }
}
pub fn (a array) reverse() array {
mut res := array{}
#res.arr = Array.from(a.arr).reverse()
return res
}
#array.prototype.$includes = function (elem) { return this.arr.find(function(e) { return vEq(elem,e); }) !== undefined;}
// reduce executes a given reducer function on each element of the array,
// resulting in a single output value.
pub fn (a array) reduce(iter fn (int, int) int, accum_start int) int {
mut accum_ := accum_start
#for (let i of a) {
#accum_ = iter(accum_, a.arr[i])
#}
return accum_
}

View File

@ -263,6 +263,7 @@ struct BuiltinPrototypeConfig {
value_of string = 'this.val'
to_string string = 'this.val.toString()'
eq string = 'this.val === other.val'
to_jsval string = 'this'
extras string
has_strfn bool
}
@ -284,6 +285,7 @@ fn (mut g JsGen) gen_builtin_prototype(c BuiltinPrototypeConfig) {
g.writeln('valueOf() { return $c.value_of },')
g.writeln('toString() { return $c.to_string },')
g.writeln('eq(other) { return $c.eq },')
g.writeln('\$toJS() { return $c.to_jsval }, ')
if c.has_strfn {
g.writeln('str() { return new string(this.toString()) }')
}
@ -306,6 +308,7 @@ fn (mut g JsGen) gen_builtin_type_defs() {
value_of: 'this.val | 0'
to_string: 'this.valueOf().toString()'
eq: 'this.valueOf() === other.valueOf()'
to_jsval: '+this'
)
}
'byte' {
@ -316,18 +319,22 @@ fn (mut g JsGen) gen_builtin_type_defs() {
value_of: 'this.val | 0'
to_string: 'new string(this.val + "")'
eq: 'this.valueOf() === other.valueOf()'
to_jsval: '+this'
)
}
'f32', 'f64', 'float_literal' {
g.gen_builtin_prototype(
typ_name: typ_name
default_value: 'new Number(0)'
to_jsval: '+this'
)
}
'bool' {
g.gen_builtin_prototype(
constructor: 'this.val = +val !== 0'
typ_name: typ_name
default_value: 'new Boolean(false)'
to_jsval: '+this != 0'
)
}
'string' {
@ -340,6 +347,7 @@ fn (mut g JsGen) gen_builtin_type_defs() {
to_string: 'this.str'
eq: 'this.str === other.str'
has_strfn: false
to_jsval: 'this.str'
)
}
'map' {
@ -348,9 +356,10 @@ fn (mut g JsGen) gen_builtin_type_defs() {
val_name: 'map'
default_value: 'new Map()'
constructor: 'this.map = map'
value_of: 'this.map'
value_of: 'this'
to_string: 'this.map.toString()'
eq: 'vEq(this, other)'
to_jsval: 'this.map'
)
}
'array' {
@ -359,9 +368,10 @@ fn (mut g JsGen) gen_builtin_type_defs() {
val_name: 'arr'
default_value: 'new Array()'
constructor: 'this.arr = arr'
value_of: 'this.arr'
value_of: 'this'
to_string: 'JSON.stringify(this.arr.map(it => it.valueOf()))'
eq: 'vEq(this, other)'
to_jsval: 'this.arr'
)
}
'any' {
@ -373,6 +383,7 @@ fn (mut g JsGen) gen_builtin_type_defs() {
value_of: 'this.val'
to_string: '"&" + this.val'
eq: 'this == other' // compare by ptr
to_jsval: 'this.val.\$toJS()'
)
}
else {}

View File

@ -5,8 +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();
a = a.$toJS();
b = b.$toJS();
var length, i, keys;
if (Array.isArray(a)) {
length = a.length;

View File

@ -1079,6 +1079,7 @@ fn (mut g JsGen) gen_for_c_stmt(it ast.ForCStmt) {
g.write('; ')
}
if it.has_cond {
g.write('+') // convert to number or boolean
g.expr(it.cond)
}
g.write('; ')
@ -1174,6 +1175,7 @@ fn (mut g JsGen) gen_for_stmt(it ast.ForStmt) {
if it.is_inf {
g.write('true')
} else {
g.write('+') // convert expr to number or boolean
g.expr(it.cond)
}
g.writeln(') {')
@ -1325,6 +1327,7 @@ fn (mut g JsGen) gen_array_init_expr(it ast.ArrayInit) {
// offering similar performance
g.write('new array(')
g.inc_indent()
if it.has_len {
t1 := g.new_tmp_var()
t2 := g.new_tmp_var()
@ -1349,6 +1352,31 @@ fn (mut g JsGen) gen_array_init_expr(it ast.ArrayInit) {
g.writeln('return $t1;')
g.dec_indent()
g.write('})()')
} else if it.is_fixed && it.exprs.len == 1 {
// [100]byte codegen
t1 := g.new_tmp_var()
t2 := g.new_tmp_var()
g.writeln('(function() {')
g.inc_indent()
g.writeln('const $t1 = [];')
g.write('for (let $t2 = 0; $t2 < ')
g.expr(it.exprs[0])
g.writeln('; $t2++) {')
g.inc_indent()
g.write('${t1}.push(')
if it.has_default {
g.expr(it.default_expr)
} else {
// Fill the array with the default values for its type
t := g.to_js_typ_val(it.elem_type)
g.write(t)
}
g.writeln(');')
g.dec_indent()
g.writeln('};')
g.writeln('return $t1;')
g.dec_indent()
g.write('})()')
} else {
g.gen_array_init_values(it.exprs)
}
@ -1549,7 +1577,9 @@ fn (mut g JsGen) gen_if_expr(node ast.IfExpr) {
g.write(' : ')
}
if i < node.branches.len - 1 || !node.has_else {
g.write('(')
g.expr(branch.cond)
g.write(')')
g.write('.valueOf()')
g.write(' ? ')
}
@ -1570,7 +1600,9 @@ fn (mut g JsGen) gen_if_expr(node ast.IfExpr) {
if '$branch.cond' == 'js' {
g.write('true')
} else {
g.write('(')
g.expr(branch.cond)
g.write(')')
g.write('.valueOf()')
}
g.writeln(') {')
@ -1578,7 +1610,9 @@ fn (mut g JsGen) gen_if_expr(node ast.IfExpr) {
}
} else if i < node.branches.len - 1 || !node.has_else {
g.write('} else if (')
g.write('(')
g.expr(branch.cond)
g.write(')')
g.write('.valueOf()')
g.writeln(') {')
} else if i == node.branches.len - 1 && node.has_else {
@ -1608,7 +1642,7 @@ fn (mut g JsGen) gen_index_expr(expr ast.IndexExpr) {
if expr.index is ast.RangeExpr {
g.expr(expr.left)
if expr.left_type.is_ptr() {
g.write('.val')
g.write('.valueOf()')
}
g.write('.slice(')
if expr.index.has_low {
@ -1622,7 +1656,7 @@ fn (mut g JsGen) gen_index_expr(expr ast.IndexExpr) {
} else {
g.expr(expr.left)
if expr.left_type.is_ptr() {
g.write('.val')
g.write('.valueOf()')
}
g.write('.length')
}
@ -1649,7 +1683,7 @@ fn (mut g JsGen) gen_index_expr(expr ast.IndexExpr) {
g.write('new byte(')
g.expr(expr.left)
if expr.left_type.is_ptr() {
g.write('.val')
g.write('.valueOf()')
}
g.write('.str.charCodeAt(')
g.expr(expr.index)
@ -1659,10 +1693,10 @@ fn (mut g JsGen) gen_index_expr(expr ast.IndexExpr) {
// TODO Does this cover all cases?
g.expr(expr.left)
if expr.left_type.is_ptr() {
g.write('.val')
g.write('.valueOf()')
}
g.write('.arr')
g.write('[')
g.write('[+')
g.cast_stack << ast.int_type_idx
g.expr(expr.index)
g.cast_stack.delete_last()
@ -1682,7 +1716,10 @@ fn (mut g JsGen) gen_infix_expr(it ast.InfixExpr) {
if it.op == .eq || it.op == .ne {
// Shallow equatables
if l_sym.kind in js.shallow_equatables && r_sym.kind in js.shallow_equatables {
// wrap left expr in parens so binary operations will work correctly.
g.write('(')
g.expr(it.left)
g.write(')')
g.write('.eq(')
g.cast_stack << int(l_sym.kind)
g.expr(it.right)
@ -1713,7 +1750,7 @@ fn (mut g JsGen) gen_infix_expr(it ast.InfixExpr) {
} else if r_sym.kind == .string {
g.write('.str.includes(')
} else {
g.write('.arr.includes(')
g.write('.\$includes(')
}
g.expr(it.left)
if l_sym.kind == .string {
@ -1728,14 +1765,15 @@ fn (mut g JsGen) gen_infix_expr(it ast.InfixExpr) {
is_arithmetic := it.op in [token.Kind.plus, .minus, .mul, .div, .mod]
mut needs_cast := is_arithmetic && it.left_type != it.right_type
mut greater_typ := 0
if needs_cast {
// todo(playX): looks like this cast is always required to perform .eq operation on types.
if true || needs_cast {
greater_typ = g.greater_typ(it.left_type, it.right_type)
if g.cast_stack.len > 0 {
needs_cast = g.cast_stack.last() != greater_typ
}
}
if needs_cast {
if true || needs_cast {
if g.ns.name == 'builtin' {
g.write('new ')
}
@ -1746,7 +1784,7 @@ fn (mut g JsGen) gen_infix_expr(it ast.InfixExpr) {
g.write(' $it.op ')
g.expr(it.right)
if needs_cast {
if true || needs_cast {
g.cast_stack.delete_last()
g.write(')')
}

View File

@ -9,8 +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();
a = a.\$toJS();
b = b.\$toJS();
var length, i, keys;
if (Array.isArray(a)) {
length = a.length;

View File

@ -108,4 +108,57 @@ abc
6
1
4
6
6
[4,3,2,1]
true
true
true
true
true
true
true
0
[0,0,0,0]
[0,7,0,0]
0
[2,4,6,8,10,12,14,16,18,20]
[2,4,6,8,10,12,14,16,18,20]
[2,4,6,8,10]
2
[1,2]
0
1
-1
0
3
-1
0
2
-1
1
2
-1
2
3
1
3
6
true
true
true
true
true
true
true
true
true
0
0
0
0
0
[2,4,6]
["is","awesome"]
[2,3,4,6,8,9,10]
[4,5,6]
[5,10]

View File

@ -6,6 +6,42 @@ struct Kkk {
q []Chunk
}
const (
c_n = 5
)
fn filter_test_helper_1(a int) bool {
return a > 3
}
fn sum(prev int, curr int) int {
return prev + curr
}
fn sub(prev int, curr int) int {
return prev - curr
}
struct Foooj {
a [5]int // c_n
}
fn double_up(mut a []int) {
for i := 0; i < a.len; i++ {
a[i] = a[i] * 2
}
}
fn double_up_v2(mut a []int) {
for i, _ in a {
a[i] = a[i] * 2 // or val*2, doesn't matter
}
}
fn modify(mut numbers []int) {
numbers[0] = 777
}
fn main() {
{
// test pointer
@ -262,6 +298,7 @@ fn main() {
}
}
{
// todo(playX): deep repeat does not yet work.
/*
// test deep repeat
mut a3 := [[[1, 1], [2, 2], [3, 3]], [[4, 4], [5, 5], [6, 6]]]
@ -319,4 +356,175 @@ fn main() {
println(a[3])
println(a[5])
}
{
// test reverse
a := [1, 2, 3, 4]
b := ['test', 'array', 'reverse']
c := a.reverse()
println(c)
d := b.reverse()
for i, _ in c {
println(c[i] == a[a.len - i - 1])
}
for i, _ in d {
println(d[i] == b[b.len - i - 1])
}
e := []int{}
f := e.reverse()
println(f.len)
}
{
// test fixed
mut nums := [4]int{}
// x := nums[1..3]
// assert x.len == 2
println(nums)
nums[1] = 7
println(nums)
nums2 := [5]int{} // c_n
println(nums2[c_n - 1])
}
{
// test mut slice
/*
todo(playX): slices do not work yet. We have to implement custom wrapper for them.
mut n := [1, 2, 3]
// modify(mut n)
modify(mut n[..2])
assert n[0] == 777
modify(mut n[2..])
assert n[2] == 777
println(n)
*/
}
{
// test mut arg
mut arr := [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
double_up(mut arr)
println(arr.str())
arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
double_up_v2(mut arr)
println(arr.str())
}
{
// test doubling
mut nums := [1, 2, 3, 4, 5]
for i in 0 .. nums.len {
nums[i] *= 2
}
println(nums.str())
}
{
// test single element
mut a := [1]
a << 2
println(a.len)
assert a[0] == 1
assert a[1] == 2
println(a)
}
{
// test find index
// string
a := ['v', 'is', 'great']
println(a.index('v'))
println(a.index('is'))
println(a.index('gre'))
// int
b := [1, 2, 3, 4]
println(b.index(1))
println(b.index(4))
println(b.index(5))
// byte
c := [0x22, 0x33, 0x55]
println(c.index(0x22))
println(c.index(0x55))
println(c.index(0x99))
// char
d := [`a`, `b`, `c`]
println(d.index(`b`))
println(d.index(`c`))
println(d.index(`u`))
}
{
// test multi
a := [[1, 2, 3], [4, 5, 6]]
println(a.len)
println(a[0].len)
println(a[0][0])
println(a[0][2])
println(a[1][2])
}
{
// test in
a := [1, 2, 3]
println(1 in a)
println(2 in a)
println(3 in a)
println(!(4 in a))
println(!(0 in a))
println(0 !in a)
println(4 !in a)
b := [1, 4, 0]
c := [3, 6, 2, 0]
println(0 in b)
println(0 in c)
}
{
// test reduce
a := [1, 2, 3, 4, 5]
b := a.reduce(sum, 0)
c := a.reduce(sum, 5)
d := a.reduce(sum, -1)
println(b)
println(c)
println(d)
e := [1, 2, 3]
f := e.reduce(sub, 0)
g := e.reduce(sub, -1)
println(f)
println(g)
}
{
a := [1, 2, 3, 4, 5, 6]
b := a.filter(it % 2 == 0)
println(b)
c := ['v', 'is', 'awesome']
d := c.filter(it.len > 1)
println(d)
assert d[0] == 'is'
assert d[1] == 'awesome'
////////
arr := [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
println(arr.filter(it % 2 == 0 || it % 3 == 0))
mut mut_arr := [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
mut_arr = mut_arr.filter(it < 4)
assert mut_arr.len == 3
println(a.filter(filter_test_helper_1))
println([1, 5, 10].filter(filter_test_helper_1))
}
{
// todo(playX): RUNTIME ERROR: Invalid memory access
/*
// test anon fn filter
filter_num := fn (i int) bool {
return i % 2 == 0
}
assert [1, 2, 3, 4, 5].filter(filter_num) == [2, 4]
*/
}
{
/*
a := [1, 2, 3, 4].filter(fn (i int) bool {
return i % 2 == 0
})
assert a == [2, 4]
*/
}
}