*/ void Change_Case(REBVAL *out, REBVAL *val, REBVAL *part, REBOOL upper) /* ** Common code for string case handling. ** ***********************************************************************/ { REBCNT len; REBCNT n; *out = *val; if (IS_CHAR(val)) { REBUNI c = VAL_CHAR(val); if (c < UNICODE_CASES) { c = upper ? UP_CASE(c) : LO_CASE(c); } VAL_CHAR(out) = c; return; } // String series: if (IS_PROTECT_SERIES(VAL_SERIES(val))) raise Error_0(RE_PROTECTED); len = Partial(val, 0, part, 0); n = VAL_INDEX(val); len += n; if (VAL_BYTE_SIZE(val)) { REBYTE *bp = VAL_BIN(val); if (upper) for (; n < len; n++) bp[n] = (REBYTE)UP_CASE(bp[n]); else { for (; n < len; n++) bp[n] = (REBYTE)LO_CASE(bp[n]); } } else { REBUNI *up = VAL_UNI(val); if (upper) { for (; n < len; n++) { if (up[n] < UNICODE_CASES) up[n] = UP_CASE(up[n]); } } else { for (; n < len; n++) { if (up[n] < UNICODE_CASES) up[n] = LO_CASE(up[n]); } } } }
*/ void Pop_Stack_Values(REBVAL *out, REBINT dsp_start, REBOOL into) /* ** Pop_Stack_Values computed values from the stack into the series ** specified by "into", or if into is NULL then store it as a ** block on top of the stack. (Also checks to see if into ** is protected, and will trigger a trap if that is the case.) ** ** Protocol for /INTO is to set the position to the tail. ** ***********************************************************************/ { REBSER *series; REBCNT len = DSP - dsp_start; REBVAL *values = BLK_SKIP(DS_Series, dsp_start + 1); if (into) { assert(ANY_BLOCK(out)); series = VAL_SERIES(out); if (IS_PROTECT_SERIES(series)) Trap(RE_PROTECTED); VAL_INDEX(out) = Insert_Series( series, VAL_INDEX(out), cast(REBYTE*, values), len ); } else {
*/ void Resolve_Context(REBSER *target, REBSER *source, REBVAL *only_words, REBFLG all, REBFLG expand) /* ** Only_words can be a block of words or an index in the target ** (for new words). ** ***********************************************************************/ { REBINT *binds = WORDS_HEAD(Bind_Table); // GC safe to do here REBVAL *words; REBVAL *vals; REBINT n; REBINT m; REBCNT i = 0; CHECK_BIND_TABLE; if (IS_PROTECT_SERIES(target)) Trap0(RE_PROTECTED); if (IS_INTEGER(only_words)) { // Must be: 0 < i <= tail i = VAL_INT32(only_words); // never <= 0 if (i == 0) i = 1; if (i >= target->tail) return; } Collect_Start(BIND_NO_SELF); // DO NOT TRAP IN THIS SECTION n = 0; // If limited resolve, tag the word ids that need to be copied: if (i) { // Only the new words of the target: for (words = FRM_WORD(target, i); NOT_END(words); words++) binds[VAL_BIND_CANON(words)] = -1; n = SERIES_TAIL(target) - 1; } else if (IS_BLOCK(only_words)) { // Limit exports to only these words: for (words = VAL_BLK_DATA(only_words); NOT_END(words); words++) { if (IS_WORD(words) || IS_SET_WORD(words)) { binds[VAL_WORD_CANON(words)] = -1; n++; } } } // Expand target as needed: if (expand && n > 0) { // Determine how many new words to add: for (words = FRM_WORD(target, 1); NOT_END(words); words++) if (binds[VAL_BIND_CANON(words)]) n--; // Expand frame by the amount required: if (n > 0) Expand_Frame(target, n, 0); else expand = 0; } // Maps a word to its value index in the source context. // Done by marking all source words (in bind table): words = FRM_WORDS(source)+1; for (n = 1; NOT_END(words); n++, words++) { if (IS_NONE(only_words) || binds[VAL_BIND_CANON(words)]) binds[VAL_WORD_CANON(words)] = n; } // Foreach word in target, copy the correct value from source: n = i ? i : 1; vals = FRM_VALUE(target, n); for (words = FRM_WORD(target, n); NOT_END(words); words++, vals++) { if ((m = binds[VAL_BIND_CANON(words)])) { binds[VAL_BIND_CANON(words)] = 0; // mark it as set if (!VAL_PROTECTED(words) && (all || IS_UNSET(vals))) { if (m < 0) SET_UNSET(vals); // no value in source context else *vals = *FRM_VALUE(source, m); //Debug_Num("type:", VAL_TYPE(vals)); //Debug_Str(Get_Word_Name(words)); } } } // Add any new words and values: if (expand) { REBVAL *val; words = FRM_WORDS(source)+1; for (n = 1; NOT_END(words); n++, words++) { if (binds[VAL_BIND_CANON(words)]) { // Note: no protect check is needed here binds[VAL_BIND_CANON(words)] = 0; val = Append_Frame(target, 0, VAL_BIND_SYM(words)); *val = *FRM_VALUE(source, n); } } } else { // Reset bind table (do not use Collect_End): if (i) { for (words = FRM_WORD(target, i); NOT_END(words); words++) binds[VAL_BIND_CANON(words)] = 0; } else if (IS_BLOCK(only_words)) { for (words = VAL_BLK_DATA(only_words); NOT_END(words); words++) { if (IS_WORD(words) || IS_SET_WORD(words)) binds[VAL_WORD_CANON(words)] = 0; } } else { for (words = FRM_WORDS(source)+1; NOT_END(words); words++) binds[VAL_BIND_CANON(words)] = 0; } } CHECK_BIND_TABLE; RESET_TAIL(BUF_WORDS); // allow reuse, trapping ok now }