forked from Mirror/wren
List.clear and List.insert().
This commit is contained in:
103
src/primitives.c
103
src/primitives.c
@ -64,52 +64,97 @@ DEF_FIBER_PRIMITIVE(fn_call6) { callFunction(fiber, AS_FN(args[0]), 7); }
|
||||
DEF_FIBER_PRIMITIVE(fn_call7) { callFunction(fiber, AS_FN(args[0]), 8); }
|
||||
DEF_FIBER_PRIMITIVE(fn_call8) { callFunction(fiber, AS_FN(args[0]), 9); }
|
||||
|
||||
// Grows [list] if needed to ensure it can hold [count] elements.
|
||||
static void ensureListCapacity(WrenVM* vm, ObjList* list, int count)
|
||||
{
|
||||
if (list->capacity >= count) return;
|
||||
|
||||
int capacity = list->capacity * LIST_GROW_FACTOR;
|
||||
if (capacity < LIST_MIN_CAPACITY) capacity = LIST_MIN_CAPACITY;
|
||||
|
||||
list->capacity *= 2;
|
||||
list->elements = wrenReallocate(vm, list->elements,
|
||||
list->capacity * sizeof(Value), capacity * sizeof(Value));
|
||||
// TODO(bob): Handle allocation failure.
|
||||
list->capacity = capacity;
|
||||
}
|
||||
|
||||
// Validates that [index] is an integer within `[0, count)`. Also allows
|
||||
// negative indices which map backwards from the end. Returns the valid positive
|
||||
// index value, or -1 if the index wasn't valid (not a number, not an int, out
|
||||
// of bounds).
|
||||
static int validateIndex(Value index, int count)
|
||||
{
|
||||
if (!IS_NUM(index)) return -1;
|
||||
|
||||
double indexNum = AS_NUM(index);
|
||||
int intIndex = (int)indexNum;
|
||||
// Make sure the index is an integer.
|
||||
if (indexNum != intIndex) return -1;
|
||||
|
||||
// Negative indices count from the end.
|
||||
if (indexNum < 0) indexNum = count + indexNum;
|
||||
|
||||
// Check bounds.
|
||||
if (indexNum < 0 || indexNum >= count) return -1;
|
||||
|
||||
return indexNum;
|
||||
}
|
||||
|
||||
DEF_PRIMITIVE(list_add)
|
||||
{
|
||||
ObjList* list = AS_LIST(args[0]);
|
||||
|
||||
// TODO(bob): Move this into value or other module?
|
||||
// Grow the list if needed.
|
||||
if (list->capacity < list->count + 1)
|
||||
{
|
||||
int capacity = list->capacity * LIST_GROW_FACTOR;
|
||||
if (capacity < LIST_MIN_CAPACITY) capacity = LIST_MIN_CAPACITY;
|
||||
|
||||
list->capacity *= 2;
|
||||
list->elements = wrenReallocate(vm, list->elements,
|
||||
list->capacity * sizeof(Value), capacity * sizeof(Value));
|
||||
// TODO(bob): Handle allocation failure.
|
||||
list->capacity = capacity;
|
||||
}
|
||||
|
||||
ensureListCapacity(vm, list, list->count + 1);
|
||||
list->elements[list->count++] = args[1];
|
||||
return args[1];
|
||||
}
|
||||
|
||||
DEF_PRIMITIVE(list_clear)
|
||||
{
|
||||
ObjList* list = AS_LIST(args[0]);
|
||||
wrenReallocate(vm, list->elements, list->capacity * sizeof(Value), 0);
|
||||
list->capacity = 0;
|
||||
list->count = 0;
|
||||
return NULL_VAL;
|
||||
}
|
||||
|
||||
DEF_PRIMITIVE(list_count)
|
||||
{
|
||||
ObjList* list = AS_LIST(args[0]);
|
||||
return NUM_VAL(list->count);
|
||||
}
|
||||
|
||||
DEF_PRIMITIVE(list_subscript)
|
||||
DEF_PRIMITIVE(list_insert)
|
||||
{
|
||||
// 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;
|
||||
int index = validateIndex(args[2], list->count + 1);
|
||||
// TODO(bob): Instead of returning null here, should signal an error
|
||||
// explicitly somehow.
|
||||
if (index == -1) return NULL_VAL;
|
||||
|
||||
// Check bounds.
|
||||
if (index < 0 || index >= list->count) return NULL_VAL;
|
||||
ensureListCapacity(vm, list, list->count + 1);
|
||||
|
||||
// Shift items down.
|
||||
for (int i = list->count; i > index; i--)
|
||||
{
|
||||
list->elements[i] = list->elements[i - 1];
|
||||
}
|
||||
|
||||
list->elements[index] = args[1];
|
||||
list->count++;
|
||||
return args[1];
|
||||
}
|
||||
|
||||
DEF_PRIMITIVE(list_subscript)
|
||||
{
|
||||
ObjList* list = AS_LIST(args[0]);
|
||||
|
||||
int index = validateIndex(args[1], list->count);
|
||||
// TODO(bob): Instead of returning null here, should signal an error
|
||||
// explicitly somehow.
|
||||
if (index == -1) return NULL_VAL;
|
||||
|
||||
return list->elements[index];
|
||||
}
|
||||
@ -351,7 +396,9 @@ void wrenLoadCore(WrenVM* vm)
|
||||
|
||||
vm->listClass = defineClass(vm, "List", vm->objectClass);
|
||||
PRIMITIVE(vm->listClass, "add ", list_add);
|
||||
PRIMITIVE(vm->listClass, "clear", list_clear);
|
||||
PRIMITIVE(vm->listClass, "count", list_count);
|
||||
PRIMITIVE(vm->listClass, "insert ", list_insert);
|
||||
PRIMITIVE(vm->listClass, "[ ]", list_subscript);
|
||||
|
||||
vm->nullClass = defineClass(vm, "Null", vm->objectClass);
|
||||
|
||||
7
test/list/clear.wren
Normal file
7
test/list/clear.wren
Normal file
@ -0,0 +1,7 @@
|
||||
var a = [1, 2, 3]
|
||||
a.clear
|
||||
io.write(a) // expect: []
|
||||
io.write(a.count) // expect: 0
|
||||
|
||||
// Returns null.
|
||||
io.write([1, 2].clear) // expect: null
|
||||
44
test/list/insert.wren
Normal file
44
test/list/insert.wren
Normal file
@ -0,0 +1,44 @@
|
||||
// TODO(bob): What happens if the index isn't an integer?
|
||||
// TODO(bob): Out of bounds.
|
||||
|
||||
// Add to empty list.
|
||||
var a = []
|
||||
a.insert(1, 0)
|
||||
io.write(a) // expect: [1]
|
||||
|
||||
// Normal indices.
|
||||
var b = [1, 2, 3]
|
||||
b.insert(4, 0)
|
||||
io.write(b) // expect: [4, 1, 2, 3]
|
||||
|
||||
var c = [1, 2, 3]
|
||||
c.insert(4, 1)
|
||||
io.write(c) // expect: [1, 4, 2, 3]
|
||||
|
||||
var d = [1, 2, 3]
|
||||
d.insert(4, 2)
|
||||
io.write(d) // expect: [1, 2, 4, 3]
|
||||
|
||||
var e = [1, 2, 3]
|
||||
e.insert(4, 3)
|
||||
io.write(e) // expect: [1, 2, 3, 4]
|
||||
|
||||
// Negative indices.
|
||||
var f = [1, 2, 3]
|
||||
f.insert(4, -4)
|
||||
io.write(f) // expect: [4, 1, 2, 3]
|
||||
|
||||
var g = [1, 2, 3]
|
||||
g.insert(4, -3)
|
||||
io.write(g) // expect: [1, 4, 2, 3]
|
||||
|
||||
var h = [1, 2, 3]
|
||||
h.insert(4, -2)
|
||||
io.write(h) // expect: [1, 2, 4, 3]
|
||||
|
||||
var i = [1, 2, 3]
|
||||
i.insert(4, -1)
|
||||
io.write(i) // expect: [1, 2, 3, 4]
|
||||
|
||||
// Returns.inserted value.
|
||||
io.write([1, 2].insert(3, 0)) // expect: 3
|
||||
Reference in New Issue
Block a user