Exemplo n.º 1
0
xx*/	REBSER *Make_Func_Words(REBSER *spec)
/*
**		Make a word list part of a context block for a function spec.
**		This series is stored in the ARGS field of the function value.
**
***********************************************************************/
{
	REBVAL *word = BLK_HEAD(spec);
	REBSER *words;
	REBCNT n;
	REBCNT len = 0;

	// Count the number of words within the spec:
	for (n = 0; n < SERIES_TAIL(spec); n++) {
		if (ANY_WORD(word+n)) len++;
	}

	// Make the words table:
	words = Make_Words(len+1);

	// Skip 0th entry (because 0 is not valid for bind index).
	len = 1;
	WORDS_HEAD(words)[0] = 0;

	// Initialize the words in the new table.
	for (n = 0; n < SERIES_TAIL(spec); n++) {
		if (ANY_WORD(word+n)) WORDS_HEAD(words)[len++] = n;
	}
	SERIES_TAIL(words) = len;
	return words;
}
Exemplo n.º 2
0
*/  REBSER *Collect_Frame(REBSER *prior, REBVAL value[], REBCNT modes)
/*
**		Scans a block for words to use in the frame. The list of
**		words can then be used to create a frame. The Bind_Table is
**		used to quickly determine duplicate entries.
**
**		Returns:
**			A block of words that can be used for a frame word list.
**			If no new words, the prior list is returned.
**
**		Modes:
**			BIND_ALL  - scan all words, or just set words
**			BIND_DEEP - scan sub-blocks too
**			BIND_GET  - substitute :word with actual word
**			BIND_NO_SELF - do not add implicit SELF to the frame
**
***********************************************************************/
{
	Collect_Start(modes);

	// Setup binding table with existing words:
	if (prior) Collect_Object(prior);

	// Scan for words, adding them to BUF_WORDS and bind table:
	Collect_Frame_Inner_Loop(WORDS_HEAD(Bind_Table), &value[0], modes);

	return Collect_End(prior);
}
Exemplo n.º 3
0
*/  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;
}
Exemplo n.º 4
0
*/  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;
}
Exemplo n.º 5
0
*/  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_ARGS(func)
**		frame: VAL_FUNC_ARGS(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_Words(frame, block);

	// Reset binding table:
	for (args = BLK_SKIP(words, 1); NOT_END(args); args++)
		binds[VAL_BIND_CANON(args)] = 0;
}
Exemplo n.º 6
0
*/  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;
}
Exemplo n.º 7
0
*/  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));
	}
}
Exemplo n.º 8
0
*/  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;
}
Exemplo n.º 9
0
void Dump_Func_Words(REBSER *words)
{
	REBINT n;

	for (n = 0; n < (REBINT)SERIES_TAIL(words); n++) {
		Debug_Fmt("%d: %d", n, WORDS_HEAD(words)[n]);
	}
}
Exemplo n.º 10
0
xx*/	void Dump_Bind_Table()
/*
***********************************************************************/
{
	REBCNT	n;
	REBINT *binds = WORDS_HEAD(Bind_Table);

	Debug_Fmt("Bind Table (Size: %d)", SERIES_TAIL(Bind_Table));
	for (n = 1; n < SERIES_TAIL(Bind_Table); n++) {
		if (binds[n])
			Debug_Fmt("Bind: %3d to %3d (%s)", n, binds[n], Get_Sym_Name(n));
	}
}
Exemplo n.º 11
0
*/	void Check_Bind_Table()
/*
***********************************************************************/
{
	REBCNT	n;
	REBINT *binds = WORDS_HEAD(Bind_Table);

	//Debug_Fmt("Bind Table (Size: %d)", SERIES_TAIL(Bind_Table));
	for (n = 0; n < SERIES_TAIL(Bind_Table); n++) {
		if (binds[n]) {
			Debug_Fmt("Bind table fault: %3d to %3d (%s)", n, binds[n], Get_Sym_Name(n));
		}
	}
}
Exemplo n.º 12
0
*/  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);
	}
}
Exemplo n.º 13
0
*/  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++;
}
Exemplo n.º 14
0
*/  void Bind_Values_Core(REBVAL value[], REBSER *frame, REBCNT mode)
/*
**		Bind words in an array of values terminated with REB_END
**		to a specified frame.  See warnings on the functions like
**		Bind_Values_Deep() about not passing just a singular REBVAL.
**
**		Different modes may be applied:
**
**          BIND_ONLY - Only bind words found in the frame.
**          BIND_ALL  - Add words to the frame during the bind.
**          BIND_SET  - Add set-words to the frame during the bind.
**                      (note: word must not occur before the SET)
**          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
**		to say that forward references are not allowed.
**
***********************************************************************/
{
	REBVAL *words;
	REBCNT index;
	REBINT *binds = WORDS_HEAD(Bind_Table); // GC safe to do here

	CHECK_MEMORY(4);

	CHECK_BIND_TABLE;

	// Note about optimization: it's not a big win to avoid the
	// binding table for short blocks (size < 4), because testing
	// every block for the rare case adds up.

	// Setup binding table
	for (index = 1; index < frame->tail; index++) {
		words = FRM_WORD(frame, index);
		if (!VAL_GET_OPT(words, EXT_WORD_HIDE))
			binds[VAL_BIND_CANON(words)] = index;
	}

	Bind_Values_Inner_Loop(binds, &value[0], frame, mode);

	// Reset binding table:
	for (words = FRM_WORDS(frame) + 1; NOT_END(words); words++)
		binds[VAL_BIND_CANON(words)] = 0;

	CHECK_BIND_TABLE;
}
Exemplo n.º 15
0
*/ 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);
}
Exemplo n.º 16
0
*/  void Collect_Object(REBSER *prior)
/*
**		Collect words from a prior object.
**
***********************************************************************/
{
	REBVAL *words = FRM_WORDS(prior);
	REBINT *binds = WORDS_HEAD(Bind_Table);
	REBINT n;

	// this is necessary for COPY_VALUES below
	// to not overwrite memory BUF_WORDS does not own
	RESIZE_SERIES(BUF_WORDS, SERIES_TAIL(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++;
}
Exemplo n.º 17
0
*/  void Bind_Block(REBSER *frame, REBVAL *block, REBCNT mode)
/*
**      Bind the words of a block to a specified frame.
**      Different modes may be applied:
**          BIND_ONLY - Only bind words found in the frame.
**          BIND_ALL  - Add words to the frame during the bind.
**          BIND_SET  - Add set-words to the frame during the bind.
**                      (note: word must not occur before the SET)
**          BIND_DEEP - Recurse into sub-blocks.
**
***********************************************************************/
{
	REBVAL *words;
	REBCNT index;
	REBINT *binds = WORDS_HEAD(Bind_Table); // GC safe to do here

	CHECK_MEMORY(4);

	CHECK_BIND_TABLE;

//	for (index = 0; index < Bind_Table->tail; index++)
//		if (binds[index] != 0) Crash(1333);

	// Note about optimization: it's not a big win to avoid the
	// binding table for short blocks (size < 4), because testing
	// every block for the rare case adds up.

	// Setup binding table:
	index = 1;
	for (index = 1; index < frame->tail; index++) {
		words = FRM_WORD(frame, index);
		if (!VAL_GET_OPT(words, OPTS_HIDE))
			binds[VAL_BIND_CANON(words)] = index;
	}

	Bind_Block_Words(frame, block, mode);

	// Reset binding table:
	for (words = FRM_WORDS(frame)+1; NOT_END(words); words++)
		binds[VAL_BIND_CANON(words)] = 0;
}
Exemplo n.º 18
0
*/  void Collect_Object(REBSER *prior)
/*
**		Collect words from a prior object.
**
***********************************************************************/
{
	REBVAL *words = FRM_WORDS(prior);
	REBINT *binds = WORDS_HEAD(Bind_Table);
	REBINT n;

	// this is necessary for memcpy below to not overwrite memory
	// BUF_WORDS does not own
	RESIZE_SERIES(BUF_WORDS, SERIES_TAIL(prior));

	// Word values can be copied just as bits (these are EXT_WORD_TYPED)
	memcpy(BLK_HEAD(BUF_WORDS), words, SERIES_TAIL(prior) * sizeof(REBVAL));

	SERIES_TAIL(BUF_WORDS) = SERIES_TAIL(prior);
	for (n = 1, words++; NOT_END(words); words++) // skips first = SELF
		binds[VAL_WORD_CANON(words)] = n++;
}
Exemplo n.º 19
0
*/  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);
	}
}
Exemplo n.º 20
0
*/  void Rebind_Block(REBSER *src_frame, REBSER *dst_frame, REBVAL *data, REBFLG modes)
/*
**      Rebind all words that reference src frame to dst frame.
**      Rebind is always deep.
**
**		There are two types of frames: relative frames and normal frames.
**		When frame_src type and frame_dst type differ,
**		modes must have REBIND_TYPE.
**
***********************************************************************/
{
	REBINT *binds = WORDS_HEAD(Bind_Table);

	for (; NOT_END(data); data++) {
		if (ANY_BLOCK(data))
			Rebind_Block(src_frame, dst_frame, VAL_BLK_DATA(data), modes);
		else if (ANY_WORD(data) && VAL_WORD_FRAME(data) == src_frame) {
			VAL_WORD_FRAME(data) = dst_frame;
			if (modes & REBIND_TABLE) VAL_WORD_INDEX(data) = binds[VAL_WORD_CANON(data)];
			if (modes & REBIND_TYPE) VAL_WORD_INDEX(data) = - VAL_WORD_INDEX(data);
		} else if ((modes & REBIND_FUNC) && (IS_FUNCTION(data) || IS_CLOSURE(data)))
			Rebind_Block(src_frame, dst_frame, BLK_HEAD(VAL_FUNC_BODY(data)), modes);
	}
}
Exemplo n.º 21
0
*/  void Collect_Start(REBCNT modes)
/*
**		Use the Bind_Table to start collecting new words for
**		a frame. Use Collect_End() when done.
**
**		WARNING: Do not call code that might call BIND or otherwise
**		make use of the Bind_Table or the Word cache array (BUF_WORDS).
**
***********************************************************************/
{
	REBINT *binds = WORDS_HEAD(Bind_Table); // GC safe to do here

	CHECK_BIND_TABLE;

	// Reuse a global word list block because length of block cannot
	// be known until all words are scanned. Then copy this block.
	if (SERIES_TAIL(BUF_WORDS)) Crash(RP_WORD_LIST); // still in use

	// Add the SELF word to slot zero.
	if ((modes = (modes & BIND_NO_SELF)?0:SYM_SELF))
		binds[modes] = -1;  // (cannot use zero here)
	Init_Frame_Word(BLK_HEAD(BUF_WORDS), modes);
	SERIES_TAIL(BUF_WORDS) = 1;
}
Exemplo n.º 22
0
Arquivo: t-object.c Projeto: Oldes/r3
static void Append_Obj(REBSER *obj, REBVAL *arg)
{
	REBCNT i, len;
	REBVAL *word, *val;
	REBINT *binds; // for binding table

	// Can be a word:
	if (ANY_WORD(arg)) {
		if (!Find_Word_Index(obj, VAL_WORD_SYM(arg), TRUE)) {
			// bug fix, 'self is protected only in selfish frames
			if ((VAL_WORD_CANON(arg) == SYM_SELF) && !IS_SELFLESS(obj))
				Trap0(RE_SELF_PROTECTED);
			Expand_Frame(obj, 1, 1); // copy word table also
			Append_Frame(obj, 0, VAL_WORD_SYM(arg));
			// val is UNSET
		}
		return;
	}

	if (!IS_BLOCK(arg)) Trap_Arg(arg);

	// Process word/value argument block:
	arg = VAL_BLK_DATA(arg);

	// Use binding table
	binds = WORDS_HEAD(Bind_Table);
	// Handle selfless
	Collect_Start(IS_SELFLESS(obj) ? BIND_NO_SELF | BIND_ALL : BIND_ALL);
	// Setup binding table with obj words:
	Collect_Object(obj);

	// Examine word/value argument block
	for (word = arg; NOT_END(word); word += 2) {

		if (!IS_WORD(word) && !IS_SET_WORD(word)) {
			// release binding table
			BLK_TERM(BUF_WORDS);
			Collect_End(obj);
			Trap_Arg(word);
		}

		if (NZ(i = binds[VAL_WORD_CANON(word)])) {
			// bug fix, 'self is protected only in selfish frames:
			if ((VAL_WORD_CANON(word) == SYM_SELF) && !IS_SELFLESS(obj)) {
				// release binding table
				BLK_TERM(BUF_WORDS);
				Collect_End(obj);
				Trap0(RE_SELF_PROTECTED);
			}
		} else {
			// collect the word
			binds[VAL_WORD_CANON(word)] = SERIES_TAIL(BUF_WORDS);
			EXPAND_SERIES_TAIL(BUF_WORDS, 1);
			val = BLK_LAST(BUF_WORDS);
			*val = *word;
		}
		if (IS_END(word + 1)) break; // fix bug#708
	}

	BLK_TERM(BUF_WORDS);

	// Append new words to obj
	len = SERIES_TAIL(obj);
	Expand_Frame(obj, SERIES_TAIL(BUF_WORDS) - len, 1);
	for (word = BLK_SKIP(BUF_WORDS, len); NOT_END(word); word++)
		Append_Frame(obj, 0, VAL_WORD_SYM(word));

	// Set new values to obj words
	for (word = arg; NOT_END(word); word += 2) {

		i = binds[VAL_WORD_CANON(word)];
		val = FRM_VALUE(obj, i);
		if (GET_FLAGS(VAL_OPTS(FRM_WORD(obj, i)), OPTS_HIDE, OPTS_LOCK)) { 
			// release binding table
			Collect_End(obj);
			if (VAL_PROTECTED(FRM_WORD(obj, i)))
				Trap1(RE_LOCKED_WORD, FRM_WORD(obj, i));
			Trap0(RE_HIDDEN);
		}

		if (IS_END(word + 1)) SET_NONE(val);
		else *val = word[1];

		if (IS_END(word + 1)) break; // fix bug#708
	}

	// release binding table
	Collect_End(obj);
}
Exemplo n.º 23
0
*/	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
}