<commit_before>/* mainwindow.cpp
 * code for the main application window, actions, etc. */

#include <QDesktopServices>
#include <QDesktopWidget>
#include <QFileDialog>
#include <QInputDialog>
#include <QMdiArea>
#include <QMdiSubWindow>
#include <QMessageBox>
#include <QPainter>
#include <QPrintDialog>
#include <QPrinter>
#include <QScrollBar>
#include <QSignalMapper>
#include <QSize>
#include <QTabWidget>
#include <QThread>
#include <QtCore>

#include "mainwindow.h"
#include "settingsdialog.h"
#include "settingsmanager.h"
#include "editor.h"
#include "ui_mainwindow.h"
#include "ui_about.h"

MainWindow::MainWindow(QWidget* parent) : QMainWindow(parent), ui(new Ui::MainWindow) {
    /* set the menu bar to work natively for systems with global bars */
    menuBar()->setNativeMenuBar(true);

    /* set up the ui elements for the window */
    ui->setupUi(this);

    /* set the title and icon */
    setWindowTitle(tr("Tetra [*]"));
    setWindowIcon(QIcon(":/icons/resources/icons/logo.svg"));

    /* set up the key shortcuts for the program */
    setupShortcuts();

    /* set up the thread and file runner for running programs */
    tetraThread = new QThread;
    fileRunner = new FileRunner(this);
    mainValue = 0;

    /* set up the status bar */
    statusBar()->showMessage("Ready.");
    coords = new QLabel("");
    statusBar()->addPermanentWidget(coords);
    updateCoordinates();

    /* set the tab bar in "document mode" and give the tab no name */
    ui->tabBar->setDocumentMode(true);
    ui->tabBar->setTabText(0, "Unsaved");

    /* set these as disabled (they are enabled dynamically */
    ui->actionCut->setEnabled(false);
    ui->actionCopy->setEnabled(false);
    ui->actionRedo->setEnabled(false);
    ui->actionUndo->setEnabled(false);

    /* set up connections of signals with the current editor */
    currentEditor()->setUpConnections(this);

    qRegisterMetaType<QTextBlock>("QTextBlock");
    qRegisterMetaType<QTextCursor>("QTextCursor");

    /* set up running so we know when we are done */
    connect(fileRunner, SIGNAL(finished()), this, SLOT(exitRunMode()));
}

MainWindow::~MainWindow() {
    delete ui;
}

void MainWindow::setupShortcuts() {
    ui->actionNew->setShortcuts(QKeySequence::New);
    ui->actionOpen->setShortcuts(QKeySequence::Open);
    ui->actionSave->setShortcuts(QKeySequence::Save);
    ui->actionSave_As->setShortcuts(QKeySequence::SaveAs);
    ui->actionPrint->setShortcuts(QKeySequence::Print);
    ui->actionClose->setShortcuts(QKeySequence::Close);
    ui->actionQuit->setShortcuts(QKeySequence::Quit);

    ui->actionFind->setShortcuts(QKeySequence::Find);
    ui->actionReplace->setShortcuts(QKeySequence::Replace);
    ui->actionCut->setShortcuts(QKeySequence::Cut);
    ui->actionCopy->setShortcuts(QKeySequence::Copy);
    ui->actionPaste->setShortcuts(QKeySequence::Paste);
    ui->actionRedo->setShortcuts(QKeySequence::Redo);
    ui->actionUndo->setShortcuts(QKeySequence::Undo);

    ui->actionDocumentation->setShortcuts(QKeySequence::HelpContents);
}

void MainWindow::closeEvent(QCloseEvent* event) {
    event->ignore();
    on_actionQuit_triggered();
}

QString MainWindow::getOpenFile() {
    return currentEditor()->getOpenFile();
}

// gives stripped name of file (removes file path)
QString MainWindow::strippedName(const QString& fullFileName) {
    return QFileInfo(fullFileName).fileName();
}

/* load an initial file e.g. as an open file */
void MainWindow::doOpen(QString fname) {
    Editor* newEditor = new Editor;
    newEditor->setUpConnections(this);
    if (newEditor->open(fname)) {
        /* if there is one tab which is empty and not modified, close it first */
        if (ui->tabBar->count() == 1 && currentEditor()->isEmpty()) {
            currentEditor()->close();
            ui->tabBar->removeTab(ui->tabBar->currentIndex());
        }

        QFileInfo info(fname);
        ui->tabBar->addTab(newEditor, info.fileName());
        ui->tabBar->setCurrentWidget(newEditor);
        updateTitle();
    } else {
        QMessageBox warning;
        warning.setText("Could not open file '" + fname + "'");
        warning.setIconPixmap(QPixmap(":/icons/resources/icons/dialog-warning.svg"));
        warning.exec();
    }
}

void MainWindow::documentWasModified() {
    if (ui->tabBar->count() == 1) {
        setWindowModified(currentEditor()->document()->isModified());
    } else {
        updateTitle();
    }
}

void MainWindow::updateCoordinates() {
    coords->setText(currentEditor()->getCoordinates());
    currentEditor()->ensureCursorVisible();
}

void MainWindow::on_actionNew_triggered() {
    Editor* newEditor = new Editor;
    newEditor->setUpConnections(this);
    ui->tabBar->addTab(newEditor, "Unsaved");
    ui->tabBar->setCurrentWidget(newEditor);
    updateTitle();
}

void MainWindow::on_actionClose_triggered() {
    if (currentEditor()->document()->isModified()) {
        QMessageBox msgBox;
        msgBox.setText("The file has been modified.");
        msgBox.setInformativeText("Do you want to save your changes?");
        msgBox.setIconPixmap(QPixmap(":/icons/resources/icons/dialog-question.svg"));
        msgBox.setStandardButtons(QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel);
        msgBox.setDefaultButton(QMessageBox::Save);
        switch (msgBox.exec()) {
            case QMessageBox::Save:
                /* try to save, if something goes wrong, bail */
                if (!currentEditor()->save()) {
                    return;
                }
                break;
            case QMessageBox::Discard:
                /* don't save! */
                break;
            case QMessageBox::Cancel:
                /* bail! */
                return;
        }
    }

    /* actually close the editor and tab */
    currentEditor()->close();
    ui->tabBar->removeTab(ui->tabBar->currentIndex());

    /* if that was the last tab, time to leave */
    if (ui->tabBar->count() == 0) {
        QApplication::quit();
    } else {
        updateTitle();
    }
}

void MainWindow::updateTitle() {
    QString full = currentEditor()->getOpenFile();
    QFileInfo info(full);

    if (full != "") {
        QString name = info.fileName();
        if (currentEditor()->document()->isModified()) {
            name += "*";
        }
        ui->tabBar->setTabText(ui->tabBar->currentIndex(), name);
    }

    if (ui->tabBar->count() == 1) {
        if (full != "") {
            setWindowTitle(info.fileName() + " [*]");
        } else {
            setWindowTitle("Tetra [*]");
        }
        setWindowModified(currentEditor()->document()->isModified());
    } else {
        setWindowTitle("Tetra [*]");
    }
}

void MainWindow::on_actionSave_triggered() {
    if (currentEditor()->save()) {
        updateTitle();
    }
}

void MainWindow::on_actionSave_As_triggered() {
    if (currentEditor()->saveas()) {
        updateTitle();
    }
}

void MainWindow::on_actionOpen_triggered() {
    QString fname = QFileDialog::getOpenFileName(this, tr("Open File"), "", "Tetra (*.ttr)");
    if (fname == "") {
        return;
    }

    doOpen(fname);
}

int MainWindow::on_actionPrint_triggered() {
    QPrinter printer;

    QPrintDialog* dialog = new QPrintDialog(&printer);
    dialog->setWindowTitle("Print Document");

    if (dialog->exec() != QDialog::Accepted) {
        return -1;
    }

    QPainter painter;
    painter.begin(&printer);
    QFont f = SettingsManager::font();
    painter.setFont(f);
    painter.drawText(100, 100, 500, 500, Qt::AlignLeft | Qt::AlignTop, currentEditor()->toPlainText());

    painter.end();
    return 0;
}

Editor* MainWindow::currentEditor() {
    return (Editor*)ui->tabBar->currentWidget();
}

void MainWindow::on_actionCut_triggered() {
    currentEditor()->cut();
}
void MainWindow::on_actionUndo_triggered() {
    currentEditor()->undo();
}
void MainWindow::on_actionQuit_triggered() {
    /* if there is one tab only, do a close */
    if (ui->tabBar->count() == 1) {
        on_actionClose_triggered();
    }

    /* check if there are unsaved tabs */
    int mod_count = 0;
    Editor* unsaved = NULL;
    for (int i = 0; i < ui->tabBar->count(); i++) {
        Editor* ed = (Editor*) ui->tabBar->widget(i);
        if (ed->document()->isModified()) {
            unsaved = ed;
            mod_count++;
        }
    }

    if (mod_count == 1) {
        QMessageBox msgBox;
        msgBox.setText("The file has been modified.");
        msgBox.setInformativeText("Do you want to save your changes?");
        msgBox.setIconPixmap(QPixmap(":/icons/resources/icons/dialog-question.svg"));
        msgBox.setStandardButtons(QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel);
        msgBox.setDefaultButton(QMessageBox::Save);
        switch (msgBox.exec()) {
            case QMessageBox::Save:
                /* try to save, if something goes wrong, bail */
                if (!unsaved->save()) {
                    return;
                }
                break;
            case QMessageBox::Discard:
                /* don't save! */
                break;
            case QMessageBox::Cancel:
                /* bail! */
                return;
        }
    } else if (mod_count > 1) {
        QMessageBox msgBox;
        msgBox.setText("Files have been modified.");
        msgBox.setInformativeText("Do you want to save all changes?");
        msgBox.setIconPixmap(QPixmap(":/icons/resources/icons/dialog-question.svg"));
        msgBox.setStandardButtons(QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel);
        msgBox.setDefaultButton(QMessageBox::Save);
        switch (msgBox.exec()) {
            case QMessageBox::Save:
                for (int i = 0; i < ui->tabBar->count(); i++) {
                    Editor* ed = (Editor*) ui->tabBar->widget(i);
                    if (!ed->save()) {
                        return;
                    }
                    break;
                }
            case QMessageBox::Discard:
                /* don't save! */
                break;
            case QMessageBox::Cancel:
                /* bail! */
                return;
        }
    }

    QApplication::quit();
}

void MainWindow::on_actionRedo_triggered() {
    currentEditor()->redo();
}
void MainWindow::on_actionCopy_triggered() {
    currentEditor()->copy();
}
void MainWindow::on_actionPaste_triggered() {
    currentEditor()->paste();
}

void MainWindow::on_actionFind_triggered() {
    QMessageBox msgBox;
    msgBox.setText("TODO");
    msgBox.exec();
}

/* help and about functions */
void MainWindow::on_actionAbout_Tetra_triggered() {
    QDialog* about = new QDialog(0, 0);
    Ui_About about_ui;
    about_ui.setupUi(about);
    about->show();
}

void MainWindow::on_actionSettings_triggered() {
    SettingsDialog* prefs = new SettingsDialog(this);
    prefs->exec();

    /* update the settings of all open editors */
    for (int i = 0; i < ui->tabBar->count(); i++) {
        Editor* ed = (Editor*) ui->tabBar->widget(i);
        ed->updateSettings();
    }

    /* update the settings for the console */
    ui->console->updateSettings();
}

void MainWindow::on_actionDocumentation_triggered() {
    QDesktopServices::openUrl(QUrl("http://tetra-lang.org/ide-reference"));
}

/* run and debug functions */
void MainWindow::on_actionDebug_triggered() {
    QMessageBox msgBox;
    msgBox.setText("TODO");
    msgBox.exec();
}

void MainWindow::receiveOutput(QString text) {
    ui->console->write(text);
}

void MainWindow::on_actionRun_triggered() {
    /* if it's not saved, we can't run */
    if (currentEditor()->save()) {
        updateTitle();
    } else {
        return;
    }

    /* make sure the bottom dock is shown */
    ui->dock->show();
    ui->console->document()->setPlainText("");

    /* disable run again */
    ui->actionRun->setDisabled(true);
    statusBar()->showMessage("Running.");

    /* start the worker thread which runs the programs */
    fileRunner->moveToThread(tetraThread);
    tetraThread->start();
    QMetaObject::invokeMethod(fileRunner, "runFile", Qt::QueuedConnection, Q_ARG(bool,false));
}

/* we were requested to get input from the running program */
void MainWindow::getInput() {
    bool ok;
    QString text;
    do {
        text = QInputDialog::getText(this, tr("Enter Input"), tr("Enter Input"), QLineEdit::Normal, "", &ok);
    } while (!ok);

    qDebug() << "main sees input as " << text << "\n";
    fileRunner->receiveInput(text);
}

/* finish running this */
void MainWindow::exitRunMode(){
    tetraThread->wait();
    ui->actionRun->setEnabled(true);
    statusBar()->showMessage("Ready.");
}

/* debugger functions */
void MainWindow::on_actionStep_triggered() {
    QMessageBox msgBox;
    msgBox.setText("TODO");
    msgBox.exec();
}

void MainWindow::on_actionContinue_triggered() {
    QMessageBox msgBox;
    msgBox.setText("TODO");
    msgBox.exec();
}

void MainWindow::on_actionNext_triggered() {
    QMessageBox msgBox;
    msgBox.setText("TODO");
    msgBox.exec();
}

void MainWindow::on_actionStop_triggered() {
    QMessageBox msgBox;
    msgBox.setText("TODO");
    msgBox.exec();
}

<commit_msg>[IDE] squelch ugly debug message<commit_after>/* mainwindow.cpp
 * code for the main application window, actions, etc. */

#include <QDesktopServices>
#include <QDesktopWidget>
#include <QFileDialog>
#include <QInputDialog>
#include <QMdiArea>
#include <QMdiSubWindow>
#include <QMessageBox>
#include <QPainter>
#include <QPrintDialog>
#include <QPrinter>
#include <QScrollBar>
#include <QSignalMapper>
#include <QSize>
#include <QTabWidget>
#include <QThread>
#include <QtCore>

#include "mainwindow.h"
#include "settingsdialog.h"
#include "settingsmanager.h"
#include "editor.h"
#include "ui_mainwindow.h"
#include "ui_about.h"

MainWindow::MainWindow(QWidget* parent) : QMainWindow(parent), ui(new Ui::MainWindow) {
    /* set the menu bar to work natively for systems with global bars */
    menuBar()->setNativeMenuBar(true);

    /* set up the ui elements for the window */
    ui->setupUi(this);

    /* set the title and icon */
    setWindowTitle(tr("Tetra [*]"));
    setWindowIcon(QIcon(":/icons/resources/icons/logo.svg"));

    /* set up the key shortcuts for the program */
    setupShortcuts();

    /* set up the thread and file runner for running programs */
    tetraThread = new QThread;
    fileRunner = new FileRunner(this);
    mainValue = 0;

    /* set up the status bar */
    statusBar()->showMessage("Ready.");
    coords = new QLabel("");
    statusBar()->addPermanentWidget(coords);
    updateCoordinates();

    /* set the tab bar in "document mode" and give the tab no name */
    ui->tabBar->setDocumentMode(true);
    ui->tabBar->setTabText(0, "Unsaved");

    /* set these as disabled (they are enabled dynamically */
    ui->actionCut->setEnabled(false);
    ui->actionCopy->setEnabled(false);
    ui->actionRedo->setEnabled(false);
    ui->actionUndo->setEnabled(false);

    /* set up connections of signals with the current editor */
    currentEditor()->setUpConnections(this);

    qRegisterMetaType<QTextBlock>("QTextBlock");
    qRegisterMetaType<QTextCursor>("QTextCursor");

    /* set up running so we know when we are done */
    connect(fileRunner, SIGNAL(finished()), this, SLOT(exitRunMode()));
}

MainWindow::~MainWindow() {
    delete ui;
}

void MainWindow::setupShortcuts() {
    ui->actionNew->setShortcuts(QKeySequence::New);
    ui->actionOpen->setShortcuts(QKeySequence::Open);
    ui->actionSave->setShortcuts(QKeySequence::Save);
    ui->actionSave_As->setShortcuts(QKeySequence::SaveAs);
    ui->actionPrint->setShortcuts(QKeySequence::Print);
    ui->actionClose->setShortcuts(QKeySequence::Close);
    ui->actionQuit->setShortcuts(QKeySequence::Quit);

    ui->actionFind->setShortcuts(QKeySequence::Find);
    ui->actionReplace->setShortcuts(QKeySequence::Replace);
    ui->actionCut->setShortcuts(QKeySequence::Cut);
    ui->actionCopy->setShortcuts(QKeySequence::Copy);
    ui->actionPaste->setShortcuts(QKeySequence::Paste);
    ui->actionRedo->setShortcuts(QKeySequence::Redo);
    ui->actionUndo->setShortcuts(QKeySequence::Undo);

    ui->actionDocumentation->setShortcuts(QKeySequence::HelpContents);
}

void MainWindow::closeEvent(QCloseEvent* event) {
    event->ignore();
    on_actionQuit_triggered();
}

QString MainWindow::getOpenFile() {
    return currentEditor()->getOpenFile();
}

// gives stripped name of file (removes file path)
QString MainWindow::strippedName(const QString& fullFileName) {
    return QFileInfo(fullFileName).fileName();
}

/* load an initial file e.g. as an open file */
void MainWindow::doOpen(QString fname) {
    Editor* newEditor = new Editor;
    newEditor->setUpConnections(this);
    if (newEditor->open(fname)) {
        /* if there is one tab which is empty and not modified, close it first */
        if (ui->tabBar->count() == 1 && currentEditor()->isEmpty()) {
            currentEditor()->close();
            ui->tabBar->removeTab(ui->tabBar->currentIndex());
        }

        QFileInfo info(fname);
        ui->tabBar->addTab(newEditor, info.fileName());
        ui->tabBar->setCurrentWidget(newEditor);
        updateTitle();
    } else {
        QMessageBox warning;
        warning.setText("Could not open file '" + fname + "'");
        warning.setIconPixmap(QPixmap(":/icons/resources/icons/dialog-warning.svg"));
        warning.exec();
    }
}

void MainWindow::documentWasModified() {
    if (ui->tabBar->count() == 1) {
        setWindowModified(currentEditor()->document()->isModified());
    } else {
        updateTitle();
    }
}

void MainWindow::updateCoordinates() {
    coords->setText(currentEditor()->getCoordinates());
    currentEditor()->ensureCursorVisible();
}

void MainWindow::on_actionNew_triggered() {
    Editor* newEditor = new Editor;
    newEditor->setUpConnections(this);
    ui->tabBar->addTab(newEditor, "Unsaved");
    ui->tabBar->setCurrentWidget(newEditor);
    updateTitle();
}

void MainWindow::on_actionClose_triggered() {
    if (currentEditor()->document()->isModified()) {
        QMessageBox msgBox;
        msgBox.setText("The file has been modified.");
        msgBox.setInformativeText("Do you want to save your changes?");
        msgBox.setIconPixmap(QPixmap(":/icons/resources/icons/dialog-question.svg"));
        msgBox.setStandardButtons(QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel);
        msgBox.setDefaultButton(QMessageBox::Save);
        switch (msgBox.exec()) {
            case QMessageBox::Save:
                /* try to save, if something goes wrong, bail */
                if (!currentEditor()->save()) {
                    return;
                }
                break;
            case QMessageBox::Discard:
                /* don't save! */
                break;
            case QMessageBox::Cancel:
                /* bail! */
                return;
        }
    }

    /* actually close the editor and tab */
    currentEditor()->close();
    ui->tabBar->removeTab(ui->tabBar->currentIndex());

    /* if that was the last tab, time to leave */
    if (ui->tabBar->count() == 0) {
        QApplication::quit();
    } else {
        updateTitle();
    }
}

void MainWindow::updateTitle() {
    QString full = currentEditor()->getOpenFile();
    QFileInfo info(full);

    if (full != "") {
        QString name = info.fileName();
        if (currentEditor()->document()->isModified()) {
            name += "*";
        }
        ui->tabBar->setTabText(ui->tabBar->currentIndex(), name);
    }

    if (ui->tabBar->count() == 1) {
        if (full != "") {
            setWindowTitle(info.fileName() + " [*]");
        } else {
            setWindowTitle("Tetra [*]");
        }
        setWindowModified(currentEditor()->document()->isModified());
    } else {
        setWindowTitle("Tetra [*]");
    }
}

void MainWindow::on_actionSave_triggered() {
    if (currentEditor()->save()) {
        updateTitle();
    }
}

void MainWindow::on_actionSave_As_triggered() {
    if (currentEditor()->saveas()) {
        updateTitle();
    }
}

void MainWindow::on_actionOpen_triggered() {
    QString fname = QFileDialog::getOpenFileName(this, tr("Open File"), "", "Tetra (*.ttr)");
    if (fname == "") {
        return;
    }

    doOpen(fname);
}

int MainWindow::on_actionPrint_triggered() {
    QPrinter printer;

    QPrintDialog* dialog = new QPrintDialog(&printer);
    dialog->setWindowTitle("Print Document");

    if (dialog->exec() != QDialog::Accepted) {
        return -1;
    }

    QPainter painter;
    painter.begin(&printer);
    QFont f = SettingsManager::font();
    painter.setFont(f);
    painter.drawText(100, 100, 500, 500, Qt::AlignLeft | Qt::AlignTop, currentEditor()->toPlainText());

    painter.end();
    return 0;
}

Editor* MainWindow::currentEditor() {
    return (Editor*)ui->tabBar->currentWidget();
}

void MainWindow::on_actionCut_triggered() {
    currentEditor()->cut();
}
void MainWindow::on_actionUndo_triggered() {
    currentEditor()->undo();
}
void MainWindow::on_actionQuit_triggered() {
    /* if there is one tab only, do a close */
    if (ui->tabBar->count() == 1) {
        on_actionClose_triggered();
    }

    /* check if there are unsaved tabs */
    int mod_count = 0;
    Editor* unsaved = NULL;
    for (int i = 0; i < ui->tabBar->count(); i++) {
        Editor* ed = (Editor*) ui->tabBar->widget(i);
        if (ed->document()->isModified()) {
            unsaved = ed;
            mod_count++;
        }
    }

    if (mod_count == 1) {
        QMessageBox msgBox;
        msgBox.setText("The file has been modified.");
        msgBox.setInformativeText("Do you want to save your changes?");
        msgBox.setIconPixmap(QPixmap(":/icons/resources/icons/dialog-question.svg"));
        msgBox.setStandardButtons(QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel);
        msgBox.setDefaultButton(QMessageBox::Save);
        switch (msgBox.exec()) {
            case QMessageBox::Save:
                /* try to save, if something goes wrong, bail */
                if (!unsaved->save()) {
                    return;
                }
                break;
            case QMessageBox::Discard:
                /* don't save! */
                break;
            case QMessageBox::Cancel:
                /* bail! */
                return;
        }
    } else if (mod_count > 1) {
        QMessageBox msgBox;
        msgBox.setText("Files have been modified.");
        msgBox.setInformativeText("Do you want to save all changes?");
        msgBox.setIconPixmap(QPixmap(":/icons/resources/icons/dialog-question.svg"));
        msgBox.setStandardButtons(QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel);
        msgBox.setDefaultButton(QMessageBox::Save);
        switch (msgBox.exec()) {
            case QMessageBox::Save:
                for (int i = 0; i < ui->tabBar->count(); i++) {
                    Editor* ed = (Editor*) ui->tabBar->widget(i);
                    if (!ed->save()) {
                        return;
                    }
                    break;
                }
            case QMessageBox::Discard:
                /* don't save! */
                break;
            case QMessageBox::Cancel:
                /* bail! */
                return;
        }
    }

    QApplication::quit();
}

void MainWindow::on_actionRedo_triggered() {
    currentEditor()->redo();
}
void MainWindow::on_actionCopy_triggered() {
    currentEditor()->copy();
}
void MainWindow::on_actionPaste_triggered() {
    currentEditor()->paste();
}

void MainWindow::on_actionFind_triggered() {
    QMessageBox msgBox;
    msgBox.setText("TODO");
    msgBox.exec();
}

/* help and about functions */
void MainWindow::on_actionAbout_Tetra_triggered() {
    QDialog* about = new QDialog(0, 0);
    Ui_About about_ui;
    about_ui.setupUi(about);
    about->show();
}

void MainWindow::on_actionSettings_triggered() {
    SettingsDialog* prefs = new SettingsDialog(this);
    prefs->exec();

    /* update the settings of all open editors */
    for (int i = 0; i < ui->tabBar->count(); i++) {
        Editor* ed = (Editor*) ui->tabBar->widget(i);
        ed->updateSettings();
    }

    /* update the settings for the console */
    ui->console->updateSettings();
}

void MainWindow::on_actionDocumentation_triggered() {
    QDesktopServices::openUrl(QUrl("http://tetra-lang.org/ide-reference"));
}

/* run and debug functions */
void MainWindow::on_actionDebug_triggered() {
    QMessageBox msgBox;
    msgBox.setText("TODO");
    msgBox.exec();
}

void MainWindow::receiveOutput(QString text) {
    ui->console->write(text);
}

void MainWindow::on_actionRun_triggered() {
    /* if it's not saved, we can't run */
    if (currentEditor()->save()) {
        updateTitle();
    } else {
        return;
    }

    /* make sure the bottom dock is shown */
    ui->dock->show();
    ui->console->document()->setPlainText("");

    /* disable run again */
    ui->actionRun->setDisabled(true);
    statusBar()->showMessage("Running.");

    /* start the worker thread which runs the programs */
    fileRunner->moveToThread(tetraThread);
    tetraThread->start();
    QMetaObject::invokeMethod(fileRunner, "runFile", Qt::QueuedConnection, Q_ARG(bool,false));
}

/* we were requested to get input from the running program */
void MainWindow::getInput() {
    bool ok;
    QString text;
    do {
        text = QInputDialog::getText(this, tr("Enter Input"), tr("Enter Input"), QLineEdit::Normal, "", &ok);
    } while (!ok);

    fileRunner->receiveInput(text);
}

/* finish running this */
void MainWindow::exitRunMode(){
    tetraThread->wait();
    ui->actionRun->setEnabled(true);
    statusBar()->showMessage("Ready.");
}

/* debugger functions */
void MainWindow::on_actionStep_triggered() {
    QMessageBox msgBox;
    msgBox.setText("TODO");
    msgBox.exec();
}

void MainWindow::on_actionContinue_triggered() {
    QMessageBox msgBox;
    msgBox.setText("TODO");
    msgBox.exec();
}

void MainWindow::on_actionNext_triggered() {
    QMessageBox msgBox;
    msgBox.setText("TODO");
    msgBox.exec();
}

void MainWindow::on_actionStop_triggered() {
    QMessageBox msgBox;
    msgBox.setText("TODO");
    msgBox.exec();
}

<|endoftext|>


<commit_before>// Copyright (c) 2018 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include <cassert>
#include <sstream>

#include "source/spirv_reducer_options.h"

#include "reducer.h"
#include "reduction_pass.h"

namespace spvtools {
namespace reduce {

struct Reducer::Impl {
  explicit Impl(spv_target_env env) : target_env(env) {}

  bool ReachedStepLimit(uint32_t current_step,
                        spv_const_reducer_options options);

  const spv_target_env target_env;  // Target environment.
  MessageConsumer consumer;         // Message consumer.
  InterestingnessFunction interestingness_function;
  std::vector<std::unique_ptr<ReductionPass>> passes;
};

Reducer::Reducer(spv_target_env env) : impl_(MakeUnique<Impl>(env)) {}

Reducer::~Reducer() = default;

void Reducer::SetMessageConsumer(MessageConsumer c) {
  for (auto& pass : impl_->passes) {
    pass->SetMessageConsumer(c);
  }
  impl_->consumer = std::move(c);
}

void Reducer::SetInterestingnessFunction(
    Reducer::InterestingnessFunction interestingness_function) {
  impl_->interestingness_function = std::move(interestingness_function);
}

Reducer::ReductionResultStatus Reducer::Run(
    std::vector<uint32_t>&& binary_in, std::vector<uint32_t>* binary_out,
    spv_const_reducer_options options) const {
  std::vector<uint32_t> current_binary = binary_in;

  // Keeps track of how many reduction attempts have been tried.  Reduction
  // bails out if this reaches a given limit.
  uint32_t reductions_applied = 0;

  // Initial state should be interesting.
  if (!impl_->interestingness_function(current_binary, reductions_applied)) {
    impl_->consumer(SPV_MSG_INFO, nullptr, {},
                    "Initial state was not interesting; stopping.");
    return Reducer::ReductionResultStatus::kInitialStateNotInteresting;
  }

  // Determines whether, on completing one round of reduction passes, it is
  // worthwhile trying a further round.
  bool another_round_worthwhile = true;

  // Apply round after round of reduction passes until we hit the reduction
  // step limit, or deem that another round is not going to be worthwhile.
  while (!impl_->ReachedStepLimit(reductions_applied, options) &&
         another_round_worthwhile) {
    // At the start of a round of reduction passes, assume another round will
    // not be worthwhile unless we find evidence to the contrary.
    another_round_worthwhile = false;

    // Iterate through the available passes
    for (auto& pass : impl_->passes) {
      // Keep applying this pass at its current granularity until it stops
      // working or we hit the reduction step limit.
      impl_->consumer(SPV_MSG_INFO, nullptr, {},
                      ("Trying pass " + pass->GetName() + ".").c_str());
      do {
        auto maybe_result = pass->TryApplyReduction(current_binary);
        if (maybe_result.empty()) {
          // This pass did not have any impact, so move on to the next pass.
          // If this pass hasn't reached its minimum granularity then it's
          // worth eventually doing another round of reductions, in order to
          // try this pass at a finer granularity.
          impl_->consumer(
              SPV_MSG_INFO, nullptr, {},
              ("Pass " + pass->GetName() + " did not make a reduction step.")
                  .c_str());
          another_round_worthwhile |= !pass->ReachedMinimumGranularity();
          break;
        }
        std::stringstream stringstream;
        reductions_applied++;
        stringstream << "Pass " << pass->GetName() << " made reduction step "
                     << reductions_applied << ".";
        impl_->consumer(SPV_MSG_INFO, nullptr, {},
                        (stringstream.str().c_str()));
        if (impl_->interestingness_function(maybe_result, reductions_applied)) {
          // Success!  The binary produced by this reduction step is
          // interesting, so make it the binary of interest henceforth, and
          // note that it's worth doing another round of reduction passes.
          impl_->consumer(SPV_MSG_INFO, nullptr, {},
                          "Reduction step succeeded.");
          current_binary = std::move(maybe_result);
          another_round_worthwhile = true;
        }
        // Bail out if the reduction step limit has been reached.
      } while (!impl_->ReachedStepLimit(reductions_applied, options));
    }
  }

  *binary_out = std::move(current_binary);

  // Report whether reduction completed, or bailed out early due to reaching
  // the step limit.
  if (impl_->ReachedStepLimit(reductions_applied, options)) {
    impl_->consumer(SPV_MSG_INFO, nullptr, {},
                    "Reached reduction step limit; stopping.");
    return Reducer::ReductionResultStatus::kReachedStepLimit;
  }
  impl_->consumer(SPV_MSG_INFO, nullptr, {}, "No more to reduce; stopping.");
  return Reducer::ReductionResultStatus::kComplete;
}

void Reducer::AddReductionPass(
    std::unique_ptr<ReductionPass>&& reduction_pass) {
  impl_->passes.push_back(std::move(reduction_pass));
}

bool Reducer::Impl::ReachedStepLimit(uint32_t current_step,
                                     spv_const_reducer_options options) {
  return current_step >= options->step_limit;
}

}  // namespace reduce
}  // namespace spvtools<commit_msg>Add newline at end of file (#2098)<commit_after>// Copyright (c) 2018 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include <cassert>
#include <sstream>

#include "source/spirv_reducer_options.h"

#include "reducer.h"
#include "reduction_pass.h"

namespace spvtools {
namespace reduce {

struct Reducer::Impl {
  explicit Impl(spv_target_env env) : target_env(env) {}

  bool ReachedStepLimit(uint32_t current_step,
                        spv_const_reducer_options options);

  const spv_target_env target_env;  // Target environment.
  MessageConsumer consumer;         // Message consumer.
  InterestingnessFunction interestingness_function;
  std::vector<std::unique_ptr<ReductionPass>> passes;
};

Reducer::Reducer(spv_target_env env) : impl_(MakeUnique<Impl>(env)) {}

Reducer::~Reducer() = default;

void Reducer::SetMessageConsumer(MessageConsumer c) {
  for (auto& pass : impl_->passes) {
    pass->SetMessageConsumer(c);
  }
  impl_->consumer = std::move(c);
}

void Reducer::SetInterestingnessFunction(
    Reducer::InterestingnessFunction interestingness_function) {
  impl_->interestingness_function = std::move(interestingness_function);
}

Reducer::ReductionResultStatus Reducer::Run(
    std::vector<uint32_t>&& binary_in, std::vector<uint32_t>* binary_out,
    spv_const_reducer_options options) const {
  std::vector<uint32_t> current_binary = binary_in;

  // Keeps track of how many reduction attempts have been tried.  Reduction
  // bails out if this reaches a given limit.
  uint32_t reductions_applied = 0;

  // Initial state should be interesting.
  if (!impl_->interestingness_function(current_binary, reductions_applied)) {
    impl_->consumer(SPV_MSG_INFO, nullptr, {},
                    "Initial state was not interesting; stopping.");
    return Reducer::ReductionResultStatus::kInitialStateNotInteresting;
  }

  // Determines whether, on completing one round of reduction passes, it is
  // worthwhile trying a further round.
  bool another_round_worthwhile = true;

  // Apply round after round of reduction passes until we hit the reduction
  // step limit, or deem that another round is not going to be worthwhile.
  while (!impl_->ReachedStepLimit(reductions_applied, options) &&
         another_round_worthwhile) {
    // At the start of a round of reduction passes, assume another round will
    // not be worthwhile unless we find evidence to the contrary.
    another_round_worthwhile = false;

    // Iterate through the available passes
    for (auto& pass : impl_->passes) {
      // Keep applying this pass at its current granularity until it stops
      // working or we hit the reduction step limit.
      impl_->consumer(SPV_MSG_INFO, nullptr, {},
                      ("Trying pass " + pass->GetName() + ".").c_str());
      do {
        auto maybe_result = pass->TryApplyReduction(current_binary);
        if (maybe_result.empty()) {
          // This pass did not have any impact, so move on to the next pass.
          // If this pass hasn't reached its minimum granularity then it's
          // worth eventually doing another round of reductions, in order to
          // try this pass at a finer granularity.
          impl_->consumer(
              SPV_MSG_INFO, nullptr, {},
              ("Pass " + pass->GetName() + " did not make a reduction step.")
                  .c_str());
          another_round_worthwhile |= !pass->ReachedMinimumGranularity();
          break;
        }
        std::stringstream stringstream;
        reductions_applied++;
        stringstream << "Pass " << pass->GetName() << " made reduction step "
                     << reductions_applied << ".";
        impl_->consumer(SPV_MSG_INFO, nullptr, {},
                        (stringstream.str().c_str()));
        if (impl_->interestingness_function(maybe_result, reductions_applied)) {
          // Success!  The binary produced by this reduction step is
          // interesting, so make it the binary of interest henceforth, and
          // note that it's worth doing another round of reduction passes.
          impl_->consumer(SPV_MSG_INFO, nullptr, {},
                          "Reduction step succeeded.");
          current_binary = std::move(maybe_result);
          another_round_worthwhile = true;
        }
        // Bail out if the reduction step limit has been reached.
      } while (!impl_->ReachedStepLimit(reductions_applied, options));
    }
  }

  *binary_out = std::move(current_binary);

  // Report whether reduction completed, or bailed out early due to reaching
  // the step limit.
  if (impl_->ReachedStepLimit(reductions_applied, options)) {
    impl_->consumer(SPV_MSG_INFO, nullptr, {},
                    "Reached reduction step limit; stopping.");
    return Reducer::ReductionResultStatus::kReachedStepLimit;
  }
  impl_->consumer(SPV_MSG_INFO, nullptr, {}, "No more to reduce; stopping.");
  return Reducer::ReductionResultStatus::kComplete;
}

void Reducer::AddReductionPass(
    std::unique_ptr<ReductionPass>&& reduction_pass) {
  impl_->passes.push_back(std::move(reduction_pass));
}

bool Reducer::Impl::ReachedStepLimit(uint32_t current_step,
                                     spv_const_reducer_options options) {
  return current_step >= options->step_limit;
}

}  // namespace reduce
}  // namespace spvtools
<|endoftext|>


<commit_before>#include "syntaxanalyzer.h"
#include "lexicalanalyzer.h"

#include <QMetaType>

SyntaxAnalyzer::SyntaxAnalyzer(QObject *parent) :
	QObject(parent),
	m_lexicalAnalyzer(new LexicalAnalyzer(this)),
	m_exprCalculator(new ExprCalculator(this))
{
}

SyntaxAnalyzer::~SyntaxAnalyzer()
{
}

QString SyntaxAnalyzer::process(const QString &input)
{
	// perform lexical analyzis
	m_lexicalAnalyzer->parse(input);
	if (m_lexicalAnalyzer->lexeme().type == LexemeEol) {
		throw Exception(tr("Input is empty"));
	}

	// Process the command: const declaration, const function or expression
	return command();
}

// Command = ConstDeclaration | Expression | FuncDeclaration
QString SyntaxAnalyzer::command()
{
	QString result;

	// const declaration
	if (m_lexicalAnalyzer->lexeme().type == LexemeConst) {
		result = constDeclaration(); // result here is just a notification
		ensureNoMoreLexemes();
	}

	// func declaration
	else if (m_lexicalAnalyzer->lexeme().type == LexemeFunc) {
		result = functionDeclaration(); // result here is a notification too
		ensureNoMoreLexemes();
	}

	// expression
	else {
		RpnCodeThread codeThread = expression(); // convert expression to RPN
		ensureNoMoreLexemes();
		result = QString::number(m_exprCalculator->calculate(codeThread), 'f', 15); // calculate
	}

	return result;
}

// ConstDeclaration = 'const' Identifier '=' {Unary Op} Number
QString SyntaxAnalyzer::constDeclaration()
{
	// 'const'
	if (m_lexicalAnalyzer->lexeme().type != LexemeConst) {
		throw Exception(tr("Illegal constant declaration beginning"));
	}
	m_lexicalAnalyzer->nextLexeme();

	// Identifier
	if (m_lexicalAnalyzer->lexeme().type != LexemeIdentifier) {
		throw Exception(tr("Identifier after ‘const’ expected"));
	}
	QString constName = m_lexicalAnalyzer->lexeme().value;
	m_lexicalAnalyzer->nextLexeme();

	// '='
	if (m_lexicalAnalyzer->lexeme().type != LexemeEqual) {
		throw Exception(tr("Sign ‘=’ expected after identifier"));
	}
	m_lexicalAnalyzer->nextLexeme();

	// {UnaryOp}
	int signMultiplyer = 1;
	while (CheckLexeme::isUnaryOperation(m_lexicalAnalyzer->lexeme())) {
		if (m_lexicalAnalyzer->lexeme().type == LexemeMinus) {
			signMultiplyer *= -1;
		}
		m_lexicalAnalyzer->nextLexeme();
	}

	// Number
	if (m_lexicalAnalyzer->lexeme().type != LexemeNumber) {
		throw Exception(tr("Number after ‘=’ expected"));
	}
	Number constValue = number();
	m_lexicalAnalyzer->nextLexeme();

	// add constant to list
	m_exprCalculator->addConstant(constName, constValue);

	// return notification
	return tr("Constant ‘%1’ now means ‘%2’").arg(constName).arg(constValue);
}

// FunctionDeclaration = 'func' Indenifier '(' FormalArgument
//		{ ',' FormalArgument} ')' '=' Expression
QString SyntaxAnalyzer::functionDeclaration()
{
	/* Get function name */

	// 'func'
	if (m_lexicalAnalyzer->lexeme().type != LexemeFunc) {
		throw Exception(tr("Illegal function declaration beginning"));
	}
	m_lexicalAnalyzer->nextLexeme();

	// identifier
	if (m_lexicalAnalyzer->lexeme().type != LexemeIdentifier) {
		throw Exception(tr("Identifier after ‘func’ expected"));
	}
	QString functionName = m_lexicalAnalyzer->lexeme().value;
	m_lexicalAnalyzer->nextLexeme();

	/* Get formal arguments and save them to list */

	if (m_lexicalAnalyzer->lexeme().type != LexemeOpeningBracket) {
		throw Exception(tr("Opening bracket expected after function name"));
	}

	do {
		m_lexicalAnalyzer->nextLexeme();
		extractFormalArgument();
	} while (m_lexicalAnalyzer->lexeme().type == LexemeComma);

	if (m_lexicalAnalyzer->lexeme().type != LexemeClosingBracket) {
		throw Exception(tr("Closing bracket expected after formal arguments list"));
	}
	m_lexicalAnalyzer->nextLexeme();

	if (m_lexicalAnalyzer->lexeme().type != LexemeEqual) {
		throw Exception(tr("Equal sign expected after closing bracket"));
	}
	m_lexicalAnalyzer->nextLexeme();

	/* Parse the function body and save it */

	RpnFunction function;
	function.argumentsCount = m_workingParams.count();
	function.codeThread = expression();
	m_workingParams.clear();
	m_exprCalculator->addFunction(functionName, function);

	return tr("Function ‘%1’ is declared").arg(functionName);
}

// Expression = Summand {SummOperator Summand}
RpnCodeThread SyntaxAnalyzer::expression()
{
	/* Note, that exception will be thrown in factor(), multOperation(), etc if something's wrong. */

	RpnCodeThread result;

	// first obligatory summand
	RpnCodeThread operand = summand();
	result << operand;

	// {SummOperator Summand} section
	while (CheckLexeme::isSummOperation(m_lexicalAnalyzer->lexeme())) {
		RpnElement operation = summOperation();
		operand = summand();

		result << operand << operation;
	}

	return result;
}

// Function = Identifier'(' ActualArgument{ ',' ActualArgument}')'
RpnCodeThread SyntaxAnalyzer::function()
{
	RpnCodeThread result;

	// Get function name and ensure it is built in or user defined

	if (m_lexicalAnalyzer->lexeme().type != LexemeIdentifier) {
		throw Exception(tr("Function name expected"));
	}
	QString functionName = m_lexicalAnalyzer->lexeme().value;
	int formalArgumentsCount;
	if (m_exprCalculator->isFunction(functionName)) {
		formalArgumentsCount = m_exprCalculator->functionArgumentsCount(functionName);
	}
	else {
		throw Exception(tr("Undeclared function ‘%1’ call").arg(functionName));
	}
	m_lexicalAnalyzer->nextLexeme();

	if (m_lexicalAnalyzer->lexeme().type != LexemeOpeningBracket) {
		throw Exception(tr("Opening bracket expected"));
	}

	// Parse actual arguments and add them to tread.
	// Ensure their count equals formal arguments count
	int actualArgumentsCount = 0;
	do {
		m_lexicalAnalyzer->nextLexeme();
		result << expression();
		actualArgumentsCount++;
		if (actualArgumentsCount > formalArgumentsCount) {
			throw Exception(tr("Too many arguments in ‘%1’ function call").arg(functionName));
		}
	} while (m_lexicalAnalyzer->lexeme().type == LexemeComma);

	if (actualArgumentsCount != formalArgumentsCount) {
		throw Exception(tr("Not enough arguments in ‘%1’ function call").arg(functionName));
	}

	if (m_lexicalAnalyzer->lexeme().type != LexemeClosingBracket) {
		throw Exception(tr("Closing bracket expected"));
	}
	m_lexicalAnalyzer->nextLexeme();

	// Add to thread a function call element
	RpnElement functionCall;
	functionCall.type = RpnElementFunction;
	functionCall.value = functionName;
	result << functionCall;

	return result;
}

// Factor = (UnaryOp Factor) | (PowerBase ['^' Factor])
RpnCodeThread SyntaxAnalyzer::factor()
{
	RpnCodeThread result;

	// UnaryOp Factor
	if (CheckLexeme::isUnaryOperation(m_lexicalAnalyzer->lexeme())) {

		if (m_lexicalAnalyzer->lexeme().type == LexemeMinus) {

			m_lexicalAnalyzer->nextLexeme();

			// -A = (-1) * A
			RpnElement minusOne = {RpnElementOperand, -1};
			RpnElement multiply = {RpnElementFunction, QVariant::fromValue(RpnFunctionMultiply)};
			RpnCodeThread rightOperand = factor();

			result << minusOne << rightOperand << multiply;
		}

		else if (m_lexicalAnalyzer->lexeme().type == LexemePlus) {
			m_lexicalAnalyzer->nextLexeme();
			result = factor();
		}

		else {
			throw Exception(tr("Unsupported unary operation"));
		}
	}

	else {
		RpnCodeThread base = powerBase();
		result << base;

		// ['^' Factor]
		if (m_lexicalAnalyzer->lexeme().type == LexemePower) {
			RpnElement power = {RpnElementFunction, QVariant::fromValue(RpnFunctionPower)};
			m_lexicalAnalyzer->nextLexeme();
			RpnCodeThread exponent = factor();

			result << exponent << power;
		}
	}

	return result;
}

// PowerBase = Number | Constant | Function | '('Expression')'
RpnCodeThread SyntaxAnalyzer::powerBase()
{
	RpnCodeThread result;

	// Number
	if (m_lexicalAnalyzer->lexeme().type == LexemeNumber) {
		Number value = number();
		RpnElement element = {RpnElementOperand, value};
		result << element;
	}

	// Constant | Function
	else if (m_lexicalAnalyzer->lexeme().type == LexemeIdentifier) {
		// Constant
		m_lexicalAnalyzer->nextLexeme();
		if (m_lexicalAnalyzer->lexeme().type != LexemeOpeningBracket) {
			m_lexicalAnalyzer->previousLexeme();
			RpnElement element = constant();
			result << element;
		}
		// Function
		else {
			m_lexicalAnalyzer->previousLexeme();
			RpnCodeThread thread = function();
			result << thread;
		}
	}

	// '('Expression')'
	else if (m_lexicalAnalyzer->lexeme().type == LexemeOpeningBracket) {
		m_lexicalAnalyzer->nextLexeme();
		result = expression();

		if (m_lexicalAnalyzer->lexeme().type != LexemeClosingBracket) {
			throw Exception(tr("Closing bracket expected"));
		}

		m_lexicalAnalyzer->nextLexeme();
	}

	else {
		throw Exception(tr("Number or expression in brackets expected"));
	}

	return result;
}

// MultOperation = '*' | '/'
RpnElement SyntaxAnalyzer::multOperation()
{
	RpnElement result;
	result.type = RpnElementFunction;

	if (m_lexicalAnalyzer->lexeme().type == LexemeMultiply) {
		result.value.setValue(RpnFunctionMultiply);
	}
	else if(m_lexicalAnalyzer->lexeme().type == LexemeDivide) {
		result.value.setValue(RpnFunctionDivide);
	}
	else {
		throw Exception(tr("Multiplication operator expected"));
	}

	m_lexicalAnalyzer->nextLexeme();
	return result;
}

// Summand = Factor {MultOperator Factor}
RpnCodeThread SyntaxAnalyzer::summand()
{
	RpnCodeThread result;
	// first obligatory factor
	RpnCodeThread operand = factor();
	result << operand;

	// {MultOperation Factor} section
	while (CheckLexeme::isMultOperation(m_lexicalAnalyzer->lexeme())) {
		RpnElement operation = multOperation();
		operand = factor();

		result << operand << operation;
	}

	return result;
}

// SummOperation = '+' | '-'
RpnElement SyntaxAnalyzer::summOperation()
{
	RpnElement result;
	result.type = RpnElementFunction;

	if (m_lexicalAnalyzer->lexeme().type == LexemePlus) {
		result.value.setValue(RpnFunctionPlus);
	}
	else if(m_lexicalAnalyzer->lexeme().type == LexemeMinus) {
		result.value.setValue(RpnFunctionMinus);
	}
	else {
		throw Exception(tr("Summation operator expected"));
	}

	m_lexicalAnalyzer->nextLexeme();
	return result;
}

Number SyntaxAnalyzer::number()
{
	bool ok = false;
	Number result = m_lexicalAnalyzer->lexeme().value.toDouble(&ok);
	if (!ok) {
		throw Exception(tr("Cannot convert ‘%1’ to a number").arg(m_lexicalAnalyzer->lexeme().value));
	}
	m_lexicalAnalyzer->nextLexeme();
	return result;
}

// Constant = Identifier (formal arguments are processed here as well)
RpnElement SyntaxAnalyzer::constant()
{
	RpnElement result;
	QString constName = m_lexicalAnalyzer->lexeme().value;

	if (m_workingParams.contains(constName)) {
		// it is an argument
		result.type = RpnElementParam;
		result.value = m_workingParams.indexOf(constName);
	}

	else if (m_exprCalculator->isConstant(constName)) {
		result.type = RpnElementConstant;
		result.value = constName;
	}

	else {
		throw Exception(tr("Undeclared identifier ‘%1’").arg(constName));
	}

	m_lexicalAnalyzer->nextLexeme();
	return result;
}

// FormalArgument = Identifier
void SyntaxAnalyzer::extractFormalArgument()
{
	if (m_lexicalAnalyzer->lexeme().type != LexemeIdentifier) {
		throw Exception(tr("Identifier expected if argument list"));
	}

	QString argumentName = m_lexicalAnalyzer->lexeme().value;
	if (m_workingParams.contains(argumentName)) {
		throw Exception(tr("Argument ‘%1’ is already in the list").arg(argumentName));
	}
	m_workingParams.append(argumentName);

	m_lexicalAnalyzer->nextLexeme();
}

void SyntaxAnalyzer::ensureNoMoreLexemes()
{
	if (m_lexicalAnalyzer->lexeme().type != LexemeEol) {
	   throw Exception(tr("End of file expected"));
   }
}

bool CheckLexeme::isMultOperation(Lexeme lexeme)
{
	return ((lexeme.type == LexemeMultiply) || (lexeme.type == LexemeDivide));
}

bool CheckLexeme::isSummOperation(Lexeme lexeme)
{
	return ((lexeme.type == LexemePlus) || (lexeme.type == LexemeMinus));
}

bool CheckLexeme::isUnaryOperation(Lexeme lexeme)
{
	return ((lexeme.type == LexemePlus) || (lexeme.type == LexemeMinus));
}
<commit_msg>Constant expression can be now assigned to a constant, not just a number. In this way a constant can be even redeclared in such a way: const smth = smth/pi + 4. Certainly we assume that 'smth' was declared before.<commit_after>#include "syntaxanalyzer.h"
#include "lexicalanalyzer.h"

#include <QMetaType>

SyntaxAnalyzer::SyntaxAnalyzer(QObject *parent) :
	QObject(parent),
	m_lexicalAnalyzer(new LexicalAnalyzer(this)),
	m_exprCalculator(new ExprCalculator(this))
{
}

SyntaxAnalyzer::~SyntaxAnalyzer()
{
}

QString SyntaxAnalyzer::process(const QString &input)
{
	// perform lexical analyzis
	m_lexicalAnalyzer->parse(input);
	if (m_lexicalAnalyzer->lexeme().type == LexemeEol) {
		throw Exception(tr("Input is empty"));
	}

	// Process the command: const declaration, const function or expression
	return command();
}

// Command = ConstDeclaration | Expression | FuncDeclaration
QString SyntaxAnalyzer::command()
{
	QString result;

	// const declaration
	if (m_lexicalAnalyzer->lexeme().type == LexemeConst) {
		result = constDeclaration(); // result here is just a notification
		ensureNoMoreLexemes();
	}

	// func declaration
	else if (m_lexicalAnalyzer->lexeme().type == LexemeFunc) {
		result = functionDeclaration(); // result here is a notification too
		ensureNoMoreLexemes();
	}

	// expression
	else {
		RpnCodeThread codeThread = expression(); // convert expression to RPN
		ensureNoMoreLexemes();
		result = QString::number(m_exprCalculator->calculate(codeThread), 'f', 15); // calculate
	}

	return result;
}

// ConstDeclaration = 'const' Identifier '=' Expression
QString SyntaxAnalyzer::constDeclaration()
{
	// 'const'
	if (m_lexicalAnalyzer->lexeme().type != LexemeConst) {
		throw Exception(tr("Illegal constant declaration beginning"));
	}
	m_lexicalAnalyzer->nextLexeme();

	// Identifier
	if (m_lexicalAnalyzer->lexeme().type != LexemeIdentifier) {
		throw Exception(tr("Identifier after ‘const’ expected"));
	}
	QString constName = m_lexicalAnalyzer->lexeme().value;
	m_lexicalAnalyzer->nextLexeme();

	// '='
	if (m_lexicalAnalyzer->lexeme().type != LexemeEqual) {
		throw Exception(tr("Sign ‘=’ expected after identifier"));
	}
	m_lexicalAnalyzer->nextLexeme();

	// Expression
	RpnCodeThread constThread = expression();
	Number constValue = m_exprCalculator->calculate(constThread);
	m_lexicalAnalyzer->nextLexeme();

	// add constant to list
	m_exprCalculator->addConstant(constName, constValue);

	// return notification
	return tr("Constant ‘%1’ now means ‘%2’").arg(constName).arg(constValue);
}

// FunctionDeclaration = 'func' Indenifier '(' FormalArgument
//		{ ',' FormalArgument} ')' '=' Expression
QString SyntaxAnalyzer::functionDeclaration()
{
	/* Get function name */

	// 'func'
	if (m_lexicalAnalyzer->lexeme().type != LexemeFunc) {
		throw Exception(tr("Illegal function declaration beginning"));
	}
	m_lexicalAnalyzer->nextLexeme();

	// identifier
	if (m_lexicalAnalyzer->lexeme().type != LexemeIdentifier) {
		throw Exception(tr("Identifier after ‘func’ expected"));
	}
	QString functionName = m_lexicalAnalyzer->lexeme().value;
	m_lexicalAnalyzer->nextLexeme();

	/* Get formal arguments and save them to list */

	if (m_lexicalAnalyzer->lexeme().type != LexemeOpeningBracket) {
		throw Exception(tr("Opening bracket expected after function name"));
	}

	do {
		m_lexicalAnalyzer->nextLexeme();
		extractFormalArgument();
	} while (m_lexicalAnalyzer->lexeme().type == LexemeComma);

	if (m_lexicalAnalyzer->lexeme().type != LexemeClosingBracket) {
		throw Exception(tr("Closing bracket expected after formal arguments list"));
	}
	m_lexicalAnalyzer->nextLexeme();

	if (m_lexicalAnalyzer->lexeme().type != LexemeEqual) {
		throw Exception(tr("Equal sign expected after closing bracket"));
	}
	m_lexicalAnalyzer->nextLexeme();

	/* Parse the function body and save it */

	RpnFunction function;
	function.argumentsCount = m_workingParams.count();
	function.codeThread = expression();
	m_workingParams.clear();
	m_exprCalculator->addFunction(functionName, function);

	return tr("Function ‘%1’ is declared").arg(functionName);
}

// Expression = Summand {SummOperator Summand}
RpnCodeThread SyntaxAnalyzer::expression()
{
	/* Note, that exception will be thrown in factor(), multOperation(), etc if something's wrong. */

	RpnCodeThread result;

	// first obligatory summand
	RpnCodeThread operand = summand();
	result << operand;

	// {SummOperator Summand} section
	while (CheckLexeme::isSummOperation(m_lexicalAnalyzer->lexeme())) {
		RpnElement operation = summOperation();
		operand = summand();

		result << operand << operation;
	}

	return result;
}

// Function = Identifier'(' ActualArgument{ ',' ActualArgument}')'
RpnCodeThread SyntaxAnalyzer::function()
{
	RpnCodeThread result;

	// Get function name and ensure it is built in or user defined

	if (m_lexicalAnalyzer->lexeme().type != LexemeIdentifier) {
		throw Exception(tr("Function name expected"));
	}
	QString functionName = m_lexicalAnalyzer->lexeme().value;
	int formalArgumentsCount;
	if (m_exprCalculator->isFunction(functionName)) {
		formalArgumentsCount = m_exprCalculator->functionArgumentsCount(functionName);
	}
	else {
		throw Exception(tr("Undeclared function ‘%1’ call").arg(functionName));
	}
	m_lexicalAnalyzer->nextLexeme();

	if (m_lexicalAnalyzer->lexeme().type != LexemeOpeningBracket) {
		throw Exception(tr("Opening bracket expected"));
	}

	// Parse actual arguments and add them to tread.
	// Ensure their count equals formal arguments count
	int actualArgumentsCount = 0;
	do {
		m_lexicalAnalyzer->nextLexeme();
		result << expression();
		actualArgumentsCount++;
		if (actualArgumentsCount > formalArgumentsCount) {
			throw Exception(tr("Too many arguments in ‘%1’ function call").arg(functionName));
		}
	} while (m_lexicalAnalyzer->lexeme().type == LexemeComma);

	if (actualArgumentsCount != formalArgumentsCount) {
		throw Exception(tr("Not enough arguments in ‘%1’ function call").arg(functionName));
	}

	if (m_lexicalAnalyzer->lexeme().type != LexemeClosingBracket) {
		throw Exception(tr("Closing bracket expected"));
	}
	m_lexicalAnalyzer->nextLexeme();

	// Add to thread a function call element
	RpnElement functionCall;
	functionCall.type = RpnElementFunction;
	functionCall.value = functionName;
	result << functionCall;

	return result;
}

// Factor = (UnaryOp Factor) | (PowerBase ['^' Factor])
RpnCodeThread SyntaxAnalyzer::factor()
{
	RpnCodeThread result;

	// UnaryOp Factor
	if (CheckLexeme::isUnaryOperation(m_lexicalAnalyzer->lexeme())) {

		if (m_lexicalAnalyzer->lexeme().type == LexemeMinus) {

			m_lexicalAnalyzer->nextLexeme();

			// -A = (-1) * A
			RpnElement minusOne = {RpnElementOperand, -1};
			RpnElement multiply = {RpnElementFunction, QVariant::fromValue(RpnFunctionMultiply)};
			RpnCodeThread rightOperand = factor();

			result << minusOne << rightOperand << multiply;
		}

		else if (m_lexicalAnalyzer->lexeme().type == LexemePlus) {
			m_lexicalAnalyzer->nextLexeme();
			result = factor();
		}

		else {
			throw Exception(tr("Unsupported unary operation"));
		}
	}

	else {
		RpnCodeThread base = powerBase();
		result << base;

		// ['^' Factor]
		if (m_lexicalAnalyzer->lexeme().type == LexemePower) {
			RpnElement power = {RpnElementFunction, QVariant::fromValue(RpnFunctionPower)};
			m_lexicalAnalyzer->nextLexeme();
			RpnCodeThread exponent = factor();

			result << exponent << power;
		}
	}

	return result;
}

// PowerBase = Number | Constant | Function | '('Expression')'
RpnCodeThread SyntaxAnalyzer::powerBase()
{
	RpnCodeThread result;

	// Number
	if (m_lexicalAnalyzer->lexeme().type == LexemeNumber) {
		Number value = number();
		RpnElement element = {RpnElementOperand, value};
		result << element;
	}

	// Constant | Function
	else if (m_lexicalAnalyzer->lexeme().type == LexemeIdentifier) {
		// Constant
		m_lexicalAnalyzer->nextLexeme();
		if (m_lexicalAnalyzer->lexeme().type != LexemeOpeningBracket) {
			m_lexicalAnalyzer->previousLexeme();
			RpnElement element = constant();
			result << element;
		}
		// Function
		else {
			m_lexicalAnalyzer->previousLexeme();
			RpnCodeThread thread = function();
			result << thread;
		}
	}

	// '('Expression')'
	else if (m_lexicalAnalyzer->lexeme().type == LexemeOpeningBracket) {
		m_lexicalAnalyzer->nextLexeme();
		result = expression();

		if (m_lexicalAnalyzer->lexeme().type != LexemeClosingBracket) {
			throw Exception(tr("Closing bracket expected"));
		}

		m_lexicalAnalyzer->nextLexeme();
	}

	else {
		throw Exception(tr("Number or expression in brackets expected"));
	}

	return result;
}

// MultOperation = '*' | '/'
RpnElement SyntaxAnalyzer::multOperation()
{
	RpnElement result;
	result.type = RpnElementFunction;

	if (m_lexicalAnalyzer->lexeme().type == LexemeMultiply) {
		result.value.setValue(RpnFunctionMultiply);
	}
	else if(m_lexicalAnalyzer->lexeme().type == LexemeDivide) {
		result.value.setValue(RpnFunctionDivide);
	}
	else {
		throw Exception(tr("Multiplication operator expected"));
	}

	m_lexicalAnalyzer->nextLexeme();
	return result;
}

// Summand = Factor {MultOperator Factor}
RpnCodeThread SyntaxAnalyzer::summand()
{
	RpnCodeThread result;
	// first obligatory factor
	RpnCodeThread operand = factor();
	result << operand;

	// {MultOperation Factor} section
	while (CheckLexeme::isMultOperation(m_lexicalAnalyzer->lexeme())) {
		RpnElement operation = multOperation();
		operand = factor();

		result << operand << operation;
	}

	return result;
}

// SummOperation = '+' | '-'
RpnElement SyntaxAnalyzer::summOperation()
{
	RpnElement result;
	result.type = RpnElementFunction;

	if (m_lexicalAnalyzer->lexeme().type == LexemePlus) {
		result.value.setValue(RpnFunctionPlus);
	}
	else if(m_lexicalAnalyzer->lexeme().type == LexemeMinus) {
		result.value.setValue(RpnFunctionMinus);
	}
	else {
		throw Exception(tr("Summation operator expected"));
	}

	m_lexicalAnalyzer->nextLexeme();
	return result;
}

Number SyntaxAnalyzer::number()
{
	bool ok = false;
	Number result = m_lexicalAnalyzer->lexeme().value.toDouble(&ok);
	if (!ok) {
		throw Exception(tr("Cannot convert ‘%1’ to a number").arg(m_lexicalAnalyzer->lexeme().value));
	}
	m_lexicalAnalyzer->nextLexeme();
	return result;
}

// Constant = Identifier (formal arguments are processed here as well)
RpnElement SyntaxAnalyzer::constant()
{
	RpnElement result;
	QString constName = m_lexicalAnalyzer->lexeme().value;

	// it is a formal argument
	if (m_workingParams.contains(constName)) {
		result.type = RpnElementParam;
		result.value = m_workingParams.indexOf(constName);
	}

	// it is a constant
	else if (m_exprCalculator->isConstant(constName)) {
		result.type = RpnElementConstant;
		result.value = constName;
	}

	else {
		throw Exception(tr("Undeclared identifier ‘%1’").arg(constName));
	}

	m_lexicalAnalyzer->nextLexeme();
	return result;
}

// FormalArgument = Identifier
void SyntaxAnalyzer::extractFormalArgument()
{
	if (m_lexicalAnalyzer->lexeme().type != LexemeIdentifier) {
		throw Exception(tr("Identifier expected if argument list"));
	}

	QString argumentName = m_lexicalAnalyzer->lexeme().value;
	if (m_workingParams.contains(argumentName)) {
		throw Exception(tr("Argument ‘%1’ is already in the list").arg(argumentName));
	}
	m_workingParams.append(argumentName);

	m_lexicalAnalyzer->nextLexeme();
}

void SyntaxAnalyzer::ensureNoMoreLexemes()
{
	if (m_lexicalAnalyzer->lexeme().type != LexemeEol) {
	   throw Exception(tr("End of file expected"));
   }
}

bool CheckLexeme::isMultOperation(Lexeme lexeme)
{
	return ((lexeme.type == LexemeMultiply) || (lexeme.type == LexemeDivide));
}

bool CheckLexeme::isSummOperation(Lexeme lexeme)
{
	return ((lexeme.type == LexemePlus) || (lexeme.type == LexemeMinus));
}

bool CheckLexeme::isUnaryOperation(Lexeme lexeme)
{
	return ((lexeme.type == LexemePlus) || (lexeme.type == LexemeMinus));
}
<|endoftext|>


<commit_before>// stdafx.cpp : source file that includes just the standard includes
// Scrub Cup Work.pch will be the pre-compiled header
// stdafx.obj will contain the pre-compiled type information

#include "stdafx.h"

// TODO: reference any additional headers you need in STDAFX.H
// and not in this file
<commit_msg>Delete stdafx.cpp<commit_after><|endoftext|>


<commit_before>/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * This file incorporates work covered by the following license notice:
 *
 *   Licensed to the Apache Software Foundation (ASF) under one or more
 *   contributor license agreements. See the NOTICE file distributed
 *   with this work for additional information regarding copyright
 *   ownership. The ASF licenses this file to you under the Apache
 *   License, Version 2.0 (the "License"); you may not use this file
 *   except in compliance with the License. You may obtain a copy of
 *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
 */

#include "XMLIndexBibliographyEntryContext.hxx"
#include "XMLIndexTemplateContext.hxx"
#include <xmloff/xmlictxt.hxx>
#include <xmloff/xmlimp.hxx>
#include <xmloff/txtimp.hxx>
#include <xmloff/nmspmap.hxx>
#include "xmloff/xmlnmspe.hxx"
#include <xmloff/xmltoken.hxx>
#include <xmloff/xmluconv.hxx>
#include <com/sun/star/text/BibliographyDataField.hpp>

using namespace ::com::sun::star::text;
using namespace ::xmloff::token;

using ::com::sun::star::beans::PropertyValue;
using ::com::sun::star::beans::PropertyValues;
using ::com::sun::star::uno::Reference;
using ::com::sun::star::uno::Sequence;
using ::com::sun::star::uno::Any;
using ::com::sun::star::xml::sax::XAttributeList;

const sal_Char sAPI_TokenType[] = "TokenType";
const sal_Char sAPI_CharacterStyleName[] = "CharacterStyleName";

TYPEINIT1( XMLIndexBibliographyEntryContext, XMLIndexSimpleEntryContext);

XMLIndexBibliographyEntryContext::XMLIndexBibliographyEntryContext(
    SvXMLImport& rImport,
    XMLIndexTemplateContext& rTemplate,
    sal_uInt16 nPrfx,
    const OUString& rLocalName ) :
        XMLIndexSimpleEntryContext(rImport,
                                   rTemplate.sTokenBibliographyDataField,
                                   rTemplate,
                                   nPrfx, rLocalName),
        nBibliographyInfo(BibliographyDataField::IDENTIFIER),
        bBibliographyInfoOK(sal_False)
{
}

XMLIndexBibliographyEntryContext::~XMLIndexBibliographyEntryContext()
{
}

const SvXMLEnumMapEntry aBibliographyDataFieldMap[] =
{
    { XML_ADDRESS,              BibliographyDataField::ADDRESS },
    { XML_ANNOTE,               BibliographyDataField::ANNOTE },
    { XML_AUTHOR,               BibliographyDataField::AUTHOR },
    { XML_BIBLIOGRAPHY_TYPE,    BibliographyDataField::BIBILIOGRAPHIC_TYPE },
    // #96658#: also read old documents (bib*i*liographic...)
    { XML_BIBILIOGRAPHIC_TYPE,  BibliographyDataField::BIBILIOGRAPHIC_TYPE },
    { XML_BOOKTITLE,            BibliographyDataField::BOOKTITLE },
    { XML_CHAPTER,              BibliographyDataField::CHAPTER },
    { XML_CUSTOM1,              BibliographyDataField::CUSTOM1 },
    { XML_CUSTOM2,              BibliographyDataField::CUSTOM2 },
    { XML_CUSTOM3,              BibliographyDataField::CUSTOM3 },
    { XML_CUSTOM4,              BibliographyDataField::CUSTOM4 },
    { XML_CUSTOM5,              BibliographyDataField::CUSTOM5 },
    { XML_EDITION,              BibliographyDataField::EDITION },
    { XML_EDITOR,               BibliographyDataField::EDITOR },
    { XML_HOWPUBLISHED,         BibliographyDataField::HOWPUBLISHED },
    { XML_IDENTIFIER,           BibliographyDataField::IDENTIFIER },
    { XML_INSTITUTION,          BibliographyDataField::INSTITUTION },
    { XML_ISBN,                 BibliographyDataField::ISBN },
    { XML_JOURNAL,              BibliographyDataField::JOURNAL },
    { XML_MONTH,                BibliographyDataField::MONTH },
    { XML_NOTE,                 BibliographyDataField::NOTE },
    { XML_NUMBER,               BibliographyDataField::NUMBER },
    { XML_ORGANIZATIONS,        BibliographyDataField::ORGANIZATIONS },
    { XML_PAGES,                BibliographyDataField::PAGES },
    { XML_PUBLISHER,            BibliographyDataField::PUBLISHER },
    { XML_REPORT_TYPE,          BibliographyDataField::REPORT_TYPE },
    { XML_SCHOOL,               BibliographyDataField::SCHOOL },
    { XML_SERIES,               BibliographyDataField::SERIES },
    { XML_TITLE,                BibliographyDataField::TITLE },
    { XML_URL,                  BibliographyDataField::URL },
    { XML_VOLUME,               BibliographyDataField::VOLUME },
    { XML_YEAR,                 BibliographyDataField::YEAR },
    { XML_TOKEN_INVALID, 0 }
};

void XMLIndexBibliographyEntryContext::StartElement(
    const Reference<XAttributeList> & xAttrList)
{
    // handle both, style name and bibliography info
    sal_Int16 nLength = xAttrList->getLength();
    for(sal_Int16 nAttr = 0; nAttr < nLength; nAttr++)
    {
        OUString sLocalName;
        sal_uInt16 nPrefix = GetImport().GetNamespaceMap().
            GetKeyByAttrName( xAttrList->getNameByIndex(nAttr),
                              &sLocalName );
        if (XML_NAMESPACE_TEXT == nPrefix)
        {
            if ( IsXMLToken( sLocalName, XML_STYLE_NAME ) )
            {
                sCharStyleName = xAttrList->getValueByIndex(nAttr);
                bCharStyleNameOK = sal_True;
            }
            else if ( IsXMLToken( sLocalName, XML_BIBLIOGRAPHY_DATA_FIELD ) )
            {
                sal_uInt16 nTmp;
                if (SvXMLUnitConverter::convertEnum(
                    nTmp, xAttrList->getValueByIndex(nAttr),
                    aBibliographyDataFieldMap))
                {
                    nBibliographyInfo = nTmp;
                    bBibliographyInfoOK = sal_True;
                }
            }
        }
    }

    // if we have a style name, set it!
    if (bCharStyleNameOK)
    {
        nValues++;
    }

    // always bibliography; else element is not valid
    nValues++;
}

void XMLIndexBibliographyEntryContext::EndElement()
{
    // only valid, if we have bibliography info
    if (bBibliographyInfoOK)
    {
        XMLIndexSimpleEntryContext::EndElement();
    }
}

void XMLIndexBibliographyEntryContext::FillPropertyValues(
    ::com::sun::star::uno::Sequence<
        ::com::sun::star::beans::PropertyValue> & rValues)
{
    // entry name and (optionally) style name in parent class
    XMLIndexSimpleEntryContext::FillPropertyValues(rValues);

    // bibliography data field
    sal_Int32 nIndex = bCharStyleNameOK ? 2 : 1;
    rValues[nIndex].Name = rTemplateContext.sBibliographyDataField;
    Any aAny;
    aAny <<= nBibliographyInfo;
    rValues[nIndex].Value = aAny;
}

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
<commit_msg>-Werror,-Wunused-const-variable<commit_after>/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * This file incorporates work covered by the following license notice:
 *
 *   Licensed to the Apache Software Foundation (ASF) under one or more
 *   contributor license agreements. See the NOTICE file distributed
 *   with this work for additional information regarding copyright
 *   ownership. The ASF licenses this file to you under the Apache
 *   License, Version 2.0 (the "License"); you may not use this file
 *   except in compliance with the License. You may obtain a copy of
 *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
 */

#include "XMLIndexBibliographyEntryContext.hxx"
#include "XMLIndexTemplateContext.hxx"
#include <xmloff/xmlictxt.hxx>
#include <xmloff/xmlimp.hxx>
#include <xmloff/txtimp.hxx>
#include <xmloff/nmspmap.hxx>
#include "xmloff/xmlnmspe.hxx"
#include <xmloff/xmltoken.hxx>
#include <xmloff/xmluconv.hxx>
#include <com/sun/star/text/BibliographyDataField.hpp>

using namespace ::com::sun::star::text;
using namespace ::xmloff::token;

using ::com::sun::star::beans::PropertyValue;
using ::com::sun::star::beans::PropertyValues;
using ::com::sun::star::uno::Reference;
using ::com::sun::star::uno::Sequence;
using ::com::sun::star::uno::Any;
using ::com::sun::star::xml::sax::XAttributeList;

TYPEINIT1( XMLIndexBibliographyEntryContext, XMLIndexSimpleEntryContext);

XMLIndexBibliographyEntryContext::XMLIndexBibliographyEntryContext(
    SvXMLImport& rImport,
    XMLIndexTemplateContext& rTemplate,
    sal_uInt16 nPrfx,
    const OUString& rLocalName ) :
        XMLIndexSimpleEntryContext(rImport,
                                   rTemplate.sTokenBibliographyDataField,
                                   rTemplate,
                                   nPrfx, rLocalName),
        nBibliographyInfo(BibliographyDataField::IDENTIFIER),
        bBibliographyInfoOK(sal_False)
{
}

XMLIndexBibliographyEntryContext::~XMLIndexBibliographyEntryContext()
{
}

const SvXMLEnumMapEntry aBibliographyDataFieldMap[] =
{
    { XML_ADDRESS,              BibliographyDataField::ADDRESS },
    { XML_ANNOTE,               BibliographyDataField::ANNOTE },
    { XML_AUTHOR,               BibliographyDataField::AUTHOR },
    { XML_BIBLIOGRAPHY_TYPE,    BibliographyDataField::BIBILIOGRAPHIC_TYPE },
    // #96658#: also read old documents (bib*i*liographic...)
    { XML_BIBILIOGRAPHIC_TYPE,  BibliographyDataField::BIBILIOGRAPHIC_TYPE },
    { XML_BOOKTITLE,            BibliographyDataField::BOOKTITLE },
    { XML_CHAPTER,              BibliographyDataField::CHAPTER },
    { XML_CUSTOM1,              BibliographyDataField::CUSTOM1 },
    { XML_CUSTOM2,              BibliographyDataField::CUSTOM2 },
    { XML_CUSTOM3,              BibliographyDataField::CUSTOM3 },
    { XML_CUSTOM4,              BibliographyDataField::CUSTOM4 },
    { XML_CUSTOM5,              BibliographyDataField::CUSTOM5 },
    { XML_EDITION,              BibliographyDataField::EDITION },
    { XML_EDITOR,               BibliographyDataField::EDITOR },
    { XML_HOWPUBLISHED,         BibliographyDataField::HOWPUBLISHED },
    { XML_IDENTIFIER,           BibliographyDataField::IDENTIFIER },
    { XML_INSTITUTION,          BibliographyDataField::INSTITUTION },
    { XML_ISBN,                 BibliographyDataField::ISBN },
    { XML_JOURNAL,              BibliographyDataField::JOURNAL },
    { XML_MONTH,                BibliographyDataField::MONTH },
    { XML_NOTE,                 BibliographyDataField::NOTE },
    { XML_NUMBER,               BibliographyDataField::NUMBER },
    { XML_ORGANIZATIONS,        BibliographyDataField::ORGANIZATIONS },
    { XML_PAGES,                BibliographyDataField::PAGES },
    { XML_PUBLISHER,            BibliographyDataField::PUBLISHER },
    { XML_REPORT_TYPE,          BibliographyDataField::REPORT_TYPE },
    { XML_SCHOOL,               BibliographyDataField::SCHOOL },
    { XML_SERIES,               BibliographyDataField::SERIES },
    { XML_TITLE,                BibliographyDataField::TITLE },
    { XML_URL,                  BibliographyDataField::URL },
    { XML_VOLUME,               BibliographyDataField::VOLUME },
    { XML_YEAR,                 BibliographyDataField::YEAR },
    { XML_TOKEN_INVALID, 0 }
};

void XMLIndexBibliographyEntryContext::StartElement(
    const Reference<XAttributeList> & xAttrList)
{
    // handle both, style name and bibliography info
    sal_Int16 nLength = xAttrList->getLength();
    for(sal_Int16 nAttr = 0; nAttr < nLength; nAttr++)
    {
        OUString sLocalName;
        sal_uInt16 nPrefix = GetImport().GetNamespaceMap().
            GetKeyByAttrName( xAttrList->getNameByIndex(nAttr),
                              &sLocalName );
        if (XML_NAMESPACE_TEXT == nPrefix)
        {
            if ( IsXMLToken( sLocalName, XML_STYLE_NAME ) )
            {
                sCharStyleName = xAttrList->getValueByIndex(nAttr);
                bCharStyleNameOK = sal_True;
            }
            else if ( IsXMLToken( sLocalName, XML_BIBLIOGRAPHY_DATA_FIELD ) )
            {
                sal_uInt16 nTmp;
                if (SvXMLUnitConverter::convertEnum(
                    nTmp, xAttrList->getValueByIndex(nAttr),
                    aBibliographyDataFieldMap))
                {
                    nBibliographyInfo = nTmp;
                    bBibliographyInfoOK = sal_True;
                }
            }
        }
    }

    // if we have a style name, set it!
    if (bCharStyleNameOK)
    {
        nValues++;
    }

    // always bibliography; else element is not valid
    nValues++;
}

void XMLIndexBibliographyEntryContext::EndElement()
{
    // only valid, if we have bibliography info
    if (bBibliographyInfoOK)
    {
        XMLIndexSimpleEntryContext::EndElement();
    }
}

void XMLIndexBibliographyEntryContext::FillPropertyValues(
    ::com::sun::star::uno::Sequence<
        ::com::sun::star::beans::PropertyValue> & rValues)
{
    // entry name and (optionally) style name in parent class
    XMLIndexSimpleEntryContext::FillPropertyValues(rValues);

    // bibliography data field
    sal_Int32 nIndex = bCharStyleNameOK ? 2 : 1;
    rValues[nIndex].Name = rTemplateContext.sBibliographyDataField;
    Any aAny;
    aAny <<= nBibliographyInfo;
    rValues[nIndex].Value = aAny;
}

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
<|endoftext|>


<commit_before>#include <iostream>
#include <string>
#include <vector>
#include <sstream>

#include "util.hpp"
#include "range.hpp"
#include "grid.hpp"
#include "hint.hpp"
#include "hintconsumer.hpp"
#include "singlehint.hpp"
#include "hiddendouble.hpp"
#include "forcingchain.hpp"
#include "pointing.hpp"
#include "boxlinereduction.hpp"
#include "xwing.hpp"

int main(int argc, char *argv[]) {
#if 0
    std::string
    s =
    ".....39483.9..85....4.....25..9.......7.1.6.......7..16.....1....87..2.91753.....";
#endif
#if 0
    std::string
    s =
    "59.8.2.67.........6..7.3..1..9...1.....186.....7...3..8..4.5..2.........32.6.8.45";
#endif
#if 0
    std::string
    s =
    "..........9.7.6.2..3..1..5...2.6.3..76.5.1.49..9.4.8...2..7..3..5.9.4.8..........";
#endif
#if 0
    std::string
            s =
                    "385694..21465729832973814566148.3..97531.96.8829.6...147193826553...6.9796......4";

#endif
#if 1
    std::string s = "9..6.2..4.7.9.428...43789..4..5.9..2.9.....4.56.4.1.98..9145637735896421146...859";
#endif
    std::istringstream in(s);
    Grid grid;
    std::vector<HintProducer *> hintproducers;

    hintproducers.push_back(new SingleHintProducer());
    hintproducers.push_back(new HiddenDoubleHintProducer());
    hintproducers.push_back(new PointingHintProducer());
    hintproducers.push_back(new BoxLineReductionHintProducer());
    hintproducers.push_back(new XWingHintProducer());
    hintproducers.push_back(new ForcingChainHintProducer());

    grid.load(in);
    grid.print(std::cout);
    grid.print_choices(std::cout);
    grid.print_status(std::cout);
    std::cout << std::endl;

    int iteration = 0;
    while (true) {
        ++iteration;
        SingleHintConsumer consumer;
        for (std::vector<HintProducer *>::const_iterator i =
                hintproducers.begin(); i != hintproducers.end(); ++i) {
            (*i)->find_hints(grid, consumer);
            if (consumer.has_hints())
                break;
        }
        if (!consumer.has_hints())
            break;
#if 0
        for (ListHintConsumer::iterator i = consumer.begin(); i
                != consumer.end(); ++i) {
            (*i)->print_description(std::cout);
            std::cout << std::endl;
            (*i)->apply();
        }
#endif
        std::cout << "iteration: " << iteration << std::endl;
        grid.print_choices(std::cout);
        grid.print_status(std::cout);
        std::cout << std::endl;
    }
    std::cout << "result: " << std::endl;
    grid.print_choices(std::cout);
    grid.print_status(std::cout);
    std::cout << std::endl;

    //     std::for_each(hintproducers.begin(), hintproducers.end(), destroy<HintProducer *>());
    return 0;
}

<commit_msg>segfault in xwing<commit_after>#include <iostream>
#include <string>
#include <vector>
#include <sstream>

#include "util.hpp"
#include "range.hpp"
#include "grid.hpp"
#include "hint.hpp"
#include "hintconsumer.hpp"
#include "singlehint.hpp"
#include "hiddendouble.hpp"
#include "forcingchain.hpp"
#include "pointing.hpp"
#include "boxlinereduction.hpp"
#include "xwing.hpp"

int main(int argc, char *argv[]) {
#if 0
    std::string
    s =
    ".....39483.9..85....4.....25..9.......7.1.6.......7..16.....1....87..2.91753.....";
#endif
#if 0
    std::string
    s =
    "59.8.2.67.........6..7.3..1..9...1.....186.....7...3..8..4.5..2.........32.6.8.45";
#endif
#if 0
    std::string
    s =
    "..........9.7.6.2..3..1..5...2.6.3..76.5.1.49..9.4.8...2..7..3..5.9.4.8..........";
#endif
#if 0
    std::string
    s =
    "385694..21465729832973814566148.3..97531.96.8829.6...147193826553...6.9796......4";

#endif
#if 1
    std::string
            s =
                    "9..6.2..4.7.9.428...43789..4..5.9..2.9.....4.56.4.1.98..9145637735896421146...859";
#endif
    std::istringstream in(s);
    Grid grid;
    std::vector<HintProducer *> hintproducers;

    hintproducers.push_back(new SingleHintProducer());
    hintproducers.push_back(new HiddenDoubleHintProducer());
    hintproducers.push_back(new PointingHintProducer());
    hintproducers.push_back(new BoxLineReductionHintProducer());
    hintproducers.push_back(new XWingHintProducer());
    hintproducers.push_back(new ForcingChainHintProducer());

    grid.load(in);
    grid.print(std::cout);
    grid.print_choices(std::cout);
    grid.print_status(std::cout);
    std::cout << std::endl;

    int iteration = 0;
    while (true) {
        ++iteration;
        SingleHintConsumer consumer;
        for (std::vector<HintProducer *>::const_iterator i =
                hintproducers.begin(); i != hintproducers.end(); ++i) {
            (*i)->find_hints(grid, consumer);
            if (consumer.has_hints())
                break;
        }
        if (!consumer.has_hints())
            break;
#if 0
        for (ListHintConsumer::iterator i = consumer.begin(); i
                != consumer.end(); ++i) {
            (*i)->print_description(std::cout);
            std::cout << std::endl;
            (*i)->apply();
        }
#endif
        std::cout << "iteration: " << iteration << std::endl;
        grid.print_choices(std::cout);
        grid.print_status(std::cout);
        std::cout << std::endl;
    }
    std::cout << "result: " << std::endl;
    grid.print_choices(std::cout);
    grid.print_status(std::cout);
    std::cout << std::endl;

    std::for_each(hintproducers.begin(), hintproducers.end(), destroy<
            HintProducer *> ());

    return 0;
}

<|endoftext|>


<commit_before>/*
 * Copyright (c) 2017 Cisco and/or its affiliates.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at:
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <sstream>

#include <vom/route_api_types.hpp>
#include <vom/route_cmds.hpp>

namespace VOM {
namespace route {
namespace ip_route_cmds {

update_cmd::update_cmd(HW::item<bool>& item,
                       table_id_t id,
                       const prefix_t& prefix,
                       const path& path)
  : rpc_cmd(item)
  , m_id(id)
  , m_prefix(prefix)
  , m_path(path)
{
}

bool
update_cmd::operator==(const update_cmd& other) const
{
  return ((m_prefix == other.m_prefix) && (m_id == other.m_id) &&
          (m_path == other.m_path));
}

rc_t
update_cmd::issue(connection& con)
{
  msg_t req(con.ctx(), 0, std::ref(*this));

  auto& payload = req.get_request().get_payload();

  payload.table_id = m_id;
  payload.is_add = 1;
  payload.is_multipath = 0;

  m_prefix.to_vpp(&payload.is_ipv6, payload.dst_address,
                  &payload.dst_address_length);
  to_vpp(m_path, payload);

  VAPI_CALL(req.execute());

  return (wait());
}

std::string
update_cmd::to_string() const
{
  std::ostringstream s;
  s << "ip-route-create: " << m_hw_item.to_string() << " table-id:" << m_id
    << " prefix:" << m_prefix.to_string() << " paths:" << m_path.to_string();

  return (s.str());
}

delete_cmd::delete_cmd(HW::item<bool>& item,
                       table_id_t id,
                       const prefix_t& prefix,
                       const path& path)
  : rpc_cmd(item)
  , m_id(id)
  , m_prefix(prefix)
  , m_path(path)
{
}

bool
delete_cmd::operator==(const delete_cmd& other) const
{
  return ((m_prefix == other.m_prefix) && (m_id == other.m_id) &&
          (m_path == other.m_path));
}

rc_t
delete_cmd::issue(connection& con)
{
  msg_t req(con.ctx(), 0, std::ref(*this));

  auto& payload = req.get_request().get_payload();
  payload.table_id = m_id;
  payload.is_add = 0;

  m_prefix.to_vpp(&payload.is_ipv6, payload.dst_address,
                  &payload.dst_address_length);
  to_vpp(m_path, payload);

  VAPI_CALL(req.execute());

  wait();
  m_hw_item.set(rc_t::NOOP);

  return rc_t::OK;
}

std::string
delete_cmd::to_string() const
{
  std::ostringstream s;
  s << "ip-route-delete: " << m_hw_item.to_string() << " id:" << m_id
    << " prefix:" << m_prefix.to_string() << " paths:" << m_path.to_string();

  return (s.str());
}

dump_v4_cmd::dump_v4_cmd()
{
}

bool
dump_v4_cmd::operator==(const dump_v4_cmd& other) const
{
  return (true);
}

rc_t
dump_v4_cmd::issue(connection& con)
{
  m_dump.reset(new msg_t(con.ctx(), std::ref(*this)));

  VAPI_CALL(m_dump->execute());

  wait();

  return rc_t::OK;
}

std::string
dump_v4_cmd::to_string() const
{
  return ("ip-route-v4-dump");
}

dump_v6_cmd::dump_v6_cmd()
{
}

bool
dump_v6_cmd::operator==(const dump_v6_cmd& other) const
{
  return (true);
}

rc_t
dump_v6_cmd::issue(connection& con)
{
  m_dump.reset(new msg_t(con.ctx(), std::ref(*this)));

  VAPI_CALL(m_dump->execute());

  wait();

  return rc_t::OK;
}

std::string
dump_v6_cmd::to_string() const
{
  return ("ip-route-v6-dump");
}
} // namespace ip_route_cmds
} // namespace route
} // namespace vom
  /*
   * fd.io coding-style-patch-verification: ON
   *
   * Local Variables:
   * eval: (c-set-style "mozilla")
   * End:
   */
<commit_msg>VOM: routes support multipath so set is_multipath in route update<commit_after>/*
 * Copyright (c) 2017 Cisco and/or its affiliates.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at:
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <sstream>

#include <vom/route_api_types.hpp>
#include <vom/route_cmds.hpp>

namespace VOM {
namespace route {
namespace ip_route_cmds {

update_cmd::update_cmd(HW::item<bool>& item,
                       table_id_t id,
                       const prefix_t& prefix,
                       const path& path)
  : rpc_cmd(item)
  , m_id(id)
  , m_prefix(prefix)
  , m_path(path)
{
}

bool
update_cmd::operator==(const update_cmd& other) const
{
  return ((m_prefix == other.m_prefix) && (m_id == other.m_id) &&
          (m_path == other.m_path));
}

rc_t
update_cmd::issue(connection& con)
{
  msg_t req(con.ctx(), 0, std::ref(*this));

  auto& payload = req.get_request().get_payload();

  payload.table_id = m_id;
  payload.is_add = 1;
  payload.is_multipath = 1;

  m_prefix.to_vpp(&payload.is_ipv6, payload.dst_address,
                  &payload.dst_address_length);
  to_vpp(m_path, payload);

  VAPI_CALL(req.execute());

  return (wait());
}

std::string
update_cmd::to_string() const
{
  std::ostringstream s;
  s << "ip-route-create: " << m_hw_item.to_string() << " table-id:" << m_id
    << " prefix:" << m_prefix.to_string() << " paths:" << m_path.to_string();

  return (s.str());
}

delete_cmd::delete_cmd(HW::item<bool>& item,
                       table_id_t id,
                       const prefix_t& prefix,
                       const path& path)
  : rpc_cmd(item)
  , m_id(id)
  , m_prefix(prefix)
  , m_path(path)
{
}

bool
delete_cmd::operator==(const delete_cmd& other) const
{
  return ((m_prefix == other.m_prefix) && (m_id == other.m_id) &&
          (m_path == other.m_path));
}

rc_t
delete_cmd::issue(connection& con)
{
  msg_t req(con.ctx(), 0, std::ref(*this));

  auto& payload = req.get_request().get_payload();
  payload.table_id = m_id;
  payload.is_add = 0;

  m_prefix.to_vpp(&payload.is_ipv6, payload.dst_address,
                  &payload.dst_address_length);
  to_vpp(m_path, payload);

  VAPI_CALL(req.execute());

  wait();
  m_hw_item.set(rc_t::NOOP);

  return rc_t::OK;
}

std::string
delete_cmd::to_string() const
{
  std::ostringstream s;
  s << "ip-route-delete: " << m_hw_item.to_string() << " id:" << m_id
    << " prefix:" << m_prefix.to_string() << " paths:" << m_path.to_string();

  return (s.str());
}

dump_v4_cmd::dump_v4_cmd()
{
}

bool
dump_v4_cmd::operator==(const dump_v4_cmd& other) const
{
  return (true);
}

rc_t
dump_v4_cmd::issue(connection& con)
{
  m_dump.reset(new msg_t(con.ctx(), std::ref(*this)));

  VAPI_CALL(m_dump->execute());

  wait();

  return rc_t::OK;
}

std::string
dump_v4_cmd::to_string() const
{
  return ("ip-route-v4-dump");
}

dump_v6_cmd::dump_v6_cmd()
{
}

bool
dump_v6_cmd::operator==(const dump_v6_cmd& other) const
{
  return (true);
}

rc_t
dump_v6_cmd::issue(connection& con)
{
  m_dump.reset(new msg_t(con.ctx(), std::ref(*this)));

  VAPI_CALL(m_dump->execute());

  wait();

  return rc_t::OK;
}

std::string
dump_v6_cmd::to_string() const
{
  return ("ip-route-v6-dump");
}
} // namespace ip_route_cmds
} // namespace route
} // namespace vom
  /*
   * fd.io coding-style-patch-verification: ON
   *
   * Local Variables:
   * eval: (c-set-style "mozilla")
   * End:
   */
<|endoftext|>


<commit_before><commit_msg>Tweaking the window settings to improve performance by not drawing an additional system background<commit_after><|endoftext|>


<commit_before>#include "pcsclite.h"
#include "cardreader.h"

using namespace v8;
using namespace node;

void init_all(Local<Object> target) {
    PCSCLite::init(target);
    CardReader::init(target);
}

NODE_MODULE(pcsclite, init_all)
<commit_msg>src: make the module Context aware<commit_after>#include "pcsclite.h"
#include "cardreader.h"

using namespace v8;
using namespace node;

void init_all(Local<Object> target) {
    PCSCLite::init(target);
    CardReader::init(target);
}

#if NODE_MAJOR_VERSION >= 10
NAN_MODULE_WORKER_ENABLED(pcsclite, init_all)
#else
NODE_MODULE(pcsclite, init_all)
#endif
<|endoftext|>