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 { 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 sym := g.table.get_type_symbol(g.unwrap_generic(typ))
mut str_fn_name := styp_to_str_fn_name(styp) mut str_fn_name := styp_to_str_fn_name(styp)
if sym.info is table.Alias { if sym.info is table.Alias as sym_info {
sym = g.table.get_type_symbol((sym.info as table.Alias).parent_type) if sym_info.is_import {
str_fn_name = styp_to_str_fn_name(sym.name.replace('.', '__')) 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() sym_has_str_method, str_method_expects_ptr, str_nr_args := sym.str_method_info()
// generate for type // 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}') 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 g.str_types << already_generated_key
match sym.info { match sym.info as sym_info {
table.Alias { g.gen_str_default(sym, styp, str_fn_name) } table.Alias {
table.Array { g.gen_str_for_array(it, styp, str_fn_name) } if sym_info.is_import {
table.ArrayFixed { g.gen_str_for_array_fixed(it, styp, str_fn_name) } g.gen_str_default(sym, styp, str_fn_name)
table.Enum { g.gen_str_for_enum(it, styp, str_fn_name) } } else {
table.Struct { g.gen_str_for_struct(it, styp, str_fn_name) } g.gen_str_for_alias(sym_info, 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) } table.Array {
else { verror("could not generate string method $str_fn_name for type \'$styp\'") } 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 // 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 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) { 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) mut typ := info.elem_type
field_styp := g.typ(info.elem_type) mut sym := g.table.get_type_symbol(info.elem_type)
is_elem_ptr := info.elem_type.is_ptr() 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() sym_has_str_method, str_method_expects_ptr, _ := sym.str_method_info()
mut elem_str_fn_name := '' mut elem_str_fn_name := ''
if sym_has_str_method { 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) elem_str_fn_name = styp_to_str_fn_name(field_styp)
} }
if !sym_has_str_method { if !sym_has_str_method {
// eprintln('> sym.name: does not have method `str`') g.gen_str_for_type_with_styp(typ, field_styp)
g.gen_str_for_type_with_styp(info.elem_type, field_styp)
} }
g.type_definitions.writeln('string ${str_fn_name}($styp a); // auto') 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);}') 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);') 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 // no need to free "true"/"false" literals
g.auto_str_funcs.writeln('\t\tstring_free(&x);') 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) { 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) mut typ := info.elem_type
field_styp := g.typ(info.elem_type) mut sym := g.table.get_type_symbol(info.elem_type)
is_elem_ptr := info.elem_type.is_ptr() 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() sym_has_str_method, str_method_expects_ptr, _ := sym.str_method_info()
mut elem_str_fn_name := '' mut elem_str_fn_name := ''
if sym_has_str_method { 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) elem_str_fn_name = styp_to_str_fn_name(field_styp)
} }
if !sym.has_method('str') { 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.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);}') 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('))') g.write('))')
} else { } else {
styp := g.typ(node.typ) 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) g.expr(node.expr)
if node.expr is ast.IntegerLiteral && if node.expr is ast.IntegerLiteral &&
node.typ in [table.u64_type, table.u32_type, table.u16_type] { 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 { fn (mut g Gen) gen_expr_to_string(expr ast.Expr, etype table.Type) ?bool {
mut sym := g.table.get_type_symbol(etype) mut typ := etype
if sym.info is table.Alias { mut sym := g.table.get_type_symbol(typ)
sym = g.table.get_type_symbol((sym.info as table.Alias).parent_type) 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() sym_has_str_method, str_method_expects_ptr, _ := sym.str_method_info()
if etype.has_flag(.variadic) { if typ.has_flag(.variadic) {
str_fn_name := g.gen_str_for_type(etype) str_fn_name := g.gen_str_for_type(typ)
g.write('${str_fn_name}(') g.write('${str_fn_name}(')
g.expr(expr) g.expr(expr)
g.write(')') g.write(')')
} else if sym.kind == .alias && (sym.info as table.Alias).parent_type == table.string_type { } else if typ == table.string_type {
// handle string aliases
g.expr(expr) g.expr(expr)
return true return true
} else if sym.kind == .enum_ { } 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 } else { false }
} }
if is_var { 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.write('${str_fn_name}(')
g.enum_expr(expr) g.enum_expr(expr)
g.write(')') 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 } else if sym_has_str_method || sym.kind in
[.array, .array_fixed, .map, .struct_, .multi_return, .sum_type] { [.array, .array_fixed, .map, .struct_, .multi_return, .sum_type] {
is_p := etype.is_ptr() is_p := typ.is_ptr()
val_type := if is_p { etype.deref() } else { etype } val_type := if is_p { typ.deref() } else { typ }
str_fn_name := g.gen_str_for_type(val_type) str_fn_name := g.gen_str_for_type(val_type)
if is_p && str_method_expects_ptr { 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 { 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 { if !is_p && !str_method_expects_ptr {
g.write('${str_fn_name}( ') g.write('${str_fn_name}(')
} }
if !is_p && str_method_expects_ptr { 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 ast.ArrayInit {
if expr.is_fixed { 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(')') g.write(')')
} }
} }
} else if g.typ(etype).starts_with('Option') { } else if g.typ(typ).starts_with('Option') {
str_fn_name := 'OptionBase_str' str_fn_name := 'OptionBase_str'
g.write('${str_fn_name}(*(OptionBase*)&') g.write('${str_fn_name}(*(OptionBase*)&')
g.expr(expr) g.expr(expr)
g.write(')') g.write(')')
} else { } 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 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 // cgen shouldn't modify ast nodes, this should be moved
// g.generate_tmp_autofree_arg_vars(node, name) // g.generate_tmp_autofree_arg_vars(node, name)
// Handle `print(x)` // Handle `print(x)`
mut print_auto_str := false
if is_print && node.args[0].typ != table.string_type { // && !free_tmp_arg_vars { 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 { if typ == 0 {
g.checker_bug('print arg.typ is 0', node.pos) g.checker_bug('print arg.typ is 0', node.pos)
} }
mut styp := g.typ(typ) mut sym := g.table.get_type_symbol(typ)
sym := g.table.get_type_symbol(typ) if sym.info is table.Alias as alias_info {
if typ.is_ptr() { typ = alias_info.parent_type
styp = styp.replace('*', '') sym = g.table.get_type_symbol(alias_info.parent_type)
} }
mut str_fn_name := g.gen_str_for_type_with_styp(typ, styp) // check if alias parent also not a string
if g.autofree && !typ.has_flag(.optional) { if typ != table.string_type {
// Create a temporary variable so that the value can be freed mut styp := g.typ(typ)
tmp := g.new_tmp_var() if typ.is_ptr() {
// tmps << tmp styp = styp.replace('*', '')
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 }
} }
if typ.is_ptr() && sym.kind != .struct_ { mut str_fn_name := g.gen_str_for_type_with_styp(typ, styp)
// ptr_str() for pointers if g.autofree && !typ.has_flag(.optional) {
styp = 'ptr' // Create a temporary variable so that the value can be freed
str_fn_name = 'ptr_str' tmp := g.new_tmp_var()
} // tmps << tmp
if sym.kind == .enum_ { g.write('string $tmp = ${str_fn_name}(')
if is_var { g.expr(node.args[0].expr)
g.write('${print_method}(${str_fn_name}(') g.writeln('); ${print_method}($tmp); string_free(&$tmp); //MEM2 $styp')
} 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 { } else {
g.write('${print_method}(${str_fn_name}(') expr := node.args[0].expr
if typ.is_ptr() && sym.kind == .struct_ { is_var := match expr {
// dereference ast.SelectorExpr { true }
g.write('*') 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) if !print_auto_str {
g.write('panic_debug($paline, tos3("$pafile"), tos3("$pamod"), tos3("$pafn"), ') if g.pref.is_debug && node.name == 'panic' {
// g.call_args(node.args, node.expected_arg_types) // , []) paline, pafile, pamod, pafn := g.panic_debug_info(node.pos)
g.call_args(node) g.write('panic_debug($paline, tos3("$pafile"), tos3("$pamod"), tos3("$pafn"), ')
g.write(')') // g.call_args(node.args, node.expected_arg_types) // , [])
} 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.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_c_call = false
g.is_json_fn = 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.expr(call_expr.left)
g.write(', ') g.write(', ')
typ := node.expr_types[i] typ := node.expr_types[i]
sym := g.table.get_type_symbol(typ) g.write(g.typ(typ))
// if typ.is_number() { g.write('_str(')
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.expr(node.exprs[i]) g.expr(node.exprs[i])
g.writeln('));') g.writeln('));')
} }

View File

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

View File

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

View File

@ -182,7 +182,7 @@ fn test_struct_with_struct_pointer() {
} }
fn test_struct_with_nil() { fn test_struct_with_nil() {
w := Wrapper4{} w := Wrapper4{0}
assert '$w' == 'Wrapper4{\n foo: &nil\n}' assert '$w' == 'Wrapper4{\n foo: &nil\n}'
assert w.str() == '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 { fn generic_fn_interpolation<T>(p T) string {
return '$p' return '$p'
} }
fn generic_fn_str<T>(p T) string { fn generic_fn_str<T>(p T) string {
return p.str() return p.str()
} }
fn test_generic_auto_str() { fn test_generic_auto_str() {
s := ForGeneric{} s := ForGeneric{}
assert generic_fn_interpolation(s) == 'ForGeneric{}' assert generic_fn_interpolation(s) == 'ForGeneric{}'
assert generic_fn_str(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})'
}