diff --git a/.gitignore b/.gitignore
index e2cdcbd8d1..ae03092d40 100644
--- a/.gitignore
+++ b/.gitignore
@@ -155,3 +155,4 @@ bench/vectors/obj
autofuzz.log
.project.gf
+.aider*
diff --git a/cmd/tools/changelog_helper.v b/cmd/tools/changelog_helper.v
index f0d88605f0..3fe71e7676 100644
--- a/cmd/tools/changelog_helper.v
+++ b/cmd/tools/changelog_helper.v
@@ -311,7 +311,7 @@ fn (l Line) write_at_category(txt string) ?string {
title := category_map[l.category]
title_pos := txt.index(title)?
// Find the position of the ### category title
- pos := txt.index_after('\n', title_pos + 1)
+ pos := txt.index_after('\n', title_pos + 1) or { return none }
first_half := txt[..pos]
second_half := txt[pos..]
if txt.contains(l.text) {
diff --git a/cmd/tools/vpm/common.v b/cmd/tools/vpm/common.v
index 8f84a85828..27c4086ba5 100644
--- a/cmd/tools/vpm/common.v
+++ b/cmd/tools/vpm/common.v
@@ -104,24 +104,18 @@ fn get_all_modules() []string {
mut start_token := "'
// get the start index of the module entry
- mut start_index := s.index_after(start_token, read_len)
+ mut start_index := s.index_after(start_token, read_len) or { -1 }
if start_index == -1 {
start_token = ' s.len {
+ return none
+ }
+
+ mut strt := start
+ if start < 0 {
+ strt = 0
+ }
+ if start >= s.len {
+ return none
+ }
+ mut i := strt
+
+ for i < s.len {
+ mut j := 0
+ mut ii := i
+ for j < p.len && s[ii] == p[j] {
+ j++
+ ii++
+ }
+
+ if j == p.len {
+ return i
+ }
+ i++
+ }
+ return none
+}
+
+pub fn (s string) index_after_(p string, start int) int {
if p.len > s.len {
return -1
}
diff --git a/vlib/builtin/string.v b/vlib/builtin/string.v
index 48415eba16..14c3cb9bc1 100644
--- a/vlib/builtin/string.v
+++ b/vlib/builtin/string.v
@@ -392,7 +392,7 @@ pub fn (s string) replace(rep string, with string) string {
}
mut idx := 0
for {
- idx = s.index_after(rep, idx)
+ idx = s.index_after_(rep, idx)
if idx == -1 {
break
}
@@ -463,7 +463,7 @@ pub fn (s string) replace_each(vals []string) string {
with := vals[rep_i + 1]
for {
- idx = s_.index_after(rep, idx)
+ idx = s_.index_after_(rep, idx)
if idx == -1 {
break
}
@@ -1352,7 +1352,36 @@ fn (s string) index_last_(p string) int {
// index_after returns the position of the input string, starting search from `start` position.
@[direct_array_access]
-pub fn (s string) index_after(p string, start int) int {
+pub fn (s string) index_after(p string, start int) ?int {
+ if p.len > s.len {
+ return none
+ }
+ mut strt := start
+ if start < 0 {
+ strt = 0
+ }
+ if start >= s.len {
+ return none
+ }
+ mut i := strt
+ for i < s.len {
+ mut j := 0
+ mut ii := i
+ for j < p.len && unsafe { s.str[ii] == p.str[j] } {
+ j++
+ ii++
+ }
+ if j == p.len {
+ return i
+ }
+ i++
+ }
+ return none
+}
+
+// index_after_ returns the position of the input string, starting search from `start` position.
+@[direct_array_access]
+pub fn (s string) index_after_(p string, start int) int {
if p.len > s.len {
return -1
}
@@ -1429,7 +1458,7 @@ pub fn (s string) count(substr string) int {
mut i := 0
for {
- i = s.index_after(substr, i)
+ i = s.index_after_(substr, i)
if i == -1 {
return n
}
diff --git a/vlib/encoding/csv/reader.v b/vlib/encoding/csv/reader.v
index f9e78a2b27..3055a0c7da 100644
--- a/vlib/encoding/csv/reader.v
+++ b/vlib/encoding/csv/reader.v
@@ -95,11 +95,11 @@ fn (mut r Reader) read_line() !string {
return &EndOfFileError{}
}
le := if r.is_mac_pre_osx_le { '\r' } else { '\n' }
- mut i := r.data.index_after(le, r.row_pos)
+ mut i := r.data.index_after(le, r.row_pos) or { -1 }
if i == -1 {
if r.row_pos == 0 {
// check for pre osx mac line endings
- i = r.data.index_after('\r', r.row_pos)
+ i = r.data.index_after('\r', r.row_pos) or { -1 }
if i != -1 {
r.is_mac_pre_osx_le = true
} else {
diff --git a/vlib/net/http/util.v b/vlib/net/http/util.v
index 52e8c913e4..d90b17ef8a 100644
--- a/vlib/net/http/util.v
+++ b/vlib/net/http/util.v
@@ -8,9 +8,6 @@ module http
// "GET / HTTP/1.1" => ["GET" "/" "HTTP/1.1"]
fn fast_request_words(line string) (int, int) {
space1 := line.index(' ') or { return 0, 0 }
- space2 := line.index_after(' ', space1 + 1)
- if space2 == -1 {
- return 0, 0
- }
+ space2 := line.index_after(' ', space1 + 1) or { return 0, 0 }
return space1, space2
}
diff --git a/vlib/v/ast/cflags.v b/vlib/v/ast/cflags.v
index 8913ead423..d18ff7df78 100644
--- a/vlib/v/ast/cflags.v
+++ b/vlib/v/ast/cflags.v
@@ -64,7 +64,7 @@ pub fn (mut t Table) parse_cflag(cflg string, mod string, ctimedefines []string)
if has_next {
break
}
- index = flag.index_after(' -', index + 1)
+ index = flag.index_after(' -', index + 1) or { -1 }
}
if index == -1 {
value = flag.trim_space()
diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v
index 4a8f7fa212..b86d5e0874 100644
--- a/vlib/v/checker/checker.v
+++ b/vlib/v/checker/checker.v
@@ -3367,15 +3367,17 @@ fn (mut c Checker) cast_expr(mut node ast.CastExpr) ast.Type {
}
c.check_any_type(to_type, to_sym, node.pos)
- if (to_sym.is_number() && from_sym.name == 'JS.Number')
- || (to_sym.is_number() && from_sym.name == 'JS.BigInt')
- || (to_sym.is_string() && from_sym.name == 'JS.String')
- || (to_type.is_bool() && from_sym.name == 'JS.Boolean')
- || (from_type.is_bool() && to_sym.name == 'JS.Boolean')
- || (from_sym.is_number() && to_sym.name == 'JS.Number')
- || (from_sym.is_number() && to_sym.name == 'JS.BigInt')
- || (from_sym.is_string() && to_sym.name == 'JS.String') {
- return to_type
+ if c.pref.backend.is_js() {
+ if (to_sym.is_number() && from_sym.name == 'JS.Number')
+ || (to_sym.is_number() && from_sym.name == 'JS.BigInt')
+ || (to_sym.is_string() && from_sym.name == 'JS.String')
+ || (to_type.is_bool() && from_sym.name == 'JS.Boolean')
+ || (from_type.is_bool() && to_sym.name == 'JS.Boolean')
+ || (from_sym.is_number() && to_sym.name == 'JS.Number')
+ || (from_sym.is_number() && to_sym.name == 'JS.BigInt')
+ || (from_sym.is_string() && to_sym.name == 'JS.String') {
+ return to_type
+ }
}
if !c.expected_type.has_flag(.generic) && to_sym.name.len == 1
diff --git a/vlib/v/eval/expr.c.v b/vlib/v/eval/expr.c.v
index f6bb2856cc..4fd2698f88 100644
--- a/vlib/v/eval/expr.c.v
+++ b/vlib/v/eval/expr.c.v
@@ -579,12 +579,15 @@ pub fn (mut e Eval) expr(expr ast.Expr, expecting ast.Type) Object {
}
e.error('unhandled index expression ${left}[ ${index} ]')
}
+ ast.OrExpr {
+ e.error('unhandled expression ${typeof(expr).name}')
+ }
ast.AnonFn, ast.ArrayDecompose, ast.AsCast, ast.Assoc, ast.AtExpr, ast.CTempVar,
ast.ChanInit, ast.Comment, ast.ComptimeCall, ast.ComptimeSelector, ast.ComptimeType,
ast.ConcatExpr, ast.DumpExpr, ast.EmptyExpr, ast.EnumVal, ast.GoExpr, ast.SpawnExpr,
ast.IfGuardExpr, ast.IsRefType, ast.Likely, ast.LockExpr, ast.MapInit, ast.MatchExpr,
- ast.Nil, ast.None, ast.OffsetOf, ast.OrExpr, ast.RangeExpr, ast.SelectExpr, ast.SqlExpr,
- ast.TypeNode, ast.TypeOf, ast.LambdaExpr {
+ ast.Nil, ast.None, ast.OffsetOf, ast.RangeExpr, ast.SelectExpr, ast.SqlExpr, ast.TypeNode,
+ ast.TypeOf, ast.LambdaExpr {
e.error('unhandled expression ${typeof(expr).name}')
}
}
diff --git a/vlib/v/scanner/scanner.v b/vlib/v/scanner/scanner.v
index 533a78cc3b..54ecb37609 100644
--- a/vlib/v/scanner/scanner.v
+++ b/vlib/v/scanner/scanner.v
@@ -1506,10 +1506,7 @@ fn trim_slash_line_break(s string) string {
mut ret_str := s
for {
// find the position of the first `\` followed by a newline, after `start`:
- idx := ret_str.index_after('\\\n', start)
- if idx == -1 {
- break
- }
+ idx := ret_str.index_after('\\\n', start) or { break }
start = idx
// Here, ret_str[idx] is \, and ret_str[idx+1] is newline.
// Depending on the number of backslashes before the newline, we should either