From 1c340174b7f9935105f8c8d53c603b754ab4fe4a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20D=C3=A4schle?= Date: Wed, 8 Apr 2020 22:14:01 +0200 Subject: [PATCH] cgen: print nested structs --- .gitignore | 5 +- vlib/v/gen/cgen.v | 90 +++++++++++++-------- vlib/v/tests/inout/nested_structs.out | 7 ++ vlib/v/tests/inout/nested_structs.vv | 16 ++++ vlib/v/tests/prod/assoc.prod.v.expected.txt | 2 +- 5 files changed, 81 insertions(+), 39 deletions(-) create mode 100644 vlib/v/tests/inout/nested_structs.out create mode 100644 vlib/v/tests/inout/nested_structs.vv diff --git a/.gitignore b/.gitignore index 7f8501b91c..eb521220a4 100644 --- a/.gitignore +++ b/.gitignore @@ -83,7 +83,4 @@ cachegrind.out.* .gdb_history /thirdparty/pg exe -vlib/v/tests/inout/hello.v -vlib/v/tests/inout/hello_devs.v -vlib/v/tests/inout/os.v -vlib/v/tests/inout/enum_print.v +vlib/v/tests/inout/*.v diff --git a/vlib/v/gen/cgen.v b/vlib/v/gen/cgen.v index 0a700337a1..aaa95523b5 100644 --- a/vlib/v/gen/cgen.v +++ b/vlib/v/gen/cgen.v @@ -2334,11 +2334,7 @@ fn (g mut Gen) string_inter_literal(node ast.StringInterLiteral) { } if is_var { styp := g.typ(node.expr_types[i]) - if !sym.has_method('str') && !(styp in g.str_types) { - // Generate an automatic str() method if this type doesn't have it already - g.str_types << styp - g.gen_str_for_type(sym, styp) - } + g.gen_str_for_type(sym, styp) g.write('${styp}_str(') g.enum_expr(expr) g.write(')') @@ -2510,14 +2506,10 @@ fn (g mut Gen) fn_call(node ast.CallExpr) { typ := node.args[0].typ mut styp := g.typ(typ) sym := g.table.get_type_symbol(typ) - if !sym.has_method('str') && !(styp in g.str_types) { - // Generate an automatic str() method if this type doesn't have it already - if table.type_is_ptr(typ) { - styp = styp.replace('*', '') - } - g.str_types << styp - g.gen_str_for_type(sym, styp) + if table.type_is_ptr(typ) { + styp = styp.replace('*', '') } + g.gen_str_for_type(sym, styp) if g.autofree && !table.type_is(typ, .optional) { // Create a temporary variable so that the value can be freed tmp := g.new_tmp_var() @@ -2562,6 +2554,9 @@ fn (g mut Gen) fn_call(node ast.CallExpr) { // g.write('*') } g.expr(node.args[0].expr) + if sym.kind ==.struct_ && styp != 'ptr' && !sym.has_method('str') { + g.write(', 0') // trailing 0 is initial struct indent count + } g.write('))') } } else { @@ -3042,6 +3037,10 @@ fn (g mut Gen) go_stmt(node ast.GoStmt) { // already generated styp, reuse it fn (g mut Gen) gen_str_for_type(sym table.TypeSymbol, styp string) { + if sym.has_method('str') || styp in g.str_types { + return + } + g.str_types << styp match sym.info { table.Struct { g.gen_str_for_struct(it, styp) @@ -3057,7 +3056,7 @@ fn (g mut Gen) gen_str_for_type(sym table.TypeSymbol, styp string) { fn (g mut Gen) gen_str_for_enum(info table.Enum, styp string) { s := styp.replace('.', '__') - g.definitions.write('string ${s}_str($styp a) {\n\tswitch(a) {\n') + g.definitions.write('string ${s}_str($styp it) {\n\tswitch(it) {\n') for i, val in info.vals { g.definitions.write('\t\tcase ${s}_$val: return tos3("$val");\n') } @@ -3065,36 +3064,59 @@ fn (g mut Gen) gen_str_for_enum(info table.Enum, styp string) { } fn (g mut Gen) gen_str_for_struct(info table.Struct, styp string) { - s := styp.replace('.', '__') - g.definitions.write('string ${s}_str($styp a) { return _STR("$styp {\\n') - for field in info.fields { - fmt := type_to_fmt(field.typ) - g.definitions.write('\t$field.name: $fmt\\n') + // TODO: short it if possible + // generates all definitions of substructs + for i, field in info.fields { + sym := g.table.get_type_symbol(field.typ) + if sym.kind == .struct_ { + field_styp := g.typ(field.typ) + g.gen_str_for_type(sym, field_styp) + } } - g.definitions.write('}"') + + s := styp.replace('.', '__') + g.definitions.write('string ${s}_str($styp it, int indent_count) {\n') + // generate ident / indent length = 4 spaces + g.definitions.write('\tstring indents = tos3("");\n\tfor (int i = 0; i < indent_count; i++) { indents = string_add(indents, tos3(" ")); }\n') + g.definitions.write('\treturn _STR("$styp {\\n') + for field in info.fields { + fmt := g.type_to_fmt(field.typ) + g.definitions.write('%.*s ' + '$field.name: $fmt\\n') + } + g.definitions.write('%.*s}"') if info.fields.len > 0 { g.definitions.write(', ') - } - for i, field in info.fields { - g.definitions.write('a.' + field.name) - if field.typ == table.string_type { - g.definitions.write('.len, a.${field.name}.str') - } else if field.typ == table.bool_type { - g.definitions.write(' ? 4 : 5, a.${field.name} ? "true" : "false"') - } - if i < info.fields.len - 1 { - g.definitions.write(', ') + for i, field in info.fields { + sym := g.table.get_type_symbol(field.typ) + if sym.kind == .struct_ { + field_styp := g.typ(field.typ) + g.definitions.write('indents.len, indents.str, ${field_styp}_str(it.$field.name, indent_count + 1).len, ${field_styp}_str(it.$field.name, indent_count + 1).str') + } else { + g.definitions.write('indents.len, indents.str, it.$field.name') + if field.typ == table.string_type { + g.definitions.write('.len, it.${field.name}.str') + } else if field.typ == table.bool_type { + g.definitions.write(' ? 4 : 5, it.${field.name} ? "true" : "false"') + } + if i < info.fields.len - 1 { + g.definitions.write(', ') + } + } } } - g.definitions.writeln('); }') + g.definitions.writeln(', indents.len, indents.str);\n}') } -fn type_to_fmt(typ table.Type) string { - n := int(typ) - if n == table.string_type { +fn (g Gen) type_to_fmt(typ table.Type) string { + sym := g.table.get_type_symbol(typ) + if sym.kind == .struct_ { + return "%.*s" + } else if typ == table.string_type { return "\'%.*s\'" - } else if n == table.bool_type { + } else if typ == table.bool_type { return '%.*s' + } else if typ in [table.f32_type, table.f64_type] { + return '%g' // g removes trailing zeros unlike %f } return '%d' } diff --git a/vlib/v/tests/inout/nested_structs.out b/vlib/v/tests/inout/nested_structs.out new file mode 100644 index 0000000000..b1b44ad24e --- /dev/null +++ b/vlib/v/tests/inout/nested_structs.out @@ -0,0 +1,7 @@ +A { + test: false + b: B { + pass: false + name: '' + } +} \ No newline at end of file diff --git a/vlib/v/tests/inout/nested_structs.vv b/vlib/v/tests/inout/nested_structs.vv new file mode 100644 index 0000000000..26ed593289 --- /dev/null +++ b/vlib/v/tests/inout/nested_structs.vv @@ -0,0 +1,16 @@ +module main + +struct B { + pass bool + name string +} + +struct A { + test bool + b B +} + +fn main() { + a := A{} + println(a) +} diff --git a/vlib/v/tests/prod/assoc.prod.v.expected.txt b/vlib/v/tests/prod/assoc.prod.v.expected.txt index 0a0ead9519..432b232bf3 100644 --- a/vlib/v/tests/prod/assoc.prod.v.expected.txt +++ b/vlib/v/tests/prod/assoc.prod.v.expected.txt @@ -1,3 +1,3 @@ MyStruct { - s: '6' + s: '6' } \ No newline at end of file