Add AssertionException, specialize pprint
diff --git a/Evaluator.cpp b/Evaluator.cpp
index 56685ec..9ce5bf7 100644
--- a/Evaluator.cpp
+++ b/Evaluator.cpp
@@ -287,8 +287,7 @@
void rtError(QString brief, QString details)
{
- eout("Runtime Error: " + brief);
- eout(details);
+ throw AssertionException(brief + "\n" + details);
}
void EvalQuitException::raise() const
@@ -326,3 +325,29 @@
{
return "StackOverflowException: at " + pprint(_failedAt);
}
+
+AssertionException::AssertionException(QString message)
+ : QException()
+{
+ _message = message;
+}
+
+QString AssertionException::message() const
+{
+ return _message;
+}
+
+void AssertionException::raise() const
+{
+ throw *this;
+}
+
+AssertionException *AssertionException::clone() const
+{
+ return new AssertionException(*this);
+}
+
+AssertionException::operator QString() const
+{
+ return "AssertionException: " + _message;
+}
diff --git a/Evaluator.h b/Evaluator.h
index 47ea941..7034669 100644
--- a/Evaluator.h
+++ b/Evaluator.h
@@ -59,6 +59,23 @@
AstNode _failedAt;
};
+class AssertionException : public QException
+{
+public:
+ AssertionException(QString message = "");
+ AssertionException(const AssertionException &other) = default;
+
+ QString message() const;
+
+ void raise() const override;
+ AssertionException *clone() const override;
+
+ operator QString() const;
+
+private:
+ QString _message;
+};
+
class Evaluator {
public:
Evaluator();
diff --git a/PPrint.h b/PPrint.h
index 6298d6b..3ae9546 100644
--- a/PPrint.h
+++ b/PPrint.h
@@ -3,6 +3,8 @@
#include <QString>
#include <QList>
+#include <type_traits>
+
#include "Token.h"
#include "AstNode.h"
#include "Parser.h"
@@ -16,6 +18,25 @@
//template <>
//QString pprint<AstNode>(AstNode val);
+template <typename T, typename std::enable_if_t<std::is_base_of<TokenBase<T>, T>::value>::value = true>
+QString pprint(QList<T> val)
+{
+ QString out;
+ int lastType = -1;
+
+ qInfo() << "pprint specialized";
+
+ for (const T &v : val)
+ {
+ if ((lastType != v.type() || v.type() != T::SYMBOL) && lastType != -1)
+ out += " ";
+
+ out += QString(v);
+ }
+
+ return out;
+}
+
template <typename T>
QString pprint(QList<T> val)
{
diff --git a/StdLib.cpp b/StdLib.cpp
index 5d6bf6a..be91d59 100644
--- a/StdLib.cpp
+++ b/StdLib.cpp
@@ -1,6 +1,9 @@
#include "StdLib.h"
#include "PPrint.h"
+#include <QEventLoop>
+#include <QTimer>
+
StdLib::StdLib()
{
_print.addNativeSentence("e.Expr", [](VarContext args)
@@ -16,10 +19,27 @@
sout(pprint(expr));
return QList<Token>();
});
+
+ _sleep.addNativeSentence("s.Time", [](VarContext args)
+ {
+ Token time = args.singleVar("Time");
+
+ if (time.type() != Token::INTEGER)
+ rtError("Invalid argument", "First argument to <Time> must be an integer, got " + pprint(time));
+
+ QEventLoop loop;
+ QTimer timer;
+ timer.connect(&timer, &QTimer::timeout, &loop, &QEventLoop::quit);
+ timer.start(time.integer());
+ loop.exec();
+
+ return QList<Token>();
+ });
}
void StdLib::load(Evaluator &eval)
{
eval.addFunction(_print);
eval.addFunction(_prout);
+ eval.addFunction(_sleep);
}
diff --git a/StdLib.h b/StdLib.h
index 61fc2a6..0cc98a5 100644
--- a/StdLib.h
+++ b/StdLib.h
@@ -11,5 +11,6 @@
private:
Function _print{"Print"},
- _prout{"Prout"};
+ _prout{"Prout"},
+ _sleep{"Sleep"};
};
diff --git a/ide/CellModel.cpp b/ide/CellModel.cpp
index 8271c87..0aa29bb 100644
--- a/ide/CellModel.cpp
+++ b/ide/CellModel.cpp
@@ -147,6 +147,11 @@
addCell(Cell(code, result));
}
+void CellModel::insertCellBefore(int index)
+{
+ insertRow(index);
+}
+
void CellModel::announceCellChange(Cell *cell, int role)
{
// TODO: Optimize
diff --git a/ide/CellModel.h b/ide/CellModel.h
index 1f56056..428422a 100644
--- a/ide/CellModel.h
+++ b/ide/CellModel.h
@@ -44,6 +44,8 @@
Q_INVOKABLE void addCell(const Cell &cell);
Q_INVOKABLE void addCell(QString code, QString result);
+ Q_INVOKABLE void insertCellBefore(int index);
+
private:
Notebook *_notebook;
void announceCellChange(Cell *cell, int role);
diff --git a/ide/NbRuntime.cpp b/ide/NbRuntime.cpp
index 8454597..35df413 100644
--- a/ide/NbRuntime.cpp
+++ b/ide/NbRuntime.cpp
@@ -2,10 +2,12 @@
#include "NbRuntime.h"
#include "../Parser.h"
+#include "../StdLib.h"
NbRuntime::NbRuntime(QObject *parent)
: QThread(parent)
{
+ StdLib().load(_eval);
}
void NbRuntime::queueCell(Cell *cell)
@@ -118,5 +120,10 @@
_running = nullptr;
emit cellFinishedRunning(cell, RuntimeResult(ex));
}
+ catch (AssertionException &ex)
+ {
+ _running = nullptr;
+ emit cellFinishedRunning(cell, RuntimeResult(ex));
+ }
}
}
diff --git a/ide/Notebook.cpp b/ide/Notebook.cpp
index 82bee7e..953e98b 100644
--- a/ide/Notebook.cpp
+++ b/ide/Notebook.cpp
@@ -2,6 +2,8 @@
#include "CellModel.h"
#include "../PPrint.h"
+// TODO: avoid potential race condition if Cell is deleted, pass by value with same UUID instead
+
Notebook::Notebook(QObject *parent)
: QObject(parent)
, _cellModel(new CellModel(this))
diff --git a/ide/qml/main.qml b/ide/qml/main.qml
index bf99a8d..ef6134a 100644
--- a/ide/qml/main.qml
+++ b/ide/qml/main.qml
@@ -76,7 +76,7 @@
}
InsertRow {
- onInsertClicked: notebook.cellModel.insertRows(notebook.cellModel.index(0, 0), 1);
+ onInsertClicked: notebook.cellModel.insertCellBefore(0)
}
}
@@ -86,7 +86,6 @@
required property var model
required property var index
required property var uuid
- required property int status
width: codeEditor.width - 5
@@ -98,7 +97,7 @@
onInsertBelowClicked: {
console.info(index);
- notebook.cellModel.insertRows(notebook.cellModel.index(index + 1, 0), 1);
+ notebook.cellModel.insertCellBefore(index + 1);
}
onRunClicked: {