diff --git a/vlib/v/ast/ast.v b/vlib/v/ast/ast.v index cd9c6fc3ca..7addf4ecb8 100644 --- a/vlib/v/ast/ast.v +++ b/vlib/v/ast/ast.v @@ -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 diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v index 39e4e90302..bcb8a7fa7e 100644 --- a/vlib/v/checker/checker.v +++ b/vlib/v/checker/checker.v @@ -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) } diff --git a/vlib/v/gen/cgen.v b/vlib/v/gen/cgen.v index f31ac4b21f..689c927519 100644 --- a/vlib/v/gen/cgen.v +++ b/vlib/v/gen/cgen.v @@ -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) diff --git a/vlib/v/gen/fn.v b/vlib/v/gen/fn.v index b262244bd6..c4abe66018 100644 --- a/vlib/v/gen/fn.v +++ b/vlib/v/gen/fn.v @@ -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) { diff --git a/vlib/v/parser/fn.v b/vlib/v/parser/fn.v index d2cba036b3..de7a572fc5 100644 --- a/vlib/v/parser/fn.v +++ b/vlib/v/parser/fn.v @@ -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 diff --git a/vlib/v/tests/valgrind/1.strings_and_arrays.v b/vlib/v/tests/valgrind/1.strings_and_arrays.v index a25d1e2d68..e580a36bd3 100644 --- a/vlib/v/tests/valgrind/1.strings_and_arrays.v +++ b/vlib/v/tests/valgrind/1.strings_and_arrays.v @@ -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') }