js: fix `rand` build, properly use key values on map, add `rand.string` (#12020)

pull/12037/head
playX 2021-10-01 21:23:49 +03:00 committed by GitHub
parent 60ecbec8ea
commit 82f187e5e0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 186 additions and 39 deletions

View File

@ -1331,8 +1331,8 @@ fn test_struct_array_of_multi_type_in() {
}, },
] ]
println(ivan in people) println(ivan in people)
println('TODO: Map eq') // println('TODO: Map eq')
// assert ivan in people assert ivan in people
} }
fn test_struct_array_of_multi_type_index() { fn test_struct_array_of_multi_type_index() {

View File

@ -2,6 +2,7 @@ module builtin
struct map { struct map {
m JS.Map m JS.Map
pub:
len int len int
} }
@ -14,7 +15,7 @@ pub fn (mut m map) delete(key voidptr) {
pub fn (m &map) free() {} pub fn (m &map) free() {}
#map.prototype[Symbol.iterator] = function () { return this.map[Symbol.iterator](); } #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 () { #map.prototype.toString = function () {
#function fmtKey(key) { return typeof key == 'string' ? '\'' + key + '\'' : key} #function fmtKey(key) { return typeof key == 'string' ? '\'' + key + '\'' : key}
#let res = '{' #let res = '{'

View File

@ -125,3 +125,16 @@ pub fn hex(len int) string {
pub fn ascii(len int) string { pub fn ascii(len int) string {
return string_from_set(ascii_chars, len) 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)
}

View File

@ -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
}

View File

@ -38,19 +38,6 @@ __global (
default_rng &PRNG 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. // 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] [manualfree]
pub fn new_default(config config.PRNGConfigStruct) &PRNG { pub fn new_default(config config.PRNGConfigStruct) &PRNG {

View File

@ -0,0 +1,7 @@
import rand
fn test_string() {
res := rand.string(4)
assert res.len == 4
println(res)
}

View File

@ -0,0 +1,3 @@
module wyrand
pub fn (mut r WyRandRNG) free() {}

View File

@ -250,9 +250,3 @@ pub fn (mut rng WyRandRNG) f64_in_range(min f64, max f64) f64 {
} }
return min + rng.f64n(max - min) 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) }
}

View File

@ -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) }
}

View File

@ -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('\tstrings__Builder_write_string(sb, new string("{"));')
g.definitions.writeln('\tlet i = 0;') g.definitions.writeln('\tlet i = 0;')
g.definitions.writeln('\tfor (let [key,value] of m.map) {') g.definitions.writeln('\tfor (let [key,value] of m.map) {')
g.definitions.writeln('\t\tkey = new ${key_styp}(key);')
if key_sym.kind == .string { 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 { } else if key_sym.kind == .rune {
// tmp_str := str_intp_rune('${key_str_fn_name}(key)') // tmp_str := str_intp_rune('${key_str_fn_name}(key)')
// g.definitions.writeln('\t\tstrings__Builder_write_string(sb, $tmp_str);') // g.definitions.writeln('\t\tstrings__Builder_write_string(sb, $tmp_str);')

View File

@ -300,11 +300,6 @@ fn (mut g JsGen) gen_builtin_prototype(c BuiltinPrototypeConfig) {
g.dec_indent() g.dec_indent()
g.writeln('};\n') g.writeln('};\n')
g.writeln('function ${c.typ_name}__eq(self,other) { return $c.eq; } ') 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. // generate builtin type definitions, used for casting and methods.

View File

@ -294,11 +294,13 @@ fn (mut g JsGen) infix_in_not_in_op(node ast.InfixExpr) {
g.gen_deref_ptr(node.right_type) g.gen_deref_ptr(node.right_type)
g.write('.map.has(') g.write('.map.has(')
g.expr(node.left) g.expr(node.left)
/*
if l_sym.sym.kind == .string { if l_sym.sym.kind == .string {
g.write('.str') g.write('.str')
} else { } else {
g.write('.valueOf()') g.write('.valueOf()')
} }*/
g.write('.\$toJS()')
g.write(')') g.write(')')
} else { } else {
g.write('.str.includes(') g.write('.str.includes(')

View File

@ -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.write('js_main();')
g.escape_namespace() g.escape_namespace()
// resolve imports // resolve imports
@ -207,6 +219,7 @@ pub fn gen(files []&ast.File, table &ast.Table, pref &pref.Preferences) string {
nodes := deps_resolved.nodes nodes := deps_resolved.nodes
mut out := g.definitions.str() + g.hashes() mut out := g.definitions.str() + g.hashes()
// equality check for js objects // equality check for js objects
// TODO: Fix msvc bug that's preventing $embed_file('fast_deep_equal.js') // TODO: Fix msvc bug that's preventing $embed_file('fast_deep_equal.js')
// unsafe { // 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 += 'if (typeof module === "object" && module.exports) module.exports = $export;\n'
} }
out += '\n' out += '\n'
out += g.out.str()
out += g.out.str()
/* /*
TODO(playX): Again add support for these doc comments TODO(playX): Again add support for these doc comments
for node in nodes { for node in nodes {
@ -876,12 +889,18 @@ fn (mut g JsGen) expr(node ast.Expr) {
g.write(')') g.write(')')
} }
ast.PostfixExpr { ast.PostfixExpr {
// match node.expr {
// ast.IndexExpr {
// g.gen_postfix_index_expr(node.expr,node.op)
// } else {
g.expr(node.expr) g.expr(node.expr)
if node.op in [.inc, .dec] { if node.op in [.inc, .dec] {
g.write('.val $node.op') g.write('.val $node.op')
} else { } else {
g.write(node.op.str()) g.write(node.op.str())
} }
// }
// }
} }
ast.PrefixExpr { ast.PrefixExpr {
if node.op in [.amp, .mul] { 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 array_set := false
mut map_set := false
match left { match left {
ast.IndexExpr { ast.IndexExpr {
g.expr(left.left) g.expr(left.left)
@ -1133,11 +1153,17 @@ fn (mut g JsGen) gen_assign_stmt(stmt ast.AssignStmt, semicolon bool) {
g.write('.valueOf()') g.write('.valueOf()')
} }
array_set = true array_set = true
if g.table.get_type_symbol(left.left_type).kind == .map { if g.table.get_type_symbol(left.left_type).kind == .map {
g.write('.map.set(') g.write('.map.set(')
map_set = true
} else { } else {
g.write('.arr.set(') g.write('.arr.set(')
} }
if map_set {
g.expr(left.index)
g.write('.\$toJS(),')
} else {
g.write('new int(') g.write('new int(')
g.cast_stack << ast.int_type_idx g.cast_stack << ast.int_type_idx
g.expr(left.index) g.expr(left.index)
@ -1145,6 +1171,7 @@ fn (mut g JsGen) gen_assign_stmt(stmt ast.AssignStmt, semicolon bool) {
g.cast_stack.delete_last() g.cast_stack.delete_last()
g.write('),') g.write('),')
} }
}
else { else {
g.expr(left) g.expr(left)
} }
@ -2308,6 +2335,7 @@ fn (mut g JsGen) gen_index_expr(expr ast.IndexExpr) {
g.write(')') g.write(')')
} else if left_typ.kind == .map { } else if left_typ.kind == .map {
g.expr(expr.left) g.expr(expr.left)
if expr.is_setter { if expr.is_setter {
g.inside_map_set = true g.inside_map_set = true
g.write('.map.set(') g.write('.map.set(')
@ -2315,7 +2343,7 @@ fn (mut g JsGen) gen_index_expr(expr ast.IndexExpr) {
g.write('.map.get(') g.write('.map.get(')
} }
g.expr(expr.index) g.expr(expr.index)
g.write('.toString()') g.write('.\$toJS()')
if !expr.is_setter { if !expr.is_setter {
g.write(')') g.write(')')
} }
@ -2632,6 +2660,7 @@ fn (mut g JsGen) gen_map_init_expr(it ast.MapInit) {
val := it.vals[i] val := it.vals[i]
g.write('[') g.write('[')
g.expr(key) g.expr(key)
g.write('.\$toJS()')
g.write(', ') g.write(', ')
g.expr(val) g.expr(val)
g.write(']') g.write(']')
@ -2950,3 +2979,95 @@ fn replace_op(s string) string {
else { '' } 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('))')
}
}
}