-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathnotebook_app.cpp
297 lines (235 loc) · 8.4 KB
/
notebook_app.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
#include "notebook_app.hpp"
NotebookApp::NotebookApp(QWidget *parent) :QWidget(parent)
{
inputWidget = new InputWidget;
outputWidget = new OutputWidget;
inputWidget->setObjectName("input");
outputWidget->setObjectName("output");
startButton = new QPushButton("Start Kernel");
stopButton = new QPushButton("Stop Kernel");
resetButton = new QPushButton("Reset Kernel");
interruptButton = new QPushButton("Interrupt Kernel");
startButton->setObjectName("start");
stopButton->setObjectName("stop");
resetButton->setObjectName("reset");
interruptButton->setObjectName("interrupt");
//twoThreadsRunning = true;
// put make-point/line/text procedure into env map after reading in the file
eval_from_file(STARTUP_FILE);
interp.interrupt();
resetInterp = interp;
guiThread = new std::thread(&Interpreter::Kernal, &interp);
QGridLayout *layout = new QGridLayout();
layout->addWidget(startButton, 0, 0);
layout->addWidget(stopButton, 0, 1);
layout->addWidget(resetButton, 0, 2);
layout->addWidget(interruptButton, 0, 3);
layout->addWidget(inputWidget, 1, 0,1,4);//,1,1,Qt::AlignJustify);
layout->addWidget(outputWidget, 2, 0,1,4);//,1,1,Qt::AlignJustify);
setLayout(layout);
connectSlots();
}
NotebookApp::~NotebookApp() {
if (guiThread != nullptr) {
MessageQueue<std::string> &inputMessage = MessageQueue<std::string>::getInstance();
inputMessage.push("%exit");
guiThread->join();
delete guiThread;
}
guiThread = nullptr;
}
void NotebookApp::handle_PlotScript(QString input)
{
emit(initializeScreen());
std::string inputStr = input.toStdString();
//qDebug() << inputStr;
std::istringstream argumentStream(inputStr);
MessageQueue<std::string> &inputMessage = MessageQueue<std::string>::getInstance();
MessageQueue<messageOut> &outputMessage = MessageQueue<messageOut>::getInstance();
//MessageQueue<Expression> &interruptMessage = MessageQueue<Expression>::getInstance();
messageOut output;
if (inputStr != "%start" && guiThread != nullptr) {
inputMessage.push(inputStr);
qDebug() << "message pushed";
}
QString test = QString::fromStdString(inputStr);
qDebug() << test;
if (inputStr == "%start") {
if (guiThread == nullptr) {
guiThread = new std::thread(&Interpreter::Kernal, &interp);
//twoThreadsRunning = true;
}
}
else if (inputStr == "%stop" && guiThread != nullptr) {
if (guiThread->joinable()) {
guiThread->join();
guiThread = nullptr;
//twoThreadsRunning = false;
}
}
else if (inputStr == "%reset") {
if (guiThread != nullptr) {
guiThread->join();
guiThread = nullptr;
}
interp.clear();
interp = resetInterp;
guiThread = new std::thread(&Interpreter::Kernal, &interp);
}
else {
if (guiThread != nullptr) {
outputMessage.wait_and_pop(output);
if (output.isExpression == true) {
whichSignal(output.expMsg);
}
else {
qDebug() << QString::fromStdString(output.error);
error(output.error);
}
}
else {
if(inputStr != "%stop" && inputStr != "%reset")
error("Error: interpreter kernel not running");
}
}
}
void NotebookApp::start() {
QString input("%start");
handle_PlotScript(input);
}
void NotebookApp::stop() {
QString input("%stop");
handle_PlotScript(input);
}
void NotebookApp::reset() {
QString input("%reset");
handle_PlotScript(input);
}
void NotebookApp::interrupt() {
QString input("%interrupt");
handle_PlotScript(input);
}
void NotebookApp::connectSlots()
{
connect(inputWidget, SIGNAL(sendToPlotScript(QString)), this, SLOT(handle_PlotScript(QString)));
//data ready to output
connect(this, SIGNAL(dataReady(QString)), outputWidget, SLOT(showResult(QString)));
connect(this, SIGNAL(makePointReady(std::vector<double>)), outputWidget, SLOT(plotPoint(std::vector<double>)));
connect(this, SIGNAL(makeLineReady(std::vector<double>)), outputWidget, SLOT(plotLine(std::vector<double>)));
connect(this, SIGNAL(makeTextReady(QString, double, double,double,double)), outputWidget, SLOT(showText(QString, double, double,double,double)));
connect(this, SIGNAL(initializeScreen()), outputWidget, SLOT(clearScreen()));
connect(startButton, SIGNAL(released()), this, SLOT(start()));
connect(stopButton, SIGNAL(released()), this, SLOT(stop()));
connect(resetButton, SIGNAL(released()), this, SLOT(reset()));
connect(interruptButton, SIGNAL(released()), this, SLOT(interrupt()));
}
// plotscript functions
void NotebookApp::error(const std::string & err_str) {
QString output = QString::fromStdString(err_str);
emit dataReady(output);
}
void NotebookApp::eval_from_stream(std::istream & stream) {
if (!interp.parseStream(stream)) {
error("Error: invalid expression. Could not parse.");
}
else {
try {
Expression exp = interp.evaluate();
whichSignal(exp);
}
catch (const SemanticError & ex) {
error(ex.what());
}
}
}
void NotebookApp::eval_from_file(std::string filename) {
std::ifstream ifs(filename);
if (!ifs) {
error("Could not open file for reading.");
}
qDebug() << "input file successfully implemented";
eval_from_stream(ifs);
}
void NotebookApp::whichSignal(Expression exp)
{
std::vector<Expression> tempParameters; // for graphics
// if the input is make-point: takes 3 inputs (x,y,size) and emit those as signal
if (exp.get_property("object-name").second.head().asStringLiteral() == "point")
{
plotParameters.clear();
size = exp.get_property("size").second.head().asNumber();
for (auto e = exp.tailConstBegin(); e != exp.tailConstEnd(); ++e)
tempParameters.push_back(*e);
x = tempParameters[0].head().asNumber();
y = tempParameters[1].head().asNumber();
if (size < 0)
error("Error in make-point: size must be non-negative");
plotParameters.push_back(x);
plotParameters.push_back(y);
plotParameters.push_back(size);
for (int i = 0; i < 3; i++)
qDebug() << "final parameters: " << plotParameters[i];
emit(makePointReady(plotParameters));
}
// if the input is make-line: takes 5 inputs (x1,y1,x2,y2,thickness) and emit those as signal
else if (exp.get_property("object-name").second.head().asStringLiteral() == "line")
{
plotParameters.clear();
thickness = exp.get_property("thickness").second.head().asNumber();
if (thickness < 0)
error("Error: in make-line: thickness must be positive");
for (auto e = exp.tailConstBegin(); e != exp.tailConstEnd(); ++e)
{
Expression points = *e;
for (auto a = points.tailConstBegin(); a != points.tailConstEnd(); ++a)
tempParameters.push_back(*a);
}
qDebug() << "in line part of which signal function, size: " << tempParameters.size();
for (int i = 0; i < 4; i++)
plotParameters.push_back(tempParameters[i].head().asNumber());
plotParameters.push_back(thickness);
for (int i = 0; i < 5; i++)
qDebug() <<"final parameters: " << plotParameters[i];
emit(makeLineReady(plotParameters));
}
else if (exp.get_property("object-name").second.head().asStringLiteral() == "text")
{
QString text = QString::fromStdString(exp.head().asStringLiteral());
//obtain the position of the text
Expression position = exp.get_property("position").second;
if (position.get_property("object-name").second.head().asStringLiteral() != "point")
error("Error in make-text: object-name of position property not a point");
for (auto e = position.tailConstBegin(); e != position.tailConstEnd(); ++e)
tempParameters.push_back(*e);
x = tempParameters[0].head().asNumber();
y = tempParameters[1].head().asNumber();
Expression textScale = exp.get_property("text-scale").second;
if (textScale.head().asNumber() < 0)
scale = 1;
else
scale = textScale.head().asNumber();
Expression textRotation = exp.get_property("text-rotation").second;
if (!textRotation.isHeadNumber())
phi = 0;
else
phi = textRotation.head().asNumber();
QString test("this is a test");
emit(makeTextReady(text, x, y,scale,phi));
}
//recursion for evaluating list of properties
else if (exp.head().asSymbol() == "list")
{
for (auto e = exp.tailConstBegin(); e != exp.tailConstEnd(); ++e)
whichSignal(*e);
}
else // regular expression
{
if (exp.head().asSymbol() != "lambda")
{
std::stringstream stream;
stream << exp;
std::string output = stream.str();
emit(dataReady(QString::fromStdString(output)));
}
}
}