v.gen.js: port fully the array test suite & add fixes (#11073)

pull/11099/head
playX 2021-08-07 17:58:49 +03:00 committed by GitHub
parent c560d58f1e
commit 94c321c80d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 360 additions and 15 deletions

View File

@ -14,3 +14,13 @@ pub fn (mut m map) delete(key voidptr) {
pub fn (m &map) free() {} pub fn (m &map) free() {}
#map.prototype[Symbol.iterator] = function () { return this.map[Symbol.iterator](); } #map.prototype[Symbol.iterator] = function () { return this.map[Symbol.iterator](); }
#map.prototype.toString = function () {
#function fmtKey(key) { return typeof key == 'string' ? '\'' + key + '\'' : key}
#let res = '{'
#for (const entry of this) {
#res += fmtKey(entry[0]) + ': ' + entry[0];
#}
#res += '}'
#return res;
#}

View File

@ -94,7 +94,10 @@ pub fn (s string) count(substr string) int {
} }
pub fn (s string) ends_with(p string) bool { pub fn (s string) ends_with(p string) bool {
return s.str.endsWith(p.str) mut res := false
#res.val = s.str.endsWith(p.str)
return res
} }
pub fn (s string) starts_with(p string) bool { pub fn (s string) starts_with(p string) bool {
@ -133,7 +136,7 @@ pub fn (s string) fields() []string {
} }
pub fn (s string) find_between(start string, end string) string { pub fn (s string) find_between(start string, end string) string {
return string(s.str.slice(s.str.indexOf(start.str), s.str.indexOf(end.str) + 1)) return string(s.str.slice(s.str.indexOf(start.str) + 1, s.str.indexOf(end.str)))
} }
// unnecessary in the JS backend, implemented for api parity. // unnecessary in the JS backend, implemented for api parity.
@ -464,3 +467,77 @@ pub fn (s string) strip_margin_custom(del byte) string {
return result return result
} }
// split_nth splits the string based on the passed `delim` substring.
// It returns the first Nth parts. When N=0, return all the splits.
// The last returned element has the remainder of the string, even if
// the remainder contains more `delim` substrings.
[direct_array_access]
pub fn (s string) split_nth(delim string, nth int) []string {
mut res := []string{}
mut i := 0
match delim.len {
0 {
i = 1
for ch in s {
if nth > 0 && i >= nth {
res << s[i..]
break
}
res << ch.str()
i++
}
return res
}
1 {
mut start := 0
delim_byte := delim[0]
for i < s.len {
if s[i] == delim_byte {
was_last := nth > 0 && res.len == nth - 1
if was_last {
break
}
val := s[start..i] //.substr(start, i)
res << val
start = i + delim.len
i = start
} else {
i++
}
}
// Then the remaining right part of the string
if nth < 1 || res.len < nth {
res << s[start..]
}
return res
}
else {
mut start := 0
// Take the left part for each delimiter occurence
for i <= s.len {
is_delim := i + delim.len <= s.len && s[i..i + delim.len] == delim
if is_delim {
was_last := nth > 0 && res.len == nth - 1
if was_last {
break
}
val := s[start..i] // .substr(start, i)
res << val
start = i + delim.len
i = start
} else {
i++
}
}
// Then the remaining right part of the string
if nth < 1 || res.len < nth {
res << s[start..]
}
return res
}
}
}

View File

@ -30,7 +30,7 @@ fn (mut g JsGen) to_js_typ_val(t ast.Type) string {
styp = '$prefix${g.sym_to_js_typ(sym)}("")' styp = '$prefix${g.sym_to_js_typ(sym)}("")'
} }
.map { .map {
styp = 'new Map()' styp = 'new map(new Map())'
} }
.array { .array {
styp = '$prefix${g.sym_to_js_typ(sym)}()' styp = '$prefix${g.sym_to_js_typ(sym)}()'
@ -335,6 +335,7 @@ fn (mut g JsGen) gen_builtin_type_defs() {
typ_name: typ_name typ_name: typ_name
default_value: 'new Boolean(false)' default_value: 'new Boolean(false)'
to_jsval: '+this != 0' to_jsval: '+this != 0'
eq: 'this.val === other.valueOf()'
) )
} }
'string' { 'string' {
@ -354,7 +355,7 @@ fn (mut g JsGen) gen_builtin_type_defs() {
g.gen_builtin_prototype( g.gen_builtin_prototype(
typ_name: typ_name typ_name: typ_name
val_name: 'map' val_name: 'map'
default_value: 'new Map()' default_value: 'new map(new Map())'
constructor: 'this.map = map' constructor: 'this.map = map'
value_of: 'this' value_of: 'this'
to_string: 'this.map.toString()' to_string: 'this.map.toString()'

View File

@ -1831,17 +1831,16 @@ fn (mut g JsGen) gen_infix_expr(it ast.InfixExpr) {
} else { } else {
is_arithmetic := it.op in [token.Kind.plus, .minus, .mul, .div, .mod] 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 mut greater_typ := 0
// todo(playX): looks like this cast is always required to perform .eq operation on types. // todo(playX): looks like this cast is always required to perform .eq operation on types.
if true || needs_cast { if is_arithmetic {
greater_typ = g.greater_typ(it.left_type, it.right_type) greater_typ = g.greater_typ(it.left_type, it.right_type)
if g.cast_stack.len > 0 { if g.cast_stack.len > 0 {
needs_cast = g.cast_stack.last() != greater_typ // needs_cast = g.cast_stack.last() != greater_typ
} }
} }
if true || needs_cast { if is_arithmetic {
if g.ns.name == 'builtin' { if g.ns.name == 'builtin' {
g.write('new ') g.write('new ')
} }
@ -1855,7 +1854,7 @@ fn (mut g JsGen) gen_infix_expr(it ast.InfixExpr) {
g.expr(it.right) g.expr(it.right)
if true || needs_cast { if is_arithmetic {
g.cast_stack.delete_last() g.cast_stack.delete_last()
g.write(')') g.write(')')
} }

View File

@ -195,6 +195,7 @@ true
[2, 3, 4] [2, 3, 4]
[1, 2, 3] [1, 2, 3]
[1, 2, 3] [1, 2, 3]
[[1, 2, 3], [4, 5, 6]]
true true
true true
true true
@ -292,5 +293,11 @@ true
true true
true true
0 0
`exists`: true and `not exists`: false
[[], [], [], []] [[], [], [], []]
[[], [], [123], []] [[], [], [123], []]
[{}, {}, {}, {}]
[{}, {}, {'123': 123}, {}]
Numbers { odds: [1, 3, 5] , evens: [2, 4] }
Numbers { odds: [3, 5, 7] , evens: [2, 6, 10] }
[[10, 10, 10], [10, 10, 10], [10, 10, 10]]

View File

@ -16,6 +16,11 @@ struct Coord {
z int z int
} }
struct Numbers {
odds []int
evens []int
}
struct Person { struct Person {
name string name string
nums []int nums []int
@ -672,15 +677,13 @@ fn main() {
} }
{ {
// test array str // test array str
// todo(playX): JS array formatting should match what default builtin impl has.
/*
numbers := [1, 2, 3] numbers := [1, 2, 3]
assert numbers == [1, 2, 3] assert numbers == [1, 2, 3]
numbers2 := [numbers, [4, 5, 6]] // dup str() bug numbers2 := [numbers, [4, 5, 6]] // dup str() bug
println(numbers2) println(numbers2)
assert true assert true
assert numbers.str() == '[1, 2, 3]' assert numbers.str() == '[1, 2, 3]'
*/
} }
{ {
// test eq // test eq
@ -1110,8 +1113,7 @@ fn main() {
} }
{ {
// test array struct contains // test array struct contains
/*
todo: does not work
mut coords := []Coord{} mut coords := []Coord{}
coord_1 := Coord{ coord_1 := Coord{
x: 1 x: 1
@ -1124,7 +1126,6 @@ fn main() {
println('`exists`: $exists and `not exists`: $not_exists') println('`exists`: $exists and `not exists`: $not_exists')
assert exists == true assert exists == true
assert not_exists == false assert not_exists == false
*/
} }
{ {
// test array of array append // test array of array append
@ -1133,4 +1134,47 @@ fn main() {
x[2] << 123 // RTE x[2] << 123 // RTE
println(x) println(x)
} }
{
// test array of map insert
mut x := []map[string]int{len: 4}
println(x) // OK
x[2]['123'] = 123 // RTE
println(x)
}
{
// todo(playX): does not work
/*
// test multi fixed array init
a := [3][3]int{}
println(a)
*/
}
{
// test array of multi filter
arr := [1, 2, 3, 4, 5]
nums := Numbers{
odds: arr.filter(it % 2 == 1)
evens: arr.filter(it % 2 == 0)
}
println(nums)
assert nums.odds == [1, 3, 5]
assert nums.evens == [2, 4]
}
{
// test array of multi map
arr := [1, 3, 5]
nums := Numbers{
odds: arr.map(it + 2)
evens: arr.map(it * 2)
}
println(nums)
assert nums.odds == [3, 5, 7]
assert nums.evens == [2, 6, 10]
}
{
// test multi fixed array with default init
a := [3][3]int{init: [3]int{init: 10}}
println(a)
assert a == [[10, 10, 10]!, [10, 10, 10]!, [10, 10, 10]!]!
}
} }

View File

@ -0,0 +1,7 @@
ab
1000
true
true
true
man
true

View File

@ -0,0 +1,200 @@
struct Foo {
bar int
mut:
str string
}
fn main() {
{
// test add
mut a := 'a'
a += 'b'
println(a)
a = 'a'
for i := 1; i < 1000; i++ {
a += 'b'
}
println(a.len)
println(a.ends_with('bbbbb'))
a += '123'
println(a.ends_with('3'))
}
{
// test ends with
a := 'browser.v'
println(a.ends_with('.v'))
s := 'V Programming Language'
assert s.ends_with('guage') == true
assert s.ends_with('Language') == true
assert s.ends_with('Programming Language') == true
assert s.ends_with('V') == false
}
{
// test between
s := 'hello [man] how you doing'
println(s.find_between('[', ']'))
}
{
// test compare
a := 'Music'
b := 'src'
println(b >= a)
}
{
// test lt
a := ''
b := 'a'
c := 'a'
d := 'b'
e := 'aa'
f := 'ab'
assert a < b
assert !(b < c)
assert c < d
assert !(d < e)
assert c < e
assert e < f
}
{
// test ge
a := 'aa'
b := 'aa'
c := 'ab'
d := 'abc'
e := 'aaa'
assert b >= a
assert c >= b
assert d >= c
assert !(c >= d)
assert e >= a
}
{
// test compare strings
a := 'aa'
b := 'aa'
c := 'ab'
d := 'abc'
e := 'aaa'
assert compare_strings(a, b) == 0
assert compare_strings(b, c) == -1
assert compare_strings(c, d) == -1
assert compare_strings(d, e) == 1
assert compare_strings(a, e) == -1
assert compare_strings(e, a) == 1
}
{
// test sort
mut vals := [
'arr',
'an',
'a',
'any',
]
len := vals.len
vals.sort()
assert len == vals.len
assert vals[0] == 'a'
assert vals[1] == 'an'
assert vals[2] == 'any'
assert vals[3] == 'arr'
}
{
// todo(playX): sort codegen
/*// test sort reverse
mut vals := [
'arr',
'an',
'a',
'any',
]
len := vals.len
vals.sort(b > a)
assert len == vals.len
assert vals[0] == 'a'
assert vals[1] == 'an'
assert vals[2] == 'any'
assert vals[3] == 'arr'*/
}
{
// todo: split nth
/*
a := '1,2,3'
assert a.split(',').len == 3
assert a.split_nth(',', -1).len == 3
assert a.split_nth(',', 0).len == 3
assert a.split_nth(',', 1).len == 1
assert a.split_nth(',', 2).len == 2
assert a.split_nth(',', 10).len == 3
b := '1::2::3'
assert b.split('::').len == 3
assert b.split_nth('::', -1).len == 3
assert b.split_nth('::', 0).len == 3
assert b.split_nth('::', 1).len == 1
assert b.split_nth('::', 2).len == 2
assert b.split_nth('::', 10).len == 3
c := 'ABCDEF'
println(c.split('').len)
assert c.split('').len == 6
assert c.split_nth('', 3).len == 3
assert c.split_nth('BC', -1).len == 2
d := ','
assert d.split(',').len == 2
assert d.split_nth('', 3).len == 1
assert d.split_nth(',', -1).len == 2
assert d.split_nth(',', 3).len == 2
e := ',,,0,,,,,a,,b,'
assert e.split(',,').len == 5
assert e.split_nth(',,', 3).len == 3
assert e.split_nth(',', -1).len == 12
assert e.split_nth(',', 3).len == 3
*/
}
{
// test split
mut s := 'volt/twitch.v:34'
mut vals := s.split(':')
assert vals.len == 2
assert vals[0] == 'volt/twitch.v'
assert vals[1] == '34'
// /////////
s = '2018-01-01z13:01:02'
vals = s.split('z')
assert vals.len == 2
assert vals[0] == '2018-01-01'
assert vals[1] == '13:01:02'
// //////////
s = '4627a862c3dec29fb3182a06b8965e0025759e18___1530207969___blue'
vals = s.split('___')
assert vals.len == 3
assert vals[0] == '4627a862c3dec29fb3182a06b8965e0025759e18'
assert vals[1] == '1530207969'
assert vals[2] == 'blue'
// /////////
s = 'lalala'
vals = s.split('a')
assert vals.len == 4
assert vals[0] == 'l'
assert vals[1] == 'l'
assert vals[2] == 'l'
assert vals[3] == ''
// /////////
s = 'awesome'
a := s.split('')
assert a.len == 7
assert a[0] == 'a'
assert a[1] == 'w'
assert a[2] == 'e'
assert a[3] == 's'
assert a[4] == 'o'
assert a[5] == 'm'
assert a[6] == 'e'
// /////////
s = 'wavy turquoise bags'
vals = s.split(' bags')
assert vals.len == 2
assert vals[0] == 'wavy turquoise'
assert vals[1] == ''
}
}