Properly move NbRuntime to its own thread
diff --git a/.dir-locals.el b/.dir-locals.el
new file mode 100644
index 0000000..e64b4d6
--- /dev/null
+++ b/.dir-locals.el
@@ -0,0 +1,2 @@
+((c++-mode
+ (indent-tabs-mode . nil)))
diff --git a/ide/IdeMain.cpp b/ide/IdeMain.cpp
index c8eae76..ec6627e 100644
--- a/ide/IdeMain.cpp
+++ b/ide/IdeMain.cpp
@@ -13,9 +13,6 @@
QQmlApplicationEngine engine;
- // This is done implicitly now.
- // registerTypes(&engine);
-
QQuickStyle::setStyle("Material");
qRegisterMetaType<CellModel>();
diff --git a/ide/NbRuntime.cpp b/ide/NbRuntime.cpp
index 35df413..eeb9d0d 100644
--- a/ide/NbRuntime.cpp
+++ b/ide/NbRuntime.cpp
@@ -5,7 +5,7 @@
#include "../StdLib.h"
NbRuntime::NbRuntime(QObject *parent)
- : QThread(parent)
+ : QObject(parent)
{
StdLib().load(_eval);
}
@@ -65,7 +65,7 @@
{
ParseResult ret;
Function func;
- AstNode ast;
+ QList<AstNode> ast;
if ((ret = parser.parseFunctionDefinition(&func)))
{
@@ -76,14 +76,17 @@
emit cellFailedToParse(cell, ret);
goto endOfCell; // JANK!
}
- else if ((ret = parser.parseOne(&ast)))
+ else if ((ret = parser.parseMany(&ast)) && !ast.empty())
{
- RuntimeResult nodeRes = _eval.evaluate(ast, _ctx);
- result += nodeRes;
-
- if (!nodeRes.success())
+ for (const AstNode &node : ast)
{
- break;
+ RuntimeResult nodeRes = _eval.evaluate(node, _ctx);
+ result += nodeRes;
+
+ if (!nodeRes.success())
+ {
+ goto endOfParseLoop;
+ }
}
}
else if (ret.status() == ParseResult::INCOMPLETE)
@@ -105,6 +108,7 @@
}
}
+ endOfParseLoop:
emit cellFinishedRunning(cell, result);
endOfCell:
diff --git a/ide/NbRuntime.h b/ide/NbRuntime.h
index 2f6a845..9d4c714 100644
--- a/ide/NbRuntime.h
+++ b/ide/NbRuntime.h
@@ -9,7 +9,7 @@
#include "../Evaluator.h"
#include "../Parser.h"
-class NbRuntime : public QThread
+class NbRuntime : public QObject
{
Q_OBJECT
diff --git a/ide/Notebook.cpp b/ide/Notebook.cpp
index 953e98b..3396779 100644
--- a/ide/Notebook.cpp
+++ b/ide/Notebook.cpp
@@ -4,17 +4,26 @@
// TODO: avoid potential race condition if Cell is deleted, pass by value with same UUID instead
+Notebook::~Notebook()
+{
+ _rtThread->quit();
+ _rtThread->wait();
+}
+
Notebook::Notebook(QObject *parent)
: QObject(parent)
, _cellModel(new CellModel(this))
+ , _rt(new NbRuntime(this))
+ , _rtThread(new QThread(this))
{
- connect(&_rt, &NbRuntime::cellFailedToParse, this, &Notebook::cellFailedToParse);
- connect(&_rt, &NbRuntime::cellFinishedRunning, this, &Notebook::cellFinishedRunning);
- connect(&_rt, &NbRuntime::cellQuit, this, &Notebook::cellQuit);
- connect(&_rt, &NbRuntime::cellRunning, this, &Notebook::cellRunning);
- connect(&_rt, &NbRuntime::cellWaiting, this, &Notebook::cellWaiting);
+ connect(_rt, &NbRuntime::cellFailedToParse, this, &Notebook::cellFailedToParse);
+ connect(_rt, &NbRuntime::cellFinishedRunning, this, &Notebook::cellFinishedRunning);
+ connect(_rt, &NbRuntime::cellQuit, this, &Notebook::cellQuit);
+ connect(_rt, &NbRuntime::cellRunning, this, &Notebook::cellRunning);
+ connect(_rt, &NbRuntime::cellWaiting, this, &Notebook::cellWaiting);
- _rt.start();
+ _rt->moveToThread(_rtThread);
+ _rtThread->start();
}
Notebook::Notebook(const Notebook &other, QObject *parent)
@@ -34,12 +43,12 @@
void Notebook::runCell(QUuid uuid)
{
qInfo() << "Running cell" << uuid;
- _rt.queueCell(Cell::cellFromUuid(uuid));
+ _rt->queueCell(Cell::cellFromUuid(uuid));
}
void Notebook::quitCell(QUuid uuid)
{
- _rt.unqueueCell(Cell::cellFromUuid(uuid));
+ _rt->unqueueCell(Cell::cellFromUuid(uuid));
}
void Notebook::cellFinishedRunning(Cell *cell, RuntimeResult result)
diff --git a/ide/Notebook.h b/ide/Notebook.h
index 6a5d0cf..0dbe21e 100644
--- a/ide/Notebook.h
+++ b/ide/Notebook.h
@@ -14,6 +14,7 @@
Q_PROPERTY(CellModel *cellModel READ cellModel NOTIFY cellModelChanged)
public:
+ ~Notebook();
explicit Notebook(QObject *parent = nullptr);
Notebook(const Notebook &other, QObject *parent = nullptr);
@@ -37,7 +38,8 @@
QList<Cell *> _cells;
CellModel *_cellModel;
- NbRuntime _rt;
+ NbRuntime *_rt;
+ QThread *_rtThread;
};
Q_DECLARE_METATYPE(Notebook)
diff --git a/ide/qml/NotebookCell.qml b/ide/qml/NotebookCell.qml
index 240e7f8..3c59393 100644
--- a/ide/qml/NotebookCell.qml
+++ b/ide/qml/NotebookCell.qml
@@ -22,7 +22,10 @@
height: column.height
- Keys.onEscapePressed: root.cellUnfocused()
+ Keys.onEscapePressed: {
+ root.cellUnfocused()
+ code.focus = false
+ }
ColumnLayout {
id: column
@@ -76,9 +79,11 @@
Layout.fillHeight: true
TextArea {
+ id: code
+
Layout.fillWidth: true
Layout.fillHeight: true
- id: code
+
font.family: "monospace"
text: root.code
selectByMouse: true
@@ -115,6 +120,8 @@
}
RoundButton {
+ Layout.alignment: Qt.AlignTop
+
icon.source: "qrc:///icons/menu.svg"
icon.color: Constants.buttonGrey
flat: true
diff --git a/main.cpp b/main.cpp
index 0cb36e8..278f1d0 100644
--- a/main.cpp
+++ b/main.cpp
@@ -22,35 +22,35 @@
void testEval(QString function, QString expression, QString expected)
{
- Evaluator eval;
- Parser funcParser(function),
- exprParser(expression),
- resParser(expected);
+ Evaluator eval;
+ Parser funcParser(function),
+ exprParser(expression),
+ resParser(expected);
- Function func;
+ Function func;
- QList<AstNode> expr;
- ParseResult exprRet = exprParser.parseMany<AstNode>(&expr);
- QList<Token> res;
- ParseResult resRet = resParser.parseMany<Token>(&res);
- ParseResult funcRet;
+ QList<AstNode> expr;
+ ParseResult exprRet = exprParser.parseMany<AstNode>(&expr);
+ QList<Token> res;
+ ParseResult resRet = resParser.parseMany<Token>(&res);
+ ParseResult funcRet;
- QList<Token> result;
+ QList<Token> result;
- exprParser.skip();
- resParser.skip();
- while ((funcRet = funcParser.parseFunctionDefinition(&func)))
- {
- eval.addFunction(func);
- }
+ exprParser.skip();
+ resParser.skip();
+ while ((funcRet = funcParser.parseFunctionDefinition(&func)))
+ {
+ eval.addFunction(func);
+ }
- funcParser.skip();
+ funcParser.skip();
- if (!exprRet || !resRet || funcRet.status() == ParseResult::INCOMPLETE)
- {
+ if (!exprRet || !resRet || funcRet.status() == ParseResult::INCOMPLETE)
+ {
g_numFailed++;
qDebug() << "\n\033[31mTEST FAILS:\033[0m";
- qDebug() << "Failed to fully parse expression, function or result";
+ qDebug() << "Failed to fully parse expression, function or result";
qDebug() << "Function:";
sout(pprint(funcRet, funcParser));
@@ -60,33 +60,33 @@
qDebug() << "Result:";
sout(pprint(resRet, resParser));
- goto end;
- }
+ goto end;
+ }
- for (const AstNode &node : expr)
- {
- RuntimeResult rr = eval.evaluate(node, VarContext());
+ for (const AstNode &node : expr)
+ {
+ RuntimeResult rr = eval.evaluate(node, VarContext());
- if (!rr.success())
- {
- g_numFailed++;
- qDebug() << "\n\033[31mTEST FAILS:\033[0m";
- qDebug() << "Runtime error while evaluating" << node;
- qDebug() << rr;
+ if (!rr.success())
+ {
+ g_numFailed++;
+ qDebug() << "\n\033[31mTEST FAILS:\033[0m";
+ qDebug() << "Runtime error while evaluating" << node;
+ qDebug() << rr;
- goto end;
- }
+ goto end;
+ }
- result.append(rr.result());
- }
+ result.append(rr.result());
+ }
- if (result != res)
- {
- g_numFailed++;
- qDebug() << "\n\033[31mTEST FAILS:\033[0m";
- qDebug() << "Expected result" << res;
- qDebug() << "Got" << result;
- }
+ if (result != res)
+ {
+ g_numFailed++;
+ qDebug() << "\n\033[31mTEST FAILS:\033[0m";
+ qDebug() << "Expected result" << res;
+ qDebug() << "Got" << result;
+ }
end:
qDebug() << "\033[36mEvaluate\033[0m" << function << expression << "->" << pprint(result);
@@ -94,7 +94,7 @@
void testEval(QString function, QString expression, QList<Token> expected)
{
- testEval(function, expression, pprint(expected));
+ testEval(function, expression, pprint(expected));
}
void testEval(QString expression, QString expected)
@@ -124,13 +124,13 @@
Parser dataParser(data),
patternParser(pattern);
- QList<Token> parsedData, parsedPattern;
-
- dataParser.parseMany<Token>(&parsedData);
- patternParser.parseMany<Token>(&parsedPattern);
+ QList<Token> parsedData, parsedPattern;
+
+ dataParser.parseMany<Token>(&parsedData);
+ patternParser.parseMany<Token>(&parsedPattern);
testMatch(pattern + " = " + data, shouldBe,
- match(parsedData, parsedPattern, VarContext()));
+ match(parsedData, parsedPattern, VarContext()));
}
void testParseAst(QString string, QList<AstNode> equals = {})
@@ -138,14 +138,14 @@
Parser parser{string};
QList<AstNode> result;
- parser.parseMany<AstNode>(&result);
+ parser.parseMany<AstNode>(&result);
- if (!equals.empty() && result != equals)
- {
+ if (!equals.empty() && result != equals)
+ {
g_numFailed++;
qDebug() << "\n\033[31mTEST FAILS:\033[0m";
qDebug() << "Expected" << pprint(equals);
- }
+ }
qDebug() << "\033[36mParse\033[0m" << string << pprint(result);
}
@@ -153,7 +153,7 @@
void testParseFunc(QString string)
{
Parser parser{string};
- ParseResult ret;
+ ParseResult ret;
Function func;
@@ -200,13 +200,13 @@
Token('e', "middle"),
Token('s', "a")};
testMatch("s.a e.middle s.a = aea", true,
- match({Token('a'), Token('e'), Token('a')}, sameStartEnd, VarContext()));
+ match({Token('a'), Token('e'), Token('a')}, sameStartEnd, VarContext()));
testMatch("s.a e.middle s.a = aef Hi a", true,
- match({Token('a'), Token('e'), Token('f'), Token("Hi"), Token('a')}, sameStartEnd, VarContext()));
+ match({Token('a'), Token('e'), Token('f'), Token("Hi"), Token('a')}, sameStartEnd, VarContext()));
testMatch("s.a e.middle s.a = aef Hi c", false,
- match({Token('a'), Token('e'), Token('f'), Token("Hi"), Token('c')}, sameStartEnd, VarContext()));
+ match({Token('a'), Token('e'), Token('f'), Token("Hi"), Token('c')}, sameStartEnd, VarContext()));
LTok parenthesized = {
Token(LTok({Token('s', "a")})),
@@ -220,14 +220,14 @@
Token('y')};
testMatch("(s.a) e.Middle s.a = (y)f MiddleStuff y", true,
- match(parenTest1, parenthesized, VarContext()));
+ match(parenTest1, parenthesized, VarContext()));
// testMatch("(y)f Middle-stuff y", "(s.a) e.Middle s.a");
testMatch("(a)", "(a)");
- testMatch("hello", "s.A e.Rest");
- testMatch("123", "123");
- testMatch("(123)", "t.a");
- testMatch("(123)", "(s.a)");
+ testMatch("hello", "s.A e.Rest");
+ testMatch("123", "123");
+ testMatch("(123)", "t.a");
+ testMatch("(123)", "(s.a)");
}
void testAllParses()
@@ -244,8 +244,8 @@
testParseAst("(s.a) e.Middle s.a");
testParseAst("Hello; Goodbye");
testParseAst("Key = Value");
- testParseAst("123", {AstNode("123", 10)});
- testParseAst("12 00", {AstNode::fromInteger(12), AstNode::fromInteger(0)});
+ testParseAst("123", {AstNode("123", 10)});
+ testParseAst("12 00", {AstNode::fromInteger(12), AstNode::fromInteger(0)});
testParseAst("s.A s.B", {AstNode('s', "A"), AstNode('s', "B")});
testParseAst("a '=' b", {AstNode('a'), AstNode('='), AstNode('b')});
testParseAst("'This\\'<>#$@#^%\\n' 'another $3543543'");
@@ -259,8 +259,8 @@
void testAllEvals()
{
- testEval("First {s.A e.Rest = s.A;}", "<First hello>", "h");
- testEval("Number { = 123; }", "<Number>", QList<Token>{Token::fromInteger(123)});
+ testEval("First {s.A e.Rest = s.A;}", "<First hello>", "h");
+ testEval("Number { = 123; }", "<Number>", QList<Token>{Token::fromInteger(123)});
testEval("<Br Name '=' Jim> <Dg Name>", "Jim");
testEval("<Br A '=' hello> <Br A '=' 'good bye'> <Dg A> <Dg A>", "'good byehello'");
}
@@ -273,43 +273,43 @@
a.setApplicationName("REFAL");
a.setApplicationVersion("1.0-a1");
- QCommandLineParser cli;
- cli.setApplicationDescription("REFAL interpreter");
- cli.addHelpOption();
- cli.addVersionOption();
+ QCommandLineParser cli;
+ cli.setApplicationDescription("REFAL interpreter");
+ cli.addHelpOption();
+ cli.addVersionOption();
cli.addPositionalArgument("script", "REFAL script to run");
- QCommandLineOption testOption(QStringList{"t", "test"}, "Run test suite.");
- cli.addOption(testOption);
+ QCommandLineOption testOption(QStringList{"t", "test"}, "Run test suite.");
+ cli.addOption(testOption);
QCommandLineOption replOption(QStringList({"r", "repl"}), "Start CLI REPL");
cli.addOption(replOption);
- cli.process(a);
+ cli.process(a);
if (cli.positionalArguments().length() > 0)
{
qDebug() << "Running script" << cli.positionalArguments()[0];
}
else if (cli.isSet(testOption))
- {
- testAllMatches();
- qDebug() << "";
- testAllParses();
- qDebug() << "";
- testAllFunctionDefs();
- qDebug() << "";
- testAllEvals();
+ {
+ testAllMatches();
+ qDebug() << "";
+ testAllParses();
+ qDebug() << "";
+ testAllFunctionDefs();
+ qDebug() << "";
+ testAllEvals();
- qDebug() << "";
+ qDebug() << "";
- return testResults();
- }
+ return testResults();
+ }
else if (cli.isSet(replOption))
- {
- Repl repl;
- repl.start();
- }
+ {
+ Repl repl;
+ repl.start();
+ }
else
{
return ideMain(&a);