static bool prim_list_subscript(WrenVM vm, Obj[] args, int stackStart)
{
ObjList list = (ObjList)args[stackStart];
if (args[stackStart + 1].Type == ObjType.Num)
{
int index = (int)args[stackStart + 1].Num;
if (index == args[stackStart + 1].Num)
{
if (index < 0)
{
index += list.Count();
}
if (index >= 0 && index < list.Count())
{
args[stackStart] = list.Get(index);
return true;
}
vm.Fiber.Error = Obj.MakeString("Subscript out of bounds.");
return false;
}
vm.Fiber.Error = Obj.MakeString("Subscript must be an integer.");
return false;
}
ObjRange r = args[stackStart + 1] as ObjRange;
if (r == null)
{
vm.Fiber.Error = Obj.MakeString("Subscript must be a number or a range.");
return false;
}
// TODO: This is seriously broken and needs a rewrite
int from = (int)r.From;
if (from != r.From)
{
vm.Fiber.Error = Obj.MakeString("Range start must be an integer.");
return false;
}
int to = (int)r.To;
if (to != r.To)
{
vm.Fiber.Error = Obj.MakeString("Range end must be an integer.");
return false;
}
if (from < 0)
from += list.Count();
if (to < 0)
to += list.Count();
int step = to < from ? -1 : 1;
if (step > 0 && r.IsInclusive)
to += 1;
if (step < 0 && !r.IsInclusive)
to += 1;
// Handle copying an empty list
if (list.Count() == 0 && to == (r.IsInclusive ? -1 : 0))
{
to = 0;
step = 1;
}
int count = (to - from) * step + (step < 0 ? 1 : 0);
if (to < 0 || from + (count * step) > list.Count())
{
vm.Fiber.Error = Obj.MakeString("Range end out of bounds.");
return false;
}
if (from < 0 || (from >= list.Count() && from > 0))
{
vm.Fiber.Error = Obj.MakeString("Range start out of bounds.");
return false;
}
ObjList result = new ObjList(count);
for (int i = 0; i < count; i++)
{
result.Add(list.Get(from + (i * step)));
}
args[stackStart] = result;
return true;
}