1 #include "yacasengine.h"
2
3 #include <string>
4
5 #include <QtCore/QFile>
6 #include <QtCore/QMutexLocker>
7 #include <QtCore/QSet>
8
YacasEngine(const QString & scripts_path,YacasRequestQueue & requests,QObject * parent)9 YacasEngine::YacasEngine(const QString& scripts_path,
10 YacasRequestQueue& requests,
11 QObject* parent) :
12 QObject(parent),
13 _requests(requests),
14 _yacas(new CYacas(_side_effects)),
15 _idx(1)
16 {
17 if (!QFile(scripts_path + "yacasinit.ys").exists())
18 throw std::runtime_error(QString("Invalid yacas scripts path: %1")
19 .arg(scripts_path)
20 .toStdString());
21
22 _yacas->Evaluate(std::string("DefaultDirectory(\"") +
23 scripts_path.toStdString() + std::string("\");"));
24 _yacas->Evaluate("Load(\"yacasinit.ys\");");
25
26 _yacas->Evaluate("Plot2D'outputs();");
27 _yacas->Evaluate("UnProtect(Plot2D'outputs);");
28 _yacas->Evaluate("Plot2D'yagy(values_IsList, _options'hash) <-- "
29 "Yagy'Plot2D'Data(values, options'hash);");
30 _yacas->Evaluate(
31 "Plot2D'outputs() := { {\"default\", \"yagy\"}, {\"data\", "
32 "\"Plot2D'data\"}, {\"gnuplot\", \"Plot2D'gnuplot\"}, {\"java\", "
33 "\"Plot2D'java\"}, {\"yagy\", \"Plot2D'yagy\"}, };");
34 _yacas->Evaluate("Protect(Plot2D'outputs);");
35 _yacas->Evaluate("Plot3DS'outputs();");
36 _yacas->Evaluate("UnProtect(Plot3DS'outputs);");
37 _yacas->Evaluate("Plot3DS'yagy(values_IsList, _options'hash) <-- "
38 "Yagy'Plot3DS'Data(values, options'hash);");
39 _yacas->Evaluate("Plot3DS'outputs() := { {\"default\", \"yagy\"}, "
40 "{\"data\", \"Plot3DS'data\"}, {\"gnuplot\", "
41 "\"Plot3DS'gnuplot\"}, {\"yagy\", \"Plot3DS'yagy\"},};");
42 _yacas->Evaluate("Protect(Plot3DS'outputs);");
43
44 _update_symbols();
45 }
46
~YacasEngine()47 YacasEngine::~YacasEngine()
48 {
49 delete _yacas;
50 }
51
cancel()52 void YacasEngine::cancel()
53 {
54 _yacas->getDefEnv().getEnv().stop_evaluation = true;
55 }
56
symbols() const57 QStringList YacasEngine::symbols() const
58 {
59 QMutexLocker lock(&_symbols_mtx);
60 return _symbols;
61 }
62
on_start_processing()63 void YacasEngine::on_start_processing()
64 {
65 for (;;) {
66
67 QMutexLocker lock(&_requests.mtx);
68
69 if (_requests.shutdown)
70 return;
71
72 busy(false);
73
74 _requests.cnd.wait(&_requests.mtx);
75
76 if (_requests.shutdown)
77 return;
78
79 _yacas->getDefEnv().getEnv().stop_evaluation = false;
80
81 busy(true);
82
83 while (!_requests.waiting.empty()) {
84 YacasRequest* request = _requests.waiting.dequeue();
85
86 // Beware of low flying butterflies
87 _requests.mtx.unlock();
88
89 const QString expr = request->take();
90
91 _side_effects.clear();
92 _side_effects.str("");
93 _yacas->Evaluate((expr + ";").toStdString());
94
95 _update_symbols();
96
97 if (!_yacas->IsError()) {
98 QString result = QString::fromStdString(_yacas->Result());
99 result = result.left(result.length() - 1).trimmed();
100
101 YacasRequest::ResultType result_type = YacasRequest::EXPRESSION;
102 if (result.startsWith("Yagy'Plot2D'Data")) {
103 result_type = YacasRequest::PLOT2D;
104 result = result.remove("Yagy'Plot2D'Data(");
105 result.truncate(result.length() - 1);
106 } else if (result.startsWith("Yagy'Plot3DS'Data")) {
107 result_type = YacasRequest::PLOT3D;
108 result = result.remove("Yagy'Plot3DS'Data(");
109 result.truncate(result.length() - 1);
110 } else if (result.startsWith("Graph(")) {
111 result_type = YacasRequest::GRAPH;
112 result = result.remove("Graph(");
113 result.truncate(result.length() - 1);
114 }
115 request->answer(_idx++,
116 result_type,
117 result,
118 QString::fromStdString(_side_effects.str()));
119 } else {
120 QString msg = QString::fromStdString(_yacas->Error());
121 request->answer(_idx++,
122 YacasRequest::ERROR,
123 msg.trimmed(),
124 QString::fromStdString(_side_effects.str()));
125 }
126
127 _requests.mtx.lock();
128 }
129 }
130 }
131
_update_symbols()132 void YacasEngine::_update_symbols()
133 {
134 QMutexLocker lock(&_symbols_mtx);
135
136 QSet<QString> ss;
137
138 for (auto op : _yacas->getDefEnv().getEnv().PreFix())
139 ss.insert(QString::fromStdString(*op.first));
140
141 for (auto op : _yacas->getDefEnv().getEnv().InFix())
142 ss.insert(QString::fromStdString(*op.first));
143
144 for (auto op : _yacas->getDefEnv().getEnv().PostFix())
145 ss.insert(QString::fromStdString(*op.first));
146
147 for (auto op : _yacas->getDefEnv().getEnv().Bodied())
148 ss.insert(QString::fromStdString(*op.first));
149
150 for (auto op : _yacas->getDefEnv().getEnv().CoreCommands())
151 ss.insert(QString::fromStdString(*op.first));
152
153 for (auto& op : _yacas->getDefEnv().getEnv().UserFunctions())
154 ss.insert(QString::fromStdString(*op.first));
155
156 _symbols = QStringList::fromSet(ss);
157 }
158