mirror of
https://github.com/vlang/v.git
synced 2023-08-10 21:13:21 +03:00
js: fix string.bytes codegen, readline, add tests for strings
(#12060)
This commit is contained in:
@ -3,32 +3,37 @@
|
||||
// that can be found in the LICENSE file.
|
||||
module strings
|
||||
|
||||
/*
|
||||
pub struct Builder {
|
||||
mut:
|
||||
buf []byte
|
||||
pub mut:
|
||||
len int
|
||||
initial_size int = 1
|
||||
}
|
||||
}*/
|
||||
|
||||
pub type Builder = []byte
|
||||
|
||||
pub fn new_builder(initial_size int) Builder {
|
||||
return Builder{[]byte{cap: initial_size}, 0, initial_size}
|
||||
return []byte{cap: initial_size}
|
||||
}
|
||||
|
||||
pub fn (mut b Builder) write_b(data byte) {
|
||||
b.buf << data
|
||||
b << data
|
||||
}
|
||||
|
||||
pub fn (mut b Builder) write(data []byte) ?int {
|
||||
if data.len == 0 {
|
||||
return 0
|
||||
}
|
||||
b.buf << data
|
||||
b << data
|
||||
return data.len
|
||||
}
|
||||
|
||||
pub fn (b &Builder) byte_at(n int) byte {
|
||||
return b.buf[n]
|
||||
unsafe {
|
||||
return b[n]
|
||||
}
|
||||
}
|
||||
|
||||
pub fn (mut b Builder) write_string(s string) {
|
||||
@ -37,7 +42,7 @@ pub fn (mut b Builder) write_string(s string) {
|
||||
}
|
||||
|
||||
for c in s {
|
||||
b.buf << c
|
||||
b << c
|
||||
}
|
||||
}
|
||||
|
||||
@ -46,14 +51,41 @@ pub fn (mut b Builder) writeln(s string) {
|
||||
b.write_string(s)
|
||||
}
|
||||
|
||||
b.buf << 10
|
||||
b << 10
|
||||
}
|
||||
|
||||
pub fn (mut b Builder) str() string {
|
||||
s := ''
|
||||
|
||||
#for (const c of b.val.buf.arr.arr)
|
||||
#for (const c of b.val.arr.arr)
|
||||
#s.str += String.fromCharCode(+c)
|
||||
|
||||
b.trim(0)
|
||||
return s
|
||||
}
|
||||
|
||||
pub fn (mut b Builder) cut_last(n int) string {
|
||||
cut_pos := b.len - n
|
||||
x := b[cut_pos..]
|
||||
res := x.bytestr()
|
||||
b.trim(cut_pos)
|
||||
return res
|
||||
}
|
||||
|
||||
pub fn (mut b Builder) go_back_to(pos int) {
|
||||
b.trim(pos)
|
||||
}
|
||||
|
||||
// go_back discards the last `n` bytes from the buffer
|
||||
pub fn (mut b Builder) go_back(n int) {
|
||||
b.trim(b.len - n)
|
||||
}
|
||||
|
||||
// cut_to cuts the string after `pos` and returns it.
|
||||
// if `pos` is superior to builder length, returns an empty string
|
||||
// and cancel further operations
|
||||
pub fn (mut b Builder) cut_to(pos int) string {
|
||||
if pos > b.len {
|
||||
return ''
|
||||
}
|
||||
return b.cut_last(b.len - pos)
|
||||
}
|
||||
|
94
vlib/strings/builder_test.js.v
Normal file
94
vlib/strings/builder_test.js.v
Normal file
@ -0,0 +1,94 @@
|
||||
import strings
|
||||
|
||||
type MyInt = int
|
||||
|
||||
const maxn = 100000
|
||||
|
||||
fn test_sb() {
|
||||
mut sb := strings.new_builder(100)
|
||||
sb.write_string('hi')
|
||||
sb.write_string('!')
|
||||
sb.write_string('hello')
|
||||
assert sb.len == 8
|
||||
sb_end := sb.str()
|
||||
assert sb_end == 'hi!hello'
|
||||
assert sb.len == 0
|
||||
///
|
||||
sb = strings.new_builder(10)
|
||||
sb.write_string('a')
|
||||
sb.write_string('b')
|
||||
assert sb.len == 2
|
||||
assert sb.str() == 'ab'
|
||||
// Test interpolation optimization
|
||||
sb = strings.new_builder(10)
|
||||
x := 10
|
||||
y := MyInt(20)
|
||||
sb.writeln('x = $x y = $y')
|
||||
res := sb.str()
|
||||
assert res[res.len - 1] == `\n`
|
||||
println('"$res"')
|
||||
assert res.trim_space() == 'x = 10 y = 20'
|
||||
//
|
||||
sb = strings.new_builder(10)
|
||||
sb.write_string('x = $x y = $y')
|
||||
assert sb.str() == 'x = 10 y = 20'
|
||||
//$if !windows {
|
||||
sb = strings.new_builder(10)
|
||||
sb.write_string('123456')
|
||||
last_2 := sb.cut_last(2)
|
||||
assert last_2 == '56'
|
||||
final_sb := sb.str()
|
||||
assert final_sb == '1234'
|
||||
//}
|
||||
}
|
||||
|
||||
fn test_big_sb() {
|
||||
mut sb := strings.new_builder(100)
|
||||
mut sb2 := strings.new_builder(10000)
|
||||
for i in 0 .. maxn {
|
||||
sb.writeln(i.str())
|
||||
sb2.write_string('+')
|
||||
}
|
||||
s := sb.str()
|
||||
lines := s.split_into_lines()
|
||||
assert lines.len == maxn
|
||||
assert lines[0] == '0'
|
||||
assert lines[1] == '1'
|
||||
assert lines[777] == '777'
|
||||
assert lines[98765] == '98765'
|
||||
println(sb2.len)
|
||||
assert sb2.len == maxn
|
||||
}
|
||||
|
||||
fn test_byte_write() {
|
||||
mut sb := strings.new_builder(100)
|
||||
temp_str := 'byte testing'
|
||||
mut count := 0
|
||||
for word in temp_str {
|
||||
sb.write_b(word)
|
||||
count++
|
||||
assert count == sb.len
|
||||
}
|
||||
sb_final := sb.str()
|
||||
assert sb_final == temp_str
|
||||
}
|
||||
|
||||
fn test_strings_builder_reuse() {
|
||||
mut sb := strings.new_builder(256)
|
||||
sb.write_string('world')
|
||||
assert sb.str() == 'world'
|
||||
sb.write_string('hello')
|
||||
assert sb.str() == 'hello'
|
||||
}
|
||||
|
||||
fn test_cut_to() {
|
||||
mut sb := strings.new_builder(16)
|
||||
sb.write_string('hello')
|
||||
assert sb.cut_to(3) == 'lo'
|
||||
assert sb.len == 3
|
||||
assert sb.cut_to(3) == ''
|
||||
assert sb.len == 3
|
||||
assert sb.cut_to(0) == 'hel'
|
||||
assert sb.cut_to(32) == ''
|
||||
assert sb.len == 0
|
||||
}
|
13
vlib/strings/similarity_test.js.v
Normal file
13
vlib/strings/similarity_test.js.v
Normal file
@ -0,0 +1,13 @@
|
||||
import strings
|
||||
|
||||
fn test_levenshtein_distance() {
|
||||
assert strings.levenshtein_distance('', '') == 0
|
||||
assert strings.levenshtein_distance('one', 'one') == 0
|
||||
assert strings.levenshtein_distance('', 'two') == 3
|
||||
assert strings.levenshtein_distance('three', '') == 5
|
||||
assert strings.levenshtein_distance('bananna', '') == 7
|
||||
assert strings.levenshtein_distance('cats', 'hats') == 1
|
||||
assert strings.levenshtein_distance('hugs', 'shrugs') == 2
|
||||
assert strings.levenshtein_distance('broom', 'shroom') == 2
|
||||
assert strings.levenshtein_distance('flomax', 'volmax') == 3
|
||||
}
|
@ -9,10 +9,8 @@ pub fn repeat(c byte, n int) string {
|
||||
}
|
||||
|
||||
pub fn repeat_string(s string, n int) string {
|
||||
return ''
|
||||
/*
|
||||
// TODO: uncomment this. It is commented for now, so that `v doc strings` works
|
||||
res := # s.repeat(n)
|
||||
res := ''
|
||||
#res.str = s.str.repeat(n.valueOf())
|
||||
|
||||
return res
|
||||
*/
|
||||
}
|
||||
|
14
vlib/strings/strings_test.js.v
Normal file
14
vlib/strings/strings_test.js.v
Normal file
@ -0,0 +1,14 @@
|
||||
import strings
|
||||
|
||||
fn test_repeat() {
|
||||
assert strings.repeat(`x`, 10) == 'xxxxxxxxxx'
|
||||
assert strings.repeat(`a`, 1) == 'a'
|
||||
assert strings.repeat(`a`, 0) == ''
|
||||
}
|
||||
|
||||
fn test_repeat_string() {
|
||||
assert strings.repeat_string('abc', 3) == 'abcabcabc'
|
||||
assert strings.repeat_string('abc', 1) == 'abc'
|
||||
assert strings.repeat_string('abc', 0) == ''
|
||||
assert strings.repeat_string('', 200) == ''
|
||||
}
|
159
vlib/strings/textscanner/textscanner_test.js.v
Normal file
159
vlib/strings/textscanner/textscanner_test.js.v
Normal file
@ -0,0 +1,159 @@
|
||||
import strings.textscanner
|
||||
|
||||
fn test_remaining() {
|
||||
mut s := textscanner.new('abc')
|
||||
assert s.remaining() == 3
|
||||
s.next()
|
||||
s.next()
|
||||
assert s.remaining() == 1
|
||||
s.next()
|
||||
assert s.remaining() == 0
|
||||
s.next()
|
||||
s.next()
|
||||
assert s.remaining() == 0
|
||||
s.reset()
|
||||
assert s.remaining() == 3
|
||||
}
|
||||
|
||||
fn test_next() {
|
||||
mut s := textscanner.new('abc')
|
||||
assert s.next() == `a`
|
||||
assert s.next() == `b`
|
||||
assert s.next() == `c`
|
||||
assert s.next() == -1
|
||||
assert s.next() == -1
|
||||
assert s.next() == -1
|
||||
}
|
||||
|
||||
fn test_skip() {
|
||||
mut s := textscanner.new('abc')
|
||||
assert s.next() == `a`
|
||||
s.skip()
|
||||
assert s.next() == `c`
|
||||
assert s.next() == -1
|
||||
}
|
||||
|
||||
fn test_skip_n() {
|
||||
mut s := textscanner.new('abc')
|
||||
s.skip_n(2)
|
||||
assert s.next() == `c`
|
||||
assert s.next() == -1
|
||||
}
|
||||
|
||||
fn test_peek() {
|
||||
mut s := textscanner.new('abc')
|
||||
assert s.peek() == `a`
|
||||
assert s.peek() == `a`
|
||||
assert s.peek() == `a`
|
||||
//
|
||||
assert s.next() == `a`
|
||||
assert s.next() == `b`
|
||||
assert s.next() == `c`
|
||||
assert s.next() == -1
|
||||
}
|
||||
|
||||
fn test_peek_n() {
|
||||
mut s := textscanner.new('abc')
|
||||
assert s.peek_n(0) == `a`
|
||||
assert s.peek_n(1) == `b`
|
||||
assert s.peek_n(2) == `c`
|
||||
assert s.peek_n(3) == -1
|
||||
assert s.peek_n(4) == -1
|
||||
//
|
||||
assert s.next() == `a`
|
||||
assert s.next() == `b`
|
||||
assert s.next() == `c`
|
||||
assert s.next() == -1
|
||||
}
|
||||
|
||||
fn test_back() {
|
||||
mut s := textscanner.new('abc')
|
||||
assert s.next() == `a`
|
||||
s.back()
|
||||
assert s.next() == `a`
|
||||
assert s.next() == `b`
|
||||
s.back()
|
||||
assert s.next() == `b`
|
||||
assert s.next() == `c`
|
||||
assert s.next() == -1
|
||||
}
|
||||
|
||||
fn test_back_n() {
|
||||
mut s := textscanner.new('abc')
|
||||
assert s.next() == `a`
|
||||
s.back_n(10)
|
||||
assert s.next() == `a`
|
||||
assert s.next() == `b`
|
||||
assert s.next() == `c`
|
||||
s.back_n(2)
|
||||
assert s.next() == `b`
|
||||
}
|
||||
|
||||
fn test_peek_back() {
|
||||
mut s := textscanner.new('abc')
|
||||
assert s.next() == `a`
|
||||
assert s.next() == `b`
|
||||
// check that calling .peek_back() multiple times
|
||||
// does not change the state:
|
||||
assert s.peek_back() == `a`
|
||||
assert s.peek_back() == `a`
|
||||
assert s.peek_back() == `a`
|
||||
// advance, then peek_back again:
|
||||
assert s.next() == `c`
|
||||
assert s.peek_back() == `b`
|
||||
// peeking before the start:
|
||||
s.reset()
|
||||
assert s.peek_back() == -1
|
||||
// peeking right at the end:
|
||||
s.goto_end()
|
||||
assert s.peek_back() == `b`
|
||||
}
|
||||
|
||||
fn test_peek_back_n() {
|
||||
mut s := textscanner.new('abc')
|
||||
s.goto_end()
|
||||
assert s.peek_back_n(0) == `c`
|
||||
assert s.peek_back_n(1) == `b`
|
||||
assert s.peek_back_n(2) == `a`
|
||||
assert s.peek_back_n(3) == -1
|
||||
assert s.peek_back_n(4) == -1
|
||||
}
|
||||
|
||||
fn test_reset() {
|
||||
mut s := textscanner.new('abc')
|
||||
assert s.next() == `a`
|
||||
s.next()
|
||||
s.next()
|
||||
assert s.next() == -1
|
||||
s.reset()
|
||||
assert s.next() == `a`
|
||||
}
|
||||
|
||||
fn test_current() {
|
||||
mut s := textscanner.new('abc')
|
||||
assert s.current() == -1
|
||||
assert s.next() == `a`
|
||||
assert s.current() == `a`
|
||||
assert s.current() == `a`
|
||||
assert s.peek_back() == -1
|
||||
assert s.next() == `b`
|
||||
assert s.current() == `b`
|
||||
assert s.current() == `b`
|
||||
assert s.peek_back() == `a`
|
||||
assert s.next() == `c`
|
||||
assert s.current() == `c`
|
||||
assert s.next() == -1
|
||||
assert s.current() == `c`
|
||||
assert s.next() == -1
|
||||
assert s.current() == `c`
|
||||
s.reset()
|
||||
assert s.current() == -1
|
||||
assert s.next() == `a`
|
||||
assert s.current() == `a`
|
||||
}
|
||||
|
||||
fn test_goto_end() {
|
||||
mut s := textscanner.new('abc')
|
||||
s.goto_end()
|
||||
assert s.current() == `c`
|
||||
}
|
Reference in New Issue
Block a user