diff --git a/src/primitives.c b/src/primitives.c index 8408971f..ae60a628 100644 --- a/src/primitives.c +++ b/src/primitives.c @@ -91,6 +91,28 @@ DEF_PRIMITIVE(list_count) return NUM_VAL(list->count); } +DEF_PRIMITIVE(list_subscript) +{ + // TODO(bob): Instead of returning null here, all of these failure cases + // should signal an error explicitly somehow. + if (!IS_NUM(args[1])) return NULL_VAL; + + double indexNum = AS_NUM(args[1]); + int index = (int)indexNum; + // Make sure the index is an integer. + if (indexNum != index) return NULL_VAL; + + ObjList* list = AS_LIST(args[0]); + + // Negative indices count from the end. + if (index < 0) index = list->count + index; + + // Check bounds. + if (index < 0 || index >= list->count) return NULL_VAL; + + return list->elements[index]; +} + DEF_PRIMITIVE(num_abs) { return NUM_VAL(fabs(AS_NUM(args[0]))); @@ -319,6 +341,7 @@ void loadCore(VM* vm) vm->listClass = AS_CLASS(findGlobal(vm, "List")); PRIMITIVE(vm->listClass, "count", list_count); + PRIMITIVE(vm->listClass, "[ ]", list_subscript); vm->nullClass = AS_CLASS(findGlobal(vm, "Null")); diff --git a/test/list_subscript.wren b/test/list_subscript.wren new file mode 100644 index 00000000..18c52f20 --- /dev/null +++ b/test/list_subscript.wren @@ -0,0 +1,25 @@ +// Returns elements. +var list = ["a", "b", "c", "d"] +io.write(list[0]) // expect: a +io.write(list[1]) // expect: b +io.write(list[2]) // expect: c +io.write(list[3]) // expect: d + +// Allows indexing backwards from the end. +io.write(list[-4]) // expect: a +io.write(list[-3]) // expect: b +io.write(list[-2]) // expect: c +io.write(list[-1]) // expect: d + +// Handle out of bounds. +// TODO(bob): Should halt the fiber or raise an error somehow. +io.write(list[4]) // expect: null +io.write(list[-5]) // expect: null + +// Handle wrong argument type. +// TODO(bob): Should halt the fiber or raise an error somehow. +io.write(list[true]) // expect: null + +// Handle non-integer index. +// TODO(bob): Should halt the fiber or raise an error somehow. +io.write(list[1.5]) // expect: null