1 /*
2 Copyright (C) 2008, 2009 Andres Cabrera
3 mantaraya36@gmail.com
4
5 This file is part of CsoundQt.
6
7 CsoundQt is free software; you can redistribute it
8 and/or modify it under the terms of the GNU Lesser General Public
9 License as published by the Free Software Foundation; either
10 version 2.1 of the License, or (at your option) any later version.
11
12 CsoundQt is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU Lesser General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public
18 License along with Csound; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
20 02111-1307 USA
21 */
22
23 #include "opentryparser.h"
24 #include "types.h"
25
26 #include <QFile>
27
28
OpEntryParser(QString opcodeFile)29 OpEntryParser::OpEntryParser(QString opcodeFile)
30 : m_opcodeFile(opcodeFile)
31 {
32 m_udosMap = nullptr;
33 QDomDocument m_doc("opcodes");
34 QFile file(m_opcodeFile);
35 if (!file.open(QIODevice::ReadOnly)) {
36 qDebug() << "OpEntryParser::OpEntryParser could not find opcode file:" << opcodeFile;
37 return;
38 }
39 if (!m_doc.setContent(&file)) {
40 qDebug() << "OpEntryParser::OpEntryParser set content";
41 file.close();
42 return;
43 }
44 file.close();
45 excludedOpcodes << "|" << "||" << "^" << "+" << "*" << "-" << "/";
46 // << "instr" << "endin" << "opcode" << "endop"
47 // << "sr" << "kr" << "ksmps" << "nchnls" << "0dbfs";
48 QDomElement docElem = m_doc.documentElement();
49 QList<Opcode> opcodesInCategoryList;
50
51 QDomElement cat = docElem.firstChildElement("category");
52 while(!cat.isNull()) {
53 QString catName = cat.attribute("name", "Miscellaneous");
54 opcodesInCategoryList.clear();
55 QDomElement opcode = cat.firstChildElement("opcode");
56 while(!opcode.isNull()) {
57 QDomElement desc = opcode.firstChildElement("desc");
58 QString description = desc.text();
59 QDomElement synop = opcode.firstChildElement("synopsis");
60 while(!synop.isNull()) {
61 Opcode op;
62 op.desc = description;
63 QDomElement s = synop.toElement();
64 QDomNode node = s.firstChild();
65 QDomElement elem = node.toElement();
66 if (elem.tagName()=="opcodename") {
67 op.opcodeName = elem.text().simplified();
68 op.inArgs = node.nextSibling().toText().data();
69 }
70 else {
71 op.outArgs = node.toText().data().simplified();
72 node = node.nextSibling();
73 op.opcodeName = node.toElement().text().simplified();
74 node = node.nextSibling();
75 if (!node.isNull())
76 op.inArgs = node.toText().data().simplified();
77 }
78 if (op.opcodeName != "" && excludedOpcodes.count(op.opcodeName) == 0
79 && catName !="Utilities") {
80 addOpcode(op);
81 opcodesInCategoryList << op;
82 }
83 synop = synop.nextSiblingElement("synopsis");
84 }
85 opcode = opcode.nextSiblingElement("opcode");
86 }
87 QPair<QString, QList<Opcode> > newCategory(catName, opcodesInCategoryList);
88 opcodeListCategory.append(opcodesInCategoryList);
89 categoryList.append(catName);
90 // qDebug() << "Category: " << categoryList.last();
91 opcodeCategoryList.append(newCategory);
92 cat = cat.nextSiblingElement("category");
93 }
94 addExtraOpcodes();
95 }
96
~OpEntryParser()97 OpEntryParser::~OpEntryParser()
98 {
99 }
100
addExtraOpcodes()101 void OpEntryParser::addExtraOpcodes()
102 {
103 Opcode opcode;
104 opcode.outArgs = "";
105 opcode.opcodeName = "then";
106 opcode.inArgs ="";
107 addOpcode(opcode);
108
109 addFlag("use-system-sr", "Use the samplerate defined by the realtime audio backend");
110 addFlag("omacro", "--omacro:XXX=YYY set orchestra macro XXX to value YYY");
111 addFlag("port", "--port=N. listen to UDP port N for instruments/orchestra code");
112
113 }
114
opcodeNameList()115 QStringList OpEntryParser::opcodeNameList()
116 {
117 QStringList list;
118 // qDebug("OpEntryParser::opcodeNameList() opcodeList.size() = %i",opcodeList.size());
119 for (int i = 0; i<opcodeList.size();i++) {
120 list.append(opcodeList[i].opcodeName);
121 }
122 return list;
123 }
124
addOpcode(Opcode opcode)125 void OpEntryParser::addOpcode(Opcode opcode)
126 {
127 int i = 0;
128 int size = opcodeList.size();
129 while (i<size && opcodeList[i].opcodeName < opcode.opcodeName)
130 i++;
131 opcodeList.insert(i, opcode);
132 }
133
addFlag(QString flag,QString desc)134 void OpEntryParser::addFlag(QString flag, QString desc) {
135 Opcode opcode;
136 opcode.desc = desc;
137 opcode.opcodeName = flag;
138 opcode.inArgs = "";
139 opcode.outArgs = "";
140 opcode.isFlag = 1;
141 opcodeList.append(opcode);
142 }
143
findOpcode(QString opcodeName)144 Opcode OpEntryParser::findOpcode(QString opcodeName) {
145 for (int i = 0; i < opcodeList.size(); i++) {
146 if (opcodeList[i].opcodeName == opcodeName) {
147 return opcodeList[i];
148 }
149 }
150 if(m_udosMap->contains(opcodeName)) {
151 return m_udosMap->value(opcodeName);
152 }
153 qDebug() << "OpEntryParser::findOpcode: opcode " << opcodeName << "not found";
154 return Opcode();
155 }
156
opcodeSyntax(Opcode opc)157 QString opcodeSyntax(Opcode opc) {
158 QString syntax = opc.outArgs.simplified();
159 if (!opc.outArgs.isEmpty())
160 syntax += " ";
161 syntax += opc.opcodeName.simplified();
162 if (!opc.inArgs.isEmpty()) {
163 syntax += " " + opc.inArgs.simplified();
164 }
165 if(!opc.desc.isEmpty()) {
166 syntax += "<br />[ " + opc.desc + " ]";
167 }
168 return syntax;
169 }
170
getSyntax(QString opcodeName)171 QString OpEntryParser::getSyntax(QString opcodeName)
172 {
173 if (opcodeName.size() < 2) {
174 return "";
175 }
176 Opcode opc = findOpcode(opcodeName);
177 if(!opc.opcodeName.isEmpty()) {
178 QString syntax = opcodeSyntax(opc);
179 return syntax;
180 }
181 return "";
182 }
183
getPossibleSyntax(QString word)184 QVector<Opcode> OpEntryParser::getPossibleSyntax(QString word)
185 {
186 QVector<Opcode> out;
187 for (int i = 0; i < opcodeList.size(); i++) {
188 if (opcodeList[i].opcodeName.startsWith(word)) {
189 out << opcodeList[i];
190 }
191 }
192 auto it = m_udosMap->constBegin();
193 while(it != m_udosMap->constEnd()) {
194 if(it->opcodeName.startsWith(word))
195 out << it.value();
196 it++;
197 }
198 return out;
199 }
200
getOpcodesByCategory()201 QList< QPair<QString, QList<Opcode> > > OpEntryParser::getOpcodesByCategory()
202 {
203 return opcodeCategoryList;
204 }
205
getCategoryCount()206 int OpEntryParser::getCategoryCount()
207 {
208 // qDebug("OpEntryParser::getCategoryCount()");
209 return categoryList.size();
210 }
211
getCategory(int index)212 QString OpEntryParser::getCategory(int index)
213 {
214 if (index < categoryList.size())
215 return categoryList[index];
216 else return QString();
217 }
218
getCategoryList()219 QStringList OpEntryParser::getCategoryList()
220 {
221 return QStringList(categoryList);
222 }
223
getOpcodeList(int index)224 QList<Opcode> OpEntryParser::getOpcodeList(int index)
225 {
226 return opcodeListCategory[index];
227 }
228
isOpcode(QString opcodeName)229 bool OpEntryParser::isOpcode(QString opcodeName)
230 {
231 for (int i = 0; i< opcodeList.size();i++) {
232 if (opcodeName == opcodeList[i].opcodeName) {
233 return true;
234 }
235 }
236 if(this->m_udosMap->contains(opcodeName))
237 return true;
238 return false;
239 }
240
241
getOpcodeArgNames(Node & node)242 bool OpEntryParser::getOpcodeArgNames(Node &node)
243 {
244 QString opcodeName = node.getName();
245 QVector<Port> inputs = node.getInputs();
246 QVector<Port> outputs = node.getOutputs();
247 int idx = -1;
248 for (int i = 0; i< opcodeList.size();i++) {
249 if (opcodeName == opcodeList[i].opcodeName) {
250 idx = i;
251 break;
252 }
253 }
254 Opcode opcode;
255 if(idx >= 0) {
256 opcode = opcodeList[idx];
257 } else {
258 if(m_udosMap->contains(opcodeName))
259 opcode = m_udosMap->value(opcodeName);
260 else
261 return false;
262 }
263 QString inArgs = opcode.inArgs;
264 // QString inArgs = opcodeList[idx].inArgs;
265 QString inArgsOpt = "";
266 if (inArgs.contains("["))
267 inArgsOpt = inArgs.mid(inArgs.indexOf("["));
268 inArgs.remove(inArgsOpt);
269 QStringList args = inArgs.split(QRegExp("[,\\\"]+"), QString::SkipEmptyParts);
270 for (int count = 0; count < args.size(); count ++) {
271 args[count] = args[count].trimmed();
272 if (args[count] == "")
273 args.removeAt(count);
274 }
275 QStringList argsOpt = inArgsOpt.split(QRegExp("[,\\\\\\s\\[\\]]+"), QString::SkipEmptyParts);
276 for (int j = 0; j < inputs.size(); j++) {
277 if (j < args.size()) {
278 inputs[j].argName = args[j];
279 inputs[j].optional = false;
280 }
281 else { //optional parameter
282 int index = j - args.size();
283 if (index < inArgsOpt.size()) {
284 if (index < argsOpt.size()) {
285 // in case the opcode contains an undefined number of optional arguments
286 inputs[j].argName = argsOpt[index];
287 }
288 else {
289 inputs[j].argName = "";
290 }
291 inputs[j].optional = true;
292 // qDebug() << "OpEntryParser::getOpcodeArgNames " << inputs[j].argName ;
293 }
294 else {
295 qDebug("OpEntryParser::getOpcodeArgNames: Error too many inargs");
296 }
297 }
298 }
299 // QString outArgs = opcodeList[i].outArgs;
300 QString outArgs = opcode.outArgs;
301 QString outArgsOpt = "";
302 if (outArgs.contains("["))
303 outArgsOpt = outArgs.mid(outArgs.indexOf("["));
304 outArgs.remove(outArgsOpt);
305 args = outArgs.split(QRegExp("[,\\s]+"), QString::SkipEmptyParts);
306 argsOpt = outArgsOpt.split(QRegExp("[,\\\\\\s\\[\\]]"), QString::SkipEmptyParts);
307 for (int j = 0; j < outputs.size(); j++) {
308 if (j < args.size()) {
309 outputs[j].argName = args[j];
310 outputs[j].optional = false;
311 }
312 else { //optional parameter
313 int index = j - args.size();
314 if (index < inArgsOpt.size()) {
315 if (index < argsOpt.size()) {
316 // in case the opcode contains an undefined number of optional arguments
317 outputs[j].argName = argsOpt[index];
318 }
319 else {
320 outputs[j].argName = "";
321 }
322 outputs[j].optional = true;
323 }
324 else {
325 qDebug("OpEntryParser::getOpcodeArgNames: Error too many outargs");
326 }
327 }
328 }
329 node.setInputs(inputs);
330 node.setOutputs(outputs);
331 return true;
332 }
333