js: copy variables passed to closures (#12328)
							parent
							
								
									0e95e4d7b4
								
							
						
					
					
						commit
						fa02418a55
					
				|  | @ -221,7 +221,7 @@ fn (mut g JsGen) gen_str_for_option(typ ast.Type, styp string, str_fn_name strin | |||
| 	g.definitions.writeln('function ${str_fn_name}(it) { return indent_${str_fn_name}(it, 0); }') | ||||
| 	g.definitions.writeln('function indent_${str_fn_name}(it, indent_count) {') | ||||
| 	g.definitions.writeln('\tlet res;') | ||||
| 	g.definitions.writeln('\tif (it.state == 0) {') | ||||
| 	g.definitions.writeln('\tif (it.state.val == 0) {') | ||||
| 	if sym.kind == .string { | ||||
| 		tmp_res := '${parent_str_fn_name}(it.data)' | ||||
| 		g.definitions.writeln('\t\tres = ${str_intp_sq(tmp_res)};') | ||||
|  | @ -281,7 +281,7 @@ fn (mut g JsGen) gen_str_for_multi_return(info ast.MultiReturn, styp string, str | |||
| 		} else { | ||||
| 			deref, deref_label := deref_kind(str_method_expects_ptr, is_arg_ptr, typ) | ||||
| 			fn_builder.writeln('\t\tstrings__Builder_write_string(sb, new string("$deref_label"));') | ||||
| 			fn_builder.writeln('\tstrings__Builder_write_string(sb, ${arg_str_fn_name}( $deref a[$i]));') | ||||
| 			fn_builder.writeln('\tstrings__Builder_write_string(sb, ${arg_str_fn_name}( a[$i] $deref ));') | ||||
| 		} | ||||
| 		if i != info.types.len - 1 { | ||||
| 			fn_builder.writeln('\tstrings__Builder_write_string(sb, new string(", "));') | ||||
|  | @ -385,6 +385,26 @@ fn (mut g JsGen) gen_str_for_interface(info ast.Interface, styp string, str_fn_n | |||
| } | ||||
| 
 | ||||
| fn (mut g JsGen) gen_str_for_union_sum_type(info ast.SumType, styp string, str_fn_name string) { | ||||
| 	g.definitions.writeln('function ${str_fn_name}(x) { return indent_${str_fn_name}(x, 0); }') | ||||
| 	mut fn_builder := strings.new_builder(512) | ||||
| 	fn_builder.writeln('function indent_${str_fn_name}(x, indent_count) {') | ||||
| 	for typ in info.variants { | ||||
| 		typ_str := g.typ(typ) | ||||
| 		mut func_name := g.get_str_fn(typ) | ||||
| 		sym := g.table.get_type_symbol(typ) | ||||
| 		sym_has_str_method, str_method_expects_ptr, _ := sym.str_method_info() | ||||
| 		deref := if sym_has_str_method && str_method_expects_ptr { | ||||
| 			' ' | ||||
| 		} else { | ||||
| 			if typ.is_ptr() { '.valueOf()' } else { ' ' } | ||||
| 		} | ||||
| 		if should_use_indent_func(sym.kind) && !sym_has_str_method { | ||||
| 			func_name = 'indent_$func_name' | ||||
| 		} | ||||
| 		fn_builder.writeln('if (x instanceof $typ_str) { return ${func_name}(x$deref); }') | ||||
| 	} | ||||
| 	fn_builder.writeln('builtin__panic(new string("unknown sum type value"));\n}') | ||||
| 	g.definitions.writeln(fn_builder.str()) | ||||
| } | ||||
| 
 | ||||
| fn (mut g JsGen) fn_decl_str(info ast.FnType) string { | ||||
|  |  | |||
|  | @ -14,6 +14,13 @@ fn (mut g JsGen) to_js_typ_def_val(s string) string { | |||
| 	return dval | ||||
| } | ||||
| 
 | ||||
| fn (mut g JsGen) copy_val(t ast.Type, tmp string) string { | ||||
| 	fun := g.get_copy_fn(t) | ||||
| 	temp := g.new_tmp_var() | ||||
| 	g.writeln('let $temp = ${fun}($tmp);') | ||||
| 	return temp | ||||
| } | ||||
| 
 | ||||
| fn (mut g JsGen) to_js_typ_val(t ast.Type) string { | ||||
| 	sym := g.table.get_type_symbol(t) | ||||
| 	mut styp := '' | ||||
|  |  | |||
|  | @ -0,0 +1,227 @@ | |||
| module js | ||||
| 
 | ||||
| import v.ast | ||||
| import strings | ||||
| import v.util | ||||
| 
 | ||||
| [inline] | ||||
| fn styp_to_copy_fn_name(styp string) string { | ||||
| 	return styp.replace_each(['*', '', '.', '__', ' ', '__']) + '_\$copy' | ||||
| } | ||||
| 
 | ||||
| fn (mut g JsGen) get_copy_fn(typ ast.Type) string { | ||||
| 	mut unwrapped := g.unwrap_generic(typ).set_nr_muls(0).clear_flag(.variadic) | ||||
| 	if g.pref.nofloat { | ||||
| 		if typ == ast.f32_type { | ||||
| 			unwrapped = ast.u32_type | ||||
| 		} else if typ == ast.f64_type { | ||||
| 			unwrapped = ast.u64_type | ||||
| 		} | ||||
| 	} | ||||
| 	if typ.has_flag(.optional) { | ||||
| 		unwrapped.set_flag(.optional) | ||||
| 	} | ||||
| 	styp := g.typ(unwrapped) | ||||
| 	mut sym := g.table.get_type_symbol(unwrapped) | ||||
| 	mut copy_fn_name := styp_to_copy_fn_name(styp) | ||||
| 	if mut sym.info is ast.Alias { | ||||
| 		if sym.info.is_import { | ||||
| 			sym = g.table.get_type_symbol(sym.info.parent_type) | ||||
| 			copy_fn_name = styp_to_copy_fn_name(sym.name) | ||||
| 		} | ||||
| 	} | ||||
| 	g.copy_types << StrType{ | ||||
| 		typ: unwrapped | ||||
| 		styp: styp | ||||
| 	} | ||||
| 	return copy_fn_name | ||||
| } | ||||
| 
 | ||||
| fn (mut g JsGen) gen_copy_for_option(typ ast.Type, styp string, copy_fn_name string) { | ||||
| 	g.definitions.writeln('function ${copy_fn_name}(it) { return it; }') | ||||
| } | ||||
| 
 | ||||
| fn (mut g JsGen) gen_copy_for_alias(info ast.Alias, styp string, copy_fn_name string) { | ||||
| 	parent_copy_fn_name := g.get_str_fn(info.parent_type) | ||||
| 
 | ||||
| 	g.definitions.writeln('function ${copy_fn_name}(it) {') | ||||
| 	g.definitions.writeln('\tlet res = ${parent_copy_fn_name}(it);') | ||||
| 	g.definitions.writeln('\treturn res;') | ||||
| 	g.definitions.writeln('}') | ||||
| } | ||||
| 
 | ||||
| fn (mut g JsGen) gen_copy_for_multi_return(info ast.MultiReturn, styp string, copy_fn_name string) { | ||||
| 	mut fn_builder := strings.new_builder(512) | ||||
| 	fn_builder.writeln('function ${copy_fn_name}(a) {') | ||||
| 	fn_builder.writeln('\tlet arr = []') | ||||
| 	for i, typ in info.types { | ||||
| 		sym := g.table.get_type_symbol(typ) | ||||
| 		arg_copy_fn_name := g.get_copy_fn(typ) | ||||
| 
 | ||||
| 		if sym.kind in [.f32, .f64] { | ||||
| 			if sym.kind == .f32 { | ||||
| 				fn_builder.writeln('\tarr.push(new f32(a[$i].val));') | ||||
| 			} else { | ||||
| 				fn_builder.writeln('\tarr.push(new f64(a[$i].val));') | ||||
| 			} | ||||
| 		} else if sym.kind == .string { | ||||
| 			fn_builder.writeln('\tarr.push(new string(a[$i].str +""));') | ||||
| 		} else if sym.kind == .function { | ||||
| 			fn_builder.writeln('\tarr.push(a[$i]);') | ||||
| 		} else { | ||||
| 			fn_builder.writeln('\tarr.push(${arg_copy_fn_name}(a[$i]));') | ||||
| 		} | ||||
| 	} | ||||
| 	fn_builder.writeln('\treturn arr;') | ||||
| 	fn_builder.writeln('}') | ||||
| 	g.definitions.writeln(fn_builder.str()) | ||||
| } | ||||
| 
 | ||||
| fn (mut g JsGen) gen_copy_for_enum(info ast.Enum, styp string, copy_fn_name string) { | ||||
| 	g.definitions.writeln('function ${copy_fn_name}(it) { return it; }') | ||||
| } | ||||
| 
 | ||||
| fn (mut g JsGen) gen_copy_for_union_sum_type(info ast.SumType, styp string, copy_fn_name string) { | ||||
| 	mut fn_builder := strings.new_builder(512) | ||||
| 	fn_builder.writeln('function ${copy_fn_name}(x) {') | ||||
| 	for typ in info.variants { | ||||
| 		typ_str := g.typ(typ) | ||||
| 		mut func_name := g.get_copy_fn(typ) | ||||
| 		fn_builder.writeln('if (x instanceof $typ_str) { return ${func_name}(x); }') | ||||
| 	} | ||||
| 	fn_builder.writeln('builtin__panic(new string("unknown sum type value"));\n}') | ||||
| 	g.definitions.writeln(fn_builder.str()) | ||||
| } | ||||
| 
 | ||||
| fn (mut g JsGen) gen_copy_for_interface(info ast.Interface, styp string, copy_fn_name string) { | ||||
| 	mut fn_builder := strings.new_builder(512) | ||||
| 	mut clean_interface_v_type_name := styp.replace('__', '.') | ||||
| 	if styp.ends_with('*') { | ||||
| 		clean_interface_v_type_name = '&' + clean_interface_v_type_name.replace('*', '') | ||||
| 	} | ||||
| 	if clean_interface_v_type_name.contains('_T_') { | ||||
| 		clean_interface_v_type_name = | ||||
| 			clean_interface_v_type_name.replace('Array_', '[]').replace('_T_', '<').replace('_', ', ') + | ||||
| 			'>' | ||||
| 	} | ||||
| 	clean_interface_v_type_name = util.strip_main_name(clean_interface_v_type_name) | ||||
| 	fn_builder.writeln('function ${copy_fn_name}(x) { return x; }') | ||||
| 	/* | ||||
| 	for typ in info.types { | ||||
| 		subtype := g.table.get_type_symbol(typ) | ||||
| 		mut func_name := g.get_copy_fn(typ) | ||||
| 		if typ == ast.string_type { | ||||
| 
 | ||||
| 			fn_builder.write_string('\tif (x instanceof string)') | ||||
| 			fn_builder.write_string(' return new string(x.str + "");') | ||||
| 		} else { | ||||
| 			/* | ||||
| 			mut val := '${func_name}(${deref}($subtype.cname*)x._$subtype.cname' | ||||
| 			if should_use_indent_func(subtype.kind) && !sym_has_str_method { | ||||
| 				val += ', indent_count' | ||||
| 			} | ||||
| 			val += ')' | ||||
| 			val = val | ||||
| 			*/ | ||||
| 			res := '"TODO' | ||||
| 			fn_builder.write_string('\tif (x instanceof ${g.typ(typ)})') | ||||
| 			fn_builder.write_string(' return ${func_name}(x);\n') | ||||
| 		} | ||||
| 	} | ||||
| 	fn_builder.writeln('\tbuiltin__panic("unknown interface value");') | ||||
| 	fn_builder.writeln('}')*/ | ||||
| 	g.definitions.writeln(fn_builder.str()) | ||||
| } | ||||
| 
 | ||||
| fn (mut g JsGen) gen_copy_for_fn_type(info ast.FnType, styp string, copy_fn_name string) { | ||||
| 	g.definitions.writeln('function $copy_fn_name (x) { return x; }') | ||||
| } | ||||
| 
 | ||||
| fn (mut g JsGen) gen_copy_for_array(info ast.Array, styp string, copy_fn_name string) { | ||||
| 	g.definitions.writeln('function $copy_fn_name (x) { return x; }') | ||||
| } | ||||
| 
 | ||||
| fn (mut g JsGen) gen_copy_for_array_fixed(info ast.ArrayFixed, styp string, copy_fn_name string) { | ||||
| 	g.definitions.writeln('function $copy_fn_name (x) { return x; }') | ||||
| } | ||||
| 
 | ||||
| fn (mut g JsGen) gen_copy_for_map(info ast.Map, styp string, copy_fn_name string) { | ||||
| 	g.definitions.writeln('function $copy_fn_name (x) { return x; }') | ||||
| } | ||||
| 
 | ||||
| fn (mut g JsGen) gen_copy_for_struct(info ast.Struct, styp string, copy_fn_name string) { | ||||
| 	mut fn_builder := strings.new_builder(512) | ||||
| 	defer { | ||||
| 		g.definitions.writeln(fn_builder.str()) | ||||
| 	} | ||||
| 
 | ||||
| 	fn_builder.writeln('function ${copy_fn_name}(it) {') | ||||
| 
 | ||||
| 	tmp := g.new_tmp_var() | ||||
| 	fn_builder.writeln('\tlet $tmp = new ${styp}({});') | ||||
| 	for field in info.fields { | ||||
| 		func_name := g.get_copy_fn(field.typ) | ||||
| 		fn_builder.writeln('\t${tmp}.$field.name = ${func_name}(it.$field.name);') | ||||
| 	} | ||||
| 	fn_builder.writeln('\treturn $tmp;\n}') | ||||
| } | ||||
| 
 | ||||
| fn (mut g JsGen) final_gen_copy(typ StrType) { | ||||
| 	if typ in g.generated_copy_fns { | ||||
| 		return | ||||
| 	} | ||||
| 	g.generated_copy_fns << typ | ||||
| 	sym := g.table.get_type_symbol(typ.typ) | ||||
| 	if sym.has_method('\$copy') && !typ.typ.has_flag(.optional) { | ||||
| 		return | ||||
| 	} | ||||
| 	styp := typ.styp | ||||
| 	copy_fn_name := styp_to_copy_fn_name(styp) | ||||
| 	if typ.typ.has_flag(.optional) { | ||||
| 		g.gen_copy_for_option(typ.typ, styp, copy_fn_name) | ||||
| 		return | ||||
| 	} | ||||
| 	match sym.kind { | ||||
| 		.byte, .u8, .u16, .u32, .u64, .i16, .int, .i64, .isize, .usize, .bool, .int_literal, | ||||
| 		.float_literal, .f32, .f64 { | ||||
| 			g.definitions.writeln('function ${sym.cname}_\$copy(it) { return new ${sym.cname}(it.val); }') | ||||
| 			return | ||||
| 		} | ||||
| 		else {} | ||||
| 	} | ||||
| 	match mut sym.info { | ||||
| 		ast.Alias { | ||||
| 			g.gen_copy_for_alias(sym.info, styp, copy_fn_name) | ||||
| 		} | ||||
| 		ast.Array { | ||||
| 			g.gen_copy_for_array(sym.info, styp, copy_fn_name) | ||||
| 		} | ||||
| 		ast.ArrayFixed { | ||||
| 			g.gen_copy_for_array_fixed(sym.info, styp, copy_fn_name) | ||||
| 		} | ||||
| 		ast.Enum { | ||||
| 			g.gen_copy_for_enum(sym.info, styp, copy_fn_name) | ||||
| 		} | ||||
| 		ast.FnType { | ||||
| 			g.gen_copy_for_fn_type(sym.info, styp, copy_fn_name) | ||||
| 		} | ||||
| 		ast.Struct { | ||||
| 			g.gen_copy_for_struct(sym.info, styp, copy_fn_name) | ||||
| 		} | ||||
| 		ast.Map { | ||||
| 			g.gen_copy_for_map(sym.info, styp, copy_fn_name) | ||||
| 		} | ||||
| 		ast.MultiReturn { | ||||
| 			g.gen_copy_for_multi_return(sym.info, styp, copy_fn_name) | ||||
| 		} | ||||
| 		ast.SumType { | ||||
| 			g.gen_copy_for_union_sum_type(sym.info, styp, copy_fn_name) | ||||
| 		} | ||||
| 		ast.Interface { | ||||
| 			g.gen_copy_for_interface(sym.info, styp, copy_fn_name) | ||||
| 		} | ||||
| 		else { | ||||
| 			verror("could not generate string method $copy_fn_name for type '$styp'") | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | @ -428,6 +428,7 @@ fn (mut g JsGen) gen_fn_decl(it ast.FnDecl) { | |||
| 		return | ||||
| 	} | ||||
| 	cur_fn_decl := g.fn_decl | ||||
| 	g.fn_decl = unsafe { &it } | ||||
| 	g.gen_method_decl(it, res) | ||||
| 	g.fn_decl = cur_fn_decl | ||||
| } | ||||
|  | @ -601,3 +602,75 @@ fn (mut g JsGen) fn_args(args []ast.Param, is_variadic bool) { | |||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| fn (mut g JsGen) gen_anon_fn(mut fun ast.AnonFn) { | ||||
| 	if fun.has_gen { | ||||
| 		return | ||||
| 	} | ||||
| 	fun.has_gen = true | ||||
| 	it := fun.decl | ||||
| 	unsafe { | ||||
| 		g.fn_decl = &it | ||||
| 	} | ||||
| 	cur_fn_save := g.table.cur_fn | ||||
| 	defer { | ||||
| 		g.table.cur_fn = cur_fn_save | ||||
| 	} | ||||
| 	unsafe { | ||||
| 		g.table.cur_fn = &it | ||||
| 	} | ||||
| 	mut name := it.name | ||||
| 	if name in ['+', '-', '*', '/', '%', '<', '=='] { | ||||
| 		name = util.replace_op(name) | ||||
| 	} | ||||
| 	g.writeln('(function () { ') | ||||
| 	mut inherited2copy := map[string]string{} | ||||
| 	for inherited in fun.inherited_vars { | ||||
| 		if !inherited.is_mut { | ||||
| 			copy := g.copy_val(inherited.typ, inherited.name) | ||||
| 			inherited2copy[inherited.name] = copy | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	name = g.js_name(name) | ||||
| 
 | ||||
| 	name = g.generic_fn_name(g.table.cur_concrete_types, name, true) | ||||
| 	if name in parser.builtin_functions { | ||||
| 		name = 'builtin__$name' | ||||
| 	} | ||||
| 	if it.is_pub && !it.is_method { | ||||
| 		g.push_pub_var(name) | ||||
| 	} | ||||
| 	g.gen_attrs(it.attrs) | ||||
| 
 | ||||
| 	g.write('return function (') | ||||
| 
 | ||||
| 	mut args := it.params | ||||
| 
 | ||||
| 	g.fn_args(args, it.is_variadic) | ||||
| 	g.writeln(') {') | ||||
| 
 | ||||
| 	g.inc_indent() | ||||
| 	for i, arg in args { | ||||
| 		is_varg := i == args.len - 1 && it.is_variadic | ||||
| 		arg_name := g.js_name(arg.name) | ||||
| 		if is_varg { | ||||
| 			g.writeln('$arg_name = new array(new array_buffer({arr: $arg_name,len: new int(${arg_name}.length),index_start: new int(0)}));') | ||||
| 		} else { | ||||
| 			if arg.typ.is_ptr() || arg.is_mut { | ||||
| 				g.writeln('$arg_name = new \$ref($arg_name)') | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	for inherited in fun.inherited_vars { | ||||
| 		if !inherited.is_mut { | ||||
| 			g.writeln('let $inherited.name = ${inherited2copy[inherited.name]};') | ||||
| 		} | ||||
| 	} | ||||
| 	g.stmts(it.stmts) | ||||
| 	g.dec_indent() | ||||
| 	g.writeln('}})()') | ||||
| 
 | ||||
| 	g.fn_decl = voidptr(0) | ||||
| } | ||||
|  |  | |||
|  | @ -66,13 +66,16 @@ mut: | |||
| 	fn_decl                &ast.FnDecl // pointer to the FnDecl we are currently inside otherwise 0
 | ||||
| 	generated_str_fns      []StrType | ||||
| 	str_types              []StrType // types that need automatic str() generation
 | ||||
| 	array_fn_definitions   []string  // array equality functions that have been defined
 | ||||
| 	map_fn_definitions     []string  // map equality functions that have been defined
 | ||||
| 	struct_fn_definitions  []string  // struct equality functions that have been defined
 | ||||
| 	sumtype_fn_definitions []string  // sumtype equality functions that have been defined
 | ||||
| 	alias_fn_definitions   []string  // alias equality functions that have been defined
 | ||||
| 	auto_fn_definitions    []string  // auto generated functions defination list
 | ||||
| 	anon_fn_definitions    []string  // anon generated functions defination list
 | ||||
| 	copy_types             []StrType // types that need to be deep copied
 | ||||
| 	generated_copy_fns     []StrType | ||||
| 	array_fn_definitions   []string // array equality functions that have been defined
 | ||||
| 	map_fn_definitions     []string // map equality functions that have been defined
 | ||||
| 	struct_fn_definitions  []string // struct equality functions that have been defined
 | ||||
| 	sumtype_fn_definitions []string // sumtype equality functions that have been defined
 | ||||
| 	alias_fn_definitions   []string // alias equality functions that have been defined
 | ||||
| 	auto_fn_definitions    []string // auto generated functions defination list
 | ||||
| 	anon_fn_definitions    []string // anon generated functions defination list
 | ||||
| 	copy_fn_definitions    []string | ||||
| 	method_fn_decls        map[string][]ast.FnDecl | ||||
| 	builtin_fns            []string // Functions defined in `builtin`
 | ||||
| 	empty_line             bool | ||||
|  | @ -162,6 +165,9 @@ pub fn gen(files []&ast.File, table &ast.Table, pref &pref.Preferences) string { | |||
| 	for i := 0; i < g.str_types.len; i++ { | ||||
| 		g.final_gen_str(g.str_types[i]) | ||||
| 	} | ||||
| 	for i := 0; i < g.copy_types.len; i++ { | ||||
| 		g.final_gen_copy(g.copy_types[i]) | ||||
| 	} | ||||
| 	if g.pref.is_test { | ||||
| 		g.gen_js_main_for_tests() | ||||
| 	} | ||||
|  | @ -607,14 +613,14 @@ fn (mut g JsGen) gen_alias_type_decl(node ast.AliasTypeDecl) { | |||
| 
 | ||||
| fn (mut g JsGen) stmt_no_semi(node ast.Stmt) { | ||||
| 	g.stmt_start_pos = g.out.len | ||||
| 	match node { | ||||
| 	match mut node { | ||||
| 		ast.EmptyStmt {} | ||||
| 		ast.AsmStmt { | ||||
| 			panic('inline asm is not supported by js') | ||||
| 		} | ||||
| 		ast.AssertStmt { | ||||
| 			g.write_v_source_line_info(node.pos) | ||||
| 			g.gen_assert_stmt(node) | ||||
| 			g.gen_assert_stmt(mut node) | ||||
| 		} | ||||
| 		ast.AssignStmt { | ||||
| 			g.write_v_source_line_info(node.pos) | ||||
|  | @ -648,7 +654,7 @@ fn (mut g JsGen) stmt_no_semi(node ast.Stmt) { | |||
| 		} | ||||
| 		ast.FnDecl { | ||||
| 			g.write_v_source_line_info(node.pos) | ||||
| 			g.fn_decl = unsafe { &node } | ||||
| 
 | ||||
| 			g.gen_fn_decl(node) | ||||
| 		} | ||||
| 		ast.ForCStmt { | ||||
|  | @ -710,14 +716,14 @@ fn (mut g JsGen) stmt_no_semi(node ast.Stmt) { | |||
| 
 | ||||
| fn (mut g JsGen) stmt(node ast.Stmt) { | ||||
| 	g.stmt_start_pos = g.out.len | ||||
| 	match node { | ||||
| 	match mut node { | ||||
| 		ast.EmptyStmt {} | ||||
| 		ast.AsmStmt { | ||||
| 			panic('inline asm is not supported by js') | ||||
| 		} | ||||
| 		ast.AssertStmt { | ||||
| 			g.write_v_source_line_info(node.pos) | ||||
| 			g.gen_assert_stmt(node) | ||||
| 			g.gen_assert_stmt(mut node) | ||||
| 		} | ||||
| 		ast.AssignStmt { | ||||
| 			g.write_v_source_line_info(node.pos) | ||||
|  | @ -751,7 +757,6 @@ fn (mut g JsGen) stmt(node ast.Stmt) { | |||
| 		} | ||||
| 		ast.FnDecl { | ||||
| 			g.write_v_source_line_info(node.pos) | ||||
| 			g.fn_decl = unsafe { &node } | ||||
| 			g.gen_fn_decl(node) | ||||
| 		} | ||||
| 		ast.ForCStmt { | ||||
|  | @ -808,7 +813,7 @@ fn (mut g JsGen) stmt(node ast.Stmt) { | |||
| 			g.gen_struct_decl(node) | ||||
| 		} | ||||
| 		ast.TypeDecl { | ||||
| 			match node { | ||||
| 			match mut node { | ||||
| 				ast.AliasTypeDecl { | ||||
| 					g.gen_alias_type_decl(node) | ||||
| 				} | ||||
|  | @ -820,10 +825,10 @@ fn (mut g JsGen) stmt(node ast.Stmt) { | |||
| 
 | ||||
| fn (mut g JsGen) expr(node ast.Expr) { | ||||
| 	// NB: please keep the type names in the match here in alphabetical order:
 | ||||
| 	match node { | ||||
| 	match mut node { | ||||
| 		ast.EmptyExpr {} | ||||
| 		ast.AnonFn { | ||||
| 			g.gen_fn_decl(node.decl) | ||||
| 			g.gen_anon_fn(mut node) | ||||
| 		} | ||||
| 		ast.ArrayDecompose {} | ||||
| 		ast.ArrayInit { | ||||
|  | @ -1091,7 +1096,7 @@ fn (mut g JsGen) gen_ctemp_var(tvar ast.CTempVar) { | |||
| 
 | ||||
| fn (mut g JsGen) gen_assert_metainfo(node ast.AssertStmt) string { | ||||
| 	mod_path := g.file.path | ||||
| 	fn_name := g.fn_decl.name | ||||
| 	fn_name := if g.fn_decl == voidptr(0) || g.fn_decl.is_anon { 'anon' } else { g.fn_decl.name } | ||||
| 	line_nr := node.pos.line_nr | ||||
| 	src := node.expr.str() | ||||
| 	metaname := 'v_assert_meta_info_$g.new_tmp_var()' | ||||
|  | @ -1176,8 +1181,7 @@ fn (mut g JsGen) gen_assert_single_expr(expr ast.Expr, typ ast.Type) { | |||
| } | ||||
| 
 | ||||
| // TODO
 | ||||
| fn (mut g JsGen) gen_assert_stmt(orig_node ast.AssertStmt) { | ||||
| 	mut node := orig_node | ||||
| fn (mut g JsGen) gen_assert_stmt(mut node ast.AssertStmt) { | ||||
| 	if !node.is_used { | ||||
| 		return | ||||
| 	} | ||||
|  | @ -1192,18 +1196,18 @@ fn (mut g JsGen) gen_assert_stmt(orig_node ast.AssertStmt) { | |||
| 			node.expr.right = subst_expr | ||||
| 		} | ||||
| 	} | ||||
| 	mut a := node | ||||
| 
 | ||||
| 	g.write('if( ') | ||||
| 	g.expr(a.expr) | ||||
| 	g.expr(node.expr) | ||||
| 	g.write('.valueOf() ) {') | ||||
| 	s_assertion := a.expr.str().replace('"', "'") | ||||
| 	s_assertion := node.expr.str().replace('"', "'") | ||||
| 	mut mod_path := g.file.path.replace('\\', '\\\\') | ||||
| 	if g.is_test { | ||||
| 		metaname_ok := g.gen_assert_metainfo(a) | ||||
| 		metaname_ok := g.gen_assert_metainfo(node) | ||||
| 		g.writeln('	g_test_oks++;') | ||||
| 		g.writeln('	main__cb_assertion_ok($metaname_ok);') | ||||
| 		g.writeln('} else {') | ||||
| 		metaname_fail := g.gen_assert_metainfo(a) | ||||
| 		metaname_fail := g.gen_assert_metainfo(node) | ||||
| 		g.writeln('	g_test_fails++;') | ||||
| 		g.writeln('	main__cb_assertion_failed($metaname_fail);') | ||||
| 		g.writeln('	builtin__exit(1);') | ||||
|  | @ -1212,7 +1216,8 @@ fn (mut g JsGen) gen_assert_stmt(orig_node ast.AssertStmt) { | |||
| 	} | ||||
| 	g.writeln('} else {') | ||||
| 	g.inc_indent() | ||||
| 	g.writeln('builtin__eprintln(new string("$mod_path:${a.pos.line_nr + 1}: FAIL: fn ${g.fn_decl.name}(): assert $s_assertion"));') | ||||
| 	fname := if g.fn_decl == voidptr(0) || g.fn_decl.is_anon { 'anon' } else { g.fn_decl.name } | ||||
| 	g.writeln('builtin__eprintln(new string("$mod_path:${node.pos.line_nr + 1}: FAIL: fn ${fname}(): assert $s_assertion"));') | ||||
| 	g.writeln('builtin__exit(1);') | ||||
| 	g.dec_indent() | ||||
| 	g.writeln('}') | ||||
|  | @ -1772,6 +1777,12 @@ fn (mut g JsGen) gen_hash_stmt(it ast.HashStmt) { | |||
| 	g.writeln(it.val) | ||||
| } | ||||
| 
 | ||||
| fn (mut g JsGen) gen_sumtype_decl(it ast.SumTypeDecl) { | ||||
| 	name := g.js_name(it.name) | ||||
| 	g.push_pub_var('/** @type $name */\n\t\t$name') | ||||
| 	g.writeln('function ${g.js_name(it.name)} (arg) { return arg; }') | ||||
| } | ||||
| 
 | ||||
| fn (mut g JsGen) gen_struct_decl(node ast.StructDecl) { | ||||
| 	mut name := node.name | ||||
| 	if name.starts_with('JS.') { | ||||
|  | @ -3216,6 +3227,10 @@ fn (mut g JsGen) gen_type_cast_expr(it ast.CastExpr) { | |||
| 		|| (it.expr is ast.FloatLiteral && it.typ in ast.float_type_idxs)) | ||||
| 	// Skip cast if type is the same as the parrent caster
 | ||||
| 	tsym := g.table.get_final_type_symbol(it.typ) | ||||
| 	if tsym.kind == .sum_type { | ||||
| 		g.expr(it.expr) | ||||
| 		return | ||||
| 	} | ||||
| 	if it.expr is ast.IntegerLiteral && (tsym.kind == .i64 || tsym.kind == .u64) { | ||||
| 		g.write('new ') | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue