Commit 5bb95e5e authored by Victor Yacovlev's avatar Victor Yacovlev

Unified architecture for Python/Kumir/Pascal/etc.

parent b3b428dd
......@@ -238,7 +238,7 @@ void KumirProgram::blindRun()
endStatus_ = Running;
if (state_==Idle) {
emit giveMeAProgram();
prepareKumirRunner(GeneratorInterface::LinesOnly);
prepareRunner(GeneratorInterface::LinesOnly);
}
state_ = BlindRun;
PluginManager::instance()->switchGlobalState(PluginInterface::GS_Running);
......@@ -253,7 +253,7 @@ void KumirProgram::testingRun()
endStatus_ = Running;
if (state_==Idle) {
emit giveMeAProgram();
prepareKumirRunner(GeneratorInterface::LinesOnly);
prepareRunner(GeneratorInterface::LinesOnly);
if (!runner()->hasTestingEntryPoint()) {
QMessageBox::information(mainWidget_, testingRunAction_->text(),
tr("This program does not have testing algorithm")
......@@ -274,7 +274,7 @@ void KumirProgram::regularRun()
endStatus_ = Running;
if (state_==Idle) {
emit giveMeAProgram();
prepareKumirRunner(GeneratorInterface::LinesAndVariables);
prepareRunner(GeneratorInterface::LinesAndVariables);
}
state_ = RegularRun;
PluginManager::instance()->switchGlobalState(PluginInterface::GS_Running);
......@@ -282,31 +282,36 @@ void KumirProgram::regularRun()
runner()->runContinuous();
}
void KumirProgram::prepareKumirRunner(Shared::GeneratorInterface::DebugLevel debugLevel)
void KumirProgram::prepareRunner(Shared::GeneratorInterface::DebugLevel debugLevel)
{
bool ok = false;
QString sourceProgramPath;
sourceProgramPath = editor_->documentContents().sourceUrl.toLocalFile();
Shared::RunInterface::SourceInfo sourceInfo;
sourceInfo.sourceFileName = sourceProgramPath;
Shared::RunInterface::RunnableProgram program;
program.sourceFileName = sourceProgramPath;
program.sourceData = editor_->analizer()->plugin()->sourceFileHandler()->toString(editor_->documentContents());
if (editor_->analizer()->compiler()) {
// Use AST to generate executable (only Kumir language)
editor_->ensureAnalized();
const AST::DataPtr ast = editor_->analizer()->compiler()->abstractSyntaxTree();
QByteArray bufArray;
kumirCodeGenerator()->setOutputToText(false);
kumirCodeGenerator()->setDebugLevel(debugLevel);
QString fileNameSuffix, mimeType;
kumirCodeGenerator()->generateExecuable(ast, bufArray, mimeType, fileNameSuffix);
runner()->loadProgram(sourceProgramPath, bufArray, sourceInfo);
program.executableData = bufArray;
runner()->loadProgram(program);
}
else {
const KumFile::Data source = editor_->documentContents();
sourceProgramPath = source.sourceUrl.toLocalFile();
const QString sourceText = source.hasHiddenText
? source.visibleText + "\n" + source.hiddenText
: source.visibleText;
const QByteArray sourceData = sourceText.toUtf8();
ok = runner()->loadProgram(sourceProgramPath, sourceData, sourceInfo);
// Use source text as executable
program.executableData =editor_->analizer()->plugin()->sourceFileHandler()->toBytes(editor_->documentContents());
program.executableFileName = program.sourceFileName;
ok = runner()->loadProgram(program);
}
const QString newCwd = QFileInfo(sourceProgramPath).absoluteDir().absolutePath();
QDir::setCurrent(newCwd);
......@@ -320,7 +325,7 @@ void KumirProgram::stepRun()
endStatus_ = Running;
if (state_==Idle) {
emit giveMeAProgram();
prepareKumirRunner(GeneratorInterface::LinesAndVariables);
prepareRunner(GeneratorInterface::LinesAndVariables);
}
state_ = StepRun;
// stepRunAction_->setIcon(QIcon::fromTheme("debug-step-over", QIcon(QApplication::instance()->property("sharePath").toString()+"/icons/debug-step-over.png")));
......
......@@ -76,7 +76,7 @@ private:
static Shared::RunInterface * runner();
void setAllActorsAnimationFlag(bool animationEnabled);
void prepareKumirRunner(Shared::GeneratorInterface::DebugLevel);
void prepareRunner(Shared::GeneratorInterface::DebugLevel);
private /*fields*/:
enum State { Idle, RegularRun, BlindRun, StepRun, TestingRun } state_;
......
......@@ -1386,7 +1386,7 @@ void MainWindow::newText(const QString &fileName, const QString & text)
Shared::Editor::InstanceInterface * editor =
m_plugin->plugin_editor->newDocument("", QDir::currentPath());
KumFile::Data data;
Shared::Analizer::SourceFileInterface::Data data;
data.canonicalSourceLanguageName = "";
data.sourceUrl = fileName.isEmpty()
? QUrl() : QUrl::fromLocalFile(fileName);
......@@ -2124,7 +2124,7 @@ TabWidgetElement* MainWindow::loadFromCourseManager(
courseManagerTab->setCourseTitle(data.title);
}
if (data.language == ST::Kumir) {
KumFile::Data src = data.content;
Shared::Analizer::SourceFileInterface::Data src = data.content;
src.canonicalSourceLanguageName = "kum";
if (courseManagerTab) {
......
......@@ -103,7 +103,7 @@ QString Plugin::initialize(const QStringList & parameters, const ExtensionSystem
qDebug() << "LINE DEBUG: " << QFileInfo(QString(__FILE__)).fileName() << ":" << __LINE__;
qRegisterMetaType<QProcess::ProcessError>("QProcess::ProcessError");
qDebug() << "LINE DEBUG: " << QFileInfo(QString(__FILE__)).fileName() << ":" << __LINE__;
qRegisterMetaType<KumFile::Data>("KumirFile.Data");
qRegisterMetaType<Shared::Analizer::SourceFileInterface::Data>("KumirFile.Data");
qDebug() << "LINE DEBUG: " << QFileInfo(QString(__FILE__)).fileName() << ":" << __LINE__;
qRegisterMetaType<Shared::GuiInterface::ProgramSourceText::Language>
("Gui.ProgramSourceText.Language");
......
......@@ -207,7 +207,7 @@ void TabWidgetElement::setDocumentChangesClean(bool clean)
QString TabWidgetElement::title() const
{
if (editorInstance_) {
const KumFile::Data data = editorInstance_->documentContents();
const Shared::Analizer::SourceFileInterface::Data data = editorInstance_->documentContents();
const QUrl url = data.sourceUrl;
if (url.isValid()) {
const QString fullPath = editorInstance_->documentContents().sourceUrl.toLocalFile();
......
#include "coursemanager_plugin.h"
#include <dataformats/kumfile.h>
#include "task/mainwindow.h"
#include "interfaces/analizerinterface.h"
namespace CourseManager {
......@@ -34,10 +35,12 @@ QList<QMenu*> Plugin::menus()const
QString Plugin::getText()
{
GI * gui = ExtensionSystem::PluginManager::instance()->findPlugin<GI>();
qDebug()<<"Text"<< KumFile::toString(gui->programSource().content);
return KumFile::toString(gui->programSource().content);
GI * gui = ExtensionSystem::PluginManager::instance()->findPlugin<GI>();
Shared::AnalizerInterface * analizer =
ExtensionSystem::PluginManager::instance()->findPlugin<Shared::AnalizerInterface>();
const QString text = analizer->sourceFileHandler()->toString(gui->programSource().content);
qDebug()<<"Text"<< text;
return text;
}
void Plugin::setPreProgram(QVariant param)
......@@ -48,8 +51,10 @@ void Plugin::setPreProgram(QVariant param)
}
else
{GI * gui = ExtensionSystem::PluginManager::instance()->findPlugin<GI>();
Shared::AnalizerInterface * analizer =
ExtensionSystem::PluginManager::instance()->findPlugin<Shared::AnalizerInterface>();
Shared::GuiInterface::ProgramSourceText text;
text.content=KumFile::fromString(param.toString());
text.content=analizer->sourceFileHandler()->fromString(param.toString());
text.content=KumFile::insertTeacherMark(text.content);
text.language=Shared::GuiInterface::ProgramSourceText::Kumir;
gui->setProgramSource(text);
......@@ -67,9 +72,11 @@ bool Plugin::setTextFromFile(QString fname)
if(!file.open(QIODevice::ReadOnly))return false;
GI * gui = ExtensionSystem::PluginManager::instance()->findPlugin<GI>();
Shared::AnalizerInterface * analizer =
ExtensionSystem::PluginManager::instance()->findPlugin<Shared::AnalizerInterface>();
Shared::GuiInterface::ProgramSourceText text;
QDataStream ds(&file);
ds>>text.content;
text.content = analizer->sourceFileHandler()->fromBytes(file.readAll());
file.close();
text.language=Shared::GuiInterface::ProgramSourceText::Kumir;
text.content=KumFile::insertTeacherMark(text.content);
gui->setProgramSource(text);
......
......@@ -708,7 +708,7 @@ QDataStream & operator>> (QDataStream & stream, ToggleLineProtectedCommand & com
QDataStream & operator<< (QDataStream & stream, const ChangeHiddenLineDelimeterCommand & command)
{
stream << command.firstHiddenLineNo;
stream << KumFile::toString(command.prevData);
// stream << KumFile::toString(command.prevData);
return stream;
}
......@@ -717,7 +717,7 @@ QDataStream & operator>> (QDataStream & stream, ChangeHiddenLineDelimeterCommand
stream >> command.firstHiddenLineNo;
QString s;
stream >> s;
command.prevData = KumFile::fromString(s);
// command.prevData = KumFile::fromString(s);
return stream;
}
......
......@@ -198,7 +198,7 @@ public:
void undo();
private:
class TextDocument * doc;
struct KumFile::Data prevData;
struct Shared::Analizer::SourceFileInterface::Data prevData;
int firstHiddenLineNo;
};
......
......@@ -84,30 +84,18 @@ void EditorInstance::appendMarginText(int lineNo, const QString &text)
void EditorInstance::loadDocument(QIODevice *device, const QString &fileNameSuffix,
const QString &sourceEncoding, const QUrl &sourceUrl)
{
Shared::AnalizerInterface * analizerPlugin = nullptr;
ExtensionSystem::PluginManager * manager =
ExtensionSystem::PluginManager::instance();
const QByteArray bytes = device->readAll();
QList<Shared::AnalizerInterface*> analizers =
manager->findPlugins<Shared::AnalizerInterface>();
Shared::Analizer::SourceFileInterface::Data data;
for (int i=0; i<analizers.size(); i++) {
if (analizers[i]->defaultDocumentFileNameSuffix() == fileNameSuffix) {
analizerPlugin = analizers[i];
break;
}
if (analizerPlugin_) {
data = analizerPlugin_->sourceFileHandler()->fromBytes(bytes, sourceEncoding);
}
else {
QTextCodec * codec = QTextCodec::codecForName(sourceEncoding.toLatin1());
data.hasHiddenText = false;
data.visibleText = codec->toUnicode(bytes);
}
// bool keepIndents = analizerPlugin==nullptr || analizerPlugin->indentsSignificant();
bool keepIndents = true;
const QByteArray bytes = device->readAll();
KumFile::Data data = KumFile::fromString(
KumFile::readRawDataAsString(bytes, sourceEncoding, fileNameSuffix),
keepIndents
);
data.canonicalSourceLanguageName = fileNameSuffix;
data.sourceUrl = sourceUrl;
loadDocument(data);
......@@ -137,7 +125,7 @@ void EditorInstance::loadDocument(const QString &fileName)
}
}
void EditorInstance::loadDocument(const KumFile::Data &data)
void EditorInstance::loadDocument(const Shared::Analizer::SourceFileInterface::Data &data)
{
Shared::AnalizerInterface * analizerPlugin = nullptr;
Shared::Analizer::InstanceInterface * analizerInstance = nullptr;
......@@ -960,54 +948,9 @@ QList<QMenu*> EditorInstance::menus() const
return result;
}
QByteArray EditorInstance::saveState() const
{
QBuffer buffer;
buffer.open(QIODevice::WriteOnly);
QDataStream stream(&buffer);
stream << (*this);
QByteArray data = buffer.data();
QByteArray md5 = QCryptographicHash::hash(data, QCryptographicHash::Md5);
QByteArray version =
QCoreApplication::instance()->applicationVersion().leftJustified(20, ' ')
.toLatin1();
return md5 + version + data;
}
void EditorInstance::restoreState(const QByteArray &data)
{
if (data.size()>=36) {
QByteArray checksum = data.mid(0,16);
QString version = QString::fromLatin1(data.mid(16,20)).trimmed();
QString myVersion = QCoreApplication::instance()->applicationVersion();
QByteArray d = data.mid(36);
QByteArray md5 = QCryptographicHash::hash(d, QCryptographicHash::Md5);
bool equal = true;
for (int i=0; i<16; i++) {
if (checksum[i]!=md5[i]) {
equal = false;
break;
}
}
if (version>myVersion || (myVersion.contains("alpha") && myVersion!=version)) {
qWarning() << "Can't restore state: version mismatch (my: "
<< myVersion << ", required: " << version << ")";
}
else if (!equal) {
qWarning() << "Can't restore state: MD5 checksum mismatch";
}
else {
QDataStream stream(d);
stream >> (*this);
}
}
else {
qWarning() << "Can't restore state: not enought data";
}
checkForClean();
}
void EditorInstance::setKumFile(const KumFile::Data &data)
void EditorInstance::setKumFile(const Shared::Analizer::SourceFileInterface::Data &data)
{
notSaved_ = true;
doc_->setKumFile(data, plugin_->teacherMode_);
......@@ -1041,9 +984,9 @@ void EditorInstance::setPlainText(const QString & data)
checkForClean();
}
KumFile::Data EditorInstance::documentContents() const
Shared::Analizer::SourceFileInterface::Data EditorInstance::documentContents() const
{
KumFile::Data data = doc_->toKumFile();
Shared::Analizer::SourceFileInterface::Data data = doc_->toKumFile();
data.sourceUrl = documentUrl_;
return data;
}
......@@ -1051,7 +994,7 @@ KumFile::Data EditorInstance::documentContents() const
void EditorInstance::saveDocument(const QString &fileName)
{
QFile f(fileName);
if (f.open(QIODevice::WriteOnly|QIODevice::Text)) {
if (f.open(QIODevice::WriteOnly)) {
saveDocument(&f);
f.close();
documentUrl_ = QUrl::fromLocalFile(fileName);
......@@ -1063,8 +1006,21 @@ void EditorInstance::saveDocument(const QString &fileName)
void EditorInstance::saveDocument(QIODevice *device)
{
QDataStream ds(device);
ds << documentContents();
if (analizerPlugin_) {
QByteArray bytes = analizerPlugin_->sourceFileHandler()->toBytes(documentContents());
device->write(bytes);
}
else {
QTextStream ts(device);
#ifdef Q_OS_WIN32
ts.setCodec("CP1251");
#else
ts.setCodec("UTF-8");
ts.setGenerateByteOrderMark(true);
#endif
ts << documentContents().visibleText;
ts.flush();
}
notSaved_ = false;
checkForClean();
doc_->undoStack()->setClean();
......@@ -1182,109 +1138,6 @@ void EditorInstance::setForceNotSavedFlag(bool v)
checkForClean();
}
QDataStream & operator<< (QDataStream & stream, const EditorInstance & editor)
{
stream << KumFile::toString(editor.documentContents());
stream << editor.cursor()->row();
stream << editor.cursor()->column();
stream << quint8(editor.forceNotSavedFlag());
stream << editor.document()->undoStack()->count();
stream << editor.document()->undoStack()->cleanIndex();
stream << editor.document()->undoStack()->index();
for (int i=0; i<editor.document()->undoStack()->count(); i++) {
const QUndoCommand * cmd = editor.document()->undoStack()->command(i);
stream << cmd->id();
if (cmd->id()==1) {
const InsertCommand * insertCommand =
static_cast<const InsertCommand*>(cmd);
stream << (*insertCommand);
}
if (cmd->id()==2) {
const RemoveCommand * removeCommand =
static_cast<const RemoveCommand*>(cmd);
stream << (*removeCommand);
}
if (cmd->id()==3) {
const InsertBlockCommand * insertCommand =
static_cast<const InsertBlockCommand*>(cmd);
stream << (*insertCommand);
}
if (cmd->id()==4) {
const RemoveBlockCommand * removeCommand =
static_cast<const RemoveBlockCommand*>(cmd);
stream << (*removeCommand);
}
if (cmd->id()==0xA0) {
const ToggleLineProtectedCommand * toggleCommand =
static_cast<const ToggleLineProtectedCommand*>(cmd);
stream << (*toggleCommand);
}
}
return stream;
}
QDataStream & operator>> (QDataStream & stream, EditorInstance & editor)
{
QString txt;
int row, col;
stream >> txt;
stream >> row;
stream >> col;
editor.setKumFile(KumFile::fromString(txt));
editor.cursor()->setRow(row);
editor.cursor()->setColumn(col);
quint8 notsaved;
stream >> notsaved;
editor.setForceNotSavedFlag(bool(notsaved));
int undoCount, cleanIndex, undoIndex;
stream >> undoCount >> cleanIndex >> undoIndex;
QUndoStack * undo = editor.document()->undoStack();
TextDocument::noUndoRedo = true;
for (int i=0; i<undoCount; i++) {
if (i==cleanIndex)
undo->setClean();
int id;
stream >> id;
if (id==1) {
InsertCommand * cmd = new InsertCommand(editor.document(),
editor.cursor(),
editor.analizer());
stream >> (*cmd);
undo->push(cmd);
}
if (id==2) {
RemoveCommand * cmd = new RemoveCommand(editor.document(),
editor.cursor(),
editor.analizer());
stream >> (*cmd);
undo->push(cmd);
}
if (id==3) {
InsertBlockCommand * cmd = new InsertBlockCommand(editor.document(),
editor.cursor(),
editor.analizer());
stream >> (*cmd);
undo->push(cmd);
}
if (id==4) {
RemoveBlockCommand * cmd = new RemoveBlockCommand(editor.document(),
editor.cursor(),
editor.analizer());
stream >> (*cmd);
undo->push(cmd);
}
if (id==0xA0) {
ToggleLineProtectedCommand * cmd = new ToggleLineProtectedCommand(editor.document(), -1);
stream >> (*cmd);
undo->push(cmd);
}
}
undo->setIndex(undoIndex);
TextDocument::noUndoRedo = false;
return stream;
}
} // namespace Editor
......@@ -46,7 +46,7 @@ public:
QSize minimumSizeHint() const;
QList<QMenu*> menus() const;
KumFile::Data documentContents() const;
Shared::Analizer::SourceFileInterface::Data documentContents() const;
void loadDocument(QIODevice * device,
const QString & fileNameSuffix = "",
......@@ -54,11 +54,11 @@ public:
const QUrl & sourceUrl = QUrl()
) /* throws QString */;
void loadDocument(const QString & fileName) /* throws QString */;
void loadDocument(const KumFile::Data &data) /* throws QString */;
void loadDocument(const Shared::Analizer::SourceFileInterface::Data &data) /* throws QString */;
void saveDocument(const QString &fileName);
void saveDocument(QIODevice * device);
void setKumFile(const KumFile::Data & data);
void setKumFile(const Shared::Analizer::SourceFileInterface::Data & data);
void setPlainText(const QString & data);
void setDocumentId(int id);
......@@ -83,9 +83,7 @@ public:
void lock();
void unlock();
void setLineHighlighted(int lineNo, const QColor & color, quint32 colStart, quint32 colEnd);
void ensureAnalized();
QByteArray saveState() const;
void restoreState(const QByteArray &data);
void ensureAnalized();
void unsetAnalizer();
bool forceNotSavedFlag() const;
void setForceNotSavedFlag(bool v);
......@@ -189,8 +187,6 @@ private /* fields */:
QUrl documentUrl_;
};
QDataStream & operator<< (QDataStream & stream, const EditorInstance & editor);
QDataStream & operator>> (QDataStream & stream, EditorInstance & editor);
} // namespace Editor
......
......@@ -73,14 +73,8 @@ EditorInstance::InstanceInterface * EditorPlugin::newDocument(
if (f.open(QIODevice::ReadOnly|QIODevice::Text)) {
const QByteArray bytes = f.readAll();
f.close();
const KumFile::Data data =
KumFile::fromString(
KumFile::readRawDataAsString(
bytes,
QString(),
analizerPlugin->defaultDocumentFileNameSuffix()
)
);
const Shared::Analizer::SourceFileInterface::Data data =
analizerPlugin->sourceFileHandler()->fromBytes(bytes);
editor->setKumFile(data);
}
}
......@@ -89,7 +83,7 @@ EditorInstance::InstanceInterface * EditorPlugin::newDocument(
return editor;
}
Shared::Editor::InstanceInterface * EditorPlugin::loadDocument(const KumFile::Data &data)
Shared::Editor::InstanceInterface * EditorPlugin::loadDocument(const Shared::Analizer::SourceFileInterface::Data &data)
{
EditorInstance * editor = new EditorInstance(this, true, nullptr, nullptr);
connectGlobalSignalsToEditor(editor);
......@@ -104,7 +98,21 @@ Shared::Editor::InstanceInterface * EditorPlugin::loadDocument(
const QUrl & sourceUrl
)
{
EditorInstance * editor = new EditorInstance(this, true, nullptr, nullptr);
Shared::AnalizerInterface * analizerPlugin = nullptr;
QList<Shared::AnalizerInterface*> analizers =
ExtensionSystem::PluginManager::instance()
->findPlugins<Shared::AnalizerInterface>();
for (int i=0; i<analizers.size(); i++) {
const QString suffix = analizers[i]->defaultDocumentFileNameSuffix();
if (suffix == fileNameSuffix) {
analizerPlugin = analizers[i];
break;
}
}
EditorInstance * editor = new EditorInstance(this, true, analizerPlugin, nullptr);
connectGlobalSignalsToEditor(editor);
editor->loadDocument(device, fileNameSuffix, sourceEncoding, sourceUrl);
return editor;
......@@ -112,7 +120,21 @@ Shared::Editor::InstanceInterface * EditorPlugin::loadDocument(
Shared::Editor::InstanceInterface * EditorPlugin::loadDocument(const QString &fileName)
{
EditorInstance * editor = new EditorInstance(this, true, nullptr, nullptr);
Shared::AnalizerInterface * analizerPlugin = nullptr;
QList<Shared::AnalizerInterface*> analizers =
ExtensionSystem::PluginManager::instance()
->findPlugins<Shared::AnalizerInterface>();
for (int i=0; i<analizers.size(); i++) {
const QString suffix = "." + analizers[i]->defaultDocumentFileNameSuffix();
if (fileName.endsWith(suffix)) {
analizerPlugin = analizers[i];
break;
}
}
EditorInstance * editor = new EditorInstance(this, true, analizerPlugin, nullptr);
connectGlobalSignalsToEditor(editor);
editor->loadDocument(fileName);
return editor;
......
......@@ -39,7 +39,7 @@ public:
const QString & fileName) /* throws QString */;
Shared::Editor::InstanceInterface * loadDocument(
const KumFile::Data &data) /* throws QString */;
const Shared::Analizer::SourceFileInterface::Data &data) /* throws QString */;