checker, cgen: generate .free() methods for custom structs automatically (#11529)
parent
2eeba4758a
commit
39ad6da506
|
@ -2472,6 +2472,8 @@ pub fn (mut c Checker) method_call(mut node ast.CallExpr) ast.Type {
|
||||||
}
|
}
|
||||||
c.fail_if_unreadable(node.left, left_type, 'receiver')
|
c.fail_if_unreadable(node.left, left_type, 'receiver')
|
||||||
return ast.string_type
|
return ast.string_type
|
||||||
|
} else if method_name == 'free' {
|
||||||
|
return ast.void_type
|
||||||
}
|
}
|
||||||
// call struct field fn type
|
// call struct field fn type
|
||||||
// TODO: can we use SelectorExpr for all? this dosent really belong here
|
// TODO: can we use SelectorExpr for all? this dosent really belong here
|
||||||
|
|
|
@ -0,0 +1,65 @@
|
||||||
|
// Copyright (c) 2019-2021 Alexander Medvednikov. All rights reserved.
|
||||||
|
// Use of this source code is governed by an MIT license that can be found in the LICENSE file.
|
||||||
|
module c
|
||||||
|
|
||||||
|
import v.ast
|
||||||
|
import strings
|
||||||
|
|
||||||
|
fn (mut g Gen) gen_free_method_for_type(typ ast.Type) string {
|
||||||
|
styp := g.typ(typ).replace('*', '')
|
||||||
|
mut sym := g.table.get_type_symbol(g.unwrap_generic(typ))
|
||||||
|
mut fn_name := styp_to_free_fn_name(styp)
|
||||||
|
if mut sym.info is ast.Alias {
|
||||||
|
if sym.info.is_import {
|
||||||
|
sym = g.table.get_type_symbol(sym.info.parent_type)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if sym.kind == .map {
|
||||||
|
return 'map_free'
|
||||||
|
} else if sym.kind == .array {
|
||||||
|
return 'array_free'
|
||||||
|
}
|
||||||
|
|
||||||
|
if sym.has_method('free') {
|
||||||
|
return fn_name
|
||||||
|
}
|
||||||
|
match mut sym.info {
|
||||||
|
ast.Struct {
|
||||||
|
g.gen_free_for_struct(sym.info, styp, fn_name)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
println(g.table.type_str(typ))
|
||||||
|
verror("could not generate free method '$fn_name' for type '$styp'")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return fn_name
|
||||||
|
}
|
||||||
|
|
||||||
|
fn (mut g Gen) gen_free_for_struct(info ast.Struct, styp string, fn_name string) {
|
||||||
|
g.type_definitions.writeln('void ${fn_name}($styp* it); // auto')
|
||||||
|
mut fn_builder := strings.new_builder(512)
|
||||||
|
defer {
|
||||||
|
g.auto_fn_definitions << fn_builder.str()
|
||||||
|
}
|
||||||
|
fn_builder.writeln('void ${fn_name}($styp* it) {')
|
||||||
|
for field in info.fields {
|
||||||
|
sym := g.table.get_type_symbol(g.unwrap_generic(field.typ))
|
||||||
|
|
||||||
|
if sym.kind !in [.string, .array, .map, .struct_] {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
mut field_styp := g.typ(field.typ).replace('*', '')
|
||||||
|
field_styp_fn_name := if sym.has_method('free') {
|
||||||
|
'${field_styp}_free'
|
||||||
|
} else {
|
||||||
|
g.gen_free_method_for_type(field.typ)
|
||||||
|
}
|
||||||
|
fn_builder.writeln('\t${field_styp_fn_name}(&(it->$field.name));')
|
||||||
|
}
|
||||||
|
fn_builder.writeln('}')
|
||||||
|
}
|
||||||
|
|
||||||
|
[inline]
|
||||||
|
fn styp_to_free_fn_name(styp string) string {
|
||||||
|
return styp.replace_each(['*', '', '.', '__', ' ', '__']) + '_free'
|
||||||
|
}
|
|
@ -796,6 +796,12 @@ fn (mut g Gen) method_call(node ast.CallExpr) {
|
||||||
rec_type = rec_type.clear_flag(.shared_f).set_nr_muls(0)
|
rec_type = rec_type.clear_flag(.shared_f).set_nr_muls(0)
|
||||||
}
|
}
|
||||||
g.gen_str_method_for_type(rec_type)
|
g.gen_str_method_for_type(rec_type)
|
||||||
|
} else if node.name == 'free' {
|
||||||
|
mut rec_type := node.receiver_type
|
||||||
|
if rec_type.has_flag(.shared_f) {
|
||||||
|
rec_type = rec_type.clear_flag(.shared_f).set_nr_muls(0)
|
||||||
|
}
|
||||||
|
g.gen_free_method_for_type(rec_type)
|
||||||
}
|
}
|
||||||
mut has_cast := false
|
mut has_cast := false
|
||||||
if left_sym.kind == .map && node.name in ['clone', 'move'] {
|
if left_sym.kind == .map && node.name in ['clone', 'move'] {
|
||||||
|
|
|
@ -0,0 +1,17 @@
|
||||||
|
struct Info {
|
||||||
|
name string
|
||||||
|
notes []string
|
||||||
|
maps map[int]int
|
||||||
|
info SubInfo
|
||||||
|
}
|
||||||
|
|
||||||
|
struct SubInfo {
|
||||||
|
path string
|
||||||
|
files []string
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_autogen_free() {
|
||||||
|
info := &Info{}
|
||||||
|
info.free()
|
||||||
|
assert true
|
||||||
|
}
|
Loading…
Reference in New Issue