206 lines
5.5 KiB
Plaintext
206 lines
5.5 KiB
Plaintext
// Mini-VM scanning and numeric helpers
|
|
static box MiniVmScan {
|
|
// helper: find needle from position pos
|
|
index_of_from(hay, needle, pos) {
|
|
// Guard position; clamp to valid range to avoid negative substring
|
|
if pos < 0 { pos = 0 }
|
|
local n = hay.length()
|
|
if pos >= n { return -1 }
|
|
local m = needle.length()
|
|
if m <= 0 { return pos }
|
|
local i = pos
|
|
local limit = n - m
|
|
loop (i <= limit) {
|
|
local seg = hay.substring(i, i + m)
|
|
if seg == needle { return i }
|
|
i = i + 1
|
|
}
|
|
return -1
|
|
}
|
|
|
|
// helper: find balanced bracket range [ ... ] starting at idx (points to '[')
|
|
find_balanced_array_end(json, idx) {
|
|
@n = json.length()
|
|
if json.substring(idx, idx+1) != "[" { return -1 }
|
|
@depth = 0
|
|
@i = idx
|
|
@in_str = 0
|
|
@guard = 0
|
|
loop (i < n) {
|
|
guard = guard + 1
|
|
if guard > 50000 { return -1 }
|
|
@ch = json.substring(i, i+1)
|
|
if in_str == 1 {
|
|
if ch == "\\" { i = i + 2 continue }
|
|
if ch == "\"" { in_str = 0 i = i + 1 continue }
|
|
i = i + 1
|
|
continue
|
|
}
|
|
if ch == "\"" { in_str = 1 i = i + 1 continue }
|
|
if ch == "[" { depth = depth + 1 }
|
|
if ch == "]" {
|
|
depth = depth - 1
|
|
if depth == 0 { return i }
|
|
}
|
|
i = i + 1
|
|
}
|
|
return -1
|
|
}
|
|
|
|
// helper: find balanced object range { ... } starting at idx (points to '{')
|
|
find_balanced_object_end(json, idx) {
|
|
@n = json.length()
|
|
if json.substring(idx, idx+1) != "{" { return -1 }
|
|
@depth = 0
|
|
@i = idx
|
|
@in_str = 0
|
|
@guard = 0
|
|
loop (i < n) {
|
|
guard = guard + 1
|
|
if guard > 50000 { return -1 }
|
|
@ch = json.substring(i, i+1)
|
|
if in_str == 1 {
|
|
if ch == "\\" { i = i + 2 continue }
|
|
if ch == "\"" { in_str = 0 i = i + 1 continue }
|
|
i = i + 1
|
|
continue
|
|
}
|
|
if ch == "\"" { in_str = 1 i = i + 1 continue }
|
|
if ch == "{" { depth = depth + 1 }
|
|
if ch == "}" {
|
|
depth = depth - 1
|
|
if depth == 0 { return i }
|
|
}
|
|
i = i + 1
|
|
}
|
|
return -1
|
|
}
|
|
|
|
_str_to_int(s) {
|
|
@i = 0
|
|
@n = s.length()
|
|
@acc = 0
|
|
loop (i < n) {
|
|
@ch = s.substring(i, i+1)
|
|
if ch == "0" { acc = acc * 10 + 0 i = i + 1 continue }
|
|
if ch == "1" { acc = acc * 10 + 1 i = i + 1 continue }
|
|
if ch == "2" { acc = acc * 10 + 2 i = i + 1 continue }
|
|
if ch == "3" { acc = acc * 10 + 3 i = i + 1 continue }
|
|
if ch == "4" { acc = acc * 10 + 4 i = i + 1 continue }
|
|
if ch == "5" { acc = acc * 10 + 5 i = i + 1 continue }
|
|
if ch == "6" { acc = acc * 10 + 6 i = i + 1 continue }
|
|
if ch == "7" { acc = acc * 10 + 7 i = i + 1 continue }
|
|
if ch == "8" { acc = acc * 10 + 8 i = i + 1 continue }
|
|
if ch == "9" { acc = acc * 10 + 9 i = i + 1 continue }
|
|
break
|
|
}
|
|
return acc
|
|
}
|
|
_digit_char(d) {
|
|
if d == 0 { return "0" }
|
|
if d == 1 { return "1" }
|
|
if d == 2 { return "2" }
|
|
if d == 3 { return "3" }
|
|
if d == 4 { return "4" }
|
|
if d == 5 { return "5" }
|
|
if d == 6 { return "6" }
|
|
if d == 7 { return "7" }
|
|
if d == 8 { return "8" }
|
|
if d == 9 { return "9" }
|
|
return "0"
|
|
}
|
|
_int_to_str(n) {
|
|
if n == 0 { return "0" }
|
|
@v = n
|
|
@out = ""
|
|
loop (v > 0) {
|
|
@d = v % 10
|
|
@ch = _digit_char(d)
|
|
out = ch + out
|
|
v = v / 10
|
|
}
|
|
return out
|
|
}
|
|
|
|
// Read digit runs starting at pos
|
|
read_digits(json, pos) {
|
|
@out = ""
|
|
loop (true) {
|
|
@s = json.substring(pos, pos+1)
|
|
if s == "" { break }
|
|
if s == "0" { out = out + s pos = pos + 1 continue }
|
|
if s == "1" { out = out + s pos = pos + 1 continue }
|
|
if s == "2" { out = out + s pos = pos + 1 continue }
|
|
if s == "3" { out = out + s pos = pos + 1 continue }
|
|
if s == "4" { out = out + s pos = pos + 1 continue }
|
|
if s == "5" { out = out + s pos = pos + 1 continue }
|
|
if s == "6" { out = out + s pos = pos + 1 continue }
|
|
if s == "7" { out = out + s pos = pos + 1 continue }
|
|
if s == "8" { out = out + s pos = pos + 1 continue }
|
|
if s == "9" { out = out + s pos = pos + 1 continue }
|
|
break
|
|
}
|
|
return out
|
|
}
|
|
|
|
// Linear pass: sum all numbers outside of quotes
|
|
sum_numbers_no_quotes(json) {
|
|
@i = 0
|
|
@n = json.length()
|
|
@total = 0
|
|
loop (i < n) {
|
|
@ch = json.substring(i, i+1)
|
|
if ch == "\"" {
|
|
@j = index_of_from(json, "\"", i+1)
|
|
if j < 0 { break }
|
|
i = j + 1
|
|
continue
|
|
}
|
|
@d = read_digits(json, i)
|
|
if d { total = total + _str_to_int(d) i = i + d.length() continue }
|
|
i = i + 1
|
|
}
|
|
return _int_to_str(total)
|
|
}
|
|
|
|
// Naive: sum all digit runs anywhere
|
|
sum_all_digits_naive(json) {
|
|
@i = 0
|
|
@n = json.length()
|
|
@total = 0
|
|
loop (i < n) {
|
|
@d = read_digits(json, i)
|
|
if d { total = total + _str_to_int(d) i = i + d.length() continue }
|
|
i = i + 1
|
|
}
|
|
return _int_to_str(total)
|
|
}
|
|
|
|
// Sum first two integers outside quotes; returns string or empty
|
|
sum_first_two_numbers(json) {
|
|
@i = 0
|
|
@n = json.length()
|
|
@total = 0
|
|
local found = 0
|
|
loop (i < n) {
|
|
@ch = json.substring(i, i+1)
|
|
if ch == "\"" {
|
|
@j = index_of_from(json, "\"", i+1)
|
|
if j < 0 { break }
|
|
i = j + 1
|
|
continue
|
|
}
|
|
@d = read_digits(json, i)
|
|
if d {
|
|
total = total + _str_to_int(d)
|
|
found = found + 1
|
|
i = i + d.length()
|
|
if found >= 2 { return _int_to_str(total) }
|
|
continue
|
|
}
|
|
i = i + 1
|
|
}
|
|
return ""
|
|
}
|
|
}
|