Skip to content

Commit 708cd15

Browse files
gh-103: Make non-existent MAP keys error.
1 parent 734a12a commit 708cd15

File tree

3 files changed

+34
-7
lines changed

3 files changed

+34
-7
lines changed

docs/SPECIFICATION.html

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -356,6 +356,8 @@
356356
357357
`MAP` indexing MUST use angle brackets (`<` and `>`) with a comma-separated list of keys. Each key MUST evaluate to a scalar value of type `INT`, `FLT`, or `STR`. Tensor values MUST NOT be permitted as keys. The number of keys supplied MAY vary between lookups.
358358
359+
Looking up a key that does not exist MUST raise a runtime error.
360+
359361
Intermediate nested maps MUST be created on-demand when assigning to deeper keys. Assigning a value of a different type to an existing key MUST raise a runtime error.
360362
361363
When a `MAP` index expression is used in call position and the indexed value resolves to a `FUNC`, the interpreter MUST bind `SELF` for the duration of that call to the `MAP` value that supplied the function. If the `MAP` expression refers to a visible pointer alias to a `MAP` binding, `SELF` MUST alias the underlying binding so that mutations through `SELF` update the original map. Otherwise `SELF` MUST follow normal `MAP` value semantics, so calling through a non-pointer value mutates only the local copy.

src/interpreter.c

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1854,7 +1854,14 @@ Value eval_expr(Interpreter* interp, Expr* expr, Env* env) {
18541854
int found = 0;
18551855
Value got = value_map_get(cur, ikv, &found);
18561856
value_free(ikv);
1857-
if (!found) { value_free(cur); final_val = value_null(); break; }
1857+
if (!found) {
1858+
value_free(cur);
1859+
interp->error = strdup("Map key not found");
1860+
interp->error_line = ik->line;
1861+
interp->error_col = ik->column;
1862+
err = true;
1863+
break;
1864+
}
18581865
value_free(cur);
18591866
cur = got; // continue descending (got is a copy)
18601867
if (ii + 1 == idxs->count) final_val = value_copy(cur);
@@ -1925,8 +1932,13 @@ Value eval_expr(Interpreter* interp, Expr* expr, Env* env) {
19251932
int found = 0;
19261933
Value got = value_map_get(cur, key, &found);
19271934
value_free(key);
1928-
// If not found, return null (missing key)
1929-
if (!found) { value_free(cur); return value_null(); }
1935+
if (!found) {
1936+
value_free(cur);
1937+
interp->error = strdup("Map key not found");
1938+
interp->error_line = it->line;
1939+
interp->error_col = it->column;
1940+
return value_null();
1941+
}
19301942
// If this is last index, return the found value
19311943
if (i + 1 == nidx) {
19321944
// free original map container if it was a copy

tests/test2.pre

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -223,19 +223,32 @@ ASSERT(EQ(m<"foo">, 0d5))
223223
ASSERT(EQ(m<"bar">, 0d10))
224224
ASSERT(EQ(m<"nested", "a">, 0d1))
225225
ASSERT(EQ(m<"nested", "b">, 0d2))
226-
! Missing key should return null/false
227-
ASSERT(NOT(m<"nope">))
226+
! Missing key should raise an error
227+
INT: map_missing_err = 0d0
228+
TRY{
229+
m<"nope">
230+
}CATCH{
231+
map_missing_err = 0d1
232+
}
233+
ASSERT(EQ(map_missing_err, 0d1))
228234
PRINT("Maps: PASS\n")
229235

230236
! Regression test for GH-61: ensure DEL works on map index targets
231237
PRINT("Testing DEL on map indexing (regression GH-61)...")
232238
MAP: reg = <"foo" = 0d1, "bar" = 0d2, "nested" = <"a" = 0d10>>
233239
ASSERT(EQ(reg<"foo">, 0d1))
234240
DEL(reg<"foo">)
235-
ASSERT(NOT(reg<"foo">))
241+
ASSERT(NOT(KEYIN("foo", reg)))
242+
INT: reg_missing_err = 0d0
243+
TRY{
244+
reg<"foo">
245+
}CATCH{
246+
reg_missing_err = 0d1
247+
}
248+
ASSERT(EQ(reg_missing_err, 0d1))
236249
! Deleting nested key
237250
DEL(reg<"nested", "a">)
238-
ASSERT(NOT(reg<"nested", "a">))
251+
ASSERT(NOT(KEYIN("a", reg<"nested">)))
239252
DEL(reg)
240253
PRINT("DEL map-index: PASS\n")
241254

0 commit comments

Comments
 (0)