From 64d0006ff99ac0a71b80573384e86490b2017865 Mon Sep 17 00:00:00 2001 From: Leah Lundqvist Date: Sun, 14 Mar 2021 07:20:01 +0100 Subject: [PATCH] jsgen: fix string and array for loops and improve casting (#9295) --- examples/.gitignore | 1 + vlib/builtin/js/string.v | 1 + vlib/v/gen/js/builtin_types.v | 16 ++++---- vlib/v/gen/js/js.v | 72 ++++++++++++++++++++--------------- 4 files changed, 52 insertions(+), 38 deletions(-) diff --git a/examples/.gitignore b/examples/.gitignore index 218cb60e9b..8299fd79fd 100644 --- a/examples/.gitignore +++ b/examples/.gitignore @@ -1 +1,2 @@ *.ppm +*.js \ No newline at end of file diff --git a/vlib/builtin/js/string.v b/vlib/builtin/js/string.v index 7602ca5a86..656c6ba80e 100644 --- a/vlib/builtin/js/string.v +++ b/vlib/builtin/js/string.v @@ -1,6 +1,7 @@ module builtin pub struct string { +pub: str JS.String len u32 } diff --git a/vlib/v/gen/js/builtin_types.v b/vlib/v/gen/js/builtin_types.v index 6e8b6c167e..792823be04 100644 --- a/vlib/v/gen/js/builtin_types.v +++ b/vlib/v/gen/js/builtin_types.v @@ -212,13 +212,14 @@ fn (mut g JsGen) struct_typ(s string) string { struct BuiltinPrototypeCongig { typ_name string - val_name string = 'val' + val_name string = 'val' default_value string - constructor string = 'this.val = val' - value_of string = 'this.val' - to_string string = 'this.val.toString()' - eq string = 'this.val === other.val' + constructor string = 'this.val = val' + value_of string = 'this.val' + to_string string = 'this.val.toString()' + eq string = 'this.val === other.val' extras string + has_strfn bool } // ugly arguments but not sure a config struct would be worth it @@ -226,7 +227,7 @@ fn (mut g JsGen) gen_builtin_prototype(c BuiltinPrototypeCongig) { g.writeln('function ${c.typ_name}(${c.val_name} = ${c.default_value}) { ${c.constructor} }') g.writeln('${c.typ_name}.prototype = {') g.inc_indent() - g.writeln('val: ${c.default_value},') + g.writeln('${c.val_name}: ${c.default_value},') if c.extras.len > 0 { g.writeln('${c.extras},') } @@ -239,7 +240,7 @@ fn (mut g JsGen) gen_builtin_prototype(c BuiltinPrototypeCongig) { g.writeln('valueOf() { return ${c.value_of} },') g.writeln('toString() { return ${c.to_string} },') g.writeln('eq(other) { return ${c.eq} },') - g.writeln('str() { return new string(this.toString()) }') + if c.has_strfn { g.writeln('str() { return new string(this.toString()) }') } g.dec_indent() g.writeln('};\n') } @@ -292,6 +293,7 @@ fn (mut g JsGen) gen_builtin_type_defs() { value_of: 'this.str' to_string: 'this.str' eq: 'this.str === other.str' + has_strfn: false }) } 'map' { diff --git a/vlib/v/gen/js/js.v b/vlib/v/gen/js/js.v index 9ebf4ec909..2dc1c0cf0a 100644 --- a/vlib/v/gen/js/js.v +++ b/vlib/v/gen/js/js.v @@ -690,7 +690,9 @@ fn (mut g JsGen) gen_assign_stmt(stmt ast.AssignStmt) { } else { g.write(' $op ') // TODO: Multiple types?? - should_cast := g.table.type_kind(stmt.left_types.first()) in js.shallow_equatables + should_cast := (g.table.type_kind(stmt.left_types.first()) in shallow_equatables) + && (g.cast_stack.len <= 0 || stmt.left_types.first() != g.cast_stack.last()) + if should_cast { g.cast_stack << stmt.left_types.first() if g.file.mod.name == 'builtin' { @@ -920,36 +922,36 @@ fn (mut g JsGen) gen_for_in_stmt(it ast.ForInStmt) { g.writeln('}') } else if it.kind in [.array, .string] || it.cond_type.has_flag(.variadic) { // `for num in nums {` - i := if it.key_var in ['', '_'] { g.new_tmp_var() } else { it.key_var } - val := if it.val_var in ['', '_'] { '' } else { it.val_var } + val := if it.val_var in ['', '_'] { '_' } else { it.val_var } // styp := g.typ(it.val_type) - g.inside_loop = true - g.write('for (let $i = 0; $i < ') - g.expr(it.cond) - g.writeln('.len; ++$i) {') - g.inside_loop = false - if val !in ['', '_'] { - g.write('\tconst $val = ') + if it.key_var.len > 0 { + g.write('for (const [$it.key_var, $val] of ') if it.kind == .string { - if g.file.mod.name == 'builtin' { - g.write('new ') - } - g.write('byte(') - } - g.expr(it.cond) - g.write(if it.kind == .array { - '.arr' - } else if it.kind == .string { - '.str' + g.write('Array.from(') + g.expr(it.cond) + g.write('.str.split(\'\').entries(), ([$it.key_var, $val]) => [$it.key_var, ') + if g.ns.name == 'builtin' { g.write('new ') } + g.write('byte($val)])') } else { - '.val' - }) - g.write('[$i]') - if it.kind == .string { - g.write(')') + g.expr(it.cond) + g.write('.entries()') + } + + } else { + g.write('for (const $val of ') + g.expr(it.cond) + if it.kind == .string { + g.write('.str.split(\'\')') + } + // cast characters to bytes + if val !in ['', '_'] && it.kind == .string { + g.write('.map(c => ') + if g.ns.name == 'builtin' { g.write('new ') } + g.write('byte(c))') + } - g.writeln(';') } + g.writeln(') {') g.stmts(it.stmts) g.writeln('}') } else if it.kind == .map { @@ -1393,7 +1395,9 @@ fn (mut g JsGen) gen_infix_expr(it ast.InfixExpr) { if l_sym.kind in js.shallow_equatables && r_sym.kind in js.shallow_equatables { g.expr(it.left) g.write('.eq(') + g.cast_stack << int(l_sym.kind) g.expr(it.right) + g.cast_stack.delete_last() g.write(')') } else { g.write('vEq(') @@ -1431,10 +1435,16 @@ fn (mut g JsGen) gen_infix_expr(it ast.InfixExpr) { g.write(g.typ(it.right_type)) } else { is_arithmetic := it.op in [token.Kind.plus, .minus, .mul, .div, .mod] - needs_cast := it.left_type != it.right_type - - if is_arithmetic && needs_cast { - greater_typ := g.greater_typ(it.left_type, it.right_type) + mut needs_cast := is_arithmetic && it.left_type != it.right_type + mut greater_typ := 0 + if needs_cast { + greater_typ = g.greater_typ(it.left_type, it.right_type) + if g.cast_stack.len > 0 { + needs_cast = g.cast_stack.last() != greater_typ + } + } + + if needs_cast { if g.ns.name == 'builtin' { g.write('new ') } @@ -1445,7 +1455,7 @@ fn (mut g JsGen) gen_infix_expr(it ast.InfixExpr) { g.write(' $it.op ') g.expr(it.right) - if is_arithmetic && needs_cast { + if needs_cast { g.cast_stack.delete_last() g.write(')') }