cgen: generate str for variadic (#4587)
parent
4bcdf11743
commit
aacc3c6f7e
|
@ -16,7 +16,6 @@ const (
|
||||||
'vlib/v/tests/fixed_array_test.v',
|
'vlib/v/tests/fixed_array_test.v',
|
||||||
'vlib/v/tests/num_lit_call_method_test.v',
|
'vlib/v/tests/num_lit_call_method_test.v',
|
||||||
'vlib/v/tests/pointers_test.v',
|
'vlib/v/tests/pointers_test.v',
|
||||||
'vlib/v/tests/string_interpolation_variadic_test.v',
|
|
||||||
'vlib/v/tests/type_test.v',
|
'vlib/v/tests/type_test.v',
|
||||||
'vlib/v/tests/interface_test.v',
|
'vlib/v/tests/interface_test.v',
|
||||||
'vlib/v/tests/valgrind/valgrind_test.v', // ubuntu-musl only
|
'vlib/v/tests/valgrind/valgrind_test.v', // ubuntu-musl only
|
||||||
|
|
|
@ -2369,16 +2369,24 @@ fn (mut g Gen) string_inter_literal(node ast.StringInterLiteral) {
|
||||||
g.expr(expr)
|
g.expr(expr)
|
||||||
} else {
|
} else {
|
||||||
sym := g.table.get_type_symbol(node.expr_types[i])
|
sym := g.table.get_type_symbol(node.expr_types[i])
|
||||||
if sym.kind == .enum_ {
|
if node.expr_types[i].flag_is(.variadic) {
|
||||||
|
str_fn_name := g.gen_str_for_type(node.expr_types[i])
|
||||||
|
g.write('${str_fn_name}(')
|
||||||
|
g.expr(expr)
|
||||||
|
g.write(')')
|
||||||
|
g.write('.len, ')
|
||||||
|
g.write('${str_fn_name}(')
|
||||||
|
g.expr(expr)
|
||||||
|
g.write(').str')
|
||||||
|
}
|
||||||
|
else if sym.kind == .enum_ {
|
||||||
is_var := match node.exprs[i] {
|
is_var := match node.exprs[i] {
|
||||||
ast.SelectorExpr { true }
|
ast.SelectorExpr { true }
|
||||||
ast.Ident { true }
|
ast.Ident { true }
|
||||||
else { false }
|
else { false }
|
||||||
}
|
}
|
||||||
if is_var {
|
if is_var {
|
||||||
styp := g.typ(node.expr_types[i])
|
str_fn_name := g.gen_str_for_type(node.expr_types[i])
|
||||||
str_fn_name := styp_to_str_fn_name(styp)
|
|
||||||
g.gen_str_for_type(sym, styp, str_fn_name)
|
|
||||||
g.write('${str_fn_name}(')
|
g.write('${str_fn_name}(')
|
||||||
g.enum_expr(expr)
|
g.enum_expr(expr)
|
||||||
g.write(')')
|
g.write(')')
|
||||||
|
@ -2396,9 +2404,7 @@ fn (mut g Gen) string_inter_literal(node ast.StringInterLiteral) {
|
||||||
g.write('"')
|
g.write('"')
|
||||||
}
|
}
|
||||||
} else if sym.kind in [.array, .array_fixed] {
|
} else if sym.kind in [.array, .array_fixed] {
|
||||||
styp := g.typ(node.expr_types[i])
|
str_fn_name := g.gen_str_for_type(node.expr_types[i])
|
||||||
str_fn_name := styp_to_str_fn_name(styp)
|
|
||||||
g.gen_str_for_type(sym, styp, str_fn_name)
|
|
||||||
g.write('${str_fn_name}(')
|
g.write('${str_fn_name}(')
|
||||||
g.expr(expr)
|
g.expr(expr)
|
||||||
g.write(')')
|
g.write(')')
|
||||||
|
@ -2407,9 +2413,7 @@ fn (mut g Gen) string_inter_literal(node ast.StringInterLiteral) {
|
||||||
g.expr(expr)
|
g.expr(expr)
|
||||||
g.write(').str')
|
g.write(').str')
|
||||||
} else if sym.kind == .map && !sym.has_method('str') {
|
} else if sym.kind == .map && !sym.has_method('str') {
|
||||||
styp := g.typ(node.expr_types[i])
|
str_fn_name := g.gen_str_for_type(node.expr_types[i])
|
||||||
str_fn_name := styp_to_str_fn_name(styp)
|
|
||||||
g.gen_str_for_type(sym, styp, str_fn_name)
|
|
||||||
g.write('${str_fn_name}(')
|
g.write('${str_fn_name}(')
|
||||||
g.expr(expr)
|
g.expr(expr)
|
||||||
g.write(')')
|
g.write(')')
|
||||||
|
@ -2418,9 +2422,7 @@ fn (mut g Gen) string_inter_literal(node ast.StringInterLiteral) {
|
||||||
g.expr(expr)
|
g.expr(expr)
|
||||||
g.write(').str')
|
g.write(').str')
|
||||||
} else if sym.kind == .struct_ && !sym.has_method('str') {
|
} else if sym.kind == .struct_ && !sym.has_method('str') {
|
||||||
styp := g.typ(node.expr_types[i])
|
str_fn_name := g.gen_str_for_type(node.expr_types[i])
|
||||||
str_fn_name := styp_to_str_fn_name(styp)
|
|
||||||
g.gen_str_for_type(sym, styp, str_fn_name)
|
|
||||||
g.write('${str_fn_name}(')
|
g.write('${str_fn_name}(')
|
||||||
g.expr(expr)
|
g.expr(expr)
|
||||||
g.write(',0)')
|
g.write(',0)')
|
||||||
|
@ -2961,27 +2963,45 @@ fn (mut g Gen) is_expr(node ast.InfixExpr) {
|
||||||
g.expr(node.right)
|
g.expr(node.right)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[inline]
|
||||||
fn styp_to_str_fn_name(styp string) string {
|
fn styp_to_str_fn_name(styp string) string {
|
||||||
res := styp.replace('.', '__').replace('*', '_ptr') + '_str'
|
return styp.replace('*', '_ptr') + '_str'
|
||||||
return res
|
}
|
||||||
|
|
||||||
|
[inline]
|
||||||
|
fn (mut g Gen) gen_str_for_type(typ table.Type) string {
|
||||||
|
styp := g.typ(typ)
|
||||||
|
return g.gen_str_for_type_with_styp(typ, styp)
|
||||||
}
|
}
|
||||||
|
|
||||||
// already generated styp, reuse it
|
// already generated styp, reuse it
|
||||||
fn (mut g Gen) gen_str_for_type(sym table.TypeSymbol, styp, str_fn_name string) {
|
fn (mut g Gen) gen_str_for_type_with_styp(typ table.Type, styp string) string {
|
||||||
|
sym := g.table.get_type_symbol(typ)
|
||||||
|
str_fn_name := styp_to_str_fn_name(styp)
|
||||||
already_generated_key := '${styp}:${str_fn_name}'
|
already_generated_key := '${styp}:${str_fn_name}'
|
||||||
if sym.has_method('str') || already_generated_key in g.str_types {
|
// generate for type
|
||||||
return
|
if !sym.has_method('str') && !(already_generated_key in g.str_types) {
|
||||||
|
g.str_types << already_generated_key
|
||||||
|
match sym.info {
|
||||||
|
table.Alias { g.gen_str_default(sym, styp, str_fn_name) }
|
||||||
|
table.Array { g.gen_str_for_array(it, styp, str_fn_name) }
|
||||||
|
table.ArrayFixed { g.gen_str_for_array_fixed(it, styp, str_fn_name) }
|
||||||
|
table.Enum { g.gen_str_for_enum(it, styp, str_fn_name) }
|
||||||
|
table.Struct { g.gen_str_for_struct(it, styp, str_fn_name) }
|
||||||
|
table.Map { g.gen_str_for_map(it, styp, str_fn_name) }
|
||||||
|
else { verror("could not generate string method $str_fn_name for type \'${styp}\'") }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
g.str_types << already_generated_key
|
// if varg, generate str for varg
|
||||||
match sym.info {
|
if typ.flag_is(.variadic) {
|
||||||
table.Alias { g.gen_str_default(sym, styp, str_fn_name) }
|
varg_already_generated_key := 'varg_$already_generated_key'
|
||||||
table.Array { g.gen_str_for_array(it, styp, str_fn_name) }
|
if !(varg_already_generated_key in g.str_types) {
|
||||||
table.ArrayFixed { g.gen_str_for_array_fixed(it, styp, str_fn_name) }
|
g.gen_str_for_varg(styp, str_fn_name)
|
||||||
table.Enum { g.gen_str_for_enum(it, styp, str_fn_name) }
|
g.str_types << varg_already_generated_key
|
||||||
table.Struct { g.gen_str_for_struct(it, styp, str_fn_name) }
|
}
|
||||||
table.Map { g.gen_str_for_map(it, styp, str_fn_name) }
|
return 'varg_$str_fn_name'
|
||||||
else { verror("could not generate string method $str_fn_name for type \'${styp}\'") }
|
|
||||||
}
|
}
|
||||||
|
return str_fn_name
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (mut g Gen) gen_str_default(sym table.TypeSymbol, styp, str_fn_name string) {
|
fn (mut g Gen) gen_str_default(sym table.TypeSymbol, styp, str_fn_name string) {
|
||||||
|
@ -3038,9 +3058,8 @@ fn (mut g Gen) gen_str_for_struct(info table.Struct, styp, str_fn_name string) {
|
||||||
sym := g.table.get_type_symbol(field.typ)
|
sym := g.table.get_type_symbol(field.typ)
|
||||||
if sym.kind in [.struct_, .array, .array_fixed, .map, .enum_] {
|
if sym.kind in [.struct_, .array, .array_fixed, .map, .enum_] {
|
||||||
field_styp := g.typ(field.typ)
|
field_styp := g.typ(field.typ)
|
||||||
field_fn_name := styp_to_str_fn_name(field_styp)
|
field_fn_name := g.gen_str_for_type_with_styp(field.typ, field_styp)
|
||||||
fnames2strfunc[field_styp] = field_fn_name
|
fnames2strfunc[field_styp] = field_fn_name
|
||||||
g.gen_str_for_type(sym, field_styp, field_fn_name)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
g.definitions.writeln('string ${str_fn_name}($styp x, int indent_count); // auto')
|
g.definitions.writeln('string ${str_fn_name}($styp x, int indent_count); // auto')
|
||||||
|
@ -3103,7 +3122,7 @@ fn (mut g Gen) gen_str_for_array(info table.Array, styp, str_fn_name string) {
|
||||||
sym := g.table.get_type_symbol(info.elem_type)
|
sym := g.table.get_type_symbol(info.elem_type)
|
||||||
field_styp := g.typ(info.elem_type)
|
field_styp := g.typ(info.elem_type)
|
||||||
if sym.kind == .struct_ && !sym.has_method('str') {
|
if sym.kind == .struct_ && !sym.has_method('str') {
|
||||||
g.gen_str_for_type(sym, field_styp, styp_to_str_fn_name(field_styp))
|
g.gen_str_for_type_with_styp(info.elem_type, field_styp)
|
||||||
}
|
}
|
||||||
g.definitions.writeln('string ${str_fn_name}($styp a); // auto')
|
g.definitions.writeln('string ${str_fn_name}($styp a); // auto')
|
||||||
g.auto_str_funcs.writeln('string ${str_fn_name}($styp a) {')
|
g.auto_str_funcs.writeln('string ${str_fn_name}($styp a) {')
|
||||||
|
@ -3131,7 +3150,7 @@ fn (mut g Gen) gen_str_for_array_fixed(info table.ArrayFixed, styp, str_fn_name
|
||||||
sym := g.table.get_type_symbol(info.elem_type)
|
sym := g.table.get_type_symbol(info.elem_type)
|
||||||
field_styp := g.typ(info.elem_type)
|
field_styp := g.typ(info.elem_type)
|
||||||
if sym.kind == .struct_ && !sym.has_method('str') {
|
if sym.kind == .struct_ && !sym.has_method('str') {
|
||||||
g.gen_str_for_type(sym, field_styp, styp_to_str_fn_name(field_styp))
|
g.gen_str_for_type_with_styp(info.elem_type, field_styp)
|
||||||
}
|
}
|
||||||
g.definitions.writeln('string ${str_fn_name}($styp a); // auto')
|
g.definitions.writeln('string ${str_fn_name}($styp a); // auto')
|
||||||
g.auto_str_funcs.writeln('string ${str_fn_name}($styp a) {')
|
g.auto_str_funcs.writeln('string ${str_fn_name}($styp a) {')
|
||||||
|
@ -3160,12 +3179,12 @@ fn (mut g Gen) gen_str_for_map(info table.Map, styp, str_fn_name string) {
|
||||||
key_sym := g.table.get_type_symbol(info.key_type)
|
key_sym := g.table.get_type_symbol(info.key_type)
|
||||||
key_styp := g.typ(info.key_type)
|
key_styp := g.typ(info.key_type)
|
||||||
if key_sym.kind == .struct_ && !key_sym.has_method('str') {
|
if key_sym.kind == .struct_ && !key_sym.has_method('str') {
|
||||||
g.gen_str_for_type(key_sym, key_styp, styp_to_str_fn_name(key_styp))
|
g.gen_str_for_type_with_styp(info.key_type, key_styp)
|
||||||
}
|
}
|
||||||
val_sym := g.table.get_type_symbol(info.value_type)
|
val_sym := g.table.get_type_symbol(info.value_type)
|
||||||
val_styp := g.typ(info.value_type)
|
val_styp := g.typ(info.value_type)
|
||||||
if val_sym.kind == .struct_ && !val_sym.has_method('str') {
|
if val_sym.kind == .struct_ && !val_sym.has_method('str') {
|
||||||
g.gen_str_for_type(val_sym, val_styp, styp_to_str_fn_name(val_styp))
|
g.gen_str_for_type_with_styp(info.value_type, val_styp)
|
||||||
}
|
}
|
||||||
zero := g.type_default(info.value_type)
|
zero := g.type_default(info.value_type)
|
||||||
g.definitions.writeln('string ${str_fn_name}($styp m); // auto')
|
g.definitions.writeln('string ${str_fn_name}($styp m); // auto')
|
||||||
|
@ -3198,6 +3217,22 @@ fn (mut g Gen) gen_str_for_map(info table.Map, styp, str_fn_name string) {
|
||||||
g.auto_str_funcs.writeln('}')
|
g.auto_str_funcs.writeln('}')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn (mut g Gen) gen_str_for_varg(styp, str_fn_name string) {
|
||||||
|
g.definitions.writeln('string varg_${str_fn_name}(varg_$styp it); // auto')
|
||||||
|
g.auto_str_funcs.writeln('string varg_${str_fn_name}(varg_$styp it) {')
|
||||||
|
g.auto_str_funcs.writeln('\tstrings__Builder sb = strings__new_builder(it.len);')
|
||||||
|
g.auto_str_funcs.writeln('\tstrings__Builder_write(&sb, tos3("["));')
|
||||||
|
g.auto_str_funcs.writeln('\tfor(int i=0; i<it.len; i++) {')
|
||||||
|
g.auto_str_funcs.writeln('\t\tstrings__Builder_write(&sb, ${str_fn_name}(it.args[i], 0));')
|
||||||
|
g.auto_str_funcs.writeln('\t\tif (i < it.len-1) {')
|
||||||
|
g.auto_str_funcs.writeln('\t\t\tstrings__Builder_write(&sb, tos3(", "));')
|
||||||
|
g.auto_str_funcs.writeln('\t\t}')
|
||||||
|
g.auto_str_funcs.writeln('\t}')
|
||||||
|
g.auto_str_funcs.writeln('\tstrings__Builder_write(&sb, tos3("]"));')
|
||||||
|
g.auto_str_funcs.writeln('\treturn strings__Builder_str(&sb);')
|
||||||
|
g.auto_str_funcs.writeln('}')
|
||||||
|
}
|
||||||
|
|
||||||
fn (g Gen) type_to_fmt(typ table.Type) string {
|
fn (g Gen) type_to_fmt(typ table.Type) string {
|
||||||
sym := g.table.get_type_symbol(typ)
|
sym := g.table.get_type_symbol(typ)
|
||||||
if sym.kind in [.struct_, .array, .array_fixed, .map] {
|
if sym.kind in [.struct_, .array, .array_fixed, .map] {
|
||||||
|
|
|
@ -373,8 +373,7 @@ fn (mut g Gen) fn_call(node ast.CallExpr) {
|
||||||
if typ.is_ptr() {
|
if typ.is_ptr() {
|
||||||
styp = styp.replace('*', '')
|
styp = styp.replace('*', '')
|
||||||
}
|
}
|
||||||
mut str_fn_name := styp_to_str_fn_name(styp)
|
mut str_fn_name := g.gen_str_for_type_with_styp(typ, styp)
|
||||||
g.gen_str_for_type(sym, styp, str_fn_name)
|
|
||||||
if g.autofree && !typ.flag_is(.optional) {
|
if g.autofree && !typ.flag_is(.optional) {
|
||||||
// Create a temporary variable so that the value can be freed
|
// Create a temporary variable so that the value can be freed
|
||||||
tmp := g.new_tmp_var()
|
tmp := g.new_tmp_var()
|
||||||
|
@ -417,7 +416,7 @@ fn (mut g Gen) fn_call(node ast.CallExpr) {
|
||||||
g.write('*')
|
g.write('*')
|
||||||
}
|
}
|
||||||
g.expr(expr)
|
g.expr(expr)
|
||||||
if sym.kind == .struct_ && styp != 'ptr' && !sym.has_method('str') {
|
if !typ.flag_is(.variadic) && sym.kind == .struct_ && styp != 'ptr' && !sym.has_method('str') {
|
||||||
g.write(', 0') // trailing 0 is initial struct indent count
|
g.write(', 0') // trailing 0 is initial struct indent count
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,12 +18,12 @@ fn test_vargs_string_interpolation() {
|
||||||
results := my_variadic_function(superman, man)
|
results := my_variadic_function(superman, man)
|
||||||
assert results.contains('Man {')
|
assert results.contains('Man {')
|
||||||
//
|
//
|
||||||
assert results.contains('name: Superman')
|
assert results.contains("name: 'Superman'")
|
||||||
assert results.contains('age: 30')
|
assert results.contains('age: 30')
|
||||||
assert results.contains('}, Man {')
|
assert results.contains('}, Man {')
|
||||||
//
|
//
|
||||||
assert results.contains('interests: ["programming"')
|
assert results.contains('interests: ["programming"')
|
||||||
assert results.contains('name: Me')
|
assert results.contains("name: 'Me'")
|
||||||
//
|
//
|
||||||
assert results.contains('}]')
|
assert results.contains('}]')
|
||||||
//
|
//
|
||||||
|
|
Loading…
Reference in New Issue