js: fix printing, make builtins for result and option types behave correctly (#11336)
parent
f33f216698
commit
a9b705bfd8
|
@ -136,7 +136,7 @@ pub fn (a array) str() string {
|
||||||
}
|
}
|
||||||
|
|
||||||
#array.prototype[Symbol.iterator] = function () { return this.arr[Symbol.iterator](); }
|
#array.prototype[Symbol.iterator] = function () { return this.arr[Symbol.iterator](); }
|
||||||
#array.prototype.entries = function () { return this.arr.entries(); }
|
#array.prototype.entries = function () { let result = []; for (const [key,val] of this.arr.entries()) { result.push([new int(key), val]); } return result[Symbol.iterator](); }
|
||||||
#array.prototype.map = function(callback) { return new builtin.array(this.arr.map(callback)); }
|
#array.prototype.map = function(callback) { return new builtin.array(this.arr.map(callback)); }
|
||||||
#array.prototype.filter = function(callback) { return new array(this.arr.filter( function (it) { return (+callback(it)) != 0; } )); }
|
#array.prototype.filter = function(callback) { return new array(this.arr.filter( function (it) { return (+callback(it)) != 0; } )); }
|
||||||
#Object.defineProperty(array.prototype,'cap',{ get: function () { return this.len; } })
|
#Object.defineProperty(array.prototype,'cap',{ get: function () { return this.len; } })
|
||||||
|
|
|
@ -2,36 +2,36 @@ module builtin
|
||||||
|
|
||||||
// used to generate JS throw statements.
|
// used to generate JS throw statements.
|
||||||
pub fn js_throw(s any) {
|
pub fn js_throw(s any) {
|
||||||
#throw (s instanceof Error ? s : new Error(s))
|
#throw s
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn println(s any) {
|
pub fn println(s string) {
|
||||||
$if js_freestanding {
|
$if js_freestanding {
|
||||||
#print(s.toString())
|
#print(s.str)
|
||||||
} $else {
|
} $else {
|
||||||
#console.log(s.toString())
|
#console.log(s.str)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn print(s any) {
|
pub fn print(s string) {
|
||||||
$if js_node {
|
$if js_node {
|
||||||
#$process.stdout.write(s.toString())
|
#$process.stdout.write(s.str)
|
||||||
} $else {
|
} $else {
|
||||||
panic('Cannot `print` in a browser, use `println` instead')
|
panic('Cannot `print` in a browser, use `println` instead')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn eprintln(s any) {
|
pub fn eprintln(s string) {
|
||||||
$if js_freestanding {
|
$if js_freestanding {
|
||||||
#print(s.toString())
|
#print(s.str)
|
||||||
} $else {
|
} $else {
|
||||||
#console.error(s.toString())
|
#console.error(s.str)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn eprint(s any) {
|
pub fn eprint(s string) {
|
||||||
$if js_node {
|
$if js_node {
|
||||||
#$process.stderr.write(s.toString())
|
#$process.stderr.write(s.str)
|
||||||
} $else {
|
} $else {
|
||||||
panic('Cannot `eprint` in a browser, use `println` instead')
|
panic('Cannot `eprint` in a browser, use `println` instead')
|
||||||
}
|
}
|
||||||
|
@ -50,3 +50,12 @@ fn opt_ok(data voidptr, option Option) {
|
||||||
#option.err = none__
|
#option.err = none__
|
||||||
#option.data = data
|
#option.data = data
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn unwrap(opt string) string {
|
||||||
|
mut o := Option{}
|
||||||
|
#o = opt
|
||||||
|
if o.state != 0 {
|
||||||
|
js_throw(o.err)
|
||||||
|
}
|
||||||
|
return opt
|
||||||
|
}
|
||||||
|
|
|
@ -6,14 +6,6 @@ module builtin
|
||||||
|
|
||||||
fn (a any) toString()
|
fn (a any) toString()
|
||||||
|
|
||||||
pub fn unwrap(opt any) any {
|
|
||||||
o := &Option(opt)
|
|
||||||
if o.state != 0 {
|
|
||||||
js_throw(o.err)
|
|
||||||
}
|
|
||||||
return opt
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn panic(s string) {
|
pub fn panic(s string) {
|
||||||
eprintln('V panic: $s')
|
eprintln('V panic: $s')
|
||||||
exit(1)
|
exit(1)
|
||||||
|
@ -32,13 +24,6 @@ pub:
|
||||||
code int
|
code int
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const none__ = IError(&None__{})
|
|
||||||
|
|
||||||
pub struct Option {
|
|
||||||
state byte
|
|
||||||
err IError = none__
|
|
||||||
}
|
|
||||||
|
|
||||||
struct None__ {
|
struct None__ {
|
||||||
msg string
|
msg string
|
||||||
code int
|
code int
|
||||||
|
@ -48,6 +33,13 @@ fn (_ None__) str() string {
|
||||||
return 'none'
|
return 'none'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub const none__ = IError(None__{'', 0})
|
||||||
|
|
||||||
|
pub struct Option {
|
||||||
|
state byte
|
||||||
|
err IError = none__
|
||||||
|
}
|
||||||
|
|
||||||
pub fn (err IError) str() string {
|
pub fn (err IError) str() string {
|
||||||
return match err {
|
return match err {
|
||||||
None__ { 'none' }
|
None__ { 'none' }
|
||||||
|
|
|
@ -0,0 +1,241 @@
|
||||||
|
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()
|
||||||
|
}
|
|
@ -406,6 +406,12 @@ pub fn (mut g JsGen) init() {
|
||||||
g.definitions.writeln('const \$process = process;')
|
g.definitions.writeln('const \$process = process;')
|
||||||
}
|
}
|
||||||
g.definitions.writeln('function alias(value) { return value; } ')
|
g.definitions.writeln('function alias(value) { return value; } ')
|
||||||
|
|
||||||
|
g.definitions.writeln('function \$v_fmt(value) { let res = "";
|
||||||
|
if (Object.getPrototypeOf(s).hasOwnProperty("str") && typeof s.str == "function") res = s.str().str
|
||||||
|
else res = s.toString()
|
||||||
|
return res
|
||||||
|
} ')
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (g JsGen) hashes() string {
|
pub fn (g JsGen) hashes() string {
|
||||||
|
@ -1323,11 +1329,14 @@ enum FnGenType {
|
||||||
function
|
function
|
||||||
struct_method
|
struct_method
|
||||||
alias_method
|
alias_method
|
||||||
|
iface_method
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (g &JsGen) fn_gen_type(it &ast.FnDecl) FnGenType {
|
fn (g &JsGen) fn_gen_type(it &ast.FnDecl) FnGenType {
|
||||||
if it.is_method && g.table.get_type_symbol(it.params[0].typ).kind == .alias {
|
if it.is_method && g.table.get_type_symbol(it.params[0].typ).kind == .alias {
|
||||||
return .alias_method
|
return .alias_method
|
||||||
|
} else if it.is_method && g.table.get_type_symbol(it.params[0].typ).kind == .interface_ {
|
||||||
|
return .iface_method
|
||||||
} else if it.is_method || it.no_body {
|
} else if it.is_method || it.no_body {
|
||||||
return .struct_method
|
return .struct_method
|
||||||
} else {
|
} else {
|
||||||
|
@ -1366,7 +1375,7 @@ fn (mut g JsGen) gen_method_decl(it ast.FnDecl, typ FnGenType) {
|
||||||
unsafe {
|
unsafe {
|
||||||
g.fn_decl = &it
|
g.fn_decl = &it
|
||||||
}
|
}
|
||||||
if typ == .alias_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))
|
||||||
name := g.js_name(sym.name)
|
name := g.js_name(sym.name)
|
||||||
if name in js.v_types {
|
if name in js.v_types {
|
||||||
|
@ -1443,13 +1452,17 @@ fn (mut g JsGen) gen_method_decl(it ast.FnDecl, typ FnGenType) {
|
||||||
}
|
}
|
||||||
|
|
||||||
g.stmts(it.stmts)
|
g.stmts(it.stmts)
|
||||||
g.write('}')
|
g.writeln('}')
|
||||||
|
|
||||||
if is_main {
|
if is_main {
|
||||||
g.write(')();')
|
g.write(')();')
|
||||||
|
} else if typ != .struct_method {
|
||||||
|
// g.write(';')
|
||||||
}
|
}
|
||||||
if typ == .struct_method || typ == .alias_method {
|
if typ == .struct_method || typ == .alias_method || typ == .iface_method {
|
||||||
g.writeln('\n')
|
g.writeln('\n')
|
||||||
}
|
}
|
||||||
|
|
||||||
g.fn_decl = voidptr(0)
|
g.fn_decl = voidptr(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1620,7 +1633,7 @@ fn (mut g JsGen) gen_interface_decl(it ast.InterfaceDecl) {
|
||||||
// This is a hack to make the interface's type accessible outside its namespace
|
// This is a hack to make the interface's type accessible outside its namespace
|
||||||
// TODO: interfaces are always `pub`?
|
// TODO: interfaces are always `pub`?
|
||||||
name := g.js_name(it.name)
|
name := g.js_name(it.name)
|
||||||
g.push_pub_var('/** @type $name */\n\t\t$name: undefined')
|
g.push_pub_var('/** @type $name */\n\t\t$name')
|
||||||
g.writeln('function ${g.js_name(it.name)} (arg) { return arg; }')
|
g.writeln('function ${g.js_name(it.name)} (arg) { return arg; }')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1828,217 +1841,6 @@ fn (mut g JsGen) gen_array_init_values(exprs []ast.Expr) {
|
||||||
g.write(']')
|
g.write(']')
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// interfaces require dynamic dispatch. To obtain method table we use getPrototypeOf
|
|
||||||
g.write('Object.getPrototypeOf(')
|
|
||||||
g.expr(it.left)
|
|
||||||
mut ltyp := it.left_type
|
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
g.call_stack << it
|
|
||||||
mut name := g.js_name(it.name)
|
|
||||||
ret_sym := g.table.get_type_symbol(it.return_type)
|
|
||||||
if it.language == .js && ret_sym.name in js.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(')
|
|
||||||
}
|
|
||||||
|
|
||||||
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 js.v_types && ret_sym.name != 'void' {
|
|
||||||
g.write(')')
|
|
||||||
}
|
|
||||||
g.call_stack.delete_last()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn (mut g JsGen) gen_ident(node ast.Ident) {
|
fn (mut g JsGen) gen_ident(node ast.Ident) {
|
||||||
mut name := g.js_name(node.name)
|
mut name := g.js_name(node.name)
|
||||||
if node.kind == .blank_ident || name in ['', '_'] {
|
if node.kind == .blank_ident || name in ['', '_'] {
|
||||||
|
@ -2337,8 +2139,17 @@ fn (mut g JsGen) match_expr_sumtype(node ast.MatchExpr, is_expr bool, cond_var M
|
||||||
if sym.kind == .sum_type {
|
if sym.kind == .sum_type {
|
||||||
g.write(' instanceof ')
|
g.write(' instanceof ')
|
||||||
g.expr(branch.exprs[sumtype_index])
|
g.expr(branch.exprs[sumtype_index])
|
||||||
} else {
|
} else if sym.kind == .interface_ {
|
||||||
panic('TODO: Generate match for interfaces')
|
if branch.exprs[sumtype_index] is ast.TypeNode {
|
||||||
|
g.write(' instanceof ')
|
||||||
|
g.expr(branch.exprs[sumtype_index])
|
||||||
|
} else {
|
||||||
|
g.write(' instanceof ')
|
||||||
|
if g.ns.name != 'builtin' {
|
||||||
|
g.write('builtin.')
|
||||||
|
}
|
||||||
|
g.write('None__')
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if is_expr && tmp_var.len == 0 {
|
if is_expr && tmp_var.len == 0 {
|
||||||
g.write(') ? ')
|
g.write(') ? ')
|
||||||
|
|
|
@ -0,0 +1,85 @@
|
||||||
|
module js
|
||||||
|
|
||||||
|
import v.ast
|
||||||
|
|
||||||
|
fn (mut g JsGen) gen_expr_to_string(expr ast.Expr, etype ast.Type) {
|
||||||
|
mut typ := etype
|
||||||
|
if etype.has_flag(.shared_f) {
|
||||||
|
typ = typ.clear_flag(.shared_f).set_nr_muls(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
mut sym := g.table.get_type_symbol(typ)
|
||||||
|
|
||||||
|
if mut sym.info is ast.Alias {
|
||||||
|
parent_sym := g.table.get_type_symbol(sym.info.parent_type)
|
||||||
|
if parent_sym.has_method('str') {
|
||||||
|
typ = sym.info.parent_type
|
||||||
|
sym = parent_sym
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sym_has_str_method, str_method_expects_ptr, _ := sym.str_method_info()
|
||||||
|
if typ.has_flag(.variadic) {
|
||||||
|
// todo(playX): generate str method just like in the C backend
|
||||||
|
g.write('new string(')
|
||||||
|
g.expr(expr)
|
||||||
|
g.write('.valueOf()')
|
||||||
|
g.write('.toString())')
|
||||||
|
} else if typ == ast.string_type {
|
||||||
|
g.expr(expr)
|
||||||
|
} else if typ == ast.bool_type {
|
||||||
|
g.write('new string(')
|
||||||
|
g.expr(expr)
|
||||||
|
g.write('.valueOf() ? "true" : "false")')
|
||||||
|
} else if sym.kind == .none_ {
|
||||||
|
g.write('new string("<none>")')
|
||||||
|
} else if sym.kind == .enum_ {
|
||||||
|
g.write('new string(')
|
||||||
|
if expr !is ast.EnumVal {
|
||||||
|
g.expr(expr)
|
||||||
|
g.write('.valueOf()')
|
||||||
|
g.write('.toString()')
|
||||||
|
} else {
|
||||||
|
g.write('"')
|
||||||
|
g.expr(expr)
|
||||||
|
g.write('"')
|
||||||
|
}
|
||||||
|
g.write(')')
|
||||||
|
} else if sym.kind == .interface_ && sym_has_str_method {
|
||||||
|
is_ptr := typ.is_ptr()
|
||||||
|
g.write(sym.mod.replace_once('${g.ns.name}.', ''))
|
||||||
|
g.write('.')
|
||||||
|
g.write(sym.name)
|
||||||
|
g.write('.prototype.str.call(')
|
||||||
|
g.expr(expr)
|
||||||
|
if !str_method_expects_ptr && is_ptr {
|
||||||
|
g.gen_deref_ptr(typ)
|
||||||
|
}
|
||||||
|
g.write(')')
|
||||||
|
}
|
||||||
|
//|| sym.kind in [.array, .array_fixed, .map, .struct_, .multi_return,.sum_type, .interface_]
|
||||||
|
else if sym_has_str_method {
|
||||||
|
g.write('new string(')
|
||||||
|
g.write('Object.getPrototypeOf(/*str exists*/')
|
||||||
|
g.expr(expr)
|
||||||
|
is_ptr := typ.is_ptr()
|
||||||
|
g.gen_deref_ptr(typ)
|
||||||
|
g.write(').str.call(')
|
||||||
|
g.expr(expr)
|
||||||
|
if !str_method_expects_ptr && is_ptr {
|
||||||
|
g.gen_deref_ptr(typ)
|
||||||
|
}
|
||||||
|
|
||||||
|
g.write('))')
|
||||||
|
} else if sym.kind == .struct_ && !sym_has_str_method {
|
||||||
|
g.write('new string(')
|
||||||
|
g.expr(expr)
|
||||||
|
g.gen_deref_ptr(typ)
|
||||||
|
g.write('.toString())')
|
||||||
|
} else {
|
||||||
|
g.write('new string(')
|
||||||
|
g.expr(expr)
|
||||||
|
g.gen_deref_ptr(typ)
|
||||||
|
g.write('.valueOf().toString())')
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue