File indexing completed on 2024-12-01 06:36:20
0001 /* 0002 SPDX-FileCopyrightText: 2003-2006 Cies Breijs <cies AT kde DOT nl> 0003 0004 SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 0007 0008 // This file is originally written by Walter Scheppers, but almost 0009 // every aspect of it is slightly changed by Cies Breijs. 0010 0011 #include "executer.h" 0012 0013 #include <errno.h> 0014 #include <math.h> 0015 0016 #include <QRandomGenerator> 0017 #include <QTimer> // for wait 0018 #include <QDebug> 0019 0020 #include <KLocalizedString> 0021 #include <QtMath> 0022 0023 0024 void Executer::initialize(TreeNode* tree, ErrorList* _errorList) 0025 { 0026 rootNode = tree; 0027 newScope = rootNode; 0028 currentNode = rootNode; 0029 finished = !currentNode->hasChildren(); // set finished to false unless the tree is empty 0030 errorList = _errorList; 0031 0032 breaking = false; 0033 returning = false; 0034 waiting = false; 0035 returnValue = nullptr; 0036 0037 executeCurrent = false; 0038 0039 functionTable.clear(); 0040 globalVariableTable.clear(); 0041 0042 while (!functionStack.isEmpty()) { 0043 // In the ForTo loop, we can assign the globalVariableTable to an entry in the functionStack 0044 // we shouldn't delete this variableTable, so check for it. 0045 VariableTable* variableTable = functionStack.pop().variableTable; 0046 if(variableTable!=&globalVariableTable) 0047 delete variableTable; 0048 } 0049 } 0050 0051 0052 void Executer::execute() 0053 { 0054 //Do we have to do anything? 0055 if (finished || waiting) return; 0056 0057 if(executeCurrent) { 0058 // executeCurrent is used to make sure the currentNode will be executed 0059 // this way the tree will not be walked before the execution... 0060 executeCurrent = false; 0061 execute(currentNode); 0062 return; 0063 } 0064 0065 if(returning) { 0066 //We are returning from a function call 0067 0068 // Handle returning in the top-level (not inside a function) as 0069 // gracefully as possible. 0070 // See: https://bugs.kde.org/show_bug.cgi?id=300949 0071 if (functionStack.isEmpty()) { 0072 addError(i18n("Cannot return outside a function. "), *(currentNode->token()), 0); 0073 finished = true; 0074 return; 0075 } 0076 0077 // Take the last called function from the function stack 0078 CalledFunction calledFunction = functionStack.pop(); 0079 0080 // Delete the local variables of the called function 0081 delete calledFunction.variableTable; 0082 currentNode = calledFunction.function; 0083 0084 if (returnValue == nullptr) 0085 currentNode->setNullValue(); // Handle an empty return value 0086 else 0087 currentNode->setValue(returnValue); 0088 0089 execute(currentNode); 0090 return; 0091 } 0092 0093 if (newScope == nullptr) { 0094 TreeNode* currentParent = currentNode->parent(); 0095 currentNode = currentNode->nextSibling(); 0096 0097 if(currentNode == nullptr) { //running off sibling list 0098 currentNode = currentParent; 0099 0100 if(currentNode == rootNode) { 0101 finished = true; 0102 return; 0103 } 0104 0105 // printExe(); // debugging thing 0106 0107 execute(currentNode); 0108 return; 0109 } 0110 0111 }else{ 0112 // We're entering a new scope 0113 // skip ahead to frist child (if any) else we will not get into the scope 0114 if(newScope->hasChildren()) 0115 currentNode = newScope->firstChild(); 0116 else 0117 currentNode = newScope; 0118 0119 newScope = nullptr; 0120 } 0121 0122 0123 while (currentNode->hasChildren() && currentNode->token()->type() != Token::Scope) 0124 currentNode = currentNode->firstChild(); 0125 0126 // printExe(); // debugging thing 0127 0128 execute(currentNode); 0129 } 0130 0131 0132 void Executer::execute(TreeNode* node) 0133 { 0134 if (finished) return; 0135 0136 // Q_EMIT a signal for GUI 0137 Token* t = node->token(); 0138 // //qDebug() << "emitting token: '" << t->look() << "' - (" << t->startRow() << "," << t->startCol() << " - " << t->endRow() << "," << t->endCol() << ")"; 0139 0140 // don't report scopes (their are not really executed) 0141 if (t->type() != Token::Scope) 0142 Q_EMIT currentlyExecuting(node); 0143 0144 // this method executes one node at the time 0145 0146 // if (currentNode->token()->type() != Token::Scope) //qDebug() << "1234567890!!!!!"; 0147 0148 switch (node->token()->type()) { 0149 0150 //BEGIN GENERATED executer_switch_cpp CODE 0151 0152 /* The code between the line that start with "//BEGIN GENERATED" and "//END GENERATED" 0153 * is generated by "generate.rb" according to the definitions specified in 0154 * "definitions.rb". Please make all changes in the "definitions.rb" file, since all 0155 * all change you make here will be overwritten the next time "generate.rb" is run. 0156 * Thanks for looking at the code! 0157 */ 0158 0159 case Token::Root : executeRoot(node); break; 0160 case Token::Scope : executeScope(node); break; 0161 case Token::Variable : executeVariable(node); break; 0162 case Token::FunctionCall : executeFunctionCall(node); break; 0163 case Token::String : /* a constant; do nothing */ break; 0164 case Token::Number : /* a constant; do nothing */ break; 0165 case Token::True : /* a constant; do nothing */ break; 0166 case Token::False : /* a constant; do nothing */ break; 0167 case Token::Exit : executeExit(node); break; 0168 case Token::If : executeIf(node); break; 0169 case Token::Else : executeElse(node); break; 0170 case Token::Repeat : executeRepeat(node); break; 0171 case Token::While : executeWhile(node); break; 0172 case Token::For : executeFor(node); break; 0173 case Token::ForTo : executeForTo(node); break; 0174 case Token::Break : executeBreak(node); break; 0175 case Token::Return : executeReturn(node); break; 0176 case Token::Wait : executeWait(node); break; 0177 case Token::Assert : executeAssert(node); break; 0178 case Token::And : executeAnd(node); break; 0179 case Token::Or : executeOr(node); break; 0180 case Token::Not : executeNot(node); break; 0181 case Token::Equals : executeEquals(node); break; 0182 case Token::NotEquals : executeNotEquals(node); break; 0183 case Token::GreaterThan : executeGreaterThan(node); break; 0184 case Token::LessThan : executeLessThan(node); break; 0185 case Token::GreaterOrEquals : executeGreaterOrEquals(node); break; 0186 case Token::LessOrEquals : executeLessOrEquals(node); break; 0187 case Token::Addition : executeAddition(node); break; 0188 case Token::Subtraction : executeSubtraction(node); break; 0189 case Token::Multiplication : executeMultiplication(node); break; 0190 case Token::Division : executeDivision(node); break; 0191 case Token::Power : executePower(node); break; 0192 case Token::Assign : executeAssign(node); break; 0193 case Token::Learn : executeLearn(node); break; 0194 case Token::ArgumentList : executeArgumentList(node); break; 0195 case Token::Reset : executeReset(node); break; 0196 case Token::Clear : executeClear(node); break; 0197 case Token::Center : executeCenter(node); break; 0198 case Token::Go : executeGo(node); break; 0199 case Token::GoX : executeGoX(node); break; 0200 case Token::GoY : executeGoY(node); break; 0201 case Token::Forward : executeForward(node); break; 0202 case Token::Backward : executeBackward(node); break; 0203 case Token::Direction : executeDirection(node); break; 0204 case Token::TurnLeft : executeTurnLeft(node); break; 0205 case Token::TurnRight : executeTurnRight(node); break; 0206 case Token::PenWidth : executePenWidth(node); break; 0207 case Token::PenUp : executePenUp(node); break; 0208 case Token::PenDown : executePenDown(node); break; 0209 case Token::PenColor : executePenColor(node); break; 0210 case Token::CanvasColor : executeCanvasColor(node); break; 0211 case Token::CanvasSize : executeCanvasSize(node); break; 0212 case Token::SpriteShow : executeSpriteShow(node); break; 0213 case Token::SpriteHide : executeSpriteHide(node); break; 0214 case Token::Print : executePrint(node); break; 0215 case Token::FontSize : executeFontSize(node); break; 0216 case Token::Random : executeRandom(node); break; 0217 case Token::GetX : executeGetX(node); break; 0218 case Token::GetY : executeGetY(node); break; 0219 case Token::Message : executeMessage(node); break; 0220 case Token::Ask : executeAsk(node); break; 0221 case Token::Pi : executePi(node); break; 0222 case Token::Tan : executeTan(node); break; 0223 case Token::Sin : executeSin(node); break; 0224 case Token::Cos : executeCos(node); break; 0225 case Token::ArcTan : executeArcTan(node); break; 0226 case Token::ArcSin : executeArcSin(node); break; 0227 case Token::ArcCos : executeArcCos(node); break; 0228 case Token::Sqrt : executeSqrt(node); break; 0229 case Token::Round : executeRound(node); break; 0230 case Token::GetDirection : executeGetDirection(node); break; 0231 case Token::Mod : executeMod(node); break; 0232 0233 //END GENERATED executer_switch_cpp CODE 0234 0235 default: 0236 //qDebug() << "Unrecognized Token type (" << node->token()->type() << ", " << node->token()->look() << ") -- THIS SHOULDN'T HAPPEN!"; 0237 break; 0238 0239 } 0240 0241 } 0242 0243 0244 VariableTable* Executer::currentVariableTable() 0245 { 0246 if (functionStack.isEmpty()) 0247 return &globalVariableTable; 0248 else 0249 return functionStack.top().variableTable; 0250 } 0251 0252 0253 0254 0255 bool Executer::checkParameterQuantity(TreeNode* node, uint quantity, int errorCode) 0256 { 0257 // //qDebug() << "called"; 0258 uint nodeSize = node->childCount(); 0259 0260 if (quantity == 0) { 0261 if (nodeSize == 0) return true; // thats easy! 0262 addError(i18n("The %1 command accepts no parameters.", node->token()->look()), *node->token(), errorCode); 0263 return false; 0264 } 0265 0266 // // CHECK THIS OUT LATER 0267 // if (nodeSize != 0) // when all parameters are forgotten the parser puts a Unknown/tokEOL param, catch this: 0268 // if (node->firstChild()->getToken().type == tokEOL) nodeSize = 0; 0269 0270 if (nodeSize != quantity) { 0271 if (nodeSize < quantity) { 0272 addError(i18np("The %2 command was called with %3 but needs 1 parameter.", "The %2 command was called with %3 but needs %1 parameters.", quantity, node->token()->look(), nodeSize), *node->token(), errorCode); 0273 } else { 0274 addError(i18np("The %2 command was called with %3 but only accepts 1 parameter.", "The %2 command was called with %3 but only accepts %1 parameters.", quantity, node->token()->look(), nodeSize), *node->token(), errorCode); 0275 } 0276 return false; 0277 } 0278 return true; // if all tests passed 0279 } 0280 0281 0282 bool Executer::checkParameterType(TreeNode* node, int valueType, int errorCode) 0283 { 0284 // //qDebug() << "called"; 0285 uint quantity = node->childCount(); 0286 TreeNode* currentChild = node->firstChild(); 0287 while (currentChild != nullptr) { 0288 if (currentChild->value()->type() != valueType) { 0289 switch (valueType) { 0290 case Value::String: 0291 if (quantity == 1) 0292 addError(i18n("The %1 command only accepts a string as its parameter.", node->token()->look()), *node->token(), errorCode); 0293 else 0294 addError(i18n("The %1 command only accepts strings as its parameters.", node->token()->look()), *node->token(), errorCode); 0295 break; 0296 0297 case Value::Number: 0298 if (quantity == 1) 0299 addError(i18n("The %1 command only accepts a number as its parameter.", node->token()->look()), *node->token(), errorCode); 0300 else 0301 addError(i18n("The %1 command only accepts numbers as its parameters.", node->token()->look()), *node->token(), errorCode); 0302 break; 0303 0304 case Value::Bool: 0305 if (quantity == 1) 0306 addError(i18n("The %1 command only accepts an answer as its parameter.", node->token()->look()), *node->token(), errorCode); 0307 else 0308 addError(i18n("The %1 command only accepts answers as its parameters.", node->token()->look()), *node->token(), errorCode); 0309 break; 0310 } 0311 0312 return false; 0313 } 0314 0315 currentChild = node->nextChild(); 0316 } 0317 return true; // if all tests passed 0318 } 0319 0320 0321 void Executer::addError(const QString& s, const Token& t, int code) 0322 { 0323 // //qDebug() << qPrintable(s) << " (runtime error)"; 0324 errorList->addError(s, t, code); 0325 } 0326 0327 0328 0329 //BEGIN GENERATED executer_cpp CODE 0330 0331 /* The code between the line that start with "//BEGIN GENERATED" and "//END GENERATED" 0332 * is generated by "generate.rb" according to the definitions specified in 0333 * "definitions.rb". Please make all changes in the "definitions.rb" file, since all 0334 * all change you make here will be overwritten the next time "generate.rb" is run. 0335 * Thanks for looking at the code! 0336 */ 0337 0338 void Executer::executeRoot(TreeNode* node) { 0339 // //qDebug() << "called"; 0340 node = node; // stop the warnings // this is a stud 0341 } 0342 void Executer::executeScope(TreeNode* node) { 0343 // //qDebug() << "called"; 0344 // catch loops, they need to be managed... 0345 int parentTokenType = node->parent()->token()->type(); 0346 if (parentTokenType == Token::If || 0347 parentTokenType == Token::Repeat || 0348 parentTokenType == Token::While || 0349 // parentTokenType == Token::ForIn || 0350 parentTokenType == Token::ForTo) { 0351 currentNode = node->parent(); 0352 executeCurrent = true; 0353 return; 0354 } 0355 if(parentTokenType == Token::Learn) { 0356 //We have the end of a Learn, so we should return 0357 returning = true; 0358 returnValue = nullptr; 0359 return; 0360 } 0361 newScope = node; 0362 } 0363 void Executer::executeVariable(TreeNode* node) { 0364 // //qDebug() << "called"; 0365 bool aValueIsNeeded = true; 0366 // no need to look up when assigning (in a for loop statement) 0367 if ((node->parent()->token()->type() == Token::ForTo) && (node->parent()->child(0)==node)) 0368 return; 0369 // we need to executeVariables in assignments for things like $x=$y to work 0370 if (node->parent()->token()->type() == Token::Assign) { 0371 // Test if we are in the LHS of the assignment 0372 if (node == node->parent()->child(0)) { 0373 // In this case we do not need to be initialized, we will get a value in executeAssign 0374 aValueIsNeeded = false; 0375 } 0376 } 0377 if (!functionStack.isEmpty() && 0378 functionStack.top().variableTable->contains(node->token()->look())) { 0379 // //qDebug() << "exists locally"; 0380 node->setValue( (*functionStack.top().variableTable)[node->token()->look()] ); 0381 } else if (globalVariableTable.contains(node->token()->look())) { 0382 // //qDebug() << "exists globally"; 0383 node->setValue(globalVariableTable[node->token()->look()]); 0384 } else if (aValueIsNeeded) 0385 { 0386 addError(i18n("The variable '%1' was used without first being assigned to a value", node->token()->look()), *node->token(), 0); 0387 } 0388 } 0389 void Executer::executeFunctionCall(TreeNode* node) { 0390 // //qDebug() << "called"; 0391 if (node->parent()->token()->type() == Token::Learn) { // in case we're defining a function 0392 currentNode = node->parent(); 0393 executeCurrent = true; 0394 return; 0395 } 0396 0397 if (returning) { // if the function is already executed and returns now 0398 returnValue = nullptr; 0399 returning = false; 0400 // //qDebug() << "==> functionReturned!"; 0401 return; 0402 } 0403 0404 if (!functionTable.contains(node->token()->look())) { 0405 addError(i18n("An unknown function named '%1' was called", node->token()->look()), *node->token(), 0); 0406 return; 0407 } 0408 0409 CalledFunction c; 0410 c.function = node; 0411 c.variableTable = new VariableTable(); 0412 functionStack.push(c); 0413 // //qDebug() << "==> functionCalled!"; 0414 0415 TreeNode* learnNode = functionTable[node->token()->look()]; 0416 0417 // if the parameter numbers are not equal... 0418 if (node->childCount() != learnNode->child(1)->childCount()) { 0419 addError( 0420 i18n("The function '%1' was called with %2, while it should be called with %3", 0421 node->token()->look(), 0422 i18ncp("The function '%1' was called with %2, while it should be called with %3", "1 parameter", "%1 parameters", node->childCount()), 0423 i18ncp("The function '%1' was called with %2, while it should be called with %3", "1 parameter", "%1 parameters", learnNode->child(1)->childCount()) 0424 ), 0425 *node->token(), 0); 0426 return; 0427 } 0428 0429 for (uint i = 0; i < node->childCount(); i++) { 0430 functionStack.top().variableTable->insert(learnNode->child(1)->child(i)->token()->look(), node->child(i)->value()); 0431 // //qDebug() << "inserted variable " << learnNode->child(1)->child(i)->token()->look() << " on function stack"; 0432 } 0433 newScope = learnNode->child(2); 0434 } 0435 void Executer::executeExit(TreeNode* node) { 0436 // //qDebug() << "called"; 0437 node = node; // stop the warnings 0438 finished = true; 0439 } 0440 void Executer::executeIf(TreeNode* node) { 0441 // //qDebug() << "called"; 0442 QString id = QStringLiteral("__%1_%2").arg(node->token()->look()).arg(reinterpret_cast<quintptr>(node)); 0443 if (currentVariableTable()->contains(id)) { 0444 currentVariableTable()->remove(id); 0445 return; 0446 } 0447 0448 if (node->child(0)->value()->boolean()) { 0449 // store a empty Value just to know we executed once 0450 currentVariableTable()->insert(id, Value()); 0451 newScope = node->child(1); 0452 } else { 0453 if (node->childCount() >= 3) { 0454 currentVariableTable()->insert(id, Value()); 0455 newScope = node->child(2); // execute the else part 0456 } 0457 } 0458 } 0459 void Executer::executeElse(TreeNode* node) { 0460 // //qDebug() << "called"; 0461 execute(node->child(0)); // execute the scope, that's all... 0462 } 0463 void Executer::executeRepeat(TreeNode* node) { 0464 // //qDebug() << "called"; 0465 QString id = QStringLiteral("__%1_%2").arg(node->token()->look()).arg(reinterpret_cast<quintptr>(node)); 0466 0467 if(breaking) { 0468 breaking = false; 0469 currentVariableTable()->remove(id); 0470 return; 0471 } 0472 0473 // the iteration state is stored on the variable table 0474 if (currentVariableTable()->contains(id)) { 0475 int currentCount = static_cast<int>(round((*currentVariableTable())[id].number())); 0476 if (currentCount > 0) { 0477 (*currentVariableTable())[id].setNumber(currentCount - 1); 0478 } else { 0479 currentVariableTable()->remove(id); 0480 return; 0481 } 0482 } else { 0483 if(static_cast<int>(round(node->child(0)->value()->number()))<=0) // handle 'repeat 0' 0484 return; 0485 0486 currentVariableTable()->insert(id, Value(round(node->child(0)->value()->number()) - 1.0)); 0487 } 0488 newScope = node->child(1); 0489 } 0490 void Executer::executeWhile(TreeNode* node) { 0491 // //qDebug() << "called"; 0492 // first time this gets called the expression is already executed 0493 // after one iteration the expression is not automatically re-executed. 0494 // so we do the following on every call to executeWhile: 0495 // exec scope, exec expression, exec scope, exec expression, ... 0496 0497 QString id = QStringLiteral("__%1_%2").arg(node->token()->look()).arg(reinterpret_cast<quintptr>(node)); 0498 0499 if (breaking) { 0500 // We hit a break command while executing the scope 0501 breaking = false; // Not breaking anymore 0502 currentVariableTable()->remove(id); // remove the value (cleanup) 0503 return; // Move to the next sibling 0504 } 0505 0506 if (currentVariableTable()->contains(id)) { 0507 newScope = node; // re-execute the expression 0508 currentVariableTable()->remove(id); 0509 return; 0510 } 0511 currentVariableTable()->insert(id, Value()); // store a empty Value just to know we executed once 0512 0513 if (node->child(0)->value()->boolean()) 0514 newScope = node->child(1); // (re-)execute the scope 0515 else 0516 currentVariableTable()->remove(id); // clean-up, keep currenNode on currentNode so the next sibling we be run next 0517 } 0518 void Executer::executeFor(TreeNode* node) { 0519 // //qDebug() << "called"; 0520 qCritical("Executer::executeFor(): should have been translated to Token::ForTo by the parser"); 0521 node = node; // stop the warnings 0522 } 0523 void Executer::executeForTo(TreeNode* node) { 0524 // //qDebug() << "called"; 0525 // first time this gets called the expressions are already executed 0526 // after one iteration the expression is not re-executed. 0527 // so we do: exec scope, exec expressions, exec scope, exec expressions, ... 0528 0529 //TODO: We have the cleanup part twice (after breaking and after the last iteration 0530 // perhaps clean it up by putting it in one place? 0531 0532 bool firstIteration = false; 0533 if (functionStack.isEmpty() || functionStack.top().function != node) { 0534 // if this for loop is called for the first time... 0535 CalledFunction c; 0536 c.function = node; 0537 // TODO: Find a better solution then this for nested for loops 0538 //c.variableTable = new VariableTable(); 0539 c.variableTable = currentVariableTable(); 0540 functionStack.push(c); 0541 0542 currentVariableTable()->insert(node->child(0)->token()->look(), Value(node->child(1)->value()->number())); 0543 firstIteration = true; 0544 } 0545 0546 QString id = QStringLiteral("__%1_%2").arg(node->token()->look()).arg(reinterpret_cast<quintptr>(node)); 0547 0548 if(breaking) { 0549 breaking = false; 0550 //delete functionStack.top().variableTable; 0551 functionStack.pop(); 0552 // if we don't delete the functionStack's varibleTable any more 0553 // do remove the for loops id.. 0554 currentVariableTable()->remove(id); 0555 return; 0556 } 0557 0558 if (currentVariableTable()->contains(id)) { 0559 newScope = node; // re-execute the expressions 0560 currentVariableTable()->remove(id); 0561 return; 0562 } 0563 currentVariableTable()->insert(id, Value()); // store a empty Value just to know we executed once 0564 0565 double currentCount = (*currentVariableTable())[node->child(0)->token()->look()].number(); 0566 double startCondition = node->child(1)->value()->number(); 0567 double endCondition = node->child(2)->value()->number(); 0568 double step = node->child(3)->value()->number(); 0569 0570 if ((startCondition < endCondition && currentCount + step <= endCondition) || 0571 (startCondition > endCondition && currentCount + step >= endCondition && step<0) || //negative loop sanity check, is it implemented? 0572 (startCondition ==endCondition && firstIteration) ) { // for expressions like for $n=1 to 1 0573 if (!firstIteration) 0574 (*currentVariableTable())[node->child(0)->token()->look()].setNumber(currentCount + step); 0575 newScope = node->child(4); // (re-)execute the scope 0576 } else { 0577 // cleaning up after last iteration... 0578 //delete functionStack.top().variableTable; 0579 functionStack.pop(); 0580 // if we don't delete the functionStack's varibleTable any more 0581 // do remove the for loops id.. 0582 currentVariableTable()->remove(id); 0583 } 0584 } 0585 void Executer::executeBreak(TreeNode* node) { 0586 // //qDebug() << "called"; 0587 if (!checkParameterQuantity(node, 0, 20000+Token::Break*100+90)) return; 0588 0589 breaking = true; 0590 0591 // Check for the first parent which is a repeat, while of for loop. 0592 // If found, switch the newScope to them so they can break. 0593 QList<int> tokenTypes; 0594 tokenTypes.append(Token::Repeat); 0595 tokenTypes.append(Token::While); 0596 tokenTypes.append(Token::ForTo); 0597 0598 TreeNode* ns = getParentOfTokenTypes(node, &tokenTypes); 0599 0600 if(ns!=nullptr) 0601 newScope = ns; 0602 //else 0603 // We could add an error right HERE 0604 0605 // At the moment we just ignore a break when we couldn't 0606 // find a matching parent 0607 } 0608 void Executer::executeReturn(TreeNode* node) { 0609 // //qDebug() << "called"; 0610 if(node->childCount()>0) 0611 returnValue = node->child(0)->value(); 0612 else 0613 returnValue = nullptr; 0614 returning = true; 0615 } 0616 void Executer::executeWait(TreeNode* node) { 0617 // //qDebug() << "called"; 0618 if (!checkParameterQuantity(node, 1, 20000+Token::Wait*100+90)) return; 0619 if (!checkParameterType(node, Value::Number, 20000+Token::Wait*100+91) ) return; 0620 waiting = true; 0621 QTimer::singleShot(static_cast<int>(1000*node->child(0)->value()->number()), this, &Executer::stopWaiting); 0622 } 0623 void Executer::executeAssert(TreeNode* node) { 0624 // //qDebug() << "called"; 0625 if (!checkParameterQuantity(node, 1, 20000+Token::Wait*100+90)) return; 0626 if (!checkParameterType(node, Value::Bool, 20000+Token::Wait*100+91) ) return; 0627 if (!node->child(0)->value()->boolean()) addError(i18n("ASSERT failed"), *node->token(), 0); 0628 } 0629 void Executer::executeAnd(TreeNode* node) { 0630 // //qDebug() << "called"; 0631 //Niels: See 'Not' 0632 if(node->childCount()!=2) { 0633 addError(i18n("'And' needs two variables"), *node->token(), 0); 0634 return; 0635 } 0636 node->value()->setBool(node->child(0)->value()->boolean() && node->child(1)->value()->boolean()); 0637 } 0638 void Executer::executeOr(TreeNode* node) { 0639 // //qDebug() << "called"; 0640 //Niels: See 'Not' 0641 if(node->childCount()!=2) { 0642 addError(i18n("'Or' needs two variables"), *node->token(), 0); 0643 return; 0644 } 0645 node->value()->setBool(node->child(0)->value()->boolean() || node->child(1)->value()->boolean()); 0646 } 0647 void Executer::executeNot(TreeNode* node) { 0648 // //qDebug() << "called"; 0649 // OLD-TODO: maybe add some error handling here... 0650 //Niels: Ok, now we check if the node has children. Should we also check whether the child value is a boolean? 0651 if(node->childCount()!=1) { 0652 addError(i18n("I need something to do a not on"), *node->token(), 0); 0653 return; 0654 } 0655 node->value()->setBool(!node->child(0)->value()->boolean()); 0656 } 0657 void Executer::executeEquals(TreeNode* node) { 0658 // //qDebug() << "called"; 0659 if(node->childCount()!=2) { 0660 addError(i18n("I cannot do a '==' without 2 variables"), *node->token(), 0); 0661 return; 0662 } 0663 node->value()->setBool(*node->child(0)->value() == node->child(1)->value()); 0664 } 0665 void Executer::executeNotEquals(TreeNode* node) { 0666 // //qDebug() << "called"; 0667 if(node->childCount()!=2) { 0668 addError(i18n("I cannot do a '!=' without 2 variables"), *node->token(), 0); 0669 return; 0670 } 0671 node->value()->setBool(*node->child(0)->value() != node->child(1)->value()); 0672 } 0673 void Executer::executeGreaterThan(TreeNode* node) { 0674 // //qDebug() << "called"; 0675 if(node->childCount()!=2) { 0676 addError(i18n("I cannot do a '>' without 2 variables"), *node->token(), 0); 0677 return; 0678 } 0679 node->value()->setBool(*node->child(0)->value() > node->child(1)->value()); 0680 } 0681 void Executer::executeLessThan(TreeNode* node) { 0682 // //qDebug() << "called"; 0683 if(node->childCount()!=2) { 0684 addError(i18n("I cannot do a '<' without 2 variables"), *node->token(), 0); 0685 return; 0686 } 0687 node->value()->setBool(*node->child(0)->value() < node->child(1)->value()); 0688 } 0689 void Executer::executeGreaterOrEquals(TreeNode* node) { 0690 // //qDebug() << "called"; 0691 if(node->childCount()!=2) { 0692 addError(i18n("I cannot do a '>=' without 2 variables"), *node->token(), 0); 0693 return; 0694 } 0695 node->value()->setBool(*node->child(0)->value() >= node->child(1)->value()); 0696 } 0697 void Executer::executeLessOrEquals(TreeNode* node) { 0698 // //qDebug() << "called"; 0699 if(node->childCount()!=2) { 0700 addError(i18n("I cannot do a '<=' without 2 variables"), *node->token(), 0); 0701 return; 0702 } 0703 node->value()->setBool(*node->child(0)->value() <= node->child(1)->value()); 0704 } 0705 void Executer::executeAddition(TreeNode* node) { 0706 // //qDebug() << "called"; 0707 if(node->childCount()!=2) { 0708 addError(i18n("You need two numbers or string to do an addition"), *node->token(), 0); 0709 return; 0710 } 0711 if (node->child(0)->value()->type() == Value::Number && node->child(1)->value()->type() == Value::Number) { 0712 node->value()->setNumber(node->child(0)->value()->number() + node->child(1)->value()->number()); 0713 } else { 0714 node->value()->setString(node->child(0)->value()->string().append(node->child(1)->value()->string())); 0715 } 0716 } 0717 void Executer::executeSubtraction(TreeNode* node) { 0718 // //qDebug() << "called"; 0719 if(node->childCount()!=2) { 0720 addError(i18n("You need two numbers to subtract"), *node->token(), 0); 0721 return; 0722 } 0723 if (node->child(0)->value()->type() == Value::Number && node->child(1)->value()->type() == Value::Number) { 0724 node->value()->setNumber(node->child(0)->value()->number() - node->child(1)->value()->number()); 0725 } else { 0726 if (node->child(0)->value()->type() != Value::Number) 0727 addError(i18n("You tried to subtract from a non-number, '%1'", node->child(0)->token()->look()), *node->token(), 0); 0728 if (node->child(1)->value()->type() != Value::Number) 0729 addError(i18n("You tried to subtract a non-number, '%1'", node->child(1)->token()->look()), *node->token(), 0); 0730 } 0731 } 0732 void Executer::executeMultiplication(TreeNode* node) { 0733 // //qDebug() << "called"; 0734 if(node->childCount()!=2) { 0735 addError(i18n("You need two numbers to multiplicate"), *node->token(), 0); 0736 return; 0737 } 0738 if (node->child(0)->value()->type() == Value::Number && node->child(1)->value()->type() == Value::Number) { 0739 node->value()->setNumber(node->child(0)->value()->number() * node->child(1)->value()->number()); 0740 } else { 0741 if (node->child(0)->value()->type() != Value::Number) 0742 addError(i18n("You tried to multiplicate a non-number, '%1'", node->child(0)->token()->look()), *node->token(), 0); 0743 if (node->child(1)->value()->type() != Value::Number) 0744 addError(i18n("You tried to multiplicate by a non-number, '%1'", node->child(1)->token()->look()), *node->token(), 0); 0745 } 0746 } 0747 void Executer::executeDivision(TreeNode* node) { 0748 // //qDebug() << "called"; 0749 if(node->childCount()!=2) { 0750 addError(i18n("You need two numbers to divide"), *node->token(), 0); 0751 return; 0752 } 0753 if (node->child(0)->value()->type() == Value::Number && node->child(1)->value()->type() == Value::Number) { 0754 if(node->child(1)->value()->number()==0) { 0755 addError(i18n("You tried to divide by zero"), *node->token(), 0); 0756 return; 0757 } 0758 node->value()->setNumber(node->child(0)->value()->number() / node->child(1)->value()->number()); 0759 } else { 0760 if (node->child(0)->value()->type() != Value::Number) 0761 addError(i18n("You tried to divide a non-number, '%1'", node->child(0)->token()->look()), *node->token(), 0); 0762 if (node->child(1)->value()->type() != Value::Number) 0763 addError(i18n("You tried to divide by a non-number, '%1'", node->child(1)->token()->look()), *node->token(), 0); 0764 } 0765 } 0766 void Executer::executePower(TreeNode* node) { 0767 // //qDebug() << "called"; 0768 if(node->childCount()!=2) { 0769 addError(i18n("You need two numbers to raise a power"), *node->token(), 0); 0770 return; 0771 } 0772 if (node->child(0)->value()->type() == Value::Number && node->child(1)->value()->type() == Value::Number) { 0773 node->value()->setNumber(pow(node->child(0)->value()->number(), node->child(1)->value()->number())); 0774 0775 double result = pow(node->child(0)->value()->number(), node->child(1)->value()->number()); 0776 0777 int error = errno; 0778 if(error==ERANGE) { 0779 node->value()->setNumber(0); 0780 addError(i18n("The result of an exponentiation was too large"), *node->token(), 0); 0781 }else{ 0782 node->value()->setNumber(result); 0783 } 0784 } else { 0785 if (node->child(0)->value()->type() != Value::Number) 0786 addError(i18n("You tried to raise a non-number to a power, '%1'", node->child(0)->token()->look()), *node->token(), 0); 0787 if (node->child(1)->value()->type() != Value::Number) 0788 addError(i18n("You tried to raise the power of a non-number, '%1'", node->child(1)->token()->look()), *node->token(), 0); 0789 } 0790 } 0791 void Executer::executeAssign(TreeNode* node) { 0792 // //qDebug() << "called"; 0793 if(node->childCount()!=2) { 0794 addError(i18n("You need one variable and a value or variable to do a '='"), *node->token(), 0); 0795 return; 0796 } 0797 if (!functionStack.isEmpty() && !globalVariableTable.contains(node->child(0)->token()->look())) // &&functionStack.top().variableTable->contains(node->token()->look())) 0798 { 0799 // //qDebug() << "function scope"; 0800 functionStack.top().variableTable->insert(node->child(0)->token()->look(), node->child(1)->value()); 0801 } else { 0802 // inserts unless already exists then replaces 0803 globalVariableTable.insert(node->child(0)->token()->look(), node->child(1)->value()); 0804 } 0805 // //qDebug() << "variableTable updated!"; 0806 Q_EMIT variableTableUpdated(node->child(0)->token()->look(), node->child(1)->value()); 0807 } 0808 void Executer::executeLearn(TreeNode* node) { 0809 // //qDebug() << "called"; 0810 if(functionTable.contains(node->child(0)->token()->look())) { 0811 addError(i18n("The function '%1' is already defined.", node->child(0)->token()->look()), *node->token(), 0); 0812 return; 0813 } 0814 functionTable.insert(node->child(0)->token()->look(), node); 0815 // //qDebug() << "functionTable updated!"; 0816 QStringList parameters; 0817 for (uint i = 0; i < node->child(1)->childCount(); i++) 0818 parameters << node->child(1)->child(i)->token()->look(); 0819 Q_EMIT functionTableUpdated(node->child(0)->token()->look(), parameters); 0820 } 0821 void Executer::executeArgumentList(TreeNode* node) { 0822 // //qDebug() << "called"; 0823 node = node; // stop the warnings // this is a stud 0824 } 0825 void Executer::executeReset(TreeNode* node) { 0826 // //qDebug() << "called"; 0827 if (!checkParameterQuantity(node, 0, 20000+Token::Reset*100+90)) return; 0828 Q_EMIT reset(); 0829 } 0830 void Executer::executeClear(TreeNode* node) { 0831 // //qDebug() << "called"; 0832 if (!checkParameterQuantity(node, 0, 20000+Token::Clear*100+90)) return; 0833 Q_EMIT clear(); 0834 } 0835 void Executer::executeCenter(TreeNode* node) { 0836 // //qDebug() << "called"; 0837 if (!checkParameterQuantity(node, 0, 20000+Token::Center*100+90)) return; 0838 Q_EMIT center(); 0839 } 0840 void Executer::executeGo(TreeNode* node) { 0841 // //qDebug() << "called"; 0842 if (!checkParameterQuantity(node, 2, 20000+Token::Go*100+90) || 0843 !checkParameterType(node, Value::Number, 20000+Token::Go*100+91)) return; 0844 Q_EMIT go(node->child(0)->value()->number(), node->child(1)->value()->number()); 0845 } 0846 void Executer::executeGoX(TreeNode* node) { 0847 // //qDebug() << "called"; 0848 if (!checkParameterQuantity(node, 1, 20000+Token::GoX*100+90) || 0849 !checkParameterType(node, Value::Number, 20000+Token::GoX*100+91)) return; 0850 Q_EMIT goX(node->child(0)->value()->number()); 0851 } 0852 void Executer::executeGoY(TreeNode* node) { 0853 // //qDebug() << "called"; 0854 if (!checkParameterQuantity(node, 1, 20000+Token::GoY*100+90) || 0855 !checkParameterType(node, Value::Number, 20000+Token::GoY*100+91)) return; 0856 Q_EMIT goY(node->child(0)->value()->number()); 0857 } 0858 void Executer::executeForward(TreeNode* node) { 0859 // //qDebug() << "called"; 0860 if (!checkParameterQuantity(node, 1, 20000+Token::Forward*100+90) || 0861 !checkParameterType(node, Value::Number, 20000+Token::Forward*100+91)) return; 0862 Q_EMIT forward(node->child(0)->value()->number()); 0863 } 0864 void Executer::executeBackward(TreeNode* node) { 0865 // //qDebug() << "called"; 0866 if (!checkParameterQuantity(node, 1, 20000+Token::Backward*100+90) || 0867 !checkParameterType(node, Value::Number, 20000+Token::Backward*100+91)) return; 0868 Q_EMIT backward(node->child(0)->value()->number()); 0869 } 0870 void Executer::executeDirection(TreeNode* node) { 0871 // //qDebug() << "called"; 0872 if (!checkParameterQuantity(node, 1, 20000+Token::Direction*100+90) || 0873 !checkParameterType(node, Value::Number, 20000+Token::Direction*100+91)) return; 0874 Q_EMIT direction(node->child(0)->value()->number()); 0875 } 0876 void Executer::executeTurnLeft(TreeNode* node) { 0877 // //qDebug() << "called"; 0878 if (!checkParameterQuantity(node, 1, 20000+Token::TurnLeft*100+90) || 0879 !checkParameterType(node, Value::Number, 20000+Token::TurnLeft*100+91)) return; 0880 Q_EMIT turnLeft(node->child(0)->value()->number()); 0881 } 0882 void Executer::executeTurnRight(TreeNode* node) { 0883 // //qDebug() << "called"; 0884 if (!checkParameterQuantity(node, 1, 20000+Token::TurnRight*100+90) || 0885 !checkParameterType(node, Value::Number, 20000+Token::TurnRight*100+91)) return; 0886 Q_EMIT turnRight(node->child(0)->value()->number()); 0887 } 0888 void Executer::executePenWidth(TreeNode* node) { 0889 // //qDebug() << "called"; 0890 if (!checkParameterQuantity(node, 1, 20000+Token::PenWidth*100+90) || 0891 !checkParameterType(node, Value::Number, 20000+Token::PenWidth*100+91)) return; 0892 Q_EMIT penWidth(node->child(0)->value()->number()); 0893 } 0894 void Executer::executePenUp(TreeNode* node) { 0895 // //qDebug() << "called"; 0896 if (!checkParameterQuantity(node, 0, 20000+Token::PenUp*100+90)) return; 0897 Q_EMIT penUp(); 0898 } 0899 void Executer::executePenDown(TreeNode* node) { 0900 // //qDebug() << "called"; 0901 if (!checkParameterQuantity(node, 0, 20000+Token::PenDown*100+90)) return; 0902 Q_EMIT penDown(); 0903 } 0904 void Executer::executePenColor(TreeNode* node) { 0905 // //qDebug() << "called"; 0906 if (!checkParameterQuantity(node, 3, 20000+Token::PenColor*100+90) || 0907 !checkParameterType(node, Value::Number, 20000+Token::PenColor*100+91)) return; 0908 Q_EMIT penColor(node->child(0)->value()->number(), node->child(1)->value()->number(), node->child(2)->value()->number()); 0909 } 0910 void Executer::executeCanvasColor(TreeNode* node) { 0911 // //qDebug() << "called"; 0912 if (!checkParameterQuantity(node, 3, 20000+Token::CanvasColor*100+90) || 0913 !checkParameterType(node, Value::Number, 20000+Token::CanvasColor*100+91)) return; 0914 Q_EMIT canvasColor(node->child(0)->value()->number(), node->child(1)->value()->number(), node->child(2)->value()->number()); 0915 } 0916 void Executer::executeCanvasSize(TreeNode* node) { 0917 // //qDebug() << "called"; 0918 if (!checkParameterQuantity(node, 2, 20000+Token::CanvasSize*100+90) || 0919 !checkParameterType(node, Value::Number, 20000+Token::CanvasSize*100+91)) return; 0920 Q_EMIT canvasSize(node->child(0)->value()->number(), node->child(1)->value()->number()); 0921 } 0922 void Executer::executeSpriteShow(TreeNode* node) { 0923 // //qDebug() << "called"; 0924 if (!checkParameterQuantity(node, 0, 20000+Token::SpriteShow*100+90)) return; 0925 Q_EMIT spriteShow(); 0926 } 0927 void Executer::executeSpriteHide(TreeNode* node) { 0928 // //qDebug() << "called"; 0929 if (!checkParameterQuantity(node, 0, 20000+Token::SpriteHide*100+90)) return; 0930 Q_EMIT spriteHide(); 0931 } 0932 void Executer::executePrint(TreeNode* node) { 0933 // //qDebug() << "called"; 0934 if (!checkParameterQuantity(node, 1, 20000+Token::Print*100+90)) 0935 return; 0936 // //qDebug() << "Printing: '" << node->child(0)->value()->string() << "'"; 0937 Q_EMIT print(node->child(0)->value()->string()); 0938 } 0939 void Executer::executeFontSize(TreeNode* node) { 0940 // //qDebug() << "called"; 0941 if (!checkParameterQuantity(node, 1, 20000+Token::FontSize*100+90) || 0942 !checkParameterType(node, Value::Number, 20000+Token::FontSize*100+91)) return; 0943 Q_EMIT fontSize(node->child(0)->value()->number()); 0944 } 0945 void Executer::executeRandom(TreeNode* node) { 0946 // //qDebug() << "called"; 0947 if (!checkParameterQuantity(node, 2, 20000+Token::Random*100+90)) return; 0948 TreeNode* nodeX = node->child(0); // getting 0949 TreeNode* nodeY = node->child(1); 0950 0951 if (!checkParameterType(node, Value::Number, 20000+Token::Random*100+91)) return; 0952 double x = nodeX->value()->number(); 0953 double y = nodeY->value()->number(); 0954 double r = QRandomGenerator::global()->bounded(1.0); 0955 node->value()->setNumber(r * (y - x) + x); 0956 } 0957 void Executer::executeGetX(TreeNode* node) { 0958 // //qDebug() << "called"; 0959 if (!checkParameterQuantity(node, 0, 20000+Token::GetX*100+90)) return; 0960 double value = 0; 0961 Q_EMIT getX(value); 0962 node->value()->setNumber(value); 0963 } 0964 void Executer::executeGetY(TreeNode* node) { 0965 // //qDebug() << "called"; 0966 if (!checkParameterQuantity(node, 0, 20000+Token::GetY*100+90)) return; 0967 double value = 0; 0968 Q_EMIT getY(value); 0969 node->value()->setNumber(value); 0970 } 0971 void Executer::executeMessage(TreeNode* node) { 0972 // //qDebug() << "called"; 0973 if (!checkParameterQuantity(node, 1, 20000+Token::Message*100+90)) return; 0974 Q_EMIT message(node->child(0)->value()->string()); 0975 } 0976 void Executer::executeAsk(TreeNode* node) { 0977 // //qDebug() << "called"; 0978 if (!checkParameterQuantity(node, 1, 20000+Token::Ask*100+90)) return; 0979 QString value = node->child(0)->value()->string(); 0980 Q_EMIT ask(value); 0981 0982 bool convertOk; 0983 double d = value.toDouble(&convertOk); 0984 if(convertOk) 0985 node->value()->setNumber(d); 0986 else 0987 node->value()->setString(value); 0988 } 0989 void Executer::executePi(TreeNode* node) { 0990 // //qDebug() << "called"; 0991 node->value()->setNumber(M_PI); 0992 } 0993 void Executer::executeTan(TreeNode* node) { 0994 // //qDebug() << "called"; 0995 if (!checkParameterQuantity(node, 1, 20000+Token::Tan*100+90)) return; 0996 0997 double deg = node->child(0)->value()->number(); 0998 node->value()->setNumber(tan(qDegreesToRadians(deg))); 0999 } 1000 void Executer::executeSin(TreeNode* node) { 1001 // //qDebug() << "called"; 1002 if (!checkParameterQuantity(node, 1, 20000+Token::Sin*100+90)) return; 1003 1004 double deg = node->child(0)->value()->number(); 1005 node->value()->setNumber(sin(qDegreesToRadians(deg))); 1006 } 1007 void Executer::executeCos(TreeNode* node) { 1008 // //qDebug() << "called"; 1009 if (!checkParameterQuantity(node, 1, 20000+Token::Cos*100+90)) return; 1010 1011 double deg = node->child(0)->value()->number(); 1012 node->value()->setNumber(cos(qDegreesToRadians(deg))); 1013 } 1014 void Executer::executeArcTan(TreeNode* node) { 1015 // //qDebug() << "called"; 1016 if (!checkParameterQuantity(node, 1, 20000+Token::ArcTan*100+90)) return; 1017 1018 double deg = node->child(0)->value()->number(); 1019 node->value()->setNumber(qRadiansToDegrees(atan(deg))); 1020 } 1021 void Executer::executeArcSin(TreeNode* node) { 1022 // //qDebug() << "called"; 1023 if (!checkParameterQuantity(node, 1, 20000+Token::ArcSin*100+90)) return; 1024 1025 double deg = node->child(0)->value()->number(); 1026 node->value()->setNumber(qRadiansToDegrees(asin(deg))); 1027 } 1028 void Executer::executeArcCos(TreeNode* node) { 1029 // //qDebug() << "called"; 1030 if (!checkParameterQuantity(node, 1, 20000+Token::ArcCos*100+90)) return; 1031 1032 double deg = node->child(0)->value()->number(); 1033 node->value()->setNumber(qRadiansToDegrees(acos(deg))); 1034 } 1035 void Executer::executeSqrt(TreeNode* node) { 1036 // //qDebug() << "called"; 1037 if (!checkParameterQuantity(node, 1, 20000+Token::Sqrt*100+90)) return; 1038 1039 double val = node->child(0)->value()->number(); 1040 if(val<0) { 1041 addError(i18n("Can't do a sqrt of a negative number"), *node->child(0)->token(), 0); 1042 node->value()->setNumber(0); 1043 return; 1044 } 1045 node->value()->setNumber(sqrt(val)); 1046 } 1047 void Executer::executeRound(TreeNode* node) { 1048 // //qDebug() << "called"; 1049 if (!checkParameterQuantity(node, 1, 20000+Token::Round*100+90)) return; 1050 1051 double val = node->child(0)->value()->number(); 1052 node->value()->setNumber(round(val)); 1053 } 1054 void Executer::executeGetDirection(TreeNode* node) { 1055 // //qDebug() << "called"; 1056 if (!checkParameterQuantity(node, 0, 20000+Token::GetDirection*100+90)) return; 1057 double value = 0; 1058 Q_EMIT getDirection(value); 1059 node->value()->setNumber(value); 1060 } 1061 void Executer::executeMod(TreeNode* node) { 1062 // //qDebug() << "called"; 1063 if (!checkParameterQuantity(node, 2, 20000+Token::Mod*100+90)) return; 1064 TreeNode* nodeX = node->child(0); // getting 1065 TreeNode* nodeY = node->child(1); 1066 1067 if (!checkParameterType(node, Value::Number, 20000+Token::Mod*100+91)) return; 1068 double x = nodeX->value()->number(); 1069 double y = nodeY->value()->number(); 1070 double m = (static_cast<int>(round(x)) % static_cast<int>(round(y))); 1071 node->value()->setNumber(m); 1072 } 1073 1074 //END GENERATED executer_cpp CODE 1075 1076 TreeNode* Executer::getParentOfTokenTypes(TreeNode* child, QList<int>* types) { 1077 for (int type : *types) { 1078 if(child->parent()->token()->type()==type) 1079 return child->parent(); 1080 else if(child->parent()->token()->type()==Token::Root) 1081 return nullptr; 1082 } 1083 return getParentOfTokenTypes(child->parent(), types); 1084 } 1085 1086 void Executer::printExe() { 1087 // if (currentNode->token()->type() != Token::Scope) 1088 // //qDebug() << "EXE> " << qPrintable(currentNode->token()->look()); 1089 } 1090 1091 #include "moc_executer.cpp"