// // Copy_And_Bind_Relative_Deep_Managed: C // // This routine is called by Make_Function in order to take the raw material // given as a function body, and de-relativize any IS_RELATIVE(value)s that // happen to be in it already (as any Copy does). But it also needs to make // new relative references to ANY-WORD! that are referencing function // parameters, as well as to relativize the copies of ANY-ARRAY! that contain // these relative words...so that they refer to the archetypal function // to which they should be relative. // REBARR *Copy_And_Bind_Relative_Deep_Managed( const REBVAL *body, REBARR *paramlist, // body of function is not actually ready yet REBU64 bind_types ) { // !!! Currently this is done in two phases, because the historical code // would use the generic copying code and then do a bind phase afterward. // Both phases are folded into this routine to make it easier to make // a one-pass version when time permits. // REBARR *copy = COPY_ANY_ARRAY_AT_DEEP_MANAGED(body); struct Reb_Binder binder; INIT_BINDER(&binder); // Setup binding table from the argument word list // REBCNT index = 1; RELVAL *param = ARR_AT(paramlist, 1); // [0] is FUNCTION! value for (; NOT_END(param); param++, index++) Add_Binder_Index(&binder, VAL_KEY_CANON(param), index); Bind_Relative_Inner_Loop(&binder, ARR_HEAD(copy), paramlist, bind_types); // Reset binding table // param = ARR_AT(paramlist, 1); // [0] is FUNCTION! value for (; NOT_END(param); param++) Remove_Binder_Index(&binder, VAL_KEY_CANON(param)); SHUTDOWN_BINDER(&binder); return copy; }
*/ static void Bind_Relative_Inner_Loop(REBINT *binds, REBSER *frame, REBSER *block) /* ** Recursive function for relative function word binding. ** ** Note: frame arg points to an identifying series of the function, ** not a normal frame. This will be used to verify the word fetch. ** ***********************************************************************/ { REBVAL *value = BLK_HEAD(block); for (; NOT_END(value); value++) { if (ANY_WORD(value)) { // Is the word (canon sym) found in this frame? REBINT n = binds[VAL_WORD_CANON(value)]; if (n != 0) { // Word is in frame, bind it: VAL_WORD_INDEX(value) = n; VAL_WORD_FRAME(value) = frame; // func body } } else if (ANY_BLOCK(value)) Bind_Relative_Inner_Loop(binds, frame, VAL_SERIES(value)); } }
*/ void Bind_Relative(REBSER *words, REBSER *frame, REBSER *block) /* ** Bind the words of a function block to a stack frame. ** To indicate the relative nature of the index, it is set to ** a negative offset. ** ** words: VAL_FUNC_WORDS(func) ** frame: VAL_FUNC_WORDS(func) ** block: block to bind ** ***********************************************************************/ { REBVAL *args; REBINT index; REBINT *binds = WORDS_HEAD(Bind_Table); // GC safe to do here args = BLK_SKIP(words, 1); CHECK_BIND_TABLE; //Dump_Block(words); // Setup binding table from the argument word list: for (index = 1; NOT_END(args); args++, index++) binds[VAL_BIND_CANON(args)] = -index; Bind_Relative_Inner_Loop(binds, frame, block); // Reset binding table: for (args = BLK_SKIP(words, 1); NOT_END(args); args++) binds[VAL_BIND_CANON(args)] = 0; CHECK_BIND_TABLE; }
// // Bind_Relative_Inner_Loop: C // // Recursive function for relative function word binding. Returns TRUE if // any relative bindings were made. // static void Bind_Relative_Inner_Loop( struct Reb_Binder *binder, RELVAL *head, REBARR *paramlist, REBU64 bind_types ) { RELVAL *value = head; for (; NOT_END(value); value++) { REBU64 type_bit = FLAGIT_KIND(VAL_TYPE(value)); // The two-pass copy-and-then-bind should have gotten rid of all the // relative values to other functions during the copy. // // !!! Long term, in a single pass copy, this would have to deal // with relative values and run them through the specification // process if they were not just getting overwritten. // assert(!IS_RELATIVE(value)); if (type_bit & bind_types) { REBINT n = Try_Get_Binder_Index(binder, VAL_WORD_CANON(value)); if (n != 0) { // // Word's canon symbol is in frame. Relatively bind it. // (clear out existing binding flags first). // UNBIND_WORD(value); SET_VAL_FLAGS(value, WORD_FLAG_BOUND | VALUE_FLAG_RELATIVE); INIT_WORD_FUNC(value, AS_FUNC(paramlist)); // incomplete func INIT_WORD_INDEX(value, n); } } else if (ANY_ARRAY(value)) { Bind_Relative_Inner_Loop( binder, VAL_ARRAY_AT(value), paramlist, bind_types ); // Set the bits in the ANY-ARRAY! REBVAL to indicate that it is // relative to the function. // // !!! Technically speaking it is not necessary for an array to // be marked relative if it doesn't contain any relative words // under it. However, for uniformity in the near term, it's // easiest to debug if there is a clear mark on arrays that are // part of a deep copy of a function body either way. // SET_VAL_FLAG(value, VALUE_FLAG_RELATIVE); INIT_RELATIVE(value, AS_FUNC(paramlist)); // incomplete func } } }