// // Try_Bind_Word: C // // Binds a word to a context. If word is not part of the context. // REBCNT Try_Bind_Word(REBCTX *context, REBVAL *word) { REBCNT n = Find_Canon_In_Context(context, VAL_WORD_CANON(word), FALSE); if (n != 0) { // // Previously may have been bound relative, remove flag. // CLEAR_VAL_FLAG(word, VALUE_FLAG_RELATIVE); SET_VAL_FLAG(word, WORD_FLAG_BOUND); INIT_WORD_CONTEXT(word, context); INIT_WORD_INDEX(word, n); } return n; }
// // 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; }
// // Bind_Values_Inner_Loop: C // // Bind_Values_Core() sets up the binding table and then calls // this recursive routine to do the actual binding. // static void Bind_Values_Inner_Loop( struct Reb_Binder *binder, RELVAL *head, REBCTX *context, REBU64 bind_types, // !!! REVIEW: force word types low enough for 32-bit? REBU64 add_midstream_types, REBFLGS flags ) { RELVAL *value = head; for (; NOT_END(value); value++) { REBU64 type_bit = FLAGIT_KIND(VAL_TYPE(value)); if (type_bit & bind_types) { REBSTR *canon = VAL_WORD_CANON(value); REBCNT n = Try_Get_Binder_Index(binder, canon); if (n != 0) { assert(n <= CTX_LEN(context)); // We're overwriting any previous binding, which may have // been relative. // CLEAR_VAL_FLAG(value, VALUE_FLAG_RELATIVE); SET_VAL_FLAG(value, WORD_FLAG_BOUND); INIT_WORD_CONTEXT(value, context); INIT_WORD_INDEX(value, n); } else if (type_bit & add_midstream_types) { // // Word is not in context, so add it if option is specified // Expand_Context(context, 1); Append_Context(context, value, 0); Add_Binder_Index(binder, canon, VAL_WORD_INDEX(value)); } } else if (ANY_ARRAY(value) && (flags & BIND_DEEP)) { Bind_Values_Inner_Loop( binder, VAL_ARRAY_AT(value), context, bind_types, add_midstream_types, flags ); } else if ( IS_FUNCTION(value) && IS_FUNCTION_INTERPRETED(value) && (flags & BIND_FUNC) ) { // !!! Likely-to-be deprecated functionality--rebinding inside the // content of an already formed function. :-/ // Bind_Values_Inner_Loop( binder, VAL_FUNC_BODY(value), context, bind_types, add_midstream_types, flags ); } } }