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 | ||||
| 		} | ||||
|  | @ -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