// 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; }