fix string indexing in native

This commit is contained in:
2026-02-23 10:36:22 -06:00
parent 94c28f0e17
commit f26b6e853d
10 changed files with 11127 additions and 10943 deletions

View File

@@ -7494,6 +7494,162 @@ run("disruption propagation - comparison error direct vs nested", function() {
}
})
// ============================================================================
// STRING BRACKET INDEXING — str[n] must return the character at index n
// Regression: native __load_index_ss only handled arrays, returning null for
// strings. This broke key[0]=='$' in engine.cm, surfacing as '$stop' undefined.
// ============================================================================
run("string bracket index - first char", function() {
var s = "hello"
assert_eq(s[0], "h", "s[0]")
})
run("string bracket index - middle char", function() {
var s = "hello"
assert_eq(s[2], "l", "s[2]")
})
run("string bracket index - last char", function() {
var s = "hello"
assert_eq(s[4], "o", "s[4]")
})
run("string bracket index - out of bounds returns null", function() {
var s = "hi"
assert_eq(s[5], null, "s[5] oob")
assert_eq(s[99], null, "s[99] oob")
})
run("string bracket index - negative returns null", function() {
var s = "abc"
assert_eq(s[-1], null, "s[-1]")
})
run("string bracket index - single char string", function() {
var s = "x"
assert_eq(s[0], "x", "s[0] single")
assert_eq(s[1], null, "s[1] oob single")
})
run("string bracket index - special chars", function() {
var s = "$stop"
assert_eq(s[0], "$", "dollar sign at [0]")
assert_eq(s[1], "s", "s at [1]")
assert_eq(s[4], "p", "p at [4]")
})
run("string bracket index - empty string", function() {
var s = ""
assert_eq(s[0], null, "empty[0]")
})
run("string bracket index - comparison", function() {
var key = "$hello"
if (key[0] == "$") {
// pass — this is the pattern engine.cm uses
} else {
fail("key[0] should equal '$' but got " + text(key[0]))
}
})
run("string bracket index - in conditional", function() {
var s = "abc"
var r = null
if (s[0] == "a") r = "ok"
assert_eq(r, "ok", "s[0]=='a' conditional")
})
run("string bracket index - loop over chars", function() {
var s = "abcd"
var out = ""
var i = 0
for (i = 0; i < length(s); i++) {
out = out + s[i]
}
assert_eq(out, "abcd", "loop over string chars")
})
run("string bracket index - dynamic index", function() {
var s = "world"
var i = 2
assert_eq(s[i], "r", "s[dynamic]")
i = 0
assert_eq(s[i], "w", "s[dynamic 0]")
})
run("string bracket index - 7 char immediate boundary", function() {
// immediate strings store up to 7 ASCII chars inline
var s7 = "abcdefg"
assert_eq(s7[0], "a", "imm7[0]")
assert_eq(s7[6], "g", "imm7[6]")
var s8 = "abcdefgh"
assert_eq(s8[0], "a", "heap8[0]")
assert_eq(s8[7], "h", "heap8[7]")
})
run("string bracket index - used as record key", function() {
var s = "$name"
var prefix = s[0]
var rest = text(s, 1)
var obj = {}
obj[prefix + rest] = 42
assert_eq(obj["$name"], 42, "reconstruct key from bracket index")
})
// ============================================================================
// INDEXED ACCESS ON NON-ARRAY TYPES — native fast path must fall through
// These smoke out __load_index_ss returning null instead of calling runtime.
// ============================================================================
run("record bracket index with numeric key returns null", function() {
var obj = {a: 1}
assert_eq(obj[0], null, "record[0]")
})
run("null bracket index returns null", function() {
var x = null
assert_eq(x[0], null, "null[0]")
})
run("number bracket index returns null", function() {
var n = 42
assert_eq(n[0], null, "number[0]")
})
run("boolean bracket index returns null", function() {
var b = true
assert_eq(b[0], null, "bool[0]")
})
run("string length still works", function() {
assert_eq(length("hello"), 5, "length of 'hello'")
assert_eq(length(""), 0, "length of ''")
assert_eq(length("abcdefg"), 7, "length of 7-char imm")
assert_eq(length("abcdefgh"), 8, "length of 8-char heap")
})
run("mixed array and string indexing", function() {
var arr = ["abc", "def"]
assert_eq(arr[0][0], "a", "arr[0][0]")
assert_eq(arr[1][2], "f", "arr[1][2]")
})
run("string index result equality", function() {
var a = "hello"
var b = "hello"
assert_eq(a[0] == b[0], true, "same char from same string pos")
assert_eq(a[0] == "h", true, "char equals literal")
assert_eq(a[0] != "x", true, "char not-equals different literal")
})
run("string index in text() call", function() {
var s = "$abc"
var sub = text(s, 1)
assert_eq(sub, "abc", "text(s, 1) strips first char")
assert_eq(s[0] + sub, "$abc", "reassemble from index + substring")
})
// ============================================================================
// SUMMARY
// ============================================================================