cgen: enable string index error handling `s[i] or {...}` (#10670)
							parent
							
								
									9e61321d4c
								
							
						
					
					
						commit
						a1f123bd42
					
				|  | @ -1263,6 +1263,17 @@ fn (s string) at(idx int) byte { | |||
| 	} | ||||
| } | ||||
| 
 | ||||
| // version of `at()` that is used in `a[i] or {`
 | ||||
| // return an error when the index is out of range
 | ||||
| fn (s string) at_with_check(idx int) ?byte { | ||||
| 	if idx < 0 || idx >= s.len { | ||||
| 		return error('string index out of range') | ||||
| 	} | ||||
| 	unsafe { | ||||
| 		return s.str[idx] | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // is_space returns `true` if the byte is a white space character.
 | ||||
| // The following list is considered white space characters: ` `, `\t`, `\n`, `\v`, `\f`, `\r`, 0x85, 0xa0
 | ||||
| // Example: assert byte(` `).is_space() == true
 | ||||
|  |  | |||
|  | @ -24,6 +24,22 @@ fn (mut g Gen) index_expr(node ast.IndexExpr) { | |||
| 				g.write('.str[ ') | ||||
| 				g.expr(node.index) | ||||
| 				g.write(']') | ||||
| 			} else { | ||||
| 				gen_or := node.or_expr.kind != .absent || node.is_option | ||||
| 				if gen_or { | ||||
| 					tmp_opt := g.new_tmp_var() | ||||
| 					cur_line := g.go_before_stmt(0) | ||||
| 					g.out.write_string(util.tabs(g.indent)) | ||||
| 					opt_elem_type := g.typ(ast.byte_type.set_flag(.optional)) | ||||
| 					g.write('$opt_elem_type $tmp_opt = string_at_with_check(') | ||||
| 					g.expr(node.left) | ||||
| 					g.write(', ') | ||||
| 					g.expr(node.index) | ||||
| 					g.writeln(');') | ||||
| 					if !node.is_option { | ||||
| 						g.or_block(tmp_opt, node.or_expr, ast.byte_type) | ||||
| 					} | ||||
| 					g.write('\n$cur_line*(byte*)&${tmp_opt}.data') | ||||
| 				} else { | ||||
| 					g.write('string_at(') | ||||
| 					g.expr(node.left) | ||||
|  | @ -31,6 +47,7 @@ fn (mut g Gen) index_expr(node ast.IndexExpr) { | |||
| 					g.expr(node.index) | ||||
| 					g.write(')') | ||||
| 				} | ||||
| 			} | ||||
| 		} else { | ||||
| 			g.expr(node.left) | ||||
| 			g.write('[') | ||||
|  |  | |||
|  | @ -0,0 +1,52 @@ | |||
| fn test_empty_string_access() { | ||||
| 	mut res := '' | ||||
| 	a := '' | ||||
| 	if a[0] or { `0` } == `1` { | ||||
| 		res = 'good' | ||||
| 	} else { | ||||
| 		res = 'bad' | ||||
| 	} | ||||
| 	assert res == 'bad' | ||||
| } | ||||
| 
 | ||||
| fn test_good_string_access() { | ||||
| 	mut res := '' | ||||
| 	a := 'abcd' | ||||
| 	if a[2] or { `0` } == `c` { | ||||
| 		res = 'good' | ||||
| 	} else { | ||||
| 		res = 'bad' | ||||
| 	} | ||||
| 	assert res == 'good' | ||||
| } | ||||
| 
 | ||||
| fn test_if_guard_bad() { | ||||
| 	mut res := 'bad' | ||||
| 	a := 'xy' | ||||
| 	if z := a[2] { | ||||
| 		res = '${z:c}' | ||||
| 	} | ||||
| 	assert res == 'bad' | ||||
| } | ||||
| 
 | ||||
| fn test_if_guard_good() { | ||||
| 	mut res := 'bad' | ||||
| 	a := 'xy123' | ||||
| 	if z := a[2] { | ||||
| 		res = '${z:c}' | ||||
| 	} | ||||
| 	assert res == '1' | ||||
| } | ||||
| 
 | ||||
| fn get_propagate(s string, i int) ?string { | ||||
| 	c := s[i] ? | ||||
| 	return 'got `${c:c}`' | ||||
| } | ||||
| 
 | ||||
| fn test_propagation() { | ||||
| 	s := 'abcd' | ||||
| 	x := get_propagate(s, 2) or { '$err' } | ||||
| 	y := get_propagate(s, 5) or { '$err' } | ||||
| 	assert x == 'got `c`' | ||||
| 	assert y == 'string index out of range' | ||||
| } | ||||
		Loading…
	
		Reference in New Issue