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\'") }
|
||||
}
|
||||
}
|
||||
|
@ -299,7 +299,6 @@ 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.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