gen: add prefix when printing type aliases (#6701)

pull/6740/head
Daniel Däschle 2020-11-03 14:13:35 +01:00 committed by GitHub
parent 18f5ed671d
commit 9d5be12517
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 224 additions and 114 deletions

View File

@ -10,9 +10,11 @@ import v.util
fn (mut g Gen) gen_str_for_type_with_styp(typ table.Type, styp string) string {
mut sym := g.table.get_type_symbol(g.unwrap_generic(typ))
mut str_fn_name := styp_to_str_fn_name(styp)
if sym.info is table.Alias {
sym = g.table.get_type_symbol((sym.info as table.Alias).parent_type)
str_fn_name = styp_to_str_fn_name(sym.name.replace('.', '__'))
if sym.info is table.Alias as sym_info {
if sym_info.is_import {
sym = g.table.get_type_symbol((sym.info as table.Alias).parent_type)
str_fn_name = styp_to_str_fn_name(sym.name.replace('.', '__'))
}
}
sym_has_str_method, str_method_expects_ptr, str_nr_args := sym.str_method_info()
// generate for type
@ -45,16 +47,38 @@ fn (mut g Gen) gen_str_for_type_with_styp(typ table.Type, styp string) string {
eprintln('> gen_str_for_type_with_styp: |typ: ${typ:5}, ${sym.name:20}|has_str: ${sym_has_str_method:5}|expects_ptr: ${str_method_expects_ptr:5}|nr_args: ${str_nr_args:1}|fn_name: ${str_fn_name:20}')
}
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) }
table.MultiReturn { g.gen_str_for_multi_return(it, styp, str_fn_name) }
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\'") }
match sym.info as sym_info {
table.Alias {
if sym_info.is_import {
g.gen_str_default(sym, styp, str_fn_name)
} else {
g.gen_str_for_alias(sym_info, 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)
}
table.MultiReturn {
g.gen_str_for_multi_return(it, styp, str_fn_name)
}
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\'")
}
}
}
// if varg, generate str for varg
@ -69,10 +93,36 @@ fn (mut g Gen) gen_str_for_type_with_styp(typ table.Type, styp string) string {
return str_fn_name
}
fn (mut g Gen) gen_str_for_alias(info table.Alias, styp string, str_fn_name string) {
sym := g.table.get_type_symbol(info.parent_type)
sym_has_str_method, _, _ := sym.str_method_info()
mut parent_str_fn_name := styp_to_str_fn_name(sym.name.replace('.', '__'))
if !sym_has_str_method {
parent_styp := g.typ(info.parent_type)
parent_str_fn_name = g.gen_str_for_type_with_styp(info.parent_type, parent_styp)
}
mut clean_type_v_type_name := util.strip_main_name(styp.replace('__', '.'))
g.type_definitions.writeln('string ${str_fn_name}($styp it); // auto')
g.auto_str_funcs.writeln('string ${str_fn_name}($styp it) { return indent_${str_fn_name}(it, 0); }')
g.type_definitions.writeln('string indent_${str_fn_name}($styp it, int indent_count); // auto')
g.auto_str_funcs.writeln('string indent_${str_fn_name}($styp it, int indent_count) {')
g.auto_str_funcs.writeln('\tstring indents = tos_lit("");')
g.auto_str_funcs.writeln('\tfor (int i = 0; i < indent_count; ++i) {')
g.auto_str_funcs.writeln('\t\tindents = string_add(indents, tos_lit(" "));')
g.auto_str_funcs.writeln('\t}')
g.auto_str_funcs.writeln('\treturn _STR("%.*s\\000${clean_type_v_type_name}(%.*s\\000)", 3, indents, ${parent_str_fn_name}(it));')
g.auto_str_funcs.writeln('}')
}
fn (mut g Gen) gen_str_for_array(info table.Array, styp string, str_fn_name string) {
sym := g.table.get_type_symbol(info.elem_type)
field_styp := g.typ(info.elem_type)
is_elem_ptr := info.elem_type.is_ptr()
mut typ := info.elem_type
mut sym := g.table.get_type_symbol(info.elem_type)
if sym.info is table.Alias as alias_info {
typ = alias_info.parent_type
sym = g.table.get_type_symbol(alias_info.parent_type)
}
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 {
@ -85,8 +135,7 @@ fn (mut g Gen) gen_str_for_array(info table.Array, styp string, str_fn_name stri
elem_str_fn_name = styp_to_str_fn_name(field_styp)
}
if !sym_has_str_method {
// eprintln('> sym.name: does not have method `str`')
g.gen_str_for_type_with_styp(info.elem_type, field_styp)
g.gen_str_for_type_with_styp(typ, field_styp)
}
g.type_definitions.writeln('string ${str_fn_name}($styp a); // auto')
g.auto_str_funcs.writeln('string ${str_fn_name}($styp a) { return indent_${str_fn_name}(a, 0);}')
@ -117,7 +166,7 @@ fn (mut g Gen) gen_str_for_array(info table.Array, styp string, str_fn_name stri
}
}
g.auto_str_funcs.writeln('\t\tstrings__Builder_write(&sb, x);')
if g.pref.autofree && info.elem_type != table.bool_type {
if g.pref.autofree && typ != table.bool_type {
// no need to free "true"/"false" literals
g.auto_str_funcs.writeln('\t\tstring_free(&x);')
}
@ -134,9 +183,14 @@ fn (mut g Gen) gen_str_for_array(info table.Array, styp string, str_fn_name stri
}
fn (mut g Gen) gen_str_for_array_fixed(info table.ArrayFixed, styp string, str_fn_name string) {
sym := g.table.get_type_symbol(info.elem_type)
field_styp := g.typ(info.elem_type)
is_elem_ptr := info.elem_type.is_ptr()
mut typ := info.elem_type
mut sym := g.table.get_type_symbol(info.elem_type)
if sym.info is table.Alias as alias_info {
typ = alias_info.parent_type
sym = g.table.get_type_symbol(alias_info.parent_type)
}
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 {
@ -146,7 +200,7 @@ fn (mut g Gen) gen_str_for_array_fixed(info table.ArrayFixed, styp string, str_f
elem_str_fn_name = styp_to_str_fn_name(field_styp)
}
if !sym.has_method('str') {
g.gen_str_for_type_with_styp(info.elem_type, field_styp)
elem_str_fn_name = g.gen_str_for_type_with_styp(typ, field_styp)
}
g.type_definitions.writeln('string ${str_fn_name}($styp a); // auto')
g.auto_str_funcs.writeln('string ${str_fn_name}($styp a) { return indent_${str_fn_name}(a, 0);}')

View File

@ -2090,7 +2090,11 @@ fn (mut g Gen) expr(node ast.Expr) {
g.write('))')
} else {
styp := g.typ(node.typ)
g.write('(($styp)(')
mut cast_label := ''
if sym.kind != .alias || (sym.info as table.Alias).parent_type != node.expr_type {
cast_label = '($styp)'
}
g.write('(${cast_label}(')
g.expr(node.expr)
if node.expr is ast.IntegerLiteral &&
node.typ in [table.u64_type, table.u32_type, table.u16_type] {
@ -4402,18 +4406,22 @@ fn (g &Gen) sort_structs(typesa []table.TypeSymbol) []table.TypeSymbol {
}
fn (mut g Gen) gen_expr_to_string(expr ast.Expr, etype table.Type) ?bool {
mut sym := g.table.get_type_symbol(etype)
if sym.info is table.Alias {
sym = g.table.get_type_symbol((sym.info as table.Alias).parent_type)
mut typ := etype
mut sym := g.table.get_type_symbol(typ)
if sym.info is table.Alias as alias_info {
parent_sym := g.table.get_type_symbol(alias_info.parent_type)
if parent_sym.has_method('str') {
sym = parent_sym
typ = alias_info.parent_type
}
}
sym_has_str_method, str_method_expects_ptr, _ := sym.str_method_info()
if etype.has_flag(.variadic) {
str_fn_name := g.gen_str_for_type(etype)
if typ.has_flag(.variadic) {
str_fn_name := g.gen_str_for_type(typ)
g.write('${str_fn_name}(')
g.expr(expr)
g.write(')')
} else if sym.kind == .alias && (sym.info as table.Alias).parent_type == table.string_type {
// handle string aliases
} else if typ == table.string_type {
g.expr(expr)
return true
} else if sym.kind == .enum_ {
@ -4422,7 +4430,7 @@ fn (mut g Gen) gen_expr_to_string(expr ast.Expr, etype table.Type) ?bool {
else { false }
}
if is_var {
str_fn_name := g.gen_str_for_type(etype)
str_fn_name := g.gen_str_for_type(typ)
g.write('${str_fn_name}(')
g.enum_expr(expr)
g.write(')')
@ -4433,20 +4441,20 @@ fn (mut g Gen) gen_expr_to_string(expr ast.Expr, etype table.Type) ?bool {
}
} 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 }
is_p := typ.is_ptr()
val_type := if is_p { typ.deref() } else { typ }
str_fn_name := g.gen_str_for_type(val_type)
if is_p && str_method_expects_ptr {
g.write('string_add(_SLIT("&"), ${str_fn_name}( (')
g.write('string_add(_SLIT("&"), ${str_fn_name}((')
}
if is_p && !str_method_expects_ptr {
g.write('string_add(_SLIT("&"), ${str_fn_name}( *(')
g.write('string_add(_SLIT("&"), ${str_fn_name}(*(')
}
if !is_p && !str_method_expects_ptr {
g.write('${str_fn_name}( ')
g.write('${str_fn_name}(')
}
if !is_p && str_method_expects_ptr {
g.write('${str_fn_name}( &')
g.write('${str_fn_name}(&')
}
if expr is ast.ArrayInit {
if expr.is_fixed {
@ -4473,13 +4481,16 @@ fn (mut g Gen) gen_expr_to_string(expr ast.Expr, etype table.Type) ?bool {
g.write(')')
}
}
} else if g.typ(etype).starts_with('Option') {
} else if g.typ(typ).starts_with('Option') {
str_fn_name := 'OptionBase_str'
g.write('${str_fn_name}(*(OptionBase*)&')
g.expr(expr)
g.write(')')
} else {
return error('cannot convert to string')
str_fn_name := g.gen_str_for_type(typ)
g.write('${str_fn_name}(')
g.expr(expr)
g.write(')')
}
return true
}

View File

@ -548,82 +548,94 @@ fn (mut g Gen) fn_call(node ast.CallExpr) {
// cgen shouldn't modify ast nodes, this should be moved
// g.generate_tmp_autofree_arg_vars(node, name)
// Handle `print(x)`
mut print_auto_str := false
if is_print && node.args[0].typ != table.string_type { // && !free_tmp_arg_vars {
typ := node.args[0].typ
mut typ := node.args[0].typ
if typ == 0 {
g.checker_bug('print arg.typ is 0', node.pos)
}
mut styp := g.typ(typ)
sym := g.table.get_type_symbol(typ)
if typ.is_ptr() {
styp = styp.replace('*', '')
mut sym := g.table.get_type_symbol(typ)
if sym.info is table.Alias as alias_info {
typ = alias_info.parent_type
sym = g.table.get_type_symbol(alias_info.parent_type)
}
mut str_fn_name := g.gen_str_for_type_with_styp(typ, styp)
if g.autofree && !typ.has_flag(.optional) {
// Create a temporary variable so that the value can be freed
tmp := g.new_tmp_var()
// tmps << tmp
g.write('string $tmp = ${str_fn_name}(')
g.expr(node.args[0].expr)
g.writeln('); ${print_method}($tmp); string_free(&$tmp); //MEM2 $styp')
} else {
expr := node.args[0].expr
is_var := match expr {
ast.SelectorExpr { true }
ast.Ident { true }
else { false }
// check if alias parent also not a string
if typ != table.string_type {
mut styp := g.typ(typ)
if typ.is_ptr() {
styp = styp.replace('*', '')
}
if typ.is_ptr() && sym.kind != .struct_ {
// ptr_str() for pointers
styp = 'ptr'
str_fn_name = 'ptr_str'
}
if sym.kind == .enum_ {
if is_var {
g.write('${print_method}(${str_fn_name}(')
} else {
// when no var, print string directly
g.write('${print_method}(tos3("')
}
if typ.is_ptr() {
// dereference
g.write('*')
}
g.enum_expr(expr)
if !is_var {
// end of string
g.write('"')
}
mut str_fn_name := g.gen_str_for_type_with_styp(typ, styp)
if g.autofree && !typ.has_flag(.optional) {
// Create a temporary variable so that the value can be freed
tmp := g.new_tmp_var()
// tmps << tmp
g.write('string $tmp = ${str_fn_name}(')
g.expr(node.args[0].expr)
g.writeln('); ${print_method}($tmp); string_free(&$tmp); //MEM2 $styp')
} else {
g.write('${print_method}(${str_fn_name}(')
if typ.is_ptr() && sym.kind == .struct_ {
// dereference
g.write('*')
expr := node.args[0].expr
is_var := match expr {
ast.SelectorExpr { true }
ast.Ident { true }
else { false }
}
g.expr(expr)
if typ.is_ptr() && sym.kind != .struct_ {
// ptr_str() for pointers
styp = 'ptr'
str_fn_name = 'ptr_str'
}
if sym.kind == .enum_ {
if is_var {
g.write('${print_method}(${str_fn_name}(')
} else {
// when no var, print string directly
g.write('${print_method}(tos3("')
}
if typ.is_ptr() {
// dereference
g.write('*')
}
g.enum_expr(expr)
if !is_var {
// end of string
g.write('"')
}
} else {
g.write('${print_method}(${str_fn_name}(')
if typ.is_ptr() && sym.kind == .struct_ {
// dereference
g.write('*')
}
g.expr(expr)
}
g.write('))')
}
g.write('))')
print_auto_str = true
}
} else if g.pref.is_debug && node.name == 'panic' {
paline, pafile, pamod, pafn := g.panic_debug_info(node.pos)
g.write('panic_debug($paline, tos3("$pafile"), tos3("$pamod"), tos3("$pafn"), ')
// g.call_args(node.args, node.expected_arg_types) // , [])
g.call_args(node)
g.write(')')
} else {
// Simple function call
// if free_tmp_arg_vars {
// g.writeln(';')
// g.write(cur_line + ' /* <== af cur line*/')
// }
g.write('${g.get_ternary_name(name)}(')
if g.is_json_fn {
g.write(json_obj)
} else {
// g.call_args(node.args, node.expected_arg_types) // , tmp_arg_vars_to_free)
}
if !print_auto_str {
if g.pref.is_debug && node.name == 'panic' {
paline, pafile, pamod, pafn := g.panic_debug_info(node.pos)
g.write('panic_debug($paline, tos3("$pafile"), tos3("$pamod"), tos3("$pafn"), ')
// g.call_args(node.args, node.expected_arg_types) // , [])
g.call_args(node)
g.write(')')
} else {
// Simple function call
// if free_tmp_arg_vars {
// g.writeln(';')
// g.write(cur_line + ' /* <== af cur line*/')
// }
g.write('${g.get_ternary_name(name)}(')
if g.is_json_fn {
g.write(json_obj)
} else {
// g.call_args(node.args, node.expected_arg_types) // , tmp_arg_vars_to_free)
g.call_args(node)
}
g.write(')')
}
g.write(')')
}
g.is_c_call = false
g.is_json_fn = false

View File

@ -266,15 +266,8 @@ fn (mut g Gen) string_inter_literal_sb_optimized(call_expr ast.CallExpr) {
g.expr(call_expr.left)
g.write(', ')
typ := node.expr_types[i]
sym := g.table.get_type_symbol(typ)
// if typ.is_number() {
if sym.kind == .alias && (sym.info as table.Alias).parent_type.is_number() {
// Handle number aliases TODO this must be more generic, handled by g.typ()?
g.write('int_str(')
} else {
g.write(g.typ(typ))
g.write('_str(')
}
g.write(g.typ(typ))
g.write('_str(')
g.expr(node.exprs[i])
g.writeln('));')
}

View File

@ -1571,6 +1571,7 @@ fn (mut p Parser) import_syms(mut parent ast.Import) {
info: table.Alias{
parent_type: typ
language: table.Language.v
is_import: true
}
is_public: false
})

View File

@ -732,6 +732,7 @@ pub struct Alias {
pub:
parent_type Type
language Language
is_import bool
}
pub struct Aggregate {

View File

@ -182,7 +182,7 @@ fn test_struct_with_struct_pointer() {
}
fn test_struct_with_nil() {
w := Wrapper4{}
w := Wrapper4{0}
assert '$w' == 'Wrapper4{\n foo: &nil\n}'
assert w.str() == 'Wrapper4{\n foo: &nil\n}'
}
@ -223,11 +223,49 @@ struct ForGeneric {}
fn generic_fn_interpolation<T>(p T) string {
return '$p'
}
fn generic_fn_str<T>(p T) string {
return p.str()
}
fn test_generic_auto_str() {
s := ForGeneric{}
assert generic_fn_interpolation(s) == 'ForGeneric{}'
assert generic_fn_str(s) == 'ForGeneric{}'
}
type Alias1 = int
fn test_alias_in_array() {
t := [Alias1(1)]
assert t.str() == '[1]'
assert '$t' == '[1]'
}
type Alias2 = int
fn test_alias_in_fixed_array() {
t := [Alias1(1)]!!
assert t.str() == '[1]'
assert '$t' == '[1]'
}
fn test_alias_int() {
a := Alias1(1)
assert a.str() == '1'
assert '$a' == '1'
}
type Alias3 = string
fn test_alias_string() {
s := 'test'
a := Alias3(s)
assert a.str() == s
assert '$a' == s
}
type TestAlias = TestStruct
fn test_alias_struct() {
ts := TestStruct{}
t := TestAlias(ts)
assert t.str() == 'TestAlias($ts)'
assert '$t' == 'TestAlias(TestStruct{\n x: 0\n})'
}