compiler: handle ranges as `match` conditions (#5847)
parent
612fe1b8fb
commit
b900577dae
|
@ -2585,6 +2585,39 @@ fn (mut c Checker) match_exprs(mut node ast.MatchExpr, type_sym table.TypeSymbol
|
|||
for branch in node.branches {
|
||||
for expr in branch.exprs {
|
||||
mut key := ''
|
||||
if expr is ast.RangeExpr {
|
||||
mut low := 0
|
||||
mut high := 0
|
||||
c.expected_type = node.expected_type
|
||||
if expr.low is ast.IntegerLiteral as low_expr {
|
||||
if expr.high is ast.IntegerLiteral as high_expr {
|
||||
low = low_expr.val.int()
|
||||
high = high_expr.val.int()
|
||||
} else {
|
||||
c.error('mismatched range types', low_expr.pos)
|
||||
}
|
||||
} else if expr.low is ast.CharLiteral as low_expr {
|
||||
if expr.high is ast.CharLiteral as high_expr {
|
||||
low = low_expr.val[0]
|
||||
high = high_expr.val[0]
|
||||
} else {
|
||||
c.error('mismatched range types', low_expr.pos)
|
||||
}
|
||||
} else {
|
||||
typ := c.table.type_to_str(c.expr(expr.low))
|
||||
c.error('cannot use type `$typ` in match range', branch.pos)
|
||||
}
|
||||
|
||||
for i in low..high {
|
||||
key = i.str()
|
||||
val := if key in branch_exprs { branch_exprs[key] } else { 0 }
|
||||
if val == 1 {
|
||||
c.error('match case `$key` is handled more than once', branch.pos)
|
||||
}
|
||||
branch_exprs[key] = val + 1
|
||||
}
|
||||
continue
|
||||
}
|
||||
match expr {
|
||||
ast.Type { key = c.table.type_to_str(expr.typ) }
|
||||
ast.EnumVal { key = expr.val }
|
||||
|
|
|
@ -33,3 +33,10 @@ vlib/v/checker/tests/match_duplicate_branch.v:43:3: error: match case `2` is han
|
|||
| ~~~
|
||||
44 | else { println('else') }
|
||||
45 | }
|
||||
vlib/v/checker/tests/match_duplicate_branch.v:51:3: error: match case `3` is handled more than once
|
||||
49 | match i {
|
||||
50 | 1..5 { println('1 to 4') }
|
||||
51 | 3 { println('3') }
|
||||
| ~~~
|
||||
52 | else { println('else') }
|
||||
53 | }
|
|
@ -45,8 +45,17 @@ fn test_int(i int) {
|
|||
}
|
||||
}
|
||||
|
||||
fn test_range(i int) {
|
||||
match i {
|
||||
1..5 { println('1 to 4') }
|
||||
3 { println('3') }
|
||||
else { println('else') }
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
test_sum_type(St1{})
|
||||
test_enum(.red)
|
||||
test_int(2)
|
||||
test_range(4)
|
||||
}
|
||||
|
|
|
@ -2226,20 +2226,30 @@ fn (mut g Gen) match_expr(node ast.MatchExpr) {
|
|||
// g.write('._interface_idx == _${sym.name}_${branch_sym} ')
|
||||
g.write('._interface_idx == ')
|
||||
}
|
||||
g.expr(expr)
|
||||
} else if type_sym.kind == .string {
|
||||
g.write('string_eq(')
|
||||
//
|
||||
g.expr(node.cond)
|
||||
g.write(', ')
|
||||
// g.write('string_eq($tmp, ')
|
||||
g.expr(expr)
|
||||
g.write(')')
|
||||
} else if expr is ast.RangeExpr {
|
||||
g.write('(')
|
||||
g.expr(node.cond)
|
||||
g.write(' >= ')
|
||||
g.expr(expr.low)
|
||||
g.write(' && ')
|
||||
g.expr(node.cond)
|
||||
g.write(' < ')
|
||||
g.expr(expr.high)
|
||||
g.write(')')
|
||||
} else {
|
||||
g.expr(node.cond)
|
||||
g.write(' == ')
|
||||
// g.write('$tmp == ')
|
||||
}
|
||||
g.expr(expr)
|
||||
if type_sym.kind == .string {
|
||||
g.write(')')
|
||||
g.expr(expr)
|
||||
}
|
||||
if i < branch.exprs.len - 1 {
|
||||
g.write(' || ')
|
||||
|
|
|
@ -187,7 +187,18 @@ fn (mut p Parser) match_expr() ast.MatchExpr {
|
|||
p.inside_match_case = true
|
||||
expr := p.expr(0)
|
||||
p.inside_match_case = false
|
||||
exprs << expr
|
||||
if p.tok.kind == .dotdot {
|
||||
p.next()
|
||||
expr2 := p.expr(0)
|
||||
exprs << ast.RangeExpr{
|
||||
low: expr
|
||||
high: expr2
|
||||
has_low: true
|
||||
has_high: true
|
||||
}
|
||||
} else {
|
||||
exprs << expr
|
||||
}
|
||||
if p.tok.kind != .comma {
|
||||
break
|
||||
}
|
||||
|
|
|
@ -62,6 +62,24 @@ fn test_match_integers() {
|
|||
assert a == -2
|
||||
}
|
||||
|
||||
fn test_match_multiple() {
|
||||
assert match 5 {
|
||||
1, 2, 3 { '1-3' }
|
||||
4, 5 { '4-5' }
|
||||
6..9, 9 { '6-9' }
|
||||
else { 'other' }
|
||||
} == '4-5'
|
||||
}
|
||||
|
||||
fn test_match_range() {
|
||||
assert match `f` {
|
||||
`0`..`9` { 'digit' }
|
||||
`A`..`Z` { 'uppercase' }
|
||||
`a`..`z` { 'lowercase' }
|
||||
else { 'other' }
|
||||
} == 'lowercase'
|
||||
}
|
||||
|
||||
fn test_match_enums() {
|
||||
mut b := Color.red
|
||||
match b {
|
||||
|
|
Loading…
Reference in New Issue