NumeRe v1.1.4
NumeRe: Framework für Numerische Rechnungen
dependency.cpp
Go to the documentation of this file.
1/*****************************************************************************
2 NumeRe: Framework fuer Numerische Rechnungen
3 Copyright (C) 2019 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
20#include "dependency.hpp"
21#include "procedureelement.hpp"
22#include "../../kernel.hpp"
23
24// CLASS DEPENDENCYLIST FUNCTIONS
25//
26
27
37static bool compare(const Dependency& first, const Dependency& second)
38{
39 return first.getProcedureName() < second.getProcedureName();
40}
41
42
52static bool isequal(const Dependency& first, const Dependency& second)
53{
54 return first.getProcedureName() == second.getProcedureName();
55}
56
57
66{
67 sort(compare);
68 list::unique(isequal);
69}
70
71
72// CLASS DEPENDENCIES FUNCTIONS
73//
74
75
83{
84 // Get a unix-like path name and extract the thisfile
85 // namespace
86 sFileName = replacePathSeparator(procedureFile->getFileName());
87 sThisNameSpace = sFileName.substr(0, sFileName.rfind('/')+1);
88 sThisFileNameSpacePrefix = sFileName.substr(sFileName.rfind('/')+1);
91
92 // Get the current default procedure path
93 std::string sProcDefPath = NumeReKernel::getInstance()->getSettings().getProcPath();
94
95 // If the default procedure path is part of the
96 // thisfile namespace, remove this part and translate
97 // it into an actual namespace
98 if (sThisNameSpace.substr(0, sProcDefPath.length()) == sProcDefPath)
99 {
100 sThisNameSpace.erase(0, sProcDefPath.length());
101
102 while (sThisNameSpace.front() == '/')
103 sThisNameSpace.erase(0, 1);
104
105 if (sThisNameSpace.length())
106 {
107 replaceAll(sThisNameSpace, "/", "~");
108
109 while (sThisNameSpace.back() == '~')
110 sThisNameSpace.pop_back();
111 }
112 else
113 sThisNameSpace = "main";
114 }
115 else if (sThisNameSpace.length())
116 {
117 while (sThisNameSpace.back() == '/')
118 sThisNameSpace.pop_back();
119 }
120
121 // Call Dependcies::walk() to calculate the dependencies
122 walk(procedureFile);
123}
124
125
137{
138 int line = procedureFile->getFirstLine().first;
139
140 // Walk through the whole file
141 while (!procedureFile->isLastLine(line))
142 {
143 // Get the dependencies of the current procedure
144 line = getProcedureDependencies(procedureFile, line);
145 }
146
147 // Make the list of dependencies unique
148 for (auto iter = mDependencies.begin(); iter != mDependencies.end(); ++iter)
149 iter->second.unique();
150}
151
152
162int Dependencies::getProcedureDependencies(ProcedureElement* procedureFile, int nCurrentLine)
163{
164 std::pair<int, ProcedureCommandLine> commandline = procedureFile->getCurrentLine(nCurrentLine);
165 std::string sProcedureName;
166 std::string sCurrentNameSpace = "main~";
167
168 // Search for the head of the current procedure
169 while (commandline.second.getType() != ProcedureCommandLine::TYPE_PROCEDURE_HEAD)
170 {
171 commandline = procedureFile->getNextLine(commandline.first);
172
173 if (procedureFile->isLastLine(commandline.first))
174 return commandline.first;
175 }
176
177 // extract procedure name
178 sProcedureName = getProcedureName(commandline.second.getCommandLine());
179
180 // Insert the "thisfile" namespace, if the current procedure is not
181 // the main procedure of the current file
182 if (sProcedureName.find('~') != std::string::npos && procedureFile->getFileName().substr(procedureFile->getFileName().rfind('/')+1) != sProcedureName.substr(sProcedureName.rfind('~')+1) + ".nprc")
183 sProcedureName.insert(sProcedureName.rfind('~')+1, sThisFileNameSpacePrefix + "thisfile~");
184 else if (sProcedureName.find('/') != std::string::npos && procedureFile->getFileName().substr(procedureFile->getFileName().rfind('/')+1) != sProcedureName.substr(sProcedureName.rfind('/')+1) + ".nprc")
185 sProcedureName.insert(sProcedureName.rfind('/')+1, sThisFileNameSpacePrefix + "thisfile~");
186 else
187 sMainProcedure = sProcedureName;
188
189 // Create a new (empty) dependency list
190 mDependencies[sProcedureName] = DependencyList();
191
192 // As long as we do not hit the procedure foot, we search for
193 // namespace declarations and procedure calls
194 while (commandline.second.getType() != ProcedureCommandLine::TYPE_PROCEDURE_FOOT && !procedureFile->isLastLine(commandline.first))
195 {
196 commandline = procedureFile->getNextLine(commandline.first);
197
198 if (findCommand(commandline.second.getCommandLine()).sString == "namespace")
199 {
200 // Resolve the current namespace declaration
201 sCurrentNameSpace = decodeNameSpace(commandline.second.getCommandLine(), sThisNameSpace);
202
203 if (sCurrentNameSpace.length())
204 sCurrentNameSpace += "~";
205 else
206 sCurrentNameSpace = "main~";
207 }
208 else
209 resolveProcedureCalls(commandline.second.getCommandLine(), sProcedureName, sCurrentNameSpace);
210 }
211
212 // Return the foot line of the procedure
213 return commandline.first;
214}
215
216
225std::string Dependencies::getProcedureName(std::string sCommandLine) const
226{
227 if (sCommandLine.find("procedure ") == std::string::npos || sCommandLine.find('$') == std::string::npos)
228 return "";
229
230 if (sThisNameSpace.find('/') != std::string::npos)
231 return "$" + sThisNameSpace + "/" + sCommandLine.substr(sCommandLine.find('$')+1, sCommandLine.find('(') - sCommandLine.find('$')-1);
232
233 return "$" + sThisNameSpace + "~" + sCommandLine.substr(sCommandLine.find('$')+1, sCommandLine.find('(') - sCommandLine.find('$')-1);
234}
235
236
248void Dependencies::resolveProcedureCalls(std::string sLine, const std::string& sProcedureName, const std::string& sCurrentNameSpace)
249{
250 if (sLine.find('$') != std::string::npos && sLine.find('(', sLine.find('$')) != std::string::npos)
251 {
252 sLine += " ";
253 size_t nPos = 0;
254
255 // Handle all procedure calls one after the other
256 while (sLine.find('$', nPos) != std::string::npos && sLine.find('(', sLine.find('$', nPos)) != std::string::npos)
257 {
258 nPos = sLine.find('$', nPos) + 1;
259 std::string __sName = sLine.substr(nPos, sLine.find('(', nPos) - nPos);
260
261 if (!isInQuotes(sLine, nPos, true))
262 {
263 // Add namespaces, where necessary
264 if (__sName.find('~') == std::string::npos)
265 __sName = sCurrentNameSpace + __sName;
266
267 if (__sName.substr(0, 5) == "this~")
268 __sName.replace(0, 4, sThisNameSpace);
269
270 if (__sName.substr(0, 9) == "thisfile~")
271 __sName = sThisNameSpace + "~" + sThisFileNameSpacePrefix + __sName;
272
273 // Handle explicit procedure file names
274 if (sLine[nPos] == '\'')
275 __sName = sLine.substr(nPos + 1, sLine.find('\'', nPos + 1) - nPos - 1);
276
277 if (__sName.find('/') != std::string::npos && __sName.find("thisfile~") == std::string::npos)
278 replaceAll(__sName, "~", "/");
279
280 // Add procedure name and called procedure file name to the
281 // dependency list
282 mDependencies[sProcedureName].push_back(Dependency("$" + __sName, getProcedureFileName(__sName)));
283 }
284
285 nPos += __sName.length() + 1;
286 }
287 }
288}
289
290
299std::string Dependencies::getProcedureFileName(std::string sProc) const
300{
301 if (sProc.length())
302 {
303 // Handle the "thisfile" namespace by using the call stack
304 // to obtain the corresponding file name
305 if (sProc.find("thisfile~") != std::string::npos)
306 return sFileName;
307
308 // Replace all tilde characters in the current path
309 // string. Consider the special namespace "main", which
310 // is a reference to the toplevel procedure folder
311 for (size_t i = 0; i < sProc.length(); i++)
312 {
313 if (sProc[i] == '~')
314 {
315 if (sProc.length() > 5 && i >= 4 && sProc.substr(i - 4, 5) == "main~")
316 sProc = sProc.substr(0, i - 4) + sProc.substr(i + 1);
317 else
318 sProc[i] = '/';
319 }
320 }
321
322 // Create a valid file name from the procedure name
324
325 // Append the newly obtained procedure file name
326 // to the call stack
327 return sProc;
328 }
329
330 return "";
331}
332
std::string getProcedureName(std::string sCommandLine) const
This member function extracts the procedure name from the procedure head.
Definition: dependency.cpp:225
std::map< std::string, DependencyList > mDependencies
Definition: dependency.hpp:83
void resolveProcedureCalls(std::string sCommandLine, const std::string &sProcedureName, const std::string &sCurrentNameSpace)
This member function resilves the procedure calls contained in the current procedure command line.
Definition: dependency.cpp:248
std::string sMainProcedure
Definition: dependency.hpp:87
std::string sFileName
Definition: dependency.hpp:84
std::string getProcedureFileName(std::string sProc) const
This member function returns the file name of the current called procedure.
Definition: dependency.cpp:299
std::string sThisFileNameSpacePrefix
Definition: dependency.hpp:85
Dependencies(ProcedureElement *procedureFile)
Dependencies constructor.
Definition: dependency.cpp:82
int getProcedureDependencies(ProcedureElement *procedureFile, int nCurrentLine)
This member function calculates the dependencies of the current procedure.
Definition: dependency.cpp:162
std::string sThisNameSpace
Definition: dependency.hpp:86
void walk(ProcedureElement *procedureFile)
This member function will walk through the file and redirect the control to getProcedureDependencies(...
Definition: dependency.cpp:136
This class resembles a simple dependency containing a procedure name and the corresponding file name.
Definition: dependency.hpp:33
std::string & getProcedureName()
Definition: dependency.hpp:46
This class is a child of the std::list, where the function unique() has been overridden (i....
Definition: dependency.hpp:64
void unique()
Implementation of DependencyList::unique.
Definition: dependency.cpp:65
std::string ValidFileName(std::string _sFileName, const std::string sExtension=".dat", bool checkExtension=true, bool doCleanPath=true) const
This member function evaluates, whether the passed filename is a valid filename. One may supply a pre...
Definition: filesystem.cpp:280
static NumeReKernel * getInstance()
This static member function returns a a pointer to the singleton instance of the kernel.
Definition: kernel.hpp:221
Procedure & getProcedureInterpreter()
Definition: kernel.hpp:316
Settings & getSettings()
Definition: kernel.hpp:296
This class contains the pre-parsed contents of a single procedure file.
std::string getFileName() const
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...
bool isLastLine(int currentline)
This member function determines, whether the current line is the last line of the stored procedure fi...
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::string getProcPath() const
Returns the current procedure root import path.
Definition: settings.hpp:1068
static bool isequal(const Dependency &first, const Dependency &second)
Static helper function for DependencyList::unique.
Definition: dependency.cpp:52
static bool compare(const Dependency &first, const Dependency &second)
Static helper function for DependencyList::unique.
Definition: dependency.cpp:37
std::string replacePathSeparator(const std::string &)
This function replaces the Windows style path sparators to UNIX style.
void replaceAll(std::string &sToModify, const char *sToRep, const char *sNewValue, size_t nStart, size_t nEnd)
This function replaces all occurences of the string sToRep in the string sToModify with the new value...
std::string sString
Match findCommand(StringView sCmd, const std::string &sCommand)
This function is very important for the command handler.
Definition: tools.cpp:1275
string decodeNameSpace(string sCommandLine, const string &sThisNameSpace)
Definition: tools.cpp:3476
bool isInQuotes(StringView sExpr, unsigned int nPos, bool bIgnoreVarParser)
Checks, whether the position in the passed expression is part of a string literal.
Definition: tools.cpp:1672