cgen/autofree: fix and simplify optionals

pull/6357/head
Alexander Medvednikov 2020-09-12 16:40:52 +02:00
parent f162e61748
commit b74c1805d7
6 changed files with 85 additions and 30 deletions

View File

@ -850,6 +850,15 @@ pub:
pos token.Position
}
// `or { ... }`
pub struct OrExpr2 {
pub:
call_expr CallExpr
stmts []Stmt // inside `or { }`
kind OrKind
pos token.Position
}
pub struct Assoc {
pub:
var_name string

View File

@ -2629,6 +2629,9 @@ pub fn (mut c Checker) expr(node ast.Expr) table.Type {
// never happens
return table.void_type
}
// ast.OrExpr2 {
// return node.typ
// }
ast.ParExpr {
return c.expr(node.expr)
}

View File

@ -1335,6 +1335,33 @@ fn (mut g Gen) gen_assign_stmt(assign_stmt ast.AssignStmt) {
g.writeln('); // free str on re-assignment')
}
}
// Handle optionals. We need to declare a temp variable for them, that's why they are handled
// here, not in call_expr().
// `pos := s.index('x') or { return }`
// ==========>
// Option_int _t190 = string_index(s, _STR("x"));
// if (!_t190.ok) {
// string err = _t190.v_error;
// int errcode = _t190.ecode;
// return;
// }
// int pos = *(int*)_t190.data;
mut gen_or := false
if g.pref.autofree && assign_stmt.op == .decl_assign && assign_stmt.left_types.len == 1 &&
assign_stmt.right[0] is ast.CallExpr {
call_expr := assign_stmt.right[0] as ast.CallExpr
if call_expr.or_block.kind != .absent {
styp := g.typ(call_expr.return_type.set_flag(.optional))
tmp_opt := g.new_tmp_var()
g.write('/*AF opt*/$styp $tmp_opt = ')
g.expr(assign_stmt.right[0])
gen_or = true
g.or_block(tmp_opt, call_expr.or_block, call_expr.return_type)
g.writeln('/*=============ret*/')
// return
}
}
//
// json_test failed w/o this check
if return_type != table.void_type && return_type != 0 {
sym := g.table.get_type_symbol(return_type)

View File

@ -280,9 +280,12 @@ fn (mut g Gen) call_expr(node ast.CallExpr) {
defer {
g.inside_call = false
}
gen_or := node.or_block.kind != .absent
gen_or := node.or_block.kind != .absent && !g.pref.autofree
// if gen_or {
// g.writeln('/*start*/')
// }
is_gen_or_and_assign_rhs := gen_or && g.is_assign_rhs
cur_line := if is_gen_or_and_assign_rhs {
cur_line := if is_gen_or_and_assign_rhs && !g.pref.autofree {
line := g.go_before_stmt(0)
g.out.write(tabs[g.indent])
line
@ -304,10 +307,13 @@ fn (mut g Gen) call_expr(node ast.CallExpr) {
} else {
g.fn_call(node)
}
if gen_or {
g.or_block(tmp_opt, node.or_block, node.return_type)
if gen_or { // && !g.pref.autofree {
if !g.pref.autofree {
g.or_block(tmp_opt, node.or_block, node.return_type)
}
if is_gen_or_and_assign_rhs {
g.write('\n$cur_line$tmp_opt')
g.write('\n $cur_line $tmp_opt')
// g.write('\n /*call_expr cur_line:*/ $cur_line /*C*/ $tmp_opt /*end*/')
// g.insert_before_stmt('\n /* VVV */ $tmp_opt')
}
}
@ -545,13 +551,14 @@ fn (mut g Gen) fn_call(node ast.CallExpr) {
t := '_tt${g.tmp_count2}_arg_expr_${fn_name}_$i'
g.called_fn_name = name
str_expr := g.write_expr_to_string(arg.expr)
g.insert_before_stmt('string $t = $str_expr; // new3. to free $i ')
/*
// g.insert_before_stmt('string $t = $str_expr; // new3. to free $i ')
cur_line = g.go_before_stmt(0)
// println('cur line ="$cur_line"')
g.writeln('string $t = $str_expr; // new. to free $i ')
*/
g.writeln('string $t = $str_expr; // new3. to free $i ')
// Now free the tmp arg vars right after the function call
g.strs_to_free << 'string_free(&$t);'
}
// g.strs_to_free << (';')
}
// Handle `print(x)`
if is_print && node.args[0].typ != table.string_type { // && !free_tmp_arg_vars {
@ -617,7 +624,7 @@ fn (mut g Gen) fn_call(node ast.CallExpr) {
// Simple function call
if free_tmp_arg_vars {
// g.writeln(';')
g.write(cur_line + ' /* cur line*/')
g.write(cur_line + ' /* <== af cur line*/')
}
g.write('${g.get_ternary_name(name)}(')
if g.is_json_fn {
@ -630,22 +637,6 @@ fn (mut g Gen) fn_call(node ast.CallExpr) {
}
g.is_c_call = false
g.is_json_fn = false
if free_tmp_arg_vars { // && tmp_arg_vars_to_free.len > 0 {
// g.writeln(';')
// g.write(cur_line + ' /* cur line*/')
// g.write(tmp)
// Now free the tmp arg vars right after the function call
g.strs_to_free << (';')
for i, arg in node.args {
if arg.is_tmp_autofree {
fn_name := node.name.replace('.', '_')
tmp := '_tt${g.tmp_count2}_arg_expr_${fn_name}_$i'
g.strs_to_free << ('string_free(&$tmp);')
// g.writeln('string_free(&$tmp);')
}
}
// g.writeln('')
}
}
// fn (mut g Gen) call_args(args []ast.CallArg, expected_types []table.Type, tmp_arg_vars_to_free []string) {

View File

@ -9,6 +9,7 @@ import v.token
import v.util
pub fn (mut p Parser) call_expr(language table.Language, mod string) ast.CallExpr {
// pub fn (mut p Parser) call_expr(language table.Language, mod string) ast.Expr {
first_pos := p.tok.position()
mut fn_name := if language == .c {
'C.$p.check_name()'
@ -88,6 +89,25 @@ pub fn (mut p Parser) call_expr(language table.Language, mod string) ast.CallExp
fn_name = registered.name
}
}
/*
call_expr := ast.CallExpr{
name: fn_name
args: args
mod: fn_mod
pos: pos
language: language
generic_type: generic_type
}
if or_kind != .absent {
return ast.OrExpr2{
call_expr: call_expr
stmts: or_stmts
kind: or_kind
pos: pos
}
}
return call_expr
*/
return ast.CallExpr{
name: fn_name
args: args

View File

@ -64,17 +64,21 @@ fn match_expr() string {
return res
}
/*
fn opt(s string) ?int {
return 1
}
fn optional_str() {
q := 'select'
s := 'x'
pos := s.index('query: $q') or {
pos2 := opt('query:$q') or {
// pos := s.index('query: $q') or {
println('exiting')
return
}
println(pos)
println(pos2)
}
*/
fn main() {
println('start')
foo()
@ -82,6 +86,7 @@ fn main() {
str_inter()
match_expr()
reassign_str()
// optional_str()
// str_replace()
println('end')
}