diff --git a/vlib/v/gen/c/auto_str_array.v b/vlib/v/gen/c/auto_str_array.v deleted file mode 100644 index b30431f266..0000000000 --- a/vlib/v/gen/c/auto_str_array.v +++ /dev/null @@ -1,161 +0,0 @@ -module c - -// Copyright (c) 2019-2021 Alexander Medvednikov. 2021 Dario Deledda. All rights reserved. -// Use of this source code is governed by an MIT license -// that can be found in the LICENSE file. -import v.ast - -fn (mut g Gen) gen_str_for_array(info ast.Array, styp string, str_fn_name string) { - mut typ := info.elem_type - mut sym := g.table.get_type_symbol(info.elem_type) - if mut sym.info is ast.Alias { - typ = sym.info.parent_type - sym = g.table.get_type_symbol(typ) - } - field_styp := g.typ(typ) - is_elem_ptr := typ.is_ptr() - sym_has_str_method, str_method_expects_ptr, _ := sym.str_method_info() - mut elem_str_fn_name := '' - if sym_has_str_method { - elem_str_fn_name = if is_elem_ptr { - field_styp.replace('*', '') + '_str' - } else { - field_styp + '_str' - } - if sym.kind == .byte { - elem_str_fn_name = elem_str_fn_name + '_escaped' - } - } else { - elem_str_fn_name = styp_to_str_fn_name(field_styp) - } - if !sym_has_str_method { - g.gen_str_for_type(typ) - } - g.type_definitions.writeln('static string ${str_fn_name}($styp a); // auto') - g.auto_str_funcs.writeln('static string ${str_fn_name}($styp a) { return indent_${str_fn_name}(a, 0);}') - g.type_definitions.writeln('static string indent_${str_fn_name}($styp a, int indent_count); // auto') - g.auto_str_funcs.writeln('static string indent_${str_fn_name}($styp a, int indent_count) {') - g.auto_str_funcs.writeln('\tstrings__Builder sb = strings__new_builder(a.len * 10);') - g.auto_str_funcs.writeln('\tstrings__Builder_write_string(&sb, _SLIT("["));') - g.auto_str_funcs.writeln('\tfor (int i = 0; i < a.len; ++i) {') - if sym.kind == .function { - g.auto_str_funcs.writeln('\t\tstring x = ${elem_str_fn_name}();') - } else { - if sym.kind == .array_fixed { - g.auto_str_funcs.writeln('\t\t$field_styp it;') - g.auto_str_funcs.writeln('\t\tmemcpy(*($field_styp*)it, (byte*)array_get(a, i), sizeof($field_styp));') - } else { - g.auto_str_funcs.writeln('\t\t$field_styp it = *($field_styp*)array_get(a, i);') - } - if should_use_indent_func(sym.kind) && !sym_has_str_method { - if is_elem_ptr { - g.auto_str_funcs.writeln('\t\tstring x = indent_${elem_str_fn_name}(*it, indent_count);') - } else { - g.auto_str_funcs.writeln('\t\tstring x = indent_${elem_str_fn_name}(it, indent_count);') - } - } else if sym.kind in [.f32, .f64] { - if sym.kind == .f32 { - g.auto_str_funcs.writeln('\t\tstring x = ${str_intp_g32('it')};') - } else { - g.auto_str_funcs.writeln('\t\tstring x = ${str_intp_g64('it')};') - } - } else if sym.kind == .rune { - // Rune are managed at this level as strings - g.auto_str_funcs.writeln('\t\tstring x = str_intp(2, _MOV((StrIntpData[]){{_SLIT("\`"), $si_s_code, {.d_s = ${elem_str_fn_name}(it) }}, {_SLIT("\`"), 0, {.d_c = 0 }}}));\n') - } else if sym.kind == .string { - g.auto_str_funcs.writeln('\t\tstring x = str_intp(2, _MOV((StrIntpData[]){{_SLIT("\'"), $si_s_code, {.d_s = it }}, {_SLIT("\'"), 0, {.d_c = 0 }}}));\n') - } else { - // There is a custom .str() method, so use it. - // NB: we need to take account of whether the user has defined - // `fn (x T) str() {` or `fn (x &T) str() {`, and convert accordingly - deref, deref_label := deref_kind(str_method_expects_ptr, is_elem_ptr, typ) - g.auto_str_funcs.writeln('\t\tstrings__Builder_write_string(&sb, _SLIT("$deref_label"));') - g.auto_str_funcs.writeln('\t\tstring x = ${elem_str_fn_name}( $deref it);') - } - } - g.auto_str_funcs.writeln('\t\tstrings__Builder_write_string(&sb, x);') - if g.is_autofree && typ != ast.bool_type { - // no need to free "true"/"false" literals - g.auto_str_funcs.writeln('\t\tstring_free(&x);') - } - g.auto_str_funcs.writeln('\t\tif (i < a.len-1) {') - g.auto_str_funcs.writeln('\t\t\tstrings__Builder_write_string(&sb, _SLIT(", "));') - g.auto_str_funcs.writeln('\t\t}') - g.auto_str_funcs.writeln('\t}') - g.auto_str_funcs.writeln('\tstrings__Builder_write_string(&sb, _SLIT("]"));') - g.auto_str_funcs.writeln('\tstring res = strings__Builder_str(&sb);') - g.auto_str_funcs.writeln('\tstrings__Builder_free(&sb);') - g.auto_str_funcs.writeln('\treturn res;') - g.auto_str_funcs.writeln('}') -} - -fn (mut g Gen) gen_str_for_array_fixed(info ast.ArrayFixed, styp string, str_fn_name string) { - mut typ := info.elem_type - mut sym := g.table.get_type_symbol(info.elem_type) - if mut sym.info is ast.Alias { - typ = sym.info.parent_type - sym = g.table.get_type_symbol(typ) - } - field_styp := g.typ(typ) - is_elem_ptr := typ.is_ptr() - sym_has_str_method, str_method_expects_ptr, _ := sym.str_method_info() - mut elem_str_fn_name := '' - if sym_has_str_method { - elem_str_fn_name = if is_elem_ptr { - field_styp.replace('*', '') + '_str' - } else { - field_styp + '_str' - } - } else { - elem_str_fn_name = styp_to_str_fn_name(field_styp) - } - if !sym.has_method('str') { - elem_str_fn_name = g.gen_str_for_type(typ) - } - g.type_definitions.writeln('static string ${str_fn_name}($styp a); // auto') - g.auto_str_funcs.writeln('static string ${str_fn_name}($styp a) { return indent_${str_fn_name}(a, 0);}') - g.type_definitions.writeln('static string indent_${str_fn_name}($styp a, int indent_count); // auto') - g.auto_str_funcs.writeln('static string indent_${str_fn_name}($styp a, int indent_count) {') - g.auto_str_funcs.writeln('\tstrings__Builder sb = strings__new_builder($info.size * 10);') - g.auto_str_funcs.writeln('\tstrings__Builder_write_string(&sb, _SLIT("["));') - if sym.kind == .function { - g.auto_str_funcs.writeln('\t\tstring x = ${elem_str_fn_name}();') - } else { - deref, deref_label := deref_kind(str_method_expects_ptr, is_elem_ptr, typ) - g.auto_str_funcs.writeln('\tfor (int i = 0; i < $info.size; ++i) {') - if should_use_indent_func(sym.kind) && !sym_has_str_method { - if is_elem_ptr { - g.auto_str_funcs.writeln('\t\tstrings__Builder_write_string(&sb, _SLIT("$deref_label"));') - g.auto_str_funcs.writeln('\t\tif ( 0 == a[i] ) {') - g.auto_str_funcs.writeln('\t\t\tstrings__Builder_write_string(&sb, _SLIT("0"));') - g.auto_str_funcs.writeln('\t\t}else{') - g.auto_str_funcs.writeln('\t\t\tstrings__Builder_write_string(&sb, ${elem_str_fn_name}( $deref a[i]) );') - g.auto_str_funcs.writeln('\t\t}') - } else { - g.auto_str_funcs.writeln('\t\tstrings__Builder_write_string(&sb, ${elem_str_fn_name}( $deref a[i]) );') - } - } else if sym.kind in [.f32, .f64] { - if sym.kind == .f32 { - g.auto_str_funcs.writeln('\t\tstrings__Builder_write_string(&sb, ${str_intp_g32('a[i]')} );') - } else { - g.auto_str_funcs.writeln('\t\tstrings__Builder_write_string(&sb, ${str_intp_g64('a[i]')} );') - } - } else if sym.kind == .string { - g.auto_str_funcs.writeln('\t\tstrings__Builder_write_string(&sb, ${str_intp_sq('a[i]')});') - } else if sym.kind == .rune { - tmp_str := str_intp_rune('${elem_str_fn_name}( $deref a[i])') - g.auto_str_funcs.writeln('\t\tstrings__Builder_write_string(&sb, $tmp_str);') - } else { - g.auto_str_funcs.writeln('\t\tstrings__Builder_write_string(&sb, ${elem_str_fn_name}( $deref a[i]));') - } - } - g.auto_str_funcs.writeln('\t\tif (i < ${info.size - 1}) {') - g.auto_str_funcs.writeln('\t\t\tstrings__Builder_write_string(&sb, _SLIT(", "));') - g.auto_str_funcs.writeln('\t\t}') - g.auto_str_funcs.writeln('\t}') - g.auto_str_funcs.writeln('\tstrings__Builder_write_string(&sb, _SLIT("]"));') - g.auto_str_funcs.writeln('\tstring res = strings__Builder_str(&sb);') - g.auto_str_funcs.writeln('\tstrings__Builder_free(&sb);') - g.auto_str_funcs.writeln('\treturn res;') - g.auto_str_funcs.writeln('}') -} diff --git a/vlib/v/gen/c/auto_str_map.v b/vlib/v/gen/c/auto_str_map.v deleted file mode 100644 index 0f6424aa31..0000000000 --- a/vlib/v/gen/c/auto_str_map.v +++ /dev/null @@ -1,85 +0,0 @@ -module c - -// Copyright (c) 2019-2021 Alexander Medvednikov. 2021 Dario Deledda. All rights reserved. -// Use of this source code is governed by an MIT license -// that can be found in the LICENSE file. -import v.ast - -fn (mut g Gen) gen_str_for_map(info ast.Map, styp string, str_fn_name string) { - mut key_typ := info.key_type - mut key_sym := g.table.get_type_symbol(key_typ) - if mut key_sym.info is ast.Alias { - key_typ = key_sym.info.parent_type - key_sym = g.table.get_type_symbol(key_typ) - } - key_styp := g.typ(key_typ) - key_str_fn_name := key_styp.replace('*', '') + '_str' - if !key_sym.has_method('str') { - g.gen_str_for_type(key_typ) - } - - mut val_typ := info.value_type - mut val_sym := g.table.get_type_symbol(val_typ) - if mut val_sym.info is ast.Alias { - val_typ = val_sym.info.parent_type - val_sym = g.table.get_type_symbol(val_typ) - } - val_styp := g.typ(val_typ) - elem_str_fn_name := val_styp.replace('*', '') + '_str' - if !val_sym.has_method('str') { - g.gen_str_for_type(val_typ) - } - - g.type_definitions.writeln('static string ${str_fn_name}($styp m); // auto') - g.auto_str_funcs.writeln('static string ${str_fn_name}($styp m) { return indent_${str_fn_name}(m, 0);}') - g.type_definitions.writeln('static string indent_${str_fn_name}($styp m, int indent_count); // auto') - g.auto_str_funcs.writeln('static string indent_${str_fn_name}($styp m, int indent_count) { /* gen_str_for_map */') - g.auto_str_funcs.writeln('\tstrings__Builder sb = strings__new_builder(m.key_values.len*10);') - g.auto_str_funcs.writeln('\tstrings__Builder_write_string(&sb, _SLIT("{"));') - g.auto_str_funcs.writeln('\tfor (int i = 0; i < m.key_values.len; ++i) {') - g.auto_str_funcs.writeln('\t\tif (!DenseArray_has_index(&m.key_values, i)) { continue; }') - - if key_sym.kind == .string { - g.auto_str_funcs.writeln('\t\tstring key = *(string*)DenseArray_key(&m.key_values, i);') - } else { - g.auto_str_funcs.writeln('\t\t$key_styp key = *($key_styp*)DenseArray_key(&m.key_values, i);') - } - if key_sym.kind == .string { - g.auto_str_funcs.writeln('\t\tstrings__Builder_write_string(&sb, ${str_intp_sq('key')});') - } else if key_sym.kind == .rune { - tmp_str := str_intp_rune('${key_str_fn_name}(key)') - g.auto_str_funcs.writeln('\t\tstrings__Builder_write_string(&sb, $tmp_str);') - } else { - g.auto_str_funcs.writeln('\t\tstrings__Builder_write_string(&sb, ${key_str_fn_name}(key));') - } - g.auto_str_funcs.writeln('\t\tstrings__Builder_write_string(&sb, _SLIT(": "));') - if val_sym.kind == .function { - g.auto_str_funcs.writeln('\t\tstrings__Builder_write_string(&sb, ${elem_str_fn_name}());') - } else if val_sym.kind == .string { - tmp_str := str_intp_sq('*($val_styp*)DenseArray_value(&m.key_values, i)') - g.auto_str_funcs.writeln('\t\tstrings__Builder_write_string(&sb, $tmp_str);') - } else if should_use_indent_func(val_sym.kind) && !val_sym.has_method('str') { - g.auto_str_funcs.writeln('\t\tstrings__Builder_write_string(&sb, indent_${elem_str_fn_name}(*($val_styp*)DenseArray_value(&m.key_values, i), indent_count));') - } else if val_sym.kind in [.f32, .f64] { - tmp_val := '*($val_styp*)DenseArray_value(&m.key_values, i)' - if val_sym.kind == .f32 { - g.auto_str_funcs.writeln('\t\tstrings__Builder_write_string(&sb, ${str_intp_g32(tmp_val)});') - } else { - g.auto_str_funcs.writeln('\t\tstrings__Builder_write_string(&sb, ${str_intp_g64(tmp_val)});') - } - } else if val_sym.kind == .rune { - tmp_str := str_intp_rune('${elem_str_fn_name}(*($val_styp*)DenseArray_value(&m.key_values, i))') - g.auto_str_funcs.writeln('\t\tstrings__Builder_write_string(&sb, $tmp_str);') - } else { - g.auto_str_funcs.writeln('\t\tstrings__Builder_write_string(&sb, ${elem_str_fn_name}(*($val_styp*)DenseArray_value(&m.key_values, i)));') - } - g.auto_str_funcs.writeln('\t\tif (i != m.key_values.len-1) {') - g.auto_str_funcs.writeln('\t\t\tstrings__Builder_write_string(&sb, _SLIT(", "));') - g.auto_str_funcs.writeln('\t\t}') - g.auto_str_funcs.writeln('\t}') - g.auto_str_funcs.writeln('\tstrings__Builder_write_string(&sb, _SLIT("}"));') - g.auto_str_funcs.writeln('\tstring res = strings__Builder_str(&sb);') - g.auto_str_funcs.writeln('\tstrings__Builder_free(&sb);') - g.auto_str_funcs.writeln('\treturn res;') - g.auto_str_funcs.writeln('}') -} diff --git a/vlib/v/gen/c/auto_str_methods.v b/vlib/v/gen/c/auto_str_methods.v index fecfa6b78e..9cf8cc5f83 100644 --- a/vlib/v/gen/c/auto_str_methods.v +++ b/vlib/v/gen/c/auto_str_methods.v @@ -4,6 +4,7 @@ module c import v.ast import v.util +import strings pub enum StrIntpType { si_no_str = 0 // no parameter to print only fix string @@ -512,3 +513,429 @@ fn deref_kind(str_method_expects_ptr bool, is_elem_ptr bool, typ ast.Type) (stri } return '', '' } + +fn (mut g Gen) gen_str_for_array(info ast.Array, styp string, str_fn_name string) { + mut typ := info.elem_type + mut sym := g.table.get_type_symbol(info.elem_type) + if mut sym.info is ast.Alias { + typ = sym.info.parent_type + sym = g.table.get_type_symbol(typ) + } + field_styp := g.typ(typ) + is_elem_ptr := typ.is_ptr() + sym_has_str_method, str_method_expects_ptr, _ := sym.str_method_info() + mut elem_str_fn_name := '' + if sym_has_str_method { + elem_str_fn_name = if is_elem_ptr { + field_styp.replace('*', '') + '_str' + } else { + field_styp + '_str' + } + if sym.kind == .byte { + elem_str_fn_name = elem_str_fn_name + '_escaped' + } + } else { + elem_str_fn_name = styp_to_str_fn_name(field_styp) + } + if !sym_has_str_method { + g.gen_str_for_type(typ) + } + g.type_definitions.writeln('static string ${str_fn_name}($styp a); // auto') + g.auto_str_funcs.writeln('static string ${str_fn_name}($styp a) { return indent_${str_fn_name}(a, 0);}') + g.type_definitions.writeln('static string indent_${str_fn_name}($styp a, int indent_count); // auto') + g.auto_str_funcs.writeln('static string indent_${str_fn_name}($styp a, int indent_count) {') + g.auto_str_funcs.writeln('\tstrings__Builder sb = strings__new_builder(a.len * 10);') + g.auto_str_funcs.writeln('\tstrings__Builder_write_string(&sb, _SLIT("["));') + g.auto_str_funcs.writeln('\tfor (int i = 0; i < a.len; ++i) {') + if sym.kind == .function { + g.auto_str_funcs.writeln('\t\tstring x = ${elem_str_fn_name}();') + } else { + if sym.kind == .array_fixed { + g.auto_str_funcs.writeln('\t\t$field_styp it;') + g.auto_str_funcs.writeln('\t\tmemcpy(*($field_styp*)it, (byte*)array_get(a, i), sizeof($field_styp));') + } else { + g.auto_str_funcs.writeln('\t\t$field_styp it = *($field_styp*)array_get(a, i);') + } + if should_use_indent_func(sym.kind) && !sym_has_str_method { + if is_elem_ptr { + g.auto_str_funcs.writeln('\t\tstring x = indent_${elem_str_fn_name}(*it, indent_count);') + } else { + g.auto_str_funcs.writeln('\t\tstring x = indent_${elem_str_fn_name}(it, indent_count);') + } + } else if sym.kind in [.f32, .f64] { + if sym.kind == .f32 { + g.auto_str_funcs.writeln('\t\tstring x = ${str_intp_g32('it')};') + } else { + g.auto_str_funcs.writeln('\t\tstring x = ${str_intp_g64('it')};') + } + } else if sym.kind == .rune { + // Rune are managed at this level as strings + g.auto_str_funcs.writeln('\t\tstring x = str_intp(2, _MOV((StrIntpData[]){{_SLIT("\`"), $c.si_s_code, {.d_s = ${elem_str_fn_name}(it) }}, {_SLIT("\`"), 0, {.d_c = 0 }}}));\n') + } else if sym.kind == .string { + g.auto_str_funcs.writeln('\t\tstring x = str_intp(2, _MOV((StrIntpData[]){{_SLIT("\'"), $c.si_s_code, {.d_s = it }}, {_SLIT("\'"), 0, {.d_c = 0 }}}));\n') + } else { + // There is a custom .str() method, so use it. + // NB: we need to take account of whether the user has defined + // `fn (x T) str() {` or `fn (x &T) str() {`, and convert accordingly + deref, deref_label := deref_kind(str_method_expects_ptr, is_elem_ptr, typ) + g.auto_str_funcs.writeln('\t\tstrings__Builder_write_string(&sb, _SLIT("$deref_label"));') + g.auto_str_funcs.writeln('\t\tstring x = ${elem_str_fn_name}( $deref it);') + } + } + g.auto_str_funcs.writeln('\t\tstrings__Builder_write_string(&sb, x);') + if g.is_autofree && typ != ast.bool_type { + // no need to free "true"/"false" literals + g.auto_str_funcs.writeln('\t\tstring_free(&x);') + } + g.auto_str_funcs.writeln('\t\tif (i < a.len-1) {') + g.auto_str_funcs.writeln('\t\t\tstrings__Builder_write_string(&sb, _SLIT(", "));') + g.auto_str_funcs.writeln('\t\t}') + g.auto_str_funcs.writeln('\t}') + g.auto_str_funcs.writeln('\tstrings__Builder_write_string(&sb, _SLIT("]"));') + g.auto_str_funcs.writeln('\tstring res = strings__Builder_str(&sb);') + g.auto_str_funcs.writeln('\tstrings__Builder_free(&sb);') + g.auto_str_funcs.writeln('\treturn res;') + g.auto_str_funcs.writeln('}') +} + +fn (mut g Gen) gen_str_for_array_fixed(info ast.ArrayFixed, styp string, str_fn_name string) { + mut typ := info.elem_type + mut sym := g.table.get_type_symbol(info.elem_type) + if mut sym.info is ast.Alias { + typ = sym.info.parent_type + sym = g.table.get_type_symbol(typ) + } + field_styp := g.typ(typ) + is_elem_ptr := typ.is_ptr() + sym_has_str_method, str_method_expects_ptr, _ := sym.str_method_info() + mut elem_str_fn_name := '' + if sym_has_str_method { + elem_str_fn_name = if is_elem_ptr { + field_styp.replace('*', '') + '_str' + } else { + field_styp + '_str' + } + } else { + elem_str_fn_name = styp_to_str_fn_name(field_styp) + } + if !sym.has_method('str') { + elem_str_fn_name = g.gen_str_for_type(typ) + } + g.type_definitions.writeln('static string ${str_fn_name}($styp a); // auto') + g.auto_str_funcs.writeln('static string ${str_fn_name}($styp a) { return indent_${str_fn_name}(a, 0);}') + g.type_definitions.writeln('static string indent_${str_fn_name}($styp a, int indent_count); // auto') + g.auto_str_funcs.writeln('static string indent_${str_fn_name}($styp a, int indent_count) {') + g.auto_str_funcs.writeln('\tstrings__Builder sb = strings__new_builder($info.size * 10);') + g.auto_str_funcs.writeln('\tstrings__Builder_write_string(&sb, _SLIT("["));') + if sym.kind == .function { + g.auto_str_funcs.writeln('\t\tstring x = ${elem_str_fn_name}();') + } else { + deref, deref_label := deref_kind(str_method_expects_ptr, is_elem_ptr, typ) + g.auto_str_funcs.writeln('\tfor (int i = 0; i < $info.size; ++i) {') + if should_use_indent_func(sym.kind) && !sym_has_str_method { + if is_elem_ptr { + g.auto_str_funcs.writeln('\t\tstrings__Builder_write_string(&sb, _SLIT("$deref_label"));') + g.auto_str_funcs.writeln('\t\tif ( 0 == a[i] ) {') + g.auto_str_funcs.writeln('\t\t\tstrings__Builder_write_string(&sb, _SLIT("0"));') + g.auto_str_funcs.writeln('\t\t}else{') + g.auto_str_funcs.writeln('\t\t\tstrings__Builder_write_string(&sb, ${elem_str_fn_name}( $deref a[i]) );') + g.auto_str_funcs.writeln('\t\t}') + } else { + g.auto_str_funcs.writeln('\t\tstrings__Builder_write_string(&sb, ${elem_str_fn_name}( $deref a[i]) );') + } + } else if sym.kind in [.f32, .f64] { + if sym.kind == .f32 { + g.auto_str_funcs.writeln('\t\tstrings__Builder_write_string(&sb, ${str_intp_g32('a[i]')} );') + } else { + g.auto_str_funcs.writeln('\t\tstrings__Builder_write_string(&sb, ${str_intp_g64('a[i]')} );') + } + } else if sym.kind == .string { + g.auto_str_funcs.writeln('\t\tstrings__Builder_write_string(&sb, ${str_intp_sq('a[i]')});') + } else if sym.kind == .rune { + tmp_str := str_intp_rune('${elem_str_fn_name}( $deref a[i])') + g.auto_str_funcs.writeln('\t\tstrings__Builder_write_string(&sb, $tmp_str);') + } else { + g.auto_str_funcs.writeln('\t\tstrings__Builder_write_string(&sb, ${elem_str_fn_name}( $deref a[i]));') + } + } + g.auto_str_funcs.writeln('\t\tif (i < ${info.size - 1}) {') + g.auto_str_funcs.writeln('\t\t\tstrings__Builder_write_string(&sb, _SLIT(", "));') + g.auto_str_funcs.writeln('\t\t}') + g.auto_str_funcs.writeln('\t}') + g.auto_str_funcs.writeln('\tstrings__Builder_write_string(&sb, _SLIT("]"));') + g.auto_str_funcs.writeln('\tstring res = strings__Builder_str(&sb);') + g.auto_str_funcs.writeln('\tstrings__Builder_free(&sb);') + g.auto_str_funcs.writeln('\treturn res;') + g.auto_str_funcs.writeln('}') +} + +fn (mut g Gen) gen_str_for_map(info ast.Map, styp string, str_fn_name string) { + mut key_typ := info.key_type + mut key_sym := g.table.get_type_symbol(key_typ) + if mut key_sym.info is ast.Alias { + key_typ = key_sym.info.parent_type + key_sym = g.table.get_type_symbol(key_typ) + } + key_styp := g.typ(key_typ) + key_str_fn_name := key_styp.replace('*', '') + '_str' + if !key_sym.has_method('str') { + g.gen_str_for_type(key_typ) + } + + mut val_typ := info.value_type + mut val_sym := g.table.get_type_symbol(val_typ) + if mut val_sym.info is ast.Alias { + val_typ = val_sym.info.parent_type + val_sym = g.table.get_type_symbol(val_typ) + } + val_styp := g.typ(val_typ) + elem_str_fn_name := val_styp.replace('*', '') + '_str' + if !val_sym.has_method('str') { + g.gen_str_for_type(val_typ) + } + + g.type_definitions.writeln('static string ${str_fn_name}($styp m); // auto') + g.auto_str_funcs.writeln('static string ${str_fn_name}($styp m) { return indent_${str_fn_name}(m, 0);}') + g.type_definitions.writeln('static string indent_${str_fn_name}($styp m, int indent_count); // auto') + g.auto_str_funcs.writeln('static string indent_${str_fn_name}($styp m, int indent_count) { /* gen_str_for_map */') + g.auto_str_funcs.writeln('\tstrings__Builder sb = strings__new_builder(m.key_values.len*10);') + g.auto_str_funcs.writeln('\tstrings__Builder_write_string(&sb, _SLIT("{"));') + g.auto_str_funcs.writeln('\tfor (int i = 0; i < m.key_values.len; ++i) {') + g.auto_str_funcs.writeln('\t\tif (!DenseArray_has_index(&m.key_values, i)) { continue; }') + + if key_sym.kind == .string { + g.auto_str_funcs.writeln('\t\tstring key = *(string*)DenseArray_key(&m.key_values, i);') + } else { + g.auto_str_funcs.writeln('\t\t$key_styp key = *($key_styp*)DenseArray_key(&m.key_values, i);') + } + if key_sym.kind == .string { + g.auto_str_funcs.writeln('\t\tstrings__Builder_write_string(&sb, ${str_intp_sq('key')});') + } else if key_sym.kind == .rune { + tmp_str := str_intp_rune('${key_str_fn_name}(key)') + g.auto_str_funcs.writeln('\t\tstrings__Builder_write_string(&sb, $tmp_str);') + } else { + g.auto_str_funcs.writeln('\t\tstrings__Builder_write_string(&sb, ${key_str_fn_name}(key));') + } + g.auto_str_funcs.writeln('\t\tstrings__Builder_write_string(&sb, _SLIT(": "));') + if val_sym.kind == .function { + g.auto_str_funcs.writeln('\t\tstrings__Builder_write_string(&sb, ${elem_str_fn_name}());') + } else if val_sym.kind == .string { + tmp_str := str_intp_sq('*($val_styp*)DenseArray_value(&m.key_values, i)') + g.auto_str_funcs.writeln('\t\tstrings__Builder_write_string(&sb, $tmp_str);') + } else if should_use_indent_func(val_sym.kind) && !val_sym.has_method('str') { + g.auto_str_funcs.writeln('\t\tstrings__Builder_write_string(&sb, indent_${elem_str_fn_name}(*($val_styp*)DenseArray_value(&m.key_values, i), indent_count));') + } else if val_sym.kind in [.f32, .f64] { + tmp_val := '*($val_styp*)DenseArray_value(&m.key_values, i)' + if val_sym.kind == .f32 { + g.auto_str_funcs.writeln('\t\tstrings__Builder_write_string(&sb, ${str_intp_g32(tmp_val)});') + } else { + g.auto_str_funcs.writeln('\t\tstrings__Builder_write_string(&sb, ${str_intp_g64(tmp_val)});') + } + } else if val_sym.kind == .rune { + tmp_str := str_intp_rune('${elem_str_fn_name}(*($val_styp*)DenseArray_value(&m.key_values, i))') + g.auto_str_funcs.writeln('\t\tstrings__Builder_write_string(&sb, $tmp_str);') + } else { + g.auto_str_funcs.writeln('\t\tstrings__Builder_write_string(&sb, ${elem_str_fn_name}(*($val_styp*)DenseArray_value(&m.key_values, i)));') + } + g.auto_str_funcs.writeln('\t\tif (i != m.key_values.len-1) {') + g.auto_str_funcs.writeln('\t\t\tstrings__Builder_write_string(&sb, _SLIT(", "));') + g.auto_str_funcs.writeln('\t\t}') + g.auto_str_funcs.writeln('\t}') + g.auto_str_funcs.writeln('\tstrings__Builder_write_string(&sb, _SLIT("}"));') + g.auto_str_funcs.writeln('\tstring res = strings__Builder_str(&sb);') + g.auto_str_funcs.writeln('\tstrings__Builder_free(&sb);') + g.auto_str_funcs.writeln('\treturn res;') + g.auto_str_funcs.writeln('}') +} + +fn (g &Gen) type_to_fmt1(typ ast.Type) StrIntpType { + if typ == ast.byte_type_idx { + return .si_u8 + } + if typ == ast.char_type_idx { + return .si_c + } + if typ == ast.voidptr_type_idx || typ in ast.byteptr_types { + return .si_p + } + if typ in ast.charptr_types { + return .si_s + // return '%C\\000' // a C string + } + sym := g.table.get_type_symbol(typ) + if typ.is_ptr() && (typ.is_int_valptr() || typ.is_float_valptr()) { + return .si_s + } else if sym.kind in [.struct_, .array, .array_fixed, .map, .bool, .enum_, .interface_, + .sum_type, .function, .alias, .chan] { + return .si_s + } else if sym.kind == .string { + return .si_s + // return "'%.*s\\000'" + } else if sym.kind in [.f32, .f64] { + if sym.kind == .f32 { + return .si_g32 + } + return .si_g64 + } else if sym.kind == .int { + return .si_i32 + } else if sym.kind == .u32 { + return .si_u32 + } else if sym.kind == .u64 { + return .si_u64 + } else if sym.kind == .i64 { + return .si_i64 + } + return .si_i32 +} + +fn (mut g Gen) gen_str_for_struct(info ast.Struct, styp string, str_fn_name string) { + // _str() functions should have a single argument, the indenting ones take 2: + g.type_definitions.writeln('static string ${str_fn_name}($styp it); // auto') + g.auto_str_funcs.writeln('static string ${str_fn_name}($styp it) { return indent_${str_fn_name}(it, 0);}') + g.type_definitions.writeln('static string indent_${str_fn_name}($styp it, int indent_count); // auto') + mut fn_builder := strings.new_builder(512) + defer { + g.auto_fn_definitions << fn_builder.str() + } + fn_builder.writeln('static string indent_${str_fn_name}($styp it, int indent_count) {') + mut clean_struct_v_type_name := styp.replace('__', '.') + if clean_struct_v_type_name.contains('_T_') { + // TODO: this is a bit hacky. styp shouldn't be even parsed with _T_ + // use something different than g.typ for styp + clean_struct_v_type_name = + clean_struct_v_type_name.replace('Array_', '[]').replace('_T_', '<').replace('_', ', ') + + '>' + } + clean_struct_v_type_name = util.strip_main_name(clean_struct_v_type_name) + // generate ident / indent length = 4 spaces + if info.fields.len == 0 { + fn_builder.writeln('\treturn _SLIT("$clean_struct_v_type_name{}");') + fn_builder.writeln('}') + fn_builder.writeln('') + return + } + + fn_builder.writeln('\tstring indents = string_repeat(_SLIT(" "), indent_count);') + fn_builder.writeln('\tstring res = str_intp( ${info.fields.len * 4 + 3}, _MOV((StrIntpData[]){') + fn_builder.writeln('\t\t{_SLIT("$clean_struct_v_type_name{\\n"), 0, {.d_c=0}},') + + for i, field in info.fields { + mut ptr_amp := if field.typ.is_ptr() { '&' } else { '' } + base_fmt := g.type_to_fmt1(g.unwrap_generic(field.typ)) + + // manage prefix and quote symbol for the filed + mut quote_str := '' + mut prefix := '' + sym := g.table.get_type_symbol(g.unwrap_generic(field.typ)) + if sym.kind == .string { + quote_str = "'" + } else if field.typ in ast.charptr_types { + quote_str = '\\"' + prefix = 'C' + } + + // first fields doesn't need \n + if i == 0 { + fn_builder.write_string('\t\t{_SLIT0, $c.si_s_code, {.d_s=indents}}, {_SLIT(" $field.name: $ptr_amp$prefix"), 0, {.d_c=0}}, ') + } else { + fn_builder.write_string('\t\t{_SLIT("\\n"), $c.si_s_code, {.d_s=indents}}, {_SLIT(" $field.name: $ptr_amp$prefix"), 0, {.d_c=0}}, ') + } + + // custom methods management + has_custom_str := sym.has_method('str') + mut field_styp := g.typ(field.typ).replace('*', '') + field_styp_fn_name := if has_custom_str { + '${field_styp}_str' + } else { + g.gen_str_for_type(field.typ) + } + + // manage the fact hat with float we use always the g representation + if sym.kind !in [.f32, .f64] { + fn_builder.write_string('{_SLIT("$quote_str"), ${int(base_fmt)}, {.${data_str(base_fmt)}=') + } else { + g_fmt := '0x' + (u32(base_fmt) | u32(0x7F) << 9).hex() + fn_builder.write_string('{_SLIT("$quote_str"), $g_fmt, {.${data_str(base_fmt)}=') + } + + mut func := struct_auto_str_func1(sym, field.typ, field_styp_fn_name, field.name) + + // manage reference types can be "nil" + if field.typ.is_ptr() && !(field.typ in ast.charptr_types + || field.typ in ast.byteptr_types || field.typ == ast.voidptr_type_idx) { + fn_builder.write_string('isnil(it.${c_name(field.name)})') + fn_builder.write_string(' ? _SLIT("nil") : ') + // struct, floats and ints have a special case through the _str function + if sym.kind != .struct_ && !field.typ.is_int_valptr() && !field.typ.is_float_valptr() { + fn_builder.write_string('*') + } + } + // handle circular ref type of struct to the struct itself + if styp == field_styp { + fn_builder.write_string('_SLIT("")') + } else { + // manage C charptr + if field.typ in ast.charptr_types { + fn_builder.write_string('tos2((byteptr)$func)') + } else { + fn_builder.write_string(func) + } + } + + fn_builder.writeln('}}, {_SLIT("$quote_str"), 0, {.d_c=0}},') + } + fn_builder.writeln('\t\t{_SLIT("\\n"), $c.si_s_code, {.d_s=indents}}, {_SLIT("}"), 0, {.d_c=0}},') + fn_builder.writeln('\t}));') + fn_builder.writeln('\tstring_free(&indents);') + fn_builder.writeln('\treturn res;') + fn_builder.writeln('}') +} + +fn struct_auto_str_func1(sym &ast.TypeSymbol, field_type ast.Type, fn_name string, field_name string) string { + has_custom_str, expects_ptr, _ := sym.str_method_info() + if sym.kind == .enum_ { + return '${fn_name}(it.${c_name(field_name)})' + } else if should_use_indent_func(sym.kind) { + mut obj := 'it.${c_name(field_name)}' + if field_type.is_ptr() && !expects_ptr { + obj = '*$obj' + } + if has_custom_str { + return '${fn_name}($obj)' + } + return 'indent_${fn_name}($obj, indent_count + 1)' + } else if sym.kind in [.array, .array_fixed, .map, .sum_type] { + if has_custom_str { + return '${fn_name}(it.${c_name(field_name)})' + } + return 'indent_${fn_name}(it.${c_name(field_name)}, indent_count + 1)' + } else if sym.kind == .function { + return '${fn_name}()' + } else { + if sym.kind == .chan { + return '${fn_name}(it.${c_name(field_name)})' + } + mut method_str := 'it.${c_name(field_name)}' + if sym.kind == .bool { + method_str += ' ? _SLIT("true") : _SLIT("false")' + } else if (field_type.is_int_valptr() || field_type.is_float_valptr()) + && field_type.is_ptr() && !expects_ptr { + // ptr int can be "nil", so this needs to be casted to a string + if sym.kind == .f32 { + return 'str_intp(1, _MOV((StrIntpData[]){ + {_SLIT0, $si_g32_code, {.d_f32 = *$method_str }} + }))' + } else if sym.kind == .f64 { + return 'str_intp(1, _MOV((StrIntpData[]){ + {_SLIT0, $si_g64_code, {.d_f64 = *$method_str }} + }))' + } else if sym.kind == .u64 { + fmt_type := StrIntpType.si_u64 + return 'str_intp(1, _MOV((StrIntpData[]){{_SLIT0, ${u32(fmt_type) | 0xfe00}, {.d_u64 = *$method_str }}}))' + } + fmt_type := StrIntpType.si_i32 + return 'str_intp(1, _MOV((StrIntpData[]){{_SLIT0, ${u32(fmt_type) | 0xfe00}, {.d_i32 = *$method_str }}}))' + } + return method_str + } +} diff --git a/vlib/v/gen/c/auto_str_struct.v b/vlib/v/gen/c/auto_str_struct.v deleted file mode 100644 index 8bcfc53169..0000000000 --- a/vlib/v/gen/c/auto_str_struct.v +++ /dev/null @@ -1,200 +0,0 @@ -module c - -// Copyright (c) 2019-2021 Alexander Medvednikov. 2021 Dario Deledda. All rights reserved. -// Use of this source code is governed by an MIT license -// that can be found in the LICENSE file. -import v.ast -import v.util -import strings - -fn (g &Gen) type_to_fmt1(typ ast.Type) StrIntpType { - if typ == ast.byte_type_idx { - return .si_u8 - } - if typ == ast.char_type_idx { - return .si_c - } - if typ == ast.voidptr_type_idx || typ in ast.byteptr_types { - return .si_p - } - if typ in ast.charptr_types { - return .si_s - // return '%C\\000' // a C string - } - sym := g.table.get_type_symbol(typ) - if typ.is_ptr() && (typ.is_int_valptr() || typ.is_float_valptr()) { - return .si_s - } else if sym.kind in [.struct_, .array, .array_fixed, .map, .bool, .enum_, .interface_, - .sum_type, .function, .alias, .chan] { - return .si_s - } else if sym.kind == .string { - return .si_s - // return "'%.*s\\000'" - } else if sym.kind in [.f32, .f64] { - if sym.kind == .f32 { - return .si_g32 - } - return .si_g64 - } else if sym.kind == .int { - return .si_i32 - } else if sym.kind == .u32 { - return .si_u32 - } else if sym.kind == .u64 { - return .si_u64 - } else if sym.kind == .i64 { - return .si_i64 - } - return .si_i32 -} - -fn (mut g Gen) gen_str_for_struct(info ast.Struct, styp string, str_fn_name string) { - // _str() functions should have a single argument, the indenting ones take 2: - g.type_definitions.writeln('static string ${str_fn_name}($styp it); // auto') - g.auto_str_funcs.writeln('static string ${str_fn_name}($styp it) { return indent_${str_fn_name}(it, 0);}') - g.type_definitions.writeln('static string indent_${str_fn_name}($styp it, int indent_count); // auto') - mut fn_builder := strings.new_builder(512) - defer { - g.auto_fn_definitions << fn_builder.str() - } - fn_builder.writeln('static string indent_${str_fn_name}($styp it, int indent_count) {') - mut clean_struct_v_type_name := styp.replace('__', '.') - if clean_struct_v_type_name.contains('_T_') { - // TODO: this is a bit hacky. styp shouldn't be even parsed with _T_ - // use something different than g.typ for styp - clean_struct_v_type_name = - clean_struct_v_type_name.replace('Array_', '[]').replace('_T_', '<').replace('_', ', ') + - '>' - } - clean_struct_v_type_name = util.strip_main_name(clean_struct_v_type_name) - // generate ident / indent length = 4 spaces - if info.fields.len == 0 { - fn_builder.writeln('\treturn _SLIT("$clean_struct_v_type_name{}");') - fn_builder.writeln('}') - fn_builder.writeln('') - return - } - - fn_builder.writeln('\tstring indents = string_repeat(_SLIT(" "), indent_count);') - fn_builder.writeln('\tstring res = str_intp( ${info.fields.len * 4 + 3}, _MOV((StrIntpData[]){') - fn_builder.writeln('\t\t{_SLIT("$clean_struct_v_type_name{\\n"), 0, {.d_c=0}},') - - for i, field in info.fields { - mut ptr_amp := if field.typ.is_ptr() { '&' } else { '' } - base_fmt := g.type_to_fmt1(g.unwrap_generic(field.typ)) - - // manage prefix and quote symbol for the filed - mut quote_str := '' - mut prefix := '' - sym := g.table.get_type_symbol(g.unwrap_generic(field.typ)) - if sym.kind == .string { - quote_str = "'" - } else if field.typ in ast.charptr_types { - quote_str = '\\"' - prefix = 'C' - } - - // first fields doesn't need \n - if i == 0 { - fn_builder.write_string('\t\t{_SLIT0, $si_s_code, {.d_s=indents}}, {_SLIT(" $field.name: $ptr_amp$prefix"), 0, {.d_c=0}}, ') - } else { - fn_builder.write_string('\t\t{_SLIT("\\n"), $si_s_code, {.d_s=indents}}, {_SLIT(" $field.name: $ptr_amp$prefix"), 0, {.d_c=0}}, ') - } - - // custom methods management - has_custom_str := sym.has_method('str') - mut field_styp := g.typ(field.typ).replace('*', '') - field_styp_fn_name := if has_custom_str { - '${field_styp}_str' - } else { - g.gen_str_for_type(field.typ) - } - - // manage the fact hat with float we use always the g representation - if sym.kind !in [.f32, .f64] { - fn_builder.write_string('{_SLIT("$quote_str"), ${int(base_fmt)}, {.${data_str(base_fmt)}=') - } else { - g_fmt := '0x' + (u32(base_fmt) | u32(0x7F) << 9).hex() - fn_builder.write_string('{_SLIT("$quote_str"), $g_fmt, {.${data_str(base_fmt)}=') - } - - mut func := struct_auto_str_func1(sym, field.typ, field_styp_fn_name, field.name) - - // manage reference types can be "nil" - if field.typ.is_ptr() && !(field.typ in ast.charptr_types - || field.typ in ast.byteptr_types || field.typ == ast.voidptr_type_idx) { - fn_builder.write_string('isnil(it.${c_name(field.name)})') - fn_builder.write_string(' ? _SLIT("nil") : ') - // struct, floats and ints have a special case through the _str function - if sym.kind != .struct_ && !field.typ.is_int_valptr() && !field.typ.is_float_valptr() { - fn_builder.write_string('*') - } - } - // handle circular ref type of struct to the struct itself - if styp == field_styp { - fn_builder.write_string('_SLIT("")') - } else { - // manage C charptr - if field.typ in ast.charptr_types { - fn_builder.write_string('tos2((byteptr)$func)') - } else { - fn_builder.write_string(func) - } - } - - fn_builder.writeln('}}, {_SLIT("$quote_str"), 0, {.d_c=0}},') - } - fn_builder.writeln('\t\t{_SLIT("\\n"), $si_s_code, {.d_s=indents}}, {_SLIT("}"), 0, {.d_c=0}},') - fn_builder.writeln('\t}));') - fn_builder.writeln('\tstring_free(&indents);') - fn_builder.writeln('\treturn res;') - fn_builder.writeln('}') -} - -fn struct_auto_str_func1(sym &ast.TypeSymbol, field_type ast.Type, fn_name string, field_name string) string { - has_custom_str, expects_ptr, _ := sym.str_method_info() - if sym.kind == .enum_ { - return '${fn_name}(it.${c_name(field_name)})' - } else if should_use_indent_func(sym.kind) { - mut obj := 'it.${c_name(field_name)}' - if field_type.is_ptr() && !expects_ptr { - obj = '*$obj' - } - if has_custom_str { - return '${fn_name}($obj)' - } - return 'indent_${fn_name}($obj, indent_count + 1)' - } else if sym.kind in [.array, .array_fixed, .map, .sum_type] { - if has_custom_str { - return '${fn_name}(it.${c_name(field_name)})' - } - return 'indent_${fn_name}(it.${c_name(field_name)}, indent_count + 1)' - } else if sym.kind == .function { - return '${fn_name}()' - } else { - if sym.kind == .chan { - return '${fn_name}(it.${c_name(field_name)})' - } - mut method_str := 'it.${c_name(field_name)}' - if sym.kind == .bool { - method_str += ' ? _SLIT("true") : _SLIT("false")' - } else if (field_type.is_int_valptr() || field_type.is_float_valptr()) - && field_type.is_ptr() && !expects_ptr { - // ptr int can be "nil", so this needs to be casted to a string - if sym.kind == .f32 { - return 'str_intp(1, _MOV((StrIntpData[]){ - {_SLIT0, $si_g32_code, {.d_f32 = *$method_str }} - }))' - } else if sym.kind == .f64 { - return 'str_intp(1, _MOV((StrIntpData[]){ - {_SLIT0, $si_g64_code, {.d_f64 = *$method_str }} - }))' - } else if sym.kind == .u64 { - fmt_type := StrIntpType.si_u64 - return 'str_intp(1, _MOV((StrIntpData[]){{_SLIT0, ${u32(fmt_type) | 0xfe00}, {.d_u64 = *$method_str }}}))' - } - fmt_type := StrIntpType.si_i32 - return 'str_intp(1, _MOV((StrIntpData[]){{_SLIT0, ${u32(fmt_type) | 0xfe00}, {.d_i32 = *$method_str }}}))' - } - return method_str - } -}