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