diff --git a/src/canvas.cpp b/src/canvas.cpp index 8f466f2..033a572 100644 --- a/src/canvas.cpp +++ b/src/canvas.cpp @@ -1,287 +1,281 @@ /* Copyright (C) 2003-2006 Cies Breijs This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "canvas.h" #include #include #include +#include #include -// this function is used in executer and canvas: -#define ROUND2INT(x) ( (x) >= 0 ? (int)( (x) + .5 ) : (int)( (x) - .5 ) ) -#ifndef M_PI -#define M_PI 3.14159265358979323846264338327950288419717 -#endif - -const double DegToRad = M_PI / 180.0; int kTurtleZValue = 1; int kCanvasFrameZValue = -10000; int kCanvasMargin = 20; Canvas::Canvas(QWidget *parent) : QGraphicsView(parent) { // create a new scene for this view _scene = new QGraphicsScene(parent); //_scene->setItemIndexMethod(QGraphicsScene::NoIndex); //_scene->setSceneRect(-200, -200, 400, 400); // (-50, -50, 50, 50); setCacheMode(CacheBackground); setRenderHint(QPainter::Antialiasing); setTransformationAnchor(AnchorUnderMouse); setResizeAnchor(AnchorViewCenter); setMinimumSize(100, 100); // foreground pen for drawing pen = new QPen(); // font textFont = new QFont(); // Canvas area marker canvasFrame = new QGraphicsRectItem(); canvasFrame->setZValue(kCanvasFrameZValue); _scene->addItem(canvasFrame); // the turtle shape turtle = new Sprite(); turtle->setZValue(kTurtleZValue); // above the others _scene->addItem(turtle); // set initial values initValues(); setInteractive(false); // at last we assign the scene to the view setScene(_scene); } Canvas::~Canvas() { delete pen; delete turtle; delete canvasFrame; delete textFont; delete _scene; } void Canvas::initValues() { _scene->setSceneRect(QRectF(0, 0, 400, 400)); canvasFrame->setBrush(QBrush()); canvasFrame->setRect(_scene->sceneRect()); fitInView(_scene->sceneRect().adjusted(kCanvasMargin * -1, kCanvasMargin * -1, kCanvasMargin, kCanvasMargin), Qt::KeepAspectRatio); turtle->setPos(200, 200); turtle->setAngle(0); _scene->setBackgroundBrush(QBrush(Qt::white)); pen->setColor(Qt::black); pen->setWidth(1); penWidthIsZero = false; textColor.setRgb(0, 0, 0) ; delete textFont; textFont = new QFont(); // Reset our pen to the default position slotPenDown(); // Show turtle, might have been hidden in the last run slotSpriteShow(); } void Canvas::resizeEvent(QResizeEvent* event) { fitInView(_scene->sceneRect().adjusted(kCanvasMargin*-1,kCanvasMargin*-1,kCanvasMargin,kCanvasMargin), Qt::KeepAspectRatio); event->accept(); } QColor Canvas::rgbDoublesToColor(double r, double g, double b) { return QColor(qMin(qMax((int)r, 0), 255), qMin(qMax((int)g, 0), 255), qMin(qMax((int)b, 0), 255)); } void Canvas::drawLine(double x1, double y1, double x2, double y2) { if (penWidthIsZero) return; QGraphicsLineItem* line = new QGraphicsLineItem(QLineF(x1, y1, x2, y2), nullptr); _scene->addItem(line); line->setPen(*pen); lines.append(line); } void Canvas::slotClear() { QList list = _scene->items(); foreach (QGraphicsItem* item, list) { // delete all but the turtle (who lives on a separate layer with z-value 1) if ((item->zValue() != kTurtleZValue) && (item->zValue() != kCanvasFrameZValue)) delete item; } } void Canvas::slotForward(double x) { - double x2 = turtle->pos().x() + (x * std::sin(turtle->angle() * DegToRad)); - double y2 = turtle->pos().y() - (x * std::cos(turtle->angle() * DegToRad)); + double x2 = turtle->pos().x() + (x * std::sin(qDegreesToRadians(turtle->angle()))); + double y2 = turtle->pos().y() - (x * std::cos(qDegreesToRadians(turtle->angle()))); drawLine(turtle->pos().x(), turtle->pos().y(), x2, y2); slotGo(x2, y2); } void Canvas::slotBackward(double x) { - double x2 = turtle->pos().x() - ( x * std::sin(turtle->angle() * DegToRad) ); - double y2 = turtle->pos().y() + ( x * std::cos(turtle->angle() * DegToRad) ); + double x2 = turtle->pos().x() - ( x * std::sin(qDegreesToRadians(turtle->angle()))); + double y2 = turtle->pos().y() + ( x * std::cos(qDegreesToRadians(turtle->angle()))); drawLine(turtle->pos().x(), turtle->pos().y(), x2, y2); slotGo(x2, y2); } void Canvas::slotCenter() { slotGo(_scene->width()/2, _scene->height()/2); } void Canvas::slotPenWidth(double width) { - int w = qMax(ROUND2INT(width), 0); + int w = qMax(static_cast(round(width)), 0); if (w == 0) { penWidthIsZero = true; return; } else { penWidthIsZero = false; if (w == 1) pen->setWidth(0); else pen->setWidthF(width); } } void Canvas::slotPenColor(double r, double g, double b) { pen->setColor(rgbDoublesToColor(r, g, b)); textColor.setRgb((int)r, (int)g, (int)b); } void Canvas::slotCanvasColor(double r, double g, double b) { //_scene->setBackgroundBrush(QBrush(rgbDoublesToColor(r, g, b))); canvasFrame->setBrush(QBrush(rgbDoublesToColor(r, g, b))); } void Canvas::slotCanvasSize(double r, double g) { _scene->setSceneRect(QRectF(0,0,r,g)); canvasFrame->setRect(_scene->sceneRect()); fitInView(_scene->sceneRect(), Qt::KeepAspectRatio); } void Canvas::slotPrint(const QString& text) { QGraphicsTextItem *ti = new QGraphicsTextItem(text, nullptr); _scene->addItem(ti); // ti->setDefaultTextColor(textColor); ti->setFont(*textFont); ti->setTransform(QTransform().rotate(turtle->angle()), true); ti->setPos(turtle->pos().x(), turtle->pos().y()); ti->setDefaultTextColor(textColor); } void Canvas::slotFontType(const QString& family, const QString& extra) { textFont->setFamily(family); textFont->setBold(extra.contains(i18n("bold"))); textFont->setItalic(extra.contains(i18n("italic"))); textFont->setUnderline(extra.contains(i18n("underline"))); textFont->setOverline(extra.contains(i18n("overline"))); textFont->setStrikeOut(extra.contains(i18n("strikeout"))); } void Canvas::slotReset() { slotClear(); initValues(); } void Canvas::wheelEvent(QWheelEvent *event) { scaleView(std::pow((double)2.0, -event->delta() / 240.0)); } void Canvas::scaleView(double scaleFactor) { qreal factor = matrix().scale(scaleFactor, scaleFactor).mapRect(QRectF(0, 0, 1, 1)).width(); if (factor < 0.07 || factor > 100) return; scale(scaleFactor, scaleFactor); } void Canvas::getX(double& value) { value = turtle->pos().x(); } void Canvas::getY(double& value) { value = turtle->pos().y(); } void Canvas::getDirection(double &value) { value = fmod(turtle->angle(), 360); } QImage Canvas::getPicture() { QImage png(sceneRect().size().toSize(), QImage::Format_RGB32); // create a painter to draw on the image QPainter p(&png); p.setRenderHint(QPainter::Antialiasing); // antialiasing like our Canvas _scene->render(&p); p.end(); return png; } void Canvas::saveAsSvg(const QString& title, const QString& fileName) { Q_UNUSED(title); // it would have been nicer if this method didn't needed to be passed a filename.. // but otherwise some QBuffer, QByteArray, etc. thing had to be set up. QSvgGenerator generator; generator.setFileName(fileName); generator.setSize(_scene->sceneRect().size().toSize()); generator.setViewBox(_scene->sceneRect()); generator.setTitle(title); // generator.setDescription(i18n("Created with KTurtle %1 -- %2").arg(version).arg(website)); // create a painter to draw on the image QPainter p(&generator); // p.setRenderHint(QPainter::Antialiasing); // antialiasing like our Canvas bool spriteWasVisible = turtle->isVisible(); slotSpriteHide(); // hide the sprite as it draws really ugly (especially when Qt < 4.5) _scene->render(&p); if(spriteWasVisible) slotSpriteShow(); p.end(); } diff --git a/src/directiondialog.cpp b/src/directiondialog.cpp index 1d0c702..2fd5d58 100644 --- a/src/directiondialog.cpp +++ b/src/directiondialog.cpp @@ -1,427 +1,423 @@ /* Copyright (C) 2007 Niels Slot This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "directiondialog.h" #include using std::atan; -#ifndef M_PI -#define M_PI 3.14159265358979323846264338327950288419717 -#endif - #include #include #include #include #include #include #include #include #include #include #include #include #include +#include #include #include #include -#define ROUND2INT(x) ( (x) >= 0 ? (int)( (x) + .5 ) : (int)( (x) - .5 ) ) //BEGIN DirectionCanvas widget DirectionCanvas::DirectionCanvas(QWidget* parent) : QWidget(parent) { setFocusPolicy(Qt::ClickFocus); setMinimumSize(230, 200); setBackgroundRole(QPalette::Base); setAutoFillBackground(true); turtle.load(QString(":turtle.svg")); greyTurtle.load(QString(":turtle_grey.svg")); deg = 0; previousDeg = 0; greyTurtleEnabled = true; } void DirectionCanvas::enableGreyTurtle(bool enable) { greyTurtleEnabled = enable; update(); } void DirectionCanvas::paintEvent(QPaintEvent *event) { Q_UNUSED(event); int side = qMin(width(), height()); QPainter painter(this); painter.setRenderHint(QPainter::Antialiasing); painter.save(); // Place us in the middle of the widget painter.translate(width() / 2, height() / 2); // Scale the widget to a square of 200 by 200 painter.scale(side / 200.0, side / 200.0); // Draw the ellipse. With a nice border of 10 painter.drawEllipse(-80, -80, 160, 160); // Draw the lines in the circle painter.save(); for (int i = 0; i < 4; i++) { painter.drawLine(0, -80, 0, 80); painter.rotate(45); } painter.restore(); painter.drawText(-100, -98, 200, 200, Qt::AlignHCenter|Qt::AlignTop, "0"); painter.drawText(-100, -100, 200, 200, Qt::AlignHCenter|Qt::AlignBottom, "180"); painter.drawText(-100, -100, 203, 200, Qt::AlignRight|Qt::AlignVCenter, "90"); painter.drawText(-109, -100, 200, 200, Qt::AlignLeft|Qt::AlignVCenter, "270"); painter.save(); // the gray turtle if (greyTurtleEnabled) { painter.rotate(previousDeg); painter.setPen(Qt::blue); painter.drawLine(0, -80, 0, 0); QRectF greyTurtleRect(-25, -25, 50, 50); greyTurtle.render(&painter, greyTurtleRect); painter.restore(); painter.save(); } // the more healthy looking one painter.rotate(deg); painter.setPen(Qt::red); painter.drawLine(0, -80, 0, 0); QRectF turtleRect(-25, -25, 50, 50); turtle.render(&painter, turtleRect); painter.restore(); painter.restore(); // Draw the widget's border painter.setPen(palette().dark().color()); painter.setBrush(Qt::NoBrush); painter.drawRect(QRect(0, 0, width() - 1, height() - 1)); } void DirectionCanvas::mouseMoveEvent(QMouseEvent *event) { mousePressEvent(event); } void DirectionCanvas::mousePressEvent(QMouseEvent *event) { // Only act upon left and right mouse button clicks, // then translate the X and Y coordinates so that // (0, 0) is in the middle of the widget, sent the // signals and update the widget. if (event->buttons() & Qt::LeftButton) { deg = translateMouseCoords(event->x() - (width() / 2), event->y() - (height() / 2)); update(); emit degreeChanged(deg); } else if (event->buttons() & Qt::RightButton) { previousDeg = translateMouseCoords(event->x() - (width() / 2), event->y() - (height() / 2)); emit previousDegreeChanged(previousDeg); update(); } } void DirectionCanvas::updateDirections(double previousDeg, double deg) { this->deg = deg; this->previousDeg = previousDeg; update(); } double DirectionCanvas::translateMouseCoords(double trans_x, double trans_y) { // We now have 4 squares. One four every corner. // With a cross in the middle. // For every square we calculate a different tangent // therefore we have to add of subtract a number of degrees double result = 0; if (trans_x >= 0 && trans_y >= 0) { // Right down double arc_tan = trans_y / trans_x; result = 90 + (atan(arc_tan)) * (180/M_PI); } else if (trans_x <= 0 && trans_y >= 0) { // Left down trans_x = trans_x * -1; double arc_tan = trans_y / trans_x; result = 270 - (atan(arc_tan)) * (180/M_PI); } else if (trans_x >= 0 && trans_y <= 0) { // Right up trans_y = trans_y * -1; double arc_tan = trans_y / trans_x; result = 90 - (atan(arc_tan)) * (180/M_PI); } else if (trans_x <= 0 && trans_y <= 0) { // Left up trans_x = trans_x * -1; trans_y = trans_y * -1; double arc_tan = trans_y / trans_x; result = 270 + (atan(arc_tan)) * (180/M_PI); } return result; } //END DirectionCanvas widget DirectionDialog::DirectionDialog(double deg, QWidget* parent) : QDialog(parent) { skipValueChangedEvent = false; while (deg < 0 || deg > 359) { if (deg < 0) deg = deg + 360; else if (deg > 359) deg = deg - 360; } translator = Translator::instance(); setWindowTitle(i18n("Direction Chooser")); setModal(false); QVBoxLayout *mainLayout = new QVBoxLayout(this); QWidget *mainWidget = new QWidget(this); mainLayout->addWidget(mainWidget); QWidget* baseWidget = new QWidget(this); mainLayout->addWidget(baseWidget); QVBoxLayout* baseLayout = new QVBoxLayout; baseLayout->setMargin(0); baseWidget->setLayout( baseLayout ); QHBoxLayout* degreeChooserLayout = new QHBoxLayout; baseLayout->addLayout(degreeChooserLayout); canvas = new DirectionCanvas(baseWidget); mainLayout->addWidget(canvas); connect(canvas, &DirectionCanvas::degreeChanged, this, &DirectionDialog::updateDegrees); connect(canvas, &DirectionCanvas::previousDegreeChanged, this, &DirectionDialog::updatePreviousDegrees); degreeChooserLayout->addWidget(canvas); QWidget* rightWidget = new QWidget(baseWidget); mainLayout->addWidget(rightWidget); degreeChooserLayout->addWidget(rightWidget); QVBoxLayout* rightLayout = new QVBoxLayout(rightWidget); // command picker QLabel* commandPickerLabel = new QLabel(rightWidget); commandPickerLabel->setText(i18n("Command &type:")); commandPickerLabel->setScaledContents(true); rightLayout->addWidget(commandPickerLabel); commandPicker = new QComboBox(rightWidget); commandPicker->insertItem(Turnleft, translator->default2localized("turnleft")); commandPicker->insertItem(Turnright, translator->default2localized("turnright")); commandPicker->insertItem(Direction, translator->default2localized("direction")); rightLayout->addWidget(commandPicker); commandPickerLabel->setBuddy(commandPicker); connect(commandPicker, static_cast(&QComboBox::currentIndexChanged), this, &DirectionDialog::changeCommand); rightLayout->addStretch(); // direction QLabel* previousDirectionLabel = new QLabel(rightWidget); previousDirectionLabel->setText(i18n("&Previous direction:")); previousDirectionLabel->setScaledContents(true); rightLayout->addWidget(previousDirectionLabel); previousDirectionSpin = new QSpinBox(rightWidget); // Use -360 to 720 instead of 0 to 360 // If 0 to 360 is used, then wrap-around goes from 360 to 0 (which isn't really a step at all) // Instead use larger range and then convert it into the 0 to 359 range whenever it is changed. previousDirectionSpin->setRange(-360, 720); previousDirectionSpin->setWrapping(true); previousDirectionSpin->setSingleStep(10); previousDirectionSpin->setValue((int)deg); rightLayout->addWidget(previousDirectionSpin); previousDirectionLabel->setBuddy(previousDirectionSpin); connect(previousDirectionSpin, static_cast(&QSpinBox::valueChanged), this, &DirectionDialog::directionChanged); // previous direction QLabel* directionLabel = new QLabel(rightWidget); directionLabel->setText(i18n("&New direction:")); rightLayout->addWidget(directionLabel); directionSpin = new QSpinBox(rightWidget); // Use -360 to 720 instead of 0 to 360 // If 0 to 360 is used, then wrap-around goes from 360 to 0 (which isn't really a step at all) // Instead use larger range and then convert it into the 0 to 359 range whenever it is changed. directionSpin->setRange(-360, 720); directionSpin->setWrapping(true); directionSpin->setSingleStep(10); directionSpin->setValue((int)deg); rightLayout->addWidget(directionSpin); directionLabel->setBuddy(directionSpin); connect(directionSpin, static_cast(&QSpinBox::valueChanged), this, &DirectionDialog::directionChanged); baseLayout->addSpacing(20); // commandBox and copy/paste buttons QHBoxLayout *pasteRowLayout = new QHBoxLayout; baseLayout->addLayout(pasteRowLayout); pasteRowLayout->addStretch(); commandBox = new QLineEdit(rightWidget); commandBox->setReadOnly(true); commandBox->setFont(QFontDatabase::systemFont(QFontDatabase::FixedFont)); commandBox->setMinimumWidth(commandBox->fontMetrics().width("000000000_360")); pasteRowLayout->addWidget(commandBox); QPushButton* copyButton = new QPushButton(QIcon::fromTheme("edit-copy"), i18n("&Copy to clipboard"), baseWidget); mainLayout->addWidget(copyButton); pasteRowLayout->addWidget(copyButton); connect(copyButton, &QPushButton::clicked, this, &DirectionDialog::copyProxy); QPushButton* pasteButton = new QPushButton(QIcon::fromTheme("edit-paste"), i18n("&Paste to editor"), baseWidget); mainLayout->addWidget(pasteButton); pasteRowLayout->addWidget(pasteButton); connect(pasteButton, &QPushButton::clicked, this, &DirectionDialog::pasteProxy); pasteRowLayout->addStretch(); baseLayout->addSpacing(10); QDialogButtonBox *buttonBox = new QDialogButtonBox(); QPushButton *user1Button = new QPushButton; buttonBox->addButton(user1Button, QDialogButtonBox::ActionRole); connect(buttonBox, &QDialogButtonBox::accepted, this, &DirectionDialog::accept); connect(buttonBox, &QDialogButtonBox::rejected, this, &DirectionDialog::reject); mainLayout->addWidget(buttonBox); user1Button->setDefault(true); KGuiItem::assign(user1Button, KStandardGuiItem::close()); connect(user1Button, &QPushButton::clicked, this, &DirectionDialog::close); changeCommand(0); show(); } void DirectionDialog::directionChanged(int value) { Q_UNUSED(value); // if value is outside of the 0 to 359 range, then move it into that range if (previousDirectionSpin->value() < 0) { previousDirectionSpin->setValue(previousDirectionSpin->value() + 360); } else if (previousDirectionSpin->value() >= 360) { previousDirectionSpin->setValue(previousDirectionSpin->value() - 360); } // if value is outside of the 0 to 359 range, then move it into that range if (directionSpin->value() < 0) { directionSpin->setValue(directionSpin->value() + 360); } else if (directionSpin->value() >= 360) { directionSpin->setValue(directionSpin->value() - 360); } // Don't update the canvas when we just updated the direction spinbox. // (only update when the users changes the spinbox) if (skipValueChangedEvent) { skipValueChangedEvent = false; return; } updateCanvas(); updateCommandBox(); } void DirectionDialog::updateCanvas() { // Get the things we need, then update the canvas. int previousDir = previousDirectionSpin->value(); int dir = directionSpin->value(); canvas->updateDirections(previousDir, dir); } void DirectionDialog::changeCommand(int command) { currentCommand = command; if (currentCommand == Direction) { previousDirectionSpin->setEnabled(false); canvas->enableGreyTurtle(false); } else { previousDirectionSpin->setEnabled(true); canvas->enableGreyTurtle(true); } updateCanvas(); updateCommandBox(); } void DirectionDialog::updateDegrees(double deg) { // The canvas has changed, update the spinbox and command-LineEdit skipValueChangedEvent = true; - directionSpin->setValue(ROUND2INT(deg)); + directionSpin->setValue(static_cast(round(deg))); updateCommandBox(); } void DirectionDialog::updatePreviousDegrees(double deg) { // The canvas has changed, update the spinbox and commandBox skipValueChangedEvent = true; - previousDirectionSpin->setValue(ROUND2INT(deg)); + previousDirectionSpin->setValue(static_cast(round(deg))); updateCommandBox(); } void DirectionDialog::updateCommandBox() { // Generate a new value for the commandBox. QString output; int degree = 0; switch (currentCommand) { case Turnleft: output.append(translator->default2localized("turnleft")); degree = 360 - (directionSpin->value() - previousDirectionSpin->value()); break; case Turnright: output.append(translator->default2localized("turnright")); degree = directionSpin->value() - previousDirectionSpin->value(); break; case Direction: output.append(translator->default2localized("direction")); degree = directionSpin->value(); break; } if (degree < 0) { degree += 360; } else if (degree >= 360) { degree -= 360; } output.append(QString(" %1\n").arg(degree)); commandBox->setText(output); } void DirectionDialog::copyProxy() { QApplication::clipboard()->setText(commandBox->text()); } void DirectionDialog::pasteProxy() { emit pasteText(commandBox->text()); } diff --git a/src/interpreter/executer.cpp b/src/interpreter/executer.cpp index 55c3433..ec25866 100644 --- a/src/interpreter/executer.cpp +++ b/src/interpreter/executer.cpp @@ -1,1107 +1,1102 @@ /* Copyright (C) 2003-2006 Cies Breijs This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ // This file is originally written by Walter Scheppers, but almost // every aspect of it is slightly changed by Cies Breijs. #include "executer.h" #include #include #include // for wait #include #include #include +#include -// this function is used in executer and canvas: -#define ROUND2INT(x) ( (x) >= 0 ? (int)( (x) + .5 ) : (int)( (x) - .5 ) ) - -#define DEG2RAD(deg) ( deg * (M_PI / 180) ) -#define RAD2DEG(rad) ( rad * (180 / M_PI) ) - void Executer::initialize(TreeNode* tree, ErrorList* _errorList) { rootNode = tree; newScope = rootNode; currentNode = rootNode; finished = !currentNode->hasChildren(); // set finished to false unless the tree is empty errorList = _errorList; breaking = false; returning = false; waiting = false; returnValue = 0; executeCurrent = false; functionTable.clear(); globalVariableTable.clear(); while (!functionStack.isEmpty()) { // In the ForTo loop, we can assign the globalVariableTable to an entry in the functionStack // we shouldn't delete this variableTable, so check for it. VariableTable* variableTable = functionStack.pop().variableTable; if(variableTable!=&globalVariableTable) delete variableTable; } } void Executer::execute() { //Do we have to do anything? if (finished || waiting) return; if(executeCurrent) { // executeCurrent is used to make sure the currentNode will be executed // this way the tree will not be walked before the execution... executeCurrent = false; execute(currentNode); return; } if(returning) { //We are returning from a function call // Handle returning in the top-level (not inside a function) as // gracefully as possible. // See: https://bugs.kde.org/show_bug.cgi?id=300949 if (functionStack.isEmpty()) { addError(i18n("Cannot return outside a function. "), *(currentNode->token()), 0); finished = true; return; } // Take the last called function from the function stack CalledFunction calledFunction = functionStack.pop(); // Delete the local variables of the called function delete calledFunction.variableTable; currentNode = calledFunction.function; if (returnValue == 0) currentNode->setNullValue(); // Handle an empty return value else currentNode->setValue(returnValue); execute(currentNode); return; } if (newScope == 0) { TreeNode* currentParent = currentNode->parent(); currentNode = currentNode->nextSibling(); if(currentNode == 0) { //running off sibling list currentNode = currentParent; if(currentNode == rootNode) { finished = true; return; } // printExe(); // debugging thing execute(currentNode); return; } }else{ // We're entering a new scope // skip ahead to frist child (if any) else we will not get into the scope if(newScope->hasChildren()) currentNode = newScope->firstChild(); else currentNode = newScope; newScope = 0; } while (currentNode->hasChildren() && currentNode->token()->type() != Token::Scope) currentNode = currentNode->firstChild(); // printExe(); // debugging thing execute(currentNode); } void Executer::execute(TreeNode* node) { if (finished) return; // emit a signal for GUI Token* t = node->token(); // //qDebug() << "emitting token: '" << t->look() << "' - (" << t->startRow() << "," << t->startCol() << " - " << t->endRow() << "," << t->endCol() << ")"; // don't report scopes (their are not really executed) if (t->type() != Token::Scope) emit currentlyExecuting(node); // this method executes one node at the time // if (currentNode->token()->type() != Token::Scope) //qDebug() << "1234567890!!!!!"; switch (node->token()->type()) { //BEGIN GENERATED executer_switch_cpp CODE /* The code between the line that start with "//BEGIN GENERATED" and "//END GENERATED" * is generated by "generate.rb" according to the definitions specified in * "definitions.rb". Please make all changes in the "definitions.rb" file, since all * all change you make here will be overwritten the next time "generate.rb" is run. * Thanks for looking at the code! */ case Token::Root : executeRoot(node); break; case Token::Scope : executeScope(node); break; case Token::Variable : executeVariable(node); break; case Token::FunctionCall : executeFunctionCall(node); break; case Token::String : /* a constant; do nothing */ break; case Token::Number : /* a constant; do nothing */ break; case Token::True : /* a constant; do nothing */ break; case Token::False : /* a constant; do nothing */ break; case Token::Exit : executeExit(node); break; case Token::If : executeIf(node); break; case Token::Else : executeElse(node); break; case Token::Repeat : executeRepeat(node); break; case Token::While : executeWhile(node); break; case Token::For : executeFor(node); break; case Token::ForTo : executeForTo(node); break; case Token::Break : executeBreak(node); break; case Token::Return : executeReturn(node); break; case Token::Wait : executeWait(node); break; case Token::Assert : executeAssert(node); break; case Token::And : executeAnd(node); break; case Token::Or : executeOr(node); break; case Token::Not : executeNot(node); break; case Token::Equals : executeEquals(node); break; case Token::NotEquals : executeNotEquals(node); break; case Token::GreaterThan : executeGreaterThan(node); break; case Token::LessThan : executeLessThan(node); break; case Token::GreaterOrEquals : executeGreaterOrEquals(node); break; case Token::LessOrEquals : executeLessOrEquals(node); break; case Token::Addition : executeAddition(node); break; case Token::Substracton : executeSubstracton(node); break; case Token::Multiplication : executeMultiplication(node); break; case Token::Division : executeDivision(node); break; case Token::Power : executePower(node); break; case Token::Assign : executeAssign(node); break; case Token::Learn : executeLearn(node); break; case Token::ArgumentList : executeArgumentList(node); break; case Token::Reset : executeReset(node); break; case Token::Clear : executeClear(node); break; case Token::Center : executeCenter(node); break; case Token::Go : executeGo(node); break; case Token::GoX : executeGoX(node); break; case Token::GoY : executeGoY(node); break; case Token::Forward : executeForward(node); break; case Token::Backward : executeBackward(node); break; case Token::Direction : executeDirection(node); break; case Token::TurnLeft : executeTurnLeft(node); break; case Token::TurnRight : executeTurnRight(node); break; case Token::PenWidth : executePenWidth(node); break; case Token::PenUp : executePenUp(node); break; case Token::PenDown : executePenDown(node); break; case Token::PenColor : executePenColor(node); break; case Token::CanvasColor : executeCanvasColor(node); break; case Token::CanvasSize : executeCanvasSize(node); break; case Token::SpriteShow : executeSpriteShow(node); break; case Token::SpriteHide : executeSpriteHide(node); break; case Token::Print : executePrint(node); break; case Token::FontSize : executeFontSize(node); break; case Token::Random : executeRandom(node); break; case Token::GetX : executeGetX(node); break; case Token::GetY : executeGetY(node); break; case Token::Message : executeMessage(node); break; case Token::Ask : executeAsk(node); break; case Token::Pi : executePi(node); break; case Token::Tan : executeTan(node); break; case Token::Sin : executeSin(node); break; case Token::Cos : executeCos(node); break; case Token::ArcTan : executeArcTan(node); break; case Token::ArcSin : executeArcSin(node); break; case Token::ArcCos : executeArcCos(node); break; case Token::Sqrt : executeSqrt(node); break; case Token::Round : executeRound(node); break; case Token::GetDirection : executeGetDirection(node); break; case Token::Mod : executeMod(node); break; //END GENERATED executer_switch_cpp CODE default: //qDebug() << "Unrecognizd Token type (" << node->token()->type() << ", " << node->token()->look() << ") -- THIS SHOULDN'T HAPPEN!"; break; } } VariableTable* Executer::currentVariableTable() { if (functionStack.isEmpty()) return &globalVariableTable; else return functionStack.top().variableTable; } bool Executer::checkParameterQuantity(TreeNode* node, uint quantity, int errorCode) { // //qDebug() << "called"; uint nodeSize = node->childCount(); if (quantity == 0) { if (nodeSize == 0) return true; // thats easy! addError(i18n("The %1 command accepts no parameters.", node->token()->look()), *node->token(), errorCode); return false; } // // CHECK THIS OUT LATER // if (nodeSize != 0) // when all parameters are forgotten the parser puts a Unknown/tokEOL param, catch this: // if (node->firstChild()->getToken().type == tokEOL) nodeSize = 0; if (nodeSize != quantity) { if (nodeSize < quantity) { 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); } else { 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); } return false; } return true; // if all tests passed } bool Executer::checkParameterType(TreeNode* node, int valueType, int errorCode) { // //qDebug() << "called"; uint quantity = node->childCount(); TreeNode* currentChild = node->firstChild(); while (currentChild != 0) { if (currentChild->value()->type() != valueType) { switch (valueType) { case Value::String: if (quantity == 1) addError(i18n("The %1 command only accepts a string as its parameter.", node->token()->look()), *node->token(), errorCode); else addError(i18n("The %1 command only accepts strings as its parameters.", node->token()->look()), *node->token(), errorCode); break; case Value::Number: if (quantity == 1) addError(i18n("The %1 command only accepts a number as its parameter.", node->token()->look()), *node->token(), errorCode); else addError(i18n("The %1 command only accepts numbers as its parameters.", node->token()->look()), *node->token(), errorCode); break; case Value::Bool: if (quantity == 1) addError(i18n("The %1 command only accepts an answer as its parameter.", node->token()->look()), *node->token(), errorCode); else addError(i18n("The %1 command only accepts answers as its parameters.", node->token()->look()), *node->token(), errorCode); break; } return false; } currentChild = node->nextChild(); } return true; // if all tests passed } void Executer::addError(const QString& s, const Token& t, int code) { // //qDebug() << qPrintable(s) << " (runtime error)"; errorList->addError(s, t, code); } //BEGIN GENERATED executer_cpp CODE /* The code between the line that start with "//BEGIN GENERATED" and "//END GENERATED" * is generated by "generate.rb" according to the definitions specified in * "definitions.rb". Please make all changes in the "definitions.rb" file, since all * all change you make here will be overwritten the next time "generate.rb" is run. * Thanks for looking at the code! */ void Executer::executeRoot(TreeNode* node) { // //qDebug() << "called"; node = node; // stop the warnings // this is a stud } void Executer::executeScope(TreeNode* node) { // //qDebug() << "called"; // catch loops, they need to be managed... int parentTokenType = node->parent()->token()->type(); if (parentTokenType == Token::If || parentTokenType == Token::Repeat || parentTokenType == Token::While || // parentTokenType == Token::ForIn || parentTokenType == Token::ForTo) { currentNode = node->parent(); executeCurrent = true; return; } if(parentTokenType == Token::Learn) { //We have the end of a Learn, so we should return returning = true; returnValue = 0; return; } newScope = node; } void Executer::executeVariable(TreeNode* node) { // //qDebug() << "called"; bool aValueIsNeeded = true; // no need to look up when assigning (in a for loop statement) if ((node->parent()->token()->type() == Token::ForTo) && (node->parent()->child(0)==node)) return; // we need to executeVariables in assignments for things like $x=$y to work if (node->parent()->token()->type() == Token::Assign) { // Test if we are in the LHS of the assignment if (node == node->parent()->child(0)) { // In this case we do not need to be initialized, we will get a value in executeAssign aValueIsNeeded = false; } } if (!functionStack.isEmpty() && functionStack.top().variableTable->contains(node->token()->look())) { // //qDebug() << "exists locally"; node->setValue( (*functionStack.top().variableTable)[node->token()->look()] ); } else if (globalVariableTable.contains(node->token()->look())) { // //qDebug() << "exists globally"; node->setValue(globalVariableTable[node->token()->look()]); } else if (aValueIsNeeded) { addError(i18n("The variable '%1' was used without first being assigned to a value", node->token()->look()), *node->token(), 0); } } void Executer::executeFunctionCall(TreeNode* node) { // //qDebug() << "called"; if (node->parent()->token()->type() == Token::Learn) { // in case we're defining a function currentNode = node->parent(); executeCurrent = true; return; } if (returning) { // if the function is already executed and returns now returnValue = 0; returning = false; // //qDebug() << "==> functionReturned!"; return; } if (!functionTable.contains(node->token()->look())) { addError(i18n("An unknown function named '%1' was called", node->token()->look()), *node->token(), 0); return; } CalledFunction c; c.function = node; c.variableTable = new VariableTable(); functionStack.push(c); // //qDebug() << "==> functionCalled!"; TreeNode* learnNode = functionTable[node->token()->look()]; // if the parameter numbers are not equal... if (node->childCount() != learnNode->child(1)->childCount()) { addError( i18n("The function '%1' was called with %2, while it should be called with %3", node->token()->look(), i18ncp("The function '%1' was called with %2, while it should be called with %3", "1 parameter", "%1 parameters", node->childCount()), i18ncp("The function '%1' was called with %2, while it should be called with %3", "1 parameter", "%1 parameters", learnNode->child(1)->childCount()) ), *node->token(), 0); return; } for (uint i = 0; i < node->childCount(); i++) { functionStack.top().variableTable->insert(learnNode->child(1)->child(i)->token()->look(), node->child(i)->value()); // //qDebug() << "inserted variable " << learnNode->child(1)->child(i)->token()->look() << " on function stack"; } newScope = learnNode->child(2); } void Executer::executeExit(TreeNode* node) { // //qDebug() << "called"; node = node; // stop the warnings finished = true; } void Executer::executeIf(TreeNode* node) { // //qDebug() << "called"; QString id = QString("__%1_%2").arg(node->token()->look()).arg((quintptr)node); if (currentVariableTable()->contains(id)) { currentVariableTable()->remove(id); return; } if (node->child(0)->value()->boolean()) { // store a empty Value just to know we executed once currentVariableTable()->insert(id, Value()); newScope = node->child(1); } else { if (node->childCount() >= 3) { currentVariableTable()->insert(id, Value()); newScope = node->child(2); // execute the else part } } } void Executer::executeElse(TreeNode* node) { // //qDebug() << "called"; execute(node->child(0)); // execute the scope, that's all... } void Executer::executeRepeat(TreeNode* node) { // //qDebug() << "called"; QString id = QString("__%1_%2").arg(node->token()->look()).arg((quintptr)node); if(breaking) { breaking = false; currentVariableTable()->remove(id); return; } // the iteration state is stored on the variable table if (currentVariableTable()->contains(id)) { - int currentCount = ROUND2INT((*currentVariableTable())[id].number()); + int currentCount = static_cast(round((*currentVariableTable())[id].number())); if (currentCount > 0) { (*currentVariableTable())[id].setNumber(currentCount - 1); } else { currentVariableTable()->remove(id); return; } } else { - if(ROUND2INT(node->child(0)->value()->number())<=0) // handle 'repeat 0' + if(static_cast(round(node->child(0)->value()->number()))<=0) // handle 'repeat 0' return; - currentVariableTable()->insert(id, Value((double)(ROUND2INT(node->child(0)->value()->number()) - 1))); + currentVariableTable()->insert(id, Value(round(node->child(0)->value()->number()) - 1.0)); } newScope = node->child(1); } void Executer::executeWhile(TreeNode* node) { // //qDebug() << "called"; // first time this gets called the expression is already executed // after one iteration the expression is not automatically re-executed. // so we do the following on every call to executeWhile: // exec scope, exec expression, exec scope, exec expression, ... QString id = QString("__%1_%2").arg(node->token()->look()).arg((quintptr)node); if (breaking) { // We hit a break command while executing the scope breaking = false; // Not breaking anymore currentVariableTable()->remove(id); // remove the value (cleanup) return; // Move to the next sibbling } if (currentVariableTable()->contains(id)) { newScope = node; // re-execute the expression currentVariableTable()->remove(id); return; } currentVariableTable()->insert(id, Value()); // store a empty Value just to know we executed once if (node->child(0)->value()->boolean()) newScope = node->child(1); // (re-)execute the scope else currentVariableTable()->remove(id); // clean-up, keep currenNode on currentNode so the next sibling we be run next } void Executer::executeFor(TreeNode* node) { // //qDebug() << "called"; qCritical("Executer::executeFor(): should have been translated to Token::ForTo by the parser"); node = node; // stop the warnings } void Executer::executeForTo(TreeNode* node) { // //qDebug() << "called"; // first time this gets called the expressions are already executed // after one iteration the expression is not re-executed. // so we do: exec scope, exec expressions, exec scope, exec expressions, ... //TODO: We have the cleanup part twice (after breaking and after the last iteration // perhaps clean it up by putting in in one place? bool firstIteration = false; if (functionStack.isEmpty() || functionStack.top().function != node) { // if this for loop is called for the first time... CalledFunction c; c.function = node; // TODO: Find a better solution then this for nested for loops //c.variableTable = new VariableTable(); c.variableTable = currentVariableTable(); functionStack.push(c); currentVariableTable()->insert(node->child(0)->token()->look(), Value(node->child(1)->value()->number())); firstIteration = true; } QString id = QString("__%1_%2").arg(node->token()->look()).arg((quintptr)node); if(breaking) { breaking = false; //delete functionStack.top().variableTable; functionStack.pop(); // if we don't delete the functionStack's varibleTable any more // do remove the for loops id.. currentVariableTable()->remove(id); return; } if (currentVariableTable()->contains(id)) { newScope = node; // re-execute the expressions currentVariableTable()->remove(id); return; } currentVariableTable()->insert(id, Value()); // store a empty Value just to know we executed once double currentCount = (*currentVariableTable())[node->child(0)->token()->look()].number(); double startCondition = node->child(1)->value()->number(); double endCondition = node->child(2)->value()->number(); double step = node->child(3)->value()->number(); if ((startCondition < endCondition && currentCount + step <= endCondition) || (startCondition > endCondition && currentCount + step >= endCondition && step<0) || //negative loop sanity check, is it implemented? (startCondition ==endCondition && firstIteration) ) { // for expressions like for $n=1 to 1 if (!firstIteration) (*currentVariableTable())[node->child(0)->token()->look()].setNumber(currentCount + step); newScope = node->child(4); // (re-)execute the scope } else { // cleaning up after last iteration... //delete functionStack.top().variableTable; functionStack.pop(); // if we don't delete the functionStack's varibleTable any more // do remove the for loops id.. currentVariableTable()->remove(id); } } void Executer::executeBreak(TreeNode* node) { // //qDebug() << "called"; if (!checkParameterQuantity(node, 0, 20000+Token::Break*100+90)) return; breaking = true; // Check for the first parent which is a repeat, while of for loop. // If found, switch the newScope to them so they can break. QList tokenTypes; tokenTypes.append(Token::Repeat); tokenTypes.append(Token::While); tokenTypes.append(Token::ForTo); TreeNode* ns = getParentOfTokenTypes(node, &tokenTypes); if(ns!=0) newScope = ns; //else // We could add an error right HERE // At the moment we just ignore a break when we couldn't // find a matching parent } void Executer::executeReturn(TreeNode* node) { // //qDebug() << "called"; if(node->childCount()>0) returnValue = node->child(0)->value(); else returnValue = 0; returning = true; } void Executer::executeWait(TreeNode* node) { // //qDebug() << "called"; if (!checkParameterQuantity(node, 1, 20000+Token::Wait*100+90)) return; if (!checkParameterType(node, Value::Number, 20000+Token::Wait*100+91) ) return; waiting = true; QTimer::singleShot((int)(1000*node->child(0)->value()->number()), this, SLOT(stopWaiting())); } void Executer::executeAssert(TreeNode* node) { // //qDebug() << "called"; if (!checkParameterQuantity(node, 1, 20000+Token::Wait*100+90)) return; if (!checkParameterType(node, Value::Bool, 20000+Token::Wait*100+91) ) return; if (!node->child(0)->value()->boolean()) addError(i18n("ASSERT failed"), *node->token(), 0); } void Executer::executeAnd(TreeNode* node) { // //qDebug() << "called"; //Niels: See 'Not' if(node->childCount()!=2) { addError(i18n("'And' needs two variables"), *node->token(), 0); return; } node->value()->setBool(node->child(0)->value()->boolean() && node->child(1)->value()->boolean()); } void Executer::executeOr(TreeNode* node) { // //qDebug() << "called"; //Niels: See 'Not' if(node->childCount()!=2) { addError(i18n("'Or' needs two variables"), *node->token(), 0); return; } node->value()->setBool(node->child(0)->value()->boolean() || node->child(1)->value()->boolean()); } void Executer::executeNot(TreeNode* node) { // //qDebug() << "called"; // OLD-TODO: maybe add some error handling here... //Niels: Ok, now we check if the node has children. Should we also check whether the child value is a boolean? if(node->childCount()!=1) { addError(i18n("I need something to do a not on"), *node->token(), 0); return; } node->value()->setBool(!node->child(0)->value()->boolean()); } void Executer::executeEquals(TreeNode* node) { // //qDebug() << "called"; if(node->childCount()!=2) { addError(i18n("I cannot do a '==' without 2 variables"), *node->token(), 0); return; } node->value()->setBool(*node->child(0)->value() == node->child(1)->value()); } void Executer::executeNotEquals(TreeNode* node) { // //qDebug() << "called"; if(node->childCount()!=2) { addError(i18n("I cannot do a '!=' without 2 variables"), *node->token(), 0); return; } node->value()->setBool(*node->child(0)->value() != node->child(1)->value()); } void Executer::executeGreaterThan(TreeNode* node) { // //qDebug() << "called"; if(node->childCount()!=2) { addError(i18n("I cannot do a '>' without 2 variables"), *node->token(), 0); return; } node->value()->setBool(*node->child(0)->value() > node->child(1)->value()); } void Executer::executeLessThan(TreeNode* node) { // //qDebug() << "called"; if(node->childCount()!=2) { addError(i18n("I cannot do a '<' without 2 variables"), *node->token(), 0); return; } node->value()->setBool(*node->child(0)->value() < node->child(1)->value()); } void Executer::executeGreaterOrEquals(TreeNode* node) { // //qDebug() << "called"; if(node->childCount()!=2) { addError(i18n("I cannot do a '>=' without 2 variables"), *node->token(), 0); return; } node->value()->setBool(*node->child(0)->value() >= node->child(1)->value()); } void Executer::executeLessOrEquals(TreeNode* node) { // //qDebug() << "called"; if(node->childCount()!=2) { addError(i18n("I cannot do a '<=' without 2 variables"), *node->token(), 0); return; } node->value()->setBool(*node->child(0)->value() <= node->child(1)->value()); } void Executer::executeAddition(TreeNode* node) { // //qDebug() << "called"; if(node->childCount()!=2) { addError(i18n("You need two numbers or string to do an addition"), *node->token(), 0); return; } if (node->child(0)->value()->type() == Value::Number && node->child(1)->value()->type() == Value::Number) { node->value()->setNumber(node->child(0)->value()->number() + node->child(1)->value()->number()); } else { node->value()->setString(node->child(0)->value()->string().append(node->child(1)->value()->string())); } } void Executer::executeSubstracton(TreeNode* node) { // //qDebug() << "called"; if(node->childCount()!=2) { addError(i18n("You need two numbers to subtract"), *node->token(), 0); return; } if (node->child(0)->value()->type() == Value::Number && node->child(1)->value()->type() == Value::Number) { node->value()->setNumber(node->child(0)->value()->number() - node->child(1)->value()->number()); } else { if (node->child(0)->value()->type() != Value::Number) addError(i18n("You tried to subtract from a non-number, '%1'", node->child(0)->token()->look()), *node->token(), 0); if (node->child(1)->value()->type() != Value::Number) addError(i18n("You tried to subtract a non-number, '%1'", node->child(1)->token()->look()), *node->token(), 0); } } void Executer::executeMultiplication(TreeNode* node) { // //qDebug() << "called"; if(node->childCount()!=2) { addError(i18n("You need two numbers to multiplicate"), *node->token(), 0); return; } if (node->child(0)->value()->type() == Value::Number && node->child(1)->value()->type() == Value::Number) { node->value()->setNumber(node->child(0)->value()->number() * node->child(1)->value()->number()); } else { if (node->child(0)->value()->type() != Value::Number) addError(i18n("You tried to multiplicate a non-number, '%1'", node->child(0)->token()->look()), *node->token(), 0); if (node->child(1)->value()->type() != Value::Number) addError(i18n("You tried to multiplicate by a non-number, '%1'", node->child(1)->token()->look()), *node->token(), 0); } } void Executer::executeDivision(TreeNode* node) { // //qDebug() << "called"; if(node->childCount()!=2) { addError(i18n("You need two numbers to divide"), *node->token(), 0); return; } if (node->child(0)->value()->type() == Value::Number && node->child(1)->value()->type() == Value::Number) { if(node->child(1)->value()->number()==0) { addError(i18n("You tried to divide by zero"), *node->token(), 0); return; } node->value()->setNumber(node->child(0)->value()->number() / node->child(1)->value()->number()); } else { if (node->child(0)->value()->type() != Value::Number) addError(i18n("You tried to divide a non-number, '%1'", node->child(0)->token()->look()), *node->token(), 0); if (node->child(1)->value()->type() != Value::Number) addError(i18n("You tried to divide by a non-number, '%1'", node->child(1)->token()->look()), *node->token(), 0); } } void Executer::executePower(TreeNode* node) { // //qDebug() << "called"; if(node->childCount()!=2) { addError(i18n("You need two numbers to raise a power"), *node->token(), 0); return; } if (node->child(0)->value()->type() == Value::Number && node->child(1)->value()->type() == Value::Number) { node->value()->setNumber(pow(node->child(0)->value()->number(), node->child(1)->value()->number())); double result = pow(node->child(0)->value()->number(), node->child(1)->value()->number()); int error = errno; if(error==ERANGE) { node->value()->setNumber(0); addError(i18n("The result of an exponentiation was too large"), *node->token(), 0); }else{ node->value()->setNumber(result); } } else { if (node->child(0)->value()->type() != Value::Number) addError(i18n("You tried to raise a non-number to a power, '%1'", node->child(0)->token()->look()), *node->token(), 0); if (node->child(1)->value()->type() != Value::Number) addError(i18n("You tried to raise the power of a non-number, '%1'", node->child(1)->token()->look()), *node->token(), 0); } } void Executer::executeAssign(TreeNode* node) { // //qDebug() << "called"; if(node->childCount()!=2) { addError(i18n("You need one variable and a value or variable to do a '='"), *node->token(), 0); return; } if (!functionStack.isEmpty() && !globalVariableTable.contains(node->child(0)->token()->look())) // &&functionStack.top().variableTable->contains(node->token()->look())) { // //qDebug() << "function scope"; functionStack.top().variableTable->insert(node->child(0)->token()->look(), node->child(1)->value()); } else { // inserts unless already exists then replaces globalVariableTable.insert(node->child(0)->token()->look(), node->child(1)->value()); } // //qDebug() << "variableTable updated!"; emit variableTableUpdated(node->child(0)->token()->look(), node->child(1)->value()); } void Executer::executeLearn(TreeNode* node) { // //qDebug() << "called"; if(functionTable.contains(node->child(0)->token()->look())) { addError(i18n("The function '%1' is already defined.", node->child(0)->token()->look()), *node->token(), 0); return; } functionTable.insert(node->child(0)->token()->look(), node); // //qDebug() << "functionTable updated!"; QStringList parameters; for (uint i = 0; i < node->child(1)->childCount(); i++) parameters << node->child(1)->child(i)->token()->look(); emit functionTableUpdated(node->child(0)->token()->look(), parameters); } void Executer::executeArgumentList(TreeNode* node) { // //qDebug() << "called"; node = node; // stop the warnings // this is a stud } void Executer::executeReset(TreeNode* node) { // //qDebug() << "called"; if (!checkParameterQuantity(node, 0, 20000+Token::Reset*100+90)) return; emit reset(); } void Executer::executeClear(TreeNode* node) { // //qDebug() << "called"; if (!checkParameterQuantity(node, 0, 20000+Token::Clear*100+90)) return; emit clear(); } void Executer::executeCenter(TreeNode* node) { // //qDebug() << "called"; if (!checkParameterQuantity(node, 0, 20000+Token::Center*100+90)) return; emit center(); } void Executer::executeGo(TreeNode* node) { // //qDebug() << "called"; if (!checkParameterQuantity(node, 2, 20000+Token::Go*100+90) || !checkParameterType(node, Value::Number, 20000+Token::Go*100+91)) return; emit go(node->child(0)->value()->number(), node->child(1)->value()->number()); } void Executer::executeGoX(TreeNode* node) { // //qDebug() << "called"; if (!checkParameterQuantity(node, 1, 20000+Token::GoX*100+90) || !checkParameterType(node, Value::Number, 20000+Token::GoX*100+91)) return; emit goX(node->child(0)->value()->number()); } void Executer::executeGoY(TreeNode* node) { // //qDebug() << "called"; if (!checkParameterQuantity(node, 1, 20000+Token::GoY*100+90) || !checkParameterType(node, Value::Number, 20000+Token::GoY*100+91)) return; emit goY(node->child(0)->value()->number()); } void Executer::executeForward(TreeNode* node) { // //qDebug() << "called"; if (!checkParameterQuantity(node, 1, 20000+Token::Forward*100+90) || !checkParameterType(node, Value::Number, 20000+Token::Forward*100+91)) return; emit forward(node->child(0)->value()->number()); } void Executer::executeBackward(TreeNode* node) { // //qDebug() << "called"; if (!checkParameterQuantity(node, 1, 20000+Token::Backward*100+90) || !checkParameterType(node, Value::Number, 20000+Token::Backward*100+91)) return; emit backward(node->child(0)->value()->number()); } void Executer::executeDirection(TreeNode* node) { // //qDebug() << "called"; if (!checkParameterQuantity(node, 1, 20000+Token::Direction*100+90) || !checkParameterType(node, Value::Number, 20000+Token::Direction*100+91)) return; emit direction(node->child(0)->value()->number()); } void Executer::executeTurnLeft(TreeNode* node) { // //qDebug() << "called"; if (!checkParameterQuantity(node, 1, 20000+Token::TurnLeft*100+90) || !checkParameterType(node, Value::Number, 20000+Token::TurnLeft*100+91)) return; emit turnLeft(node->child(0)->value()->number()); } void Executer::executeTurnRight(TreeNode* node) { // //qDebug() << "called"; if (!checkParameterQuantity(node, 1, 20000+Token::TurnRight*100+90) || !checkParameterType(node, Value::Number, 20000+Token::TurnRight*100+91)) return; emit turnRight(node->child(0)->value()->number()); } void Executer::executePenWidth(TreeNode* node) { // //qDebug() << "called"; if (!checkParameterQuantity(node, 1, 20000+Token::PenWidth*100+90) || !checkParameterType(node, Value::Number, 20000+Token::PenWidth*100+91)) return; emit penWidth(node->child(0)->value()->number()); } void Executer::executePenUp(TreeNode* node) { // //qDebug() << "called"; if (!checkParameterQuantity(node, 0, 20000+Token::PenUp*100+90)) return; emit penUp(); } void Executer::executePenDown(TreeNode* node) { // //qDebug() << "called"; if (!checkParameterQuantity(node, 0, 20000+Token::PenDown*100+90)) return; emit penDown(); } void Executer::executePenColor(TreeNode* node) { // //qDebug() << "called"; if (!checkParameterQuantity(node, 3, 20000+Token::PenColor*100+90) || !checkParameterType(node, Value::Number, 20000+Token::PenColor*100+91)) return; emit penColor(node->child(0)->value()->number(), node->child(1)->value()->number(), node->child(2)->value()->number()); } void Executer::executeCanvasColor(TreeNode* node) { // //qDebug() << "called"; if (!checkParameterQuantity(node, 3, 20000+Token::CanvasColor*100+90) || !checkParameterType(node, Value::Number, 20000+Token::CanvasColor*100+91)) return; emit canvasColor(node->child(0)->value()->number(), node->child(1)->value()->number(), node->child(2)->value()->number()); } void Executer::executeCanvasSize(TreeNode* node) { // //qDebug() << "called"; if (!checkParameterQuantity(node, 2, 20000+Token::CanvasSize*100+90) || !checkParameterType(node, Value::Number, 20000+Token::CanvasSize*100+91)) return; emit canvasSize(node->child(0)->value()->number(), node->child(1)->value()->number()); } void Executer::executeSpriteShow(TreeNode* node) { // //qDebug() << "called"; if (!checkParameterQuantity(node, 0, 20000+Token::SpriteShow*100+90)) return; emit spriteShow(); } void Executer::executeSpriteHide(TreeNode* node) { // //qDebug() << "called"; if (!checkParameterQuantity(node, 0, 20000+Token::SpriteHide*100+90)) return; emit spriteHide(); } void Executer::executePrint(TreeNode* node) { // //qDebug() << "called"; if (!checkParameterQuantity(node, 1, 20000+Token::Print*100+90)) return; // //qDebug() << "Printing: '" << node->child(0)->value()->string() << "'"; emit print(node->child(0)->value()->string()); } void Executer::executeFontSize(TreeNode* node) { // //qDebug() << "called"; if (!checkParameterQuantity(node, 1, 20000+Token::FontSize*100+90) || !checkParameterType(node, Value::Number, 20000+Token::FontSize*100+91)) return; emit fontSize(node->child(0)->value()->number()); } void Executer::executeRandom(TreeNode* node) { // //qDebug() << "called"; if (!checkParameterQuantity(node, 2, 20000+Token::Random*100+90)) return; TreeNode* nodeX = node->child(0); // getting TreeNode* nodeY = node->child(1); if (!checkParameterType(node, Value::Number, 20000+Token::Random*100+91)) return; double x = nodeX->value()->number(); double y = nodeY->value()->number(); double r = (double)(KRandom::random()) / RAND_MAX; node->value()->setNumber(r * (y - x) + x); } void Executer::executeGetX(TreeNode* node) { // //qDebug() << "called"; if (!checkParameterQuantity(node, 0, 20000+Token::GetX*100+90)) return; double value = 0; emit getX(value); node->value()->setNumber(value); } void Executer::executeGetY(TreeNode* node) { // //qDebug() << "called"; if (!checkParameterQuantity(node, 0, 20000+Token::GetY*100+90)) return; double value = 0; emit getY(value); node->value()->setNumber(value); } void Executer::executeMessage(TreeNode* node) { // //qDebug() << "called"; if (!checkParameterQuantity(node, 1, 20000+Token::Message*100+90)) return; emit message(node->child(0)->value()->string()); } void Executer::executeAsk(TreeNode* node) { // //qDebug() << "called"; if (!checkParameterQuantity(node, 1, 20000+Token::Ask*100+90)) return; QString value = node->child(0)->value()->string(); emit ask(value); bool convertOk; double d = value.toDouble(&convertOk); if(convertOk) node->value()->setNumber(d); else node->value()->setString(value); } void Executer::executePi(TreeNode* node) { // //qDebug() << "called"; node->value()->setNumber(M_PI); } void Executer::executeTan(TreeNode* node) { // //qDebug() << "called"; if (!checkParameterQuantity(node, 1, 20000+Token::Tan*100+90)) return; double deg = node->child(0)->value()->number(); - node->value()->setNumber(tan(DEG2RAD(deg))); + node->value()->setNumber(tan(qDegreesToRadians(deg))); } void Executer::executeSin(TreeNode* node) { // //qDebug() << "called"; if (!checkParameterQuantity(node, 1, 20000+Token::Sin*100+90)) return; double deg = node->child(0)->value()->number(); - node->value()->setNumber(sin(DEG2RAD(deg))); + node->value()->setNumber(sin(qDegreesToRadians(deg))); } void Executer::executeCos(TreeNode* node) { // //qDebug() << "called"; if (!checkParameterQuantity(node, 1, 20000+Token::Cos*100+90)) return; double deg = node->child(0)->value()->number(); - node->value()->setNumber(cos(DEG2RAD(deg))); + node->value()->setNumber(cos(qDegreesToRadians(deg))); } void Executer::executeArcTan(TreeNode* node) { // //qDebug() << "called"; if (!checkParameterQuantity(node, 1, 20000+Token::ArcTan*100+90)) return; double deg = node->child(0)->value()->number(); - node->value()->setNumber(RAD2DEG(atan(deg))); + node->value()->setNumber(qRadiansToDegrees(atan(deg))); } void Executer::executeArcSin(TreeNode* node) { // //qDebug() << "called"; if (!checkParameterQuantity(node, 1, 20000+Token::ArcSin*100+90)) return; double deg = node->child(0)->value()->number(); - node->value()->setNumber(RAD2DEG(asin(deg))); + node->value()->setNumber(qRadiansToDegrees(asin(deg))); } void Executer::executeArcCos(TreeNode* node) { // //qDebug() << "called"; if (!checkParameterQuantity(node, 1, 20000+Token::ArcCos*100+90)) return; double deg = node->child(0)->value()->number(); - node->value()->setNumber(RAD2DEG(acos(deg))); + node->value()->setNumber(qRadiansToDegrees(acos(deg))); } void Executer::executeSqrt(TreeNode* node) { // //qDebug() << "called"; if (!checkParameterQuantity(node, 1, 20000+Token::Sqrt*100+90)) return; double val = node->child(0)->value()->number(); if(val<0) { addError(i18n("Can't do a sqrt of a negative number"), *node->child(0)->token(), 0); node->value()->setNumber(0); return; } node->value()->setNumber(sqrt(val)); } void Executer::executeRound(TreeNode* node) { // //qDebug() << "called"; if (!checkParameterQuantity(node, 1, 20000+Token::Round*100+90)) return; double val = node->child(0)->value()->number(); - node->value()->setNumber((double)ROUND2INT(val)); + node->value()->setNumber(round(val)); } void Executer::executeGetDirection(TreeNode* node) { // //qDebug() << "called"; if (!checkParameterQuantity(node, 0, 20000+Token::GetDirection*100+90)) return; double value = 0; emit getDirection(value); node->value()->setNumber(value); } void Executer::executeMod(TreeNode* node) { // //qDebug() << "called"; if (!checkParameterQuantity(node, 2, 20000+Token::Mod*100+90)) return; TreeNode* nodeX = node->child(0); // getting TreeNode* nodeY = node->child(1); if (!checkParameterType(node, Value::Number, 20000+Token::Mod*100+91)) return; double x = nodeX->value()->number(); double y = nodeY->value()->number(); - double m = (double)(ROUND2INT(x) % ROUND2INT(y)); + double m = (double)(static_cast(round(x)) % static_cast(round(y))); node->value()->setNumber(m); } //END GENERATED executer_cpp CODE TreeNode* Executer::getParentOfTokenTypes(TreeNode* child, QList* types) { foreach(int type, *types) { if(child->parent()->token()->type()==type) return child->parent(); else if(child->parent()->token()->type()==Token::Root) return 0; } return getParentOfTokenTypes(child->parent(), types); } void Executer::printExe() { // if (currentNode->token()->type() != Token::Scope) // //qDebug() << "EXE> " << qPrintable(currentNode->token()->look()); }