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.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.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; } }) | ||||
|  |  | |||
|  | @ -2,36 +2,36 @@ module builtin | |||
| 
 | ||||
| // used to generate JS throw statements.
 | ||||
| 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 { | ||||
| 		#print(s.toString()) | ||||
| 		#print(s.str) | ||||
| 	} $else { | ||||
| 		#console.log(s.toString()) | ||||
| 		#console.log(s.str) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| pub fn print(s any) { | ||||
| pub fn print(s string) { | ||||
| 	$if js_node { | ||||
| 		#$process.stdout.write(s.toString()) | ||||
| 		#$process.stdout.write(s.str) | ||||
| 	} $else { | ||||
| 		panic('Cannot `print` in a browser, use `println` instead') | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| pub fn eprintln(s any) { | ||||
| pub fn eprintln(s string) { | ||||
| 	$if js_freestanding { | ||||
| 		#print(s.toString()) | ||||
| 		#print(s.str) | ||||
| 	} $else { | ||||
| 		#console.error(s.toString()) | ||||
| 		#console.error(s.str) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| pub fn eprint(s any) { | ||||
| pub fn eprint(s string) { | ||||
| 	$if js_node { | ||||
| 		#$process.stderr.write(s.toString()) | ||||
| 		#$process.stderr.write(s.str) | ||||
| 	} $else { | ||||
| 		panic('Cannot `eprint` in a browser, use `println` instead') | ||||
| 	} | ||||
|  | @ -50,3 +50,12 @@ fn opt_ok(data voidptr, option Option) { | |||
| 	#option.err = none__ | ||||
| 	#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() | ||||
| 
 | ||||
| pub fn unwrap(opt any) any { | ||||
| 	o := &Option(opt) | ||||
| 	if o.state != 0 { | ||||
| 		js_throw(o.err) | ||||
| 	} | ||||
| 	return opt | ||||
| } | ||||
| 
 | ||||
| pub fn panic(s string) { | ||||
| 	eprintln('V panic: $s') | ||||
| 	exit(1) | ||||
|  | @ -32,13 +24,6 @@ pub: | |||
| 	code int | ||||
| } | ||||
| 
 | ||||
| pub const none__ = IError(&None__{}) | ||||
| 
 | ||||
| pub struct Option { | ||||
| 	state byte | ||||
| 	err   IError = none__ | ||||
| } | ||||
| 
 | ||||
| struct None__ { | ||||
| 	msg  string | ||||
| 	code int | ||||
|  | @ -48,6 +33,13 @@ fn (_ None__) str() string { | |||
| 	return 'none' | ||||
| } | ||||
| 
 | ||||
| pub const none__ = IError(None__{'', 0}) | ||||
| 
 | ||||
| pub struct Option { | ||||
| 	state byte | ||||
| 	err   IError = none__ | ||||
| } | ||||
| 
 | ||||
| pub fn (err IError) str() string { | ||||
| 	return match err { | ||||
| 		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('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 { | ||||
|  | @ -1323,11 +1329,14 @@ enum FnGenType { | |||
| 	function | ||||
| 	struct_method | ||||
| 	alias_method | ||||
| 	iface_method | ||||
| } | ||||
| 
 | ||||
| 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 { | ||||
| 		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 { | ||||
| 		return .struct_method | ||||
| 	} else { | ||||
|  | @ -1366,7 +1375,7 @@ fn (mut g JsGen) gen_method_decl(it ast.FnDecl, typ FnGenType) { | |||
| 	unsafe { | ||||
| 		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)) | ||||
| 		name := g.js_name(sym.name) | ||||
| 		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.write('}') | ||||
| 	g.writeln('}') | ||||
| 
 | ||||
| 	if is_main { | ||||
| 		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.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
 | ||||
| 	// TODO: interfaces are always `pub`?
 | ||||
| 	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; }') | ||||
| } | ||||
| 
 | ||||
|  | @ -1828,217 +1841,6 @@ fn (mut g JsGen) gen_array_init_values(exprs []ast.Expr) { | |||
| 	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) { | ||||
| 	mut name := g.js_name(node.name) | ||||
| 	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 { | ||||
| 					g.write(' instanceof ') | ||||
| 					g.expr(branch.exprs[sumtype_index]) | ||||
| 				} else if sym.kind == .interface_ { | ||||
| 					if branch.exprs[sumtype_index] is ast.TypeNode { | ||||
| 						g.write(' instanceof ') | ||||
| 						g.expr(branch.exprs[sumtype_index]) | ||||
| 					} else { | ||||
| 					panic('TODO: Generate match for interfaces') | ||||
| 						g.write(' instanceof ') | ||||
| 						if g.ns.name != 'builtin' { | ||||
| 							g.write('builtin.') | ||||
| 						} | ||||
| 						g.write('None__') | ||||
| 					} | ||||
| 				} | ||||
| 				if is_expr && tmp_var.len == 0 { | ||||
| 					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