cgen: add map string generation

pull/4550/head
Kris Cherven 2020-04-21 22:00:38 -04:00 committed by GitHub
parent 5c3742fbd2
commit b288ecb795
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 94 additions and 3 deletions

View File

@ -135,6 +135,16 @@ fn (d mut DenseArray) push(kv KeyValue) u32 {
return push_index
}
// Private function. Used to implement array[] operator
fn (d DenseArray) get(i int) voidptr {
$if !no_bounds_checking? {
if i < 0 || i >= d.size {
panic('DenseArray.get: index out of range (i == $i, d.len == $d.size)')
}
}
return byteptr(d.data) + i * sizeof(KeyValue)
}
// Move all zeros to the end of the array
// and resize array
fn (d mut DenseArray) zeros_to_end() {

View File

@ -2284,7 +2284,7 @@ fn (mut g Gen) string_inter_literal(node ast.StringInterLiteral) {
g.write('%.*s')
} else if node.expr_types[i] in [table.f32_type, table.f64_type] {
g.write('%g')
} else if sym.kind == .struct_ && !sym.has_method('str') {
} else if sym.kind in [.struct_, .map] && !sym.has_method('str') {
g.write('%.*s')
} else if node.expr_types[i] == table.i16_type {
g.write('%"PRId16"')
@ -2364,6 +2364,17 @@ fn (mut g Gen) string_inter_literal(node ast.StringInterLiteral) {
g.write('${str_fn_name}(')
g.expr(expr)
g.write(').str')
} else if sym.kind == .map && !sym.has_method('str') {
styp := g.typ(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.expr(expr)
g.write(')')
g.write('.len, ')
g.write('${str_fn_name}(')
g.expr(expr)
g.write(').str')
} else if sym.kind == .struct_ && !sym.has_method('str') {
styp := g.typ(node.expr_types[i])
str_fn_name := styp_to_str_fn_name(styp)
@ -2845,6 +2856,7 @@ fn (mut g Gen) gen_str_for_type(sym table.TypeSymbol, styp string, str_fn_name s
table.Array { g.gen_str_for_array(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}\'") }
}
}
@ -2899,7 +2911,7 @@ fn (mut g Gen) gen_str_for_struct(info table.Struct, styp string, str_fn_name st
mut fnames2strfunc := map[string]string
for i, field in info.fields {
sym := g.table.get_type_symbol(field.typ)
if sym.kind in [.struct_, .array, .array_fixed, .enum_] {
if sym.kind in [.struct_, .array, .array_fixed, .map, .enum_] {
field_styp := g.typ(field.typ)
field_fn_name := styp_to_str_fn_name( field_styp )
fnames2strfunc[ field_styp ] = field_fn_name
@ -2990,9 +3002,51 @@ fn (mut g Gen) gen_str_for_array(info table.Array, styp string, str_fn_name stri
g.auto_str_funcs.writeln('}')
}
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_styp := g.typ(info.key_type)
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))
}
val_sym := g.table.get_type_symbol(info.value_type)
val_styp := g.typ(info.value_type)
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))
}
zero := g.type_default(info.value_type)
g.definitions.writeln('string ${str_fn_name}($styp m); // auto')
g.auto_str_funcs.writeln('string ${str_fn_name}($styp m) { /* gen_str_for_map */')
g.auto_str_funcs.writeln('\tstrings__Builder sb = strings__new_builder(m.key_values.size*10);')
g.auto_str_funcs.writeln('\tstrings__Builder_write(&sb, tos3("$styp"));')
g.auto_str_funcs.writeln('\tstrings__Builder_write(&sb, tos3("{"));')
g.auto_str_funcs.writeln('\tfor (unsigned int i = 0; i < m.key_values.size; i++) {')
g.auto_str_funcs.writeln('\t\tstrings__Builder_write(&sb, (*(string*)DenseArray_get(m.key_values, i)));')
g.auto_str_funcs.writeln('\t\tstrings__Builder_write(&sb, tos3(": "));')
g.auto_str_funcs.write('\t$val_styp it = (*($val_styp*)map_get3(')
g.auto_str_funcs.write('m, (*(string*)DenseArray_get(m.key_values, i))')
g.auto_str_funcs.write(', ')
g.auto_str_funcs.writeln(' &($val_styp[]) { $zero }));')
if val_sym.kind == .string {
g.auto_str_funcs.writeln('\t\tstrings__Builder_write(&sb, it);')
} else if val_sym.kind == .struct_ && !val_sym.has_method('str') {
g.auto_str_funcs.writeln('\t\tstrings__Builder_write(&sb, ${val_styp}_str(it,0));')
} else if val_sym.kind in [.f32, .f64] {
g.auto_str_funcs.writeln('\t\tstrings__Builder_write(&sb, _STR("%g", it));')
} else {
g.auto_str_funcs.writeln('\t\tstrings__Builder_write(&sb, ${val_styp}_str(it));')
}
g.auto_str_funcs.writeln('\t\tif (i != m.key_values.size-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 {
sym := g.table.get_type_symbol(typ)
if sym.kind in [.struct_, .array, .array_fixed] {
if sym.kind in [.struct_, .array, .array_fixed, .map] {
return '%.*s'
} else if typ == table.string_type {
return "\'%.*s\'"

View File

@ -0,0 +1,27 @@
struct Test {
a bool
b int
y string
}
fn test_interpolation_map_to_string() {
a := map[string]string
a['1'] = 'one'
a['2'] = 'two'
a['3'] = 'three'
assert '$a' == 'map_string_string{1: one, 2: two, 3: three}'
b := map[string]int
b['1'] = 1
b['2'] = 2
b['3'] = 3
assert '$b' == 'map_string_int{1: 1, 2: 2, 3: 3}'
c := map[string]bool
c['1'] = true
c['2'] = false
assert '$c' == 'map_string_bool{1: true, 2: false}'
d := map[string]Test
d['1'] = Test{true, 0, 'abc'}
d['2'] = Test{true, 1, 'def'}
d['3'] = Test{false, 2, 'ghi'}
assert '$d'.replace('\n', '').replace('\'', '"') == 'map_string_Test{1: Test { a: true b: 0 y: "abc"}, 2: Test { a: true b: 1 y: "def"}, 3: Test { a: false b: 2 y: "ghi"}}'
}