aboutsummaryrefslogtreecommitdiff
path: root/v_windows/v/vlib/builtin/js
diff options
context:
space:
mode:
authorIndrajith K L2022-12-03 17:00:20 +0530
committerIndrajith K L2022-12-03 17:00:20 +0530
commitf5c4671bfbad96bf346bd7e9a21fc4317b4959df (patch)
tree2764fc62da58f2ba8da7ed341643fc359873142f /v_windows/v/vlib/builtin/js
downloadcli-tools-windows-f5c4671bfbad96bf346bd7e9a21fc4317b4959df.tar.gz
cli-tools-windows-f5c4671bfbad96bf346bd7e9a21fc4317b4959df.tar.bz2
cli-tools-windows-f5c4671bfbad96bf346bd7e9a21fc4317b4959df.zip
Adds most of the toolsHEADmaster
Diffstat (limited to 'v_windows/v/vlib/builtin/js')
-rw-r--r--v_windows/v/vlib/builtin/js/array.js.v253
-rw-r--r--v_windows/v/vlib/builtin/js/builtin.js.v61
-rw-r--r--v_windows/v/vlib/builtin/js/builtin.v84
-rw-r--r--v_windows/v/vlib/builtin/js/byte.js.v16
-rw-r--r--v_windows/v/vlib/builtin/js/int.js.v8
-rw-r--r--v_windows/v/vlib/builtin/js/jsfns.js.v125
-rw-r--r--v_windows/v/vlib/builtin/js/jsfns_browser.js.v59
-rw-r--r--v_windows/v/vlib/builtin/js/jsfns_node.js.v31
-rw-r--r--v_windows/v/vlib/builtin/js/map.js.v26
-rw-r--r--v_windows/v/vlib/builtin/js/string.js.v720
10 files changed, 1383 insertions, 0 deletions
diff --git a/v_windows/v/vlib/builtin/js/array.js.v b/v_windows/v/vlib/builtin/js/array.js.v
new file mode 100644
index 0000000..495e656
--- /dev/null
+++ b/v_windows/v/vlib/builtin/js/array.js.v
@@ -0,0 +1,253 @@
+module builtin
+
+struct array {
+ arr JS.Array
+pub:
+ len int
+ cap int
+}
+
+#function flatIntoArray(target, source, sourceLength, targetIndex, depth) {
+#"use strict";
+#
+#for (var sourceIndex = 0; sourceIndex < sourceLength; ++sourceIndex) {
+#if (sourceIndex in source) {
+#var element = source[sourceIndex];
+#if (depth > 0 && Array.isArray(element))
+#targetIndex = flatIntoArray(target, element, element.length, targetIndex, depth - 1);
+#else {
+#target[targetIndex] = element;
+#++targetIndex;
+#}
+#}
+#}
+#return targetIndex;
+#}
+#function flatArray(target,depth) {
+#var array = target
+#var length = array.length;
+#var depthNum = 1;
+#
+#if (depth !== undefined)
+#depthNum = +depth
+#
+#var result = []
+#
+#flatIntoArray(result, array, length, 0, depthNum);
+#return result;
+#}
+
+[unsafe]
+pub fn (a array) repeat_to_depth(count int, depth int) array {
+ if count < 0 {
+ panic('array.repeat: count is negative: $count')
+ }
+ mut arr := empty_array()
+ #let tmp = new Array(a.arr.length * +count);
+ #tmp.fill(a.arr);
+ #
+ #arr.arr = flatArray(tmp,depth+1);
+
+ return arr
+}
+
+// last returns the last element of the array.
+pub fn (a array) last() voidptr {
+ mut res := voidptr(0)
+ #res = a.arr[a.len-1];
+
+ return res
+}
+
+fn (a array) get(ix int) voidptr {
+ mut result := voidptr(0)
+ #result = a.arr[ix]
+
+ return result
+}
+
+pub fn (a array) repeat(count int) array {
+ unsafe {
+ return a.repeat_to_depth(count, 0)
+ }
+}
+
+fn empty_array() array {
+ mut arr := array{}
+ #arr = new array([])
+
+ return arr
+}
+
+fn (a &array) set_len(i int) {
+ #a.arr.length=i
+}
+
+pub fn (mut a array) sort_with_compare(compare voidptr) {
+ #a.val.arr.sort(compare)
+}
+
+pub fn (mut a array) sort() {
+ #a.val.arr.sort($sortComparator)
+}
+
+pub fn (a array) index(v string) int {
+ for i in 0 .. a.len {
+ #if (a.arr[i].toString() == v.toString())
+
+ {
+ return i
+ }
+ }
+ return -1
+}
+
+pub fn (a array) slice(start int, end int) array {
+ mut result := a
+ #result = new array(a.arr.slice(start,end))
+
+ return result
+}
+
+pub fn (mut a array) insert(i int, val voidptr) {
+ #a.val.arr.splice(i,0,val)
+}
+
+pub fn (mut a array) insert_many(i int, val voidptr, size int) {
+ #a.val.arr.splice(i,0,...val.slice(0,+size))
+}
+
+pub fn (mut a array) join(separator string) string {
+ mut res := ''
+ #res = new builtin.string(a.val.arr.join(separator +''));
+
+ return res
+}
+
+fn (a array) push(val voidptr) {
+ #a.arr.push(val)
+}
+
+pub fn (a array) str() string {
+ mut res := ''
+ #res = new builtin.string(a + '')
+
+ return res
+}
+
+#array.prototype[Symbol.iterator] = function () { return this.arr[Symbol.iterator](); }
+#array.prototype.entries = function () { let result = []; for (const [key,val] of this.arr.entries()) { result.push([new int(key), val]); } return result[Symbol.iterator](); }
+#array.prototype.map = function(callback) { return new builtin.array(this.arr.map(callback)); }
+#array.prototype.filter = function(callback) { return new array(this.arr.filter( function (it) { return (+callback(it)) != 0; } )); }
+#Object.defineProperty(array.prototype,'cap',{ get: function () { return this.len; } })
+#array.prototype.any = function (value) {
+#let val ;if (typeof value == 'function') { val = function (x) { return value(x); } } else { val = function (x) { return vEq(x,value); } }
+#for (let i = 0;i < this.arr.length;i++)
+#if (val(this.arr[i]))
+#return true;
+#
+#return false;
+#}
+
+#array.prototype.all = function (value) {
+#let val ;if (typeof value == 'function') { val = function (x) { return value(x); } } else { val = function (x) { return vEq(x,value); } }
+#for (let i = 0;i < this.arr.length;i++)
+#if (!val(this.arr[i]))
+#return false;
+#
+#return true;
+#}
+// delete deletes array element at index `i`.
+pub fn (mut a array) delete(i int) {
+ a.delete_many(i, 1)
+}
+
+// delete_many deletes `size` elements beginning with index `i`
+pub fn (mut a array) delete_many(i int, size int) {
+ #a.val.arr.splice(i.valueOf(),size.valueOf())
+}
+
+// prepend prepends one value to the array.
+pub fn (mut a array) prepend(val voidptr) {
+ a.insert(0, val)
+}
+
+// prepend_many prepends another array to this array.
+[unsafe]
+pub fn (mut a array) prepend_many(val voidptr, size int) {
+ unsafe { a.insert_many(0, val, size) }
+}
+
+pub fn (a array) reverse() array {
+ mut res := array{}
+ #res.arr = Array.from(a.arr).reverse()
+
+ return res
+}
+
+pub fn (mut a array) reverse_in_place() {
+ #a.val.arr.reverse()
+}
+
+#array.prototype.$includes = function (elem) { return this.arr.find(function(e) { return vEq(elem,e); }) !== undefined;}
+
+// reduce executes a given reducer function on each element of the array,
+// resulting in a single output value.
+pub fn (a array) reduce(iter fn (int, int) int, accum_start int) int {
+ mut accum_ := accum_start
+ #for (let i = 0;i < a.arr.length;i++) {
+ #accum_ = iter(accum_, a.arr[i])
+ #}
+
+ return accum_
+}
+
+pub fn (mut a array) pop() voidptr {
+ mut res := voidptr(0)
+ #res = a.val.arr.pop()
+
+ return res
+}
+
+pub fn (a array) first() voidptr {
+ mut res := voidptr(0)
+ #res = a.arr[0]
+
+ return res
+}
+
+#array.prototype.toString = function () {
+#let res = "["
+#for (let i = 0; i < this.arr.length;i++) {
+#res += this.arr[i].toString();
+#if (i != this.arr.length-1)
+#res += ', '
+#}
+#res += ']'
+#return res;
+#
+#}
+
+pub fn (a array) contains(key voidptr) bool {
+ #for (let i = 0; i < a.arr.length;i++)
+ #if (vEq(a.arr[i],key)) return new bool(true);
+
+ return false
+}
+
+// delete_last effectively removes last element of an array.
+pub fn (mut a array) delete_last() {
+ #a.val.arr.pop();
+}
+
+[unsafe]
+pub fn (a array) free() {
+}
+
+// todo: once (a []byte) will work rewrite this
+pub fn (a array) bytestr() string {
+ res := ''
+ #a.arr.forEach((item) => res.str += String.fromCharCode(+item))
+
+ return res
+}
diff --git a/v_windows/v/vlib/builtin/js/builtin.js.v b/v_windows/v/vlib/builtin/js/builtin.js.v
new file mode 100644
index 0000000..f64da00
--- /dev/null
+++ b/v_windows/v/vlib/builtin/js/builtin.js.v
@@ -0,0 +1,61 @@
+module builtin
+
+// used to generate JS throw statements.
+pub fn js_throw(s any) {
+ #throw s
+}
+
+pub fn println(s string) {
+ $if js_freestanding {
+ #print(s.str)
+ } $else {
+ #console.log(s.str)
+ }
+}
+
+pub fn print(s string) {
+ $if js_node {
+ #$process.stdout.write(s.str)
+ } $else {
+ panic('Cannot `print` in a browser, use `println` instead')
+ }
+}
+
+pub fn eprintln(s string) {
+ $if js_freestanding {
+ #print(s.str)
+ } $else {
+ #console.error(s.str)
+ }
+}
+
+pub fn eprint(s string) {
+ $if js_node {
+ #$process.stderr.write(s.str)
+ } $else {
+ panic('Cannot `eprint` in a browser, use `println` instead')
+ }
+}
+
+// Exits the process in node, and halts execution in the browser
+// because `process.exit` is undefined. Workaround for not having
+// a 'real' way to exit in the browser.
+pub fn exit(c int) {
+ JS.process.exit(c)
+ js_throw('exit($c)')
+}
+
+fn opt_ok(data voidptr, option Option) {
+ #option.state = 0
+ #option.err = none__
+ #option.data = data
+}
+
+pub fn unwrap(opt string) string {
+ mut o := Option{}
+ #o = opt
+ if o.state != 0 {
+ js_throw(o.err)
+ }
+ return opt
+}
diff --git a/v_windows/v/vlib/builtin/js/builtin.v b/v_windows/v/vlib/builtin/js/builtin.v
new file mode 100644
index 0000000..7c82d1a
--- /dev/null
+++ b/v_windows/v/vlib/builtin/js/builtin.v
@@ -0,0 +1,84 @@
+// 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.
+
+module builtin
+
+fn (a any) toString()
+
+pub fn panic(s string) {
+ eprintln('V panic: $s')
+ exit(1)
+}
+
+// IError holds information about an error instance
+pub interface IError {
+ msg string
+ code int
+}
+
+// Error is the default implementation of IError, that is returned by e.g. `error()`
+pub struct Error {
+pub:
+ msg string
+ code int
+}
+
+struct None__ {
+ msg string
+ code int
+}
+
+fn (_ None__) str() string {
+ return 'none'
+}
+
+pub const none__ = IError(None__{'', 0})
+
+pub struct Option {
+ state byte
+ err IError = none__
+}
+
+pub fn (err IError) str() string {
+ return match err {
+ None__ { 'none' }
+ Error { err.msg }
+ else { '$err.type_name(): $err.msg' }
+ }
+}
+
+pub fn (o Option) str() string {
+ if o.state == 0 {
+ return 'Option{ ok }'
+ }
+ if o.state == 1 {
+ return 'Option{ none }'
+ }
+ return 'Option{ error: "$o.err" }'
+}
+
+fn trace_error(x string) {
+ eprintln('> ${@FN} | $x')
+}
+
+// error returns a default error instance containing the error given in `message`.
+// Example: `if ouch { return error('an error occurred') }`
+[inline]
+pub fn error(message string) IError {
+ // trace_error(message)
+ return &Error{
+ msg: message
+ }
+}
+
+// error_with_code returns a default error instance containing the given `message` and error `code`.
+// `if ouch { return error_with_code('an error occurred', 1) }`
+[inline]
+pub fn error_with_code(message string, code int) IError {
+ // trace_error('$message | code: $code')
+ return &Error{
+ msg: message
+ code: code
+ }
+}
diff --git a/v_windows/v/vlib/builtin/js/byte.js.v b/v_windows/v/vlib/builtin/js/byte.js.v
new file mode 100644
index 0000000..af1803b
--- /dev/null
+++ b/v_windows/v/vlib/builtin/js/byte.js.v
@@ -0,0 +1,16 @@
+module builtin
+
+pub fn (b byte) is_space() bool {
+ mut result := false
+ #result.val = /^\s*$/.test(String.fromCharCode(b))
+
+ return result
+}
+
+pub fn (c byte) is_letter() bool {
+ result := false
+
+ #result.val = (c.val >= `a`.charCodeAt() && c.val <= `z`.charCodeAt()) || (c.val >= `A`.charCodeAt() && c.val <= `Z`.charCodeAt())
+
+ return result
+}
diff --git a/v_windows/v/vlib/builtin/js/int.js.v b/v_windows/v/vlib/builtin/js/int.js.v
new file mode 100644
index 0000000..08e52a9
--- /dev/null
+++ b/v_windows/v/vlib/builtin/js/int.js.v
@@ -0,0 +1,8 @@
+module builtin
+
+pub fn (i int) str() string {
+ mut res := ''
+ #res = new builtin.string( i )
+
+ return res
+}
diff --git a/v_windows/v/vlib/builtin/js/jsfns.js.v b/v_windows/v/vlib/builtin/js/jsfns.js.v
new file mode 100644
index 0000000..277c702
--- /dev/null
+++ b/v_windows/v/vlib/builtin/js/jsfns.js.v
@@ -0,0 +1,125 @@
+// 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.
+
+// This file contains JS functions present in both node and the browser.
+// They have been ported from their TypeScript definitions.
+
+module builtin
+
+pub struct JS.Number {}
+
+pub struct JS.String {
+ length JS.Number
+}
+
+pub struct JS.Boolean {}
+
+pub struct JS.Array {
+ length JS.Number
+}
+
+pub struct JS.Map {}
+
+// browser: https://developer.mozilla.org/de/docs/Web/JavaScript/Reference/Global_Objects/Error
+// node: https://nodejs.org/api/errors.html#errors_class_error
+pub struct JS.Error {
+pub:
+ name string
+ message string
+ stack string
+}
+
+// Type prototype functions
+fn (v JS.String) toString() JS.String
+fn (v JS.Number) toString() JS.String
+fn (v JS.Boolean) toString() JS.String
+fn (v JS.Array) toString() JS.String
+fn (v JS.Map) toString() JS.String
+
+// Hack for "`[]JS.String` is not a struct" when returning arr.length or arr.len
+// TODO: Fix []JS.String not a struct error
+fn native_str_arr_len(arr []JS.String) int {
+ len := 0
+ #len = arr.length
+
+ return len
+}
+
+// Top level functions
+fn JS.eval(string) any
+fn JS.parseInt(string, f64) JS.Number
+fn JS.parseFloat(string) JS.Number
+fn JS.isNaN(f64) bool
+fn JS.isFinite(f64) bool
+fn JS.decodeURI(string) string
+fn JS.decodeURIComponent(string) string
+fn JS.encodeURI(string) string
+
+type EncodeURIComponentArg = bool | f64 | string
+
+fn JS.encodeURIComponent(EncodeURIComponentArg) string
+fn JS.escape(string) string
+fn JS.unescape(string) string
+
+// console
+fn JS.console.assert(bool, ...any)
+fn JS.console.clear()
+fn JS.console.count(string)
+fn JS.console.countReset(string)
+fn JS.console.debug(...any)
+fn JS.console.dir(any, any)
+fn JS.console.dirxml(...any)
+fn JS.console.error(...any)
+fn JS.console.exception(string, ...any)
+fn JS.console.group(...any)
+fn JS.console.groupCollapsed(...any)
+fn JS.console.groupEnd()
+fn JS.console.info(...any)
+fn JS.console.log(...any)
+fn JS.console.table(any, []string)
+fn JS.console.time(string)
+fn JS.console.timeEnd(string)
+fn JS.console.timeLog(string, ...any)
+fn JS.console.timeStamp(string)
+fn JS.console.trace(...any)
+fn JS.console.warn(...any)
+
+// Math
+fn JS.Math.abs(f64) f64
+fn JS.Math.acos(f64) f64
+fn JS.Math.asin(f64) f64
+fn JS.Math.atan(f64) f64
+fn JS.Math.atan2(f64, f64) f64
+fn JS.Math.ceil(f64) f64
+fn JS.Math.cos(f64) f64
+fn JS.Math.exp(f64) f64
+fn JS.Math.floor(f64) f64
+fn JS.Math.log(f64) f64
+fn JS.Math.max(...f64) f64
+fn JS.Math.min(...f64) f64
+fn JS.Math.pow(f64, f64) f64
+fn JS.Math.random() f64
+fn JS.Math.round(f64) f64
+fn JS.Math.sin(f64) f64
+fn JS.Math.sqrt(f64) f64
+fn JS.Math.tan(f64) f64
+
+// JSON
+fn JS.JSON.stringify(any) string
+fn JS.JSON.parse(string) any
+
+// String
+fn (v JS.String) slice(a int, b int) JS.String
+fn (v JS.String) split(dot JS.String) []JS.String
+fn (s JS.String) indexOf(needle JS.String) int
+fn (s JS.String) lastIndexOf(needle JS.String) int
+
+fn (s JS.String) charAt(i int) JS.String
+fn (s JS.String) charCodeAt(i int) byte
+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) endsWith(substr JS.String) bool
+fn (s JS.String) startsWith(substr JS.String) bool
diff --git a/v_windows/v/vlib/builtin/js/jsfns_browser.js.v b/v_windows/v/vlib/builtin/js/jsfns_browser.js.v
new file mode 100644
index 0000000..72daec3
--- /dev/null
+++ b/v_windows/v/vlib/builtin/js/jsfns_browser.js.v
@@ -0,0 +1,59 @@
+// 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.
+
+// This file contains JS functions only present in the browser.
+// They have been ported from their TypeScript definitions.
+
+module builtin
+
+// Window
+fn JS.atob(string) string
+fn JS.btoa(string) string
+fn JS.clearInterval(int)
+fn JS.clearTimeout(int)
+
+// fn JS.createImageBitmap(ImageBitmapSource, ImageBitmapOptions) Promise<ImageBitmap>
+// fn JS.createImageBitmap(ImageBitmapSource, int, int, int, int, ImageBitmapOptions) Promise<ImageBitmap>
+
+// TODO: js async attribute
+// [js_async]
+// fn JS.fetch(RequestInfo, RequestInit) Promise<Response>
+fn JS.queueMicrotask(fn ())
+fn JS.setInterval(any, int, ...any) int
+fn JS.setTimeout(any, int, ...any) int
+
+fn JS.alert(any)
+fn JS.blur()
+fn JS.captureEvents()
+fn JS.close()
+fn JS.confirm(string) bool
+
+// fn JS.departFocus(NavigationReason, FocusNavigationOrigin)
+fn JS.focus()
+
+// fn JS.getComputedStyle(Element, string | null) CSSStyleDeclaration
+// fn JS.getMatchedCSSRules(Element, string | null) CSSRuleList
+// fn JS.getSelection() Selection | null
+// fn JS.matchMedia(string) MediaQueryList
+fn JS.moveBy(int, int)
+fn JS.moveTo(int, int)
+fn JS.msWriteProfilerMark(string)
+
+// fn JS.open(string, string, string, bool) ?Window
+// fn JS.postMessage(any, string, []Transferable)
+fn JS.print()
+fn JS.prompt(string, string) ?string
+fn JS.releaseEvents()
+fn JS.resizeBy(int, int)
+fn JS.resizeTo(int, int)
+
+// fn JS.scroll(ScrollToOptions)
+fn JS.scroll(int, int)
+
+// fn JS.scrollBy(ScrollToOptions)
+fn JS.scrollBy(int, int)
+
+// fn JS.scrollTo(ScrollToOptions)
+fn JS.scrollTo(int, int)
+fn JS.stop()
diff --git a/v_windows/v/vlib/builtin/js/jsfns_node.js.v b/v_windows/v/vlib/builtin/js/jsfns_node.js.v
new file mode 100644
index 0000000..6f65629
--- /dev/null
+++ b/v_windows/v/vlib/builtin/js/jsfns_node.js.v
@@ -0,0 +1,31 @@
+// 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.
+
+// This file contains JS functions only present in node.js.
+// They have been ported from their TypeScript definitions.
+
+module builtin
+
+pub struct JS.node_process {
+pub:
+ arch string
+ argsv []string
+ env []string
+ platform string
+ version string
+ // TODO: add all properties
+}
+
+// hack to access process properties
+pub fn js_node_process() JS.node_process {
+ #return process
+
+ return JS.node_process{}
+}
+
+fn JS.process.exit(int)
+fn JS.process.stdout.write(string) bool
+fn JS.process.stdout.writeln(string) bool
+fn JS.process.stderr.write(string) bool
+fn JS.process.stderr.writeln(string) bool
diff --git a/v_windows/v/vlib/builtin/js/map.js.v b/v_windows/v/vlib/builtin/js/map.js.v
new file mode 100644
index 0000000..033a5fd
--- /dev/null
+++ b/v_windows/v/vlib/builtin/js/map.js.v
@@ -0,0 +1,26 @@
+module builtin
+
+struct map {
+ m JS.Map
+ len int
+}
+
+// Removes the mapping of a particular key from the map.
+[unsafe]
+pub fn (mut m map) delete(key voidptr) {
+ #m.map.delete(key)
+}
+
+pub fn (m &map) free() {}
+
+#map.prototype[Symbol.iterator] = function () { return this.map[Symbol.iterator](); }
+
+#map.prototype.toString = function () {
+#function fmtKey(key) { return typeof key == 'string' ? '\'' + key + '\'' : key}
+#let res = '{'
+#for (const entry of this) {
+#res += fmtKey(entry[0]) + ': ' + entry[0];
+#}
+#res += '}'
+#return res;
+#}
diff --git a/v_windows/v/vlib/builtin/js/string.js.v b/v_windows/v/vlib/builtin/js/string.js.v
new file mode 100644
index 0000000..8b2933d
--- /dev/null
+++ b/v_windows/v/vlib/builtin/js/string.js.v
@@ -0,0 +1,720 @@
+module builtin
+
+pub struct string {
+pub:
+ str JS.String
+ len int
+}
+
+pub fn (s string) slice(a int, b int) string {
+ return string(s.str.slice(a, b))
+}
+
+pub fn (s string) after(dot string) string {
+ return string(s.str.slice(s.str.lastIndexOf(dot.str) + 1, int(s.str.length)))
+}
+
+pub fn (s string) after_char(dot byte) string {
+ // TODO: Implement after byte
+ return s
+}
+
+pub fn (s string) all_after(dot string) string {
+ return string(s.str.slice(s.str.indexOf(dot.str) + 1, int(s.str.length)))
+}
+
+// why does this exist?
+pub fn (s string) all_after_last(dot string) string {
+ return s.after(dot)
+}
+
+pub fn (s string) all_before(dot string) string {
+ 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)))
+}
+
+pub fn (s string) bool() bool {
+ return s == 'true'
+}
+
+pub fn (s string) split(dot string) []string {
+ mut arr := s.str.split(dot.str).map(string(it))
+ #arr = new array(arr)
+
+ return arr
+}
+
+pub fn (s string) bytes() []byte {
+ sep := ''
+ mut arr := s.str.split(sep.str).map(it.charCodeAt(0))
+ #arr = new array(arr)
+
+ return arr
+}
+
+pub fn (s string) capitalize() string {
+ part := string(s.str.slice(1, int(s.str.length)))
+ return string(s.str.charAt(0).toUpperCase().concat(part.str))
+}
+
+pub fn (s string) clone() string {
+ return string(s.str)
+}
+
+pub fn (s string) contains(substr string) bool {
+ return s.str.includes(substr.str)
+}
+
+pub fn (s string) contains_any(chars string) bool {
+ sep := ''
+ for x in chars.str.split(sep.str) {
+ if s.str.includes(x) {
+ return true
+ }
+ }
+ return false
+}
+
+pub fn (s string) contains_any_substr(chars []string) bool {
+ for x in chars {
+ if s.str.includes(x.str) {
+ return true
+ }
+ }
+ return false
+}
+
+pub fn (s string) count(substr string) int {
+ // TODO: "error: `[]JS.String` is not a struct" when returning arr.length or arr.len
+ arr := s.str.split(substr.str)
+ return native_str_arr_len(arr)
+}
+
+pub fn (s string) ends_with(p string) bool {
+ mut res := false
+ #res.val = s.str.endsWith(p.str)
+
+ return res
+}
+
+pub fn (s string) starts_with(p string) bool {
+ return s.str.startsWith(p.str)
+}
+
+pub fn (s string) fields() []string {
+ 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 {
+ return string(s.str.slice(s.str.indexOf(start.str) + 1, s.str.indexOf(end.str)))
+}
+
+// unnecessary in the JS backend, implemented for api parity.
+pub fn (s string) free() {}
+
+pub fn (s string) hash() int {
+ mut h := u32(0)
+ if h == 0 && s.len > 0 {
+ for c in s {
+ h = h * 31 + u32(c)
+ }
+ }
+ return int(h)
+}
+
+// int returns the value of the string as an integer `'1'.int() == 1`.
+pub fn (s string) int() int {
+ return int(JS.parseInt(s))
+}
+
+// i64 returns the value of the string as i64 `'1'.i64() == i64(1)`.
+pub fn (s string) i64() i64 {
+ return i64(JS.parseInt(s))
+}
+
+// i8 returns the value of the string as i8 `'1'.i8() == i8(1)`.
+pub fn (s string) i8() i8 {
+ return i8(JS.parseInt(s))
+}
+
+// i16 returns the value of the string as i16 `'1'.i16() == i16(1)`.
+pub fn (s string) i16() i16 {
+ return i16(JS.parseInt(s))
+}
+
+// f32 returns the value of the string as f32 `'1.0'.f32() == f32(1)`.
+pub fn (s string) f32() f32 {
+ // return C.atof(&char(s.str))
+ return f32(JS.parseFloat(s))
+}
+
+// f64 returns the value of the string as f64 `'1.0'.f64() == f64(1)`.
+pub fn (s string) f64() f64 {
+ return f64(JS.parseFloat(s))
+}
+
+// u16 returns the value of the string as u16 `'1'.u16() == u16(1)`.
+pub fn (s string) u16() u16 {
+ return u16(JS.parseInt(s))
+}
+
+// u32 returns the value of the string as u32 `'1'.u32() == u32(1)`.
+pub fn (s string) u32() u32 {
+ return u32(JS.parseInt(s))
+}
+
+// u64 returns the value of the string as u64 `'1'.u64() == u64(1)`.
+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
+}
+
+// TODO: check if that behaves the same as V's own string.replace(old_sub,new_sub):
+pub fn (s string) replace(old_sub string, new_sub string) string {
+ mut result := ''
+ #result = new string( s.str.replaceAll(old_sub.str, new_sub.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
+}
+
+// split_nth splits the string based on the passed `delim` substring.
+// It returns the first Nth parts. When N=0, return all the splits.
+// The last returned element has the remainder of the string, even if
+// the remainder contains more `delim` substrings.
+[direct_array_access]
+pub fn (s string) split_nth(delim string, nth int) []string {
+ mut res := []string{}
+ mut i := 0
+
+ match delim.len {
+ 0 {
+ i = 1
+ for ch in s {
+ if nth > 0 && i >= nth {
+ res << s[i..]
+ break
+ }
+ res << ch.str()
+ i++
+ }
+ return res
+ }
+ 1 {
+ mut start := 0
+ delim_byte := delim[0]
+
+ for i < s.len {
+ if s[i] == delim_byte {
+ was_last := nth > 0 && res.len == nth - 1
+ if was_last {
+ break
+ }
+ val := s[start..i] //.substr(start, i)
+ res << val
+ start = i + delim.len
+ i = start
+ } else {
+ i++
+ }
+ }
+
+ // Then the remaining right part of the string
+ if nth < 1 || res.len < nth {
+ res << s[start..]
+ }
+ return res
+ }
+ else {
+ mut start := 0
+ // Take the left part for each delimiter occurence
+ for i <= s.len {
+ is_delim := i + delim.len <= s.len && s[i..i + delim.len] == delim
+ if is_delim {
+ was_last := nth > 0 && res.len == nth - 1
+ if was_last {
+ break
+ }
+ val := s[start..i] // .substr(start, i)
+ res << val
+ start = i + delim.len
+ i = start
+ } else {
+ i++
+ }
+ }
+ // Then the remaining right part of the string
+ if nth < 1 || res.len < nth {
+ res << s[start..]
+ }
+ return res
+ }
+ }
+}
+
+struct RepIndex {
+ idx int
+ val_idx int
+}
+
+// replace_each replaces all occurences of the string pairs given in `vals`.
+// Example: assert 'ABCD'.replace_each(['B','C/','C','D','D','C']) == 'AC/DC'
+[direct_array_access]
+pub fn (s string) replace_each(vals []string) string {
+ if s.len == 0 || vals.len == 0 {
+ return s.clone()
+ }
+
+ if vals.len % 2 != 0 {
+ eprintln('string.replace_each(): odd number of strings')
+ return s.clone()
+ }
+
+ // `rep` - string to replace
+ // `with_` - string to replace with_
+ // Remember positions of all rep strings, and calculate the length
+ // of the new string to do just one allocation.
+
+ mut idxs := []RepIndex{}
+ mut idx := 0
+ mut new_len := s.len
+ s_ := s.clone()
+ #function setCharAt(str,index,chr) {
+ #if(index > str.length-1) return str;
+ #return str.substring(0,index) + chr + str.substring(index+1);
+ #}
+
+ for rep_i := 0; rep_i < vals.len; rep_i = rep_i + 2 {
+ rep := vals[rep_i]
+
+ mut with_ := vals[rep_i + 1]
+ with_ = with_
+
+ for {
+ idx = s_.index_after(rep, idx)
+ if idx == -1 {
+ break
+ }
+
+ for i in 0 .. rep.len {
+ mut j_ := i
+ j_ = j_
+ #s_.str = setCharAt(s_.str,idx + i, String.fromCharCode(127))
+ }
+
+ rep_idx := RepIndex{
+ idx: 0
+ val_idx: 0
+ }
+ // todo: primitives should always be copied
+ #rep_idx.idx = idx.val
+ #rep_idx.val_idx = new int(rep_i.val)
+ idxs << rep_idx
+ idx += rep.len
+ new_len += with_.len - rep.len
+ }
+ }
+
+ if idxs.len == 0 {
+ return s.clone()
+ }
+
+ idxs.sort(a.idx < b.idx)
+
+ mut b := ''
+ #for (let i = 0; i < new_len.val;i++) b.str += String.fromCharCode(127)
+
+ new_len = new_len
+ mut idx_pos := 0
+ mut cur_idx := idxs[idx_pos]
+ mut b_i := 0
+ for i := 0; i < s.len; i++ {
+ if i == cur_idx.idx {
+ rep := vals[cur_idx.val_idx]
+ with_ := vals[cur_idx.val_idx + 1]
+ for j in 0 .. with_.len {
+ mut j_ := j
+
+ j_ = j_
+ #b.str = setCharAt(b.str,b_i, with_.str[j])
+ //#b.str[b_i] = with_.str[j]
+ b_i++
+ }
+ i += rep.len - 1
+ idx_pos++
+ if idx_pos < idxs.len {
+ cur_idx = idxs[idx_pos]
+ }
+ } else {
+ #b.str = setCharAt(b.str,b_i,s.str[i]) //b.str[b_i] = s.str[i]
+ b_i++
+ }
+ }
+
+ return b
+}
+
+// last_index returns the position of the last occurence of the input string.
+fn (s string) last_index_(p string) int {
+ if p.len > s.len || p.len == 0 {
+ return -1
+ }
+ mut i := s.len - p.len
+ for i >= 0 {
+ mut j := 0
+ for j < p.len && s[i + j] == p[j] {
+ j++
+ }
+ if j == p.len {
+ return i
+ }
+ i--
+ }
+ return -1
+}
+
+// last_index returns the position of the last occurence of the input string.
+pub fn (s string) last_index(p string) ?int {
+ idx := s.last_index_(p)
+ if idx == -1 {
+ return none
+ }
+ return idx
+}
+
+pub fn (s string) trim_space() string {
+ res := ''
+ #res.str = s.str.trim()
+
+ return res
+}
+
+pub fn (s string) index_after(p string, start int) int {
+ if p.len > s.len {
+ return -1
+ }
+
+ mut strt := start
+ if start < 0 {
+ strt = 0
+ }
+ if start >= s.len {
+ return -1
+ }
+ mut i := strt
+
+ for i < s.len {
+ mut j := 0
+ mut ii := i
+ for j < p.len && s[ii] == p[j] {
+ j++
+ ii++
+ }
+
+ if j == p.len {
+ return i
+ }
+ i++
+ }
+ return -1
+}
+
+pub fn (s string) split_into_lines() []string {
+ mut res := []string{}
+ #let i = 0
+ #s.str.split('\n').forEach((str) => {
+ #res.arr[i] = new string(str);
+ #})
+
+ return res
+}