v/vlib/v/gen/js/fn.v

242 lines
5.0 KiB
V

module js
import v.ast
fn (mut g JsGen) gen_method_call(it ast.CallExpr) bool {
g.call_stack << it
mut name := g.js_name(it.name)
call_return_is_optional := it.return_type.has_flag(.optional)
if call_return_is_optional {
g.writeln('(function(){')
g.inc_indent()
g.writeln('try {')
g.inc_indent()
g.write('return builtin.unwrap(')
}
sym := g.table.get_type_symbol(it.receiver_type)
if sym.kind == .array {
if sym.kind == .array && it.name in ['map', 'filter'] {
g.expr(it.left)
mut ltyp := it.left_type
for ltyp.is_ptr() {
g.write('.val')
ltyp = ltyp.deref()
}
g.write('.')
// Prevent 'it' from getting shadowed inside the match
node := it
g.write(it.name)
g.write('(')
expr := node.args[0].expr
match expr {
ast.AnonFn {
g.gen_fn_decl(expr.decl)
g.write(')')
return true
}
ast.Ident {
if expr.kind == .function {
g.write(g.js_name(expr.name))
g.write(')')
return true
} else if expr.kind == .variable {
v_sym := g.table.get_type_symbol(expr.var_info().typ)
if v_sym.kind == .function {
g.write(g.js_name(expr.name))
g.write(')')
return true
}
}
}
else {}
}
g.write('it => ')
g.expr(node.args[0].expr)
g.write(')')
return true
}
left_sym := g.table.get_type_symbol(it.left_type)
if left_sym.kind == .array {
if it.name in special_array_methods {
g.expr(it.left)
mut ltyp := it.left_type
for ltyp.is_ptr() {
g.write('.val')
ltyp = ltyp.deref()
}
g.write('.')
g.gen_array_method_call(it)
return true
}
}
}
mut ltyp := it.left_type
mut lsym := g.table.get_type_symbol(ltyp)
if lsym.kind == .interface_ {
g.write(g.js_name(lsym.name))
g.write('.${name}.call(')
g.expr(it.left)
g.write(',')
for i, arg in it.args {
g.expr(arg.expr)
if i != it.args.len - 1 {
g.write(', ')
}
}
// end method call
g.write(')')
} else {
g.write('Object.getPrototypeOf(')
g.expr(it.left)
for ltyp.is_ptr() {
g.write('.val')
ltyp = ltyp.deref()
}
g.write(').$name .call(')
g.expr(it.left)
g.write(',')
for i, arg in it.args {
g.expr(arg.expr)
if i != it.args.len - 1 {
g.write(', ')
}
}
// end method call
g.write(')')
}
if call_return_is_optional {
// end unwrap
g.writeln(')')
g.dec_indent()
// begin catch block
g.writeln('} catch(err) {')
g.inc_indent()
// gen or block contents
match it.or_block.kind {
.block {
if it.or_block.stmts.len > 1 {
g.stmts(it.or_block.stmts[..it.or_block.stmts.len - 1])
}
// g.write('return ')
g.stmt(it.or_block.stmts.last())
}
.propagate {
panicstr := '`optional not set (\${err})`'
if g.file.mod.name == 'main' && g.fn_decl.name == 'main.main' {
g.writeln('return builtin.panic($panicstr)')
} else {
g.writeln('builtin.js_throw(err)')
}
}
else {}
}
// end catch
g.dec_indent()
g.writeln('}')
// end anon fn
g.dec_indent()
g.write('})()')
}
g.call_stack.delete_last()
return true
}
fn (mut g JsGen) gen_call_expr(it ast.CallExpr) {
if it.is_method {
if g.gen_method_call(it) {
return
}
}
node := it
g.call_stack << it
mut name := g.js_name(it.name)
is_print := name in ['print', 'println', 'eprint', 'eprintln', 'panic']
print_method := name
ret_sym := g.table.get_type_symbol(it.return_type)
if it.language == .js && ret_sym.name in v_types && ret_sym.name != 'void' {
g.write('new ')
if g.ns.name != 'builtin' {
g.write('builtin.')
}
g.write(ret_sym.name)
g.write('(')
}
call_return_is_optional := it.return_type.has_flag(.optional)
if call_return_is_optional {
g.writeln('(function(){')
g.inc_indent()
g.writeln('try {')
g.inc_indent()
g.write('return builtin.unwrap(')
}
if is_print {
mut typ := node.args[0].typ
expr := node.args[0].expr
g.write('builtin.$print_method (')
g.gen_expr_to_string(expr, typ)
g.write(')')
return
}
g.expr(it.left)
if name in g.builtin_fns {
g.write('builtin.')
}
g.write('${name}(')
for i, arg in it.args {
g.expr(arg.expr)
if i != it.args.len - 1 {
g.write(', ')
}
}
// end method call
g.write(')')
if call_return_is_optional {
// end unwrap
g.writeln(')')
g.dec_indent()
// begin catch block
g.writeln('} catch(err) {')
g.inc_indent()
// gen or block contents
match it.or_block.kind {
.block {
if it.or_block.stmts.len > 1 {
g.stmts(it.or_block.stmts[..it.or_block.stmts.len - 1])
}
// g.write('return ')
g.stmt(it.or_block.stmts.last())
}
.propagate {
panicstr := '`optional not set (\${err})`'
if g.file.mod.name == 'main' && g.fn_decl.name == 'main.main' {
g.writeln('return builtin.panic($panicstr)')
} else {
g.writeln('builtin.js_throw(err)')
}
}
else {}
}
// end catch
g.dec_indent()
g.writeln('}')
// end anon fn
g.dec_indent()
g.write('})()')
}
if it.language == .js && ret_sym.name in v_types && ret_sym.name != 'void' {
g.write(')')
}
g.call_stack.delete_last()
}