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.
 | // 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
 | // The following list is considered white space characters: ` `, `\t`, `\n`, `\v`, `\f`, `\r`, 0x85, 0xa0
 | ||||||
| // Example: assert byte(` `).is_space() == true
 | // Example: assert byte(` `).is_space() == true
 | ||||||
|  |  | ||||||
|  | @ -24,6 +24,22 @@ fn (mut g Gen) index_expr(node ast.IndexExpr) { | ||||||
| 				g.write('.str[ ') | 				g.write('.str[ ') | ||||||
| 				g.expr(node.index) | 				g.expr(node.index) | ||||||
| 				g.write(']') | 				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 { | 				} else { | ||||||
| 					g.write('string_at(') | 					g.write('string_at(') | ||||||
| 					g.expr(node.left) | 					g.expr(node.left) | ||||||
|  | @ -31,6 +47,7 @@ fn (mut g Gen) index_expr(node ast.IndexExpr) { | ||||||
| 					g.expr(node.index) | 					g.expr(node.index) | ||||||
| 					g.write(')') | 					g.write(')') | ||||||
| 				} | 				} | ||||||
|  | 			} | ||||||
| 		} else { | 		} else { | ||||||
| 			g.expr(node.left) | 			g.expr(node.left) | ||||||
| 			g.write('[') | 			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