autofree: simplify, clean up, and fix complex arg exprs
parent
c38a050125
commit
ae7689f739
|
@ -110,6 +110,8 @@ mut:
|
||||||
match_sumtype_exprs []ast.Expr
|
match_sumtype_exprs []ast.Expr
|
||||||
match_sumtype_syms []table.TypeSymbol
|
match_sumtype_syms []table.TypeSymbol
|
||||||
// tmp_arg_vars_to_free []string
|
// tmp_arg_vars_to_free []string
|
||||||
|
// autofree_pregen map[string]string
|
||||||
|
autofree_tmp_vars []string // to avoid redefining the same tmp vars in a single function
|
||||||
called_fn_name string
|
called_fn_name string
|
||||||
cur_mod string
|
cur_mod string
|
||||||
is_js_call bool // for handling a special type arg #1 `json.decode(User, ...)`
|
is_js_call bool // for handling a special type arg #1 `json.decode(User, ...)`
|
||||||
|
@ -738,6 +740,7 @@ fn (mut g Gen) stmt(node ast.Stmt) {
|
||||||
defer {
|
defer {
|
||||||
// If we have temporary string exprs to free after this statement, do it. e.g.:
|
// 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);`
|
// `foo('a' + 'b')` => `tmp := 'a' + 'b'; foo(tmp); string_free(&tmp);`
|
||||||
|
/*
|
||||||
if g.pref.autofree { // && !g.inside_or_block {
|
if g.pref.autofree { // && !g.inside_or_block {
|
||||||
// TODO remove the inside_or_block hack. strings are not freed in or{} atm
|
// TODO remove the inside_or_block hack. strings are not freed in or{} atm
|
||||||
if g.strs_to_free.len != 0 {
|
if g.strs_to_free.len != 0 {
|
||||||
|
@ -750,6 +753,7 @@ fn (mut g Gen) stmt(node ast.Stmt) {
|
||||||
// g.strs_to_free.free()
|
// g.strs_to_free.free()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
// println('cgen.stmt()')
|
// println('cgen.stmt()')
|
||||||
// g.writeln('//// stmt start')
|
// g.writeln('//// stmt start')
|
||||||
|
@ -816,7 +820,20 @@ fn (mut g Gen) stmt(node ast.Stmt) {
|
||||||
}
|
}
|
||||||
ast.ExprStmt {
|
ast.ExprStmt {
|
||||||
g.write_v_source_line_info(node.pos)
|
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)
|
||||||
|
}
|
||||||
g.expr(node.expr)
|
g.expr(node.expr)
|
||||||
|
if af {
|
||||||
|
if g.strs_to_free.len > 0 {
|
||||||
|
g.writeln(';\n// strs_to_free2:')
|
||||||
|
for s in g.strs_to_free {
|
||||||
|
g.writeln('string_free(&$s);')
|
||||||
|
}
|
||||||
|
g.strs_to_free = []
|
||||||
|
}
|
||||||
|
}
|
||||||
if g.inside_ternary == 0 && !node.is_expr && !(node.expr is ast.IfExpr) {
|
if g.inside_ternary == 0 && !node.is_expr && !(node.expr is ast.IfExpr) {
|
||||||
g.writeln(';')
|
g.writeln(';')
|
||||||
}
|
}
|
||||||
|
@ -1931,14 +1948,24 @@ fn (mut g Gen) expr(node ast.Expr) {
|
||||||
// if g.fileis('1.strings') {
|
// if g.fileis('1.strings') {
|
||||||
// println('before:' + node.autofree_pregen)
|
// println('before:' + node.autofree_pregen)
|
||||||
// }
|
// }
|
||||||
if g.pref.autofree && node.autofree_pregen != '' { // g.strs_to_free0.len != 0 {
|
if g.pref.autofree {
|
||||||
|
// println('pos=$node.pos.pos')
|
||||||
|
}
|
||||||
|
// if g.pref.autofree && node.autofree_pregen != '' { // g.strs_to_free0.len != 0 {
|
||||||
|
/*
|
||||||
|
if g.pref.autofree {
|
||||||
|
s := g.autofree_pregen[node.pos.pos.str()]
|
||||||
|
if s != '' {
|
||||||
// g.insert_before_stmt('/*START2*/' + g.strs_to_free0.join('\n') + '/*END*/')
|
// g.insert_before_stmt('/*START2*/' + g.strs_to_free0.join('\n') + '/*END*/')
|
||||||
g.insert_before_stmt('/*START3*/' + node.autofree_pregen + '/*END*/')
|
// g.insert_before_stmt('/*START3*/' + node.autofree_pregen + '/*END*/')
|
||||||
|
g.insert_before_stmt('/*START3*/' + s + '/*END*/')
|
||||||
// for s in g.strs_to_free0 {
|
// for s in g.strs_to_free0 {
|
||||||
|
}
|
||||||
// //g.writeln(s)
|
// //g.writeln(s)
|
||||||
// }
|
// }
|
||||||
g.strs_to_free0 = []
|
g.strs_to_free0 = []
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
ast.CastExpr {
|
ast.CastExpr {
|
||||||
// g.write('/*cast*/')
|
// g.write('/*cast*/')
|
||||||
|
|
|
@ -15,6 +15,11 @@ fn (mut g Gen) gen_fn_decl(it ast.FnDecl, skip bool) {
|
||||||
// || it.no_body {
|
// || it.no_body {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
if g.pref.autofree {
|
||||||
|
defer {
|
||||||
|
g.autofree_tmp_vars = []
|
||||||
|
}
|
||||||
|
}
|
||||||
// if g.fileis('vweb.v') {
|
// if g.fileis('vweb.v') {
|
||||||
// println('\ngen_fn_decl() $it.name $it.is_generic $g.cur_generic_type')
|
// println('\ngen_fn_decl() $it.name $it.is_generic $g.cur_generic_type')
|
||||||
// }
|
// }
|
||||||
|
@ -422,9 +427,7 @@ fn (mut g Gen) method_call(node ast.CallExpr) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// TODO2
|
// TODO2
|
||||||
unsafe {
|
// g.generate_tmp_autofree_arg_vars(node, name)
|
||||||
g.generate_tmp_autofree_arg_vars(mut node, name)
|
|
||||||
}
|
|
||||||
//
|
//
|
||||||
// if node.receiver_type != 0 {
|
// if node.receiver_type != 0 {
|
||||||
// g.write('/*${g.typ(node.receiver_type)}*/')
|
// g.write('/*${g.typ(node.receiver_type)}*/')
|
||||||
|
@ -541,9 +544,8 @@ fn (mut g Gen) fn_call(node ast.CallExpr) {
|
||||||
name += '_' + g.typ(node.generic_type)
|
name += '_' + g.typ(node.generic_type)
|
||||||
}
|
}
|
||||||
// TODO2
|
// TODO2
|
||||||
unsafe {
|
// cgen shouldn't modify ast nodes, this should be moved
|
||||||
g.generate_tmp_autofree_arg_vars(mut node, name)
|
// g.generate_tmp_autofree_arg_vars(node, name)
|
||||||
}
|
|
||||||
// Handle `print(x)`
|
// Handle `print(x)`
|
||||||
if is_print && node.args[0].typ != table.string_type { // && !free_tmp_arg_vars {
|
if is_print && node.args[0].typ != table.string_type { // && !free_tmp_arg_vars {
|
||||||
typ := node.args[0].typ
|
typ := node.args[0].typ
|
||||||
|
@ -623,39 +625,44 @@ fn (mut g Gen) fn_call(node ast.CallExpr) {
|
||||||
g.is_json_fn = false
|
g.is_json_fn = false
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (mut g Gen) generate_tmp_autofree_arg_vars(mut node ast.CallExpr, name string) {
|
fn (mut g Gen) autofree_call_pregen(node ast.CallExpr) {
|
||||||
// if g.fileis('1.strings') {
|
g.writeln('// autofree_call()')
|
||||||
// println('gen tmp autofree()')
|
|
||||||
// }
|
|
||||||
// Create a temporary var before fn call for each argument in order to free it (only if it's a complex expression,
|
// 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)`
|
// like `foo(get_string())` or `foo(a + b)`
|
||||||
mut free_tmp_arg_vars := g.autofree && g.pref.experimental && !g.is_builtin_mod &&
|
mut free_tmp_arg_vars := g.autofree && g.pref.experimental && !g.is_builtin_mod &&
|
||||||
node.args.len > 0 && !node.args[0].typ.has_flag(.optional) // TODO copy pasta checker.v
|
node.args.len > 0 && !node.args[0].typ.has_flag(.optional) // TODO copy pasta checker.v
|
||||||
// mut cur_line := ''
|
if !free_tmp_arg_vars {
|
||||||
if free_tmp_arg_vars {
|
return
|
||||||
|
}
|
||||||
free_tmp_arg_vars = false // set the flag to true only if we have at least one arg to free
|
free_tmp_arg_vars = false // set the flag to true only if we have at least one arg to free
|
||||||
g.tmp_count2++
|
g.tmp_count2++
|
||||||
for i, arg in node.args {
|
for i, arg in node.args {
|
||||||
if !arg.is_tmp_autofree {
|
if !arg.is_tmp_autofree {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
if arg.expr is ast.CallExpr {
|
||||||
|
// Any argument can be an expression that has to be freed. Generate a tmp expression
|
||||||
|
// for each of those recursively.
|
||||||
|
g.autofree_call_pregen(arg.expr as ast.CallExpr)
|
||||||
|
}
|
||||||
free_tmp_arg_vars = true
|
free_tmp_arg_vars = true
|
||||||
// t := g.new_tmp_var() + '_arg_expr_${name}_$i'
|
// t := g.new_tmp_var() + '_arg_expr_${name}_$i'
|
||||||
fn_name := node.name.replace('.', '_') // can't use name...
|
fn_name := node.name.replace('.', '_') // can't use name...
|
||||||
t := '_tt${g.tmp_count2}_arg_expr_${fn_name}_$i'
|
// t := '_tt${g.tmp_count2}_arg_expr_${fn_name}_$i'
|
||||||
g.called_fn_name = name
|
t := '_arg_expr_${fn_name}_$i'
|
||||||
str_expr := g.write_expr_to_string(arg.expr)
|
// g.called_fn_name = name
|
||||||
// g.insert_before_stmt('string $t = $str_expr; // new4. to free arg #$i name=$name')
|
used := t in g.autofree_tmp_vars
|
||||||
// g.strs_to_free0 << 'string $t = $str_expr; // new5. to free arg #$i name=$name'
|
if used {
|
||||||
node.autofree_pregen += 'string $t = $str_expr; // new6. to free arg #$i name=$name\n'
|
g.write('$t = ')
|
||||||
// println('setting pregen to ' + node.autofree_pregen)
|
} else {
|
||||||
// cur_line = g.go_before_stmt(0)
|
g.write('string $t = ')
|
||||||
// println('cur line ="$cur_line"')
|
g.autofree_tmp_vars << t
|
||||||
// g.writeln('string $t = $str_expr; // new3. to free arg #$i name=$name')
|
|
||||||
// Now free the tmp arg vars right after the function call
|
|
||||||
g.strs_to_free << 'string_free(&$t);'
|
|
||||||
}
|
}
|
||||||
// g.strs_to_free << (';')
|
g.expr(arg.expr)
|
||||||
|
g.writeln(';// new af pre')
|
||||||
|
// Now free the tmp arg vars right after the function call
|
||||||
|
g.strs_to_free << t
|
||||||
|
// g.strs_to_free << 'string_free(&$t);'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -698,7 +705,8 @@ fn (mut g Gen) call_args(node ast.CallExpr) {
|
||||||
// g.write('_arg_expr_${g.called_fn_name}_$i')
|
// g.write('_arg_expr_${g.called_fn_name}_$i')
|
||||||
// Use these variables here.
|
// Use these variables here.
|
||||||
fn_name := node.name.replace('.', '_')
|
fn_name := node.name.replace('.', '_')
|
||||||
name := '_tt${g.tmp_count2}_arg_expr_${fn_name}_$i'
|
// name := '_tt${g.tmp_count2}_arg_expr_${fn_name}_$i'
|
||||||
|
name := '_arg_expr_${fn_name}_$i'
|
||||||
g.write('/*af arg*/' + name)
|
g.write('/*af arg*/' + name)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -708,7 +716,8 @@ fn (mut g Gen) call_args(node ast.CallExpr) {
|
||||||
if use_tmp_var_autofree {
|
if use_tmp_var_autofree {
|
||||||
// TODO copypasta, move to an inline fn
|
// TODO copypasta, move to an inline fn
|
||||||
fn_name := node.name.replace('.', '_')
|
fn_name := node.name.replace('.', '_')
|
||||||
name := '_tt${g.tmp_count2}_arg_expr_${fn_name}_$i'
|
// name := '_tt${g.tmp_count2}_arg_expr_${fn_name}_$i'
|
||||||
|
name := '_arg_expr_${fn_name}_$i'
|
||||||
g.write('/*af arg2*/' + name)
|
g.write('/*af arg2*/' + name)
|
||||||
} else {
|
} else {
|
||||||
g.expr(arg.expr)
|
g.expr(arg.expr)
|
||||||
|
|
|
@ -41,8 +41,8 @@ pub enum CompilerType {
|
||||||
}
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
list_of_flags_with_param = ['o', 'output', 'd', 'define', 'b', 'backend', 'cc', 'os', 'target-os',
|
list_of_flags_with_param = ['o', 'd', 'define', 'b', 'backend', 'cc', 'os', 'target-os', 'cf',
|
||||||
'cf', 'cflags', 'path']
|
'cflags', 'path']
|
||||||
)
|
)
|
||||||
|
|
||||||
pub struct Preferences {
|
pub struct Preferences {
|
||||||
|
@ -342,7 +342,11 @@ pub fn parse_args(args []string) (&Preferences, string) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
eprint('Unknown argument `$arg`')
|
eprint('Unknown argument `$arg`')
|
||||||
eprintln(if command.len == 0 {''} else {' for command `$command`'})
|
eprintln(if command.len == 0 {
|
||||||
|
''
|
||||||
|
} else {
|
||||||
|
' for command `$command`'
|
||||||
|
})
|
||||||
exit(1)
|
exit(1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,6 +31,7 @@ fn str_tmp_expr() {
|
||||||
println('a' + 'b') // tmp expression result must be freed
|
println('a' + 'b') // tmp expression result must be freed
|
||||||
handle_strings('c' + 'd', 'e' + 'f') // multiple tmp expressions must be freed
|
handle_strings('c' + 'd', 'e' + 'f') // multiple tmp expressions must be freed
|
||||||
handle_int(handle_strings('x' + 'y', 'f')) // exprs 2 levels deep must bee freed
|
handle_int(handle_strings('x' + 'y', 'f')) // exprs 2 levels deep must bee freed
|
||||||
|
handle_strings('1', add_strings('2', '3')) // test a fn that returns a string
|
||||||
}
|
}
|
||||||
|
|
||||||
fn str_tmp_expr_advanced() {
|
fn str_tmp_expr_advanced() {
|
||||||
|
@ -41,7 +42,8 @@ fn str_tmp_expr_advanced() {
|
||||||
// t1.free()
|
// t1.free()
|
||||||
// t2.free()
|
// t2.free()
|
||||||
// t3.free()
|
// t3.free()
|
||||||
// handle_strings('c' + 'd', add_strings('e' + 'f', 'g')) // both lvl 1 and lvl2 exprs must be freed
|
//
|
||||||
|
handle_strings('c' + 'd', add_strings('e' + 'f', 'g')) // both lvl 1 and lvl2 exprs must be freed
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Foo {
|
struct Foo {
|
||||||
|
|
Loading…
Reference in New Issue