From 5e76d53fcdb2c655d66d2907cffab58a542a6f69 Mon Sep 17 00:00:00 2001 From: Delyan Angelov Date: Sun, 5 Apr 2020 11:37:14 +0300 Subject: [PATCH] compiler: support default values in optional blocks --- vlib/v/gen/cgen.v | 63 ++++++++++++++++++- vlib/v/tests/option_default_values_test.v | 77 +++++++++++++++++++++++ 2 files changed, 137 insertions(+), 3 deletions(-) create mode 100644 vlib/v/tests/option_default_values_test.v diff --git a/vlib/v/gen/cgen.v b/vlib/v/gen/cgen.v index 0d01e1e564..3bd7d88d96 100644 --- a/vlib/v/gen/cgen.v +++ b/vlib/v/gen/cgen.v @@ -2524,14 +2524,71 @@ fn (g mut Gen) fn_call(node ast.CallExpr) { // to access its fields (`.ok`, `.error` etc) // `os.cp(...)` => `Option bool tmp = os__cp(...); if (!tmp.ok) { ... }` fn (g mut Gen) or_block(var_name string, stmts []ast.Stmt, return_type table.Type) { + mr_styp := g.typ(return_type) + mr_styp2 := mr_styp[7..] // remove Option_ g.writeln(';') // or') g.writeln('if (!${var_name}.ok) {') - g.writeln('string err = ${var_name}.v_error;') - g.writeln('int errcode = ${var_name}.ecode;') - g.stmts(stmts) + g.writeln('\tstring err = ${var_name}.v_error;') + g.writeln('\tint errcode = ${var_name}.ecode;') + + last_type, type_of_last_expression := g.type_of_last_statement( stmts ) + if last_type == 'v.ast.ExprStmt' && type_of_last_expression != 'void' { + g.indent++ + for i, stmt in stmts { + if i == stmts.len-1 { + g.indent-- + g.write('\t*(${mr_styp2}*) ${var_name}.data = ') + } + g.stmt(stmt) + } + } else { + g.stmts(stmts) + } g.write('}') } + +fn (g mut Gen) type_of_last_statement(stmts []ast.Stmt) (string,string) { + mut last_type := '' + mut last_expr_result_type := '' + if stmts.len > 0 { + last_stmt := stmts[stmts.len-1] + last_type = typeof(last_stmt) + if last_type == 'v.ast.ExprStmt' { + match last_stmt { + ast.ExprStmt { + it_expr_type := typeof(it.expr) + if it_expr_type == 'v.ast.CallExpr' { + g.writeln('\t // typeof it_expr_type: $it_expr_type') + last_expr_result_type = g.type_of_call_expr(it.expr) + }else{ + last_expr_result_type = it_expr_type + } + } + else { + last_expr_result_type = last_type + } + } + } + } + g.writeln('\t// last_type: $last_type') + g.writeln('\t// last_expr_result_type: $last_expr_result_type') + return last_type, last_expr_result_type +} + +fn (g mut Gen) type_of_call_expr(node ast.Expr) string { + match node { + ast.CallExpr { + return g.typ(it.return_type) + } + else { + return typeof(node) + } + } + return '' +} + + // `a in [1,2,3]` => `a == 1 || a == 2 || a == 3` fn (g mut Gen) in_optimization(left ast.Expr, right ast.ArrayInit) { is_str := right.elem_type == table.string_type diff --git a/vlib/v/tests/option_default_values_test.v b/vlib/v/tests/option_default_values_test.v new file mode 100644 index 0000000000..4d0eea62e0 --- /dev/null +++ b/vlib/v/tests/option_default_values_test.v @@ -0,0 +1,77 @@ + +struct Abc { + x int +} + +fn i_0(x int) ?int { + if x == 0 { + return error('my error 1') + } + return x +} + +fn struct_0(x int) ?Abc { + if x == 0 { + return error('my error 2') + } + return Abc{x} +} + +fn string_0(x int) ?string { + if x == 0 { + return error('my error 3') + } + return '$x' +} + +fn return_a_string() string { + return 'abcdef' +} + +// + +fn test_optional_int() { + a := i_0(0) or { + 4999 + } + assert a == 4999 + b := i_0(4123) or { + 4999 + } + assert b == 4123 +} + +fn test_optional_struct() { + sa := struct_0(0) or { + Abc{7999} + } + assert sa.x == 7999 + sb := struct_0(3456) or { + Abc{7999} + } + assert sb.x == 3456 +} + +fn test_optional_with_statements_before_last_expression() { + s := struct_0(0) or { + eprintln('hello') + Abc{12345} + } + assert s.x == 12345 +} + +fn test_optional_with_fn_call_as_last_expression() { + s := string_0(0) or { + return_a_string() + } + assert s == 'abcdef' +} + +fn test_optional_with_fn_call_last_expr_and_preceding_statements() { + s := string_0(0) or { + eprintln('hello') + println('world') + return_a_string() + } + assert s == 'abcdef' +}