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 | ||||
| } | ||||
| 
 | ||||
| pub fn (mut a array) sort_with_comparator(compare voidptr) { | ||||
| pub fn (mut a array) sort_with_compare(compare voidptr) { | ||||
| 	#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) concat(a JS.String) JS.String | ||||
| fn (s JS.String) includes(substr JS.String) bool | ||||
| fn (s JS.String) ends_with(substr JS.String) bool | ||||
| fn (s JS.String) starts_with(substr JS.String) bool | ||||
| fn (s JS.String) endsWith(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 { | ||||
| 	return s.str.ends_with(p.str) | ||||
| 	return s.str.endsWith(p.str) | ||||
| } | ||||
| 
 | ||||
| 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 { | ||||
| 	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 { | ||||
|  | @ -167,3 +194,265 @@ pub fn (s string) u32() u32 { | |||
| pub fn (s string) u64() u64 { | ||||
| 	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 | ||||
| } | ||||
| 
 | ||||
| [inline] | ||||
| pub fn (typ Type) is_bool() bool { | ||||
| 	return typ.idx() == ast.bool_type_idx | ||||
| } | ||||
| 
 | ||||
| pub const ( | ||||
| 	void_type_idx          = 1 | ||||
| 	voidptr_type_idx       = 2 | ||||
|  |  | |||
|  | @ -308,7 +308,7 @@ fn (mut g JsGen) gen_builtin_type_defs() { | |||
| 					default_value: 'new Number(0)' | ||||
| 					constructor: 'this.val = typeof(val) == "string" ? val.charCodeAt() : (val | 0)' | ||||
| 					value_of: 'this.val | 0' | ||||
| 					to_string: 'String.fromCharCode(this.val)' | ||||
| 					to_string: 'new string(this.val + "")' | ||||
| 					eq: 'this.valueOf() === other.valueOf()' | ||||
| 				) | ||||
| 			} | ||||
|  |  | |||
|  | @ -674,6 +674,7 @@ fn (mut g JsGen) expr(node ast.Expr) { | |||
| 			} else { | ||||
| 				g.write(node.op.str()) | ||||
| 				g.expr(node.right) | ||||
| 				g.write('.valueOf()') | ||||
| 			} | ||||
| 		} | ||||
| 		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 { | ||||
| 				g.expr(branch.cond) | ||||
| 				g.write('.valueOf()') | ||||
| 				g.write(' ? ') | ||||
| 			} | ||||
| 			g.stmts(branch.stmts) | ||||
|  | @ -1474,6 +1476,7 @@ fn (mut g JsGen) gen_if_expr(node ast.IfExpr) { | |||
| 							g.write('true') | ||||
| 						} else { | ||||
| 							g.expr(branch.cond) | ||||
| 							g.write('.valueOf()') | ||||
| 						} | ||||
| 						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 { | ||||
| 				g.write('} else if (') | ||||
| 				g.expr(branch.cond) | ||||
| 				g.write('.valueOf()') | ||||
| 				g.writeln(') {') | ||||
| 			} 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?
 | ||||
| 			// 'string'[3] = `o`
 | ||||
| 		} else { | ||||
| 			// TODO: Maybe use u16 there? JS String returns values up to 2^16-1
 | ||||
| 			g.write('new byte(') | ||||
| 			g.expr(expr.left) | ||||
| 			g.write('.str.charCodeAt(') | ||||
| 			g.expr(expr.index) | ||||
| 			g.write(')') | ||||
| 			g.write('))') | ||||
| 		} | ||||
| 	} else { | ||||
| 		// 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) { | ||||
| 	text := it.val.replace("'", "\\'") | ||||
| 	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' { | ||||
| 			g.write('new ') | ||||
| 		} | ||||
| 		g.write('string(') | ||||
| 	} | ||||
| 	g.write("'$text'") | ||||
| 	if should_cast { | ||||
| 	if true || should_cast { | ||||
| 		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