From 06edbc8a381870074c51b6e72c3f028103d5c23f Mon Sep 17 00:00:00 2001 From: playX Date: Thu, 15 Jul 2021 17:36:53 +0300 Subject: [PATCH] v.gen.js: implement most of array and map methods in builtin/js (#10806) --- vlib/builtin/js/array.js.v | 114 ++++++++++++++++++++++ vlib/builtin/js/map.js.v | 14 +++ vlib/builtin/js/{string.v => string.js.v} | 10 +- vlib/v/gen/js/js.v | 44 ++++++--- 4 files changed, 168 insertions(+), 14 deletions(-) create mode 100644 vlib/builtin/js/array.js.v create mode 100644 vlib/builtin/js/map.js.v rename vlib/builtin/js/{string.v => string.js.v} (95%) diff --git a/vlib/builtin/js/array.js.v b/vlib/builtin/js/array.js.v new file mode 100644 index 0000000000..05b2a82ca4 --- /dev/null +++ b/vlib/builtin/js/array.js.v @@ -0,0 +1,114 @@ +module builtin + +struct array { + arr JS.Array +pub: + len 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 +} + +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_comparator(compare voidptr) { + #a.arr.sort(compare) +} + +pub fn (mut a array) sort() { + #a.arr.sort() +} + +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.arr.splice(i,0,val) +} + +fn (a array) push(val voidptr) { + #a.arr.push(val) +} + +#array.prototype[Symbol.iterator] = function () { return this.arr[Symbol.iterator](); } +#array.prototype.entries = function () { return this.arr.entries(); } +#array.prototype.map = function(callback) { return this.arr.map(callback); } +#array.prototype.filter = function(callback) { return this.arr.filter(callback); } diff --git a/vlib/builtin/js/map.js.v b/vlib/builtin/js/map.js.v new file mode 100644 index 0000000000..2153b53112 --- /dev/null +++ b/vlib/builtin/js/map.js.v @@ -0,0 +1,14 @@ +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.m.delete(key) +} + +pub fn (m &map) free() {} diff --git a/vlib/builtin/js/string.v b/vlib/builtin/js/string.js.v similarity index 95% rename from vlib/builtin/js/string.v rename to vlib/builtin/js/string.js.v index a835a7be39..20387a823a 100644 --- a/vlib/builtin/js/string.v +++ b/vlib/builtin/js/string.js.v @@ -41,12 +41,18 @@ pub fn (s string) bool() bool { } pub fn (s string) split(dot string) []string { - return s.str.split(dot.str).map(string(it)) + mut arr := s.str.split(dot.str).map(string(it)) + #arr = new array(arr) + + return arr } pub fn (s string) bytes() []byte { sep := '' - return s.str.split(sep.str).map(it.charCodeAt(0)) + mut arr := s.str.split(sep.str).map(it.charCodeAt(0)) + #arr = new array(arr) + + return arr } pub fn (s string) capitalize() string { diff --git a/vlib/v/gen/js/js.v b/vlib/v/gen/js/js.v index c1c9cdf33b..a4617af1a3 100644 --- a/vlib/v/gen/js/js.v +++ b/vlib/v/gen/js/js.v @@ -124,6 +124,9 @@ pub fn gen(files []&ast.File, table &ast.Table, pref &pref.Preferences) string { // builtin types if g.file.mod.name == 'builtin' && !g.generated_builtin { g.gen_builtin_type_defs() + g.writeln('Object.defineProperty(array.prototype,"len", { get: function() {return this.arr.length;}, set: function(l) { this.arr.length = l; } }); ') + g.writeln('Object.defineProperty(map.prototype,"len", { get: function() {return this.map.length;}, set: function(l) { this.map.length = l; } }); ') + g.writeln('Object.defineProperty(array.prototype,"length", { get: function() {return this.arr.length;}, set: function(l) { this.arr.length = l; } }); ') g.generated_builtin = true } @@ -1005,6 +1008,13 @@ fn (mut g JsGen) gen_method_decl(it ast.FnDecl) { g.write('${it.params[0].name} = this') } g.writeln(') {') + for i, arg in args { + is_varg := i == args.len - 1 && it.is_variadic + if is_varg { + name := g.js_name(arg.name) + g.writeln('$name = new array($name);') + } + } g.stmts(it.stmts) g.write('}') if is_main { @@ -1273,6 +1283,8 @@ fn (mut g JsGen) gen_array_init_expr(it ast.ArrayInit) { // 3) Have several limitations like missing most `Array.prototype` methods // 4) Modern engines can optimize regular arrays into typed arrays anyways, // offering similar performance + g.write('new array(') + g.inc_indent() if it.has_len { t1 := g.new_tmp_var() t2 := g.new_tmp_var() @@ -1300,6 +1312,8 @@ fn (mut g JsGen) gen_array_init_expr(it ast.ArrayInit) { } else { g.gen_array_init_values(it.exprs) } + g.dec_indent() + g.write(')') } fn (mut g JsGen) gen_array_init_values(exprs []ast.Expr) { @@ -1512,9 +1526,9 @@ fn (mut g JsGen) gen_index_expr(expr ast.IndexExpr) { g.expr(expr.left) if expr.is_setter { g.inside_map_set = true - g.write('.set(') + g.write('.map.set(') } else { - g.write('.get(') + g.write('.map.get(') } g.expr(expr.index) g.write('.toString()') @@ -1534,6 +1548,7 @@ fn (mut g JsGen) gen_index_expr(expr ast.IndexExpr) { } else { // TODO Does this cover all cases? g.expr(expr.left) + g.write('.arr') g.write('[') g.cast_stack << ast.int_type_idx g.expr(expr.index) @@ -1568,8 +1583,9 @@ fn (mut g JsGen) gen_infix_expr(it ast.InfixExpr) { g.write(')') } } else if l_sym.kind == .array && it.op == .left_shift { // arr << 1 + g.write('Array.prototype.push.call(') g.expr(it.left) - g.write('.push(') + g.write('.arr,') // arr << [1, 2] if r_sym.kind == .array { g.write('...') @@ -1579,11 +1595,11 @@ fn (mut g JsGen) gen_infix_expr(it ast.InfixExpr) { } else if r_sym.kind in [.array, .map, .string] && it.op in [.key_in, .not_in] { g.expr(it.right) if r_sym.kind == .map { - g.write('.has(') + g.write('.map.has(') } else if r_sym.kind == .string { g.write('.str.includes(') } else { - g.write('.includes(') + g.write('.arr.includes(') } g.expr(it.left) if l_sym.kind == .string { @@ -1680,6 +1696,8 @@ fn (mut g JsGen) gen_map_init_expr(it ast.MapInit) { // value_typ_sym := g.table.get_type_symbol(it.value_type) // key_typ_str := util.no_dots(key_typ_sym.name) // value_typ_str := util.no_dots(value_typ_sym.name) + g.writeln('new map(') + g.inc_indent() if it.vals.len > 0 { g.writeln('new Map([') g.inc_indent() @@ -1700,6 +1718,8 @@ fn (mut g JsGen) gen_map_init_expr(it ast.MapInit) { } else { g.write('new Map()') } + g.dec_indent() + g.write(')') } fn (mut g JsGen) gen_selector_expr(it ast.SelectorExpr) { @@ -1843,16 +1863,16 @@ fn (mut g JsGen) gen_integer_literal_expr(it ast.IntegerLiteral) { // TODO: call.language always seems to be "v", parser bug? if g.call_stack.len > 0 { call := g.call_stack[g.call_stack.len - 1] - // if call.language == .js { - for t in call.args { - if t.expr is ast.IntegerLiteral { - if t.expr == it { - g.write(it.val) - return + if call.language == .js { + for t in call.args { + if t.expr is ast.IntegerLiteral { + if t.expr == it { + g.write(it.val) + return + } } } } - //} } // Skip cast if type is the same as the parrent caster