Exemplo n.º 1
0
//
//  PD_Tuple: C
//
// Implements PATH and SET_PATH for tuple.
// Sets DS_TOP if found. Always returns 0.
//
REBINT PD_Tuple(REBPVS *pvs)
{
    const REBVAL *setval;
    REBINT n;
    REBINT i;
    REBYTE *dat;
    REBINT len;

    dat = VAL_TUPLE(pvs->value);
    len = VAL_TUPLE_LEN(pvs->value);

    if (len < 3) {
        len = 3;
    }

    n = Get_Num_From_Arg(pvs->selector);

    if ((setval = pvs->opt_setval)) {
        if (n <= 0 || n > cast(REBINT, MAX_TUPLE))
            fail (Error_Bad_Path_Select(pvs));

        if (IS_INTEGER(setval) || IS_DECIMAL(setval))
            i = Int32(setval);
        else if (IS_BLANK(setval)) {
            n--;
            CLEAR(dat + n, MAX_TUPLE - n);
            VAL_TUPLE_LEN(pvs->value) = n;
            return PE_OK;
        }
        else
            fail (Error_Bad_Path_Set(pvs));

        if (i < 0) i = 0;
        else if (i > 255) i = 255;

        dat[n - 1] = i;
        if (n > len)
            VAL_TUPLE_LEN(pvs->value) = n;

        return PE_OK;
    }
    else {
        if (n > 0 && n <= len) {
            SET_INTEGER(pvs->store, dat[n - 1]);
            return PE_USE_STORE;
        }
        else return PE_NONE;
    }
}
Exemplo n.º 2
0
//
//  Poke_Tuple_Immediate: C
//
// !!! Note: In the current implementation, tuples are immediate values.
// So a POKE only changes the `value` in your hand.
//
void Poke_Tuple_Immediate(
    REBVAL *value,
    const REBVAL *picker,
    const REBVAL *poke
) {
    REBYTE *dat = VAL_TUPLE(value);

    REBINT len = VAL_TUPLE_LEN(value);
    if (len < 3)
        len = 3;

    REBINT n = Get_Num_From_Arg(picker);
    if (n <= 0 || n > cast(REBINT, MAX_TUPLE))
        fail (Error_Out_Of_Range(picker));

    REBINT i;
    if (IS_INTEGER(poke) || IS_DECIMAL(poke))
        i = Int32(poke);
    else if (IS_BLANK(poke)) {
        n--;
        CLEAR(dat + n, MAX_TUPLE - n);
        VAL_TUPLE_LEN(value) = n;
        return;
    }
    else
        fail (poke);

    if (i < 0)
        i = 0;
    else if (i > 255)
        i = 255;

    dat[n - 1] = i;
    if (n > len)
        VAL_TUPLE_LEN(value) = n;
}
Exemplo n.º 3
0
//
//  Pick_Tuple: C
//
void Pick_Tuple(REBVAL *out, const REBVAL *value, const REBVAL *picker)
{
    const REBYTE *dat = VAL_TUPLE(value);

    REBINT len = VAL_TUPLE_LEN(value);
    if (len < 3)
        len = 3;

    REBINT n = Get_Num_From_Arg(picker);

    // This uses modulus to avoid having a conditional access into the array,
    // which would trigger Spectre mitigation:
    //
    // https://stackoverflow.com/questions/50399940/
    //
    // By always accessing the array and always being in bounds, there's no
    // speculative execution accessing unbound locations.
    //
    REBYTE byte = dat[(n - 1) % len];
    if (n > 0 and n <= len)
        Init_Integer(out, byte);
    else
        Init_Nulled(out);
}
Exemplo n.º 4
0
//
//  Series_Common_Action_Returns: C
// 
// This routine is called to handle actions on ANY-SERIES! that can be taken
// care of without knowing what specific kind of series it is.  So generally
// index manipulation, and things like LENGTH/etc.
//
// The strange name is to convey the result in an if statement, in the same
// spirit as the `if (XXX_Throws(...)) { /* handle throw */ }` pattern.
//
REBOOL Series_Common_Action_Returns(
    REB_R *r, // `r_out` would be slightly confusing, considering R_OUT
    REBFRM *frame_,
    REBSYM action
) {
    REBVAL *value = D_ARG(1);
    REBVAL *arg = D_ARGC > 1 ? D_ARG(2) : NULL;

    REBINT index = cast(REBINT, VAL_INDEX(value));
    REBINT tail = cast(REBINT, VAL_LEN_HEAD(value));
    REBINT len = 0;

    switch (action) {

    //-- Navigation:

    case SYM_HEAD:
        VAL_INDEX(value) = 0;
        break;

    case SYM_TAIL:
        VAL_INDEX(value) = (REBCNT)tail;
        break;

    case SYM_HEAD_Q:
        *r = (index == 0) ? R_TRUE : R_FALSE;
        return TRUE; // handled

    case SYM_TAIL_Q:
        *r = (index >= tail) ? R_TRUE : R_FALSE;
        return TRUE; // handled

    case SYM_PAST_Q:
        *r = (index > tail) ? R_TRUE : R_FALSE;
        return TRUE; // handled

    case SYM_NEXT:
        if (index < tail) VAL_INDEX(value)++;
        break;

    case SYM_BACK:
        if (index > 0) VAL_INDEX(value)--;
        break;

    case SYM_SKIP:
    case SYM_AT:
        len = Get_Num_From_Arg(arg);
        {
            REBI64 i = (REBI64)index + (REBI64)len;
            if (action == SYM_SKIP) {
                if (IS_LOGIC(arg)) i--;
            } else { // A_AT
                if (len > 0) i--;
            }
            if (i > (REBI64)tail) i = (REBI64)tail;
            else if (i < 0) i = 0;
            VAL_INDEX(value) = (REBCNT)i;
        }
        break;

    case SYM_INDEX_OF:
        SET_INTEGER(D_OUT, cast(REBI64, index) + 1);
        *r = R_OUT;
        return TRUE; // handled

    case SYM_LENGTH:
        SET_INTEGER(D_OUT, tail > index ? tail - index : 0);
        *r = R_OUT;
        return TRUE; // handled

    case SYM_REMOVE:
        // /PART length
        FAIL_IF_LOCKED_SERIES(VAL_SERIES(value));
        len = D_REF(2) ? Partial(value, 0, D_ARG(3)) : 1;
        index = cast(REBINT, VAL_INDEX(value));
        if (index < tail && len != 0)
            Remove_Series(VAL_SERIES(value), VAL_INDEX(value), len);
        break;

    case SYM_ADD:         // Join_Strings(value, arg);
    case SYM_SUBTRACT:    // "test this" - 10
    case SYM_MULTIPLY:    // "t" * 4 = "tttt"
    case SYM_DIVIDE:
    case SYM_REMAINDER:
    case SYM_POWER:
    case SYM_ODD_Q:
    case SYM_EVEN_Q:
    case SYM_ABSOLUTE:
        fail (Error_Illegal_Action(VAL_TYPE(value), action));

    default:
        return FALSE; // not a common operation, not handled
    }

    *D_OUT = *value;
    *r = R_OUT;
    return TRUE; // handled
}