autofree: handle more statements
parent
acc85be5ae
commit
55536bb364
|
@ -241,6 +241,8 @@ two ',
|
|||
four!']
|
||||
s = strings.join(' ')
|
||||
assert s.contains('one') && s.contains('two ') && s.contains('four')
|
||||
empty := []string{len:0}
|
||||
assert empty.join('A') == ''
|
||||
}
|
||||
|
||||
fn test_clone() {
|
||||
|
@ -906,7 +908,7 @@ fn test_sorter() {
|
|||
i: 102
|
||||
}
|
||||
]
|
||||
cmp := fn (a, b &Ka) int {
|
||||
cmp := fn (a &Ka, b &Ka) int {
|
||||
return compare_strings(a.s, b.s)
|
||||
}
|
||||
arr.sort_with_compare(cmp)
|
||||
|
|
|
@ -100,8 +100,8 @@ mut:
|
|||
inside_vweb_tmpl bool
|
||||
inside_return bool
|
||||
inside_or_block bool
|
||||
strs_to_free0 []string // strings.Builder
|
||||
strs_to_free []string // strings.Builder
|
||||
// strs_to_free0 []string // strings.Builder
|
||||
inside_call bool
|
||||
has_main bool
|
||||
inside_const bool
|
||||
|
@ -111,6 +111,7 @@ mut:
|
|||
match_sumtype_syms []table.TypeSymbol
|
||||
// tmp_arg_vars_to_free []string
|
||||
// autofree_pregen map[string]string
|
||||
// autofree_pregen_buf strings.Builder
|
||||
// autofree_tmp_vars []string // to avoid redefining the same tmp vars in a single function
|
||||
called_fn_name string
|
||||
cur_mod string
|
||||
|
@ -755,6 +756,9 @@ fn (mut g Gen) stmt(node ast.Stmt) {
|
|||
defer {
|
||||
// If we have temporary string exprs to free after this statement, do it. e.g.:
|
||||
// `foo('a' + 'b')` => `tmp := 'a' + 'b'; foo(tmp); string_free(&tmp);`
|
||||
if g.pref.autofree {
|
||||
g.autofree_call_postgen()
|
||||
}
|
||||
/*
|
||||
if g.pref.autofree { // && !g.inside_or_block {
|
||||
// TODO remove the inside_or_block hack. strings are not freed in or{} atm
|
||||
|
@ -835,14 +839,14 @@ fn (mut g Gen) stmt(node ast.Stmt) {
|
|||
}
|
||||
ast.ExprStmt {
|
||||
g.write_v_source_line_info(node.pos)
|
||||
af := g.pref.autofree && node.expr is ast.CallExpr && !g.is_builtin_mod
|
||||
if af {
|
||||
g.autofree_call_pregen(node.expr as ast.CallExpr)
|
||||
}
|
||||
// af := g.pref.autofree && node.expr is ast.CallExpr && !g.is_builtin_mod
|
||||
// if af {
|
||||
// g.autofree_call_pregen(node.expr as ast.CallExpr)
|
||||
// }
|
||||
g.expr(node.expr)
|
||||
if af {
|
||||
g.autofree_call_postgen()
|
||||
}
|
||||
// if af {
|
||||
// g.autofree_call_postgen()
|
||||
// }
|
||||
if g.inside_ternary == 0 && !node.is_expr && !(node.expr is ast.IfExpr) {
|
||||
g.writeln(';')
|
||||
}
|
||||
|
@ -1011,9 +1015,9 @@ fn (mut g Gen) stmt(node ast.Stmt) {
|
|||
af := g.pref.autofree && node.exprs.len > 0 && node.exprs[0] is ast.CallExpr && !g.is_builtin_mod
|
||||
if g.pref.autofree {
|
||||
g.writeln('// ast.Return free')
|
||||
if af {
|
||||
g.autofree_call_pregen(node.exprs[0] as ast.CallExpr)
|
||||
}
|
||||
// if af {
|
||||
// g.autofree_call_pregen(node.exprs[0] as ast.CallExpr)
|
||||
// }
|
||||
// g.autofree_scope_vars(node.pos.pos)
|
||||
g.write_autofree_stmts_when_needed(node)
|
||||
}
|
||||
|
@ -1390,11 +1394,12 @@ fn (mut g Gen) gen_assign_stmt(assign_stmt ast.AssignStmt) {
|
|||
}
|
||||
}
|
||||
// Autofree tmp arg vars
|
||||
first_right := assign_stmt.right[0]
|
||||
af := g.pref.autofree && first_right is ast.CallExpr && !g.is_builtin_mod
|
||||
if af {
|
||||
g.autofree_call_pregen(first_right as ast.CallExpr)
|
||||
}
|
||||
// first_right := assign_stmt.right[0]
|
||||
// af := g.pref.autofree && first_right is ast.CallExpr && !g.is_builtin_mod
|
||||
// if af {
|
||||
// g.autofree_call_pregen(first_right as ast.CallExpr)
|
||||
// }
|
||||
//
|
||||
//
|
||||
// Handle optionals. We need to declare a temp variable for them, that's why they are handled
|
||||
// here, not in call_expr().
|
||||
|
@ -1422,9 +1427,9 @@ fn (mut g Gen) gen_assign_stmt(assign_stmt ast.AssignStmt) {
|
|||
gen_or = true
|
||||
g.or_block(tmp_opt, call_expr.or_block, call_expr.return_type)
|
||||
g.writeln('/*=============ret*/')
|
||||
if af && is_optional {
|
||||
g.autofree_call_postgen()
|
||||
}
|
||||
// if af && is_optional {
|
||||
// g.autofree_call_postgen()
|
||||
// }
|
||||
// return
|
||||
}
|
||||
}
|
||||
|
@ -1987,7 +1992,15 @@ fn (mut g Gen) expr(node ast.Expr) {
|
|||
// if g.fileis('1.strings') {
|
||||
// println('before:' + node.autofree_pregen)
|
||||
// }
|
||||
if g.pref.autofree {
|
||||
if g.pref.autofree && !g.is_builtin_mod && g.strs_to_free0.len == 0 {
|
||||
// if len != 0, that means we are handling call expr inside call expr (arg)
|
||||
// and it'll get messed up here, since it's handled recursively in autofree_call_pregen()
|
||||
// so just skip it
|
||||
g.autofree_call_pregen(node)
|
||||
if g.strs_to_free0.len > 0 {
|
||||
g.insert_before_stmt(g.strs_to_free0.join('\n'))
|
||||
}
|
||||
g.strs_to_free0 = []
|
||||
// println('pos=$node.pos.pos')
|
||||
}
|
||||
// if g.pref.autofree && node.autofree_pregen != '' { // g.strs_to_free0.len != 0 {
|
||||
|
|
|
@ -620,7 +620,7 @@ fn (mut g Gen) fn_call(node ast.CallExpr) {
|
|||
}
|
||||
|
||||
fn (mut g Gen) autofree_call_pregen(node ast.CallExpr) {
|
||||
g.writeln('// autofree_call()')
|
||||
// g.writeln('// autofree_call_pregen()')
|
||||
// Create a temporary var before fn call for each argument in order to free it (only if it's a complex expression,
|
||||
// like `foo(get_string())` or `foo(a + b)`
|
||||
mut free_tmp_arg_vars := g.autofree && g.pref.experimental && !g.is_builtin_mod &&
|
||||
|
@ -648,19 +648,22 @@ fn (mut g Gen) autofree_call_pregen(node ast.CallExpr) {
|
|||
// g.called_fn_name = name
|
||||
// used := t in g.autofree_tmp_vars
|
||||
used := scope.known_var(t)
|
||||
if used {
|
||||
g.write('$t = ')
|
||||
mut s := if used {
|
||||
'$t = '
|
||||
} else {
|
||||
g.write('string $t = ')
|
||||
scope.register(t, ast.Var{
|
||||
name: t
|
||||
typ: table.string_type
|
||||
is_arg: true // TODO hack so that it's not freed twice when out of scope. it's probably better to use one model
|
||||
})
|
||||
'string $t = '
|
||||
// g.autofree_tmp_vars << t
|
||||
}
|
||||
g.expr(arg.expr)
|
||||
g.writeln(';// new af pre')
|
||||
// g.expr(arg.expr)
|
||||
s += g.write_expr_to_string(arg.expr)
|
||||
// g.writeln(';// new af pre')
|
||||
s += ';// new af2 pre'
|
||||
g.strs_to_free0 << s
|
||||
// Now free the tmp arg vars right after the function call
|
||||
g.strs_to_free << t
|
||||
// g.strs_to_free << 'string_free(&$t);'
|
||||
|
|
|
@ -13,14 +13,14 @@ fn foo() {
|
|||
// nums.free() // this should result in a double free and a CI error
|
||||
}
|
||||
|
||||
fn handle_strings(s, p string) int {
|
||||
fn handle_strings(s string, p string) int {
|
||||
return 0
|
||||
}
|
||||
|
||||
fn handle_int(n int) {
|
||||
}
|
||||
|
||||
fn add_strings(a, b string) string {
|
||||
fn add_strings(a string, b string) string {
|
||||
return a + b
|
||||
}
|
||||
|
||||
|
@ -120,6 +120,25 @@ fn optional_return() {
|
|||
}
|
||||
}
|
||||
|
||||
fn handle_string(s string) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
fn if_cond() {
|
||||
// handle_string('1' + '2')
|
||||
if handle_string('1' + '2') {
|
||||
// if '1' + '2' == '12' {
|
||||
println('yes')
|
||||
} else {
|
||||
println('no')
|
||||
}
|
||||
}
|
||||
|
||||
fn addition_with_tmp_expr() {
|
||||
x := 1 + handle_strings('a' + 'b', 'c')
|
||||
println(x)
|
||||
}
|
||||
|
||||
fn tt() {
|
||||
// time.parse_rfc2822('1234')
|
||||
}
|
||||
|
@ -136,6 +155,8 @@ fn main() {
|
|||
optional_str()
|
||||
optional_return()
|
||||
// str_replace()
|
||||
if_cond()
|
||||
addition_with_tmp_expr()
|
||||
println('end')
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue