// Parse the loop block and ignore its result
int Compiler::ParseOptimizeBlock(int arguments)
{
	if (!ThisTokenIsBinary('['))
	{
		CompileError(CErrExpectLiteralBlock);
		return 0;
	}

	int nTextStart = ThisTokenRange().m_start;

	_ASSERTE(IsInOptimizedBlock());

	// Parse the arguments - note we parse them anyway, regardless of whether they are wanted, 
	// and subsequently complain if there are too many
	NextToken();
	int argument = 0;
	while (m_ok && ThisTokenIsSpecial(':') )
	{
		if (NextToken()==NameConst)
		{
			if (argument < arguments)
				RenameTemporary(argument, ThisTokenText(), ThisTokenRange());
			else
				AddTemporary(ThisTokenText(), ThisTokenRange(), true);
			argument++;
			NextToken();
		}
		else
			CompileError(CErrExpectVariable);
	}

	int argBar = -1;
	if (m_ok && argument > 0)
	{
		if (ThisTokenIsBinary(TEMPSDELIMITER))
		{
			argBar = ThisTokenRange().m_stop;
			NextToken();
		}
		else
			m_ok = false;
	}

	int nBlockTemps = 0;
	if (m_ok)
	{
		// Temporarily commented out for interim release
		ParseTemporaries();
		
		ParseBlockStatements();
		if (m_ok && ThisToken() != CloseSquare)
			CompileError(TEXTRANGE(nTextStart, LastTokenRange().m_stop), CErrBlockNotClosed);
	}
	
	if (m_ok && argument != arguments)
		CompileError(TEXTRANGE(nTextStart, argBar < 0 ? ThisTokenRange().m_stop : argBar), CErrIncorrectBlockArgCount);

	return nBlockTemps;
}
void Compiler::ParseToByNumberDo(int toPointer, Oop oopNumber, bool bNegativeStep)
{
	PushOptimizedScope();
	
	// Add an "each". This should be at the top of the temporary stack as it is taken over by the do: block
	TempVarRef* pEachTempRef = AddOptimizedTemp(eachTempName);
	
	// Start to generate bytecodes

	// First we must store that from value into our 'each' counter variable/argument. This involves
	// stepping back a bit ...
	_ASSERTE(toPointer < m_codePointer);
	int currentPos = m_codePointer;
	m_codePointer = toPointer;
	// Note we store so leaving the value on the stack as the result of the whole expression
	GenStoreTemp(pEachTempRef);
	m_codePointer = currentPos + m_bytecodes[toPointer].instructionLength();
	
	// Dup the to: value
	GenDup();
	// And push the from value
	GenPushTemp(pEachTempRef);

	// We must jump over the block to the test first time through
	int jumpOver = GenJumpInstruction(LongJump);

	int loopHead = m_codePointer;

	// Parse the one argument block.
	// Leave nothing on the stack, expect 1 argument
	ParseOptimizeBlock(1);

	// Pop off the result of the optimized block
	GenPopStack();
	
	GenDup();
	GenPushTemp(pEachTempRef);
	// If the step is 1/-1, this will be optimised down to Increment/Decrement
	GenNumber(oopNumber, LastTokenRange());
	int add = GenInstruction(SendArithmeticAdd);
	int store = GenStoreTemp(pEachTempRef);

	int comparePointer = m_codePointer;
	
	if (bNegativeStep)
		GenInstruction(SendArithmeticGT);
	else
		// Note that < is the best message to send, since it is normally directly implemented
		GenInstruction(SendArithmeticLT);

	GenJump(LongJumpIfFalse, loopHead);

	// Pop the to: value
	GenPopStack();

	SetJumpTarget(jumpOver, comparePointer);

	TODO("Is this in the right place? What is the last real IP of the loop");
	PopOptimizedScope(ThisTokenRange().m_stop);
	NextToken();
}
bool Compiler::ParseIfNotNil(const TEXTRANGE& messageRange, int exprStartPos)
{
	if (!ThisTokenIsBinary('['))
	{
		Warning(CWarnExpectMonadicOrNiladicBlockArg, (Oop)InternSymbol("ifNotNil:"));
		return false;
	}

	int dupMark = GenDup();
	BreakPoint();
	const int sendIsNil = GenInstruction(SpecialSendIsNil);
	AddTextMap(sendIsNil, exprStartPos, LastTokenRange().m_stop);

	// We're going to add a pop and jump on condition instruction here
	// Its a forward jump, so we need to patch up the target later
	const int popAndJumpMark = GenJumpInstruction(LongJumpIfTrue);
	int argc = ParseIfNotNilBlock();

	// If the ifNotNil: block did not have any arguments, then we do not need the Dup, and we also
	// need to patch out the corresponding pop.
	if (!argc)
	{
		UngenInstruction(dupMark);
		UngenInstruction(popAndJumpMark + lengthOfByteCode(LongJumpIfTrue));
	}

	int ifNilMark;

	// Has an #ifNil: branch?
	if (strcmp(ThisTokenText(), "ifNil:") == 0)
	{
		POTE oteSelector = AddSymbolToFrame("ifNotNil:ifNil:", messageRange);

		// Generate the jump out instruction (forward jump, so target not yet known)
		int jumpOutMark = GenJumpInstruction(LongJump);

		// Mark first instruction of the "else" branch
		ifNilMark = m_codePointer;

		// ifNotNil:ifNil: form
		NextToken();

		ParseIfNilBlock(!argc);

		SetJumpTarget(jumpOutMark, GenNop());
	}
	else
	{
		// No "ifNil:" branch 

		POTE oteSelector = AddSymbolToFrame("ifNotNil:", messageRange);

		if (!argc)
		{
			// Since we've removed the Dup if the ifNotNil: block had no args, we need to ensure there is nil atop the stack
			// This should normally get optimized away later if the expression value is not used.

			// Generate the jump out instruction
			int jumpOutMark = GenJumpInstruction(LongJump);

			ifNilMark = GenInstruction(ShortPushNil);

			SetJumpTarget(jumpOutMark, GenNop());
		}
		else
		{
			ifNilMark = GenNop();
		}
	}
	
	SetJumpTarget(popAndJumpMark, ifNilMark);
	
	return true;
}
bool Compiler::ParseIfNil(const TEXTRANGE& messageRange, int exprStartPos)
{
	if (!ThisTokenIsBinary('['))
	{
		Warning(CWarnExpectNiladicBlockArg, (Oop)InternSymbol("ifNil:"));
		return false;
	}

	int dupMark = GenDup();

	BreakPoint();
	const int sendIsNil = GenInstruction(SpecialSendIsNil);
	const int mapEntry = AddTextMap(sendIsNil, exprStartPos, LastTokenRange().m_stop);

	// We're going to add a pop and jump on condition instruction here
	// Its a forward jump, so we need to patch up the target later
	const int popAndJumpMark = GenJumpInstruction(LongJumpIfFalse);

	ParseIfNilBlock(false);
	
	int ifNotNilMark;

	if (strcmp(ThisTokenText(), "ifNotNil:") == 0)
	{
		POTE oteSelector = AddSymbolToFrame("ifNil:ifNotNil:", messageRange);

		// Generate the jump out instruction (forward jump, so target not yet known)
		int jumpOutMark = GenJumpInstruction(LongJump);

		// Mark first instruction of the "else" branch
		ifNotNilMark = m_codePointer;

		// #ifNil:ifNotNil: form
		NextToken();

		int argc = ParseIfNotNilBlock();

		// Be careful, may not actually be a literal block there
		if (m_ok)
		{
			// If the ifNotNil: block does not need an argument, we can patch out the Dup
			// and corresponding pop
			if (!argc)
			{
				UngenInstruction(dupMark);
				_ASSERTE(m_bytecodes[popAndJumpMark + lengthOfByteCode(LongJumpIfFalse)].byte == PopStackTop);
				UngenInstruction(popAndJumpMark + lengthOfByteCode(LongJumpIfFalse));
				_ASSERTE(m_bytecodes[ifNotNilMark].byte == PopStackTop);
				UngenInstruction(ifNotNilMark);
			}

			// Set unconditional jump at the end of the ifNil to jump over the "else" branch to a Nop
			SetJumpTarget(jumpOutMark, GenNop());
		}
	}
	else
	{
		POTE oteSelector = AddSymbolToFrame("ifNil:", messageRange);

		// No "else" branch, but we still need an instruction to jump to
		ifNotNilMark = GenNop();
	}

	if (m_ok)
	{
		// Conditional jump to the "else" branch (or the Nop if no else branch)
		SetJumpTarget(popAndJumpMark, ifNotNilMark);

		if (mapEntry >= 0)
			m_textMaps[mapEntry].stop = LastTokenRange().m_stop;
	}

	return true;
}
int Compiler::ParseIfNotNilBlock()
{
	if (!ThisTokenIsBinary('['))
	{
		CompileError(CErrExpectLiteralBlock);
		return 0;
	}

	PushOptimizedScope();

	// We now allow either zero or one arguments to the ifNotNil: block
	//ParseOptimizeBlock(1);

	int nTextStart = ThisTokenRange().m_start;

	_ASSERTE(IsInOptimizedBlock());

	// Generate the body code for an optimized block
	NextToken();
	int argc = 0;
	while (m_ok && ThisTokenIsSpecial(':'))
	{
		if (NextToken() == NameConst)
		{
			argc++;
			CheckTemporaryName(ThisTokenText(), ThisTokenRange(), true);
			if (m_ok)
			{
				TempVarRef* pValueTempRef = AddOptimizedTemp(ThisTokenText(), ThisTokenRange());
				GenPopAndStoreTemp(pValueTempRef);
			}
			NextToken();
		}
		else
			CompileError(CErrExpectVariable);
	}

	switch (argc)
	{
	case 0:
		// Zero arg block, we don't need the implicit arg so just discard it
		GenPopStack();
		break;

	case 1:
		m_ok = m_ok && ThisTokenIsBinary(TEMPSDELIMITER);
		NextToken();
		break;

	default:
		CompileError(TEXTRANGE(nTextStart, ThisTokenRange().m_stop), CErrTooManyIfNotNilBlockArgs);
		break;
	}
	
	int nBlockTemps = 0;
	if (m_ok)
	{
		// Temporarily commented out for interim release
		ParseTemporaries();
		
		ParseBlockStatements();
		if (m_ok && ThisToken() != CloseSquare)
			CompileError(TEXTRANGE(nTextStart, LastTokenRange().m_stop), CErrBlockNotClosed);
	}

	PopOptimizedScope(ThisTokenRange().m_stop);
	NextToken();

	return argc;
}