cgen: simplify .str() generation (#7038)

pull/7070/head
Daniel Däschle 2020-12-01 16:09:03 +01:00 committed by GitHub
parent 54e03f60b9
commit 5b6eb7b2c9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 123 additions and 237 deletions

View File

@ -327,7 +327,8 @@ pub fn (c &Checker) get_default_fmt(ftyp table.Type, typ table.Type) byte {
} }
if ftyp in [table.string_type, table.bool_type] || if ftyp in [table.string_type, table.bool_type] ||
sym.kind in sym.kind in
[.enum_, .array, .array_fixed, .struct_, .map, .multi_return, .sum_type] || sym.has_method('str') { [.enum_, .array, .array_fixed, .struct_, .map, .multi_return, .sum_type, .none_] || ftyp.has_flag(.optional) ||
sym.has_method('str') {
return `s` return `s`
} else { } else {
return `_` return `_`

View File

@ -6,45 +6,21 @@ import v.table
import v.pref import v.pref
import v.util import v.util
// already generated styp, reuse it fn (mut g Gen) gen_str_for_type(typ table.Type) string {
fn (mut g Gen) gen_str_for_type_with_styp(typ table.Type, styp string) string { styp := g.typ(typ).replace('*', '')
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 mut sym.info is table.Alias { if mut sym.info is table.Alias {
if sym.info.is_import { if sym.info.is_import {
sym = g.table.get_type_symbol(sym.info.parent_type) sym = g.table.get_type_symbol(sym.info.parent_type)
str_fn_name = styp_to_str_fn_name(sym.name.replace('.', '__')) str_fn_name = styp_to_str_fn_name(sym.name)
} }
} }
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
if sym_has_str_method && str_method_expects_ptr && str_nr_args == 1 {
// TODO: optimize out this.
// It is needed, so that println() can be called with &T and T has `fn (t &T).str() string`
/*
eprintln('>> gsftws: typ: $typ | typ_is_ptr $typ_is_ptr | styp: $styp ' +
'| $str_fn_name | sym.name: $sym.name has_str: $sym_has_str_method ' +
'| expects_ptr: $str_method_expects_ptr')
*/
str_fn_name_no_ptr := '${str_fn_name}_no_ptr'
already_generated_key_no_ptr := '$styp:$str_fn_name_no_ptr'
if already_generated_key_no_ptr !in g.str_types {
g.str_types << already_generated_key_no_ptr
g.type_definitions.writeln('static string ${str_fn_name_no_ptr}($styp it); // auto no_ptr version')
g.auto_str_funcs.writeln('static string ${str_fn_name_no_ptr}($styp it){ return ${str_fn_name}(&it); }')
}
/*
typ_is_ptr := typ.is_ptr()
ret_type := if typ_is_ptr { str_fn_name } else { str_fn_name_no_ptr }
eprintln(' ret_type: $ret_type')
return ret_type
*/
return str_fn_name_no_ptr
}
already_generated_key := '$styp:$str_fn_name' already_generated_key := '$styp:$str_fn_name'
if !sym_has_str_method && already_generated_key !in g.str_types && !typ.has_flag(.optional) { if !sym_has_str_method && already_generated_key !in g.str_types && !typ.has_flag(.optional) {
$if debugautostr ? { $if debugautostr ? {
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: |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 mut sym.info { match mut sym.info {
@ -108,8 +84,7 @@ fn (mut g Gen) gen_str_for_option(typ table.Type, styp string, str_fn_name strin
sym_name := sym.name.replace('.', '__') sym_name := sym.name.replace('.', '__')
mut parent_str_fn_name := styp_to_str_fn_name(sym_name) mut parent_str_fn_name := styp_to_str_fn_name(sym_name)
if !sym_has_str_method { if !sym_has_str_method {
parent_styp := g.typ(parent_type) parent_str_fn_name = g.gen_str_for_type(parent_type)
parent_str_fn_name = g.gen_str_for_type_with_styp(parent_type, parent_styp)
} }
g.type_definitions.writeln('string ${str_fn_name}($styp it); // auto') 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.auto_str_funcs.writeln('string ${str_fn_name}($styp it) { return indent_${str_fn_name}(it, 0); }')
@ -138,8 +113,7 @@ fn (mut g Gen) gen_str_for_alias(info table.Alias, styp string, str_fn_name stri
sym_has_str_method, _, _ := sym.str_method_info() sym_has_str_method, _, _ := sym.str_method_info()
mut parent_str_fn_name := styp_to_str_fn_name(sym.name.replace('.', '__')) mut parent_str_fn_name := styp_to_str_fn_name(sym.name.replace('.', '__'))
if !sym_has_str_method { if !sym_has_str_method {
parent_styp := g.typ(info.parent_type) parent_str_fn_name = g.gen_str_for_type(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('__', '.')) mut clean_type_v_type_name := util.strip_main_name(styp.replace('__', '.'))
g.type_definitions.writeln('static string ${str_fn_name}($styp it); // auto') g.type_definitions.writeln('static string ${str_fn_name}($styp it); // auto')
@ -175,7 +149,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 {
g.gen_str_for_type_with_styp(typ, field_styp) g.gen_str_for_type(typ)
} }
g.type_definitions.writeln('static string ${str_fn_name}($styp a); // auto') 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.auto_str_funcs.writeln('static string ${str_fn_name}($styp a) { return indent_${str_fn_name}(a, 0);}')
@ -240,7 +214,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') {
elem_str_fn_name = g.gen_str_for_type_with_styp(typ, field_styp) elem_str_fn_name = g.gen_str_for_type(typ)
} }
g.type_definitions.writeln('static string ${str_fn_name}($styp a); // auto') 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.auto_str_funcs.writeln('static string ${str_fn_name}($styp a) { return indent_${str_fn_name}(a, 0);}')
@ -275,15 +249,14 @@ fn (mut g Gen) gen_str_for_array_fixed(info table.ArrayFixed, styp string, str_f
fn (mut g Gen) gen_str_for_map(info table.Map, styp string, str_fn_name string) { fn (mut g Gen) gen_str_for_map(info table.Map, styp string, 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)
if !key_sym.has_method('str') { if !key_sym.has_method('str') {
g.gen_str_for_type_with_styp(info.key_type, key_styp) g.gen_str_for_type(info.key_type)
} }
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)
elem_str_fn_name := val_styp.replace('*', '') + '_str' elem_str_fn_name := val_styp.replace('*', '') + '_str'
if !val_sym.has_method('str') { if !val_sym.has_method('str') {
g.gen_str_for_type_with_styp(info.value_type, val_styp) g.gen_str_for_type(info.value_type)
} }
zero := g.type_default(info.value_type) zero := g.type_default(info.value_type)
g.type_definitions.writeln('static string ${str_fn_name}($styp m); // auto') g.type_definitions.writeln('static string ${str_fn_name}($styp m); // auto')
@ -339,8 +312,7 @@ fn (mut g Gen) gen_str_for_multi_return(info table.MultiReturn, styp string, str
for typ in info.types { for typ in info.types {
sym := g.table.get_type_symbol(typ) sym := g.table.get_type_symbol(typ)
if !sym.has_method('str') { if !sym.has_method('str') {
field_styp := g.typ(typ) g.gen_str_for_type(typ)
g.gen_str_for_type_with_styp(typ, field_styp)
} }
} }
g.type_definitions.writeln('static string ${str_fn_name}($styp a); // auto') g.type_definitions.writeln('static string ${str_fn_name}($styp a); // auto')
@ -397,15 +369,15 @@ fn (mut g Gen) gen_str_for_struct(info table.Struct, styp string, str_fn_name st
typ = typ.deref() typ = typ.deref()
} }
field_styp := g.typ(typ) field_styp := g.typ(typ)
field_fn_name := g.gen_str_for_type_with_styp(field.typ, field_styp) field_fn_name := g.gen_str_for_type(field.typ)
fnames2strfunc[field_styp] = field_fn_name fnames2strfunc[field_styp] = field_fn_name
} }
} }
// _str() functions should have a single argument, the indenting ones take 2: // _str() functions should have a single argument, the indenting ones take 2:
g.type_definitions.writeln('static string ${str_fn_name}($styp x); // auto') g.type_definitions.writeln('static string ${str_fn_name}($styp it); // auto')
g.auto_str_funcs.writeln('static string ${str_fn_name}($styp x) { return indent_${str_fn_name}(x, 0);}') 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 x, int indent_count); // auto') g.type_definitions.writeln('static string indent_${str_fn_name}($styp it, int indent_count); // auto')
g.auto_str_funcs.writeln('static string indent_${str_fn_name}($styp x, int indent_count) {') g.auto_str_funcs.writeln('static string indent_${str_fn_name}($styp it, int indent_count) {')
mut clean_struct_v_type_name := styp.replace('__', '.') mut clean_struct_v_type_name := styp.replace('__', '.')
if clean_struct_v_type_name.contains('_T_') { if clean_struct_v_type_name.contains('_T_') {
// TODO: this is a bit hacky. styp shouldn't be even parsed with _T_ // TODO: this is a bit hacky. styp shouldn't be even parsed with _T_
@ -413,14 +385,6 @@ fn (mut g Gen) gen_str_for_struct(info table.Struct, styp string, str_fn_name st
clean_struct_v_type_name = clean_struct_v_type_name.replace('_T_', '<').replace('_', ', ') + clean_struct_v_type_name = clean_struct_v_type_name.replace('_T_', '<').replace('_', ', ') +
'>' '>'
} }
if styp.ends_with('*') {
deref_typ := styp.replace('*', '')
g.auto_str_funcs.writeln('\t$deref_typ *it = x;')
clean_struct_v_type_name = '&' + clean_struct_v_type_name.replace('*', '')
} else {
deref_typ := styp
g.auto_str_funcs.writeln('\t$deref_typ *it = &x;')
}
clean_struct_v_type_name = util.strip_main_name(clean_struct_v_type_name) clean_struct_v_type_name = util.strip_main_name(clean_struct_v_type_name)
// generate ident / indent length = 4 spaces // generate ident / indent length = 4 spaces
g.auto_str_funcs.writeln('\tstring indents = tos_lit("");') g.auto_str_funcs.writeln('\tstring indents = tos_lit("");')
@ -428,14 +392,12 @@ fn (mut g Gen) gen_str_for_struct(info table.Struct, styp string, str_fn_name st
g.auto_str_funcs.writeln('\t\tindents = string_add(indents, tos_lit(" "));') g.auto_str_funcs.writeln('\t\tindents = string_add(indents, tos_lit(" "));')
g.auto_str_funcs.writeln('\t}') g.auto_str_funcs.writeln('\t}')
if info.fields.len == 0 { if info.fields.len == 0 {
g.auto_str_funcs.write('\treturn tos_lit("$clean_struct_v_type_name{}");') g.auto_str_funcs.write('\treturn _SLIT("$clean_struct_v_type_name{}");')
} else { } else {
g.auto_str_funcs.write('\treturn _STR("$clean_struct_v_type_name{\\n"') g.auto_str_funcs.write('\treturn _STR("$clean_struct_v_type_name{\\n"')
for field in info.fields { for field in info.fields {
mut fmt := g.type_to_fmt(field.typ) mut fmt := if field.typ.is_ptr() { '&' } else { '' }
if field.typ.is_ptr() { fmt += g.type_to_fmt(field.typ)
fmt = '&$fmt'
}
g.auto_str_funcs.writeln('\t\t"%.*s\\000 $field.name: $fmt\\n"') g.auto_str_funcs.writeln('\t\t"%.*s\\000 $field.name: $fmt\\n"')
} }
g.auto_str_funcs.write('\t\t"%.*s\\000}", ${2 * (info.fields.len + 1)}') g.auto_str_funcs.write('\t\t"%.*s\\000}", ${2 * (info.fields.len + 1)}')
@ -444,16 +406,14 @@ fn (mut g Gen) gen_str_for_struct(info table.Struct, styp string, str_fn_name st
for i, field in info.fields { for i, field in info.fields {
sym := g.table.get_type_symbol(field.typ) sym := g.table.get_type_symbol(field.typ)
has_custom_str := sym.has_method('str') has_custom_str := sym.has_method('str')
mut field_styp := g.typ(field.typ) mut field_styp := g.typ(field.typ).replace('*', '')
if field_styp.ends_with('*') {
field_styp = field_styp.replace('*', '')
}
field_styp_fn_name := if has_custom_str { '${field_styp}_str' } else { fnames2strfunc[field_styp] } field_styp_fn_name := if has_custom_str { '${field_styp}_str' } else { fnames2strfunc[field_styp] }
g.auto_str_funcs.write('indents, ') g.auto_str_funcs.write('indents, ')
func := struct_auto_str_func(sym, field.typ, field_styp_fn_name, field.name) func := struct_auto_str_func(sym, field.typ, field_styp_fn_name, field.name)
// reference types can be "nil"
if field.typ.is_ptr() { if field.typ.is_ptr() {
g.auto_str_funcs.write('isnil(it->${c_name(field.name)})') g.auto_str_funcs.write('isnil(it.${c_name(field.name)})')
g.auto_str_funcs.write(' ? tos_lit("nil") : ') g.auto_str_funcs.write(' ? _SLIT("nil") : ')
// struct, floats and ints have a special case through the _str function // struct, floats and ints have a special case through the _str function
if sym.kind != .struct_ && !field.typ.is_int() && !field.typ.is_float() { if sym.kind != .struct_ && !field.typ.is_int() && !field.typ.is_float() {
g.auto_str_funcs.write('*') g.auto_str_funcs.write('*')
@ -474,9 +434,9 @@ fn (mut g Gen) gen_str_for_struct(info table.Struct, styp string, str_fn_name st
fn struct_auto_str_func(sym table.TypeSymbol, field_type table.Type, fn_name string, field_name string) string { fn struct_auto_str_func(sym table.TypeSymbol, field_type table.Type, fn_name string, field_name string) string {
has_custom_str := sym.has_method('str') has_custom_str := sym.has_method('str')
if sym.kind == .enum_ { if sym.kind == .enum_ {
return '${fn_name}(it->${c_name(field_name)})' return '${fn_name}(it.${c_name(field_name)})'
} else if sym.kind == .struct_ { } else if sym.kind == .struct_ {
mut obj := 'it->${c_name(field_name)}' mut obj := 'it.${c_name(field_name)}'
if field_type.is_ptr() { if field_type.is_ptr() {
obj = '*$obj' obj = '*$obj'
} }
@ -486,11 +446,11 @@ fn struct_auto_str_func(sym table.TypeSymbol, field_type table.Type, fn_name str
return 'indent_${fn_name}($obj, indent_count + 1)' return 'indent_${fn_name}($obj, indent_count + 1)'
} else if sym.kind in [.array, .array_fixed, .map, .sum_type] { } else if sym.kind in [.array, .array_fixed, .map, .sum_type] {
if has_custom_str { if has_custom_str {
return '${fn_name}(it->${c_name(field_name)})' return '${fn_name}(it.${c_name(field_name)})'
} }
return 'indent_${fn_name}(it->${c_name(field_name)}, indent_count + 1)' return 'indent_${fn_name}(it.${c_name(field_name)}, indent_count + 1)'
} else { } else {
mut method_str := 'it->${c_name(field_name)}' mut method_str := 'it.${c_name(field_name)}'
if sym.kind == .bool { if sym.kind == .bool {
method_str += ' ? _SLIT("true") : _SLIT("false")' method_str += ' ? _SLIT("true") : _SLIT("false")'
} else if (field_type.is_int() || field_type.is_float()) && field_type.is_ptr() { } else if (field_type.is_int() || field_type.is_float()) && field_type.is_ptr() {
@ -534,7 +494,7 @@ fn (mut g Gen) gen_str_for_union_sum_type(info table.SumType, styp string, str_f
sym := g.table.get_type_symbol(typ) sym := g.table.get_type_symbol(typ)
if !sym.has_method('str') { if !sym.has_method('str') {
field_styp := g.typ(typ) field_styp := g.typ(typ)
field_fn_name := g.gen_str_for_type_with_styp(typ, field_styp) field_fn_name := g.gen_str_for_type(typ)
gen_fn_names[field_styp] = field_fn_name gen_fn_names[field_styp] = field_fn_name
} }
} }
@ -555,8 +515,7 @@ fn (mut g Gen) gen_str_for_union_sum_type(info table.SumType, styp string, str_f
value_fmt = "'$value_fmt'" value_fmt = "'$value_fmt'"
} }
typ_str := g.typ(typ) typ_str := g.typ(typ)
mut func_name := if typ_str in gen_fn_names { gen_fn_names[typ_str] } else { g.gen_str_for_type_with_styp(typ, mut func_name := if typ_str in gen_fn_names { gen_fn_names[typ_str] } else { g.gen_str_for_type(typ) }
typ_str) }
sym := g.table.get_type_symbol(typ) sym := g.table.get_type_symbol(typ)
if sym.kind == .struct_ { if sym.kind == .struct_ {
func_name = 'indent_$func_name' func_name = 'indent_$func_name'
@ -571,3 +530,8 @@ fn (mut g Gen) gen_str_for_union_sum_type(info table.SumType, styp string, str_f
g.auto_str_funcs.writeln('\t}') g.auto_str_funcs.writeln('\t}')
g.auto_str_funcs.writeln('}') g.auto_str_funcs.writeln('}')
} }
[inline]
fn styp_to_str_fn_name(styp string) string {
return styp.replace_each(['*', '', '.', '__']) + '_str'
}

View File

@ -1453,9 +1453,7 @@ fn (mut g Gen) gen_assert_single_expr(e ast.Expr, t table.Type) {
// without special casing ast.CastExpr here // without special casing ast.CastExpr here
g.write(ctoslit(unknown_value)) g.write(ctoslit(unknown_value))
} else { } else {
g.gen_expr_to_string(e, t) or { g.gen_expr_to_string(e, t)
g.write(ctoslit('[$err]'))
}
} }
} }
ast.Type { ast.Type {
@ -1463,9 +1461,7 @@ fn (mut g Gen) gen_assert_single_expr(e ast.Expr, t table.Type) {
g.write(ctoslit('$sym.name')) g.write(ctoslit('$sym.name'))
} }
else { else {
g.gen_expr_to_string(e, t) or { g.gen_expr_to_string(e, t)
g.write(ctoslit('[$err]'))
}
} }
} }
g.write(' /* typeof: ' + typeof(e) + ' type: ' + t.str() + ' */ ') g.write(' /* typeof: ' + typeof(e) + ' type: ' + t.str() + ' */ ')
@ -4664,90 +4660,6 @@ fn (g &Gen) sort_structs(typesa []table.TypeSymbol) []table.TypeSymbol {
return types_sorted return types_sorted
} }
fn (mut g Gen) gen_expr_to_string(expr ast.Expr, etype table.Type) ?bool {
mut typ := etype
mut sym := g.table.get_type_symbol(typ)
if mut sym.info is table.Alias {
parent_sym := g.table.get_type_symbol(sym.info.parent_type)
if parent_sym.has_method('str') {
typ = sym.info.parent_type
sym = parent_sym
}
}
sym_has_str_method, str_method_expects_ptr, _ := sym.str_method_info()
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 typ == table.string_type {
g.expr(expr)
} else if sym.kind == .enum_ {
is_var := match expr {
ast.SelectorExpr, ast.Ident { true }
else { false }
}
if is_var {
str_fn_name := g.gen_str_for_type(typ)
g.write('${str_fn_name}(')
g.enum_expr(expr)
g.write(')')
} else {
g.write('tos_lit("')
g.enum_expr(expr)
g.write('")')
}
} else if sym_has_str_method || sym.kind in
[.array, .array_fixed, .map, .struct_, .multi_return, .sum_type] {
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}((')
}
if is_p && !str_method_expects_ptr {
g.write('string_add(_SLIT("&"), ${str_fn_name}(*(')
}
if !is_p && !str_method_expects_ptr {
g.write('${str_fn_name}(')
}
if !is_p && str_method_expects_ptr {
g.write('${str_fn_name}(&')
}
if expr is ast.ArrayInit {
if expr.is_fixed {
s := g.typ(expr.typ)
g.write('($s)')
}
}
if expr is ast.CTempVar {
if expr.is_ptr {
g.write('*')
}
}
g.expr(expr)
if sym.kind == .struct_ && !sym_has_str_method {
if is_p {
g.write(')))')
} else {
g.write(')')
}
} else {
if is_p {
g.write(')))')
} else {
g.write(')')
}
}
} else {
str_fn_name := g.gen_str_for_type(typ)
g.write('${str_fn_name}(')
g.expr(expr)
g.write(')')
}
return true
}
// `nums.map(it % 2 == 0)` // `nums.map(it % 2 == 0)`
fn (mut g Gen) gen_array_map(node ast.CallExpr) { fn (mut g Gen) gen_array_map(node ast.CallExpr) {
g.inside_lambda = true g.inside_lambda = true
@ -5555,21 +5467,6 @@ 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 {
return styp.replace('*', '_ptr') + '_str'
}
[inline]
fn (mut g Gen) gen_str_for_type(typ table.Type) string {
// note: why was this here, removed for --usecache fix
// if g.pref.build_mode == .build_module {
// return ''
// }
styp := g.typ(typ)
return g.gen_str_for_type_with_styp(typ, styp)
}
fn (mut g Gen) gen_str_default(sym table.TypeSymbol, styp string, str_fn_name string) { fn (mut g Gen) gen_str_default(sym table.TypeSymbol, styp string, str_fn_name string) {
mut convertor := '' mut convertor := ''
mut typename_ := '' mut typename_ := ''

View File

@ -363,11 +363,7 @@ fn (mut g Gen) method_call(node ast.CallExpr) {
return return
} }
if node.name == 'str' { if node.name == 'str' {
mut styp := g.typ(node.receiver_type) g.gen_str_for_type(node.receiver_type)
if node.receiver_type.is_ptr() {
styp = styp.replace('*', '')
}
g.gen_str_for_type_with_styp(node.receiver_type, styp)
} }
// TODO performance, detect `array` method differently // TODO performance, detect `array` method differently
if left_sym.kind == .array && node.name in if left_sym.kind == .array && node.name in
@ -549,55 +545,18 @@ fn (mut g Gen) fn_call(node ast.CallExpr) {
} }
// check if alias parent also not a string // check if alias parent also not a string
if typ != table.string_type { if typ != table.string_type {
mut styp := g.typ(typ) expr := node.args[0].expr
if typ.is_ptr() {
styp = styp.replace('*', '')
}
mut str_fn_name := g.gen_str_for_type_with_styp(typ, styp)
if g.autofree && !typ.has_flag(.optional) { if g.autofree && !typ.has_flag(.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()
// tmps << tmp // tmps << tmp
g.write('string $tmp = ${str_fn_name}(') g.write('string $tmp = ')
g.expr(node.args[0].expr) g.gen_expr_to_string(expr, typ)
g.writeln('); ${print_method}($tmp); string_free(&$tmp); //MEM2 $styp') g.writeln('; ${print_method}($tmp); string_free(&$tmp);')
} else { } else {
expr := node.args[0].expr g.write('${print_method}(')
is_var := match expr { g.gen_expr_to_string(expr, typ)
ast.SelectorExpr { true } g.write(')')
ast.Ident { true }
else { false }
}
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('))')
} }
print_auto_str = true print_auto_str = true
} }

View File

@ -239,7 +239,6 @@ fn (mut g Gen) encode_map(key_type table.Type, value_type table.Type) string {
if key_type.is_string() { if key_type.is_string() {
key += '(($styp*)${keys_tmp}.data)[i];' key += '(($styp*)${keys_tmp}.data)[i];'
} else { } else {
// g.gen_str_for_type(key_type)
// key += '${styp}_str((($styp*)${keys_tmp}.data)[i]);' // key += '${styp}_str((($styp*)${keys_tmp}.data)[i]);'
verror('json: encode only maps with string keys') verror('json: encode only maps with string keys')
} }

View File

@ -201,6 +201,7 @@ fn (mut g Gen) string_inter_literal(node ast.StringInterLiteral) {
break break
} }
g.write(escaped_val) g.write(escaped_val)
typ := g.unwrap_generic(node.expr_types[i])
// write correct format specifier to intermediate string // write correct format specifier to intermediate string
g.write('%') g.write('%')
fspec := node.fmts[i] fspec := node.fmts[i]
@ -214,7 +215,6 @@ fn (mut g Gen) string_inter_literal(node ast.StringInterLiteral) {
if node.precisions[i] != 987698 { if node.precisions[i] != 987698 {
fmt = '${fmt}.${node.precisions[i]}' fmt = '${fmt}.${node.precisions[i]}'
} }
typ := g.unwrap_generic(node.expr_types[i])
if fspec == `s` { if fspec == `s` {
if node.fwidths[i] == 0 { if node.fwidths[i] == 0 {
g.write('.*s') g.write('.*s')
@ -268,12 +268,7 @@ fn (mut g Gen) string_inter_literal(node ast.StringInterLiteral) {
} else { } else {
g.expr(expr) g.expr(expr)
} }
} else if typ.has_flag(.variadic) { } else if node.fmts[i] == `s` || typ.has_flag(.variadic) {
g.gen_expr_to_string(expr, typ)
} else if typ == table.bool_type {
g.expr(expr)
g.write(' ? _SLIT("true") : _SLIT("false")')
} else if node.fmts[i] == `s` {
g.gen_expr_to_string(expr, typ) g.gen_expr_to_string(expr, typ)
} else if typ.is_number() || typ.is_pointer() || node.fmts[i] == `d` { } else if typ.is_number() || typ.is_pointer() || node.fmts[i] == `d` {
if typ.is_signed() && node.fmts[i] in [`x`, `X`, `o`] { if typ.is_signed() && node.fmts[i] in [`x`, `X`, `o`] {
@ -304,3 +299,74 @@ fn (mut g Gen) string_inter_literal(node ast.StringInterLiteral) {
} }
g.write(')') g.write(')')
} }
fn (mut g Gen) gen_expr_to_string(expr ast.Expr, etype table.Type) {
mut typ := etype
mut sym := g.table.get_type_symbol(typ)
// when type is alias, print the aliased value
if mut sym.info is table.Alias {
parent_sym := g.table.get_type_symbol(sym.info.parent_type)
if parent_sym.has_method('str') {
typ = sym.info.parent_type
sym = parent_sym
}
}
sym_has_str_method, str_method_expects_ptr, _ := sym.str_method_info()
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 typ == table.string_type {
g.expr(expr)
} else if typ == table.bool_type {
g.expr(expr)
g.write(' ? _SLIT("true") : _SLIT("false")')
} else if sym.kind == .none_ {
g.write('_SLIT("none")')
} else if sym.kind == .enum_ {
is_var := match expr {
ast.SelectorExpr, ast.Ident { true }
else { false }
}
if is_var {
str_fn_name := g.gen_str_for_type(typ)
g.write('${str_fn_name}(')
g.enum_expr(expr)
g.write(')')
} else {
g.write('_SLIT("')
g.enum_expr(expr)
g.write('")')
}
} else if sym_has_str_method || sym.kind in
[.array, .array_fixed, .map, .struct_, .multi_return, .sum_type] {
is_ptr := typ.is_ptr()
str_fn_name := g.gen_str_for_type(typ)
if is_ptr {
g.write('_STR("&%.*s\\000", 2, ')
}
g.write('${str_fn_name}(')
if str_method_expects_ptr && !is_ptr {
g.write('&')
} else if !str_method_expects_ptr && is_ptr {
g.write('*')
}
if expr is ast.ArrayInit {
if expr.is_fixed {
s := g.typ(expr.typ)
g.write('($s)')
}
}
g.expr(expr)
g.write(')')
if is_ptr {
g.write(')')
}
} else {
str_fn_name := g.gen_str_for_type(typ)
g.write('${str_fn_name}(')
g.expr(expr)
g.write(')')
}
}

View File

@ -5,7 +5,7 @@ Aaa{
name: '' name: ''
} }
} }
Bbb{ &Bbb{
pass: false pass: false
name: '' name: ''
} }

View File

@ -205,7 +205,7 @@ pub mut:
} }
fn fooo() { fn fooo() {
a := AttrTest{1, 2, 3, 4, 5, 6} _ := AttrTest{1, 2, 3, 4, 5, 6}
} }
/* /*
@ -275,7 +275,7 @@ struct Country {
} }
fn test_levels() { fn test_levels() {
c := Country{ _ := Country{
name: 'UK' name: 'UK'
capital: { capital: {
name: 'London' name: 'London'