Commit 268bf2d6 authored by Victor Yacovlev's avatar Victor Yacovlev

Everywhere: Line number instruction has 2 meanings; highlight statement

in line
parent 3a9e25bf
......@@ -182,7 +182,7 @@ void KumirProgram::setBytecodeRun(KPlugin *run)
connect(run, SIGNAL(stopped(int)),
this, SLOT(handleRunnerStopped(int)));
connect(run, SIGNAL(lineChanged(int)), this, SLOT(handleLineChanged(int)));
connect(run, SIGNAL(lineChanged(int,quint32,quint32)), this, SLOT(handleLineChanged(int,quint32,quint32)));
connect(run, SIGNAL(marginText(int,QString)), this, SLOT(handleMarginTextRequest(int,QString)));
connect(run, SIGNAL(clearMargin(int,int)), this, SLOT(handleMarginClearRequest(int,int)));
connect(run, SIGNAL(replaceMarginText(int,QString, bool)),
......@@ -456,7 +456,7 @@ void KumirProgram::handleRunnerStopped(int rr)
else if (reason==Shared::RunInterface::SR_Error) {
s_endStatus = tr("Evaluation error");
m_terminal->error(plugin_bytecodeRun->error());
plugin_editor->highlightLineRed(documentId_, plugin_bytecodeRun->currentLineNo());
plugin_editor->highlightLineRed(documentId_, plugin_bytecodeRun->currentLineNo(), plugin_bytecodeRun->currentColumn().first, plugin_bytecodeRun->currentColumn().second);
PluginManager::instance()->switchGlobalState(GS_Observe);
e_state = Idle;
m_terminal->clearFocus();
......@@ -492,14 +492,14 @@ void KumirProgram::handleRunnerStopped(int rr)
}
void KumirProgram::handleLineChanged(int lineNo)
void KumirProgram::handleLineChanged(int lineNo, quint32 colStart, quint32 colEnd)
{
emit activateDocumentTab(documentId_);
if (lineNo!=-1) {
if (plugin_bytecodeRun->error().isEmpty())
plugin_editor->highlightLineGreen(documentId_, lineNo);
plugin_editor->highlightLineGreen(documentId_, lineNo, colStart, colEnd);
else
plugin_editor->highlightLineRed(documentId_, lineNo);
plugin_editor->highlightLineRed(documentId_, lineNo, colStart, colEnd);
}
else {
plugin_editor->unhighlightLine(documentId_);
......
......@@ -54,7 +54,7 @@ public slots:
void stepOut();
void stop();
void switchGlobalState(ExtensionSystem::GlobalState old, ExtensionSystem::GlobalState cur);
void handleLineChanged(int lineNo);
void handleLineChanged(int lineNo, quint32 colStart, quint32 colEnd);
void handleMarginTextRequest(int lineNo, const QString & text);
void handleMarginClearRequest(int fromLine, int toLine);
void handleMarginTextReplace(int,const QString&,bool);
......
......@@ -48,7 +48,7 @@ MainWindow::MainWindow(Plugin * p) :
QObject * runnerObject =
ExtensionSystem::PluginManager::instance()->findKPlugin<Shared::RunInterface>();
if (runnerObject) {
connect(runnerObject, SIGNAL(updateStepsCounter(ulong)), this, SLOT(checkCounterValue()));
connect(runnerObject, SIGNAL(updateStepsCounter(quint64)), this, SLOT(checkCounterValue()));
}
connect(ui->actionPreferences, SIGNAL(triggered()), this, SLOT(showPreferences()));
......
......@@ -115,9 +115,9 @@ void Editor::clearMarginText(uint fromLine, uint toLine)
update();
}
void Editor::setLineHighlighted(int lineNo, const QColor &color)
void Editor::setLineHighlighted(int lineNo, const QColor &color, quint32 colStart, quint32 colEnd)
{
d->plane->setLineHighlighted(lineNo, color);
d->plane->setLineHighlighted(lineNo, color, colStart, colEnd);
}
QList<QWidget*> Editor::statusbarWidgets()
......
......@@ -40,7 +40,7 @@ public:
void checkForClean();
void lock();
void unlock();
void setLineHighlighted(int lineNo, const QColor & color);
void setLineHighlighted(int lineNo, const QColor & color, quint32 colStart, quint32 colEnd);
void ensureAnalized();
QByteArray saveState() const;
void restoreState(const QByteArray &data);
......
......@@ -42,6 +42,8 @@ EditorPlane::EditorPlane(TextDocument * doc
editor_ = editor;
analizer_ = analizer;
highlightedTextLineNumber_ = -1;
highlightedTextColumnStartNumber_ = 0u;
highlightedTextColumnEndNumber_ = 0u;
highlightedLockSymbolLineNumber_ = -1;
setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding);
marginBackgroundAlpha_ = 255;
......@@ -93,10 +95,12 @@ void EditorPlane::setTeacherMode(bool v)
teacherModeFlag_ = v;
}
void EditorPlane::setLineHighlighted(int lineNo, const QColor &color)
void EditorPlane::setLineHighlighted(int lineNo, const QColor &color, quint32 colStart, quint32 colEnd)
{
highlightedTextLineNumber_ = lineNo;
highlightedTextLineColor_ = color;
highlightedTextColumnStartNumber_ = colStart;
highlightedTextColumnEndNumber_ = colEnd;
if (lineNo>-1) {
ensureHighlightedLineVisible();
}
......@@ -926,6 +930,24 @@ void EditorPlane::paintEvent(QPaintEvent *e)
p.drawLine(highlightRightRect.bottomLeft(),
highlightRightRect.bottomRight());
if (highlightedTextColumnStartNumber_ != highlightedTextColumnEndNumber_) {
// Draw a rect around statement
QPen pen;
pen.setColor(highlightedTextLineColor_);
pen.setStyle(Qt::SolidLine);
pen.setWidth(2);
p.setPen(pen);
p.setBrush(Qt::NoBrush);
uint cw = charWidth();
uint left = cw * highlightedTextColumnStartNumber_;
uint right = cw * highlightedTextColumnEndNumber_;
left += cw * 2 * document_->indentAt(highlightedTextLineNumber_);
right += cw * 2 * document_->indentAt(highlightedTextLineNumber_);
p.drawRoundedRect(left, highlightLeftRect.top(),
int(right) - int(left), highlightLeftRect.height(),
2, 2);
}
// Restore a pen
p.setPen(Qt::NoPen);
......
......@@ -50,7 +50,7 @@ public slots:
void cut();
void removeLine();
void removeLineTail();
void setLineHighlighted(int lineNo, const QColor & color);
void setLineHighlighted(int lineNo, const QColor & color, quint32 colStart, quint32 colEnd);
void signalizeNotEditable();
protected:
static QPolygon errorUnderline(int x, int y, int len);
......@@ -130,6 +130,8 @@ private:
int highlightedTextLineNumber_;
QColor highlightedTextLineColor_;
int highlightedLockSymbolLineNumber_;
quint32 highlightedTextColumnStartNumber_;
quint32 highlightedTextColumnEndNumber_ ;
class SuggestionsWindow * autocompleteWidget_;
Shared::AnalizerInterface * analizer_;
QList<QAction*> contextMenuActions_;
......
......@@ -341,22 +341,22 @@ void EditorPlugin::changeGlobalState(ExtensionSystem::GlobalState prev, Extensio
}
}
void EditorPlugin::highlightLineGreen(int documentId, int lineNo)
void EditorPlugin::highlightLineGreen(int documentId, int lineNo, quint32 colStart, quint32 colEnd)
{
if (d->editors[documentId].e)
d->editors[documentId].e->setLineHighlighted(lineNo, QColor(Qt::darkGreen));
d->editors[documentId].e->setLineHighlighted(lineNo, QColor(Qt::darkGreen), colStart, colEnd);
}
void EditorPlugin::highlightLineRed(int documentId, int lineNo)
void EditorPlugin::highlightLineRed(int documentId, int lineNo, quint32 colStart, quint32 colEnd)
{
if (d->editors[documentId].e)
d->editors[documentId].e->setLineHighlighted(lineNo, QColor(Qt::red));
d->editors[documentId].e->setLineHighlighted(lineNo, QColor(Qt::red), colStart, colEnd);
}
void EditorPlugin::unhighlightLine(int documentId)
{
if (d->editors[documentId].e)
d->editors[documentId].e->setLineHighlighted(-1, QColor::Invalid);
d->editors[documentId].e->setLineHighlighted(-1, QColor::Invalid, 0u, 0u);
}
void EditorPlugin::ensureAnalized(int documentId)
......
......@@ -33,8 +33,8 @@ public:
KumFile::Data documentContent(int documentId) const;
Shared::AnalizerInterface * analizer(int documentId);
quint32 errorsLinesCount(int documentId) const;
void highlightLineGreen(int documentId, int lineNo);
void highlightLineRed(int documentId, int lineNo);
void highlightLineGreen(int documentId, int lineNo, quint32 colStart, quint32 colEnd);
void highlightLineRed(int documentId, int lineNo, quint32 colStart, quint32 colEnd);
void unhighlightLine(int documentId);
void appendMarginText(int documentId, int lineNo, const QString & text);
void setMarginText(int documentId, int lineNo, const QString & text, const QColor & fgColor);
......
......@@ -18,6 +18,10 @@ namespace Bytecode {
class Data;
}
namespace AST {
struct Lexem;
}
namespace KumirCodeGenerator {
typedef Shared::GeneratorInterface::DebugLevel DebugLevel;
......@@ -52,6 +56,7 @@ public:
void generateConstantTable();
void generateExternTable();
private:
QList<Bytecode::Instruction> makeLineInstructions(const QList<AST::Lexem*> & lexems) const;
quint16 constantValue(Bytecode::ValueType type, quint8 dimension, const QVariant & value,
const QString & recordModule, const QString & recordClass
);
......
......@@ -27,8 +27,8 @@ Plugin::Plugin()
connect (pRun_, SIGNAL(output(QString)), this, SIGNAL(outputRequest(QString)));
connect (pRun_, SIGNAL(input(QString)), this, SIGNAL(inputRequest(QString)));
connect (pRun_, SIGNAL(finished()), this, SLOT(handleThreadFinished()));
connect (pRun_, SIGNAL(lineChanged(int)), this, SIGNAL(lineChanged(int)));
connect (pRun_, SIGNAL(updateStepsCounter(ulong)), this, SIGNAL(updateStepsCounter(ulong)));
connect (pRun_, SIGNAL(lineChanged(int,quint32,quint32)), this, SIGNAL(lineChanged(int,quint32,quint32)));
connect (pRun_, SIGNAL(updateStepsCounter(quint64)), this, SIGNAL(updateStepsCounter(quint64)));
connect (pRun_, SIGNAL(marginText(int,QString)), this, SIGNAL(marginText(int,QString)));
connect (pRun_, SIGNAL(clearMarginRequest(int,int)), this, SIGNAL(clearMargin(int,int)));
connect (pRun_, SIGNAL(marginTextReplace(int,QString,bool)),
......@@ -80,6 +80,11 @@ int Plugin::currentLineNo() const
return pRun_->effectiveLineNo();
}
QPair<quint32,quint32> Plugin::currentColumn() const
{
return QPair<quint32,quint32>(pRun_->vm->effectiveColumn().first, pRun_->vm->effectiveColumn().second);
}
bool Plugin::loadProgram(const QString & filename, const QByteArray & source, Shared::ProgramFormat format)
{
bool ok = false;
......@@ -439,9 +444,9 @@ void Plugin::handleThreadFinished()
}
}
void Plugin::handleLineChanged(int lineNo)
void Plugin::handleLineChanged(int lineNo, quint32 colStart, quint32 colEnd)
{
emit lineChanged(lineNo);
emit lineChanged(lineNo, colStart, colEnd);
}
......
......@@ -26,6 +26,7 @@ public:
QString error() const;
int currentLineNo() const ;
QPair<quint32,quint32> currentColumn() const;
inline QDateTime loadedProgramVersion() const { return loadedVersion_; }
unsigned long int stepsCounted() const;
......@@ -77,16 +78,17 @@ protected:
protected slots:
void handleThreadFinished();
void handleLineChanged(int lineNo);
void handleLineChanged(int lineNo, quint32 colStart, quint32 colEnd);
signals:
void updateStepsCounter(unsigned long int);
void updateStepsCounter(quint64);
void errorOutputRequest(const QString &);
void stopped(int reason);
void finishInput(const QVariantList & data);
void inputRequest(const QString & format);
void outputRequest(const QString & output);
void lineChanged(int lineNo);
void lineChanged(int lineNo, quint32 colStart, quint32 colEnd);
void marginText(int lineNo, const QString & text);
void replaceMarginText(int lineNo, const QString & text, bool redFgColor);
void clearMargin(int fromLine, int toLine);
......
......@@ -59,7 +59,7 @@ void Run::stop()
QMutexLocker l(stoppingMutex_);
stoppingFlag_ = true;
if (!isRunning()) {
emit lineChanged(-1);
emit lineChanged(-1, 0u, 0u);
emit finished();
}
}
......@@ -85,7 +85,7 @@ void Run::runStepOut()
{
stepDoneFlag_ = false;
algDoneFlag_ = false;
emit lineChanged(-1);
emit lineChanged(-1, 0u, 0u);
runMode_ = RM_StepOut;
vm->setNextCallOut();
start();
......@@ -288,19 +288,19 @@ bool Run::setTextToMargin(int lineNo, const String &s, bool red)
return true;
}
bool Run::noticeOnLineNoChanged(int lineNo)
bool Run::noticeOnLineChanged(int lineNo, quint32 colStart, quint32 colEnd)
{
stepDoneMutex_->lock();
stepDoneFlag_ = true;
stepDoneMutex_->unlock();
if (mustStop())
emit lineChanged(lineNo);
emit lineChanged(lineNo, colStart, colEnd);
else
emit lineChanged(-1);
emit lineChanged(-1, 0u, 0u);
return true;
}
bool Run::noticeOnStepsChanged(unsigned long int stepsDone)
bool Run::noticeOnStepsChanged(quint64 stepsDone)
{
emit updateStepsCounter(stepsDone);
return true;
......@@ -346,15 +346,15 @@ bool Run::mustStop() const
}
}
void Run::handleAlgorhitmDone(int lineNo)
void Run::handleAlgorhitmDone(int lineNo, quint32 colStart, quint32 colEnd)
{
algDoneMutex_->lock();
algDoneFlag_ = true;
algDoneMutex_->unlock();
if (mustStop())
emit lineChanged(lineNo);
emit lineChanged(lineNo, colStart, colEnd);
else
emit lineChanged(-1);
emit lineChanged(-1, 0u, 0u);
}
void Run::handlePauseRequest()
......@@ -373,7 +373,9 @@ void Run::run()
vm->evaluateNextInstruction();
if (vm->error().length()>0) {
int lineNo = vm->effectiveLineNo();
emit lineChanged(lineNo);
std::pair<quint32,quint32> colNo =
vm->effectiveColumn();
emit lineChanged(lineNo, colNo.first, colNo.second);
emit error(QString::fromStdWString(vm->error()));
break;
}
......
......@@ -52,11 +52,9 @@ public slots:
void runBlind();
void runContinuous();
bool noticeOnLineNoChanged(
int /*lineNo*/
);
bool noticeOnLineChanged(int lineNo, uint32_t colStart, uint32_t colEnd);
bool noticeOnStepsChanged(unsigned long int stepsDone);
bool noticeOnStepsChanged(quint64 stepsDone);
bool setTextToMargin(int lineNo, const String & s, bool red);
bool appendTextToMargin(int lineNo, const String & s);
......@@ -94,14 +92,14 @@ public slots:
const Kumir::String & name,
const int indeces[4]);
void handleAlgorhitmDone(int lineNo);
void handleAlgorhitmDone(int lineNo, quint32 colStart, quint32 colEnd);
void handlePauseRequest();
signals:
void updateStepsCounter(unsigned long int);
void updateStepsCounter(quint64);
void finishInput(const QVariantList &data);
void lineChanged(int lineNo);
void lineChanged(int lineNo, quint32 colStart, quint32 colEnd);
void output(const QString &value);
void error(const QString & message);
void input(const QString & format);
......
......@@ -70,6 +70,9 @@ public:
void terminate();
bool hasMoreInstructions() const;
int currentLineNo() const;
inline QPair<quint32,quint32> currentColumn() const {
return QPair<quint32,quint32>(0u,0u);
} // Python can't handle columns
QString error() const;
// methods to access within self static functions
......
......@@ -32,8 +32,8 @@ public:
virtual KumFile::Data documentContent(int documentId) const = 0;
virtual AnalizerInterface * analizer(int documentId) = 0;
virtual quint32 errorsLinesCount(int documentId) const = 0;
virtual void highlightLineGreen(int documentId, int lineNo) = 0;
virtual void highlightLineRed(int documentId, int lineNo) = 0;
virtual void highlightLineGreen(int documentId, int lineNo, quint32 colStart, quint32 colEnd) = 0;
virtual void highlightLineRed(int documentId, int lineNo, quint32 colStart, quint32 colEnd) = 0;
virtual void unhighlightLine(int documentId) = 0;
virtual void appendMarginText(int documentId, int lineNo, const QString & text) = 0;
virtual void setMarginText(int documentId, int lineNo, const QString & text, const QColor & color) = 0;
......
......@@ -28,6 +28,7 @@ public:
virtual bool hasMoreInstructions() const = 0;
virtual bool hasTestingEntryPoint() const = 0;
virtual int currentLineNo() const = 0;
virtual QPair<quint32,quint32> currentColumn() const = 0;
virtual QString error() const = 0;
virtual QVariant valueStackTopItem() const = 0;
virtual unsigned long int stepsCounted() const = 0;
......
......@@ -50,6 +50,7 @@ struct Context {
algId = -1;
program = 0;
moduleContextNo = 0;
columnStart = columnEnd = 0u;
}
VM::AnyValue registers[255];
......@@ -61,6 +62,8 @@ struct Context {
uint8_t moduleId;
int algId;
int lineNo;
uint32_t columnStart;
uint32_t columnEnd;
size_t moduleContextNo;
Kumir::String name;
};
......
......@@ -86,6 +86,7 @@ public /*methods*/:
/** Return current 'line number' or -1 if not applicable */
inline int effectiveLineNo() const;
inline std::pair<uint32_t,uint32_t> effectiveColumn() const;
/** Returns 'true' if evaluating non-toplevel user function */
inline bool canStepOut() const;
......@@ -185,7 +186,7 @@ private /*instruction methods*/:
inline void do_push(uint8_t);
inline void do_ret();
inline void do_error(uint8_t, uint16_t);
inline void do_line(uint16_t);
inline void do_line(const Bytecode::Instruction & instr);
inline void do_ref(uint8_t, uint16_t);
inline void do_setref(uint8_t, uint16_t);
inline void do_refarr(uint8_t, uint16_t);
......@@ -939,7 +940,7 @@ void KumirVM::evaluateNextInstruction()
do_error(instr.scope, instr.arg);
break;
case LINE:
do_line(instr.arg);
do_line(instr);
break;
case REF:
do_ref(instr.scope, instr.arg);
......@@ -2675,15 +2676,16 @@ void KumirVM::do_error(uint8_t s, uint16_t id)
}
}
void KumirVM::do_line(uint16_t no)
void KumirVM::do_line(const Bytecode::Instruction & instr)
{
uint32_t from = 0u, to = 0u;
if (extractColumnPositionsFromLineInstruction(instr, from, to)) {
currentContext().columnStart = from;
currentContext().columnEnd = to;
if (!blindMode_ && contextsStack_.top().runMode==CRM_OneStep) {
if (contextsStack_.top().lineNo!=no) {
if (debugHandler_)
debugHandler_->noticeOnLineNoChanged(no);
debugHandler_->noticeOnLineChanged(currentContext().lineNo, from, to);
}
}
contextsStack_.top().lineNo = no;
if (currentContext().IP!=-1) {
stepsCounter_ ++;
if (!blindMode_ && debugHandler_) {
......@@ -2693,6 +2695,18 @@ void KumirVM::do_line(uint16_t no)
debugHandler_->noticeOnStepsChanged(stepsCounter_);
}
}
}
else {
int no = instr.arg;
// if (!blindMode_ && contextsStack_.top().runMode==CRM_OneStep) {
// if (contextsStack_.top().lineNo!=no) {
// if (debugHandler_)
// debugHandler_->noticeOnLineChanged(no, 0u, 0u);
// }
// }
currentContext().lineNo = no;
currentContext().columnStart = currentContext().columnEnd = 0u;
}
nextIP();
}
......@@ -3123,9 +3137,17 @@ void KumirVM::do_pause(uint16_t lineNo)
}
blindMode_ = false;
if (prevRunMode!=CRM_OneStep) {
if (debugHandler_) debugHandler_->noticeOnLineNoChanged(lineNo);
if (debugHandler_) {
debugHandler_->noticeOnLineChanged(currentContext().lineNo,
currentContext().columnStart,
currentContext().columnEnd);
}
(*pause_)();
if (debugHandler_) debugHandler_->noticeOnLineNoChanged(lineNo);
if (debugHandler_) {
debugHandler_->noticeOnLineChanged(currentContext().lineNo,
currentContext().columnStart,
currentContext().columnEnd);
}
if (debugHandler_) updateDebugger();
}
if (stacksMutex_) stacksMutex_->unlock();
......@@ -3181,6 +3203,15 @@ void KumirVM::setNextCallStepOver()
}
}
std::pair<uint32_t,uint32_t> KumirVM::effectiveColumn() const
{
std::pair<uint32_t, uint32_t> result(0u, 0u);
if (contextsStack_.size() > 0) {
result.first = contextsStack_.top().columnStart;
result.second = contextsStack_.top().columnEnd;
}
return result;
}
int KumirVM::effectiveLineNo() const
{
......
......@@ -268,12 +268,14 @@ public:
int /*lineNo*/
) { return false; }
inline virtual bool noticeOnLineNoChanged(
int /*lineNo*/
inline virtual bool noticeOnLineChanged(
int /*lineNo*/,
uint32_t /*columnStartNo*/,
uint32_t /*columnEndNo*/
) { return false; }
inline virtual bool noticeOnStepsChanged(
unsigned long int /*stepsDone*/
uint64_t /*stepsDone*/
) { return false; }
inline virtual bool debuggerReset() { return false; }
......
......@@ -66,6 +66,11 @@ enum VariableScope {
GLOBAL= 0x03 // Value from globals table
};
enum LineSpecification {
LINE_NUMBER = 0x00,
COLUMN_START_AND_END = 0x80
};
/* Instruction has optimal (aka serialized) size of 32 bit:
- first byte is Instruction Type
- second byte is Module Number (for CALL),
......@@ -79,6 +84,7 @@ enum VariableScope {
struct Instruction {
InstructionType type;
union {
LineSpecification lineSpec;
VariableScope scope;
uint8_t module;
uint8_t registerr;
......@@ -194,6 +200,36 @@ struct AS_Helpers {
AS_Values algorithms;
};
inline bool extractColumnPositionsFromLineInstruction(const Instruction & instr,
uint32_t &from,
uint32_t &to)
{
if (instr.type == LINE && (instr.scope & COLUMN_START_AND_END) != 0) {
uint32_t value = ((instr.lineSpec & 0x3F) << 16) | instr.arg;
from = value >> 11;
to = value & 0x7FF;
return true;
}
else {
from = to = 0u;
return false;
}
}
inline Instruction& setColumnPositionsToLineInstruction(Instruction & instr,
uint32_t from,
uint32_t to)
{
uint32_t value = (from << 11) | to;
uint16_t arg = value & 0xFFFF;
uint8_t scope = (value >> 16) & 0xFF;
scope = scope | COLUMN_START_AND_END;
instr.type = LINE;
instr.lineSpec = LineSpecification(scope);