jsgen: fix string and array for loops and improve casting (#9295)
parent
df46fe1373
commit
64d0006ff9
|
@ -1 +1,2 @@
|
|||
*.ppm
|
||||
*.js
|
|
@ -1,6 +1,7 @@
|
|||
module builtin
|
||||
|
||||
pub struct string {
|
||||
pub:
|
||||
str JS.String
|
||||
len u32
|
||||
}
|
||||
|
|
|
@ -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' {
|
||||
|
|
|
@ -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
|
||||
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 is_arithmetic && needs_cast {
|
||||
greater_typ := g.greater_typ(it.left_type, it.right_type)
|
||||
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(')')
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue