cgen: zero struct fields during initialization

pull/4106/head
Alexander Medvednikov 2020-03-23 08:59:34 +01:00
parent a5bd98610f
commit 4867803f6b
2 changed files with 146 additions and 34 deletions

View File

@ -162,12 +162,7 @@ pub fn (g mut Gen) write_typedef_types() {
info := typ.info as table.FnType info := typ.info as table.FnType
func := info.func func := info.func
if !info.has_decl && !info.is_anon { if !info.has_decl && !info.is_anon {
fn_name := if func.is_c { fn_name := if func.is_c { func.name.replace('.', '__') } else { c_name(func.name) }
func.name.replace('.', '__')
}
else {
c_name(func.name)
}
g.definitions.write('typedef ${g.typ(func.return_type)} (*$fn_name)(') g.definitions.write('typedef ${g.typ(func.return_type)} (*$fn_name)(')
for i, arg in func.args { for i, arg in func.args {
g.definitions.write(g.typ(arg.typ)) g.definitions.write(g.typ(arg.typ))
@ -410,12 +405,7 @@ fn (g mut Gen) stmt(node ast.Stmt) {
g.return_statement(it) g.return_statement(it)
} }
ast.StructDecl { ast.StructDecl {
name := if it.is_c { name := if it.is_c { it.name.replace('.', '__') } else { c_name(it.name) }
it.name.replace('.', '__')
}
else {
c_name(it.name)
}
// g.writeln('typedef struct {') // g.writeln('typedef struct {')
// for field in it.fields { // for field in it.fields {
// field_type_sym := g.table.get_type_symbol(field.typ) // field_type_sym := g.table.get_type_symbol(field.typ)
@ -994,27 +984,7 @@ fn (g mut Gen) expr(node ast.Expr) {
} }
// `user := User{name: 'Bob'}` // `user := User{name: 'Bob'}`
ast.StructInit { ast.StructInit {
styp := g.typ(it.typ) g.struct_init(it)
if g.is_amp {
g.out.go_back(1) // delete the & already generated in `prefix_expr()
g.write('($styp*)memdup(&($styp){')
}
else {
g.writeln('($styp){')
}
for i, field in it.fields {
field_name := c_name(field)
g.write('\t.$field_name = ')
g.expr_with_cast(it.exprs[i], it.expr_types[i], it.expected_types[i])
g.writeln(', ')
}
if it.fields.len == 0 {
g.write('0')
}
g.write('}')
if g.is_amp {
g.write(', sizeof($styp))')
}
} }
ast.SelectorExpr { ast.SelectorExpr {
g.expr(it.expr) g.expr(it.expr)
@ -1573,6 +1543,53 @@ fn (g mut Gen) const_decl(node ast.ConstDecl) {
} }
} }
fn (g mut Gen) struct_init(it ast.StructInit) {
mut info := table.Struct{}
mut is_struct := false
sym := g.table.get_type_symbol(it.typ)
if sym.kind == .struct_ {
is_struct = true
info = sym.info as table.Struct
}
// info := g.table.get_type_symbol(it.typ).info as table.Struct
println(info.fields.len)
styp := g.typ(it.typ)
if g.is_amp {
g.out.go_back(1) // delete the & already generated in `prefix_expr()
g.write('($styp*)memdup(&($styp){')
}
else {
g.writeln('($styp){')
}
mut inited_fields := []string
// User set fields
for i, field in it.fields {
field_name := c_name(field)
inited_fields << field
g.write('\t.$field_name = ')
g.expr_with_cast(it.exprs[i], it.expr_types[i], it.expected_types[i])
g.writeln(', ')
}
// The rest of the fields are zeroed.
if is_struct {
for field in info.fields {
if field.name in inited_fields {
continue
}
field_name := c_name(field.name)
zero := g.type_default(field.typ)
g.writeln('\t.$field_name = $zero,') // zer0')
}
}
if it.fields.len == 0 {
g.write('0')
}
g.write('}')
if g.is_amp {
g.write(', sizeof($styp))')
}
}
// { user | name: 'new name' } // { user | name: 'new name' }
fn (g mut Gen) assoc(node ast.Assoc) { fn (g mut Gen) assoc(node ast.Assoc) {
g.writeln('// assoc') g.writeln('// assoc')
@ -2075,3 +2092,97 @@ fn c_name(name_ string) string {
} }
return name return name
} }
fn (g &Gen) type_default(typ table.Type) string {
sym := g.table.get_type_symbol(typ)
if sym.kind == .array {
elem_type := 'int'
return 'new_array(0, 1, sizeof($elem_type))'
}
// Always set pointers to 0
if table.type_is_ptr(typ) {
return '0'
}
// User struct defined in another module.
// if typ.contains('__') {
if sym.kind == .struct_ {
return '{0}'
}
// if typ.ends_with('Fn') { // TODO
// return '0'
// }
// Default values for other types are not needed because of mandatory initialization
match sym.name {
'bool' {
return '0'
}
'string' {
return 'tos3("")'
}
'i8' {
return '0'
}
'i16' {
return '0'
}
'i64' {
return '0'
}
'u16' {
return '0'
}
'u32' {
return '0'
}
'u64' {
return '0'
}
'byte' {
return '0'
}
'int' {
return '0'
}
'rune' {
return '0'
}
'f32' {
return '0.0'
}
'f64' {
return '0.0'
}
'byteptr' {
return '0'
}
'voidptr' {
return '0'
}
else {}
}
return '{0}'
// TODO this results in
// error: expected a field designator, such as '.field = 4'
// - Empty ee= (Empty) { . = {0} } ;
/*
return match typ {
'bool'{ '0'}
'string'{ 'tos3("")'}
'i8'{ '0'}
'i16'{ '0'}
'i64'{ '0'}
'u16'{ '0'}
'u32'{ '0'}
'u64'{ '0'}
'byte'{ '0'}
'int'{ '0'}
'rune'{ '0'}
'f32'{ '0.0'}
'f64'{ '0.0'}
'byteptr'{ '0'}
'voidptr'{ '0'}
else { '{0} '}
}
*/
}

View File

@ -64,7 +64,8 @@ int main(int argc, char** argv) {
println(int_str(localmod__pub_int_const)); println(int_str(localmod__pub_int_const));
int g = ((int)(3.0)); int g = ((int)(3.0));
byte* bytes = ((byte*)(0)); byte* bytes = ((byte*)(0));
User* user_ptr = (User*)memdup(&(User){0}, sizeof(User)); User* user_ptr = (User*)memdup(&(User){ .age = 0,
0}, sizeof(User));
return 0; return 0;
} }