1
0
mirror of https://github.com/vlang/v.git synced 2023-08-10 21:13:21 +03:00

compiler: optionals default value

This commit is contained in:
joe-conigliaro
2019-11-04 10:38:49 +11:00
committed by Alexander Medvednikov
parent 4e64a58ac1
commit df5faf35e5
14 changed files with 86 additions and 26 deletions

View File

@ -174,9 +174,9 @@ fn (v mut V) cc() {
println('$path not found... building module $imp')
if path.ends_with('vlib/ui.o') {
println('copying ui...')
os.cp('$vdir/thirdparty/ui/ui.o', path)
os.cp('$vdir/thirdparty/ui/ui.vh', v_modules_path +
'/vlib/ui.vh')
_ = os.cp('$vdir/thirdparty/ui/ui.o', path) or { panic('error copying ui files') }
_ = os.cp('$vdir/thirdparty/ui/ui.vh', v_modules_path +
'/vlib/ui.vh') or { panic('error copying ui files') }
} else {
os.system('$vexe build module vlib${os.path_separator}$imp_path')

View File

@ -11,12 +11,15 @@ fn (p mut Parser) gen_or_else(pos int) string {
}
*/
// returns the type of the new variable
fn (p mut Parser) gen_var_decl(name string, is_static bool) string {
// Generate expression to tmp because we need its type first
// `[typ] [name] = bool_expression();`
pos := p.cgen.add_placeholder()
p.is_var_decl = true
mut typ := p.bool_expression()
p.is_var_decl = false
if typ.starts_with('...') { typ = typ[3..] }
//p.gen('/*after expr*/')
// Option check ? or {
@ -68,10 +71,13 @@ fn (p mut Parser) gen_blank_identifier_assign() {
is_indexer := p.peek() == .lsbr
is_fn_call, next_expr := p.is_next_expr_fn_call()
pos := p.cgen.add_placeholder()
p.is_var_decl = true
typ := p.bool_expression()
p.is_var_decl = false
if !is_indexer && !is_fn_call {
p.error_with_token_index('assigning `$next_expr` to `_` is redundant', assign_error_tok_idx)
}
// handle or
if p.tok == .key_orelse {
p.gen_handle_option_or_else(typ, '', pos)
} else {
@ -93,6 +99,7 @@ fn (p mut Parser) gen_handle_option_or_else(_typ, name string, fn_call_ph int) s
p.cgen.set_placeholder(fn_call_ph, '$typ $tmp = ')
typ = typ[7..]
p.genln(';')
or_tok_idx := p.token_idx
p.check(.key_orelse)
p.check(.lcbr)
p.register_var(Var {
@ -107,15 +114,26 @@ fn (p mut Parser) gen_handle_option_or_else(_typ, name string, fn_call_ph int) s
is_mut: false
is_used: true
})
if is_assign {
p.genln('$typ $name;')
}
p.genln('if (!$tmp .ok) {')
p.genln('string err = $tmp . error;')
p.genln('int errcode = $tmp . ecode;')
p.statements()
if is_assign {
p.genln('$typ $name = *($typ*) $tmp . data;')
last_ph := p.cgen.add_placeholder()
last_typ := p.statements()
if is_assign && last_typ == typ {
expr_line := p.cgen.lines[p.cgen.lines.len-3]
last_expr := expr_line[last_ph..]
p.cgen.lines[p.cgen.lines.len-3] = ''
p.genln('if (!$tmp .ok) {')
p.genln('$name = $last_expr;')
p.genln('}')
} else if is_assign {
p.genln('$name = *($typ*) $tmp . data;')
}
if !p.returns && p.prev_tok2 != .key_continue && p.prev_tok2 != .key_break {
p.error('`or` block must return/exit/continue/break/panic')
if !p.returns && last_typ != typ && is_assign && p.prev_tok2 != .key_continue && p.prev_tok2 != .key_break {
p.error_with_token_index('`or` block must provide a default value or return/exit/continue/break/panic', or_tok_idx)
}
p.returns = false
return typ

View File

@ -45,6 +45,7 @@ mut:
inside_return_expr bool
inside_unsafe bool
is_struct_init bool
is_var_decl bool
if_expr_cnt int
for_expr_cnt int // to detect whether `continue` can be used
ptr_cast bool
@ -1700,6 +1701,7 @@ fn (p mut Parser) name_expr() string {
// p.error('`$f.name` used as value')
}
fn_call_ph := p.cgen.add_placeholder()
// println('call to fn $f.name of type $f.typ')
// TODO replace the following dirty hacks (needs ptr access to fn table)
new_f := f
@ -1713,6 +1715,17 @@ fn (p mut Parser) name_expr() string {
}
f = new_f
// optional function call `function() or {}`, no return assignment
is_or_else := p.tok == .key_orelse
if !p.is_var_decl && is_or_else {
f.typ = p.gen_handle_option_or_else(f.typ, '', fn_call_ph)
}
else if !p.is_var_decl && !is_or_else && !p.inside_return_expr &&
f.typ.starts_with('Option_') {
opt_type := f.typ[7..]
p.error('unhandled option type: `?$opt_type`')
}
// dot after a function call: `get_user().age`
if p.tok == .dot {
mut typ := ''
@ -2049,11 +2062,21 @@ struct $typ.name {
return field.typ
}
// method
method := p.table.find_method(typ, field_name) or {
mut method := p.table.find_method(typ, field_name) or {
p.error_with_token_index('could not find method `$field_name`', fname_tidx) // should never happen
exit(1)
}
p.fn_call(mut method, method_ph, '', str_typ)
// optional method call `a.method() or {}`, no return assignment
is_or_else := p.tok == .key_orelse
if !p.is_var_decl && is_or_else {
method.typ = p.gen_handle_option_or_else(method.typ, '', method_ph)
}
else if !p.is_var_decl && !is_or_else && !p.inside_return_expr &&
method.typ.starts_with('Option_') {
opt_type := method.typ[7..]
p.error('unhandled option type: `?$opt_type`')
}
// Methods returning `array` should return `array_string` etc
if method.typ == 'array' && typ.name.starts_with('array_') {
return typ.name
@ -3098,7 +3121,9 @@ fn (p mut Parser) if_st(is_expr bool, elif_depth int) string {
var_name := p.lit
p.next()
p.check(.decl_assign)
p.is_var_decl = true
option_type, expr := p.tmp_expr()// := p.bool_expression()
p.is_var_decl = false
typ := option_type[7..]
// Option_User tmp = get_user(1);
// if (tmp.ok) {

View File

@ -46,6 +46,8 @@ fn test_defer_early_exit() {
fn test_defer_option() {
mut ok := Num{0}
set_num_opt(mut ok)
set_num_opt(mut ok) or {
assert false
}
assert ok.val == 1
}

View File

@ -58,3 +58,15 @@ fn test_if_opt() {
assert 1 == 1
println('nice')
}
fn for_opt_default() ?string {
return error('awww')
}
fn test_opt_default() {
a := for_opt_default() or {
// panic(err)
'default'
}
assert a == 'default'
}