File indexing completed on 2024-11-10 03:30:45
0001 # SPDX-FileCopyrightText: 2005-2009 Cies Breijs 0002 # 0003 # SPDX-License-Identifier: GPL-2.0-only 0004 0005 0006 # In this file commands/instructions/keywords/symbols/etc can easily be added to kturtle. 0007 # Changes can also be made here, but be careful cause the existing code may rely on stuff in here. 0008 # Thanks for looking at the code... 0009 0010 0011 # The following variables can be used: 0012 # 0013 # @type, the internal name of the item 0014 # @look, the en_US look for the item 0015 # @ali, the alias (another en_US look) 0016 # @args, the specification of the arguments (:none, :bool, :number, :string) 0017 # if omitted no code for argument handling wil be generated (so you gotta DIY) 0018 # examples: 0019 # @args = [:number, :number, :number] 0020 # @args = [:none] 0021 # @args = [:number, :string] 0022 # @p_def, method definition for the parser 0023 # @e_def, method definition for the executer 0024 # @funct, the functionality the item should be given 0025 # @cat, the category the item belongs to 0026 # @help, .docbook formatted text for in a help file 0027 0028 0029 # In the @funct variable, one or more categories of the item can be put. 0030 # These are the categories and their descriptions: 0031 # 0032 # statement the item is a statement and thus will be parsed as such 0033 # constant the item is a constant so does not need any execution 0034 # auto-Q_EMIT the Q_EMIT statement will be autogenerated works for many commands 0035 # node the item can exist in the node tree and 0036 0037 0038 new_item() 0039 @type = "Root" 0040 @funct = "node" 0041 parse_item() 0042 0043 new_item() 0044 @type = "Scope" 0045 @cat = "Scope" 0046 @funct = "node" 0047 @e_def = 0048 <<EOS 0049 // catch loops, they need to be managed... 0050 int parentTokenType = node->parent()->token()->type(); 0051 if (parentTokenType == Token::If || 0052 parentTokenType == Token::Repeat || 0053 parentTokenType == Token::While || 0054 // parentTokenType == Token::ForIn || 0055 parentTokenType == Token::ForTo) { 0056 currentNode = node->parent(); 0057 executeCurrent = true; 0058 return; 0059 } 0060 if(parentTokenType == Token::Learn) { 0061 //We have the end of a Learn, so we should return 0062 returning = true; 0063 returnValue = 0; 0064 return; 0065 } 0066 newScope = node; 0067 EOS 0068 parse_item() 0069 0070 new_item() 0071 @type = "WhiteSpace" 0072 parse_item() 0073 0074 new_item() 0075 @type = "EndOfLine" 0076 parse_item() 0077 0078 new_item() 0079 @type = "EndOfInput" 0080 parse_item() 0081 0082 new_item() 0083 @type = "VariablePrefix" 0084 @look = "$" 0085 @localize = false 0086 parse_item() 0087 0088 new_item() 0089 @type = "Variable" 0090 @cat = "Variable" 0091 @funct = "statement, node" 0092 @p_def = 0093 <<EOS 0094 // This is called to the variable is the first token on a line. 0095 // There has to be an assignment token right after it... 0096 TreeNode* variableNode = new TreeNode(currentToken); 0097 nextToken(); 0098 Token* remeberedToken = new Token(*currentToken); 0099 skipToken(Token::Assign, *variableNode->token()); 0100 TreeNode* assignNode = new TreeNode(remeberedToken); 0101 assignNode->appendChild(variableNode); // the LHV; the symbol 0102 assignNode->appendChild(parseExpression()); // the RHV; the expression 0103 return assignNode; 0104 EOS 0105 @e_def = 0106 <<EOS 0107 bool aValueIsNeeded = true; 0108 // no need to look up when assigning (in a for loop statement) 0109 if ((node->parent()->token()->type() == Token::ForTo) && (node->parent()->child(0)==node)) 0110 return; 0111 // we need to executeVariables in assignments for things like $x=$y to work 0112 if (node->parent()->token()->type() == Token::Assign) { 0113 // Test if we are in the LHS of the assignment 0114 if (node == node->parent()->child(0)) { 0115 // In this case we do not need to be initialized, we will get a value in executeAssign 0116 aValueIsNeeded = false; 0117 } 0118 } 0119 if (!functionStack.isEmpty() && 0120 functionStack.top().variableTable->contains(node->token()->look())) { 0121 // //qDebug() << "exists locally"; 0122 node->setValue( (*functionStack.top().variableTable)[node->token()->look()] ); 0123 } else if (globalVariableTable.contains(node->token()->look())) { 0124 // //qDebug() << "exists globally"; 0125 node->setValue(globalVariableTable[node->token()->look()]); 0126 } else if (aValueIsNeeded) 0127 { 0128 addError(i18n("The variable '%1' was used without first being assigned to a value", node->token()->look()), *node->token(), 0); 0129 } 0130 EOS 0131 parse_item() 0132 0133 new_item() 0134 @type = "FunctionCall" 0135 @cat = "FunctionCall" 0136 @funct = "statement, node" 0137 @p_def = 0138 <<EOS 0139 TreeNode* node = new TreeNode(currentToken); 0140 node->token()->setType(Token::FunctionCall); 0141 nextToken(); 0142 appendArguments(node); 0143 return node; 0144 EOS 0145 @e_def = 0146 <<EOS 0147 if (node->parent()->token()->type() == Token::Learn) { // in case we're defining a function 0148 currentNode = node->parent(); 0149 executeCurrent = true; 0150 return; 0151 } 0152 0153 if (returning) { // if the function is already executed and returns now 0154 returnValue = 0; 0155 returning = false; 0156 // //qDebug() << "==> functionReturned!"; 0157 return; 0158 } 0159 0160 if (!functionTable.contains(node->token()->look())) { 0161 addError(i18n("An unknown function named '%1' was called", node->token()->look()), *node->token(), 0); 0162 return; 0163 } 0164 0165 CalledFunction c; 0166 c.function = node; 0167 c.variableTable = new VariableTable(); 0168 functionStack.push(c); 0169 // //qDebug() << "==> functionCalled!"; 0170 0171 TreeNode* learnNode = functionTable[node->token()->look()]; 0172 0173 // if the parameter numbers are not equal... 0174 if (node->childCount() != learnNode->child(1)->childCount()) { 0175 addError( 0176 i18n("The function '%1' was called with %2, while it should be called with %3", 0177 node->token()->look(), 0178 i18ncp("The function '%1' was called with %2, while it should be called with %3", "1 parameter", "%1 parameters", node->childCount()), 0179 i18ncp("The function '%1' was called with %2, while it should be called with %3", "1 parameter", "%1 parameters", learnNode->child(1)->childCount()) 0180 ), 0181 *node->token(), 0); 0182 return; 0183 } 0184 0185 for (uint i = 0; i < node->childCount(); i++) { 0186 functionStack.top().variableTable->insert(learnNode->child(1)->child(i)->token()->look(), node->child(i)->value()); 0187 // //qDebug() << "inserted variable " << learnNode->child(1)->child(i)->token()->look() << " on function stack"; 0188 } 0189 newScope = learnNode->child(2); 0190 EOS 0191 parse_item() 0192 0193 new_item() 0194 @type = "String" 0195 @cat = "String" 0196 @funct = "node, constant" 0197 parse_item() 0198 0199 new_item() 0200 @type = "Number" 0201 @cat = "Number" 0202 @funct = "node, constant" 0203 parse_item() 0204 0205 0206 0207 new_item() 0208 @type = "True" 0209 @cat = "TrueFalse" 0210 @look = "true" 0211 @funct = "node, constant" 0212 parse_item() 0213 0214 new_item() 0215 @type = "False" 0216 @cat = "TrueFalse" 0217 @look = "false" 0218 @funct = "node, constant" 0219 parse_item() 0220 0221 0222 0223 new_item() 0224 @type = "Comment" 0225 @cat = "Comment" 0226 @look = "#" 0227 @localize = false 0228 parse_item() 0229 0230 0231 0232 new_item() 0233 # shouldnt thisone also be treated as a normal token 0234 # so the code for fetching the whole string has t be in here 0235 @type = "StringDelimiter" 0236 @cat = "String" 0237 @look = "\"" 0238 @localize = false 0239 parse_item() 0240 0241 0242 0243 new_item() 0244 @type = "ScopeOpen" 0245 @cat = "Scope" 0246 @look = "{" 0247 @localize = false 0248 @funct = "statement" 0249 @p_def = 0250 <<EOS 0251 TreeNode* scopeNode = new TreeNode(new Token(Token::Scope, "{...}", currentToken->startRow(), currentToken->startCol(), 0, 0)); 0252 delete currentToken; 0253 nextToken(); 0254 // cannot change the currentScope to this scope cauz we still have to work in the currentScope 0255 // so we set the newScope, which the currentScope will become after parsing the current statement 0256 newScope = scopeNode; 0257 return scopeNode; 0258 EOS 0259 parse_item() 0260 0261 new_item() 0262 @type = "ScopeClose" 0263 @cat = "Scope" 0264 @look = "}" 0265 @localize = false 0266 @funct = "statement" 0267 @p_def = 0268 <<EOS 0269 TreeNode* node = new TreeNode(currentToken); 0270 int endRow = currentToken->endRow(); 0271 int endCol = currentToken->endCol(); 0272 nextToken(); 0273 while (currentToken->type() == Token::EndOfLine) { // allow newlines before else 0274 delete currentToken; 0275 nextToken(); 0276 } 0277 if (currentScope->parent() && 0278 currentScope->parent()->token()->type() == Token::If && 0279 currentToken->type() == Token::Else) { 0280 currentScope->parent()->appendChild(parseElse()); 0281 } 0282 if (currentScope != rootNode) { 0283 // find the parent scope of this scope, and make it current 0284 TreeNode* parentScope = currentScope; 0285 do { 0286 parentScope = parentScope->parent(); 0287 } while (parentScope != rootNode && parentScope->token()->type() != Token::Scope); 0288 currentScope->token()->setEndRow(endRow); 0289 currentScope->token()->setEndCol(endCol); 0290 currentScope = parentScope; 0291 } 0292 return node; 0293 EOS 0294 parse_item() 0295 0296 0297 0298 new_item() 0299 @type = "ParenthesisOpen" 0300 @cat = "Parenthesis" 0301 @look = "(" 0302 @localize = false 0303 parse_item() 0304 0305 new_item() 0306 @type = "ParenthesisClose" 0307 @cat = "Parenthesis" 0308 @look = ")" 0309 @localize = false 0310 parse_item() 0311 0312 0313 0314 new_item() 0315 @type = "ArgumentSeparator" 0316 @cat = "ArgumentSeparator" 0317 @look = "," 0318 parse_item() 0319 0320 0321 0322 new_item() 0323 @type = "DecimalSeparator" 0324 @look = "." 0325 parse_item() 0326 0327 0328 0329 new_item() 0330 @type = "Exit" 0331 @cat = "ControllerCommand" 0332 @look = "exit" 0333 @funct = "statement, node" 0334 @args = [:none] 0335 @e_def = 0336 <<EOS 0337 node = node; // stop the warnings 0338 finished = true; 0339 EOS 0340 parse_item() 0341 0342 new_item() 0343 @type = "If" 0344 @cat = "ControllerCommand" 0345 @look = "if" 0346 @funct = "statement, node" 0347 @p_def = 0348 <<EOS 0349 TreeNode* node = new TreeNode(currentToken); 0350 nextToken(); 0351 node->appendChild(parseExpression()); 0352 if (currentToken->type() == Token::ScopeOpen) { 0353 node->appendChild(parseScopeOpen()); // if followed by a scope 0354 } 0355 return node; 0356 EOS 0357 @e_def = 0358 <<EOS 0359 QString id = QString("__%1_%2").arg(node->token()->look()).arg((quintptr)node); 0360 if (currentVariableTable()->contains(id)) { 0361 currentVariableTable()->remove(id); 0362 return; 0363 } 0364 0365 if (node->child(0)->value()->boolean()) { 0366 // store a empty Value just to know we executed once 0367 currentVariableTable()->insert(id, Value()); 0368 newScope = node->child(1); 0369 } else { 0370 if (node->childCount() >= 3) { 0371 currentVariableTable()->insert(id, Value()); 0372 newScope = node->child(2); // execute the else part 0373 } 0374 } 0375 EOS 0376 parse_item() 0377 0378 new_item() 0379 @type = "Else" 0380 @cat = "ControllerCommand" 0381 @look = "else" 0382 @funct = "node" 0383 @p_def = 0384 <<EOS 0385 nextToken(); 0386 if (currentToken->type() == Token::ScopeOpen) { 0387 return parseScopeOpen(); // if followed by a scope 0388 } 0389 return parseStatement(); // if followed by single statement 0390 EOS 0391 @e_def = 0392 <<EOS 0393 execute(node->child(0)); // execute the scope, that's all... 0394 EOS 0395 parse_item() 0396 0397 0398 p_def_repeat_while = 0399 <<EOS 0400 TreeNode* node = new TreeNode(currentToken); 0401 nextToken(); 0402 node->appendChild(parseExpression()); 0403 if (currentToken->type() == Token::ScopeOpen) { 0404 node->appendChild(parseScopeOpen()); // if followed by a scope 0405 } else { 0406 node->appendChild(parseStatement()); // if followed by single statement 0407 } 0408 return node; 0409 EOS 0410 0411 new_item() 0412 @type = "Repeat" 0413 @cat = "ControllerCommand" 0414 @look = "repeat" 0415 @funct = "statement, node" 0416 @p_def = p_def_repeat_while 0417 @e_def = 0418 <<EOS 0419 QString id = QString("__%1_%2").arg(node->token()->look()).arg((quintptr)node); 0420 0421 if(breaking) { 0422 breaking = false; 0423 currentVariableTable()->remove(id); 0424 return; 0425 } 0426 0427 // the iteration state is stored on the variable table 0428 if (currentVariableTable()->contains(id)) { 0429 int currentCount = ROUND2INT((*currentVariableTable())[id].number()); 0430 if (currentCount > 0) { 0431 (*currentVariableTable())[id].setNumber(currentCount - 1); 0432 } else { 0433 currentVariableTable()->remove(id); 0434 return; 0435 } 0436 } else { 0437 if(ROUND2INT(node->child(0)->value()->number())<=0) // handle 'repeat 0' 0438 return; 0439 0440 currentVariableTable()->insert(id, Value((double)(ROUND2INT(node->child(0)->value()->number()) - 1))); 0441 } 0442 newScope = node->child(1); 0443 EOS 0444 parse_item() 0445 0446 new_item() 0447 @type = "While" 0448 @cat = "ControllerCommand" 0449 @look = "while" 0450 @funct = "statement, node" 0451 @p_def = p_def_repeat_while 0452 @e_def = 0453 <<EOS 0454 // first time this gets called the expression is already executed 0455 // after one iteration the expression is not automatically re-executed. 0456 // so we do the following on every call to executeWhile: 0457 // exec scope, exec expression, exec scope, exec expression, ... 0458 0459 QString id = QString("__%1_%2").arg(node->token()->look()).arg((quintptr)node); 0460 0461 if (breaking) { 0462 // We hit a break command while executing the scope 0463 breaking = false; // Not breaking anymore 0464 currentVariableTable()->remove(id); // remove the value (cleanup) 0465 return; // Move to the next sibling 0466 } 0467 0468 if (currentVariableTable()->contains(id)) { 0469 newScope = node; // re-execute the expression 0470 currentVariableTable()->remove(id); 0471 return; 0472 } 0473 currentVariableTable()->insert(id, Value()); // store a empty Value just to know we executed once 0474 0475 if (node->child(0)->value()->boolean()) 0476 newScope = node->child(1); // (re-)execute the scope 0477 else 0478 currentVariableTable()->remove(id); // clean-up, keep currenNode on currentNode so the next sibling we be run next 0479 EOS 0480 parse_item() 0481 0482 new_item() 0483 @type = "For" 0484 @cat = "ControllerCommand" 0485 @look = "for" 0486 @funct = "statement, node" 0487 @p_def = 0488 <<EOS 0489 TreeNode* node = new TreeNode(currentToken); 0490 nextToken(); 0491 Token* firstToken = currentToken; 0492 nextToken(); 0493 if (firstToken->type() == Token::Variable && currentToken->type() == Token::Assign) { 0494 node->token()->setType(Token::ForTo); 0495 node->appendChild(new TreeNode(firstToken)); 0496 nextToken(); 0497 node->appendChild(parseExpression()); 0498 skipToken(Token::To, *node->token()); 0499 node->appendChild(parseExpression()); 0500 if (currentToken->type() == Token::Step) { 0501 nextToken(); 0502 node->appendChild(parseExpression()); 0503 } else { 0504 TreeNode* step = new TreeNode(new Token(Token::Number, "1", 0,0,0,0)); 0505 step->setValue(Value(1.0)); 0506 node->appendChild(step); 0507 } 0508 // } else if (currentToken->type() == Token::In) { 0509 // // @TODO something for a for-in loop 0510 } else { 0511 addError(i18n("'for' was called wrongly"), *node->token(), 0); 0512 finished = true; // abort after this error 0513 return node; 0514 } 0515 0516 if (currentToken->type() == Token::ScopeOpen) { 0517 node->appendChild(parseScopeOpen()); // if followed by a scope 0518 } else { 0519 node->appendChild(parseStatement()); // if followed by single statement 0520 } 0521 0522 return node; 0523 EOS 0524 @e_def = 0525 <<EOS 0526 qCritical("Executer::executeFor(): should have been translated to Token::ForTo by the parser"); 0527 node = node; // stop the warnings 0528 EOS 0529 parse_item() 0530 0531 new_item() 0532 @type = "ForTo" 0533 @cat = "ControllerCommand" 0534 @funct = "node" 0535 @e_def = 0536 <<EOS 0537 // first time this gets called the expressions are already executed 0538 // after one iteration the expression is not re-executed. 0539 // so we do: exec scope, exec expressions, exec scope, exec expressions, ... 0540 0541 //TODO: We have the cleanup part twice (after breaking and after the last iteration 0542 // perhaps clean it up by putting it in one place? 0543 0544 bool firstIteration = false; 0545 if (functionStack.isEmpty() || functionStack.top().function != node) { 0546 // if this for loop is called for the first time... 0547 CalledFunction c; 0548 c.function = node; 0549 // TODO: Find a better solution then this for nested for loops 0550 //c.variableTable = new VariableTable(); 0551 c.variableTable = currentVariableTable(); 0552 functionStack.push(c); 0553 0554 currentVariableTable()->insert(node->child(0)->token()->look(), Value(node->child(1)->value()->number())); 0555 firstIteration = true; 0556 } 0557 0558 QString id = QString("__%1_%2").arg(node->token()->look()).arg((quintptr)node); 0559 0560 if(breaking) { 0561 breaking = false; 0562 //delete functionStack.top().variableTable; 0563 functionStack.pop(); 0564 // if we don't delete the functionStack's varibleTable any more 0565 // do remove the for loops id.. 0566 currentVariableTable()->remove(id); 0567 return; 0568 } 0569 0570 if (currentVariableTable()->contains(id)) { 0571 newScope = node; // re-execute the expressions 0572 currentVariableTable()->remove(id); 0573 return; 0574 } 0575 currentVariableTable()->insert(id, Value()); // store a empty Value just to know we executed once 0576 0577 double currentCount = (*currentVariableTable())[node->child(0)->token()->look()].number(); 0578 double startCondition = node->child(1)->value()->number(); 0579 double endCondition = node->child(2)->value()->number(); 0580 double step = node->child(3)->value()->number(); 0581 0582 if ((startCondition < endCondition && currentCount + step <= endCondition) || 0583 (startCondition > endCondition && currentCount + step >= endCondition && step<0) || //negative loop sanity check, is it implemented? 0584 (startCondition ==endCondition && firstIteration) ) { // for expressions like for $n=1 to 1 0585 if (!firstIteration) 0586 (*currentVariableTable())[node->child(0)->token()->look()].setNumber(currentCount + step); 0587 newScope = node->child(4); // (re-)execute the scope 0588 } else { 0589 // cleaning up after last iteration... 0590 //delete functionStack.top().variableTable; 0591 functionStack.pop(); 0592 // if we don't delete the functionStack's varibleTable any more 0593 // do remove the for loops id.. 0594 currentVariableTable()->remove(id); 0595 } 0596 EOS 0597 parse_item() 0598 0599 new_item() 0600 @type = "To" 0601 @cat = "ControllerCommand" 0602 @look = "to" 0603 parse_item() 0604 0605 # # new_item() 0606 # # @type = "ForIn" 0607 # # @funct = "node" 0608 # # parse_item() 0609 # # 0610 # # new_item() 0611 # # @type = "In" 0612 # # @look = "in" 0613 # # parse_item() 0614 0615 new_item() 0616 @type = "Step" 0617 @cat = "ControllerCommand" 0618 @look = "step" 0619 parse_item() 0620 0621 new_item() 0622 @type = "Break" 0623 @cat = "ControllerCommand" 0624 @look = "break" 0625 @funct = "statement, node" 0626 @args = [:none] 0627 @e_def = 0628 <<EOS 0629 if (!checkParameterQuantity(node, 0, 20000+Token::Break*100+90)) return; 0630 0631 breaking = true; 0632 0633 // Check for the first parent which is a repeat, while of for loop. 0634 // If found, switch the newScope to them so they can break. 0635 QList<int> tokenTypes; 0636 tokenTypes.append(Token::Repeat); 0637 tokenTypes.append(Token::While); 0638 tokenTypes.append(Token::ForTo); 0639 0640 TreeNode* ns = getParentOfTokenTypes(node, &tokenTypes); 0641 0642 if(ns!=0) 0643 newScope = ns; 0644 //else 0645 // We could add an error right HERE 0646 0647 // At the moment we just ignore a break when we couldn't 0648 // find a matching parent 0649 EOS 0650 parse_item() 0651 0652 new_item() 0653 @type = "Return" 0654 @cat = "ControllerCommand" 0655 @look = "return" 0656 @funct = "statement, node" 0657 @p_def = 0658 <<EOS 0659 TreeNode* node = new TreeNode(currentToken); 0660 nextToken(); 0661 appendArguments(node); 0662 skipToken(Token::EndOfLine, *node->token()); 0663 return node; 0664 EOS 0665 @e_def = 0666 <<EOS 0667 if(node->childCount()>0) 0668 returnValue = node->child(0)->value(); 0669 else 0670 returnValue = 0; 0671 returning = true; 0672 EOS 0673 parse_item() 0674 0675 new_item() 0676 @type = "Wait" 0677 @cat = "ControllerCommand" 0678 @look = "wait" 0679 @funct = "statement, node" 0680 @args = [:number] 0681 @e_def = 0682 <<EOS 0683 if (!checkParameterQuantity(node, 1, 20000+Token::Wait*100+90)) return; 0684 if (!checkParameterType(node, Value::Number, 20000+Token::Wait*100+91) ) return; 0685 waiting = true; 0686 QTimer::singleShot((int)(1000*node->child(0)->value()->number()), this, SLOT(stopWaiting())); 0687 EOS 0688 parse_item() 0689 0690 0691 new_item() 0692 @type = "Assert" 0693 @cat = "Command" 0694 @look = "assert" 0695 @funct = "statement, node" 0696 @args = [:bool] 0697 @e_def = 0698 <<EOS 0699 if (!checkParameterQuantity(node, 1, 20000+Token::Wait*100+90)) return; 0700 if (!checkParameterType(node, Value::Bool, 20000+Token::Wait*100+91) ) return; 0701 if (!node->child(0)->value()->boolean()) addError(i18n("ASSERT failed"), *node->token(), 0); 0702 EOS 0703 parse_item() 0704 0705 0706 new_item() 0707 @type = "And" 0708 @cat = "BooleanOperator" 0709 @look = "and" 0710 @funct = "node" 0711 @e_def = 0712 <<EOS 0713 //Niels: See 'Not' 0714 if(node->childCount()!=2) { 0715 addError(i18n("'And' needs two variables"), *node->token(), 0); 0716 return; 0717 } 0718 node->value()->setBool(node->child(0)->value()->boolean() && node->child(1)->value()->boolean()); 0719 EOS 0720 parse_item() 0721 0722 new_item() 0723 @type = "Or" 0724 @cat = "BooleanOperator" 0725 @look = "or" 0726 @funct = "node" 0727 @e_def = 0728 <<EOS 0729 //Niels: See 'Not' 0730 if(node->childCount()!=2) { 0731 addError(i18n("'Or' needs two variables"), *node->token(), 0); 0732 return; 0733 } 0734 node->value()->setBool(node->child(0)->value()->boolean() || node->child(1)->value()->boolean()); 0735 EOS 0736 parse_item() 0737 0738 new_item() 0739 @type = "Not" 0740 @cat = "BooleanOperator" 0741 @look = "not" 0742 @funct = "node" 0743 @e_def = 0744 <<EOS 0745 // OLD-TODO: maybe add some error handling here... 0746 //Niels: Ok, now we check if the node has children. Should we also check whether the child value is a boolean? 0747 if(node->childCount()!=1) { 0748 addError(i18n("I need something to do a not on"), *node->token(), 0); 0749 return; 0750 } 0751 node->value()->setBool(!node->child(0)->value()->boolean()); 0752 EOS 0753 parse_item() 0754 0755 0756 0757 def e_def_expression_creator(look) 0758 # since the looks for expressions are the same in TurtleScript and C++ we can take this shortcut... 0759 # all the logic doing the expressioning is in the Value class 0760 return "\tif(node->childCount()!=2) { \n\t\taddError(i18n(\"I cannot do a '#{look}' without 2 variables\"), *node->token(), 0);\n\t\treturn;\n\t}\n\tnode->value()->setBool(*node->child(0)->value() #{look} node->child(1)->value());\n" 0761 end 0762 0763 new_item() 0764 @type = "Equals" 0765 @cat = "Expression" 0766 @look = "==" 0767 @localize = false 0768 @funct = "node" 0769 @e_def = e_def_expression_creator(@look) 0770 parse_item() 0771 0772 new_item() 0773 @type = "NotEquals" 0774 @cat = "Expression" 0775 @look = "!=" 0776 @localize = false 0777 @funct = "node" 0778 @e_def = e_def_expression_creator(@look) 0779 parse_item() 0780 0781 new_item() 0782 @type = "GreaterThan" 0783 @cat = "Expression" 0784 @look = ">" 0785 @localize = false 0786 @funct = "node" 0787 @e_def = e_def_expression_creator(@look) 0788 parse_item() 0789 0790 new_item() 0791 @type = "LessThan" 0792 @cat = "Expression" 0793 @look = "<" 0794 @localize = false 0795 @funct = "node" 0796 @e_def = e_def_expression_creator(@look) 0797 parse_item() 0798 0799 new_item() 0800 @type = "GreaterOrEquals" 0801 @cat = "Expression" 0802 @look = ">=" 0803 @localize = false 0804 @funct = "node" 0805 @e_def = e_def_expression_creator(@look) 0806 parse_item() 0807 0808 new_item() 0809 @type = "LessOrEquals" 0810 @cat = "Expression" 0811 @look = "<=" 0812 @localize = false 0813 @funct = "node" 0814 @e_def = e_def_expression_creator(@look) 0815 parse_item() 0816 0817 0818 0819 new_item() 0820 @type = "Addition" 0821 @cat = "MathOperator" 0822 @look = "+" 0823 @localize = false 0824 @funct = "node" 0825 @e_def = 0826 <<EOS 0827 if(node->childCount()!=2) { 0828 addError(i18n("You need two numbers or string to do an addition"), *node->token(), 0); 0829 return; 0830 } 0831 if (node->child(0)->value()->type() == Value::Number && node->child(1)->value()->type() == Value::Number) { 0832 node->value()->setNumber(node->child(0)->value()->number() + node->child(1)->value()->number()); 0833 } else { 0834 node->value()->setString(node->child(0)->value()->string().append(node->child(1)->value()->string())); 0835 } 0836 EOS 0837 parse_item() 0838 0839 new_item() 0840 @type = "Subtraction" 0841 @cat = "MathOperator" 0842 @look = "-" 0843 @localize = false 0844 @funct = "node" 0845 @e_def = 0846 <<EOS 0847 if(node->childCount()!=2) { 0848 addError(i18n("You need two numbers to subtract"), *node->token(), 0); 0849 return; 0850 } 0851 if (node->child(0)->value()->type() == Value::Number && node->child(1)->value()->type() == Value::Number) { 0852 node->value()->setNumber(node->child(0)->value()->number() - node->child(1)->value()->number()); 0853 } else { 0854 if (node->child(0)->value()->type() != Value::Number) 0855 addError(i18n("You tried to subtract from a non-number, '%1'", node->child(0)->token()->look()), *node->token(), 0); 0856 if (node->child(1)->value()->type() != Value::Number) 0857 addError(i18n("You tried to subtract a non-number, '%1'", node->child(1)->token()->look()), *node->token(), 0); 0858 } 0859 EOS 0860 parse_item() 0861 0862 new_item() 0863 @type = "Multiplication" 0864 @cat = "MathOperator" 0865 @look = "*" 0866 @localize = false 0867 @funct = "node" 0868 @e_def = 0869 <<EOS 0870 if(node->childCount()!=2) { 0871 addError(i18n("You need two numbers to multiplicate"), *node->token(), 0); 0872 return; 0873 } 0874 if (node->child(0)->value()->type() == Value::Number && node->child(1)->value()->type() == Value::Number) { 0875 node->value()->setNumber(node->child(0)->value()->number() * node->child(1)->value()->number()); 0876 } else { 0877 if (node->child(0)->value()->type() != Value::Number) 0878 addError(i18n("You tried to multiplicate a non-number, '%1'", node->child(0)->token()->look()), *node->token(), 0); 0879 if (node->child(1)->value()->type() != Value::Number) 0880 addError(i18n("You tried to multiplicate by a non-number, '%1'", node->child(1)->token()->look()), *node->token(), 0); 0881 } 0882 EOS 0883 parse_item() 0884 0885 new_item() 0886 @type = "Division" 0887 @cat = "MathOperator" 0888 @look = "/" 0889 @localize = false 0890 @funct = "node" 0891 @e_def = 0892 <<EOS 0893 if(node->childCount()!=2) { 0894 addError(i18n("You need two numbers to divide"), *node->token(), 0); 0895 return; 0896 } 0897 if (node->child(0)->value()->type() == Value::Number && node->child(1)->value()->type() == Value::Number) { 0898 if(node->child(1)->value()->number()==0) { 0899 addError(i18n("You tried to divide by zero"), *node->token(), 0); 0900 return; 0901 } 0902 node->value()->setNumber(node->child(0)->value()->number() / node->child(1)->value()->number()); 0903 } else { 0904 if (node->child(0)->value()->type() != Value::Number) 0905 addError(i18n("You tried to divide a non-number, '%1'", node->child(0)->token()->look()), *node->token(), 0); 0906 if (node->child(1)->value()->type() != Value::Number) 0907 addError(i18n("You tried to divide by a non-number, '%1'", node->child(1)->token()->look()), *node->token(), 0); 0908 } 0909 EOS 0910 parse_item() 0911 0912 new_item() 0913 @type = "Power" 0914 @cat = "MathOperator" 0915 @look = "^" # or ** 0916 @localize = false 0917 @funct = "node" 0918 @e_def = 0919 <<EOS 0920 if(node->childCount()!=2) { 0921 addError(i18n("You need two numbers to raise a power"), *node->token(), 0); 0922 return; 0923 } 0924 if (node->child(0)->value()->type() == Value::Number && node->child(1)->value()->type() == Value::Number) { 0925 node->value()->setNumber(pow(node->child(0)->value()->number(), node->child(1)->value()->number())); 0926 0927 double result = pow(node->child(0)->value()->number(), node->child(1)->value()->number()); 0928 0929 int error = errno; 0930 if(error==ERANGE) { 0931 node->value()->setNumber(0); 0932 addError(i18n("The result of an exponentiation was too large"), *node->token(), 0); 0933 }else{ 0934 node->value()->setNumber(result); 0935 } 0936 } else { 0937 if (node->child(0)->value()->type() != Value::Number) 0938 addError(i18n("You tried to raise a non-number to a power, '%1'", node->child(0)->token()->look()), *node->token(), 0); 0939 if (node->child(1)->value()->type() != Value::Number) 0940 addError(i18n("You tried to raise the power of a non-number, '%1'", node->child(1)->token()->look()), *node->token(), 0); 0941 } 0942 EOS 0943 parse_item() 0944 0945 0946 0947 new_item() 0948 @type = "Assign" 0949 @cat = "Assignment" 0950 @look = "=" 0951 @localize = false 0952 @funct = "node" 0953 @e_def = 0954 <<EOS 0955 if(node->childCount()!=2) { 0956 addError(i18n("You need one variable and a value or variable to do a '='"), *node->token(), 0); 0957 return; 0958 } 0959 if (!functionStack.isEmpty() && !globalVariableTable.contains(node->child(0)->token()->look())) // &&functionStack.top().variableTable->contains(node->token()->look())) 0960 { 0961 // //qDebug() << "function scope"; 0962 functionStack.top().variableTable->insert(node->child(0)->token()->look(), node->child(1)->value()); 0963 } else { 0964 // inserts unless already exists then replaces 0965 globalVariableTable.insert(node->child(0)->token()->look(), node->child(1)->value()); 0966 } 0967 // //qDebug() << "variableTable updated!"; 0968 Q_EMIT variableTableUpdated(node->child(0)->token()->look(), node->child(1)->value()); 0969 EOS 0970 parse_item() 0971 0972 0973 0974 new_item() 0975 @type = "Learn" 0976 @cat = "LearnCommand" 0977 @look = "learn" 0978 @funct = "statement, node" 0979 @p_def = 0980 <<EOS 0981 TreeNode* node = new TreeNode(currentToken); 0982 nextToken(); 0983 node->appendChild(new TreeNode(new Token(*currentToken))); 0984 skipToken(Token::FunctionCall, *node->token()); 0985 0986 TreeNode* argumentList = new TreeNode(new Token(Token::ArgumentList, "arguments", 0, 0, 0, 0)); 0987 while (currentToken->type() == Token::Variable) { 0988 // cannot just call appendArguments here because we're only appending Token::Variable tokens 0989 argumentList->appendChild(new TreeNode(currentToken)); 0990 nextToken(); 0991 if (currentToken->type() != Token::ArgumentSeparator) break; 0992 nextToken(); 0993 } 0994 node->appendChild(argumentList); 0995 0996 //Skip all the following EndOfLine's 0997 while (currentToken->type() == Token::EndOfLine) { 0998 delete currentToken; 0999 nextToken(); 1000 } 1001 1002 if (currentToken->type() == Token::ScopeOpen) { 1003 node->appendChild(parseScopeOpen()); // if followed by a scope 1004 } else { 1005 addError(i18n("Expected a scope after the 'learn' command"), *node->token(), 0); 1006 } 1007 return node; 1008 EOS 1009 @e_def = 1010 <<EOS 1011 if(functionTable.contains(node->child(0)->token()->look())) { 1012 addError(i18n("The function '%1' is already defined.", node->child(0)->token()->look()), *node->token(), 0); 1013 return; 1014 } 1015 functionTable.insert(node->child(0)->token()->look(), node); 1016 // //qDebug() << "functionTable updated!"; 1017 QStringList parameters; 1018 for (uint i = 0; i < node->child(1)->childCount(); i++) 1019 parameters << node->child(1)->child(i)->token()->look(); 1020 Q_EMIT functionTableUpdated(node->child(0)->token()->look(), parameters); 1021 EOS 1022 parse_item() 1023 1024 new_item() 1025 @type = "ArgumentList" 1026 @funct = "node" 1027 parse_item() 1028 1029 1030 1031 new_item() 1032 @type = "Reset" 1033 @cat = "Command" 1034 @look = "reset" 1035 @funct = "statement, node, auto-Q_EMIT" 1036 @args = [:none] 1037 parse_item() 1038 1039 new_item() 1040 @type = "Clear" 1041 @cat = "Command" 1042 @look = "clear" 1043 @ali = "ccl" 1044 @funct = "statement, node, auto-Q_EMIT" 1045 @args = [:none] 1046 parse_item() 1047 1048 new_item() 1049 @type = "Center" 1050 @cat = "Command" 1051 @look = "center" 1052 @funct = "statement, node, auto-Q_EMIT" 1053 @args = [:none] 1054 parse_item() 1055 1056 new_item() 1057 @type = "Go" 1058 @cat = "Command" 1059 @look = "go" 1060 @funct = "statement, node, auto-Q_EMIT" 1061 @args = [:number, :number] 1062 parse_item() 1063 1064 new_item() 1065 @type = "GoX" 1066 @cat = "Command" 1067 @look = "gox" 1068 @ali = "gx" 1069 @funct = "statement, node, auto-Q_EMIT" 1070 @args = [:number] 1071 parse_item() 1072 1073 new_item() 1074 @type = "GoY" 1075 @cat = "Command" 1076 @look = "goy" 1077 @ali = "gy" 1078 @funct = "statement, node, auto-Q_EMIT" 1079 @args = [:number] 1080 parse_item() 1081 1082 new_item() 1083 @type = "Forward" 1084 @cat = "Command" 1085 @look = "forward" 1086 @ali = "fw" 1087 @funct = "statement, node, auto-Q_EMIT" 1088 @args = [:number] 1089 parse_item() 1090 1091 new_item() 1092 @type = "Backward" 1093 @cat = "Command" 1094 @look = "backward" 1095 @ali = "bw" 1096 @funct = "statement, node, auto-Q_EMIT" 1097 @args = [:number] 1098 parse_item() 1099 1100 new_item() 1101 @type = "Direction" 1102 @cat = "Command" 1103 @look = "direction" 1104 @ali = "dir" 1105 @funct = "statement, node, auto-Q_EMIT" 1106 @args = [:number] 1107 parse_item() 1108 1109 new_item() 1110 @type = "TurnLeft" 1111 @cat = "Command" 1112 @look = "turnleft" 1113 @ali = "tl" 1114 @funct = "statement, node, auto-Q_EMIT" 1115 @args = [:number] 1116 parse_item() 1117 1118 new_item() 1119 @type = "TurnRight" 1120 @cat = "Command" 1121 @look = "turnright" 1122 @ali = "tr" 1123 @funct = "statement, node, auto-Q_EMIT" 1124 @args = [:number] 1125 parse_item() 1126 1127 new_item() 1128 @type = "PenWidth" 1129 @cat = "Command" 1130 @look = "penwidth" 1131 @ali = "pw" 1132 @funct = "statement, node, auto-Q_EMIT" 1133 @args = [:number] 1134 parse_item() 1135 1136 new_item() 1137 @type = "PenUp" 1138 @cat = "Command" 1139 @look = "penup" 1140 @ali = "pu" 1141 @funct = "statement, node, auto-Q_EMIT" 1142 @args = [:none] 1143 parse_item() 1144 1145 new_item() 1146 @type = "PenDown" 1147 @cat = "Command" 1148 @look = "pendown" 1149 @ali = "pd" 1150 @funct = "statement, node, auto-Q_EMIT" 1151 @args = [:none] 1152 parse_item() 1153 1154 new_item() 1155 @type = "PenColor" 1156 @cat = "Command" 1157 @look = "pencolor" 1158 @ali = "pc" 1159 @funct = "statement, node, auto-Q_EMIT" 1160 @args = [:number, :number, :number] 1161 parse_item() 1162 1163 new_item() 1164 @type = "CanvasColor" 1165 @cat = "Command" 1166 @look = "canvascolor" 1167 @ali = "cc" 1168 @funct = "statement, node, auto-Q_EMIT" 1169 @args = [:number, :number, :number] 1170 parse_item() 1171 1172 new_item() 1173 @type = "CanvasSize" 1174 @cat = "Command" 1175 @look = "canvassize" 1176 @ali = "cs" 1177 @funct = "statement, node, auto-Q_EMIT" 1178 @args = [:number, :number] 1179 parse_item() 1180 1181 new_item() 1182 @type = "SpriteShow" 1183 @cat = "Command" 1184 @look = "spriteshow" 1185 @ali = "ss" 1186 @funct = "statement, node, auto-Q_EMIT" 1187 @args = [:none] 1188 parse_item() 1189 1190 new_item() 1191 @type = "SpriteHide" 1192 @cat = "Command" 1193 @look = "spritehide" 1194 @ali = "sh" 1195 @funct = "statement, node, auto-Q_EMIT" 1196 @args = [:none] 1197 parse_item() 1198 1199 new_item() 1200 @type = "Print" 1201 @cat = "Command" 1202 @look = "print" 1203 @funct = "statement, node, auto-Q_EMIT" 1204 @args = [:string] 1205 @e_def = # define ourself because print handles any argument type 1206 <<EOS 1207 if (!checkParameterQuantity(node, 1, 20000+Token::Print*100+90)) 1208 return; 1209 // //qDebug() << "Printing: '" << node->child(0)->value()->string() << "'"; 1210 EOS 1211 parse_item() 1212 1213 new_item() 1214 @type = "FontSize" 1215 @cat = "Command" 1216 @look = "fontsize" 1217 @funct = "statement, node, auto-Q_EMIT" 1218 @args = [:number] 1219 parse_item() 1220 1221 # # new_item() 1222 # # @type = "WrapOn" 1223 # # @cat = "Command" 1224 # # @look = "wrapon" 1225 # # @funct = "statement, node, auto-Q_EMIT" 1226 # # @args = [:none] 1227 # # parse_item() 1228 # # 1229 # # new_item() 1230 # # @type = "WrapOff" 1231 # # @cat = "Command" 1232 # # @look = "wrapoff" 1233 # # @funct = "statement, node, auto-Q_EMIT" 1234 # # @args = [:none] 1235 # # parse_item() 1236 1237 1238 new_item() 1239 @type = "Random" 1240 @cat = "Command" 1241 @look = "random" 1242 @ali = "rnd" 1243 @funct = "statement, node" 1244 @args = [:number, :number] 1245 @e_def = 1246 <<EOS 1247 if (!checkParameterQuantity(node, 2, 20000+Token::Random*100+90)) return; 1248 TreeNode* nodeX = node->child(0); // getting 1249 TreeNode* nodeY = node->child(1); 1250 1251 if (!checkParameterType(node, Value::Number, 20000+Token::Random*100+91)) return; 1252 double x = nodeX->value()->number(); 1253 double y = nodeY->value()->number(); 1254 double r = (double)(KRandom::random()) / RAND_MAX; 1255 node->value()->setNumber(r * (y - x) + x); 1256 EOS 1257 parse_item() 1258 1259 new_item() 1260 @type = "GetX" 1261 @cat = "Command" 1262 @look = "getx" 1263 @funct = "statement, node" 1264 @args = [:none] 1265 @e_def = 1266 <<EOS 1267 if (!checkParameterQuantity(node, 0, 20000+Token::GetX*100+90)) return; 1268 double value = 0; 1269 Q_EMIT getX(value); 1270 node->value()->setNumber(value); 1271 EOS 1272 parse_item() 1273 1274 new_item() 1275 @type = "GetY" 1276 @cat = "Command" 1277 @look = "gety" 1278 @funct = "statement, node" 1279 @args = [:none] 1280 @e_def = 1281 <<EOS 1282 if (!checkParameterQuantity(node, 0, 20000+Token::GetY*100+90)) return; 1283 double value = 0; 1284 Q_EMIT getY(value); 1285 node->value()->setNumber(value); 1286 EOS 1287 parse_item() 1288 1289 # # new_item() 1290 # # @type = "Run" 1291 # # @cat = "Command" 1292 # # @look = "run" 1293 # # @funct = "statement, node" 1294 # # @args = [:string] 1295 # # parse_item() 1296 # # 1297 new_item() 1298 @type = "Message" 1299 @cat = "Command" 1300 @look = "message" 1301 @funct = "statement, node" 1302 @args = [:string] 1303 @e_def = 1304 <<EOS 1305 if (!checkParameterQuantity(node, 1, 20000+Token::Message*100+90)) return; 1306 Q_EMIT message(node->child(0)->value()->string()); 1307 EOS 1308 parse_item() 1309 1310 new_item() 1311 @type = "Ask" # used to be "inputwindow" 1312 @cat = "Command" 1313 @look = "ask" 1314 @funct = "statement, node" 1315 @args = [:string] 1316 @e_def = 1317 <<EOS 1318 if (!checkParameterQuantity(node, 1, 20000+Token::Ask*100+90)) return; 1319 QString value = node->child(0)->value()->string(); 1320 Q_EMIT ask(value); 1321 1322 bool convertOk; 1323 double d = value.toDouble(&convertOk); 1324 if(convertOk) 1325 node->value()->setNumber(d); 1326 else 1327 node->value()->setString(value); 1328 EOS 1329 parse_item() 1330 1331 new_item() 1332 @type = "Pi" 1333 @cat = "Command" 1334 @look = "pi" 1335 @funct = "statement, node" 1336 @args = [:none] 1337 @e_def = 1338 <<EOS 1339 node->value()->setNumber(M_PI); 1340 EOS 1341 parse_item() 1342 1343 new_item() 1344 @type = "Tan" 1345 @cat = "Command" 1346 @look = "tan" 1347 @funct = "statement, node" 1348 @args = [:number] 1349 @e_def = 1350 <<EOS 1351 if (!checkParameterQuantity(node, 1, 20000+Token::Tan*100+90)) return; 1352 1353 double deg = node->child(0)->value()->number(); 1354 node->value()->setNumber(tan(DEG2RAD(deg))); 1355 EOS 1356 parse_item() 1357 1358 new_item() 1359 @type = "Sin" 1360 @cat = "Command" 1361 @look = "sin" 1362 @funct = "statement, node" 1363 @args = [:number] 1364 @e_def = 1365 <<EOS 1366 if (!checkParameterQuantity(node, 1, 20000+Token::Sin*100+90)) return; 1367 1368 double deg = node->child(0)->value()->number(); 1369 node->value()->setNumber(sin(DEG2RAD(deg))); 1370 EOS 1371 parse_item() 1372 1373 new_item() 1374 @type = "Cos" 1375 @cat = "Command" 1376 @look = "cos" 1377 @funct = "statement, node" 1378 @args = [:number] 1379 @e_def = 1380 <<EOS 1381 if (!checkParameterQuantity(node, 1, 20000+Token::Cos*100+90)) return; 1382 1383 double deg = node->child(0)->value()->number(); 1384 node->value()->setNumber(cos(DEG2RAD(deg))); 1385 EOS 1386 parse_item() 1387 1388 new_item() 1389 @type = "ArcTan" 1390 @cat = "Command" 1391 @look = "arctan" 1392 @funct = "statement, node" 1393 @args = [:number] 1394 @e_def = 1395 <<EOS 1396 if (!checkParameterQuantity(node, 1, 20000+Token::ArcTan*100+90)) return; 1397 1398 double deg = node->child(0)->value()->number(); 1399 node->value()->setNumber(RAD2DEG(atan(deg))); 1400 EOS 1401 parse_item() 1402 1403 new_item() 1404 @type = "ArcSin" 1405 @cat = "Command" 1406 @look = "arcsin" 1407 @funct = "statement, node" 1408 @args = [:number] 1409 @e_def = 1410 <<EOS 1411 if (!checkParameterQuantity(node, 1, 20000+Token::ArcSin*100+90)) return; 1412 1413 double deg = node->child(0)->value()->number(); 1414 node->value()->setNumber(RAD2DEG(asin(deg))); 1415 EOS 1416 parse_item() 1417 1418 new_item() 1419 @type = "ArcCos" 1420 @cat = "Command" 1421 @look = "arccos" 1422 @funct = "statement, node" 1423 @args = [:number] 1424 @e_def = 1425 <<EOS 1426 if (!checkParameterQuantity(node, 1, 20000+Token::ArcCos*100+90)) return; 1427 1428 double deg = node->child(0)->value()->number(); 1429 node->value()->setNumber(RAD2DEG(acos(deg))); 1430 EOS 1431 parse_item() 1432 1433 new_item() 1434 @type = "Sqrt" 1435 @cat = "Command" 1436 @look = "sqrt" 1437 @funct = "statement, node" 1438 @args = [:number] 1439 @e_def = 1440 <<EOS 1441 if (!checkParameterQuantity(node, 1, 20000+Token::Sqrt*100+90)) return; 1442 1443 double val = node->child(0)->value()->number(); 1444 if(val<0) { 1445 addError(i18n("Can't do a sqrt of a negative number"), *node->child(0)->token(), 0); 1446 node->value()->setNumber(0); 1447 return; 1448 } 1449 node->value()->setNumber(sqrt(val)); 1450 EOS 1451 parse_item() 1452 1453 # i commented this one out because exp will need logarithm and the e number in order to be complete 1454 # new_item() 1455 # @type = "Exp" 1456 # @cat = "Command" 1457 # @look = "exp" 1458 # @funct = "statement, node" 1459 # @args = [:number] 1460 # @e_def = 1461 # <<EOS 1462 # if (!checkParameterQuantity(node, 1, 20000+Token::Exp*100+90)) return; 1463 # 1464 # double val = node->child(0)->value()->number(); 1465 # node->value()->setNumber(exp(val)); 1466 # EOS 1467 # parse_item() 1468 1469 new_item() 1470 @type = "Round" 1471 @cat = "Command" 1472 @look = "round" 1473 @funct = "statement, node" 1474 @args = [:number] 1475 @e_def = 1476 <<EOS 1477 if (!checkParameterQuantity(node, 1, 20000+Token::Round*100+90)) return; 1478 1479 double val = node->child(0)->value()->number(); 1480 node->value()->setNumber((double)ROUND2INT(val)); 1481 EOS 1482 parse_item() 1483 1484 new_item() 1485 @type = "GetDirection" 1486 @cat = "Command" 1487 @look = "getdirection" 1488 @funct = "statement, node" 1489 @args = [:none] 1490 @e_def = 1491 <<EOS 1492 if (!checkParameterQuantity(node, 0, 20000+Token::GetDirection*100+90)) return; 1493 double value = 0; 1494 Q_EMIT getDirection(value); 1495 node->value()->setNumber(value); 1496 EOS 1497 parse_item() 1498 1499 new_item() 1500 @type = "Mod" 1501 @cat = "Command" 1502 @look = "mod" 1503 @funct = "statement, node" 1504 @args = [:number, :number] 1505 @e_def = 1506 <<EOS 1507 if (!checkParameterQuantity(node, 2, 20000+Token::Mod*100+90)) return; 1508 TreeNode* nodeX = node->child(0); // getting 1509 TreeNode* nodeY = node->child(1); 1510 1511 if (!checkParameterType(node, Value::Number, 20000+Token::Mod*100+91)) return; 1512 double x = nodeX->value()->number(); 1513 double y = nodeY->value()->number(); 1514 double m = (double)(ROUND2INT(x) % ROUND2INT(y)); 1515 node->value()->setNumber(m); 1516 EOS 1517 parse_item()