8168892c708b75809f93d7c3de54bf597827ee6a
[scilab.git] / scilab / modules / slint / src / cpp / SciFile.cpp
1 /*
2  *  Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3  *  Copyright (C) 2015 - Scilab Enterprises - Calixte DENIZET
4  *
5  * Copyright (C) 2012 - 2016 - Scilab Enterprises
6  *
7  * This file is hereby licensed under the terms of the GNU GPL v2.0,
8  * pursuant to article 5.3.4 of the CeCILL v.2.1.
9  * This file was originally licensed under the terms of the CeCILL v2.1,
10  * and continues to be available under such terms.
11  * For more information, see the COPYING file which you should have received
12  * along with this program.
13  *
14  */
15
16 #include "SciFile.hxx"
17
18 extern "C"
19 {
20 #include "sci_malloc.h"
21 }
22
23 namespace slint
24 {
25
26 SciFile::SciFile() : code(nullptr), tree(nullptr), main(nullptr), codeLength(0) { }
27
28 SciFile::SciFile(const std::wstring & _filename, const wchar_t * _code, const ast::Exp * _tree) : filename(_filename), code(_code), tree(_tree), main(nullptr)
29 {
30     initLines();
31     analyzeTree();
32 }
33
34 SciFile::~SciFile()
35 {
36     FREE(const_cast<wchar_t *>(code));
37     delete tree;
38 }
39
40 const std::wstring & SciFile::getFilename() const
41 {
42     return filename;
43 }
44
45 const wchar_t * SciFile::getCode() const
46 {
47     return code;
48 }
49
50 unsigned int SciFile::getCodeLength() const
51 {
52     return codeLength;
53 }
54
55 const ast::Exp * SciFile::getTree() const
56 {
57     return tree;
58 }
59
60 bool SciFile::getPosition(const Location & loc, std::pair<unsigned int, unsigned int> & out) const
61 {
62     if (loc.first_line > lines.size() || loc.last_line > lines.size())
63     {
64         return false;
65     }
66     out.first = lines[loc.first_line - 1].first + loc.first_column - 1;
67     out.second = lines[loc.last_line - 1].first + loc.last_column - 1;
68
69     return out.first <= codeLength && out.second <= codeLength;
70 }
71
72 bool SciFile::getFromPositionToEOL(const Location & loc, std::pair<unsigned int, unsigned int> & out) const
73 {
74     if (loc.first_line + 1 > lines.size())
75     {
76         return false;
77     }
78     out.first = lines[loc.first_line - 1].first + loc.first_column - 1;
79     out.second = lines[loc.last_line - 1].second + 1;
80
81     return out.first <= codeLength;
82 }
83
84 bool SciFile::checkLineLength(const unsigned int max, std::vector<unsigned int> & out) const
85 {
86     unsigned int i = 1;
87     for (const auto & line : lines)
88     {
89         if (line.second - line.first + 1 > max)
90         {
91             out.push_back(i);
92         }
93         ++i;
94     }
95     return out.empty();
96 }
97
98 unsigned int SciFile::countLines() const
99 {
100     unsigned int i = 0;
101     for (const auto & line : lines)
102     {
103         if (line.first < line.second && !isEmptyLine(code + line.first, line.second - line.first + 1))
104         {
105             ++i;
106         }
107     }
108     return i;
109 }
110
111 unsigned int SciFile::countLines(const unsigned from, const unsigned to) const
112 {
113     unsigned int i = 0;
114     for (unsigned j = from; j <= to; ++j)
115     {
116         const auto & line = lines[j - 1];
117         if (line.first < line.second && !isEmptyLine(code + line.first, line.second - line.first + 1))
118         {
119             ++i;
120         }
121     }
122     return i;
123 }
124
125 void SciFile::initLines()
126 {
127     lines.clear();
128     codeLength = 0;
129     if (code)
130     {
131         const wchar_t * p = code;
132         lines.emplace_back(0, 0);
133         while (*p)
134         {
135             if (*p == L'\n') // Unix EOL
136             {
137                 lines.back().second = p - code - 1;
138                 lines.emplace_back(p - code + 1, 0);
139                 ++p;
140             }
141             else if (*p == L'\r')
142             {
143                 if (*(p + 1) == L'\n') // Windows EOL
144                 {
145                     lines.back().second = p - code - 1;
146                     lines.emplace_back(p - code + 2, 0);
147                     p += 2;
148                 }
149                 else // Old mac EOL
150                 {
151                     lines.back().second = p - code - 1;
152                     lines.emplace_back(p - code + 1, 0);
153                     ++p;
154                 }
155             }
156             else
157             {
158                 ++p;
159             }
160         }
161
162         lines.back().second = p - code - 1;
163         codeLength = p - code;
164     }
165
166     /*for (const auto & line : lines)
167       {
168       std::wcerr << line.first << "->" << line.second << std::endl;
169       }*/
170 }
171
172 bool SciFile::isEmptyLine(const wchar_t * line, const unsigned len) const
173 {
174     // An empty line is (^[\t ]*//) or (^[\t ]*$)
175     for (unsigned i = 0; i < len; ++i)
176     {
177         const wchar_t c = line[i];
178         if (c == L' ' || c == L'\t')
179         {
180             continue;
181         }
182         else if (c == L'/' && (i < len - 1) && line[i + 1] == L'/')
183         {
184             return true;
185         }
186         else
187         {
188             return false;
189         }
190     }
191     return true;
192 }
193
194 void SciFile::analyzeTree()
195 {
196     if (tree && tree->isSeqExp())
197     {
198         bool first = true;
199         const ast::SeqExp * se = static_cast<const ast::SeqExp *>(tree);
200         for (const auto e : se->getExps())
201         {
202             if (e->isFunctionDec())
203             {
204                 const ast::FunctionDec * fd = static_cast<const ast::FunctionDec *>(e);
205                 if (first)
206                 {
207                     main = fd;
208                     first = false;
209                 }
210                 else
211                 {
212                     privateFunctions.emplace(fd->getSymbol().getName(), fd);
213                 }
214             }
215         }
216     }
217 }
218
219 bool SciFile::isPrivateFunction(const symbol::Symbol & sym) const
220 {
221     return privateFunctions.find(sym.getName()) != privateFunctions.end();
222 }
223
224 const ast::FunctionDec * SciFile::getPrivateFunction(const std::wstring & name) const
225 {
226     auto i = privateFunctions.find(name);
227     if (i != privateFunctions.end())
228     {
229         return i->second;
230     }
231     return nullptr;
232 }
233
234 const ast::FunctionDec * SciFile::getMain() const
235 {
236     return main;
237 }
238
239 } // namespace slint