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 branch in node.branches {
|
||||||
for expr in branch.exprs {
|
for expr in branch.exprs {
|
||||||
mut key := ''
|
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 {
|
match expr {
|
||||||
ast.Type { key = c.table.type_to_str(expr.typ) }
|
ast.Type { key = c.table.type_to_str(expr.typ) }
|
||||||
ast.EnumVal { key = expr.val }
|
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') }
|
44 | else { println('else') }
|
||||||
45 | }
|
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() {
|
fn main() {
|
||||||
test_sum_type(St1{})
|
test_sum_type(St1{})
|
||||||
test_enum(.red)
|
test_enum(.red)
|
||||||
test_int(2)
|
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 == _${sym.name}_${branch_sym} ')
|
||||||
g.write('._interface_idx == ')
|
g.write('._interface_idx == ')
|
||||||
}
|
}
|
||||||
|
g.expr(expr)
|
||||||
} else if type_sym.kind == .string {
|
} else if type_sym.kind == .string {
|
||||||
g.write('string_eq(')
|
g.write('string_eq(')
|
||||||
//
|
//
|
||||||
g.expr(node.cond)
|
g.expr(node.cond)
|
||||||
g.write(', ')
|
g.write(', ')
|
||||||
// g.write('string_eq($tmp, ')
|
// 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 {
|
} else {
|
||||||
g.expr(node.cond)
|
g.expr(node.cond)
|
||||||
g.write(' == ')
|
g.write(' == ')
|
||||||
// g.write('$tmp == ')
|
// g.write('$tmp == ')
|
||||||
}
|
g.expr(expr)
|
||||||
g.expr(expr)
|
|
||||||
if type_sym.kind == .string {
|
|
||||||
g.write(')')
|
|
||||||
}
|
}
|
||||||
if i < branch.exprs.len - 1 {
|
if i < branch.exprs.len - 1 {
|
||||||
g.write(' || ')
|
g.write(' || ')
|
||||||
|
|
|
@ -187,7 +187,18 @@ fn (mut p Parser) match_expr() ast.MatchExpr {
|
||||||
p.inside_match_case = true
|
p.inside_match_case = true
|
||||||
expr := p.expr(0)
|
expr := p.expr(0)
|
||||||
p.inside_match_case = false
|
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 {
|
if p.tok.kind != .comma {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
|
@ -62,6 +62,24 @@ fn test_match_integers() {
|
||||||
assert a == -2
|
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() {
|
fn test_match_enums() {
|
||||||
mut b := Color.red
|
mut b := Color.red
|
||||||
match b {
|
match b {
|
||||||
|
|
Loading…
Reference in New Issue