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
|
||||
|
|
|
@ -25,11 +25,28 @@ fn (mut g Gen) index_expr(node ast.IndexExpr) {
|
|||
g.expr(node.index)
|
||||
g.write(']')
|
||||
} else {
|
||||
g.write('string_at(')
|
||||
g.expr(node.left)
|
||||
g.write(', ')
|
||||
g.expr(node.index)
|
||||
g.write(')')
|
||||
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)
|
||||
g.write(', ')
|
||||
g.expr(node.index)
|
||||
g.write(')')
|
||||
}
|
||||
}
|
||||
} else {
|
||||
g.expr(node.left)
|
||||
|
|
|
@ -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