cgen: implement sum type str gen (#6454)
							parent
							
								
									b0a2c28c19
								
							
						
					
					
						commit
						4f09ddccb4
					
				| 
						 | 
				
			
			@ -315,7 +315,7 @@ pub fn (c &Checker) get_default_fmt(ftyp, typ table.Type) byte {
 | 
			
		|||
			}
 | 
			
		||||
		}
 | 
			
		||||
		if ftyp in [table.string_type, table.bool_type] ||
 | 
			
		||||
			sym.kind in [.enum_, .array, .array_fixed, .struct_, .map, .multi_return] || ftyp.has_flag(.optional) ||
 | 
			
		||||
			sym.kind in [.enum_, .array, .array_fixed, .struct_, .map, .multi_return, .sum_type] || ftyp.has_flag(.optional) ||
 | 
			
		||||
			sym.has_method('str') {
 | 
			
		||||
			return `s`
 | 
			
		||||
		} else {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -53,7 +53,7 @@ fn (mut g Gen) gen_str_for_type_with_styp(typ table.Type, styp string) string {
 | 
			
		|||
			table.Struct { g.gen_str_for_struct(it, styp, str_fn_name) }
 | 
			
		||||
			table.Map { g.gen_str_for_map(it, styp, str_fn_name) }
 | 
			
		||||
			table.MultiReturn { g.gen_str_for_multi_return(it, styp, str_fn_name) }
 | 
			
		||||
			table.SumType {}
 | 
			
		||||
			table.SumType { g.gen_str_for_sum_type(it, styp, str_fn_name) }
 | 
			
		||||
			else { verror("could not generate string method $str_fn_name for type \'$styp\'") }
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -298,8 +298,7 @@ fn (mut g Gen) gen_str_for_struct(info table.Struct, styp, str_fn_name string) {
 | 
			
		|||
	}
 | 
			
		||||
	// _str() functions should have a single argument, the indenting ones take 2:
 | 
			
		||||
	g.type_definitions.writeln('string ${str_fn_name}($styp x); // auto')
 | 
			
		||||
	g.auto_str_funcs.writeln('string ${str_fn_name}($styp x) { return indent_${str_fn_name}(x,0);}')
 | 
			
		||||
	//
 | 
			
		||||
	g.auto_str_funcs.writeln('string ${str_fn_name}($styp x) { return indent_${str_fn_name}(x, 0);}')
 | 
			
		||||
	g.type_definitions.writeln('string indent_${str_fn_name}($styp x, int indent_count); // auto')
 | 
			
		||||
	g.auto_str_funcs.writeln('string indent_${str_fn_name}($styp x, int indent_count) {')
 | 
			
		||||
	mut clean_struct_v_type_name := styp.replace('__', '.')
 | 
			
		||||
| 
						 | 
				
			
			@ -346,6 +345,8 @@ fn (mut g Gen) gen_str_for_struct(info table.Struct, styp, str_fn_name string) {
 | 
			
		|||
			} else if sym.kind in [.array, .array_fixed, .map] {
 | 
			
		||||
				g.auto_str_funcs.write('indents, ')
 | 
			
		||||
				g.auto_str_funcs.write('${field_styp_fn_name}( it->${c_name(field.name)}) ')
 | 
			
		||||
			} else if sym.kind == .sum_type {
 | 
			
		||||
				g.auto_str_funcs.write('indents, indent_${field_styp_fn_name}(it->${c_name(field.name)}, indent_count + 1)')
 | 
			
		||||
			} else {
 | 
			
		||||
				g.auto_str_funcs.write('indents, it->${c_name(field.name)}')
 | 
			
		||||
				if field.typ == table.bool_type {
 | 
			
		||||
| 
						 | 
				
			
			@ -381,3 +382,50 @@ fn (mut g Gen) gen_str_for_enum(info table.Enum, styp, str_fn_name string) {
 | 
			
		|||
	g.auto_str_funcs.writeln('\t}')
 | 
			
		||||
	g.auto_str_funcs.writeln('}')
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn (mut g Gen) gen_str_for_sum_type(info table.SumType, styp, str_fn_name string) {
 | 
			
		||||
	mut gen_fn_names := map[string]string
 | 
			
		||||
	for typ in info.variants {
 | 
			
		||||
		sym := g.table.get_type_symbol(typ)
 | 
			
		||||
		if !sym.has_method('str') {
 | 
			
		||||
			field_styp := g.typ(typ)
 | 
			
		||||
			field_fn_name := g.gen_str_for_type_with_styp(typ, field_styp)
 | 
			
		||||
			gen_fn_names[field_styp] = field_fn_name
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	// _str() functions should have a single argument, the indenting ones take 2:
 | 
			
		||||
	g.type_definitions.writeln('string ${str_fn_name}($styp x); // auto')
 | 
			
		||||
	g.auto_str_funcs.writeln('string ${str_fn_name}($styp x) { return indent_${str_fn_name}(x, 0); }')
 | 
			
		||||
	g.type_definitions.writeln('string indent_${str_fn_name}($styp x, int indent_count); // auto')
 | 
			
		||||
	g.auto_str_funcs.writeln('string indent_${str_fn_name}($styp x, int indent_count) {')
 | 
			
		||||
	mut clean_sum_type_v_type_name := styp.replace('__', '.')
 | 
			
		||||
	if styp.ends_with('*') {
 | 
			
		||||
		clean_sum_type_v_type_name = '&' + clean_sum_type_v_type_name.replace('*', '')
 | 
			
		||||
	}
 | 
			
		||||
	clean_sum_type_v_type_name = util.strip_main_name(clean_sum_type_v_type_name)
 | 
			
		||||
	g.auto_str_funcs.writeln('\tswitch(x.typ) {')
 | 
			
		||||
	for typ in info.variants {
 | 
			
		||||
		mut value_fmt := '%.*s\\000'
 | 
			
		||||
		if typ == table.string_type {
 | 
			
		||||
			value_fmt = '\'$value_fmt\''
 | 
			
		||||
		}
 | 
			
		||||
		typ_str := g.typ(typ)
 | 
			
		||||
		mut func_name := if typ_str in gen_fn_names {
 | 
			
		||||
			gen_fn_names[typ_str]
 | 
			
		||||
		} else {
 | 
			
		||||
			g.gen_str_for_type_with_styp(typ, typ_str)
 | 
			
		||||
		}
 | 
			
		||||
		sym := g.table.get_type_symbol(typ)
 | 
			
		||||
		if sym.kind == .struct_ {
 | 
			
		||||
			func_name = 'indent_$func_name'
 | 
			
		||||
		}
 | 
			
		||||
		g.auto_str_funcs.write('\t\tcase $typ: return _STR("${clean_sum_type_v_type_name}($value_fmt)", 2, ${func_name}(*($typ_str*)x._object')
 | 
			
		||||
		if sym.kind == .struct_ {
 | 
			
		||||
			g.auto_str_funcs.write(', indent_count')
 | 
			
		||||
		}
 | 
			
		||||
		g.auto_str_funcs.writeln('));')
 | 
			
		||||
	}
 | 
			
		||||
	g.auto_str_funcs.writeln('\t\tdefault: return tos_lit("unknown sum type value");')
 | 
			
		||||
	g.auto_str_funcs.writeln('\t}')
 | 
			
		||||
	g.auto_str_funcs.writeln('}')
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -4159,7 +4159,8 @@ fn (mut g Gen) gen_expr_to_string(expr ast.Expr, etype table.Type) ?bool {
 | 
			
		|||
			g.enum_expr(expr)
 | 
			
		||||
			g.write('")')
 | 
			
		||||
		}
 | 
			
		||||
	} else if sym_has_str_method || sym.kind in [.array, .array_fixed, .map, .struct_, .multi_return] {
 | 
			
		||||
	} else if sym_has_str_method || sym.kind in
 | 
			
		||||
		[.array, .array_fixed, .map, .struct_, .multi_return, .sum_type] {
 | 
			
		||||
		is_p := etype.is_ptr()
 | 
			
		||||
		val_type := if is_p { etype.deref() } else { etype }
 | 
			
		||||
		str_fn_name := g.gen_str_for_type(val_type)
 | 
			
		||||
| 
						 | 
				
			
			@ -5073,6 +5074,8 @@ fn (g &Gen) type_to_fmt(typ table.Type) string {
 | 
			
		|||
		return '%g\\000' // g removes trailing zeros unlike %f
 | 
			
		||||
	} else if typ == table.u64_type {
 | 
			
		||||
		return '%lld\\000'
 | 
			
		||||
	} else if sym.kind == .sum_type {
 | 
			
		||||
		return '%.*s\\000'
 | 
			
		||||
	}
 | 
			
		||||
	return '%d\\000'
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,57 @@
 | 
			
		|||
struct Abc {
 | 
			
		||||
	foo int
 | 
			
		||||
	bar bool
 | 
			
		||||
	str string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type ST = int | string | bool | Abc
 | 
			
		||||
 | 
			
		||||
fn test_int_st_str() {
 | 
			
		||||
	a := ST(0)
 | 
			
		||||
	assert '$a' == 'ST(0)'
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn test_string_st_str() {
 | 
			
		||||
	a := ST('test')
 | 
			
		||||
	assert '$a' == 'ST(\'test\')'
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn test_struct_st_str() {
 | 
			
		||||
	a := ST(Abc{})
 | 
			
		||||
	assert '$a' == 'ST(Abc {\n    foo: 0\n    bar: false\n    str: \'\'\n})'
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn test_bool_st_str() {
 | 
			
		||||
	a := ST(false)
 | 
			
		||||
	assert '$a' == 'ST(false)'
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn test_str() {
 | 
			
		||||
	a := ST(false)
 | 
			
		||||
	assert a.str() == 'ST(false)'
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct Container {
 | 
			
		||||
	st ST
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn test_in_struct() {
 | 
			
		||||
	c := Container{ST(0)}
 | 
			
		||||
	assert '$c' == 'Container {\n    st: ST(0)\n}'
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn test_unknown_value() {
 | 
			
		||||
	c := Container{}
 | 
			
		||||
	assert '$c' == 'Container {\n    st: unknown sum type value\n}'
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn test_nested_in_struct() {
 | 
			
		||||
	abc := Abc{}
 | 
			
		||||
	c := Container{ST(abc)}
 | 
			
		||||
	assert '$c' == 'Container {\n    st: ST(Abc {\n        foo: 0\n        bar: false\n        str: \'\'\n    })\n}'
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn test_pointer() {
 | 
			
		||||
	st := ST(0)
 | 
			
		||||
	assert '${&st}' == '&ST(0)'
 | 
			
		||||
}
 | 
			
		||||
		Loading…
	
		Reference in New Issue