From 659f823c5c940250ca789a2822246834ece057c9 Mon Sep 17 00:00:00 2001 From: playX Date: Sun, 15 Aug 2021 15:09:51 +0000 Subject: [PATCH] js: initial work on porting rand module to JS backend (#11188) --- vlib/hash/wyhash.c.v | 10 +++ vlib/hash/wyhash.js.v | 1 + vlib/hash/wyhash.v | 10 --- vlib/rand/rand.c.v | 127 +++++++++++++++++++++++++++++++++ vlib/rand/rand.v | 129 +--------------------------------- vlib/v/gen/js/builtin_types.v | 2 +- vlib/v/gen/js/js.v | 55 +++++++++++---- 7 files changed, 182 insertions(+), 152 deletions(-) create mode 100644 vlib/hash/wyhash.js.v create mode 100644 vlib/rand/rand.c.v diff --git a/vlib/hash/wyhash.c.v b/vlib/hash/wyhash.c.v index 164ebeecb8..3f93d245d2 100644 --- a/vlib/hash/wyhash.c.v +++ b/vlib/hash/wyhash.c.v @@ -21,3 +21,13 @@ pub fn wyhash_c(key &byte, len u64, seed u64) u64 { pub fn wyhash64_c(a u64, b u64) u64 { return C.wyhash64(a, b) } + +[inline] +pub fn sum64_string(key string, seed u64) u64 { + return wyhash_c(key.str, u64(key.len), seed) +} + +[inline] +pub fn sum64(key []byte, seed u64) u64 { + return wyhash_c(&byte(key.data), u64(key.len), seed) +} diff --git a/vlib/hash/wyhash.js.v b/vlib/hash/wyhash.js.v new file mode 100644 index 0000000000..26af4da0eb --- /dev/null +++ b/vlib/hash/wyhash.js.v @@ -0,0 +1 @@ +module hash diff --git a/vlib/hash/wyhash.v b/vlib/hash/wyhash.v index bd89c4216e..fb438a13a7 100644 --- a/vlib/hash/wyhash.v +++ b/vlib/hash/wyhash.v @@ -23,16 +23,6 @@ const ( wyp4 = u64(0x1d8e4e27c47d124f) ) -[inline] -pub fn sum64_string(key string, seed u64) u64 { - return wyhash_c(key.str, u64(key.len), seed) -} - -[inline] -pub fn sum64(key []byte, seed u64) u64 { - return wyhash_c(&byte(key.data), u64(key.len), seed) -} - [inline] fn wyrotr(v u64, k u32) u64 { return (v >> k) | (v << (64 - k)) diff --git a/vlib/rand/rand.c.v b/vlib/rand/rand.c.v new file mode 100644 index 0000000000..066d8ebc2b --- /dev/null +++ b/vlib/rand/rand.c.v @@ -0,0 +1,127 @@ +module rand + +import time +// uuid_v4 generates a random (v4) UUID +// See https://en.wikipedia.org/wiki/Universally_unique_identifier#Version_4_(random) + +pub fn uuid_v4() string { + buflen := 36 + mut buf := unsafe { malloc_noscan(37) } + mut i_buf := 0 + mut x := u64(0) + mut d := byte(0) + for i_buf < buflen { + mut c := 0 + x = default_rng.u64() + // do most of the bit manipulation at once: + x &= 0x0F0F0F0F0F0F0F0F + x += 0x3030303030303030 + // write the ASCII codes to the buffer: + for c < 8 && i_buf < buflen { + d = byte(x) + unsafe { + buf[i_buf] = if d > 0x39 { d + 0x27 } else { d } + } + i_buf++ + c++ + x = x >> 8 + } + } + // there are still some random bits in x: + x = x >> 8 + d = byte(x) + unsafe { + buf[19] = if d > 0x39 { d + 0x27 } else { d } + buf[8] = `-` + buf[13] = `-` + buf[18] = `-` + buf[23] = `-` + buf[14] = `4` + buf[buflen] = 0 + return buf.vstring_with_len(buflen) + } +} + +const ( + ulid_encoding = '0123456789ABCDEFGHJKMNPQRSTVWXYZ' +) + +// ulid generates an Unique Lexicographically sortable IDentifier. +// See https://github.com/ulid/spec . +// NB: ULIDs can leak timing information, if you make them public, because +// you can infer the rate at which some resource is being created, like +// users or business transactions. +// (https://news.ycombinator.com/item?id=14526173) +pub fn ulid() string { + return ulid_at_millisecond(u64(time.utc().unix_time_milli())) +} + +// ulid_at_millisecond does the same as `ulid` but takes a custom Unix millisecond timestamp via `unix_time_milli`. +pub fn ulid_at_millisecond(unix_time_milli u64) string { + buflen := 26 + mut buf := unsafe { malloc_noscan(27) } + mut t := unix_time_milli + mut i := 9 + for i >= 0 { + unsafe { + buf[i] = rand.ulid_encoding[t & 0x1F] + } + t = t >> 5 + i-- + } + // first rand set + mut x := default_rng.u64() + i = 10 + for i < 19 { + unsafe { + buf[i] = rand.ulid_encoding[x & 0x1F] + } + x = x >> 5 + i++ + } + // second rand set + x = default_rng.u64() + for i < 26 { + unsafe { + buf[i] = rand.ulid_encoding[x & 0x1F] + } + x = x >> 5 + i++ + } + unsafe { + buf[26] = 0 + return buf.vstring_with_len(buflen) + } +} + +// string_from_set returns a string of length `len` containing random characters sampled from the given `charset` +pub fn string_from_set(charset string, len int) string { + if len == 0 { + return '' + } + mut buf := unsafe { malloc_noscan(len + 1) } + for i in 0 .. len { + unsafe { + buf[i] = charset[intn(charset.len)] + } + } + unsafe { + buf[len] = 0 + } + return unsafe { buf.vstring_with_len(len) } +} + +// string returns a string of length `len` containing random characters in range `[a-zA-Z]`. +pub fn string(len int) string { + return string_from_set(english_letters, len) +} + +// hex returns a hexadecimal number of length `len` containing random characters in range `[a-f0-9]`. +pub fn hex(len int) string { + return string_from_set(hex_chars, len) +} + +// ascii returns a random string of the printable ASCII characters with length `len`. +pub fn ascii(len int) string { + return string_from_set(ascii_chars, len) +} diff --git a/vlib/rand/rand.v b/vlib/rand/rand.v index e43a7abef4..b88203b5dd 100644 --- a/vlib/rand/rand.v +++ b/vlib/rand/rand.v @@ -5,7 +5,6 @@ module rand import rand.seed import rand.wyrand -import time // PRNGConfigStruct is a configuration struct for creating a new instance of the default RNG. // Note that the RNGs may have a different number of u32s required for seeding. The default @@ -13,7 +12,7 @@ import time // uses a different number of u32s, use the `seed.time_seed_array()` method with the correct // number of u32s. pub struct PRNGConfigStruct { - seed []u32 = seed.time_seed_array(2) + seed_ []u32 = seed.time_seed_array(2) } // PRNG is a common interface for all PRNGs that can be used seamlessly with the rand @@ -55,7 +54,7 @@ fn init() { // 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. pub fn new_default(config PRNGConfigStruct) &PRNG { mut rng := &wyrand.WyRandRNG{} - rng.seed(config.seed) + rng.seed(config.seed_) return rng } @@ -191,127 +190,3 @@ const ( hex_chars = 'abcdef0123456789' ascii_chars = '!"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ\\^_`abcdefghijklmnopqrstuvwxyz{|}~' ) - -// string_from_set returns a string of length `len` containing random characters sampled from the given `charset` -pub fn string_from_set(charset string, len int) string { - if len == 0 { - return '' - } - mut buf := unsafe { malloc_noscan(len + 1) } - for i in 0 .. len { - unsafe { - buf[i] = charset[intn(charset.len)] - } - } - unsafe { - buf[len] = 0 - } - return unsafe { buf.vstring_with_len(len) } -} - -// string returns a string of length `len` containing random characters in range `[a-zA-Z]`. -pub fn string(len int) string { - return string_from_set(rand.english_letters, len) -} - -// hex returns a hexadecimal number of length `len` containing random characters in range `[a-f0-9]`. -pub fn hex(len int) string { - return string_from_set(rand.hex_chars, len) -} - -// ascii returns a random string of the printable ASCII characters with length `len`. -pub fn ascii(len int) string { - return string_from_set(rand.ascii_chars, len) -} - -// uuid_v4 generates a random (v4) UUID -// See https://en.wikipedia.org/wiki/Universally_unique_identifier#Version_4_(random) -pub fn uuid_v4() string { - buflen := 36 - mut buf := unsafe { malloc_noscan(37) } - mut i_buf := 0 - mut x := u64(0) - mut d := byte(0) - for i_buf < buflen { - mut c := 0 - x = default_rng.u64() - // do most of the bit manipulation at once: - x &= 0x0F0F0F0F0F0F0F0F - x += 0x3030303030303030 - // write the ASCII codes to the buffer: - for c < 8 && i_buf < buflen { - d = byte(x) - unsafe { - buf[i_buf] = if d > 0x39 { d + 0x27 } else { d } - } - i_buf++ - c++ - x = x >> 8 - } - } - // there are still some random bits in x: - x = x >> 8 - d = byte(x) - unsafe { - buf[19] = if d > 0x39 { d + 0x27 } else { d } - buf[8] = `-` - buf[13] = `-` - buf[18] = `-` - buf[23] = `-` - buf[14] = `4` - buf[buflen] = 0 - return buf.vstring_with_len(buflen) - } -} - -const ( - ulid_encoding = '0123456789ABCDEFGHJKMNPQRSTVWXYZ' -) - -// ulid generates an Unique Lexicographically sortable IDentifier. -// See https://github.com/ulid/spec . -// NB: ULIDs can leak timing information, if you make them public, because -// you can infer the rate at which some resource is being created, like -// users or business transactions. -// (https://news.ycombinator.com/item?id=14526173) -pub fn ulid() string { - return ulid_at_millisecond(u64(time.utc().unix_time_milli())) -} - -// ulid_at_millisecond does the same as `ulid` but takes a custom Unix millisecond timestamp via `unix_time_milli`. -pub fn ulid_at_millisecond(unix_time_milli u64) string { - buflen := 26 - mut buf := unsafe { malloc_noscan(27) } - mut t := unix_time_milli - mut i := 9 - for i >= 0 { - unsafe { - buf[i] = rand.ulid_encoding[t & 0x1F] - } - t = t >> 5 - i-- - } - // first rand set - mut x := default_rng.u64() - i = 10 - for i < 19 { - unsafe { - buf[i] = rand.ulid_encoding[x & 0x1F] - } - x = x >> 5 - i++ - } - // second rand set - x = default_rng.u64() - for i < 26 { - unsafe { - buf[i] = rand.ulid_encoding[x & 0x1F] - } - x = x >> 5 - i++ - } - unsafe { - buf[26] = 0 - return buf.vstring_with_len(buflen) - } -} diff --git a/vlib/v/gen/js/builtin_types.v b/vlib/v/gen/js/builtin_types.v index 10bfa334c9..4234253d72 100644 --- a/vlib/v/gen/js/builtin_types.v +++ b/vlib/v/gen/js/builtin_types.v @@ -17,7 +17,7 @@ fn (mut g JsGen) to_js_typ_def_val(s string) string { fn (mut g JsGen) to_js_typ_val(t ast.Type) string { sym := g.table.get_type_symbol(t) mut styp := '' - mut prefix := if g.file.mod.name == 'builtin' { 'new ' } else { '' } + mut prefix := if g.file.mod.name == 'builtin' { 'new ' } else { 'new builtin.' } match sym.kind { .i8, .i16, .int, .i64, .byte, .u8, .u16, .u32, .u64, .f32, .f64, .int_literal, .float_literal, .size_t { diff --git a/vlib/v/gen/js/js.v b/vlib/v/gen/js/js.v index b1852ea81d..8e1e388324 100644 --- a/vlib/v/gen/js/js.v +++ b/vlib/v/gen/js/js.v @@ -135,6 +135,7 @@ pub fn gen(files []&ast.File, table &ast.Table, pref &pref.Preferences) string { } g.stmts(file.stmts) + g.writeln('try { init() } catch (_) {}') // store the current namespace g.escape_namespace() } @@ -502,6 +503,24 @@ fn (mut g JsGen) gen_global_decl(node ast.GlobalDecl) { ); // global') } else { // TODO(playXE): Initialize with default value of type + + if field.typ.is_ptr() { + g.writeln('Object.defineProperty(\$global,"$field.name", { + configurable: false, + $mod , + writable: true, + value: new \$ref({}) + } + ); // global') + } else { + g.writeln('Object.defineProperty(\$global,"$field.name", { + configurable: false, + $mod , + writable: true, + value: {} + } + ); // global') + } } } } @@ -961,8 +980,9 @@ fn (mut g JsGen) gen_assign_stmt(stmt ast.AssignStmt) { if should_cast { g.cast_stack << stmt.left_types.first() - if g.file.mod.name == 'builtin' { - g.write('new ') + g.write('new ') + if g.file.mod.name != 'builtin' { + g.write('builtin.') } g.write('${g.typ(stmt.left_types.first())}(') } @@ -1770,13 +1790,15 @@ fn (mut g JsGen) gen_infix_expr(it ast.InfixExpr) { if is_not { g.write('!(') } - is_arithmetic := it.op in [token.Kind.plus, .minus, .mul, .div, .mod] + is_arithmetic := it.op in [token.Kind.plus, .minus, .mul, .div, .mod, .right_shift, .left_shift, + .amp, .pipe, .xor] if is_arithmetic && ((l_sym.kind == .i64 || l_sym.kind == .u64) || (r_sym.kind == .i64 || r_sym.kind == .u64)) { // if left or right is i64 or u64 we convert them to bigint to perform operation. greater_typ := g.greater_typ(it.left_type, it.right_type) - if g.ns.name == 'builtin' { - g.write('new ') + g.write('new ') + if g.ns.name != 'builtin' { + g.write('builtin.') } g.write('${g.typ(greater_typ)}(') g.cast_stack << greater_typ @@ -2125,8 +2147,9 @@ fn (mut g JsGen) gen_type_cast_expr(it ast.CastExpr) { // Skip cast if type is the same as the parrent caster tsym := g.table.get_type_symbol(it.typ) if it.expr is ast.IntegerLiteral && (tsym.kind == .i64 || tsym.kind == .u64) { - if g.ns.name == 'builtin' { - g.write('new ') + g.write('new ') + if g.ns.name != 'builtin' { + g.write('builtin.') } g.write(tsym.kind.str()) g.write('(BigInt(') @@ -2180,13 +2203,17 @@ fn (mut g JsGen) gen_integer_literal_expr(it ast.IntegerLiteral) { // Skip cast if type is the same as the parrent caster if g.cast_stack.len > 0 { if g.cast_stack[g.cast_stack.len - 1] in ast.integer_type_idxs { - g.write('new int($it.val)') + g.write('new ') + if g.ns.name != 'builtin' { + g.write('builtin.') + } + g.write('int($it.val)') return } } - - if g.ns.name == 'builtin' { - g.write('new ') + g.write('new ') + if g.ns.name != 'builtin' { + g.write('builtin.') } g.write('${g.typ(typ)}($it.val)') @@ -2225,9 +2252,9 @@ fn (mut g JsGen) gen_float_literal_expr(it ast.FloatLiteral) { return } } - - if g.ns.name == 'builtin' { - g.write('new ') + g.write('new ') + if g.ns.name != 'builtin' { + g.write('builtin.') } g.write('${g.typ(typ)}($it.val)')