fix string indexing in native
This commit is contained in:
156
vm_suite.ce
156
vm_suite.ce
@@ -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
|
||||
// ============================================================================
|
||||
|
||||
Reference in New Issue
Block a user