NumeRe v1.1.4
NumeRe: Framework für Numerische Rechnungen
procedureelement.cpp
Go to the documentation of this file.
1/*****************************************************************************
2 NumeRe: Framework fuer Numerische Rechnungen
3 Copyright (C) 2017 Erik Haenel et al.
4
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17******************************************************************************/
18
19#include "procedureelement.hpp"
20#include "../utils/tools.hpp"
21#include "../symdef.hpp"
22#include "dependency.hpp"
23#include "includer.hpp"
24
25#include <memory>
26
27
36ProcedureElement::ProcedureElement(const StyledTextFile& procedureContents, const std::string& sFilePath) : sFileName(sFilePath), m_dependencies(nullptr)
37{
38 std::string sFolderPath = sFileName.substr(0, sFileName.rfind('/'));
39 std::string sProcCommandLine;
40 std::string sCurrentCommand;
41 std::string sCurrentLineCache;
42 std::string sProcPlotCompose;
43
44 SymDefManager _symdefs;
45 std::unique_ptr<Includer> _includer;
46 int i = 0;
47 int currentLine = 0;
48 int includeOffset = 0;
49
50 // Examine the contents of each line
51 while (i < procedureContents.getLinesCount())
52 {
53 if (_includer && _includer->is_open())
54 {
55 includeOffset++;
56 currentLine = -includeOffset;
57 sProcCommandLine = _includer->getNextLine();
58 }
59 else
60 {
61 if (_includer)
62 _includer.reset();
63
64 // get the current line
65 sProcCommandLine = procedureContents.getStrippedLine(i);
66 currentLine = i;
67 i++;
68 }
69
70 StripSpaces(sProcCommandLine);
71
72 // skip easy cases
73 if (!sProcCommandLine.length())
74 continue;
75
76 if (Includer::is_including_syntax(sProcCommandLine))
77 {
78 _includer.reset(new Includer(sProcCommandLine, sFolderPath));
79 continue;
80 }
81
82 // If the length is longer than 2, then it's possible
83 // that we have a line continuation at this point
84 if (sProcCommandLine.length() > 2)
85 {
86 if (sProcCommandLine.substr(sProcCommandLine.length() - 2, 2) == "\\\\")
87 {
88 // Add the current line to the current line cache
89 // and continue
90 sCurrentLineCache += sProcCommandLine.substr(0, sProcCommandLine.length() - 2);
91 continue;
92 }
93 }
94
95 // If the current line cache is not empty then simply
96 // append the current line and use the whole line as input
97 if (sCurrentLineCache.length())
98 {
99 sProcCommandLine = sCurrentLineCache + sProcCommandLine;
100 sCurrentLineCache.clear();
101 }
102
103 // get the current command, if any
104 sCurrentCommand = findCommand(sProcCommandLine).sString;
105
106 // Resolve symbol macros
107 if (sCurrentCommand == SYMDEF_COMMAND)
108 {
109 _symdefs.createSymbol(sProcCommandLine.substr(sCurrentCommand.length()));
110 continue;
111 }
112 else
113 {
114 _symdefs.resolveSymbols(sProcCommandLine);
115 sCurrentCommand = findCommand(sProcCommandLine).sString;
116 }
117
118 // clean the current line
119 cleanCurrentLine(sProcCommandLine, sCurrentCommand, sFolderPath);
120
121 // Handle composition blocks in advance
122 if ((sCurrentCommand == "compose"
123 || sCurrentCommand == "endcompose"
124 || sProcPlotCompose.length())
125 && sCurrentCommand != "quit")
126 {
127 if (!sProcPlotCompose.length() && sCurrentCommand == "compose")
128 {
129 // Start of the plot composition block
130 sProcPlotCompose = "plotcompose ";
131
132 if (findParameter(sProcCommandLine, "multiplot", '='))
133 {
134 sProcPlotCompose += "-multiplot=" + getArgAtPos(sProcCommandLine, findParameter(sProcCommandLine, "multiplot", '=') + 9) + " <<COMPOSE>> ";
135 }
136
137 continue;
138 }
139 else if (sCurrentCommand == "abort")
140 {
141 // Manual abort
142 sProcPlotCompose.clear();
143 continue;
144 }
145 else if (sCurrentCommand != "endcompose")
146 {
147 // An arbitrary command
148 std::string sCommand = findCommand(sProcCommandLine).sString;
149
150 if (sCommand.substr(0, 4) == "plot"
151 || sCommand.substr(0, 7) == "subplot"
152 || sCommand.substr(0, 5) == "graph"
153 || sCommand.substr(0, 4) == "grad"
154 || sCommand.substr(0, 4) == "draw"
155 || sCommand.substr(0, 4) == "dens"
156 || sCommand.substr(0, 4) == "vect"
157 || sCommand.substr(0, 4) == "cont"
158 || sCommand.substr(0, 4) == "surf"
159 || sCommand.substr(0, 4) == "mesh")
160 sProcPlotCompose += sProcCommandLine + " <<COMPOSE>> ";
161 {
162 continue;
163 }
164 }
165 else
166 {
167 // The actual end of the compose block
168 sProcCommandLine = sProcPlotCompose;
169 sProcPlotCompose.clear();
170 }
171 }
172
173 // Avoid "install" and "script" calls
174 if (sCurrentCommand == "install"
175 || sCurrentCommand == "script")
177 "@ " + toString(abs(currentLine)+1) + ": " + sProcCommandLine, sCurrentCommand);
178
179 // Ensure that the parentheses are valid
180 if (sProcCommandLine.find('(') != std::string::npos || sProcCommandLine.find('{') != std::string::npos)
181 {
182 if (!validateParenthesisNumber(sProcCommandLine))
183 {
184 sProcCommandLine.insert(0, "@ " + toString(abs(currentLine)+1) + ": ");
185
186 for (size_t j = 0; j < sProcCommandLine.length(); j++)
187 {
188 if ((sProcCommandLine[j] == '(' || sProcCommandLine[j] == '{' || sProcCommandLine[j] == '[')
189 && getMatchingParenthesis(sProcCommandLine.substr(j)) == std::string::npos)
190 throw SyntaxError(SyntaxError::UNMATCHED_PARENTHESIS, sProcCommandLine, j);
191 }
192
193 throw SyntaxError(SyntaxError::UNMATCHED_PARENTHESIS, sProcCommandLine, sProcCommandLine.find_last_of(")}]"));
194 }
195 }
196
197 // Determine the type of the actual type of the procedure command line
198 if (sCurrentCommand == "procedure")
199 {
201 std::string sArgumentList;
202
203 // Extract the flags
204 if (sProcCommandLine.rfind("::") != std::string::npos)
205 {
206 std::string sFlags = sProcCommandLine.substr(sProcCommandLine.rfind("::"));
207
208 if (sFlags.find("private") != std::string::npos)
210
211 if (sFlags.find("explicit") != std::string::npos)
213
214 if (sFlags.find("inline") != std::string::npos)
216
217 if (sFlags.find("mask") != std::string::npos || sFlags.find("silent") != std::string::npos)
219
220 if (sFlags.find("event") != std::string::npos)
222
223 if (sFlags.find("template") != std::string::npos)
225
226 if (sFlags.find("macro") != std::string::npos)
228
229 if (sFlags.find("test") != std::string::npos)
231 }
232
233 // Extract procedure name and argument list
234 if (sProcCommandLine.find('$') != std::string::npos
235 && sProcCommandLine.find('(', sProcCommandLine.find('$')) != std::string::npos)
236 {
237 std::string sProcName = sProcCommandLine.substr(sProcCommandLine.find('$'));
238 sProcName.erase(sProcName.find('('));
239
240 if (getMatchingParenthesis(sProcCommandLine.substr(sProcCommandLine.find('('))) == std::string::npos)
241 throw SyntaxError(SyntaxError::UNMATCHED_PARENTHESIS, sProcCommandLine, sProcCommandLine.find('('));
242
243 // Ensure that the argument list is defined reasonable
244 if (findCommand(sArgumentList, "var").sString == "var")
246 "@" + toString(abs(currentLine)+1) + ": " + sProcCommandLine, "var", "var");
247
248 if (findCommand(sArgumentList, "str").sString == "str")
250 "@" + toString(abs(currentLine)+1) + ": " + sProcCommandLine, "str", "str");
251
252 if (findCommand(sArgumentList, "tab").sString == "tab")
254 "@" + toString(abs(currentLine)+1) + ": " + sProcCommandLine, "tab", "tab");
255
256 if (findCommand(sArgumentList, "cst").sString == "cst")
258 "@" + toString(abs(currentLine)+1) + ": " + sProcCommandLine, "cst", "cst");
259
260 sArgumentList = sProcCommandLine.substr(sProcCommandLine.find('(')+1);
261 sArgumentList = " " + sArgumentList.erase(sArgumentList.rfind(')')) + " ";
262
263 // Store the procedure name and the corresponding line in the
264 // procedure list map
265 mProcedureList[sProcName] = currentLine;
266 }
267
268 mProcedureContents.push_back(std::make_pair(currentLine, ProcedureCommandLine(nFlags,
270 sProcCommandLine,
271 sArgumentList)));
272 }
273 else if (sCurrentCommand == "endprocedure")
274 mProcedureContents.push_back(std::make_pair(currentLine, ProcedureCommandLine(ProcedureCommandLine::FLAG_NONE,
276 sProcCommandLine)));
277 else
278 mProcedureContents.push_back(std::make_pair(currentLine, ProcedureCommandLine(ProcedureCommandLine::FLAG_NONE,
280 sProcCommandLine)));
281 }
282}
283
284
290{
291 if (m_dependencies)
292 delete m_dependencies;
293}
294
295
309void ProcedureElement::cleanCurrentLine(std::string& sProcCommandLine, const std::string& sCurrentCommand, const std::string& sFolderPath)
310{
311 // Replace the "this" path place holder
312 while (sProcCommandLine.find("<this>") != std::string::npos)
313 sProcCommandLine.replace(sProcCommandLine.find("<this>"), 6, sFolderPath);
314
315 // Remove the "global" command, if it is available
316 if (sCurrentCommand == "global")
317 {
318 sProcCommandLine = sProcCommandLine.substr(findCommand(sProcCommandLine).nPos + 6);
319 StripSpaces(sProcCommandLine);
320 }
321
322 // replace tabulator characters with whitespaces
323 for (size_t i = 0; i < sProcCommandLine.length(); i++)
324 {
325 if (sProcCommandLine[i] == '\t')
326 sProcCommandLine[i] = ' ';
327 }
328
329 // remove definition operator, where needed
330 if (sCurrentCommand != "define"
331 && sCurrentCommand != "ifndefined"
332 && sCurrentCommand != "redefine"
333 && sCurrentCommand != "ifndef"
334 && sCurrentCommand != "redef"
335 && sCurrentCommand != "lclfunc")
336 {
337 while (sProcCommandLine.find(":=") != std::string::npos)
338 sProcCommandLine.erase(sProcCommandLine.find(":="), 1);
339 }
340
341 // remove whitespaces
342 StripSpaces(sProcCommandLine);
343}
344
345
353std::pair<int, ProcedureCommandLine> ProcedureElement::getFirstLine()
354{
355 return mProcedureContents.front();
356}
357
358
369std::pair<int, ProcedureCommandLine> ProcedureElement::getCurrentLine(int nCurrentLine)
370{
371 std::pair<int, ProcedureCommandLine> currentLine;
372
373 for (int i = mProcedureContents.size()-1; i >= 0; i--)
374 {
375 if (mProcedureContents[i].first == nCurrentLine)
376 return mProcedureContents[i];
377
378 //if (abs(mProcedureContents[i].first) < nCurrentLine)
379 // break;
380 }
381
382 return currentLine;
383}
384
385
397std::pair<int, ProcedureCommandLine> ProcedureElement::getNextLine(int nCurrentLine)
398{
399 std::pair<int, ProcedureCommandLine> currentLine;
400
401 for (int i = mProcedureContents.size()-1; i >= 0; i--)
402 {
403 if (mProcedureContents[i].first == nCurrentLine && (size_t)i+1 < mProcedureContents.size())
404 return mProcedureContents[i+1];
405
406 //if (abs(mProcedureContents[i].first) < nCurrentLine)
407 // break;
408 }
409
410 return currentLine;
411}
412
413
423bool ProcedureElement::isLastLine(int nCurrentLine)
424{
425 if (mProcedureContents.back().first <= nCurrentLine)
426 return true;
427
428 return false;
429}
430
431
446int ProcedureElement::gotoProcedure(const std::string& sProcedureName)
447{
448 auto iter = mProcedureList.find(sProcedureName);
449
450 if (iter != mProcedureList.end())
451 return iter->second;
452
453 return -1;
454}
455
456
472void ProcedureElement::setByteCode(int _nByteCode, int nCurrentLine)
473{
474 for (int i = mProcedureContents.size()-1; i >= 0; i--)
475 {
476 if (mProcedureContents[i].first == nCurrentLine)
477 mProcedureContents[i].second.setByteCode(_nByteCode);
478
479 //if (abs(mProcedureContents[i].first) < nCurrentLine)
480 // break;
481 }
482}
483
484
496{
497 if (!m_dependencies)
498 m_dependencies = new Dependencies(this);
499
500 return m_dependencies;
501}
502
This class handles the dependencies of the current procedure file (passed as pointer to a ProcedureEl...
Definition: dependency.hpp:81
This class represents a file, which can be included into other files using the @ syntax.
Definition: includer.hpp:32
static bool is_including_syntax(const std::string &sLine)
Static member function which determines, whether the passed line is actually a including syntax.
Definition: includer.cpp:318
Dependencies * m_dependencies
ProcedureElement(const StyledTextFile &procedureContents, const std::string &sFolderPath)
Procedure element constructor. This class is always heap allocated.
~ProcedureElement()
Destructor. Cleares the dependency list.
std::pair< int, ProcedureCommandLine > getCurrentLine(int currentLine)
This function returns the selected line of the stored file. This member function will be used in comb...
std::map< std::string, int > mProcedureList
void cleanCurrentLine(std::string &sProcCommandLine, const std::string &sCurrentCommand, const std::string &sFilePath)
This member function does the hard work on cleaning the current procedure command line....
bool isLastLine(int currentline)
This member function determines, whether the current line is the last line of the stored procedure fi...
void setByteCode(int _nByteCode, int nCurrentLine)
This member function can be used to store the created byte code in the current procedure command line...
Dependencies * getDependencies()
This member function returns the first-level dependencies of the current procedure file....
int gotoProcedure(const std::string &sProcedureName)
This member function returns the line of the stored file, where the desired procedure may be found or...
std::pair< int, ProcedureCommandLine > getFirstLine()
This function returns the first line of the stored file.
std::pair< int, ProcedureCommandLine > getNextLine(int currentline)
This member function returns the line after the current selected line. This is probably not the same ...
std::vector< std::pair< int, ProcedureCommandLine > > mProcedureContents
This class represents a text file in memory (e.g. a code file). This class will try to lex the loaded...
std::string getStrippedLine(size_t line) const
Returns the selected line (without the line termination characters and without any comments).
int getLinesCount() const
Returns the number of lines in the current loaded file.
This class handles the file-static constants, which are more or less macros similar to #define in C/C...
Definition: symdef.hpp:32
void resolveSymbols(std::string &sCommandLine) const
Resolve all file-static constant declarations in the current line.
Definition: symdef.cpp:47
void createSymbol(const std::string &sCommandLine)
Create one or more new file-static constant declarations for the current file.
Definition: symdef.cpp:72
Common exception class for all exceptions thrown in NumeRe.
Definition: error.hpp:32
@ UNMATCHED_PARENTHESIS
Definition: error.hpp:224
@ WRONG_ARG_NAME
Definition: error.hpp:226
@ INSTALL_CMD_FOUND
Definition: error.hpp:121
unsigned int getMatchingParenthesis(const StringView &)
Returns the position of the closing parenthesis.
Definition: tools.cpp:414
CONSTCD11 std::chrono::duration< Rep, Period > abs(std::chrono::duration< Rep, Period > d)
Definition: date.h:1317
void StripSpaces(std::string &)
Removes leading and trailing white spaces and tabulator characters.
int findParameter(const std::string &sCmd, const std::string &sParam, const char cFollowing)
This function searches the passed parameter in the passed command string. If something is found,...
Definition: tools.cpp:113
std::string sString
std::string toString(int)
Converts an integer to a string without the Settings bloat.
#define SYMDEF_COMMAND
Definition: symdef.hpp:21
Match findCommand(StringView sCmd, const std::string &sCommand)
This function is very important for the command handler.
Definition: tools.cpp:1275
string getArgAtPos(const string &sCmd, unsigned int nPos, int extraction)
Extracts a options value at the selected position and applies automatic parsing, if necessary.
Definition: tools.cpp:1598
bool validateParenthesisNumber(const string &sCmd)
This function is used to validate the number of parentheses, i.e. whether there's a closing parenthes...
Definition: tools.cpp:3512