v.gen.js: port string methods and fix booleans (#10824)
parent
8b8f496762
commit
d5e0fa6d1b
|
@ -74,7 +74,7 @@ fn (a &array) set_len(i int) {
|
||||||
#a.arr.length=i
|
#a.arr.length=i
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (mut a array) sort_with_comparator(compare voidptr) {
|
pub fn (mut a array) sort_with_compare(compare voidptr) {
|
||||||
#a.arr.sort(compare)
|
#a.arr.sort(compare)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
module builtin
|
||||||
|
|
||||||
|
pub fn (b byte) is_space() bool {
|
||||||
|
mut result := false
|
||||||
|
#result = /^\s*$/.test(String.fromCharCode(b))
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
|
@ -121,5 +121,5 @@ fn (s JS.String) toUpperCase() JS.String
|
||||||
fn (s JS.String) toLowerCase() JS.String
|
fn (s JS.String) toLowerCase() JS.String
|
||||||
fn (s JS.String) concat(a JS.String) JS.String
|
fn (s JS.String) concat(a JS.String) JS.String
|
||||||
fn (s JS.String) includes(substr JS.String) bool
|
fn (s JS.String) includes(substr JS.String) bool
|
||||||
fn (s JS.String) ends_with(substr JS.String) bool
|
fn (s JS.String) endsWith(substr JS.String) bool
|
||||||
fn (s JS.String) starts_with(substr JS.String) bool
|
fn (s JS.String) startsWith(substr JS.String) bool
|
||||||
|
|
|
@ -94,15 +94,42 @@ 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.ends_with(p.str)
|
return s.str.endsWith(p.str)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (s string) starts_with(p string) bool {
|
pub fn (s string) starts_with(p string) bool {
|
||||||
return s.str.starts_with(p.str)
|
return s.str.startsWith(p.str)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (s string) fields() []string {
|
pub fn (s string) fields() []string {
|
||||||
return [] // s.str.split()
|
mut res := []string{}
|
||||||
|
mut word_start := 0
|
||||||
|
mut word_len := 0
|
||||||
|
mut is_in_word := false
|
||||||
|
mut is_space := false
|
||||||
|
for i, c in s {
|
||||||
|
is_space = c in [32, 9, 10]
|
||||||
|
if !is_space {
|
||||||
|
word_len++
|
||||||
|
}
|
||||||
|
if !is_in_word && !is_space {
|
||||||
|
word_start = i
|
||||||
|
is_in_word = true
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if is_space && is_in_word {
|
||||||
|
res << s[word_start..word_start + word_len]
|
||||||
|
is_in_word = false
|
||||||
|
word_len = 0
|
||||||
|
word_start = 0
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if is_in_word && word_len > 0 {
|
||||||
|
// collect the remainder word at the end
|
||||||
|
res << s[word_start..s.len]
|
||||||
|
}
|
||||||
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (s string) find_between(start string, end string) string {
|
pub fn (s string) find_between(start string, end string) string {
|
||||||
|
@ -167,3 +194,265 @@ pub fn (s string) u32() u32 {
|
||||||
pub fn (s string) u64() u64 {
|
pub fn (s string) u64() u64 {
|
||||||
return u64(JS.parseInt(s))
|
return u64(JS.parseInt(s))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// trim_right strips any of the characters given in `cutset` from the right of the string.
|
||||||
|
// Example: assert ' Hello V d'.trim_right(' d') == ' Hello V'
|
||||||
|
pub fn (s string) trim_right(cutset string) string {
|
||||||
|
if s.len < 1 || cutset.len < 1 {
|
||||||
|
return s.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
mut pos := s.len - 1
|
||||||
|
|
||||||
|
for pos >= 0 {
|
||||||
|
mut found := false
|
||||||
|
for cs in cutset {
|
||||||
|
if s[pos] == cs {
|
||||||
|
found = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !found {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
pos--
|
||||||
|
}
|
||||||
|
|
||||||
|
if pos < 0 {
|
||||||
|
return ''
|
||||||
|
}
|
||||||
|
|
||||||
|
return s[..pos + 1]
|
||||||
|
}
|
||||||
|
|
||||||
|
// trim_left strips any of the characters given in `cutset` from the left of the string.
|
||||||
|
// Example: assert 'd Hello V developer'.trim_left(' d') == 'Hello V developer'
|
||||||
|
[direct_array_access]
|
||||||
|
pub fn (s string) trim_left(cutset string) string {
|
||||||
|
if s.len < 1 || cutset.len < 1 {
|
||||||
|
return s.clone()
|
||||||
|
}
|
||||||
|
mut pos := 0
|
||||||
|
for pos < s.len {
|
||||||
|
mut found := false
|
||||||
|
for cs in cutset {
|
||||||
|
if s[pos] == cs {
|
||||||
|
found = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !found {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
pos++
|
||||||
|
}
|
||||||
|
return s[pos..]
|
||||||
|
}
|
||||||
|
|
||||||
|
// trim_prefix strips `str` from the start of the string.
|
||||||
|
// Example: assert 'WorldHello V'.trim_prefix('World') == 'Hello V'
|
||||||
|
pub fn (s string) trim_prefix(str string) string {
|
||||||
|
if s.starts_with(str) {
|
||||||
|
return s[str.len..]
|
||||||
|
}
|
||||||
|
return s.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
// trim_suffix strips `str` from the end of the string.
|
||||||
|
// Example: assert 'Hello VWorld'.trim_suffix('World') == 'Hello V'
|
||||||
|
pub fn (s string) trim_suffix(str string) string {
|
||||||
|
if s.ends_with(str) {
|
||||||
|
return s[..s.len - str.len]
|
||||||
|
}
|
||||||
|
return s.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
// compare_strings returns `-1` if `a < b`, `1` if `a > b` else `0`.
|
||||||
|
pub fn compare_strings(a &string, b &string) int {
|
||||||
|
if a < b {
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
if a > b {
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// compare_strings_reverse returns `1` if `a < b`, `-1` if `a > b` else `0`.
|
||||||
|
fn compare_strings_reverse(a &string, b &string) int {
|
||||||
|
if a < b {
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
if a > b {
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// compare_strings_by_len returns `-1` if `a.len < b.len`, `1` if `a.len > b.len` else `0`.
|
||||||
|
fn compare_strings_by_len(a &string, b &string) int {
|
||||||
|
if a.len < b.len {
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
if a.len > b.len {
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// compare_lower_strings returns the same as compare_strings but converts `a` and `b` to lower case before comparing.
|
||||||
|
fn compare_lower_strings(a &string, b &string) int {
|
||||||
|
aa := a.to_lower()
|
||||||
|
bb := b.to_lower()
|
||||||
|
return compare_strings(&aa, &bb)
|
||||||
|
}
|
||||||
|
|
||||||
|
// at returns the byte at index `idx`.
|
||||||
|
// Example: assert 'ABC'.at(1) == byte(`B`)
|
||||||
|
fn (s string) at(idx int) byte {
|
||||||
|
mut result := byte(0)
|
||||||
|
#result = new byte(s.str.charCodeAt(result))
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (s string) to_lower() string {
|
||||||
|
mut result := ''
|
||||||
|
#let str = s.str.toLowerCase()
|
||||||
|
#result = new string(str)
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (s string) to_upper() string {
|
||||||
|
mut result := ''
|
||||||
|
#let str = s.str.toUpperCase()
|
||||||
|
#result = new string(str)
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
// sort sorts the string array.
|
||||||
|
pub fn (mut s []string) sort() {
|
||||||
|
s.sort_with_compare(compare_strings)
|
||||||
|
}
|
||||||
|
|
||||||
|
// sort_ignore_case sorts the string array using case insesitive comparing.
|
||||||
|
pub fn (mut s []string) sort_ignore_case() {
|
||||||
|
s.sort_with_compare(compare_lower_strings)
|
||||||
|
}
|
||||||
|
|
||||||
|
// sort_by_len sorts the the string array by each string's `.len` length.
|
||||||
|
pub fn (mut s []string) sort_by_len() {
|
||||||
|
s.sort_with_compare(compare_strings_by_len)
|
||||||
|
}
|
||||||
|
|
||||||
|
// str returns a copy of the string
|
||||||
|
pub fn (s string) str() string {
|
||||||
|
return s.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (s string) repeat(count int) string {
|
||||||
|
mut result := ''
|
||||||
|
#result = new string(s.str.repeat(count))
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO(playX): Use this iterator instead of using .split('').map(c => byte(c))
|
||||||
|
#function string_iterator(string) { this.stringIteratorFieldIndex = 0; this.stringIteratorIteratedString = string.str; }
|
||||||
|
#string_iterator.prototype.next = function next() {
|
||||||
|
#var done = true;
|
||||||
|
#var value = undefined;
|
||||||
|
#var position = this.stringIteratorFieldIndex;
|
||||||
|
#if (position !== -1) {
|
||||||
|
#var string = this.stringIteratorIteratedString;
|
||||||
|
#var length = string.length >>> 0;
|
||||||
|
#if (position >= length) {
|
||||||
|
#this.stringIteratorFieldIndex = -1;
|
||||||
|
#} else {
|
||||||
|
#done = false;
|
||||||
|
#var first = string.charCodeAt(position);
|
||||||
|
#if (first < 0xD800 || first > 0xDBFF || position + 1 === length)
|
||||||
|
#value = new byte(string[position]);
|
||||||
|
#else {
|
||||||
|
#value = new byte(string[position]+string[position+1])
|
||||||
|
#}
|
||||||
|
#this.stringIteratorFieldIndex = position + value.length;
|
||||||
|
#}
|
||||||
|
#}
|
||||||
|
#return {
|
||||||
|
#value, done
|
||||||
|
#}
|
||||||
|
#}
|
||||||
|
#string.prototype[Symbol.iterator] = function () { return new string_iterator(this) }
|
||||||
|
|
||||||
|
// TODO: Make these functions actually work.
|
||||||
|
// strip_margin allows multi-line strings to be formatted in a way that removes white-space
|
||||||
|
// before a delimeter. by default `|` is used.
|
||||||
|
// Note: the delimiter has to be a byte at this time. That means surrounding
|
||||||
|
// the value in ``.
|
||||||
|
//
|
||||||
|
// Example:
|
||||||
|
// st := 'Hello there,
|
||||||
|
// |this is a string,
|
||||||
|
// | Everything before the first | is removed'.strip_margin()
|
||||||
|
// Returns:
|
||||||
|
// Hello there,
|
||||||
|
// this is a string,
|
||||||
|
// Everything before the first | is removed
|
||||||
|
pub fn (s string) strip_margin() string {
|
||||||
|
return s.strip_margin_custom(`|`)
|
||||||
|
}
|
||||||
|
|
||||||
|
// strip_margin_custom does the same as `strip_margin` but will use `del` as delimiter instead of `|`
|
||||||
|
[direct_array_access]
|
||||||
|
pub fn (s string) strip_margin_custom(del byte) string {
|
||||||
|
mut sep := del
|
||||||
|
if sep.is_space() {
|
||||||
|
eprintln('Warning: `strip_margin` cannot use white-space as a delimiter')
|
||||||
|
eprintln(' Defaulting to `|`')
|
||||||
|
sep = `|`
|
||||||
|
}
|
||||||
|
// don't know how much space the resulting string will be, but the max it
|
||||||
|
// can be is this big
|
||||||
|
mut ret := []byte{}
|
||||||
|
#ret = new array()
|
||||||
|
|
||||||
|
mut count := 0
|
||||||
|
for i := 0; i < s.len; i++ {
|
||||||
|
if s[i] in [10, 13] {
|
||||||
|
unsafe {
|
||||||
|
ret[count] = s[i]
|
||||||
|
}
|
||||||
|
count++
|
||||||
|
// CRLF
|
||||||
|
if s[i] == 13 && i < s.len - 1 && s[i + 1] == 10 {
|
||||||
|
unsafe {
|
||||||
|
ret[count] = s[i + 1]
|
||||||
|
}
|
||||||
|
count++
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
for s[i] != sep {
|
||||||
|
i++
|
||||||
|
if i >= s.len {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
unsafe {
|
||||||
|
ret[count] = s[i]
|
||||||
|
}
|
||||||
|
count++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
unsafe {
|
||||||
|
ret[count] = 0
|
||||||
|
return ret.vstring_with_len(count)
|
||||||
|
}*/
|
||||||
|
mut result := ''
|
||||||
|
#for (let x of ret.arr) result.str += String.fromCharCode(x.val)
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
|
@ -359,6 +359,11 @@ pub fn (typ Type) is_string() bool {
|
||||||
return typ.idx() in ast.string_type_idxs
|
return typ.idx() in ast.string_type_idxs
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[inline]
|
||||||
|
pub fn (typ Type) is_bool() bool {
|
||||||
|
return typ.idx() == ast.bool_type_idx
|
||||||
|
}
|
||||||
|
|
||||||
pub const (
|
pub const (
|
||||||
void_type_idx = 1
|
void_type_idx = 1
|
||||||
voidptr_type_idx = 2
|
voidptr_type_idx = 2
|
||||||
|
|
|
@ -308,7 +308,7 @@ fn (mut g JsGen) gen_builtin_type_defs() {
|
||||||
default_value: 'new Number(0)'
|
default_value: 'new Number(0)'
|
||||||
constructor: 'this.val = typeof(val) == "string" ? val.charCodeAt() : (val | 0)'
|
constructor: 'this.val = typeof(val) == "string" ? val.charCodeAt() : (val | 0)'
|
||||||
value_of: 'this.val | 0'
|
value_of: 'this.val | 0'
|
||||||
to_string: 'String.fromCharCode(this.val)'
|
to_string: 'new string(this.val + "")'
|
||||||
eq: 'this.valueOf() === other.valueOf()'
|
eq: 'this.valueOf() === other.valueOf()'
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -674,6 +674,7 @@ fn (mut g JsGen) expr(node ast.Expr) {
|
||||||
} else {
|
} else {
|
||||||
g.write(node.op.str())
|
g.write(node.op.str())
|
||||||
g.expr(node.right)
|
g.expr(node.right)
|
||||||
|
g.write('.valueOf()')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ast.RangeExpr {
|
ast.RangeExpr {
|
||||||
|
@ -1454,6 +1455,7 @@ fn (mut g JsGen) gen_if_expr(node ast.IfExpr) {
|
||||||
}
|
}
|
||||||
if i < node.branches.len - 1 || !node.has_else {
|
if i < node.branches.len - 1 || !node.has_else {
|
||||||
g.expr(branch.cond)
|
g.expr(branch.cond)
|
||||||
|
g.write('.valueOf()')
|
||||||
g.write(' ? ')
|
g.write(' ? ')
|
||||||
}
|
}
|
||||||
g.stmts(branch.stmts)
|
g.stmts(branch.stmts)
|
||||||
|
@ -1474,6 +1476,7 @@ fn (mut g JsGen) gen_if_expr(node ast.IfExpr) {
|
||||||
g.write('true')
|
g.write('true')
|
||||||
} else {
|
} else {
|
||||||
g.expr(branch.cond)
|
g.expr(branch.cond)
|
||||||
|
g.write('.valueOf()')
|
||||||
}
|
}
|
||||||
g.writeln(') {')
|
g.writeln(') {')
|
||||||
}
|
}
|
||||||
|
@ -1481,6 +1484,7 @@ fn (mut g JsGen) gen_if_expr(node ast.IfExpr) {
|
||||||
} else if i < node.branches.len - 1 || !node.has_else {
|
} else if i < node.branches.len - 1 || !node.has_else {
|
||||||
g.write('} else if (')
|
g.write('} else if (')
|
||||||
g.expr(branch.cond)
|
g.expr(branch.cond)
|
||||||
|
g.write('.valueOf()')
|
||||||
g.writeln(') {')
|
g.writeln(') {')
|
||||||
} else if i == node.branches.len - 1 && node.has_else {
|
} else if i == node.branches.len - 1 && node.has_else {
|
||||||
/*
|
/*
|
||||||
|
@ -1540,10 +1544,12 @@ fn (mut g JsGen) gen_index_expr(expr ast.IndexExpr) {
|
||||||
// TODO: What's the best way to do this?
|
// TODO: What's the best way to do this?
|
||||||
// 'string'[3] = `o`
|
// 'string'[3] = `o`
|
||||||
} else {
|
} else {
|
||||||
|
// TODO: Maybe use u16 there? JS String returns values up to 2^16-1
|
||||||
|
g.write('new byte(')
|
||||||
g.expr(expr.left)
|
g.expr(expr.left)
|
||||||
g.write('.str.charCodeAt(')
|
g.write('.str.charCodeAt(')
|
||||||
g.expr(expr.index)
|
g.expr(expr.index)
|
||||||
g.write(')')
|
g.write('))')
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// TODO Does this cover all cases?
|
// TODO Does this cover all cases?
|
||||||
|
@ -1768,14 +1774,14 @@ fn (mut g JsGen) gen_string_inter_literal(it ast.StringInterLiteral) {
|
||||||
fn (mut g JsGen) gen_string_literal(it ast.StringLiteral) {
|
fn (mut g JsGen) gen_string_literal(it ast.StringLiteral) {
|
||||||
text := it.val.replace("'", "\\'")
|
text := it.val.replace("'", "\\'")
|
||||||
should_cast := !(g.cast_stack.len > 0 && g.cast_stack.last() == ast.string_type_idx)
|
should_cast := !(g.cast_stack.len > 0 && g.cast_stack.last() == ast.string_type_idx)
|
||||||
if should_cast {
|
if true || should_cast {
|
||||||
if g.file.mod.name == 'builtin' {
|
if g.file.mod.name == 'builtin' {
|
||||||
g.write('new ')
|
g.write('new ')
|
||||||
}
|
}
|
||||||
g.write('string(')
|
g.write('string(')
|
||||||
}
|
}
|
||||||
g.write("'$text'")
|
g.write("'$text'")
|
||||||
if should_cast {
|
if true || should_cast {
|
||||||
g.write(')')
|
g.write(')')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
true
|
||||||
|
false
|
|
@ -0,0 +1,4 @@
|
||||||
|
x := ' x'
|
||||||
|
|
||||||
|
println(x[0].is_space())
|
||||||
|
println(x[1].is_space())
|
|
@ -1 +1 @@
|
||||||
2 > 1
|
2 > 1
|
|
@ -1 +1 @@
|
||||||
hello world
|
hello world
|
|
@ -0,0 +1,3 @@
|
||||||
|
Hello V developer
|
||||||
|
Hello V
|
||||||
|
Hello V
|
|
@ -0,0 +1,3 @@
|
||||||
|
println('d Hello V developer'.trim_left(' d'))
|
||||||
|
println(' Hello V d'.trim_right(' d'))
|
||||||
|
println('WorldHello V'.trim_prefix('World'))
|
Loading…
Reference in New Issue