gen: fix errors of string interpolation of fn values in struct/array/map (#7367)

pull/7371/head
yuyi 2020-12-17 17:16:27 +08:00 committed by GitHub
parent c4c0b5eb06
commit b10f692c43
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 91 additions and 42 deletions

View File

@ -160,25 +160,29 @@ fn (mut g Gen) gen_str_for_array(info table.Array, styp string, str_fn_name stri
g.auto_str_funcs.writeln('\tstrings__Builder sb = strings__new_builder(a.len * 10);')
g.auto_str_funcs.writeln('\tstrings__Builder_write(&sb, _SLIT("["));')
g.auto_str_funcs.writeln('\tfor (int i = 0; i < a.len; ++i) {')
g.auto_str_funcs.writeln('\t\t$field_styp it = (*($field_styp*)array_get(a, i));')
if sym.kind == .struct_ && !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] {
g.auto_str_funcs.writeln('\t\tstring x = _STR("%g", 1, it);')
if sym.kind == .function {
g.auto_str_funcs.writeln('\t\tstring x = ${elem_str_fn_name}();')
} 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
if (str_method_expects_ptr && is_elem_ptr) || (!str_method_expects_ptr && !is_elem_ptr) {
g.auto_str_funcs.writeln('\t\tstring x = ${elem_str_fn_name}(it);')
} else if str_method_expects_ptr && !is_elem_ptr {
g.auto_str_funcs.writeln('\t\tstring x = ${elem_str_fn_name}(&it);')
} else if !str_method_expects_ptr && is_elem_ptr {
g.auto_str_funcs.writeln('\t\tstring x = ${elem_str_fn_name}(*it);')
g.auto_str_funcs.writeln('\t\t$field_styp it = (*($field_styp*)array_get(a, i));')
if sym.kind == .struct_ && !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] {
g.auto_str_funcs.writeln('\t\tstring x = _STR("%g", 1, it);')
} 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
if (str_method_expects_ptr && is_elem_ptr) || (!str_method_expects_ptr && !is_elem_ptr) {
g.auto_str_funcs.writeln('\t\tstring x = ${elem_str_fn_name}(it);')
} else if str_method_expects_ptr && !is_elem_ptr {
g.auto_str_funcs.writeln('\t\tstring x = ${elem_str_fn_name}(&it);')
} else if !str_method_expects_ptr && is_elem_ptr {
g.auto_str_funcs.writeln('\t\tstring x = ${elem_str_fn_name}(*it);')
}
}
}
g.auto_str_funcs.writeln('\t\tstrings__Builder_write(&sb, x);')
@ -224,20 +228,24 @@ fn (mut g Gen) gen_str_for_array_fixed(info table.ArrayFixed, styp string, str_f
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(&sb, _SLIT("["));')
g.auto_str_funcs.writeln('\tfor (int i = 0; i < $info.size; ++i) {')
if sym.kind == .struct_ && !sym_has_str_method {
g.auto_str_funcs.writeln('\t\tstrings__Builder_write(&sb, ${elem_str_fn_name}(a[i], indent_count));')
} else if sym.kind in [.f32, .f64] {
g.auto_str_funcs.writeln('\t\tstrings__Builder_write(&sb, _STR("%g", 1, a[i]));')
} else if sym.kind == .string {
g.auto_str_funcs.writeln('\t\tstrings__Builder_write(&sb, _STR("\'%.*s\\000\'", 2, a[i]));')
if sym.kind == .function {
g.auto_str_funcs.writeln('\t\tstring x = ${elem_str_fn_name}();')
} else {
if (str_method_expects_ptr && is_elem_ptr) || (!str_method_expects_ptr && !is_elem_ptr) {
g.auto_str_funcs.writeln('\t\tstrings__Builder_write(&sb, ${elem_str_fn_name}(a[i]));')
} else if str_method_expects_ptr && !is_elem_ptr {
g.auto_str_funcs.writeln('\t\tstrings__Builder_write(&sb, ${elem_str_fn_name}(&a[i]));')
} else if !str_method_expects_ptr && is_elem_ptr {
g.auto_str_funcs.writeln('\t\tstrings__Builder_write(&sb, ${elem_str_fn_name}(*a[i]));')
g.auto_str_funcs.writeln('\tfor (int i = 0; i < $info.size; ++i) {')
if sym.kind == .struct_ && !sym_has_str_method {
g.auto_str_funcs.writeln('\t\tstrings__Builder_write(&sb, ${elem_str_fn_name}(a[i], indent_count));')
} else if sym.kind in [.f32, .f64] {
g.auto_str_funcs.writeln('\t\tstrings__Builder_write(&sb, _STR("%g", 1, a[i]));')
} else if sym.kind == .string {
g.auto_str_funcs.writeln('\t\tstrings__Builder_write(&sb, _STR("\'%.*s\\000\'", 2, a[i]));')
} else {
if (str_method_expects_ptr && is_elem_ptr) || (!str_method_expects_ptr && !is_elem_ptr) {
g.auto_str_funcs.writeln('\t\tstrings__Builder_write(&sb, ${elem_str_fn_name}(a[i]));')
} else if str_method_expects_ptr && !is_elem_ptr {
g.auto_str_funcs.writeln('\t\tstrings__Builder_write(&sb, ${elem_str_fn_name}(&a[i]));')
} else if !str_method_expects_ptr && is_elem_ptr {
g.auto_str_funcs.writeln('\t\tstrings__Builder_write(&sb, ${elem_str_fn_name}(*a[i]));')
}
}
}
g.auto_str_funcs.writeln('\t\tif (i < ${info.size - 1}) {')
@ -271,15 +279,19 @@ fn (mut g Gen) gen_str_for_map(info table.Map, styp string, str_fn_name string)
g.auto_str_funcs.writeln('\t\tstring key = *(string*)DenseArray_key(&m.key_values, i);')
g.auto_str_funcs.writeln('\t\tstrings__Builder_write(&sb, _STR("\'%.*s\\000\'", 2, key));')
g.auto_str_funcs.writeln('\t\tstrings__Builder_write(&sb, _SLIT(": "));')
g.auto_str_funcs.writeln('\t\t$val_styp it = *($val_styp*)DenseArray_value(&m.key_values, i);')
if val_sym.kind == .string {
g.auto_str_funcs.writeln('\t\tstrings__Builder_write(&sb, _STR("\'%.*s\\000\'", 2, it));')
} else if val_sym.kind == .struct_ && !val_sym.has_method('str') {
g.auto_str_funcs.writeln('\t\tstrings__Builder_write(&sb, indent_${elem_str_fn_name}(it, indent_count));')
} else if val_sym.kind in [.f32, .f64] {
g.auto_str_funcs.writeln('\t\tstrings__Builder_write(&sb, _STR("%g", 1, it));')
if val_sym.kind == .function {
g.auto_str_funcs.writeln('\t\tstrings__Builder_write(&sb, ${elem_str_fn_name}());')
} else {
g.auto_str_funcs.writeln('\t\tstrings__Builder_write(&sb, ${elem_str_fn_name}(it));')
g.auto_str_funcs.writeln('\t\t$val_styp it = *($val_styp*)DenseArray_value(&m.key_values, i);')
if val_sym.kind == .string {
g.auto_str_funcs.writeln('\t\tstrings__Builder_write(&sb, _STR("\'%.*s\\000\'", 2, it));')
} else if val_sym.kind == .struct_ && !val_sym.has_method('str') {
g.auto_str_funcs.writeln('\t\tstrings__Builder_write(&sb, indent_${elem_str_fn_name}(it, indent_count));')
} else if val_sym.kind in [.f32, .f64] {
g.auto_str_funcs.writeln('\t\tstrings__Builder_write(&sb, _STR("%g", 1, it));')
} else {
g.auto_str_funcs.writeln('\t\tstrings__Builder_write(&sb, ${elem_str_fn_name}(it));')
}
}
g.auto_str_funcs.writeln('\t\tif (i != m.key_values.len-1) {')
g.auto_str_funcs.writeln('\t\t\tstrings__Builder_write(&sb, _SLIT(", "));')
@ -335,6 +347,8 @@ fn (mut g Gen) gen_str_for_multi_return(info table.MultiReturn, styp string, str
g.auto_str_funcs.writeln('\tstrings__Builder_write(&sb, _STR("%g", 1, a.arg$i));')
} else if sym.kind == .string {
g.auto_str_funcs.writeln('\tstrings__Builder_write(&sb, _STR("\'%.*s\\000\'", 2, a.arg$i));')
} else if sym.kind == .function {
g.auto_str_funcs.writeln('\tstrings__Builder_write(&sb, ${str_fn_name}());')
} else {
if (str_method_expects_ptr && is_arg_ptr) || (!str_method_expects_ptr && !is_arg_ptr) {
g.auto_str_funcs.writeln('\tstrings__Builder_write(&sb, ${arg_str_fn_name}(a.arg$i));')
@ -447,6 +461,8 @@ fn struct_auto_str_func(sym table.TypeSymbol, field_type table.Type, fn_name 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 {
mut method_str := 'it.${c_name(field_name)}'
if sym.kind == .bool {

View File

@ -5659,7 +5659,8 @@ fn (g &Gen) type_to_fmt(typ table.Type) string {
sym := g.table.get_type_symbol(typ)
if typ.is_ptr() && (typ.is_int() || typ.is_float()) {
return '%.*s\\000'
} else if sym.kind in [.struct_, .array, .array_fixed, .map, .bool, .enum_, .sum_type] {
} else if sym.kind in
[.struct_, .array, .array_fixed, .map, .bool, .enum_, .sum_type, .function] {
return '%.*s\\000'
} else if sym.kind == .string {
return "\'%.*s\\000\'"

View File

@ -177,7 +177,10 @@ fn (mut g Gen) string_inter_literal_sb_optimized(call_expr ast.CallExpr) {
typ := node.expr_types[i]
g.write(g.typ(typ))
g.write('_str(')
g.expr(node.exprs[i])
sym := g.table.get_type_symbol(typ)
if sym.kind != .function {
g.expr(node.exprs[i])
}
g.writeln('));')
}
g.writeln('')
@ -366,7 +369,9 @@ fn (mut g Gen) gen_expr_to_string(expr ast.Expr, etype table.Type) {
} else {
str_fn_name := g.gen_str_for_type(typ)
g.write('${str_fn_name}(')
g.expr(expr)
if sym.kind != .function {
g.expr(expr)
}
g.write(')')
}
}

View File

@ -10,3 +10,30 @@ fn test_function_interpolation() {
println(show)
assert '$show' == 'fn (string) string'
}
struct Info {
aa fn()string
bb int
}
fn test_function_interpolation_in_struct() {
a := Info{
aa: fn()string {return 'aaa'}
bb: 22
}
println(a)
assert '$a'.contains(': fn () string')
}
fn test_function_interpolation_in_array() {
f := [fn()string{return 'aaa'}, fn()string{return 'bbb'}]
println(f)
assert '$f' == '[fn () string, fn () string]'
}
fn test_function_interpolation_in_map() {
m := {'aaa': fn()string{return 'aaa'}, 'bbb': fn()string{return 'bbb'}}
println(m)
assert '$m'.contains(': fn () string')
}