예제 #1
0
파일: n-system.c 프로젝트: kjanz1899/ren-c
//
//  Make_Where_For_Frame: C
//
// Each call frame maintains the array it is executing in, the current index
// in that array, and the index of where the current expression started.
// This can be deduced into a segment of code to display in the debug views
// to indicate roughly "what's running" at that stack level.
//
// Unfortunately, Rebol doesn't formalize this very well.  There is no lock
// on segments of blocks during their evaluation, and it's possible for
// self-modifying code to scramble the blocks being executed.  The DO
// evaluator is robust in terms of not *crashing*, but the semantics may well
// suprise users.
//
// !!! Should blocks on the stack be locked from modification, at least by
// default unless a special setting for self-modifying code unlocks it?
//
// So long as WHERE information is unreliable, this has to check that
// `expr_index` (where the evaluation started) and `index` (where the
// evaluation thinks it currently is) aren't out of bounds here.  We could
// be giving back positions now unrelated to the call...but it won't crash!
//
REBARR *Make_Where_For_Frame(struct Reb_Frame *frame)
{
    REBCNT start;
    REBCNT end;

    REBARR *where;
    REBOOL pending;

    if (FRM_IS_VALIST(frame)) {
        const REBOOL truncated = TRUE;
        Reify_Va_To_Array_In_Frame(frame, truncated);
    }

    // WARNING: MIN is a C macro and repeats its arguments.
    //
    start = MIN(ARR_LEN(FRM_ARRAY(frame)), cast(REBCNT, frame->expr_index));
    end = MIN(ARR_LEN(FRM_ARRAY(frame)), FRM_INDEX(frame));

    assert(end >= start);
    assert(frame->mode != CALL_MODE_GUARD_ARRAY_ONLY);
    pending = NOT(frame->mode == CALL_MODE_FUNCTION);

    // Do a shallow copy so that the WHERE information only includes
    // the range of the array being executed up to the point of
    // currently relevant evaluation, not all the way to the tail
    // of the block (where future potential evaluation would be)
    {
        REBCNT n = 0;

        REBCNT len =
            1 // fake function word (compensates for prefetch)
            + (end - start) // data from expr_index to the current index
            + (pending ? 1 : 0); // if it's pending we put "..." to show that

        where = Make_Array(len);

        // !!! Due to "prefetch" the expr_index will be *past* the invocation
        // of the function.  So this is a lie, as a placeholder for what a
        // real debug mode would need to actually save the data to show.
        // If the execution were a path or anything other than a word, this
        // will lose it.
        //
        Val_Init_Word(ARR_AT(where, n), REB_WORD, FRM_LABEL(frame));
        ++n;

        for (n = 1; n < len; ++n)
            *ARR_AT(where, n) = *ARR_AT(FRM_ARRAY(frame), start + n - 1);

        SET_ARRAY_LEN(where, len);
        TERM_ARRAY(where);
    }

    // Making a shallow copy offers another advantage, that it's
    // possible to get rid of the newline marker on the first element,
    // that would visually disrupt the backtrace for no reason.
    //
    if (end - start > 0)
        CLEAR_VAL_FLAG(ARR_HEAD(where), VALUE_FLAG_LINE);

    // We add an ellipsis to a pending frame to make it a little bit
    // clearer what is going on.  If someone sees a where that looks
    // like just `* [print]` the asterisk alone doesn't quite send
    // home the message that print is not running and it is
    // argument fulfillment that is why it's not "on the stack"
    // yet, so `* [print ...]` is an attempt to say that better.
    //
    // !!! This is in-band, which can be mixed up with literal usage
    // of ellipsis.  Could there be a better "out-of-band" conveyance?
    // Might the system use colorization in a value option bit.
    //
    if (pending)
        Val_Init_Word(Alloc_Tail_Array(where), REB_WORD, SYM_ELLIPSIS);

    return where;
}
예제 #2
0
파일: f-modify.c 프로젝트: asampal/ren-c
*/	REBCNT Modify_Array(REBCNT action, REBSER *dst_ser, REBCNT dst_idx, const REBVAL *src_val, REBCNT flags, REBINT dst_len, REBINT dups)
/*
**		action: INSERT, APPEND, CHANGE
**
**		dst_ser:	target
**		dst_idx:	position
**		src_val:    source
**		flags:		AN_ONLY, AN_PART
**		dst_len:	length to remove
**		dups:		dup count
**
**		return: new dst_idx
**
***********************************************************************/
{
    REBCNT tail  = SERIES_TAIL(dst_ser);
    REBINT ilen  = 1;	// length to be inserted
    REBINT size;		// total to insert

#if !defined(NDEBUG)
    REBINT index;
#endif

    if (IS_UNSET(src_val) || dups < 0) {
        // If they are effectively asking for "no action" then all we have
        // to do is return the natural index result for the operation.
        // (APPEND will return 0, insert the tail of the insertion...so index)

        return (action == A_APPEND) ? 0 : dst_idx;
    }

    if (action == A_APPEND || dst_idx > tail) dst_idx = tail;

    // Check /PART, compute LEN:
    if (!GET_FLAG(flags, AN_ONLY) && ANY_ARRAY(src_val)) {
        // Adjust length of insertion if changing /PART:
        if (action != A_CHANGE && GET_FLAG(flags, AN_PART))
            ilen = dst_len;
        else
            ilen = VAL_LEN(src_val);

        // Are we modifying ourselves? If so, copy src_val block first:
        if (dst_ser == VAL_SERIES(src_val)) {
            REBSER *series = Copy_Array_At_Shallow(
                                 VAL_SERIES(src_val), VAL_INDEX(src_val)
                             );
            src_val = BLK_HEAD(series);
        }
        else
            src_val = VAL_BLK_DATA(src_val); // skips by VAL_INDEX values
    }

    // Total to insert:
    size = dups * ilen;

    if (action != A_CHANGE) {
        // Always expand dst_ser for INSERT and APPEND actions:
        Expand_Series(dst_ser, dst_idx, size);
    } else {
        if (size > dst_len)
            Expand_Series(dst_ser, dst_idx, size-dst_len);
        else if (size < dst_len && GET_FLAG(flags, AN_PART))
            Remove_Series(dst_ser, dst_idx, dst_len-size);
        else if (size + dst_idx > tail) {
            EXPAND_SERIES_TAIL(dst_ser, size - (tail - dst_idx));
        }
    }

    tail = (action == A_APPEND) ? 0 : size + dst_idx;

#if !defined(NDEBUG)
    for (index = 0; index < ilen; index++) {
        if (SERIES_GET_FLAG(dst_ser, SER_MANAGED))
            ASSERT_VALUE_MANAGED(&src_val[index]);
    }
#endif

    dst_idx *= SERIES_WIDE(dst_ser); // loop invariant
    ilen  *= SERIES_WIDE(dst_ser); // loop invariant
    for (; dups > 0; dups--) {
        memcpy(dst_ser->data + dst_idx, src_val, ilen);
        dst_idx += ilen;
    }
    TERM_ARRAY(dst_ser);

    return tail;
}