From 82f187e5e0a319c0f678a7889e94cb0f6612609c Mon Sep 17 00:00:00 2001 From: playX Date: Fri, 1 Oct 2021 21:23:49 +0300 Subject: [PATCH] js: fix `rand` build, properly use key values on map, add `rand.string` (#12020) --- vlib/builtin/js/array_test.js.v | 4 +- vlib/builtin/js/map.js.v | 5 +- vlib/rand/rand.c.v | 13 +++ vlib/rand/rand.js.v | 17 ++++ vlib/rand/rand.v | 13 --- vlib/rand/rand_test.js.v | 7 ++ vlib/rand/wyrand/wyrand.js.v | 3 + vlib/rand/wyrand/wyrand.v | 6 -- vlib/rand/wyrand/z_wyrand.c.v | 7 ++ vlib/v/gen/js/auto_str_methods.v | 4 +- vlib/v/gen/js/builtin_types.v | 5 -- vlib/v/gen/js/infix.v | 4 +- vlib/v/gen/js/js.v | 137 +++++++++++++++++++++++++++++-- 13 files changed, 186 insertions(+), 39 deletions(-) create mode 100644 vlib/rand/rand.js.v create mode 100644 vlib/rand/rand_test.js.v create mode 100644 vlib/rand/wyrand/wyrand.js.v create mode 100644 vlib/rand/wyrand/z_wyrand.c.v diff --git a/vlib/builtin/js/array_test.js.v b/vlib/builtin/js/array_test.js.v index b90a8073dc..49e2d6f220 100644 --- a/vlib/builtin/js/array_test.js.v +++ b/vlib/builtin/js/array_test.js.v @@ -1331,8 +1331,8 @@ fn test_struct_array_of_multi_type_in() { }, ] println(ivan in people) - println('TODO: Map eq') - // assert ivan in people + // println('TODO: Map eq') + assert ivan in people } fn test_struct_array_of_multi_type_index() { diff --git a/vlib/builtin/js/map.js.v b/vlib/builtin/js/map.js.v index 033a5fde9e..1b913674b6 100644 --- a/vlib/builtin/js/map.js.v +++ b/vlib/builtin/js/map.js.v @@ -1,7 +1,8 @@ module builtin struct map { - m JS.Map + m JS.Map +pub: len int } @@ -14,7 +15,7 @@ pub fn (mut m map) delete(key voidptr) { pub fn (m &map) free() {} #map.prototype[Symbol.iterator] = function () { return this.map[Symbol.iterator](); } - +//#Object.defineProperty(map.prototype,"len",{get: function() { return this.map.size; }}) #map.prototype.toString = function () { #function fmtKey(key) { return typeof key == 'string' ? '\'' + key + '\'' : key} #let res = '{' diff --git a/vlib/rand/rand.c.v b/vlib/rand/rand.c.v index 066d8ebc2b..cfd91b411f 100644 --- a/vlib/rand/rand.c.v +++ b/vlib/rand/rand.c.v @@ -125,3 +125,16 @@ pub fn hex(len int) string { pub fn ascii(len int) string { return string_from_set(ascii_chars, len) } + +fn deinit() { + unsafe { + default_rng.free() // free the implementation + free(default_rng) // free the interface wrapper itself + } +} + +// init initializes the default RNG. +fn init() { + default_rng = new_default() + C.atexit(deinit) +} diff --git a/vlib/rand/rand.js.v b/vlib/rand/rand.js.v new file mode 100644 index 0000000000..ce4ea265c2 --- /dev/null +++ b/vlib/rand/rand.js.v @@ -0,0 +1,17 @@ +module rand + +// init initializes the default RNG. +fn init() { + default_rng = new_default() +} + +pub fn string(len int) string { + result := '' + # + #const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; + #const charactersLength = characters.length; + #for (let i = 0;i < len.val;i++) + #result.str += characters.charAt(Math.random() * charactersLength); + + return result +} diff --git a/vlib/rand/rand.v b/vlib/rand/rand.v index 29b813649e..cac98b8c74 100644 --- a/vlib/rand/rand.v +++ b/vlib/rand/rand.v @@ -38,19 +38,6 @@ __global ( default_rng &PRNG ) -// init initializes the default RNG. -fn init() { - default_rng = new_default() - C.atexit(deinit) -} - -fn deinit() { - unsafe { - default_rng.free() // free the implementation - free(default_rng) // free the interface wrapper itself - } -} - // new_default returns a new instance of the default RNG. If the seed is not provided, the current time will be used to seed the instance. [manualfree] pub fn new_default(config config.PRNGConfigStruct) &PRNG { diff --git a/vlib/rand/rand_test.js.v b/vlib/rand/rand_test.js.v new file mode 100644 index 0000000000..8603bbd4a5 --- /dev/null +++ b/vlib/rand/rand_test.js.v @@ -0,0 +1,7 @@ +import rand + +fn test_string() { + res := rand.string(4) + assert res.len == 4 + println(res) +} diff --git a/vlib/rand/wyrand/wyrand.js.v b/vlib/rand/wyrand/wyrand.js.v new file mode 100644 index 0000000000..1e5d4b4424 --- /dev/null +++ b/vlib/rand/wyrand/wyrand.js.v @@ -0,0 +1,3 @@ +module wyrand + +pub fn (mut r WyRandRNG) free() {} diff --git a/vlib/rand/wyrand/wyrand.v b/vlib/rand/wyrand/wyrand.v index a55a243ce1..22b71afbad 100644 --- a/vlib/rand/wyrand/wyrand.v +++ b/vlib/rand/wyrand/wyrand.v @@ -250,9 +250,3 @@ pub fn (mut rng WyRandRNG) f64_in_range(min f64, max f64) f64 { } return min + rng.f64n(max - min) } - -// free should be called when the generator is no longer needed -[unsafe] -pub fn (mut rng WyRandRNG) free() { - unsafe { free(rng) } -} diff --git a/vlib/rand/wyrand/z_wyrand.c.v b/vlib/rand/wyrand/z_wyrand.c.v new file mode 100644 index 0000000000..e6cb6b4b45 --- /dev/null +++ b/vlib/rand/wyrand/z_wyrand.c.v @@ -0,0 +1,7 @@ +module wyrand + +// free should be called when the generator is no longer needed +[unsafe] +pub fn (mut rng WyRandRNG) free() { + unsafe { free(rng) } +} diff --git a/vlib/v/gen/js/auto_str_methods.v b/vlib/v/gen/js/auto_str_methods.v index 2c7cedccc6..38b109aa57 100644 --- a/vlib/v/gen/js/auto_str_methods.v +++ b/vlib/v/gen/js/auto_str_methods.v @@ -589,9 +589,9 @@ fn (mut g JsGen) gen_str_for_map(info ast.Map, styp string, str_fn_name string) g.definitions.writeln('\tstrings__Builder_write_string(sb, new string("{"));') g.definitions.writeln('\tlet i = 0;') g.definitions.writeln('\tfor (let [key,value] of m.map) {') - + g.definitions.writeln('\t\tkey = new ${key_styp}(key);') if key_sym.kind == .string { - g.definitions.writeln('\t\tstrings__Builder_write_string(sb, new string(key));') + g.definitions.writeln('\t\tstrings__Builder_write_string(sb, new string("\'" + key.str + "\'"));') } else if key_sym.kind == .rune { // tmp_str := str_intp_rune('${key_str_fn_name}(key)') // g.definitions.writeln('\t\tstrings__Builder_write_string(sb, $tmp_str);') diff --git a/vlib/v/gen/js/builtin_types.v b/vlib/v/gen/js/builtin_types.v index 4e0e8d6f39..7dd4476574 100644 --- a/vlib/v/gen/js/builtin_types.v +++ b/vlib/v/gen/js/builtin_types.v @@ -300,11 +300,6 @@ fn (mut g JsGen) gen_builtin_prototype(c BuiltinPrototypeConfig) { g.dec_indent() g.writeln('};\n') g.writeln('function ${c.typ_name}__eq(self,other) { return $c.eq; } ') - for method in g.method_fn_decls[c.typ_name] { - g.inside_def_typ_decl = true - g.gen_method_decl(method, .struct_method) - g.inside_def_typ_decl = false - } } // generate builtin type definitions, used for casting and methods. diff --git a/vlib/v/gen/js/infix.v b/vlib/v/gen/js/infix.v index 010c89ca9d..767ce56a72 100644 --- a/vlib/v/gen/js/infix.v +++ b/vlib/v/gen/js/infix.v @@ -294,11 +294,13 @@ fn (mut g JsGen) infix_in_not_in_op(node ast.InfixExpr) { g.gen_deref_ptr(node.right_type) g.write('.map.has(') g.expr(node.left) + /* if l_sym.sym.kind == .string { g.write('.str') } else { g.write('.valueOf()') - } + }*/ + g.write('.\$toJS()') g.write(')') } else { g.write('.str.includes(') diff --git a/vlib/v/gen/js/js.v b/vlib/v/gen/js/js.v index ac1cb511fc..be0f8cf132 100644 --- a/vlib/v/gen/js/js.v +++ b/vlib/v/gen/js/js.v @@ -200,6 +200,18 @@ pub fn gen(files []&ast.File, table &ast.Table, pref &pref.Preferences) string { } } } + + for mod_name in g.table.modules { + g.writeln('// Initializations for module $mod_name') + init_fn_name := '${mod_name}.init' + if initfn := g.table.find_fn(init_fn_name) { + if initfn.return_type == ast.void_type && initfn.params.len == 0 { + mod_c_name := util.no_dots(mod_name) + init_fn_c_name := '${mod_c_name}__init' + g.writeln('${init_fn_c_name}();') + } + } + } g.write('js_main();') g.escape_namespace() // resolve imports @@ -207,6 +219,7 @@ pub fn gen(files []&ast.File, table &ast.Table, pref &pref.Preferences) string { nodes := deps_resolved.nodes mut out := g.definitions.str() + g.hashes() + // equality check for js objects // TODO: Fix msvc bug that's preventing $embed_file('fast_deep_equal.js') // unsafe { @@ -221,8 +234,8 @@ pub fn gen(files []&ast.File, table &ast.Table, pref &pref.Preferences) string { out += 'if (typeof module === "object" && module.exports) module.exports = $export;\n' } out += '\n' - out += g.out.str() + out += g.out.str() /* TODO(playX): Again add support for these doc comments for node in nodes { @@ -876,12 +889,18 @@ fn (mut g JsGen) expr(node ast.Expr) { g.write(')') } ast.PostfixExpr { + // match node.expr { + // ast.IndexExpr { + // g.gen_postfix_index_expr(node.expr,node.op) + // } else { g.expr(node.expr) if node.op in [.inc, .dec] { g.write('.val $node.op') } else { g.write(node.op.str()) } + // } + // } } ast.PrefixExpr { if node.op in [.amp, .mul] { @@ -1126,6 +1145,7 @@ fn (mut g JsGen) gen_assign_stmt(stmt ast.AssignStmt, semicolon bool) { } } mut array_set := false + mut map_set := false match left { ast.IndexExpr { g.expr(left.left) @@ -1133,17 +1153,24 @@ fn (mut g JsGen) gen_assign_stmt(stmt ast.AssignStmt, semicolon bool) { g.write('.valueOf()') } array_set = true + if g.table.get_type_symbol(left.left_type).kind == .map { g.write('.map.set(') + map_set = true } else { g.write('.arr.set(') } - g.write('new int(') - g.cast_stack << ast.int_type_idx - g.expr(left.index) - g.write('.valueOf()') - g.cast_stack.delete_last() - g.write('),') + if map_set { + g.expr(left.index) + g.write('.\$toJS(),') + } else { + g.write('new int(') + g.cast_stack << ast.int_type_idx + g.expr(left.index) + g.write('.valueOf()') + g.cast_stack.delete_last() + g.write('),') + } } else { g.expr(left) @@ -2308,6 +2335,7 @@ fn (mut g JsGen) gen_index_expr(expr ast.IndexExpr) { g.write(')') } else if left_typ.kind == .map { g.expr(expr.left) + if expr.is_setter { g.inside_map_set = true g.write('.map.set(') @@ -2315,7 +2343,7 @@ fn (mut g JsGen) gen_index_expr(expr ast.IndexExpr) { g.write('.map.get(') } g.expr(expr.index) - g.write('.toString()') + g.write('.\$toJS()') if !expr.is_setter { g.write(')') } @@ -2632,6 +2660,7 @@ fn (mut g JsGen) gen_map_init_expr(it ast.MapInit) { val := it.vals[i] g.write('[') g.expr(key) + g.write('.\$toJS()') g.write(', ') g.expr(val) g.write(']') @@ -2950,3 +2979,95 @@ fn replace_op(s string) string { else { '' } } } + +fn (mut g JsGen) gen_postfix_index_expr(expr ast.IndexExpr, op token.Kind) { + left_typ := g.table.get_type_symbol(expr.left_type) + // TODO: Handle splice setting if it's implemented + if expr.index is ast.RangeExpr { + if left_typ.kind == .array { + g.write('array_slice(') + } else { + g.write('string_slice(') + } + g.expr(expr.left) + if expr.left_type.is_ptr() { + g.write('.valueOf()') + } + g.write(',') + + if expr.index.has_low { + g.expr(expr.index.low) + } else { + g.write('new int(0)') + } + g.write(', ') + if expr.index.has_high { + g.expr(expr.index.high) + } else { + g.expr(expr.left) + if expr.left_type.is_ptr() { + g.write('.valueOf()') + } + g.write('.len') + } + g.write(')') + } else if left_typ.kind == .map { + g.expr(expr.left) + + if expr.is_setter { + g.inside_map_set = true + g.write('.map.set(') + } else { + g.write('.map.get(') + } + g.expr(expr.index) + g.write('.\$toJS()') + if !expr.is_setter { + g.write(')') + } else { + g.write(',') + lsym := g.table.get_type_symbol(expr.left_type) + key_typ := match lsym.info { + ast.Map { + lsym.info.value_type + } + else { + verror('unreachable') + } + } + g.write('new ${g.typ(key_typ)}(') + + g.expr(expr.left) + g.write('.map.get(') + g.expr(expr.index) + g.write('.\$toJS())') + match op { + .inc { + g.write('.val + 1)') + } + .dec { + g.write('.val - 1)') + } + else { + verror('not yet implemented') + } + } + g.write(')') + } + } else if left_typ.kind == .string { + if expr.is_setter { + // 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) + if expr.left_type.is_ptr() { + g.write('.valueOf()') + } + g.write('.str.charCodeAt(') + g.expr(expr.index) + g.write('))') + } + } +}