sync/select: allow push of literals and calculated expressions (#6429)
parent
c781a5f245
commit
4ae88c69ac
|
@ -36,32 +36,23 @@ fn test_select() {
|
|||
go do_send_int(chi)
|
||||
go do_send_byte(chb)
|
||||
go do_send_i64(chl)
|
||||
mut channels := [&sync.Channel(chi), &sync.Channel(recch), &sync.Channel(chl), &sync.Channel(chb)]
|
||||
directions := [sync.Direction.pop, .push, .pop, .pop]
|
||||
mut sum := i64(0)
|
||||
mut rl := i64(0)
|
||||
mut ri := int(0)
|
||||
mut rb := byte(0)
|
||||
mut sl := i64(0)
|
||||
mut objs := [voidptr(&ri), &sl, &rl, &rb]
|
||||
for _ in 0 .. 1200 {
|
||||
idx := sync.channel_select(mut channels, directions, mut objs, -1)
|
||||
match idx {
|
||||
0 {
|
||||
select {
|
||||
ri := <-chi {
|
||||
sum += ri
|
||||
}
|
||||
1 {
|
||||
recch <- sl {
|
||||
sl++
|
||||
}
|
||||
2 {
|
||||
rl = <-chl {
|
||||
sum += rl
|
||||
}
|
||||
3 {
|
||||
rb := <-chb {
|
||||
sum += rb
|
||||
}
|
||||
else {
|
||||
println('got $idx (timeout)')
|
||||
}
|
||||
}
|
||||
}
|
||||
// Use Gauß' formula for the first 2 contributions
|
||||
|
|
|
@ -5,9 +5,12 @@ struct St {
|
|||
a int
|
||||
}
|
||||
|
||||
fn f1(ch1 chan int, ch2 chan St, ch3 chan int, sem sync.Semaphore) {
|
||||
fn getint() int {
|
||||
return 8
|
||||
}
|
||||
|
||||
fn f1(ch1 chan int, ch2 chan St, ch3 chan int, ch4 chan int, ch5 chan int, sem sync.Semaphore) {
|
||||
mut a := 5
|
||||
st := St{}
|
||||
select {
|
||||
a = <-ch3 {
|
||||
a = 0
|
||||
|
@ -15,9 +18,18 @@ fn f1(ch1 chan int, ch2 chan St, ch3 chan int, sem sync.Semaphore) {
|
|||
b := <-ch2 {
|
||||
a = b.a
|
||||
}
|
||||
ch2 <- st {
|
||||
ch3 <- 5 {
|
||||
a = 1
|
||||
}
|
||||
ch2 <- St{a: 37} {
|
||||
a = 2
|
||||
}
|
||||
ch4 <- (6 + 7 * 9) {
|
||||
a = 8
|
||||
}
|
||||
ch5 <- getint() {
|
||||
a = 9
|
||||
}
|
||||
> 300 * time.millisecond {
|
||||
a = 3
|
||||
}
|
||||
|
@ -30,7 +42,7 @@ fn f2(ch1 chan St, ch2 chan int, sem sync.Semaphore) {
|
|||
mut r := 23
|
||||
for i in 0 .. 2 {
|
||||
select {
|
||||
b := <- ch1 {
|
||||
b := <-ch1 {
|
||||
r = b.a
|
||||
}
|
||||
ch2 <- r {
|
||||
|
@ -50,6 +62,8 @@ fn test_select_blocks() {
|
|||
ch1 := chan int{cap: 1}
|
||||
ch2 := chan St{}
|
||||
ch3 := chan int{}
|
||||
ch4 := chan int{}
|
||||
ch5 := chan int{}
|
||||
sem := sync.new_semaphore()
|
||||
mut r := false
|
||||
t := select {
|
||||
|
@ -69,7 +83,7 @@ fn test_select_blocks() {
|
|||
ch2 <- St{a: 13}
|
||||
sem.wait()
|
||||
stopwatch := time.new_stopwatch({})
|
||||
go f1(ch1, ch2, ch3, sem)
|
||||
go f1(ch1, ch2, ch3, ch4, ch5, sem)
|
||||
sem.wait()
|
||||
elapsed_ms := f64(stopwatch.elapsed()) / time.millisecond
|
||||
assert elapsed_ms >= 295.0
|
||||
|
|
|
@ -1,3 +1,11 @@
|
|||
/*
|
||||
* ATTENTION! Do not use this file as an example!
|
||||
* For that, please look at `channel_select_2_test.v` or `channel_select_3_test.v`
|
||||
*
|
||||
* This test case uses the implementation in `sync/channels.v` directly
|
||||
* in order to test it independently from the support in the core language
|
||||
*/
|
||||
|
||||
import sync
|
||||
|
||||
fn do_rec_i64(mut ch sync.Channel) {
|
||||
|
|
|
@ -3064,6 +3064,48 @@ pub fn (mut c Checker) select_expr(mut node ast.SelectExpr) table.Type {
|
|||
node.expected_type = c.expected_type
|
||||
for branch in node.branches {
|
||||
c.stmt(branch.stmt)
|
||||
match branch.stmt as stmt {
|
||||
ast.ExprStmt {
|
||||
if branch.is_timeout {
|
||||
if !stmt.typ.is_int() {
|
||||
tsym := c.table.get_type_symbol(stmt.typ)
|
||||
c.error('invalid type `$tsym.name` for timeout - expected integer type aka `time.Duration`',
|
||||
stmt.pos)
|
||||
}
|
||||
} else {
|
||||
if stmt.expr is ast.InfixExpr as expr {
|
||||
if expr.left !is ast.Ident &&
|
||||
expr.left !is ast.SelectorExpr && expr.left !is ast.IndexExpr {
|
||||
c.error('channel in `select` key must be predefined', expr.left.position())
|
||||
}
|
||||
} else {
|
||||
c.error('invalid expression for `select` key', stmt.expr.position())
|
||||
}
|
||||
}
|
||||
}
|
||||
ast.AssignStmt {
|
||||
match stmt.right[0] as expr {
|
||||
ast.PrefixExpr {
|
||||
if expr.right !is ast.Ident &&
|
||||
expr.right !is ast.SelectorExpr && expr.right !is ast.IndexExpr {
|
||||
c.error('channel in `select` key must be predefined', expr.right.position())
|
||||
}
|
||||
if expr.or_block.kind != .absent {
|
||||
err_prefix := if expr.or_block.kind == .block { 'or block' } else { 'error propagation' }
|
||||
c.error('$err_prefix not allowed in `select` key', expr.or_block.pos)
|
||||
}
|
||||
}
|
||||
else {
|
||||
c.error('`<-` receive expression expected', stmt.right[0].position())
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
if !branch.is_else {
|
||||
c.error('receive or send statement expected as `select` key', branch.stmt.position())
|
||||
}
|
||||
}
|
||||
}
|
||||
c.stmts(branch.stmts)
|
||||
}
|
||||
return table.bool_type
|
||||
|
|
|
@ -2767,11 +2767,23 @@ fn (mut g Gen) select_expr(node ast.SelectExpr) {
|
|||
} else {
|
||||
match branch.stmt as stmt {
|
||||
ast.ExprStmt {
|
||||
// send expression
|
||||
expr := stmt.expr as ast.InfixExpr
|
||||
channels << expr.left
|
||||
if expr.right is ast.Ident ||
|
||||
expr.right is ast.IndexExpr || expr.right is ast.SelectorExpr || expr.right is ast.StructInit {
|
||||
// addressable objects in the `C` output
|
||||
objs << expr.right
|
||||
tmp_objs << ''
|
||||
elem_types << ''
|
||||
} else {
|
||||
// must be evaluated to tmp var before real `select` is performed
|
||||
objs << ast.Expr{}
|
||||
tmp_obj := g.new_tmp_var()
|
||||
tmp_objs << tmp_obj
|
||||
el_stype := g.typ(g.table.mktyp(expr.right_type))
|
||||
g.writeln('$el_stype $tmp_obj;')
|
||||
}
|
||||
is_push << true
|
||||
}
|
||||
ast.AssignStmt {
|
||||
|
@ -2858,7 +2870,7 @@ fn (mut g Gen) select_expr(node ast.SelectExpr) {
|
|||
g.writeln('-1) {')
|
||||
} else {
|
||||
g.writeln('$i) {')
|
||||
if tmp_objs[i] != '' {
|
||||
if !is_push[i] && tmp_objs[i] != '' {
|
||||
g.write('\t${elem_types[i]}')
|
||||
g.expr(objs[i])
|
||||
g.writeln(' = ${tmp_objs[i]};')
|
||||
|
|
|
@ -358,6 +358,7 @@ fn (mut p Parser) select_expr() ast.SelectExpr {
|
|||
}
|
||||
} else {
|
||||
p.inside_match = true
|
||||
p.inside_select = true
|
||||
exprs, comments := p.expr_list()
|
||||
if exprs.len != 1 {
|
||||
p.error('only one expression allowed as `select` key')
|
||||
|
@ -373,6 +374,7 @@ fn (mut p Parser) select_expr() ast.SelectExpr {
|
|||
}
|
||||
}
|
||||
p.inside_match = false
|
||||
p.inside_select = false
|
||||
match stmt {
|
||||
ast.ExprStmt {
|
||||
if !stmt.is_expr {
|
||||
|
|
|
@ -47,6 +47,7 @@ mut:
|
|||
is_amp bool // for generating the right code for `&Foo{}`
|
||||
returns bool
|
||||
inside_match bool // to separate `match A { }` from `Struct{}`
|
||||
inside_select bool // to allow `ch <- Struct{} {` inside `select`
|
||||
inside_match_case bool // to separate `match_expr { }` from `Struct{}`
|
||||
inside_match_body bool // to fix eval not used TODO
|
||||
inside_unsafe bool
|
||||
|
@ -920,6 +921,7 @@ pub fn (mut p Parser) parse_ident(language table.Language) ast.Ident {
|
|||
}
|
||||
|
||||
pub fn (mut p Parser) name_expr() ast.Expr {
|
||||
prev_tok_kind := p.prev_tok.kind
|
||||
mut node := ast.Expr{}
|
||||
if p.expecting_type {
|
||||
p.expecting_type = false
|
||||
|
@ -1073,7 +1075,8 @@ pub fn (mut p Parser) name_expr() ast.Expr {
|
|||
}
|
||||
} else if (p.peek_tok.kind == .lcbr ||
|
||||
(p.peek_tok.kind == .lt && lit0_is_capital)) &&
|
||||
!p.inside_match && !p.inside_match_case && !p.inside_if && !p.inside_for { // && (p.tok.lit[0].is_capital() || p.builtin_mod) {
|
||||
(!p.inside_match || (p.inside_select && prev_tok_kind == .arrow && lit0_is_capital)) && !p.inside_match_case &&
|
||||
!p.inside_if && !p.inside_for { // && (p.tok.lit[0].is_capital() || p.builtin_mod) {
|
||||
return p.struct_init(false) // short_syntax: false
|
||||
} else if p.peek_tok.kind == .dot && (lit0_is_capital && !known_var && language == .v) {
|
||||
// `Color.green`
|
||||
|
|
Loading…
Reference in New Issue