v.gen.js: Interfaces support, fix for error propagation & panic stacktraces (#11471)
parent
90e04d03b2
commit
5b619b99c2
|
@ -79,3 +79,12 @@ pub fn (r rune) str() string {
|
||||||
|
|
||||||
return sb.str()
|
return sb.str()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn js_stacktrace() string {
|
||||||
|
stacktrace := ''
|
||||||
|
#let err = new TypeError();
|
||||||
|
#err.name = 'stacktrace: '
|
||||||
|
#stacktrace.str = err.stack
|
||||||
|
|
||||||
|
return stacktrace
|
||||||
|
}
|
||||||
|
|
|
@ -7,7 +7,7 @@ module builtin
|
||||||
fn (a any) toString()
|
fn (a any) toString()
|
||||||
|
|
||||||
pub fn panic(s string) {
|
pub fn panic(s string) {
|
||||||
eprintln('V panic: $s')
|
eprintln('V panic: $s\n$js_stacktrace()')
|
||||||
exit(1)
|
exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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) {
|
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(it.left)
|
||||||
// g.expr(node.left)
|
g.gen_deref_ptr(it.left_type)
|
||||||
g.writeln('/* TODO: Interface call */')
|
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
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -229,9 +236,9 @@ fn (mut g JsGen) method_call(node ast.CallExpr) {
|
||||||
.propagate {
|
.propagate {
|
||||||
panicstr := '`optional not set (\${err})`'
|
panicstr := '`optional not set (\${err})`'
|
||||||
if g.file.mod.name == 'main' && g.fn_decl.name == 'main.main' {
|
if g.file.mod.name == 'main' && g.fn_decl.name == 'main.main' {
|
||||||
g.writeln('return builtin.panic($panicstr)')
|
g.writeln('return panic($panicstr)')
|
||||||
} else {
|
} else {
|
||||||
g.writeln('builtin.js_throw(err)')
|
g.writeln('js_throw(err)')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {}
|
else {}
|
||||||
|
@ -315,7 +322,7 @@ fn (mut g JsGen) gen_call_expr(it ast.CallExpr) {
|
||||||
g.stmt(it.or_block.stmts.last())
|
g.stmt(it.or_block.stmts.last())
|
||||||
}
|
}
|
||||||
.propagate {
|
.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' {
|
if g.file.mod.name == 'main' && g.fn_decl.name == 'main.main' {
|
||||||
g.writeln('return panic($panicstr)')
|
g.writeln('return panic($panicstr)')
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -156,6 +156,45 @@ pub fn gen(files []&ast.File, table &ast.Table, pref &pref.Preferences) string {
|
||||||
if g.pref.is_test {
|
if g.pref.is_test {
|
||||||
g.gen_js_main_for_tests()
|
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
|
// resolve imports
|
||||||
deps_resolved := graph.resolve()
|
deps_resolved := graph.resolve()
|
||||||
nodes := deps_resolved.nodes
|
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()
|
out += g.out.str()
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
TODO(playX): Again add support for these doc comments
|
||||||
for node in nodes {
|
for node in nodes {
|
||||||
name := g.js_name(node.name).replace('.', '_')
|
name := g.js_name(node.name).replace('.', '_')
|
||||||
if g.enable_doc {
|
if g.enable_doc {
|
||||||
|
@ -212,6 +252,7 @@ pub fn gen(files []&ast.File, table &ast.Table, pref &pref.Preferences) string {
|
||||||
// public scope
|
// public scope
|
||||||
out += '\n'
|
out += '\n'
|
||||||
}*/
|
}*/
|
||||||
|
|
||||||
if g.pref.sourcemap {
|
if g.pref.sourcemap {
|
||||||
out += g.create_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() {
|
pub fn (mut g JsGen) gen_js_main_for_tests() {
|
||||||
g.enter_namespace('main')
|
g.enter_namespace('main')
|
||||||
g.writeln('(function() { ')
|
g.writeln('function js_main() { ')
|
||||||
g.inc_indent()
|
g.inc_indent()
|
||||||
all_tfuncs := g.get_all_test_function_names()
|
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.writeln('bt.end_testing();')
|
||||||
}
|
}
|
||||||
g.dec_indent()
|
g.dec_indent()
|
||||||
g.writeln('})();')
|
g.writeln('}')
|
||||||
g.escape_namespace()
|
g.escape_namespace()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -888,9 +929,13 @@ fn (mut g JsGen) expr(node ast.Expr) {
|
||||||
if node.op == .amp {
|
if node.op == .amp {
|
||||||
// if !node.right_type.is_pointer() {
|
// if !node.right_type.is_pointer() {
|
||||||
// kind of weird way to handle references but it allows us to access type methods easily.
|
// kind of weird way to handle references but it allows us to access type methods easily.
|
||||||
|
/*
|
||||||
g.write('(function(x) {')
|
g.write('(function(x) {')
|
||||||
g.write(' return { val: x, __proto__: Object.getPrototypeOf(x), valueOf: function() { return this.val; } }})( ')
|
g.write(' return { val: x, __proto__: Object.getPrototypeOf(x), valueOf: function() { return this.val; } }})( ')
|
||||||
g.expr(node.right)
|
g.expr(node.right)
|
||||||
|
g.write(')')*/
|
||||||
|
g.write('new \$ref(')
|
||||||
|
g.expr(node.right)
|
||||||
g.write(')')
|
g.write(')')
|
||||||
//} else {
|
//} else {
|
||||||
// g.expr(node.right)
|
// 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
|
// there is no concept of main in JS but we do have iife
|
||||||
g.writeln('/* program entry point */')
|
g.writeln('/* program entry point */')
|
||||||
|
|
||||||
g.write('(')
|
// g.write('(')
|
||||||
if has_go {
|
if has_go {
|
||||||
g.write('async ')
|
g.write('async ')
|
||||||
}
|
}
|
||||||
g.write('function(')
|
g.write('function js_main(')
|
||||||
} else if it.is_anon {
|
} else if it.is_anon {
|
||||||
g.write('function (')
|
g.write('function (')
|
||||||
} else {
|
} else {
|
||||||
|
@ -1451,9 +1496,18 @@ fn (mut g JsGen) gen_method_decl(it ast.FnDecl, typ FnGenType) {
|
||||||
g.writeln('}')
|
g.writeln('}')
|
||||||
|
|
||||||
if is_main {
|
if is_main {
|
||||||
g.write(')();')
|
// g.write(')')
|
||||||
}
|
}
|
||||||
g.writeln('')
|
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 {
|
if typ == .alias_method || typ == .iface_method {
|
||||||
sym := g.table.get_final_type_symbol(it.params[0].typ.set_nr_muls(0))
|
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)
|
fn_return_is_optional := g.fn_decl.return_type.has_flag(.optional)
|
||||||
if node.exprs.len == 0 {
|
if node.exprs.len == 0 {
|
||||||
if fn_return_is_optional {
|
if fn_return_is_optional {
|
||||||
g.writeln('return {}')
|
g.writeln('return {state: new int(0)}')
|
||||||
} else {
|
} else {
|
||||||
g.writeln('return;')
|
g.writeln('return;')
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue