1
0
forked from Mirror/wren

Fix #2. Finish implementing Range.

Covers error and edge cases and fully tested now.
This commit is contained in:
Bob Nystrom
2014-01-20 13:20:22 -08:00
parent 97bf314f4b
commit 46c1ba9249
14 changed files with 148 additions and 38 deletions

View File

@ -491,22 +491,22 @@ DEF_NATIVE(num_bitwiseNot)
DEF_NATIVE(num_dotDot)
{
// TODO: Check arg type.
if (!validateNum(vm, args, 1, "Right hand side of range")) return PRIM_ERROR;
double from = AS_NUM(args[0]);
double to = AS_NUM(args[1]);
RETURN_VAL(wrenNewRange(vm, from, to));
RETURN_VAL(wrenNewRange(vm, from, to, true));
}
DEF_NATIVE(num_dotDotDot)
{
// TODO: Check arg type.
if (!validateNum(vm, args, 1, "Right hand side of range")) return PRIM_ERROR;
double from = AS_NUM(args[0]);
double to = AS_NUM(args[1]);
// TODO: Is this how we want half-open ranges to work?
double to = AS_NUM(args[1]) - 1;
RETURN_VAL(wrenNewRange(vm, from, to));
RETURN_VAL(wrenNewRange(vm, from, to, false));
}
DEF_NATIVE(object_eqeq)
@ -560,10 +560,19 @@ DEF_NATIVE(range_max)
RETURN_NUM(fmax(range->from, range->to));
}
DEF_NATIVE(range_isInclusive)
{
ObjRange* range = AS_RANGE(args[0]);
RETURN_BOOL(range->isInclusive);
}
DEF_NATIVE(range_iterate)
{
ObjRange* range = AS_RANGE(args[0]);
// Special case: empty range.
if (range->from == range->to && !range->isInclusive) RETURN_FALSE;
// Start the iteration.
if (IS_NULL(args[1])) RETURN_NUM(range->from);
@ -571,9 +580,21 @@ DEF_NATIVE(range_iterate)
double iterator = AS_NUM(args[1]);
if (iterator >= range->to) RETURN_FALSE;
// Iterate towards [to] from [from].
if (range->from < range->to)
{
iterator++;
if (iterator > range->to) RETURN_FALSE;
}
else
{
iterator--;
if (iterator < range->to) RETURN_FALSE;
}
RETURN_NUM(AS_NUM(args[1]) + 1);
if (!range->isInclusive && iterator == range->to) RETURN_FALSE;
RETURN_NUM(iterator);
}
DEF_NATIVE(range_iteratorValue)
@ -586,7 +607,8 @@ DEF_NATIVE(range_toString)
{
char buffer[51];
ObjRange* range = AS_RANGE(args[0]);
sprintf(buffer, "%.14g..%.14g", range->from, range->to);
sprintf(buffer, "%.14g%s%.14g", range->from,
range->isInclusive ? ".." : "...", range->to);
RETURN_VAL(wrenNewString(vm, buffer, strlen(buffer)));
}
@ -811,6 +833,7 @@ void wrenInitializeCore(WrenVM* vm)
NATIVE(vm->rangeClass, "to", range_to);
NATIVE(vm->rangeClass, "min", range_min);
NATIVE(vm->rangeClass, "max", range_max);
NATIVE(vm->rangeClass, "isInclusive", range_isInclusive);
NATIVE(vm->rangeClass, "iterate ", range_iterate);
NATIVE(vm->rangeClass, "iteratorValue ", range_iteratorValue);
NATIVE(vm->rangeClass, "toString", range_toString);

View File

@ -301,12 +301,13 @@ Value wrenListRemoveAt(WrenVM* vm, ObjList* list, int index)
return removed;
}
Value wrenNewRange(WrenVM* vm, double from, double to)
Value wrenNewRange(WrenVM* vm, double from, double to, bool isInclusive)
{
ObjRange* range = allocate(vm, sizeof(ObjRange) + 16);
initObj(vm, &range->obj, OBJ_RANGE);
range->from = from;
range->to = to;
range->isInclusive = isInclusive;
return OBJ_VAL(range);
}

View File

@ -317,6 +317,9 @@ typedef struct
// The end of the range. May be greater or less than [from].
double to;
// True if [to] is included in the range.
bool isInclusive;
} ObjRange;
@ -560,7 +563,7 @@ void wrenListInsert(WrenVM* vm, ObjList* list, Value value, int index);
Value wrenListRemoveAt(WrenVM* vm, ObjList* list, int index);
// Creates a new range from [from] to [to].
Value wrenNewRange(WrenVM* vm, double from, double to);
Value wrenNewRange(WrenVM* vm, double from, double to, bool isInclusive);
// Creates a new string object and copies [text] into it.
Value wrenNewString(WrenVM* vm, const char* text, size_t length);