*/ REBINT PD_Pair(REBPVS *pvs) /* ***********************************************************************/ { REBVAL *sel; REBVAL *val; REBINT n = 0; REBD32 dec; if (IS_WORD(sel = pvs->select)) { if (VAL_WORD_CANON(sel) == SYM_X) n = 1; else if (VAL_WORD_CANON(sel) == SYM_Y) n = 2; else return PE_BAD_SELECT; } else if (IS_INTEGER(sel)) { n = Int32(sel); if (n != 1 && n !=2) return PE_BAD_SELECT; } else return PE_BAD_SELECT; if (NZ(val = pvs->setval)) { if (IS_INTEGER(val)) dec = (REBD32)VAL_INT64(val); else if (IS_DECIMAL(val)) dec = (REBD32)VAL_DECIMAL(val); else return PE_BAD_SET; if (n == 1) VAL_PAIR_X(pvs->value) = dec; else VAL_PAIR_Y(pvs->value) = dec; } else { dec = (n == 1 ? VAL_PAIR_X(pvs->value) : VAL_PAIR_Y(pvs->value)); SET_DECIMAL(pvs->store, dec); return PE_USE; } return PE_OK; }
// // Find_Key: C // // Returns hash index (either the match or the new one). // A return of zero is valid (as a hash index); // // Wide: width of record (normally 2, a key and a value). // // Modes: // 0 - search, return hash if found or not // 1 - search, return hash, else return -1 if not // 2 - search, return hash, else append value and return -1 // REBINT Find_Key(REBSER *series, REBSER *hser, const REBVAL *key, REBINT wide, REBCNT cased, REBYTE mode) { REBCNT *hashes; REBCNT skip; REBCNT hash; REBCNT len; REBCNT n; REBVAL *val; // Compute hash for value: len = hser->tail; hash = Hash_Value(key, len); if (!hash) fail (Error_Has_Bad_Type(key)); // Determine skip and first index: skip = (len == 0) ? 0 : (hash & 0x0000FFFF) % len; if (skip == 0) skip = 1; hash = (len == 0) ? 0 : (hash & 0x00FFFF00) % len; // Scan hash table for match: hashes = (REBCNT*)hser->data; if (ANY_WORD(key)) { while ((n = hashes[hash])) { val = BLK_SKIP(series, (n-1) * wide); if ( ANY_WORD(val) && (VAL_WORD_SYM(key) == VAL_WORD_SYM(val) || (!cased && VAL_WORD_CANON(key) == VAL_WORD_CANON(val))) ) return hash; hash += skip; if (hash >= len) hash -= len; } } else if (ANY_BINSTR(key)) { while ((n = hashes[hash])) { val = BLK_SKIP(series, (n-1) * wide); if ( VAL_TYPE(val) == VAL_TYPE(key) && 0 == Compare_String_Vals(key, val, (REBOOL)(!IS_BINARY(key) && !cased)) ) return hash; hash += skip; if (hash >= len) hash -= len; } } else { while ((n = hashes[hash])) { val = BLK_SKIP(series, (n-1) * wide); if (VAL_TYPE(val) == VAL_TYPE(key) && 0 == Cmp_Value(key, val, !cased)) return hash; hash += skip; if (hash >= len) hash -= len; } } // Append new value the target series: if (mode > 1) { hashes[hash] = SERIES_TAIL(series) + 1; Append_Values_Len(series, key, wide); } return (mode > 0) ? NOT_FOUND : hash; }
*/ static void Bind_Block_Words(REBSER *frame, REBVAL *value, REBCNT mode) /* ** Inner loop of bind block. Modes are: ** ** BIND_ONLY Only bind the words found in the frame. ** BIND_SET Add set-words to the frame during the bind. ** BIND_ALL Add words to the frame during the bind. ** BIND_DEEP Recurse into sub-blocks. ** ** NOTE: BIND_SET must be used carefully, because it does not ** bind prior instances of the word before the set-word. That is ** forward references are not allowed. ** ***********************************************************************/ { REBINT *binds = WORDS_HEAD(Bind_Table); // GC safe to do here REBCNT n; REBFLG selfish = !IS_SELFLESS(frame); for (; NOT_END(value); value++) { if (ANY_WORD(value)) { //Print("Word: %s", Get_Sym_Name(VAL_WORD_CANON(value))); // Is the word found in this frame? if (NZ(n = binds[VAL_WORD_CANON(value)])) { if (n == NO_RESULT) n = 0; // SELF word ASSERT1(n < SERIES_TAIL(frame), RP_BIND_BOUNDS); // Word is in frame, bind it: VAL_WORD_INDEX(value) = n; VAL_WORD_FRAME(value) = frame; } else if (selfish && VAL_WORD_CANON(value) == SYM_SELF) { VAL_WORD_INDEX(value) = 0; VAL_WORD_FRAME(value) = frame; } else { // Word is not in frame. Add it if option is specified: if ((mode & BIND_ALL) || ((mode & BIND_SET) && (IS_SET_WORD(value)))) { Append_Frame(frame, value, 0); binds[VAL_WORD_CANON(value)] = VAL_WORD_INDEX(value); } } } else if (ANY_BLOCK(value) && (mode & BIND_DEEP)) Bind_Block_Words(frame, VAL_BLK_DATA(value), mode); else if ((IS_FUNCTION(value) || IS_CLOSURE(value)) && (mode & BIND_FUNC)) Bind_Block_Words(frame, BLK_HEAD(VAL_FUNC_BODY(value)), mode); } }
*/ REBSER *Collect_Words(REBVAL value[], REBVAL prior_value[], REBCNT modes) /* ** Collect words from a prior block and new block. ** ***********************************************************************/ { REBSER *series; REBCNT start; REBINT *binds = WORDS_HEAD(Bind_Table); // GC safe to do here CHECK_BIND_TABLE; if (SERIES_TAIL(BUF_WORDS)) panic Error_0(RE_WORD_LIST); // still in use if (prior_value) Collect_Words_Inner_Loop(binds, &prior_value[0], BIND_ALL); start = SERIES_TAIL(BUF_WORDS); Collect_Words_Inner_Loop(binds, &value[0], modes); // Reset word markers: for (value = BLK_HEAD(BUF_WORDS); NOT_END(value); value++) binds[VAL_WORD_CANON(value)] = 0; series = Copy_Array_At_Max_Shallow( BUF_WORDS, start, SERIES_TAIL(BUF_WORDS) - start ); RESET_TAIL(BUF_WORDS); // allow reuse CHECK_BIND_TABLE; return series; }
*/ REBINT PD_Block(REBPVS *pvs) /* ***********************************************************************/ { REBINT n = 0; /* Issues!!! a/1.3 a/not-found: 10 error or append? a/not-followed: 10 error or append? */ if (IS_INTEGER(pvs->select)) { n = Int32(pvs->select) + VAL_INDEX(pvs->value) - 1; } else if (IS_WORD(pvs->select)) { n = Find_Word(VAL_SERIES(pvs->value), VAL_INDEX(pvs->value), VAL_WORD_CANON(pvs->select)); if (n != NOT_FOUND) n++; } else { // other values: n = Find_Block_Simple(VAL_SERIES(pvs->value), VAL_INDEX(pvs->value), pvs->select) + 1; } if (n < 0 || (REBCNT)n >= VAL_TAIL(pvs->value)) { if (pvs->setval) return PE_BAD_SELECT; return PE_NONE; } if (pvs->setval) TRAP_PROTECT(VAL_SERIES(pvs->value)); pvs->value = VAL_BLK_SKIP(pvs->value, n); // if valset - check PROTECT on block //if (NOT_END(pvs->path+1)) Next_Path(pvs); return PE_OK; return PE_SET; }
*/ static void Bind_Relative_Words(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); REBINT n; for (; NOT_END(value); value++) { if (ANY_WORD(value)) { // Is the word (canon sym) found in this frame? if (NZ(n = WORDS_HEAD(Bind_Table)[VAL_WORD_CANON(value)])) { // 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_Words(frame, VAL_SERIES(value)); } }
*/ REBSER *Collect_End(REBSER *prior) /* ** Finish collecting words, and free the Bind_Table for reuse. ** ***********************************************************************/ { REBVAL *words; REBINT *binds = WORDS_HEAD(Bind_Table); // GC safe to do here // Reset binding table (note BUF_WORDS may have expanded): for (words = BLK_HEAD(BUF_WORDS); NOT_END(words); words++) binds[VAL_WORD_CANON(words)] = 0; // If no new words, prior frame: if (prior && SERIES_TAIL(BUF_WORDS) == SERIES_TAIL(prior)) { RESET_TAIL(BUF_WORDS); // allow reuse return FRM_WORD_SERIES(prior); } prior = Copy_Series(BUF_WORDS); RESET_TAIL(BUF_WORDS); // allow reuse BARE_SERIES(prior); // No GC ever needed for word list CHECK_BIND_TABLE; return prior; }
// // INIT_WORD_INDEX_Debug: C // void INIT_WORD_INDEX_Debug(RELVAL *v, REBCNT i) { assert(ANY_WORD(v)); assert(GET_VAL_FLAG((v), WORD_FLAG_BOUND)); if (IS_RELATIVE(v)) assert( VAL_WORD_CANON(v) == VAL_PARAM_CANON(FUNC_PARAM(VAL_WORD_FUNC(v), i)) ); else assert( VAL_WORD_CANON(v) == CTX_KEY_CANON(VAL_WORD_CONTEXT(KNOWN(v)), i) ); v->payload.any_word.index = i; }
*/ RL_API u32 *RL_Map_Words(REBSER *series) /* ** Given a block of word values, return an array of word ids. ** ** Returns: ** An array of global word identifiers (integers). The [0] value is the size. ** Arguments: ** series - block of words as values (from REBOL blocks, not strings.) ** Notes: ** Word identifiers are persistent, and you can use them anytime. ** The block can include any kind of word, including set-words, lit-words, etc. ** If the input block contains non-words, they will be skipped. ** The array is allocated with OS_ALLOC and you can OS_FREE it any time. ** ***********************************************************************/ { REBCNT i = 1; u32 *words; REBVAL *val = BLK_HEAD(series); words = OS_ALLOC_ARRAY(u32, series->tail + 2); for (; NOT_END(val); val++) { if (ANY_WORD(val)) words[i++] = VAL_WORD_CANON(val); } words[0] = i; words[i] = 0; return words; }
*/ static void Set_Gob_Flag(REBGOB *gob, REBVAL *word) /* ***********************************************************************/ { REBINT i; for (i = 0; Gob_Flag_Words[i]; i += 2) { if (VAL_WORD_CANON(word) == Gob_Flag_Words[i]) { REBCNT flag = Gob_Flag_Words[i+1]; SET_GOB_FLAG(gob, flag); //handle mutual exclusive states switch (flag) { case GOBF_RESTORE: CLR_GOB_FLAGS(gob, GOBF_MINIMIZE, GOBF_MAXIMIZE); break; case GOBF_MINIMIZE: CLR_GOB_FLAGS(gob, GOBF_MAXIMIZE, GOBF_RESTORE); break; case GOBF_MAXIMIZE: CLR_GOB_FLAGS(gob, GOBF_MINIMIZE, GOBF_RESTORE); break; } break; } } }
*/ REBSER *Collect_Block_Words(REBVAL *block, REBVAL *prior, REBCNT modes) /* ** Collect words from a prior block and new block. ** ***********************************************************************/ { REBSER *series; REBCNT start; REBINT *binds = WORDS_HEAD(Bind_Table); // GC safe to do here CHECK_BIND_TABLE; if (SERIES_TAIL(BUF_WORDS)) Crash(RP_WORD_LIST); // still in use if (prior) Collect_Simple_Words(prior, BIND_ALL); start = SERIES_TAIL(BUF_WORDS); Collect_Simple_Words(block, modes); // Reset word markers: for (block = BLK_HEAD(BUF_WORDS); NOT_END(block); block++) binds[VAL_WORD_CANON(block)] = 0; series = Copy_Series_Part(BUF_WORDS, start, SERIES_TAIL(BUF_WORDS)-start); RESET_TAIL(BUF_WORDS); // allow reuse CHECK_BIND_TABLE; return series; }
*/ REBSER *Merge_Frames(REBSER *parent1, REBSER *parent2) /* ** Create a child frame from two parent frames. Merge common fields. ** Values from the second parent take precedence. ** ** Deep copy and rebind the child. ** ***********************************************************************/ { REBSER *wrds; REBSER *child; REBVAL *words; REBVAL *value; REBCNT n; REBINT *binds = WORDS_HEAD(Bind_Table); // Merge parent1 and parent2 words. // Keep the binding table. Collect_Start(BIND_ALL); // Setup binding table and BUF_WORDS with parent1 words: if (parent1) Collect_Object(parent1); // Add parent2 words to binding table and BUF_WORDS: Collect_Words(BLK_SKIP(FRM_WORD_SERIES(parent2), 1), BIND_ALL); // Allocate child (now that we know the correct size): wrds = Copy_Series(BUF_WORDS); child = Make_Block(SERIES_TAIL(wrds)); value = Append_Value(child); VAL_SET(value, REB_FRAME); VAL_FRM_WORDS(value) = wrds; VAL_FRM_SPEC(value) = 0; // Copy parent1 values: COPY_VALUES(FRM_VALUES(parent1)+1, FRM_VALUES(child)+1, SERIES_TAIL(parent1)-1); // Copy parent2 values: words = FRM_WORDS(parent2)+1; value = FRM_VALUES(parent2)+1; for (; NOT_END(words); words++, value++) { // no need to search when the binding table is available n = binds[VAL_WORD_CANON(words)]; BLK_HEAD(child)[n] = *value; } // Terminate the child frame: SERIES_TAIL(child) = SERIES_TAIL(wrds); BLK_TERM(child); // Deep copy the child Copy_Deep_Values(child, 1, SERIES_TAIL(child), TS_CLONE); // Rebind the child Rebind_Block(parent1, child, BLK_SKIP(child, 1), REBIND_FUNC); Rebind_Block(parent2, child, BLK_SKIP(child, 1), REBIND_FUNC | REBIND_TABLE); // release the bind table Collect_End(wrds); return child; }
*/ static REBFLG Get_Struct_Var(REBSTU *stu, REBVAL *word, REBVAL *val) /* ***********************************************************************/ { struct Struct_Field *field = NULL; REBCNT i = 0; field = (struct Struct_Field *)SERIES_DATA(stu->fields); for (i = 0; i < SERIES_TAIL(stu->fields); i ++, field ++) { if (VAL_WORD_CANON(word) == VAL_SYM_CANON(BLK_SKIP(PG_Word_Table.series, field->sym))) { if (field->array) { REBSER *ser = Make_Array(field->dimension); REBCNT n = 0; for (n = 0; n < field->dimension; n ++) { REBVAL elem; get_scalar(stu, field, n, &elem); Append_Value(ser, &elem); } Val_Init_Block(val, ser); } else { get_scalar(stu, field, 0, val); } return TRUE; } } return FALSE; }
// // Resolve_Path: C // // Given a path, determine if it is ultimately specifying a selection out // of a context...and if it is, return that context. So `a/obj/key` would // return the object assocated with obj, while `a/str/1` would return // NULL if `str` were a string as it's not an object selection. // // !!! This routine overlaps the logic of Do_Path, and should potentially // be a mode of that instead. It is not very complete, considering that it // does not execute GROUP! (and perhaps shouldn't?) and only supports a // path that picks contexts out of other contexts, via word selection. // REBCTX *Resolve_Path(const REBVAL *path, REBCNT *index_out) { RELVAL *selector; const REBVAL *var; REBARR *array; REBCNT i; array = VAL_ARRAY(path); selector = ARR_HEAD(array); if (IS_END(selector) || !ANY_WORD(selector)) return NULL; // !!! only handles heads of paths that are ANY-WORD! var = GET_OPT_VAR_MAY_FAIL(selector, VAL_SPECIFIER(path)); ++selector; if (IS_END(selector)) return NULL; // !!! does not handle single-element paths while (ANY_CONTEXT(var) && IS_WORD(selector)) { i = Find_Canon_In_Context( VAL_CONTEXT(var), VAL_WORD_CANON(selector), FALSE ); ++selector; if (IS_END(selector)) { *index_out = i; return VAL_CONTEXT(var); } var = CTX_VAR(VAL_CONTEXT(var), i); } DEAD_END; }
*/ void Collect_Words(REBVAL *block, REBFLG modes) /* ** The inner recursive loop used for Collect_Words function below. ** ***********************************************************************/ { REBINT *binds = WORDS_HEAD(Bind_Table); REBVAL *word; REBVAL *value; for (; NOT_END(block); block++) { value = block; //if (modes & BIND_GET && IS_GET_WORD(block)) value = Get_Var(block); if (ANY_WORD(value)) { if (!binds[VAL_WORD_CANON(value)]) { // only once per word if (IS_SET_WORD(value) || modes & BIND_ALL) { binds[VAL_WORD_CANON(value)] = SERIES_TAIL(BUF_WORDS); EXPAND_SERIES_TAIL(BUF_WORDS, 1); word = BLK_LAST(BUF_WORDS); VAL_SET(word, VAL_TYPE(value)); VAL_SET_OPT(word, OPTS_UNWORD); VAL_BIND_SYM(word) = VAL_WORD_SYM(value); // Allow all datatypes (to start): VAL_BIND_TYPESET(word) = ~((TYPESET(REB_END) | TYPESET(REB_UNSET))); // not END or UNSET } } else { // If word duplicated: if (modes & BIND_NO_DUP) { // Reset binding table (note BUF_WORDS may have expanded): for (word = BLK_HEAD(BUF_WORDS); NOT_END(word); word++) binds[VAL_WORD_CANON(word)] = 0; RESET_TAIL(BUF_WORDS); // allow reuse Trap1(RE_DUP_VARS, value); } } continue; } // Recurse into sub-blocks: if (ANY_EVAL_BLOCK(value) && (modes & BIND_DEEP)) Collect_Words(VAL_BLK_DATA(value), modes); // In this mode (foreach native), do not allow non-words: //else if (modes & BIND_GET) Trap_Arg(value); } BLK_TERM(BUF_WORDS); }
*/ static void Bind_Values_Inner_Loop(REBINT *binds, REBVAL value[], REBSER *frame, REBCNT mode) /* ** Bind_Values_Core() sets up the binding table and then calls ** this recursive routine to do the actual binding. ** ***********************************************************************/ { REBFLG selfish = !IS_SELFLESS(frame); for (; NOT_END(value); value++) { if (ANY_WORD(value)) { //Print("Word: %s", Get_Sym_Name(VAL_WORD_CANON(value))); // Is the word found in this frame? REBCNT n = binds[VAL_WORD_CANON(value)]; if (n != 0) { if (n == NO_RESULT) n = 0; // SELF word assert(n < SERIES_TAIL(frame)); // Word is in frame, bind it: VAL_WORD_INDEX(value) = n; VAL_WORD_FRAME(value) = frame; } else if (selfish && VAL_WORD_CANON(value) == SYM_SELF) { VAL_WORD_INDEX(value) = 0; VAL_WORD_FRAME(value) = frame; } else { // Word is not in frame. Add it if option is specified: if ((mode & BIND_ALL) || ((mode & BIND_SET) && (IS_SET_WORD(value)))) { Expand_Frame(frame, 1, 1); Append_Frame(frame, value, 0); binds[VAL_WORD_CANON(value)] = VAL_WORD_INDEX(value); } } } else if (ANY_BLOCK(value) && (mode & BIND_DEEP)) Bind_Values_Inner_Loop( binds, VAL_BLK_DATA(value), frame, mode ); else if ((IS_FUNCTION(value) || IS_CLOSURE(value)) && (mode & BIND_FUNC)) Bind_Values_Inner_Loop( binds, BLK_HEAD(VAL_FUNC_BODY(value)), frame, mode ); } }
*/ static void Collect_Frame_Inner_Loop(REBINT *binds, REBVAL value[], REBCNT modes) /* ** The inner recursive loop used for Collect_Frame function below. ** ***********************************************************************/ { for (; NOT_END(value); value++) { if (ANY_WORD(value)) { if (!binds[VAL_WORD_CANON(value)]) { // only once per word if (IS_SET_WORD(value) || modes & BIND_ALL) { REBVAL *word; binds[VAL_WORD_CANON(value)] = SERIES_TAIL(BUF_WORDS); EXPAND_SERIES_TAIL(BUF_WORDS, 1); word = BLK_LAST(BUF_WORDS); Val_Init_Word_Typed( word, VAL_TYPE(value), VAL_WORD_SYM(value), // Allow all datatypes but END or UNSET (initially): ~((TYPESET(REB_END) | TYPESET(REB_UNSET))) ); } } else { // If word duplicated: if (modes & BIND_NO_DUP) { // Reset binding table (note BUF_WORDS may have expanded): REBVAL *word; for (word = BLK_HEAD(BUF_WORDS); NOT_END(word); word++) binds[VAL_WORD_CANON(word)] = 0; RESET_TAIL(BUF_WORDS); // allow reuse raise Error_1(RE_DUP_VARS, value); } } continue; } // Recurse into sub-blocks: if (ANY_EVAL_BLOCK(value) && (modes & BIND_DEEP)) Collect_Frame_Inner_Loop(binds, VAL_BLK_DATA(value), modes); // In this mode (foreach native), do not allow non-words: //else if (modes & BIND_GET) raise Error_Invalid_Arg(value); } BLK_TERM(BUF_WORDS); }
*/ REBINT Compare_Word(REBVAL *s, REBVAL *t, REBFLG is_case) /* ** Compare the names of two words and return the difference. ** Note that words are kept UTF8 encoded. ** Positive result if s > t and negative if s < t. ** ***********************************************************************/ { REBYTE *sp = VAL_WORD_NAME(s); REBYTE *tp = VAL_WORD_NAME(t); // Use a more strict comparison than normal: if (is_case) return CMP_BYTES(sp, tp); // They are the equivalent words: if (VAL_WORD_CANON(s) == VAL_WORD_CANON(t)) return 0; // They must be differ by case: return Compare_UTF8(sp, tp, LEN_BYTES(tp)) + 2; }
*/ static REBCNT Get_Mode_Id(REBVAL *word) /* ***********************************************************************/ { REBCNT id = 0; if (IS_WORD(word)) { id = Find_Int(&Mode_Syms[0], VAL_WORD_CANON(word)); if (id == NOT_FOUND) Trap_Arg_DEAD_END(word); } return id; }
// // CT_Word: C // REBINT CT_Word(REBVAL *a, REBVAL *b, REBINT mode) { REBINT e; REBINT diff; if (mode >= 0) { e = VAL_WORD_CANON(a) == VAL_WORD_CANON(b); if (mode == 1) e &= VAL_WORD_INDEX(a) == VAL_WORD_INDEX(b) && VAL_WORD_FRAME(a) == VAL_WORD_FRAME(b); else if (mode >= 2) { e = (VAL_WORD_SYM(a) == VAL_WORD_SYM(b) && VAL_WORD_INDEX(a) == VAL_WORD_INDEX(b) && VAL_WORD_FRAME(a) == VAL_WORD_FRAME(b)); } } else { diff = Compare_Word(a, b, FALSE); if (mode == -1) e = diff >= 0; else e = diff > 0; } return e; }
*/ REBFLG MT_Datatype(REBVAL *out, REBVAL *data, REBCNT type) /* ***********************************************************************/ { if (!IS_WORD(data)) return FALSE; type = VAL_WORD_CANON(data); if (type > REB_MAX) return FALSE; VAL_SET(out, REB_DATATYPE); VAL_DATATYPE(out) = type-1; VAL_TYPE_SPEC(out) = 0; return TRUE; }
*/ static void Collect_Words_Inner_Loop(REBINT *binds, REBVAL value[], REBCNT modes) /* ** Used for Collect_Words() after the binds table has ** been set up. ** ***********************************************************************/ { for (; NOT_END(value); value++) { if (ANY_WORD(value) && !binds[VAL_WORD_CANON(value)] && (modes & BIND_ALL || IS_SET_WORD(value)) ) { REBVAL *word; binds[VAL_WORD_CANON(value)] = 1; word = Alloc_Tail_Array(BUF_WORDS); Val_Init_Word_Unbound(word, REB_WORD, VAL_WORD_SYM(value)); } else if (ANY_EVAL_BLOCK(value) && (modes & BIND_DEEP)) Collect_Words_Inner_Loop(binds, VAL_BLK_DATA(value), modes); } }
// // 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 } } }
*/ void Collect_Simple_Words(REBVAL *block, REBCNT modes) /* ** Used for Collect_Block_Words(). ** ***********************************************************************/ { REBINT *binds = WORDS_HEAD(Bind_Table); // GC safe to do here REBVAL *val; for (; NOT_END(block); block++) { if (ANY_WORD(block) && !binds[VAL_WORD_CANON(block)] && (modes & BIND_ALL || IS_SET_WORD(block)) ) { binds[VAL_WORD_CANON(block)] = 1; val = Append_Value(BUF_WORDS); Init_Word(val, VAL_WORD_SYM(block)); } else if (ANY_EVAL_BLOCK(block) && (modes & BIND_DEEP)) Collect_Simple_Words(VAL_BLK_DATA(block), modes); } }
*/ static void Set_Gob_Flag(REBGOB *gob, REBVAL *word) /* ***********************************************************************/ { REBINT i; for (i = 0; Gob_Flag_Words[i]; i += 2) { if (VAL_WORD_CANON(word) == Gob_Flag_Words[i]) { SET_GOB_FLAG(gob, Gob_Flag_Words[i+1]); break; } } }
// // 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; }
*/ void Collect_Object(REBSER *prior) /* ** Collect words from a prior object. ** ***********************************************************************/ { REBVAL *words; REBINT *binds = WORDS_HEAD(Bind_Table); // GC safe to do here REBINT n; words = FRM_WORDS(prior); COPY_VALUES(words, BLK_HEAD(BUF_WORDS), SERIES_TAIL(prior)); SERIES_TAIL(BUF_WORDS) = SERIES_TAIL(prior); for (n = 1, words++; NOT_END(words); words++) // skips first = SELF binds[VAL_WORD_CANON(words)] = n++; }
*/ REBCNT Find_Word(REBSER *series, REBCNT index, REBCNT sym) /* ** Find word (of any type) in a block... quickly. ** ***********************************************************************/ { REBVAL *value; for (; index < SERIES_TAIL(series); index++) { value = BLK_SKIP(series, index); if (ANY_WORD(value) && sym == VAL_WORD_CANON(value)) return index; } return NOT_FOUND; }
*/ static REBVAL *Eval_Arg(REBDIA *dia) /* ** Handle all values passed in a dialect. ** ** Contexts can be used for finding a word in a block of ** contexts without using a path. ** ** Returns zero on error. ** Note: stack used to hold temp values ** ***********************************************************************/ { REBVAL *value = BLK_SKIP(dia->args, dia->argi); switch (VAL_TYPE(value)) { case REB_WORD: // Only look it up if not part of dialect: if (Find_Command(dia->dialect, value) == 0) { REBVAL *val = value; // save if (dia->contexts) { value = Find_In_Contexts(VAL_WORD_CANON(value), dia->contexts); if (value) break; } value = Get_Var_No_Trap(val); // may return zero } break; case REB_PATH: if (Do_Path(&value, 0)) return 0; value = DS_TOP; break; case REB_LIT_WORD: DS_PUSH(value); value = DS_TOP; VAL_SET(value, REB_WORD); break; case REB_PAREN: value = DO_BLK(value); DS_SKIP; // do not overwrite TOS break; } return value; }
// // RL_Map_Words: C // // Given a block of word values, return an array of word ids. // // Returns: // An array of global word identifiers (integers). The [0] value is the size. // Arguments: // series - block of words as values (from REBOL blocks, not strings.) // Notes: // Word identifiers are persistent, and you can use them anytime. // The block can include any kind of word, including set-words, lit-words, etc. // If the input block contains non-words, they will be skipped. // The array is allocated with OS_ALLOC and you can OS_FREE it any time. // RL_API u32 *RL_Map_Words(REBARR *array) { REBCNT i = 1; u32 *words; REBVAL *val = ARR_HEAD(array); words = OS_ALLOC_N(u32, ARR_LEN(array) + 2); for (; NOT_END(val); val++) { if (ANY_WORD(val)) words[i++] = VAL_WORD_CANON(val); } words[0] = i; words[i] = 0; return words; }