From 9145cd66ec3a5db8f0eb8f70242ea6a1a0d31d9f Mon Sep 17 00:00:00 2001 From: playX Date: Sun, 3 Oct 2021 10:08:21 +0300 Subject: [PATCH] js: add more tests to builtin/js and implement more builtin functions (#12049) --- vlib/builtin/js/array.js.v | 9 +- vlib/builtin/js/byte.js.v | 16 + vlib/builtin/js/int.js.v | 100 ++++ vlib/builtin/js/int_test.js.v | 244 ++++++++ vlib/builtin/js/map.js.v | 2 + vlib/builtin/js/map_test.js.v | 949 +++++++++++++++++++++++++++++++ vlib/builtin/js/string.js.v | 160 +++++- vlib/builtin/js/string_test.js.v | 897 +++++++++++++++++++++++++++++ vlib/v/gen/js/infix.v | 6 +- vlib/v/gen/js/js.v | 19 +- 10 files changed, 2384 insertions(+), 18 deletions(-) create mode 100644 vlib/builtin/js/int_test.js.v create mode 100644 vlib/builtin/js/map_test.js.v create mode 100644 vlib/builtin/js/string_test.js.v diff --git a/vlib/builtin/js/array.js.v b/vlib/builtin/js/array.js.v index f9124bdaf0..834ae617d3 100644 --- a/vlib/builtin/js/array.js.v +++ b/vlib/builtin/js/array.js.v @@ -194,13 +194,6 @@ pub fn (mut a array) insert_many(i int, val voidptr, size int) { #a.val.arr.arr.splice(i,0,...val.arr.slice(0,+size)) } -pub fn (mut a array) join(separator string) string { - mut res := '' - #res = new string(a.val.arr.arr.join(separator +'')); - - return res -} - fn (mut a array) push(val voidptr) { #a.val.arr.make_copy() #if (arguments[2] && arguments[2].valueOf()) {a.val.arr.arr.push(...val)} else { @@ -246,7 +239,7 @@ struct array_iterator { #} #array_iterator.prototype[Symbol.iterator] = function () { return this; } -#array.prototype[Symbol.iterator] = function () { console.log(this.arr.index_start); return new array_iterator({ix: new int(0),end: new int(this.arr.len),arr: this}); } +#array.prototype[Symbol.iterator] = function () { return new array_iterator({ix: new int(0),end: new int(this.arr.len),arr: this}); } #array.prototype.entries = function () { let result = []; for (let key = this.arr.index_start.val;key < this.arr.len.val;key++) { result.push([new int(key), this.arr.get(new int(key))]); } return result[Symbol.iterator](); } #array.prototype.map = function(callback) { return v_map(this,callback); } #array.prototype.filter = function(callback) { return v_filter(this,callback); } diff --git a/vlib/builtin/js/byte.js.v b/vlib/builtin/js/byte.js.v index 4a46e7852f..78b3f6fb2e 100644 --- a/vlib/builtin/js/byte.js.v +++ b/vlib/builtin/js/byte.js.v @@ -21,3 +21,19 @@ pub fn (c byte) str() string { return res } + +pub fn (c byte) ascii_str() string { + res := '' + #res.str = String.fromCharCode(c.val) + + return res +} + +pub fn (c byte) repeat(count int) string { + mut res := '' + for _ in 0 .. count { + res += c.ascii_str() + } + + return res +} diff --git a/vlib/builtin/js/int.js.v b/vlib/builtin/js/int.js.v index 1220fb5033..dd67017078 100644 --- a/vlib/builtin/js/int.js.v +++ b/vlib/builtin/js/int.js.v @@ -1,5 +1,26 @@ module builtin +pub fn (i i8) str() string { + mut res := '' + #res.str = i.val.toString() + + return res +} + +pub fn (i i16) str() string { + mut res := '' + #res.str = i.val.toString() + + return res +} + +pub fn (i u16) str() string { + mut res := '' + #res.str = i.val.toString() + + return res +} + pub fn (i int) str() string { mut res := '' #res = new string( i ) @@ -48,3 +69,82 @@ pub fn (i int_literal) str() string { return res } + +pub fn (x u64) hex() string { + res := '' + #res.str = x.val.toString(16) + + return res +} + +pub fn (x i64) hex() string { + res := '' + #res.str = x.val.toString(16) + + return res +} + +pub fn (x u32) hex() string { + res := '' + #res.str = x.val.toString(16) + + return res +} + +pub fn (x u16) hex() string { + res := '' + #res.str = x.val.toString(16) + + return res +} + +pub fn (x i8) hex() string { + res := '' + #res.str = x.val.toString(16) + + return res +} + +pub fn (x i16) hex() string { + res := '' + #res.str = x.val.toString(16) + + return res +} + +pub fn (x int) hex() string { + res := '' + #res.str = x.val.toString(16) + + return res +} + +pub fn (x int_literal) hex() string { + res := '' + #res.str = x.val.toString(16) + + return res +} + +pub fn (x byte) hex() string { + res := '' + #res.str = x.val.toString(16) + + return res +} + +// hex returns a string with the hexadecimal representation +// of the byte elements of the array. +pub fn (b []byte) hex() string { + mut hex := '' + for i in b { + mut z := i + z = z + #let n0 = i.val >> 4 + #hex.str += n0 < 10 ? String.fromCharCode(n0) : String.fromCharCode(n0 + 87) + + #let n1 = i.val & 0xF + #hex.str += n1 < 10 ? String.fromCharCode(n1) : String.fromCharCode(n1 + 87) + } + return hex +} diff --git a/vlib/builtin/js/int_test.js.v b/vlib/builtin/js/int_test.js.v new file mode 100644 index 0000000000..f760d463f6 --- /dev/null +++ b/vlib/builtin/js/int_test.js.v @@ -0,0 +1,244 @@ +const ( + a = 3 + u = u64(1) +) + +fn test_const() { + b := (true && true) || false + assert b == true + assert a == 3 + assert u == u64(1) + assert u == 1 // make sure this works without the cast +} + +fn test_str_methods() { + assert i8(1).str() == '1' + assert i8(-1).str() == '-1' + assert i16(1).str() == '1' + assert i16(-1).str() == '-1' + assert int(1).str() == '1' + assert int(-1).str() == '-1' + assert int(2147483647).str() == '2147483647' + // todo: overflow check for integers + // assert int(2147483648).str() == '-2147483648' + // assert int(-2147483648).str() == '-2147483648' + assert i64(1).str() == '1' + assert i64(-1).str() == '-1' + assert u16(1).str() == '1' + // assert u16(-1).str() == '65535' + assert u32(1).str() == '1' + // assert u32(-1).str() == '4294967295' + assert u64(1).str() == '1' + // assert u64(-1).str() == '18446744073709551615' +} + +fn test_and_precendence() { + assert (2 & 0 == 0) == ((2 & 0) == 0) + assert (2 & 0 != 0) == ((2 & 0) != 0) + assert (0 & 0 >= 0) == ((0 & 0) >= 0) + assert (0 & 0 <= 0) == ((0 & 0) <= 0) + assert (0 & 0 < 1) == ((0 & 0) < 1) + assert (1 & 2 > 0) == ((1 & 2) > 0) +} + +fn test_or_precendence() { + assert (1 | 0 == 0) == ((1 | 0) == 0) + assert (1 | 0 != 1) == ((1 | 0) != 1) + assert (1 | 0 >= 2) == ((1 | 0) >= 2) + assert (1 | 0 <= 0) == ((1 | 0) <= 0) + assert (1 | 0 < 0) == ((1 | 0) < 0) + assert (1 | 0 > 1) == ((1 | 0) > 1) +} + +fn test_xor_precendence() { + assert (1 ^ 0 == 2) == ((1 ^ 0) == 2) + assert (1 ^ 0 != 2) == ((1 ^ 0) != 2) + assert (1 ^ 0 >= 0) == ((1 ^ 0) >= 0) + assert (1 ^ 0 <= 1) == ((1 ^ 0) <= 1) + assert (1 ^ 0 < 0) == ((1 ^ 0) < 0) + assert (1 ^ 0 > 1) == ((1 ^ 0) > 1) +} + +fn test_left_shift_precendence() { + assert (2 << 4 | 3) == ((2 << 4) | 3) + assert (2 << 4 | 3) != (2 << (4 | 3)) +} + +fn test_right_shift_precendence() { + assert (256 >> 4 | 3) == ((256 >> 4) | 3) + assert (256 >> 4 | 3) != (256 >> (4 | 3)) +} + +fn test_i8_print() { + b := i8(0) + println(b) + c := i16(7) + println(c) + d := u16(6) + println(d) + assert true +} + +/* +fn test_cmp() { + assert 1 ≠ 2 + assert 1 ⩽ 2 + assert 1 ⩾ 0 +} +*/ +type MyInt = int + +fn test_int_alias() { + i := MyInt(2) + assert i + 10 == 12 +} + +fn test_hex() { + x := u64(10) + assert x.hex() == 'a' + b := 1234 + assert b.hex() == '4d2' + b1 := -1 + // assert b1.hex() == 'ffffffff' + // unsigned tests + // assert u8(12).hex() == '0c' + // assert u8(255).hex() == 'ff' + assert u16(65535).hex() == 'ffff' + // assert u32(-1).hex() == 'ffffffff' + // assert u64(-1).hex() == 'ffffffffffffffff' + // signed tests + // assert i8(-1).hex() == 'ff' + assert i8(12).hex() == 'c' + assert i16(32767).hex() == '7fff' + assert int(2147483647).hex() == '7fffffff' + assert i64(9223372036854775807).hex() == '7fffffffffffffff' +} + +fn test_bin() { + x1 := 0b10 + assert x1 == 2 + x2 := 0b10101010 + assert x2 == 0xAA + x3 := -0b0000001 + assert x3 == -1 + x4 := 0b11111111 + assert x4 == 255 + x5 := byte(0b11111111) + assert x5 == 255 + x6 := char(0b11111111) + assert int(x6) == -1 + x7 := 0b0 + assert x7 == 0 + x8 := -0b0 + assert x8 == 0 +} + +fn test_oct() { + x1 := 0o12 + assert x1 == 10 + x2 := 0o350 + assert x2 == 232 + x3 := 0o00073 + assert x3 == 59 + x4 := 0 + assert x4 == 0 + x5 := 195 + assert x5 == 195 + x6 := -0o744 + assert x6 == -484 + x7 := -0o000042 + assert x7 == -34 + x8 := -112 + assert x8 == -112 + x9 := -0 + assert x9 == 0 +} + +fn test_num_separator() { + // int + assert 100_000_0 == 1000000 + assert -2_23_4_6 == -22346 + + // bin + assert 0b0_11 == 3 + assert -0b0_100 == -4 + + // oct + assert 0o1_73 == 123 + assert -0o17_5 == -125 + assert -0o175 == -125 + + // hex + assert 0xFF == 255 + assert 0xF_F == 255 + + // f32 or f64 + assert 312_2.55 == 3122.55 + assert 312_2.55 == 3122.55 +} + +fn test_int_decl() { + x1 := 0 + x2 := 1333 + x3 := -88955 + x4 := 2000000000 + x5 := -1999999999 + assert typeof(x1).name == 'int' + assert typeof(x2).name == 'int' + assert typeof(x3).name == 'int' + assert typeof(x4).name == 'int' + assert typeof(x5).name == 'int' + x7 := u64(-321314588900011) + assert typeof(x7).name == 'u64' +} + +fn test_int_to_hex() { + // array hex + /* + st := [byte(`V`), `L`, `A`, `N`, `G`] + assert st.hex() == '564c414e47' + assert st.hex().len == 10 + st1 := [byte(0x41)].repeat(100) + assert st1.hex() == '41'.repeat(100)*/ + // --- int to hex tests + c0 := 12 + // 8Bit + assert byte(0).hex() == '0' + assert byte(c0).hex() == 'c' + assert i8(c0).hex() == 'c' + assert byte(127).hex() == '7f' + assert i8(127).hex() == '7f' + assert byte(255).hex() == 'ff' + // assert byte(-1).hex() == 'ff' + // 16bit + assert u16(0).hex() == '0' + assert i16(c0).hex() == 'c' + assert u16(c0).hex() == 'c' + assert i16(32767).hex() == '7fff' + assert u16(32767).hex() == '7fff' + // assert i16(-1).hex() == 'ffff' + assert u16(65535).hex() == 'ffff' + // 32bit + assert u32(0).hex() == '0' + assert c0.hex() == 'c' + assert u32(c0).hex() == 'c' + assert 2147483647.hex() == '7fffffff' + assert u32(2147483647).hex() == '7fffffff' + // assert (-1).hex() == 'ffffffffffffffff' + assert u32(4294967295).hex() == 'ffffffff' + // 64 bit + assert u64(0).hex() == '0' + assert i64(c0).hex() == 'c' + assert u64(c0).hex() == 'c' + assert i64(9223372036854775807).hex() == '7fffffffffffffff' + assert u64(9223372036854775807).hex() == '7fffffffffffffff' + // assert i64(-1).hex() == 'ffffffffffffffff' + assert u64(18446744073709551615).hex() == 'ffffffffffffffff' +} + +fn test_repeat() { + b := byte(`V`) + assert b.repeat(5) == 'VVVVV' + assert b.repeat(1) == b.ascii_str() + assert b.repeat(0) == '' +} diff --git a/vlib/builtin/js/map.js.v b/vlib/builtin/js/map.js.v index 1b913674b6..5bcd65fb55 100644 --- a/vlib/builtin/js/map.js.v +++ b/vlib/builtin/js/map.js.v @@ -25,3 +25,5 @@ pub fn (m &map) free() {} #res += '}' #return res; #} + +#map.prototype.getOrSet = function (key, init) { if (this.map.has(key)) { return this.map.get(key); } else { this.map.set(key,init); return init; } } diff --git a/vlib/builtin/js/map_test.js.v b/vlib/builtin/js/map_test.js.v new file mode 100644 index 0000000000..76b79ed47b --- /dev/null +++ b/vlib/builtin/js/map_test.js.v @@ -0,0 +1,949 @@ +import rand + +const ( + strings = unique_strings(200, 10) +) + +fn unique_strings(arr_len int, str_len int) []string { + mut arr := []string{cap: arr_len} + for arr.len < arr_len { + str := rand.string(str_len) + if str !in arr { + arr << str + } + } + return arr +} + +fn test_get_and_set_many() { + mut m := map[string]int{} + for i, s in strings { + m[s] = i + assert m[s] == i + assert m.len == i + 1 + } + for i, s in strings { + assert m[s] == i + } + assert m.len == strings.len +} + +fn test_for_in_many() { + mut m := map[string]int{} + for i, s in strings { + m[s] = i + } + for k, v in m { + assert m[k] == v + } +} + +fn test_keys_many() { + mut m := map[string]int{} + for i, s in strings { + m[s] = i + } + keys := m.keys() + assert keys.len == strings.len + assert keys.len == m.len + assert keys == strings +} + +fn test_deletes_many() { + mut m := map[string]int{} + for i, s in strings { + m[s] = i + } + for i, s in strings { + m.delete(s) + assert m[s] == 0 + assert m.len == strings.len - (i + 1) + } + assert m.len == 0 + assert m.keys().len == 0 +} + +struct User { +mut: + name string +} + +struct Aaa { +mut: + m map[string]int + users map[string]User +} + +fn (mut a Aaa) set(key string, val int) { + a.m[key] = val +} + +fn test_map() { + mut m := map[string]int{} + assert m.len == 0 + m['hi'] = 80 + m['hello'] = 101 + assert m['hi'] == 80 + assert m['hello'] == 101 + assert m.len == 2 + assert 'hi' in m + mut sum := 0 + // Test `for in` + for _, val in m { + sum += val + } + assert sum == 80 + 101 + // Test `.keys()` + keys := m.keys() + assert keys.len == 2 + assert 'hi' in keys + assert 'hello' in keys + m.delete('hi') + assert m.len == 1 + m.delete('aloha') + assert m.len == 1 + assert m['hi'] == 0 + assert m.keys().len == 1 + assert m.keys()[0] == 'hello' + // // + mut users := map[string]User{} + users['1'] = User{'Peter'} + peter := users['1'] + assert peter.name == 'Peter' + mut a := Aaa{ + m: map[string]int{} + users: map[string]User{} + } + a.users['Bob'] = User{'Bob'} + q := a.users['Bob'] + assert q.name == 'Bob' + // test struct field change + a.users['Bob'].name = 'bob' + q2 := a.users['Bob'] + assert q2.name == 'bob' + a.m['one'] = 1 + a.set('two', 2) + assert a.m['one'] == 1 + assert a.m['two'] == 2 +} + +fn test_map_init() { + one := 'one' + three := 'three' + m := { + one: 1 + 'two': 2 + three: 1 + 2 + } + assert m['one'] == 1 + assert m['two'] == 2 + assert m['three'] == 3 + assert m['unknown'] == 0 +} + +fn test_string_map() { + // m := map[string]Fn +} + +fn test_large_map() { + // ticks := time.ticks() + mut nums := map[string]int{} + n := 30 * 1000 + for i in 0 .. n { + key := i.str() + nums[key] = i + } + assert nums['1'] == 1 + assert nums['999'] == 999 + assert nums['1000000'] == 0 + // println(time.ticks() - ticks) +} + +fn test_various_map_value() { + mut m1 := map[string]int{} + m1['test'] = 1 + assert m1['test'] == 1 + mut m2 := map[string]string{} + m2['test'] = 'test' + assert m2['test'] == 'test' + mut m3 := map[string]i8{} + m3['test'] = i8(0) + assert m3['test'] == i8(0) + mut m4 := map[string]i16{} + m4['test'] = i16(0) + assert m4['test'] == i16(0) + mut m7 := map[string]u16{} + m7['test'] = u16(0) + assert m7['test'] == u16(0) + mut m8 := map[string]u32{} + m8['test'] = u32(0) + assert m8['test'] == u32(0) + mut m9 := map[string]bool{} + m9['test'] = true + assert m9['test'] == true + mut m10 := map[string]byte{} + m10['test'] = byte(0) + assert m10['test'] == byte(0) + mut m11 := map[string]f32{} + m11['test'] = f32(0.0) + assert m11['test'] == f32(0.0) + mut m12 := map[string]f64{} + m12['test'] = f64(0.0) + assert m12['test'] == f64(0.0) + // mut m13 := map[string]rune + // m13['test'] = rune(0) + // assert m13['test'] == rune(0) + // todo(playX): pointer equality does not work yet + /* + mut m14 := map[string]voidptr{} + m14['test'] = voidptr(0) + assert m14['test'] == voidptr(0) + mut m15 := map[string]&byte{} + m15['test'] = &byte(0) + assert m15['test'] == &byte(0) + mut m16 := map[string]i64{} + m16['test'] = i64(0) + assert m16['test'] == i64(0) + mut m17 := map[string]u64{} + m17['test'] = u64(0) + assert m17['test'] == u64(0) + mut m18 := map[string]&int{} + m18['test'] = &int(0) + assert m18['test'] == &int(0)*/ +} + +fn test_string_arr() { + mut m := map[string][]string{} + m['a'] = ['one', 'two'] + assert m['a'].len == 2 + assert m['a'][0] == 'one' + assert m['a'][1] == 'two' +} + +fn mut_map(mut m map[string]int) { + m['a'] = 10 +} + +fn test_mut_arg() { + mut m := map[string]int{} + mut_map(mut m) + a := m['a'] + assert a == 10 +} + +fn test_delete() { + mut m := map[string]int{} + m['one'] = 1 + m['two'] = 2 + println(m['two']) // => "2" + m.delete('two') + println(m['two'].str()) // => 0 + assert ('two' in m) == false + println('two' in m) // => true, on Linux and Windows <-- wrong ! +} + +fn test_delete_size() { + arr := ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'] + mut m := map[string]int{} + for _ in 0 .. 10 { + for i in 0 .. 10 { + m[arr[i]] = i + } + assert m.len == 10 + println(m.len) + for i in 0 .. 10 { + m.delete(arr[i]) + } + } +} + +fn test_nested_for_in() { + mut m := map[string]int{} + for i in 0 .. 1000 { + m[i.str()] = i + } + mut i := 0 + for key1, _ in m { + assert key1 == i.str() + i++ + mut j := 0 + for key2, _ in m { + assert key2 == j.str() + j++ + } + } +} + +fn test_delete_in_for_in() { + mut m := map[string]string{} + for i in 0 .. 1000 { + m[i.str()] = i.str() + } + mut i := 0 + for key, _ in m { + assert key == i.str() + m.delete(key) + i++ + } + assert m.str() == '{}' + assert m.len == 0 +} + +fn test_set_in_for_in() { + mut m := map[string]string{} + for i in 0 .. 10 { + m[i.str()] = i.str() + } + mut last_key := '' + mut i := 0 + for key, _ in m { + m['10'] = '10' + assert key == i.str() + last_key = key + i++ + } + assert last_key == '10' +} + +fn test_delete_and_set_in_for_in() { + mut m := map[string]string{} + for i in 0 .. 1000 { + m[i.str()] = i.str() + } + mut i := 0 + for key, _ in m { + assert key == i.str() + m.delete(key) + m[key] = i.str() + if i == 999 { + break + } + i++ + } + assert m.len == 1000 + i = 0 + for key, _ in m { + assert m[key] == i.str() + i++ + } + assert i == 1000 +} + +struct Mstruct1 { +pub mut: + mymap map[string]int +} + +struct Mstruct2 { +pub mut: + mymap map[string]f64 +} + +struct Mstruct3 { +pub mut: + mymap map[string]u16 +} + +fn test_map_assign() { + mut a := map[string]f64{} + mut b := map[string]int{} + mut c := map[string]u16{} + a = { + 'x': 12.4 + 'y': 3 + } + b = { + 'u': -13 + 'v': 12 + } + c = { + 's': u16(5) + 't': 3 + } + _ := Mstruct1{{ + 'p': 12 + }} + _ := Mstruct2{{ + 'q': 1.7 + }} + _ := Mstruct3{{ + 'r': u16(6) + 's': 5 + }} +} + +fn test_postfix_op_directly() { + mut a := map[string]int{} + a['aaa']++ + assert a['aaa'] == 1 + a['aaa']++ + assert a['aaa'] == 2 + a['bbb']-- + assert a['bbb'] == -1 + a['bbb']-- + assert a['bbb'] == -2 +} + +fn test_map_push_directly() { + mut a := map[string][]string{} + a['aaa'] << ['a', 'b', 'c'] + assert a['aaa'].len == 3 + assert a['aaa'] == ['a', 'b', 'c'] +} + +fn test_assign_directly() { + mut a := map[string]int{} + a['aaa'] += 4 + assert a['aaa'] == 4 + a['aaa'] -= 2 + assert a['aaa'] == 2 +} + +fn test_map_in_directly() { + for k, v in { + 'aa': 1 + } { + assert k == 'aa' + assert v == 1 + } +} + +fn test_plus_assign_string() { + mut m := { + 'one': '' + } + m['one'] += '1' + assert m.len == 1 + assert m['one'] == '1' +} + +fn test_map_keys_to_array() { + m := { + 'a': 'b' + 'c': 'd' + } + mut arr := []string{} + for k, _ in m { + arr << k + } + sarr := arr.str() + println(sarr) + assert sarr == "['a', 'c']" +} + +fn map_in_mut(mut m map[string]int) { + if 'one' in m { + m['one'] = 2 + } +} + +fn test_map_in_mut() { + mut m := { + 'one': 1 + } + map_in_mut(mut m) + assert m['one'] == 2 +} + +fn test_map_in() { + m := { + 'Foo': 'bar' + } + if 'foo'.capitalize() in m { + println('ok') + } else { + assert false + } +} + +fn mut_map_with_relation_op_in_fn(mut m map[string]int) { + if m['one'] == 1 { + m['three'] = 3 + } + if m['two'] != 1 { + m['four'] = 4 + } + if m['one'] > 0 { + m['five'] = 5 + } + if m['one'] < 2 { + m['six'] = 6 + } + if m['two'] >= 2 { + m['seven'] = 7 + } + if m['two'] <= 2 { + m['eight'] = 8 + } +} + +fn test_mut_map_with_relation_op_in_fn() { + mut m := { + 'one': 1 + 'two': 2 + } + mut_map_with_relation_op_in_fn(mut m) + assert 'three' in m + assert 'four' in m + assert 'five' in m + assert 'six' in m + assert 'seven' in m + assert 'eight' in m +} + +fn test_map_str_after_delete() { + mut m := { + 'first': 1 + 'second': 2 + 'third': 3 + } + osm := '$m' + m.delete('second') + nsm := '$m' + println('m: $m') + assert osm == "{'first': 1, 'second': 2, 'third': 3}" + assert nsm == "{'first': 1, 'third': 3}" +} + +fn test_modify_map_value() { + mut m1 := { + 'foo': 3 + 'bar': -7 + } + m1['foo'] += 5 + m1['bar'] *= -2 + assert m1['foo'] == 8 + assert m1['bar'] == 14 +} + +fn test_map_clone() { + mut nums := { + 'foo': 1 + 'bar': 2 + } + mut nums2 := nums.clone() + nums2['foo']++ + nums2['bar'] *= 4 + assert nums['foo'] == 1 + assert nums['bar'] == 2 + assert nums2['foo'] == 2 + assert nums2['bar'] == 8 +} + +struct MValue { + name string + misc map[string]string +} + +fn test_map_default_zero() { + m := map[string]MValue{} + v := m['unknown'] + x := v.misc['x'] + println(x) + assert x == '' +} + +fn test_map_or() { + m := { + 'first': 1 + 'second': 2 + 'third': 3 + } + _ = m + // num := m['first'] or { return } +} + +fn test_int_keys() { + mut m := map[int]int{} + m[3] = 9 + m[4] = 16 + assert m.len == 2 + assert m[3] == 9 + assert m[4] == 16 + m[5] += 24 + m[5]++ + assert m[5] == 25 + mut m2 := { + 3: 9 + 4: 16 + 5: 25 + } + + four := 4 + m2.delete(3) + m2.delete(four) + m2.delete(5) + assert m2.len == 0 + assert m2[3] == 0 + assert m2[4] == 0 + assert m2[5] == 0 + assert m2.keys() == [] + + m2 = { + 3: 9 + 4: 16 + 5: 25 + } + + assert m2.len == 3 + // clone + mc := m.clone() + same := mc == m + assert same + assert mc.len == 3 + assert mc.keys() == [3, 4, 5] + mut all := []int{} + for k, v in mc { + assert m[k] == v + all << k + all << v + } + assert all == [3, 9, 4, 16, 5, 25] + + mut m3 := { + 1: 'one' + 2: 'two' + } + assert m3[1] == 'one' + m3.delete(1) +} + +enum Color { + red + green + blue +} + +type ColorAlias = Color + +fn test_alias_enum() { + mut m := map[ColorAlias]string{} + m[Color.red] = 'hi' + assert m[Color.red] == 'hi' +} + +fn test_enum_in_map() { + mut m := map[Color]string{} + m[Color.red] = 'hi' + assert Color.red in m + assert Color.green !in m + assert Color.blue !in m +} + +fn test_voidptr_keys() { + mut m := map[voidptr]string{} + v := 5 + m[&v] = 'var' + m[&m] = 'map' + assert m[&v] == 'var' + assert m[&m] == 'map' + assert m.len == 2 +} + +fn test_rune_keys() { + mut m := { + `!`: 2 + `%`: 3 + } + assert typeof(m).name == 'map[rune]int' + assert m[`!`] == 2 + m[`@`] = 7 + assert m.len == 3 + println(m) + assert '$m' == '{`!`: 2, `%`: 3, `@`: 7}' + + mut a := []rune{} + for k, v in m { + a << k + a << rune(v) + `0` + } + assert a == [`!`, `2`, `%`, `3`, `@`, `7`] +} + +fn test_eq() { + a := { + 'a': 1 + 'b': 2 + } + assert a == { + 'a': 1 + 'b': 2 + } + b := { + 'a': [[1]] + 'b': [[2]] + } + assert b == { + 'a': [[1]] + 'b': [[2]] + } + c := { + 'a': { + '11': 1 + } + 'b': { + '22': 2 + } + } + assert c == { + 'a': { + '11': 1 + } + 'b': { + '22': 2 + } + } + d := { + 'a': MValue{ + name: 'aa' + misc: { + '11': '1' + } + } + 'b': MValue{ + name: 'bb' + misc: { + '22': '2' + } + } + } + assert d == { + 'a': MValue{ + name: 'aa' + misc: { + '11': '1' + } + } + 'b': MValue{ + name: 'bb' + misc: { + '22': '2' + } + } + } +} + +fn test_non_string_key_map_str() { + assert { + 23: 4 + }.str() == '{23: 4}' + assert { + `a`: 12 + `b`: 13 + }.str() == '{`a`: 12, `b`: 13}' + assert { + 23: 'foo' + 25: 'bar' + }.str() == "{23: 'foo', 25: 'bar'}" +} + +fn test_map_assign_empty_map_init() { + mut a := { + 'one': 1 + } + a = {} + println(a) + assert a == map[string]int{} + assert '$a' == '{}' +} + +fn test_in_map_literal() { + assert 1 in { + 1: 'one' + } +} + +fn test_byte_keys() { + mut m := map[byte]byte{} + byte_max := byte(255) + for i in byte(0) .. byte_max { + m[i] = i + assert m[i] == i + } + for k, v in m { + assert k == v + } + for i in byte(0) .. 100 { + m[i]++ + assert m[i] == i + 1 + } + assert m.len == byte_max + keys := m.keys() + for i in byte(0) .. byte_max { + assert keys[i] == i + } + for i in byte(0) .. byte_max { + m.delete(i) + assert m[i] == 0 + } + assert m.len == 0 +} + +fn test_i16_keys() { + mut m := map[i16]i16{} + end := i16(1000) + for i in i16(0) .. end { + m[i] = i + assert m[i] == i + } + for k, v in m { + assert k == v + } + for i in i16(0) .. 500 { + m[i]++ + assert m[i] == i + 1 + } + assert m.len == end + keys := m.keys() + for i in i16(0) .. end { + assert keys[i] == i + } + for i in i16(0) .. end { + m.delete(i) + assert m[i] == 0 + } + assert m.len == 0 +} + +fn test_u16_keys() { + mut m := map[u16]u16{} + end := u16(1000) + for i in u16(0) .. end { + m[i] = i + assert m[i] == i + } + for k, v in m { + assert k == v + } + for i in u16(0) .. 500 { + m[i]++ + assert m[i] == i + 1 + } + assert m.len == end + keys := m.keys() + for i in u16(0) .. end { + assert keys[i] == i + } + for i in u16(0) .. end { + m.delete(i) + assert m[i] == 0 + } + assert m.len == 0 +} + +fn test_u32_keys() { + mut m := map[u32]u32{} + end := u32(1000) + for i in u32(0) .. end { + m[i] = i + assert m[i] == i + } + for k, v in m { + assert k == v + } + for i in u32(0) .. 500 { + m[i]++ + assert m[i] == i + 1 + } + assert m.len == end + keys := m.keys() + for i in u32(0) .. end { + assert keys[i] == i + } + for i in u32(0) .. end { + m.delete(i) + assert m[i] == 0 + } + assert m.len == 0 +} + +fn test_int_keys2() { + mut m := map[int]int{} + end := 1000 + for i in int(0) .. end { + m[i] = i + assert m[i] == i + } + for k, v in m { + assert k == v + } + for i in int(0) .. 500 { + m[i]++ + assert m[i] == i + 1 + } + assert m.len == end + keys := m.keys() + for i in int(0) .. end { + assert keys[i] == i + } + for i in int(0) .. end { + m.delete(i) + assert m[i] == 0 + } + assert m.len == 0 +} + +fn test_i64_keys() { + mut m := map[i64]i64{} + end := i64(1000) + for i in i64(0) .. end { + m[i] = i + assert m[i] == i + } + for k, v in m { + assert k == v + } + for i in i64(0) .. 500 { + m[i]++ + assert m[i] == i + 1 + } + assert m.len == end + keys := m.keys() + for i in i64(0) .. end { + assert keys[i] == i + } + for i in i64(0) .. end { + m.delete(i) + assert m[i] == 0 + } + assert m.len == 0 +} + +fn test_u64_keys() { + mut m := map[u64]u64{} + end := u64(1000) + for i in u64(0) .. end { + m[i] = i + assert m[i] == i + } + for k, v in m { + assert k == v + } + for i in u64(0) .. 500 { + m[i]++ + assert m[i] == i + 1 + } + assert m.len == end + keys := m.keys() + for i in u64(0) .. end { + assert keys[i] == i + } + for i in u64(0) .. end { + m.delete(i) + assert m[i] == 0 + } + assert m.len == 0 +} + +fn test_map_set_fixed_array_variable() { + mut m := map[string][2]f64{} + m['A'] = [1.1, 2.2]! + println(m) + assert '$m' == "{'A': [1.1, 2.2]}" + + mut m2 := map[string][2]f64{} + arr := [1.1, 2.2]! + m2['A'] = arr + println(m2) + assert '$m2' == "{'A': [1.1, 2.2]}" +} diff --git a/vlib/builtin/js/string.js.v b/vlib/builtin/js/string.js.v index d276435d61..1420f5cfee 100644 --- a/vlib/builtin/js/string.js.v +++ b/vlib/builtin/js/string.js.v @@ -10,6 +10,10 @@ pub fn (s string) slice(a int, b int) string { return string(s.str.slice(a, b)) } +pub fn (s string) substr(start int, end int) string { + return s.slice(start, end) +} + pub fn (s string) after(dot string) string { return string(s.str.slice(s.str.lastIndexOf(dot.str) + 1, int(s.str.length))) } @@ -20,20 +24,37 @@ pub fn (s string) after_char(dot byte) string { } pub fn (s string) all_after(dot string) string { - return string(s.str.slice(s.str.indexOf(dot.str) + 1, int(s.str.length))) + pos := if dot.len == 0 { -1 } else { s.str.indexOf(dot.str) } + if pos == -1 { + return s.clone() + } + return s[pos + dot.len..] } // why does this exist? pub fn (s string) all_after_last(dot string) string { - return s.after(dot) + pos := if dot.len == 0 { -1 } else { s.str.lastIndexOf(dot.str) } + if pos == -1 { + return s.clone() + } + return s[pos + dot.len..] } pub fn (s string) all_before(dot string) string { - return string(s.str.slice(0, s.str.indexOf(dot.str))) + pos := if dot.len == 0 { -1 } else { s.str.indexOf(dot.str) } + if pos == -1 { + return s.clone() + } + return s[..pos] + // return string(s.str.slice(0, s.str.indexOf(dot.str))) } pub fn (s string) all_before_last(dot string) string { - return string(s.str.slice(0, s.str.lastIndexOf(dot.str))) + pos := if dot.len == 0 { -1 } else { s.str.lastIndexOf(dot.str) } + if pos == -1 { + return s.clone() + } + return s[..pos] } pub fn (s string) bool() bool { @@ -79,6 +100,9 @@ pub fn (s string) contains_any(chars string) bool { } pub fn (s string) contains_any_substr(chars []string) bool { + if chars.len == 0 { + return true + } for x in chars { if s.str.includes(x.str) { return true @@ -726,3 +750,131 @@ pub fn (s string) replace_once(rep string, with_ string) string { return s2 } + +pub fn (s string) title() string { + words := s.split(' ') + mut tit := []string{} + for word in words { + tit << word.capitalize() + } + + title := tit.join(' ') + return title +} + +// index_any returns the position of any of the characters in the input string - if found. +pub fn (s string) index_any(chars string) int { + for i, ss in s { + for c in chars { + if c == ss { + return i + } + } + } + return -1 +} + +/* +// limit returns a portion of the string, starting at `0` and extending for a given number of characters afterward. +// 'hello'.limit(2) => 'he' +// 'hi'.limit(10) => 'hi' +pub fn (s string) limit(max int) string { + u := s.runes() + if u.len <= max { + return s.clone() + } + return u[0..max].string() +} +*/ +// is_title returns true if all words of the string is capitalized. +// Example: assert 'Hello V Developer'.is_title() == true +pub fn (s string) is_title() bool { + words := s.split(' ') + for word in words { + if !word.is_capital() { + return false + } + } + return true +} + +// is_capital returns `true` if the first character in the string is a capital letter. +// Example: assert 'Hello'.is_capital() == true +[direct_array_access] +pub fn (s string) is_capital() bool { + if s.len == 0 || !(s[0] >= `A` && s[0] <= `Z`) { + return false + } + for i in 1 .. s.len { + if s[i] >= `A` && s[i] <= `Z` { + return false + } + } + return true +} + +// is_upper returns `true` if all characters in the string is uppercase. +// Example: assert 'HELLO V'.is_upper() == true +pub fn (s string) is_upper() bool { + res := false + #res.val = s.str == s.str.toUpperCase() && s.str != s.str.toLowerCase() + + return res +} + +// is_upper returns `true` if all characters in the string is uppercase. +// Example: assert 'HELLO V'.is_upper() == true +pub fn (s string) is_lower() bool { + res := false + #res.val = s.str == s.str.toLowerCase() && s.str != s.str.toUpperCase() + + return res +} + +pub fn (s string) reverse() string { + res := '' + #res.str = [...s.str].reverse().join('') + + return res +} + +pub fn (s string) trim(cutset string) string { + if s.len < 1 || cutset.len < 1 { + return s.clone() + } + mut pos_left := 0 + mut pos_right := s.len - 1 + mut cs_match := true + for pos_left <= s.len && pos_right >= -1 && cs_match { + cs_match = false + for cs in cutset { + if s[pos_left] == cs { + pos_left++ + cs_match = true + break + } + } + for cs in cutset { + if s[pos_right] == cs { + pos_right-- + cs_match = true + break + } + } + if pos_left > pos_right { + return '' + } + } + return s.substr(pos_left, pos_right + 1) +} + +pub fn (s []string) join(sep string) string { + mut res := '' + for i, str in s { + res += str + if i != s.len - 1 { + res += sep + } + } + return res +} diff --git a/vlib/builtin/js/string_test.js.v b/vlib/builtin/js/string_test.js.v new file mode 100644 index 0000000000..21387f29d0 --- /dev/null +++ b/vlib/builtin/js/string_test.js.v @@ -0,0 +1,897 @@ +import strings + +// Copyright (c) 2019-2021 Alexander Medvednikov. All rights reserved. +// Use of this source code is governed by an MIT license +// that can be found in the LICENSE file. + +struct Foo { + bar int +mut: + str string +} + +fn test_add() { + mut a := 'a' + a += 'b' + assert a == ('ab') + a = 'a' + for i := 1; i < 1000; i++ { + a += 'b' + } + assert a.len == 1000 + assert a.ends_with('bbbbb') + a += '123' + assert a.ends_with('3') +} + +fn test_ends_with() { + a := 'browser.v' + assert 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 +} + +fn test_between() { + s := 'hello [man] how you doing' + assert s.find_between('[', ']') == 'man' +} + +fn test_compare() { + a := 'Music' + b := 'src' + assert b >= a +} + +fn 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 +} + +fn 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 +} + +fn 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 +} + +fn 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' +} + +fn 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' +} + +fn test_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 +} + +fn test_split_nth_values() { + line := 'CMD=eprintln(phase=1)' + + a0 := line.split_nth('=', 0) + assert a0.len == 3 + assert a0[0] == 'CMD' + assert a0[1] == 'eprintln(phase' + assert a0[2] == '1)' + + a1 := line.split_nth('=', 1) + assert a1.len == 1 + assert a1[0] == 'CMD=eprintln(phase=1)' + + a2 := line.split_nth('=', 2) + assert a2.len == 2 + assert a2[0] == 'CMD' + assert a2[1] == 'eprintln(phase=1)' + + a3 := line.split_nth('=', 3) + assert a3.len == 3 + assert a3[0] == 'CMD' + assert a3[1] == 'eprintln(phase' + assert a3[2] == '1)' + + a4 := line.split_nth('=', 4) + assert a4.len == 3 + assert a4[0] == 'CMD' + assert a4[1] == 'eprintln(phase' + assert a4[2] == '1)' +} + +fn 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] == '' +} + +/* +fn test_trim_space() { + a := ' a ' + assert a.trim_space() == 'a' + code := ' + +fn main() { + println(2) +} + +' + code_clean := 'fn main() { + println(2) +}' + assert code.trim_space() == code_clean +}*/ + +/* +fn test_join() { + mut strings := ['a', 'b', 'c'] + mut s := strings.join(' ') + assert s == 'a b c' + strings = [ + 'one +two ', + 'three! +four!', + ] + s = strings.join(' ') + assert s.contains('one') && s.contains('two ') && s.contains('four') + empty := []string{len: 0} + assert empty.join('A') == '' +}*/ + +fn test_clone() { + mut a := 'a' + a += 'a' + a += 'a' + b := a + c := a.clone() + assert c == a + assert c == 'aaa' + assert b == 'aaa' +} + +fn test_replace() { + a := 'hello man!' + mut b := a.replace('man', 'world') + assert b == ('hello world!') + b = b.replace('!', '') + assert b == ('hello world') + b = b.replace('h', 'H') + assert b == ('Hello world') + b = b.replace('foo', 'bar') + assert b == ('Hello world') + s := 'hey man how are you' + assert s.replace('man ', '') == 'hey how are you' + lol := 'lol lol lol' + assert lol.replace('lol', 'LOL') == 'LOL LOL LOL' + b = 'oneBtwoBBthree' + assert b.replace('B', '') == 'onetwothree' + b = '*charptr' + assert b.replace('charptr', 'byteptr') == '*byteptr' + c := 'abc' + println(c.replace('', '-')) + // assert c.replace('', '-') == c + v := 'a b c d' + assert v.replace(' ', ' ') == 'a b c d' +} + +fn test_replace_each() { + s := 'hello man man :)' + q := s.replace_each([ + 'man', + 'dude', + 'hello', + 'hey', + ]) + assert q == 'hey dude dude :)' + bb := '[b]bold[/b] [code]code[/code]' + assert bb.replace_each([ + '[b]', + '', + '[/b]', + '', + '[code]', + '', + '[/code]', + '', + ]) == 'bold code' + bb2 := '[b]cool[/b]' + assert bb2.replace_each([ + '[b]', + '', + '[/b]', + '', + ]) == 'cool' + t := 'aaaaaaaa' + y := t.replace_each([ + 'aa', + 'b', + ]) + assert y == 'bbbb' + s2 := 'hello_world hello' + assert s2.replace_each(['hello_world', 'aaa', 'hello', 'bbb']) == 'aaa bbb' +} + +fn test_itoa() { + num := 777 + assert num.str() == '777' + big := 7779998 + assert big.str() == '7779998' + a := 3 + assert a.str() == '3' + b := 5555 + assert b.str() == '5555' + zero := 0 + assert zero.str() == '0' + neg := -7 + assert neg.str() == '-7' +} + +fn test_reassign() { + a := 'hi' + mut b := a + b += '!' + assert a == 'hi' + assert b == 'hi!' +} + +/* +fn test_runes() { + s := 'привет' + assert s.len == 12 + s2 := 'privet' + assert s2.len == 6 + u := s.runes() + assert u.len == 6 + assert s2.substr(1, 4).len == 3 + assert s2.substr(1, 4) == 'riv' + assert s2[1..4].len == 3 + assert s2[1..4] == 'riv' + assert s2[..4].len == 4 + assert s2[..4] == 'priv' + assert s2[2..].len == 4 + assert s2[2..] == 'ivet' + assert u[1..4].string().len == 6 + assert u[1..4].string() == 'рив' + assert s2.substr(1, 2) == 'r' + assert u[1..2].string() == 'р' + assert s2.runes()[1] == `r` + assert u[1] == `р` + first := u[0] + last := u[u.len - 1] + assert first.str().len == 2 + assert last.str().len == 2 +}*/ + +fn test_contains() { + s := 'view.v' + assert s.contains('vi') + assert !s.contains('random') + assert ''.contains('') + assert 'abc'.contains('') +} + +fn test_contains_any() { + assert !'team'.contains_any('i') + assert 'fail'.contains_any('ui') + assert 'ure'.contains_any('ui') + assert 'failure'.contains_any('ui') + assert !'foo'.contains_any('') + assert !''.contains_any('') +} + +fn test_contains_any_substr() { + s := 'Some random text' + assert s.contains_any_substr(['false', 'not', 'rand']) + assert !s.contains_any_substr(['ABC', 'invalid']) + assert ''.contains_any_substr([]) + assert 'abc'.contains_any_substr(['']) +} + +fn test_arr_contains() { + a := ['a', 'b', 'c'] + assert a.contains('b') + ints := [1, 2, 3] + assert ints.contains(2) +} + +/* +fn test_to_num() { + s := '7' + assert s.int() == 7 + assert s.byte() == 7 + assert s.u64() == 7 + f := '71.5 hasdf' + // QTODO + assert f.f32() == 71.5 + vals := ['9'] + assert vals[0].int() == 9 + big := '93993993939322' + assert big.u64() == 93993993939322 + assert big.i64() == 93993993939322 +}*/ + +/* +fn test_inter_format_string() { + float_num := 1.52345 + float_num_string := '-${float_num:.3f}-' + //assert float_num_string == '-1.523-' + int_num := 7 + int_num_string := '-${int_num:03d}-' + //assert int_num_string == '-007-' + ch := `a` + ch_string := '-${ch:c}-' + //assert ch_string == '-a-' + hex_n := 192 + hex_n_string := '-${hex_n:x}-' + assert hex_n_string == '-c0-' + oct_n := 192 + oct_n_string := '-${oct_n:o}-' + assert oct_n_string == '-300-' + str := 'abc' + str_string := '-${str:s}-' + assert str_string == '-abc-' +}*/ + +/* +fn test_hash() { + s := '10000' + assert s.hash() == 46730161 + s2 := '24640' + assert s2.hash() == 47778736 + s3 := 'Content-Type' + assert s3.hash() == 949037134 + s4 := 'bad_key' + assert s4.hash() == -346636507 + s5 := '24640' + // From a map collision test + assert s5.hash() % ((1 << 20) - 1) == s.hash() % ((1 << 20) - 1) + assert s5.hash() % ((1 << 20) - 1) == 592861 +}*/ + +fn test_trim() { + assert 'banana'.trim('bna') == '' + assert 'abc'.trim('ac') == 'b' + assert 'aaabccc'.trim('ac') == 'b' +} + +fn test_trim_left() { + mut s := 'module main' + assert s.trim_left(' ') == 'module main' + s = ' module main' + assert s.trim_left(' ') == 'module main' + // test cutset + s = 'banana' + assert s.trim_left('ba') == 'nana' + assert s.trim_left('ban') == '' +} + +fn test_trim_right() { + mut s := 'module main' + assert s.trim_right(' ') == 'module main' + s = 'module main ' + assert s.trim_right(' ') == 'module main' + // test cutset + s = 'banana' + assert s.trim_right('na') == 'b' + assert s.trim_right('ban') == '' +} + +fn test_all_before() { + s := 'fn hello fn' + assert s.all_before(' ') == 'fn' + assert s.all_before('2') == s + assert s.all_before('') == s +} + +fn test_all_before_last() { + s := 'fn hello fn' + assert s.all_before_last(' ') == 'fn hello' + assert s.all_before_last('2') == s + assert s.all_before_last('') == s +} + +fn test_all_after() { + s := 'fn hello' + assert s.all_after('fn ') == 'hello' + assert s.all_after('test') == s + assert s.all_after('') == s + assert s.after('e') == 'llo' + x := s.after('e') + assert x == 'llo' +} + +fn test_reverse() { + println('hello'.reverse()) + assert 'hello'.reverse() == 'olleh' + assert ''.reverse() == '' + assert 'a'.reverse() == 'a' +} + +fn test_count() { + assert ''.count('') == 0 + assert ''.count('a') == 0 + assert 'a'.count('') == 0 + assert 'aa'.count('a') == 2 + assert 'aa'.count('aa') == 1 + assert 'aabbaa'.count('aa') == 2 + assert 'bbaabb'.count('aa') == 1 +} + +fn test_lower() { + mut s := 'A' + assert !s.is_lower() + assert s.to_lower() == 'a' + assert s.to_lower().len == 1 + s = 'HELLO' + assert !s.is_lower() + assert s.to_lower() == 'hello' + assert s.to_lower().len == 5 + s = 'Aloha' + assert !s.is_lower() + assert s.to_lower() == 'aloha' + s = 'Have A nice Day!' + assert !s.is_lower() + assert s.to_lower() == 'have a nice day!' + s = 'hi' + assert s.is_lower() + assert s.to_lower() == 'hi' + assert 'aloha!'[0] == `a` + assert 'aloha!'[5] == `!` +} + +fn test_upper() { + mut s := 'a' + assert !s.is_upper() + assert s.to_upper() == 'A' + assert s.to_upper().len == 1 + s = 'hello' + assert !s.is_upper() + assert s.to_upper() == 'HELLO' + assert s.to_upper().len == 5 + s = 'Aloha' + assert !s.is_upper() + assert s.to_upper() == 'ALOHA' + s = 'have a nice day!' + assert !s.is_upper() + assert s.to_upper() == 'HAVE A NICE DAY!' + s = 'HI' + assert s.is_upper() + assert s.to_upper() == 'HI' +} + +fn test_capitalize() { + mut s := 'hello' + assert !s.is_capital() + assert s.capitalize() == 'Hello' + s = 'test' + assert !s.is_capital() + assert s.capitalize() == 'Test' + s = 'i am ray' + assert !s.is_capital() + assert s.capitalize() == 'I am ray' + s = '' + assert !s.is_capital() + assert s.capitalize() == '' + s = 'TEST IT' + assert !s.is_capital() + assert s.capitalize() == 'TEST IT' + s = 'Test it' + assert s.is_capital() + assert s.capitalize() == 'Test it' + assert 'GameMission_t'.capitalize() == 'GameMission_t' +} + +fn test_title() { + mut s := 'hello world' + assert !s.is_title() + assert s.title() == 'Hello World' + s = 'HELLO WORLD' + assert !s.is_title() + assert s.title() == 'HELLO WORLD' + s = 'Hello World' + assert s.is_title() + assert s.title() == 'Hello World' +} + +fn test_for_loop() { + mut i := 0 + s := 'abcd' + + for c in s { + assert c == s[i] + i++ + } +} + +fn test_for_loop_two() { + s := 'abcd' + + for i, c in s { + assert c == s[i] + } +} + +fn test_quote() { + a := `'` + println('testing double quotes') + b := 'hi' + assert b == 'hi' + // assert a.str() == "'" +} + +/* +fn test_limit() { + s := 'hello' + assert s.limit(2) == 'he' + assert s.limit(9) == s + assert s.limit(0) == '' + // assert s.limit(-1) == '' +}*/ + +fn test_repeat() { + s1 := 'V! ' + assert s1.repeat(5) == 'V! V! V! V! V! ' + assert s1.repeat(1) == s1 + assert s1.repeat(0) == '' + s2 := '' + assert s2.repeat(5) == s2 + assert s2.repeat(1) == s2 + assert s2.repeat(0) == s2 + // TODO Add test for negative values +} + +fn test_starts_with() { + s := 'V Programming Language' + assert s.starts_with('V') == true + assert s.starts_with('V Programming') == true + assert s.starts_with('Language') == false +} + +fn test_trim_prefix() { + s := 'V Programming Language' + assert s.trim_prefix('V ') == 'Programming Language' + assert s.trim_prefix('V Programming ') == 'Language' + assert s.trim_prefix('Language') == s + + s2 := 'TestTestTest' + assert s2.trim_prefix('Test') == 'TestTest' + assert s2.trim_prefix('TestTest') == 'Test' + + s3 := '123Test123Test' + assert s3.trim_prefix('123') == 'Test123Test' + assert s3.trim_prefix('123Test') == '123Test' +} + +fn test_trim_suffix() { + s := 'V Programming Language' + assert s.trim_suffix(' Language') == 'V Programming' + assert s.trim_suffix(' Programming Language') == 'V' + assert s.trim_suffix('V') == s + + s2 := 'TestTestTest' + assert s2.trim_suffix('Test') == 'TestTest' + assert s2.trim_suffix('TestTest') == 'Test' + + s3 := '123Test123Test' + assert s3.trim_suffix('123') == s3 + assert s3.trim_suffix('123Test') == '123Test' +} + +fn test_raw() { + raw := r'raw\nstring' + lines := raw.split('\n') + println(lines) + assert lines.len == 1 + println('raw string: "$raw"') + + raw2 := r'Hello V\0' + assert raw2[7] == `\\` + assert raw2[8] == `0` + + raw3 := r'Hello V\x00' + assert raw3[7] == `\\` + assert raw3[8] == `x` + assert raw3[9] == `0` + assert raw3[10] == `0` +} + +fn test_raw_with_quotes() { + raw := r"some'" + r'"thing' // " should be escaped in the generated C code + // assert raw[0] == `s` + // assert raw[5] == `"` + // assert raw[6] == `t` +} + +fn test_escape() { + a := 10 + println("\"$a") + // assert "\"$a" == '"10' +} + +fn test_atoi() { + assert '234232'.int() == 234232 + assert '-9009'.int() == -9009 + assert '0'.int() == 0 + for n in -10000 .. 100000 { + s := n.str() + assert s.int() == n + } +} + +fn test_raw_inter() { + world := 'world' + println(world) + s := r'hello\n$world' + assert s == r'hello\n$world' + assert s.contains('$') +} + +fn test_c_r() { + // This used to break because of r'' and c'' + c := 42 + println('$c') + r := 50 + println('$r') +} + +fn test_inter_before_comp_if() { + s := '123' + // This used to break ('123 $....') + $if linux { + println(s) + } + assert s == '123' +} + +fn test_double_quote_inter() { + a := 1 + b := 2 + println('$a $b') + assert '$a $b' == '1 2' + assert '$a $b' == '1 2' +} + +fn foo(b byte) byte { + return b - 10 +} + +fn filter(b byte) bool { + return b != `a` +} + +/* +fn test_split_into_lines() { + line_content := 'Line' + text_crlf := '$line_content\r\n$line_content\r\n$line_content' + lines_crlf := text_crlf.split_into_lines() + + assert lines_crlf.len == 3 + for line in lines_crlf { + assert line == line_content + } + + text_lf := '$line_content\n$line_content\n$line_content' + lines_lf := text_lf.split_into_lines() + + assert lines_lf.len == 3 + for line in lines_lf { + assert line == line_content + } +} +*/ +fn test_string_literal_with_backslash() { + a := 'HelloWorld' + assert a == 'HelloWorld' + + b := 'OneTwoThree' + assert b == 'OneTwoThree' +} + +/* +type MyString = string + +fn test_string_alias() { + s := MyString('hi') + ss := s + '!' +} +*/ + +// sort an array of structs, by their string field values + +struct Ka { + s string + i int +} + +fn test_sorter() { + mut arr := [ + Ka{ + s: 'bbb' + i: 100 + }, + Ka{ + s: 'aaa' + i: 101 + }, + Ka{ + s: 'ccc' + i: 102 + }, + ] + cmp := fn (a &Ka, b &Ka) int { + return compare_strings(a.s, b.s) + } + arr.sort_with_compare(cmp) + assert arr[0].s == 'aaa' + assert arr[0].i == 101 + assert arr[1].s == 'bbb' + assert arr[1].i == 100 + assert arr[2].s == 'ccc' + assert arr[2].i == 102 +} + +fn test_fields() { + assert 'a bcde'.fields() == ['a', 'bcde'] + assert ' sss \t ssss '.fields() == ['sss', 'ssss'] + assert '\n xyz \t abc def'.fields() == ['xyz', 'abc', 'def'] + assert 'hello'.fields() == ['hello'] + assert ''.fields() == [] +} + +/* +fn test_interpolation_after_quoted_variable_still_works() { + rr := 'abc' + tt := 'xyz' + + // Basic interpolation, no internal quotes + yy := 'Replacing $rr with $tt' + assert yy == 'Replacing abc with xyz' + + // Interpolation after quoted variable ending with 'r'quote + // that may be mistaken with the start of a raw string, + // ensure that it is not. + ss := 'Replacing "$rr" with "$tt"' + assert ss == 'Replacing "abc" with "xyz"' + zz := "Replacing '$rr' with '$tt'" + assert zz == "Replacing 'abc' with 'xyz'" + + // Interpolation after quoted variable ending with 'c'quote + // may be mistaken with the start of a c string, so + // check it is not. + cc := 'abc' + ccc := "Replacing '$cc' with '$tt'" + assert ccc == "Replacing 'abc' with 'xyz'" + cccq := 'Replacing "$cc" with "$tt"' + assert cccq == 'Replacing "abc" with "xyz"' +} +*/ +fn test_index_any() { + x := 'abcdefghij' + assert x.index_any('ef') == 4 + assert x.index_any('fe') == 4 +} diff --git a/vlib/v/gen/js/infix.v b/vlib/v/gen/js/infix.v index 767ce56a72..e6d55fc2f2 100644 --- a/vlib/v/gen/js/infix.v +++ b/vlib/v/gen/js/infix.v @@ -287,7 +287,11 @@ fn (mut g JsGen) infix_in_not_in_op(node ast.InfixExpr) { g.gen_deref_ptr(node.right_type) g.write(',') g.expr(node.left) - g.write('))') + g.write(')') + if node.op == .not_in { + g.write('.valueOf()') + } + g.write(')') return } else if r_sym.unaliased_sym.kind == .map { g.expr(node.right) diff --git a/vlib/v/gen/js/js.v b/vlib/v/gen/js/js.v index be0f8cf132..c87eb5e232 100644 --- a/vlib/v/gen/js/js.v +++ b/vlib/v/gen/js/js.v @@ -145,7 +145,7 @@ pub fn gen(files []&ast.File, table &ast.Table, pref &pref.Preferences) string { g.gen_builtin_type_defs() g.writeln('Object.defineProperty(array.prototype,"len", { get: function() {return new int(this.arr.arr.length);}, set: function(l) { this.arr.arr.length = l.valueOf(); } }); ') g.writeln('Object.defineProperty(string.prototype,"len", { get: function() {return new int(this.str.length);}, set: function(l) {/* ignore */ } }); ') - g.writeln('Object.defineProperty(map.prototype,"len", { get: function() {return new int(this.map.length);}, set: function(l) { this.map.length = l.valueOf(); } }); ') + g.writeln('Object.defineProperty(map.prototype,"len", { get: function() {return new int(this.map.size);}, set: function(l) { this.map.size = l.valueOf(); } }); ') g.writeln('Object.defineProperty(array.prototype,"length", { get: function() {return new int(this.arr.arr.length);}, set: function(l) { this.arr.arr.length = l.valueOf(); } }); ') g.generated_builtin = true } @@ -1182,7 +1182,7 @@ fn (mut g JsGen) gen_assign_stmt(stmt ast.AssignStmt, semicolon bool) { g.write('.val') } - if g.inside_map_set && op == .assign { + if false && g.inside_map_set && op == .assign { g.inside_map_set = false g.write(', ') g.expr(val) @@ -2338,15 +2338,24 @@ fn (mut g JsGen) gen_index_expr(expr ast.IndexExpr) { if expr.is_setter { g.inside_map_set = true - g.write('.map.set(') + g.write('.getOrSet(') } else { g.write('.map.get(') } g.expr(expr.index) g.write('.\$toJS()') - if !expr.is_setter { - g.write(')') + if expr.is_setter { + // g.write(', ${g.to_js_typ_val(left_typ.)') + match left_typ.info { + ast.Map { + g.write(', ${g.to_js_typ_val(left_typ.info.value_type)}') + } + else { + verror('unreachable') + } + } } + g.write(')') } else if left_typ.kind == .string { if expr.is_setter { // TODO: What's the best way to do this?