for.v and match.v; do not allow arrays in `match`
parent
bd18f50c8a
commit
fdd4afa392
|
@ -0,0 +1,196 @@
|
||||||
|
// Copyright (c) 2019 Alexander Medvednikov. All rights reserved.
|
||||||
|
// Use of this source code is governed by an MIT license
|
||||||
|
// that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
module compiler
|
||||||
|
|
||||||
|
fn (p mut Parser) for_st() {
|
||||||
|
p.check(.key_for)
|
||||||
|
p.fgen(' ')
|
||||||
|
p.for_expr_cnt++
|
||||||
|
next_tok := p.peek()
|
||||||
|
//debug := p.scanner.file_path.contains('r_draw')
|
||||||
|
p.open_scope()
|
||||||
|
if p.tok == .lcbr {
|
||||||
|
// Infinite loop
|
||||||
|
p.gen('while (1) {')
|
||||||
|
}
|
||||||
|
else if p.tok == .key_mut {
|
||||||
|
p.error('`mut` is not required in for loops')
|
||||||
|
}
|
||||||
|
// for i := 0; i < 10; i++ {
|
||||||
|
else if next_tok == .decl_assign || next_tok == .assign || p.tok == .semicolon {
|
||||||
|
p.genln('for (')
|
||||||
|
if next_tok == .decl_assign {
|
||||||
|
p.var_decl()
|
||||||
|
}
|
||||||
|
else if p.tok != .semicolon {
|
||||||
|
// allow `for ;; i++ {`
|
||||||
|
// Allow `for i = 0; i < ...`
|
||||||
|
p.statement(false)
|
||||||
|
}
|
||||||
|
p.check(.semicolon)
|
||||||
|
p.gen(' ; ')
|
||||||
|
p.fgen(' ')
|
||||||
|
if p.tok != .semicolon {
|
||||||
|
p.bool_expression()
|
||||||
|
}
|
||||||
|
p.check(.semicolon)
|
||||||
|
p.gen(' ; ')
|
||||||
|
p.fgen(' ')
|
||||||
|
if p.tok != .lcbr {
|
||||||
|
p.statement(false)
|
||||||
|
}
|
||||||
|
p.genln(') { ')
|
||||||
|
}
|
||||||
|
// for i, val in array
|
||||||
|
else if p.peek() == .comma {
|
||||||
|
/*
|
||||||
|
`for i, val in array {`
|
||||||
|
==>
|
||||||
|
```
|
||||||
|
array_int tmp = array;
|
||||||
|
for (int i = 0; i < tmp.len; i++) {
|
||||||
|
int val = tmp[i];
|
||||||
|
```
|
||||||
|
*/
|
||||||
|
i := p.check_name()
|
||||||
|
p.check(.comma)
|
||||||
|
val := p.check_name()
|
||||||
|
if i == '_' && val == '_' {
|
||||||
|
p.error('no new variables on the left side of `in`')
|
||||||
|
}
|
||||||
|
p.fgen(' ')
|
||||||
|
p.check(.key_in)
|
||||||
|
p.fgen(' ')
|
||||||
|
tmp := p.get_tmp()
|
||||||
|
p.cgen.start_tmp()
|
||||||
|
mut typ := p.bool_expression()
|
||||||
|
is_arr := typ.starts_with('array_')
|
||||||
|
is_map := typ.starts_with('map_')
|
||||||
|
is_str := typ == 'string'
|
||||||
|
is_variadic_arg := typ.starts_with('varg_')
|
||||||
|
if !is_arr && !is_str && !is_map && !is_variadic_arg {
|
||||||
|
p.error('cannot range over type `$typ`')
|
||||||
|
}
|
||||||
|
expr := p.cgen.end_tmp()
|
||||||
|
if !is_variadic_arg {
|
||||||
|
if p.is_js {
|
||||||
|
p.genln('var $tmp = $expr;')
|
||||||
|
} else {
|
||||||
|
p.genln('$typ $tmp = $expr;')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// typ = strings.Replace(typ, "_ptr", "*", -1)
|
||||||
|
mut i_var_type := 'int'
|
||||||
|
if is_variadic_arg {
|
||||||
|
typ = typ[5..]
|
||||||
|
p.gen_for_varg_header(i, expr, typ, val)
|
||||||
|
}
|
||||||
|
else if is_arr {
|
||||||
|
typ = typ[6..]
|
||||||
|
p.gen_for_header(i, tmp, typ, val)
|
||||||
|
}
|
||||||
|
else if is_map {
|
||||||
|
i_var_type = 'string'
|
||||||
|
typ = typ[4..]
|
||||||
|
p.gen_for_map_header(i, tmp, typ, val, typ)
|
||||||
|
}
|
||||||
|
else if is_str {
|
||||||
|
typ = 'byte'
|
||||||
|
p.gen_for_str_header(i, tmp, typ, val)
|
||||||
|
}
|
||||||
|
// Register temp vars
|
||||||
|
if i != '_' {
|
||||||
|
p.register_var(Var {
|
||||||
|
name: i
|
||||||
|
typ: i_var_type
|
||||||
|
is_mut: true
|
||||||
|
is_changed: true
|
||||||
|
})
|
||||||
|
}
|
||||||
|
if val != '_' {
|
||||||
|
p.register_var(Var {
|
||||||
|
name: val
|
||||||
|
typ: typ
|
||||||
|
ptr: typ.contains('*')
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// `for val in vals`
|
||||||
|
else if p.peek() == .key_in {
|
||||||
|
val := p.check_name()
|
||||||
|
p.fgen(' ')
|
||||||
|
p.check(.key_in)
|
||||||
|
p.fspace()
|
||||||
|
tmp := p.get_tmp()
|
||||||
|
p.cgen.start_tmp()
|
||||||
|
mut typ := p.bool_expression()
|
||||||
|
expr := p.cgen.end_tmp()
|
||||||
|
is_range := p.tok == .dotdot
|
||||||
|
is_variadic_arg := typ.starts_with('varg_')
|
||||||
|
mut range_end := ''
|
||||||
|
if is_range {
|
||||||
|
p.check_types(typ, 'int')
|
||||||
|
p.check_space(.dotdot)
|
||||||
|
p.cgen.start_tmp()
|
||||||
|
p.check_types(p.bool_expression(), 'int')
|
||||||
|
range_end = p.cgen.end_tmp()
|
||||||
|
}
|
||||||
|
is_arr := typ.contains('array')
|
||||||
|
is_str := typ == 'string'
|
||||||
|
if !is_arr && !is_str && !is_range && !is_variadic_arg {
|
||||||
|
p.error('cannot range over type `$typ`')
|
||||||
|
}
|
||||||
|
if !is_variadic_arg {
|
||||||
|
if p.is_js {
|
||||||
|
p.genln('var $tmp = $expr;')
|
||||||
|
} else {
|
||||||
|
p.genln('$typ $tmp = $expr;')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// TODO var_type := if...
|
||||||
|
i := p.get_tmp()
|
||||||
|
if is_variadic_arg {
|
||||||
|
typ = typ[5..]
|
||||||
|
p.gen_for_varg_header(i, expr, typ, val)
|
||||||
|
}
|
||||||
|
else if is_range {
|
||||||
|
typ = 'int'
|
||||||
|
p.gen_for_range_header(i, range_end, tmp, typ, val)
|
||||||
|
}
|
||||||
|
else if is_arr {
|
||||||
|
typ = typ[6..]// all after `array_`
|
||||||
|
p.gen_for_header(i, tmp, typ, val)
|
||||||
|
}
|
||||||
|
else if is_str {
|
||||||
|
typ = 'byte'
|
||||||
|
p.gen_for_str_header(i, tmp, typ, val)
|
||||||
|
}
|
||||||
|
// println('for typ=$typ vartyp=$var_typ')
|
||||||
|
// Register temp var
|
||||||
|
if val != '_' {
|
||||||
|
p.register_var(Var {
|
||||||
|
name: val
|
||||||
|
typ: typ
|
||||||
|
ptr: typ.contains('*')
|
||||||
|
is_changed: true
|
||||||
|
is_mut: false
|
||||||
|
is_for_var: true
|
||||||
|
})
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// `for a < b {`
|
||||||
|
p.gen('while (')
|
||||||
|
p.check_types(p.bool_expression(), 'bool')
|
||||||
|
p.genln(') {')
|
||||||
|
}
|
||||||
|
p.fspace()
|
||||||
|
p.check(.lcbr)
|
||||||
|
p.genln('')
|
||||||
|
p.statements()
|
||||||
|
p.close_scope()
|
||||||
|
p.for_expr_cnt--
|
||||||
|
p.returns = false // TODO handle loops that are guaranteed to return
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,221 @@
|
||||||
|
// Copyright (c) 2019 Alexander Medvednikov. All rights reserved.
|
||||||
|
// Use of this source code is governed by an MIT license
|
||||||
|
// that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
module compiler
|
||||||
|
|
||||||
|
import (
|
||||||
|
strings
|
||||||
|
)
|
||||||
|
|
||||||
|
// Returns typ if used as expression
|
||||||
|
fn (p mut Parser) match_statement(is_expr bool) string {
|
||||||
|
p.check(.key_match)
|
||||||
|
p.cgen.start_tmp()
|
||||||
|
typ := p.bool_expression()
|
||||||
|
if typ.starts_with('array_') {
|
||||||
|
p.error('arrays cannot be compared')
|
||||||
|
}
|
||||||
|
expr := p.cgen.end_tmp()
|
||||||
|
|
||||||
|
// is it safe to use p.cgen.insert_before ???
|
||||||
|
tmp_var := p.get_tmp()
|
||||||
|
p.cgen.insert_before('$typ $tmp_var = $expr;')
|
||||||
|
|
||||||
|
p.check(.lcbr)
|
||||||
|
mut i := 0
|
||||||
|
mut all_cases_return := true
|
||||||
|
|
||||||
|
// stores typ of resulting variable
|
||||||
|
mut res_typ := ''
|
||||||
|
|
||||||
|
defer {
|
||||||
|
p.check(.rcbr)
|
||||||
|
}
|
||||||
|
|
||||||
|
for p.tok != .rcbr {
|
||||||
|
if p.tok == .key_else {
|
||||||
|
p.check(.key_else)
|
||||||
|
if p.tok == .arrow {
|
||||||
|
p.warn(warn_match_arrow)
|
||||||
|
p.check(.arrow)
|
||||||
|
}
|
||||||
|
|
||||||
|
// unwrap match if there is only else
|
||||||
|
if i == 0 {
|
||||||
|
if is_expr {
|
||||||
|
// statements are dissallowed (if match is expression) so user cant declare variables there and so on
|
||||||
|
|
||||||
|
// allow braces is else
|
||||||
|
got_brace := p.tok == .lcbr
|
||||||
|
if got_brace {
|
||||||
|
p.check(.lcbr)
|
||||||
|
}
|
||||||
|
|
||||||
|
p.gen('( ')
|
||||||
|
|
||||||
|
res_typ = p.bool_expression()
|
||||||
|
|
||||||
|
p.gen(' )')
|
||||||
|
|
||||||
|
// allow braces in else
|
||||||
|
if got_brace {
|
||||||
|
p.check(.rcbr)
|
||||||
|
}
|
||||||
|
|
||||||
|
return res_typ
|
||||||
|
} else {
|
||||||
|
p.returns = false
|
||||||
|
p.check(.lcbr)
|
||||||
|
|
||||||
|
p.genln('{ ')
|
||||||
|
p.statements()
|
||||||
|
p.returns = all_cases_return && p.returns
|
||||||
|
return ''
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if is_expr {
|
||||||
|
// statements are dissallowed (if match is expression) so user cant declare variables there and so on
|
||||||
|
p.gen(':(')
|
||||||
|
|
||||||
|
// allow braces is else
|
||||||
|
got_brace := p.tok == .lcbr
|
||||||
|
if got_brace {
|
||||||
|
p.check(.lcbr)
|
||||||
|
}
|
||||||
|
|
||||||
|
p.check_types(p.bool_expression(), res_typ)
|
||||||
|
|
||||||
|
// allow braces in else
|
||||||
|
if got_brace {
|
||||||
|
p.check(.rcbr)
|
||||||
|
}
|
||||||
|
|
||||||
|
p.gen(strings.repeat(`)`, i+1))
|
||||||
|
|
||||||
|
return res_typ
|
||||||
|
} else {
|
||||||
|
p.returns = false
|
||||||
|
p.genln('else // default:')
|
||||||
|
|
||||||
|
p.check(.lcbr)
|
||||||
|
|
||||||
|
p.genln('{ ')
|
||||||
|
p.statements()
|
||||||
|
|
||||||
|
p.returns = all_cases_return && p.returns
|
||||||
|
return ''
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if i > 0 {
|
||||||
|
if is_expr {
|
||||||
|
p.gen(': (')
|
||||||
|
} else {
|
||||||
|
p.gen('else ')
|
||||||
|
}
|
||||||
|
} else if is_expr {
|
||||||
|
p.gen('(')
|
||||||
|
}
|
||||||
|
|
||||||
|
if is_expr {
|
||||||
|
p.gen('(')
|
||||||
|
} else {
|
||||||
|
p.gen('if (')
|
||||||
|
}
|
||||||
|
|
||||||
|
ph := p.cgen.add_placeholder()
|
||||||
|
|
||||||
|
// Multiple checks separated by comma
|
||||||
|
mut got_comma := false
|
||||||
|
|
||||||
|
for {
|
||||||
|
if got_comma {
|
||||||
|
p.gen(') || (')
|
||||||
|
}
|
||||||
|
|
||||||
|
mut got_string := false
|
||||||
|
|
||||||
|
if typ == 'string' {
|
||||||
|
got_string = true
|
||||||
|
p.gen('string_eq($tmp_var, ')
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
p.gen('$tmp_var == ')
|
||||||
|
}
|
||||||
|
|
||||||
|
p.expected_type = typ
|
||||||
|
p.check_types(p.bool_expression(), typ)
|
||||||
|
p.expected_type = ''
|
||||||
|
|
||||||
|
if got_string {
|
||||||
|
p.gen(')')
|
||||||
|
}
|
||||||
|
|
||||||
|
if p.tok != .comma {
|
||||||
|
if got_comma {
|
||||||
|
p.gen(') ')
|
||||||
|
p.cgen.set_placeholder(ph, '(')
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
p.check(.comma)
|
||||||
|
got_comma = true
|
||||||
|
}
|
||||||
|
p.gen(')')
|
||||||
|
|
||||||
|
if p.tok == .arrow {
|
||||||
|
p.warn(warn_match_arrow)
|
||||||
|
p.check(.arrow)
|
||||||
|
}
|
||||||
|
|
||||||
|
// statements are dissallowed (if match is expression) so user cant declare variables there and so on
|
||||||
|
if is_expr {
|
||||||
|
p.gen('? (')
|
||||||
|
|
||||||
|
// braces are required for now
|
||||||
|
p.check(.lcbr)
|
||||||
|
|
||||||
|
if i == 0 {
|
||||||
|
// on the first iteration we set value of res_typ
|
||||||
|
res_typ = p.bool_expression()
|
||||||
|
} else {
|
||||||
|
// later on we check that the value is of res_typ type
|
||||||
|
p.check_types(p.bool_expression(), res_typ)
|
||||||
|
}
|
||||||
|
|
||||||
|
// braces are required for now
|
||||||
|
p.check(.rcbr)
|
||||||
|
|
||||||
|
p.gen(')')
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
p.returns = false
|
||||||
|
p.check(.lcbr)
|
||||||
|
|
||||||
|
p.genln('{ ')
|
||||||
|
p.statements()
|
||||||
|
|
||||||
|
all_cases_return = all_cases_return && p.returns
|
||||||
|
// p.gen(')')
|
||||||
|
}
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
|
||||||
|
if is_expr {
|
||||||
|
// we get here if no else found, ternary requires "else" branch
|
||||||
|
p.error('Match expression requires "else"')
|
||||||
|
}
|
||||||
|
|
||||||
|
p.returns = false // only get here when no default, so return is not guaranteed
|
||||||
|
|
||||||
|
return ''
|
||||||
|
}
|
||||||
|
|
||||||
|
fn (p mut Parser) switch_statement() {
|
||||||
|
p.error('`switch` statement has been removed, use `match` instead:\n' +
|
||||||
|
'https://vlang.io/docs#match')
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -3246,403 +3246,6 @@ fn (p mut Parser) if_st(is_expr bool, elif_depth int) string {
|
||||||
return typ
|
return typ
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (p mut Parser) for_st() {
|
|
||||||
p.check(.key_for)
|
|
||||||
p.fgen(' ')
|
|
||||||
p.for_expr_cnt++
|
|
||||||
next_tok := p.peek()
|
|
||||||
//debug := p.scanner.file_path.contains('r_draw')
|
|
||||||
p.open_scope()
|
|
||||||
if p.tok == .lcbr {
|
|
||||||
// Infinite loop
|
|
||||||
p.gen('while (1) {')
|
|
||||||
}
|
|
||||||
else if p.tok == .key_mut {
|
|
||||||
p.error('`mut` is not required in for loops')
|
|
||||||
}
|
|
||||||
// for i := 0; i < 10; i++ {
|
|
||||||
else if next_tok == .decl_assign || next_tok == .assign || p.tok == .semicolon {
|
|
||||||
p.genln('for (')
|
|
||||||
if next_tok == .decl_assign {
|
|
||||||
p.var_decl()
|
|
||||||
}
|
|
||||||
else if p.tok != .semicolon {
|
|
||||||
// allow `for ;; i++ {`
|
|
||||||
// Allow `for i = 0; i < ...`
|
|
||||||
p.statement(false)
|
|
||||||
}
|
|
||||||
p.check(.semicolon)
|
|
||||||
p.gen(' ; ')
|
|
||||||
p.fgen(' ')
|
|
||||||
if p.tok != .semicolon {
|
|
||||||
p.bool_expression()
|
|
||||||
}
|
|
||||||
p.check(.semicolon)
|
|
||||||
p.gen(' ; ')
|
|
||||||
p.fgen(' ')
|
|
||||||
if p.tok != .lcbr {
|
|
||||||
p.statement(false)
|
|
||||||
}
|
|
||||||
p.genln(') { ')
|
|
||||||
}
|
|
||||||
// for i, val in array
|
|
||||||
else if p.peek() == .comma {
|
|
||||||
/*
|
|
||||||
`for i, val in array {`
|
|
||||||
==>
|
|
||||||
```
|
|
||||||
array_int tmp = array;
|
|
||||||
for (int i = 0; i < tmp.len; i++) {
|
|
||||||
int val = tmp[i];
|
|
||||||
```
|
|
||||||
*/
|
|
||||||
i := p.check_name()
|
|
||||||
p.check(.comma)
|
|
||||||
val := p.check_name()
|
|
||||||
if i == '_' && val == '_' {
|
|
||||||
p.error('no new variables on the left side of `in`')
|
|
||||||
}
|
|
||||||
p.fgen(' ')
|
|
||||||
p.check(.key_in)
|
|
||||||
p.fgen(' ')
|
|
||||||
tmp := p.get_tmp()
|
|
||||||
p.cgen.start_tmp()
|
|
||||||
mut typ := p.bool_expression()
|
|
||||||
is_arr := typ.starts_with('array_')
|
|
||||||
is_map := typ.starts_with('map_')
|
|
||||||
is_str := typ == 'string'
|
|
||||||
is_variadic_arg := typ.starts_with('varg_')
|
|
||||||
if !is_arr && !is_str && !is_map && !is_variadic_arg {
|
|
||||||
p.error('cannot range over type `$typ`')
|
|
||||||
}
|
|
||||||
expr := p.cgen.end_tmp()
|
|
||||||
if !is_variadic_arg {
|
|
||||||
if p.is_js {
|
|
||||||
p.genln('var $tmp = $expr;')
|
|
||||||
} else {
|
|
||||||
p.genln('$typ $tmp = $expr;')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// typ = strings.Replace(typ, "_ptr", "*", -1)
|
|
||||||
mut i_var_type := 'int'
|
|
||||||
if is_variadic_arg {
|
|
||||||
typ = typ[5..]
|
|
||||||
p.gen_for_varg_header(i, expr, typ, val)
|
|
||||||
}
|
|
||||||
else if is_arr {
|
|
||||||
typ = typ[6..]
|
|
||||||
p.gen_for_header(i, tmp, typ, val)
|
|
||||||
}
|
|
||||||
else if is_map {
|
|
||||||
i_var_type = 'string'
|
|
||||||
typ = typ[4..]
|
|
||||||
p.gen_for_map_header(i, tmp, typ, val, typ)
|
|
||||||
}
|
|
||||||
else if is_str {
|
|
||||||
typ = 'byte'
|
|
||||||
p.gen_for_str_header(i, tmp, typ, val)
|
|
||||||
}
|
|
||||||
// Register temp vars
|
|
||||||
if i != '_' {
|
|
||||||
p.register_var(Var {
|
|
||||||
name: i
|
|
||||||
typ: i_var_type
|
|
||||||
is_mut: true
|
|
||||||
is_changed: true
|
|
||||||
})
|
|
||||||
}
|
|
||||||
if val != '_' {
|
|
||||||
p.register_var(Var {
|
|
||||||
name: val
|
|
||||||
typ: typ
|
|
||||||
ptr: typ.contains('*')
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// `for val in vals`
|
|
||||||
else if p.peek() == .key_in {
|
|
||||||
val := p.check_name()
|
|
||||||
p.fgen(' ')
|
|
||||||
p.check(.key_in)
|
|
||||||
p.fspace()
|
|
||||||
tmp := p.get_tmp()
|
|
||||||
p.cgen.start_tmp()
|
|
||||||
mut typ := p.bool_expression()
|
|
||||||
expr := p.cgen.end_tmp()
|
|
||||||
is_range := p.tok == .dotdot
|
|
||||||
is_variadic_arg := typ.starts_with('varg_')
|
|
||||||
mut range_end := ''
|
|
||||||
if is_range {
|
|
||||||
p.check_types(typ, 'int')
|
|
||||||
p.check_space(.dotdot)
|
|
||||||
p.cgen.start_tmp()
|
|
||||||
p.check_types(p.bool_expression(), 'int')
|
|
||||||
range_end = p.cgen.end_tmp()
|
|
||||||
}
|
|
||||||
is_arr := typ.contains('array')
|
|
||||||
is_str := typ == 'string'
|
|
||||||
if !is_arr && !is_str && !is_range && !is_variadic_arg {
|
|
||||||
p.error('cannot range over type `$typ`')
|
|
||||||
}
|
|
||||||
if !is_variadic_arg {
|
|
||||||
if p.is_js {
|
|
||||||
p.genln('var $tmp = $expr;')
|
|
||||||
} else {
|
|
||||||
p.genln('$typ $tmp = $expr;')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// TODO var_type := if...
|
|
||||||
i := p.get_tmp()
|
|
||||||
if is_variadic_arg {
|
|
||||||
typ = typ[5..]
|
|
||||||
p.gen_for_varg_header(i, expr, typ, val)
|
|
||||||
}
|
|
||||||
else if is_range {
|
|
||||||
typ = 'int'
|
|
||||||
p.gen_for_range_header(i, range_end, tmp, typ, val)
|
|
||||||
}
|
|
||||||
else if is_arr {
|
|
||||||
typ = typ[6..]// all after `array_`
|
|
||||||
p.gen_for_header(i, tmp, typ, val)
|
|
||||||
}
|
|
||||||
else if is_str {
|
|
||||||
typ = 'byte'
|
|
||||||
p.gen_for_str_header(i, tmp, typ, val)
|
|
||||||
}
|
|
||||||
// println('for typ=$typ vartyp=$var_typ')
|
|
||||||
// Register temp var
|
|
||||||
if val != '_' {
|
|
||||||
p.register_var(Var {
|
|
||||||
name: val
|
|
||||||
typ: typ
|
|
||||||
ptr: typ.contains('*')
|
|
||||||
is_changed: true
|
|
||||||
is_mut: false
|
|
||||||
is_for_var: true
|
|
||||||
})
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// `for a < b {`
|
|
||||||
p.gen('while (')
|
|
||||||
p.check_types(p.bool_expression(), 'bool')
|
|
||||||
p.genln(') {')
|
|
||||||
}
|
|
||||||
p.fspace()
|
|
||||||
p.check(.lcbr)
|
|
||||||
p.genln('')
|
|
||||||
p.statements()
|
|
||||||
p.close_scope()
|
|
||||||
p.for_expr_cnt--
|
|
||||||
p.returns = false // TODO handle loops that are guaranteed to return
|
|
||||||
}
|
|
||||||
|
|
||||||
fn (p mut Parser) switch_statement() {
|
|
||||||
p.error('`switch` statement has been removed, use `match` instead:\n' +
|
|
||||||
'https://vlang.io/docs#match')
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns typ if used as expression
|
|
||||||
fn (p mut Parser) match_statement(is_expr bool) string {
|
|
||||||
p.check(.key_match)
|
|
||||||
p.cgen.start_tmp()
|
|
||||||
typ := p.bool_expression()
|
|
||||||
expr := p.cgen.end_tmp()
|
|
||||||
|
|
||||||
// is it safe to use p.cgen.insert_before ???
|
|
||||||
tmp_var := p.get_tmp()
|
|
||||||
p.cgen.insert_before('$typ $tmp_var = $expr;')
|
|
||||||
|
|
||||||
p.check(.lcbr)
|
|
||||||
mut i := 0
|
|
||||||
mut all_cases_return := true
|
|
||||||
|
|
||||||
// stores typ of resulting variable
|
|
||||||
mut res_typ := ''
|
|
||||||
|
|
||||||
defer {
|
|
||||||
p.check(.rcbr)
|
|
||||||
}
|
|
||||||
|
|
||||||
for p.tok != .rcbr {
|
|
||||||
if p.tok == .key_else {
|
|
||||||
p.check(.key_else)
|
|
||||||
if p.tok == .arrow {
|
|
||||||
p.warn(warn_match_arrow)
|
|
||||||
p.check(.arrow)
|
|
||||||
}
|
|
||||||
|
|
||||||
// unwrap match if there is only else
|
|
||||||
if i == 0 {
|
|
||||||
if is_expr {
|
|
||||||
// statements are dissallowed (if match is expression) so user cant declare variables there and so on
|
|
||||||
|
|
||||||
// allow braces is else
|
|
||||||
got_brace := p.tok == .lcbr
|
|
||||||
if got_brace {
|
|
||||||
p.check(.lcbr)
|
|
||||||
}
|
|
||||||
|
|
||||||
p.gen('( ')
|
|
||||||
|
|
||||||
res_typ = p.bool_expression()
|
|
||||||
|
|
||||||
p.gen(' )')
|
|
||||||
|
|
||||||
// allow braces in else
|
|
||||||
if got_brace {
|
|
||||||
p.check(.rcbr)
|
|
||||||
}
|
|
||||||
|
|
||||||
return res_typ
|
|
||||||
} else {
|
|
||||||
p.returns = false
|
|
||||||
p.check(.lcbr)
|
|
||||||
|
|
||||||
p.genln('{ ')
|
|
||||||
p.statements()
|
|
||||||
p.returns = all_cases_return && p.returns
|
|
||||||
return ''
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if is_expr {
|
|
||||||
// statements are dissallowed (if match is expression) so user cant declare variables there and so on
|
|
||||||
p.gen(':(')
|
|
||||||
|
|
||||||
// allow braces is else
|
|
||||||
got_brace := p.tok == .lcbr
|
|
||||||
if got_brace {
|
|
||||||
p.check(.lcbr)
|
|
||||||
}
|
|
||||||
|
|
||||||
p.check_types(p.bool_expression(), res_typ)
|
|
||||||
|
|
||||||
// allow braces in else
|
|
||||||
if got_brace {
|
|
||||||
p.check(.rcbr)
|
|
||||||
}
|
|
||||||
|
|
||||||
p.gen(strings.repeat(`)`, i+1))
|
|
||||||
|
|
||||||
return res_typ
|
|
||||||
} else {
|
|
||||||
p.returns = false
|
|
||||||
p.genln('else // default:')
|
|
||||||
|
|
||||||
p.check(.lcbr)
|
|
||||||
|
|
||||||
p.genln('{ ')
|
|
||||||
p.statements()
|
|
||||||
|
|
||||||
p.returns = all_cases_return && p.returns
|
|
||||||
return ''
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if i > 0 {
|
|
||||||
if is_expr {
|
|
||||||
p.gen(': (')
|
|
||||||
} else {
|
|
||||||
p.gen('else ')
|
|
||||||
}
|
|
||||||
} else if is_expr {
|
|
||||||
p.gen('(')
|
|
||||||
}
|
|
||||||
|
|
||||||
if is_expr {
|
|
||||||
p.gen('(')
|
|
||||||
} else {
|
|
||||||
p.gen('if (')
|
|
||||||
}
|
|
||||||
|
|
||||||
ph := p.cgen.add_placeholder()
|
|
||||||
|
|
||||||
// Multiple checks separated by comma
|
|
||||||
mut got_comma := false
|
|
||||||
|
|
||||||
for {
|
|
||||||
if got_comma {
|
|
||||||
p.gen(') || (')
|
|
||||||
}
|
|
||||||
|
|
||||||
mut got_string := false
|
|
||||||
|
|
||||||
if typ == 'string' {
|
|
||||||
got_string = true
|
|
||||||
p.gen('string_eq($tmp_var, ')
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
p.gen('$tmp_var == ')
|
|
||||||
}
|
|
||||||
|
|
||||||
p.expected_type = typ
|
|
||||||
p.check_types(p.bool_expression(), typ)
|
|
||||||
p.expected_type = ''
|
|
||||||
|
|
||||||
if got_string {
|
|
||||||
p.gen(')')
|
|
||||||
}
|
|
||||||
|
|
||||||
if p.tok != .comma {
|
|
||||||
if got_comma {
|
|
||||||
p.gen(') ')
|
|
||||||
p.cgen.set_placeholder(ph, '(')
|
|
||||||
}
|
|
||||||
break
|
|
||||||
}
|
|
||||||
p.check(.comma)
|
|
||||||
got_comma = true
|
|
||||||
}
|
|
||||||
p.gen(')')
|
|
||||||
|
|
||||||
if p.tok == .arrow {
|
|
||||||
p.warn(warn_match_arrow)
|
|
||||||
p.check(.arrow)
|
|
||||||
}
|
|
||||||
|
|
||||||
// statements are dissallowed (if match is expression) so user cant declare variables there and so on
|
|
||||||
if is_expr {
|
|
||||||
p.gen('? (')
|
|
||||||
|
|
||||||
// braces are required for now
|
|
||||||
p.check(.lcbr)
|
|
||||||
|
|
||||||
if i == 0 {
|
|
||||||
// on the first iteration we set value of res_typ
|
|
||||||
res_typ = p.bool_expression()
|
|
||||||
} else {
|
|
||||||
// later on we check that the value is of res_typ type
|
|
||||||
p.check_types(p.bool_expression(), res_typ)
|
|
||||||
}
|
|
||||||
|
|
||||||
// braces are required for now
|
|
||||||
p.check(.rcbr)
|
|
||||||
|
|
||||||
p.gen(')')
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
p.returns = false
|
|
||||||
p.check(.lcbr)
|
|
||||||
|
|
||||||
p.genln('{ ')
|
|
||||||
p.statements()
|
|
||||||
|
|
||||||
all_cases_return = all_cases_return && p.returns
|
|
||||||
// p.gen(')')
|
|
||||||
}
|
|
||||||
i++
|
|
||||||
}
|
|
||||||
|
|
||||||
if is_expr {
|
|
||||||
// we get here if no else found, ternary requires "else" branch
|
|
||||||
p.error('Match expression requires "else"')
|
|
||||||
}
|
|
||||||
|
|
||||||
p.returns = false // only get here when no default, so return is not guaranteed
|
|
||||||
|
|
||||||
return ''
|
|
||||||
}
|
|
||||||
|
|
||||||
fn (p mut Parser) assert_statement() {
|
fn (p mut Parser) assert_statement() {
|
||||||
if p.first_pass() {
|
if p.first_pass() {
|
||||||
return
|
return
|
||||||
|
|
Loading…
Reference in New Issue