diff --git a/vlib/builtin/js/builtin.js.v b/vlib/builtin/js/builtin.js.v index f526966f21..090f60efa6 100644 --- a/vlib/builtin/js/builtin.js.v +++ b/vlib/builtin/js/builtin.js.v @@ -79,3 +79,12 @@ pub fn (r rune) str() string { return sb.str() } + +fn js_stacktrace() string { + stacktrace := '' + #let err = new TypeError(); + #err.name = 'stacktrace: ' + #stacktrace.str = err.stack + + return stacktrace +} diff --git a/vlib/builtin/js/builtin.v b/vlib/builtin/js/builtin.v index 7c82d1ad98..1e27bb53e7 100644 --- a/vlib/builtin/js/builtin.v +++ b/vlib/builtin/js/builtin.v @@ -7,7 +7,7 @@ module builtin fn (a any) toString() pub fn panic(s string) { - eprintln('V panic: $s') + eprintln('V panic: $s\n$js_stacktrace()') exit(1) } diff --git a/vlib/v/gen/js/fn.v b/vlib/v/gen/js/fn.v index cf90b61312..75387d61cc 100644 --- a/vlib/v/gen/js/fn.v +++ b/vlib/v/gen/js/fn.v @@ -130,9 +130,16 @@ fn (mut g JsGen) method_call(node ast.CallExpr) { } if typ_sym.kind == .interface_ && (typ_sym.info as ast.Interface).defines_method(node.name) { - // g.write('${g.js_name(receiver_type_name)}_name_table') - // g.expr(node.left) - g.writeln('/* TODO: Interface call */') + g.expr(it.left) + g.gen_deref_ptr(it.left_type) + g.write('.${it.name}(') + for i, arg in it.args { + g.expr(arg.expr) + if i != it.args.len - 1 { + g.write(', ') + } + } + g.write(')') return } @@ -229,9 +236,9 @@ fn (mut g JsGen) method_call(node ast.CallExpr) { .propagate { panicstr := '`optional not set (\${err})`' if g.file.mod.name == 'main' && g.fn_decl.name == 'main.main' { - g.writeln('return builtin.panic($panicstr)') + g.writeln('return panic($panicstr)') } else { - g.writeln('builtin.js_throw(err)') + g.writeln('js_throw(err)') } } else {} @@ -315,7 +322,7 @@ fn (mut g JsGen) gen_call_expr(it ast.CallExpr) { g.stmt(it.or_block.stmts.last()) } .propagate { - panicstr := '`optional not set (\${err})`' + panicstr := '`optional not set (\${err.val.msg})`' if g.file.mod.name == 'main' && g.fn_decl.name == 'main.main' { g.writeln('return panic($panicstr)') } else { diff --git a/vlib/v/gen/js/js.v b/vlib/v/gen/js/js.v index 469b615c1a..01e2822872 100644 --- a/vlib/v/gen/js/js.v +++ b/vlib/v/gen/js/js.v @@ -156,6 +156,45 @@ pub fn gen(files []&ast.File, table &ast.Table, pref &pref.Preferences) string { if g.pref.is_test { g.gen_js_main_for_tests() } + g.enter_namespace('main') + // generate JS methods for interface methods + for _, iface_types in g.table.iface_types { + for ty in iface_types { + sym := g.table.get_type_symbol(ty) + for method in sym.methods { + p_sym := g.table.get_type_symbol(method.params[0].typ) + mname := g.js_name(p_sym.name) + '_' + method.name + g.write('${g.js_name(sym.name)}.prototype.$method.name = function(') + for i, param in method.params { + if i == 0 { + continue + } + g.write('${g.js_name(param.name)}') + if i != method.params.len - 1 { + g.write(',') + } + } + g.writeln(') {') + g.inc_indent() + g.write('return ${mname}(') + for i, param in method.params { + if i == 0 { + g.write('this') + } else { + g.write('${g.js_name(param.name)}') + } + if i != method.params.len - 1 { + g.write(',') + } + } + g.writeln(')') + g.dec_indent() + g.writeln('}') + } + } + } + g.write('js_main();') + g.escape_namespace() // resolve imports deps_resolved := graph.resolve() nodes := deps_resolved.nodes @@ -178,6 +217,7 @@ pub fn gen(files []&ast.File, table &ast.Table, pref &pref.Preferences) string { out += g.out.str() /* + TODO(playX): Again add support for these doc comments for node in nodes { name := g.js_name(node.name).replace('.', '_') if g.enable_doc { @@ -212,6 +252,7 @@ pub fn gen(files []&ast.File, table &ast.Table, pref &pref.Preferences) string { // public scope out += '\n' }*/ + if g.pref.sourcemap { out += g.create_sourcemap() } @@ -229,7 +270,7 @@ fn (g JsGen) create_sourcemap() string { pub fn (mut g JsGen) gen_js_main_for_tests() { g.enter_namespace('main') - g.writeln('(function() { ') + g.writeln('function js_main() { ') g.inc_indent() all_tfuncs := g.get_all_test_function_names() @@ -256,7 +297,7 @@ pub fn (mut g JsGen) gen_js_main_for_tests() { g.writeln('bt.end_testing();') } g.dec_indent() - g.writeln('})();') + g.writeln('}') g.escape_namespace() } @@ -888,9 +929,13 @@ fn (mut g JsGen) expr(node ast.Expr) { if node.op == .amp { // if !node.right_type.is_pointer() { // kind of weird way to handle references but it allows us to access type methods easily. + /* g.write('(function(x) {') g.write(' return { val: x, __proto__: Object.getPrototypeOf(x), valueOf: function() { return this.val; } }})( ') g.expr(node.right) + g.write(')')*/ + g.write('new \$ref(') + g.expr(node.right) g.write(')') //} else { // g.expr(node.right) @@ -1406,11 +1451,11 @@ fn (mut g JsGen) gen_method_decl(it ast.FnDecl, typ FnGenType) { // there is no concept of main in JS but we do have iife g.writeln('/* program entry point */') - g.write('(') + // g.write('(') if has_go { g.write('async ') } - g.write('function(') + g.write('function js_main(') } else if it.is_anon { g.write('function (') } else { @@ -1451,9 +1496,18 @@ fn (mut g JsGen) gen_method_decl(it ast.FnDecl, typ FnGenType) { g.writeln('}') if is_main { - g.write(')();') + // g.write(')') } g.writeln('') + + for attr in it.attrs { + match attr.name { + 'export' { + g.writeln('globalThis.$attr.arg = ${g.js_name(it.name)};') + } + else {} + } + } /* if typ == .alias_method || typ == .iface_method { sym := g.table.get_final_type_symbol(it.params[0].typ.set_nr_muls(0)) @@ -1733,7 +1787,7 @@ fn (mut g JsGen) gen_return_stmt(it ast.Return) { fn_return_is_optional := g.fn_decl.return_type.has_flag(.optional) if node.exprs.len == 0 { if fn_return_is_optional { - g.writeln('return {}') + g.writeln('return {state: new int(0)}') } else { g.writeln('return;') }