Euphoria
textfileparser.cc
Go to the documentation of this file.
1 #include "core/textfileparser.h"
2 
3 #include "assert/assert.h"
4 
5 #include "base/numeric.h"
6 #include "base/stringutils.h"
7 #include "base/stringbuilder.h"
8 
9 
10 namespace eu::core
11 {
12  namespace detail
13  {
14  char
16  {
17  return peek(1);
18  }
19 
20  struct TextFileString : public Textfile
21  {
22  std::string text;
23  std::size_t next_position = 0;
24 
25  [[nodiscard]]
26  bool
27  has_more() const override
28  {
29  return next_position < text.size();
30  }
31 
32  char
33  peek(int advance) override
34  {
35  ASSERT(advance >= 0);
36  const auto index = next_position + advance;
37 
38  if (index >= text.size())
39  {
40  return 0;
41  }
42  else
43  {
44  return text[index];
45  }
46  }
47 
48  char
49  read() override
50  {
51  if (!has_more())
52  {
53  return 0;
54  }
55 
56  const auto r = text[next_position];
57  next_position += 1;
58  return r;
59  }
60  };
61 
62  std::shared_ptr<Textfile>
63  create_from_string(const std::string& str)
64  {
65  auto file = std::make_shared<TextFileString>();
66  file->text = str;
67  return file;
68  }
69  }
70 
71  namespace
72  {
73  bool
74  is_newline(const char c)
75  {
76  if(c == '\n')
77  {
78  return true;
79  }
80 
81  if(c == '\r')
82  {
83  return true;
84  }
85 
86  return false;
87  }
88  }
89 
90  TextfileParser::TextfileParser(std::shared_ptr<detail::Textfile> afile)
91  : file(afile)
92  {
93  }
94 
96  TextfileParser::from_string(const std::string& str)
97  {
99  }
100 
101  char
103  {
104  return file->peek(advance);
105  }
106 
107 
108  std::string
110  {
111  const auto c = peek_char(advance);
113  }
114 
115  // if peekchar(0) is c then it is read and function returns true,
116  // otherwise false
117  bool
119  {
120  if(peek_char() == c)
121  {
122  read_char();
123  return true;
124  }
125  else
126  {
127  return false;
128  }
129  }
130 
131 
132  char
134  {
135  const char r = file->read();
136 
137  if(is_newline(r))
138  {
139  location.column = 1;
140  location.line += 1;
141  }
142  else
143  {
144  location.column += 1;
145  }
146 
147  return r;
148  }
149 
150  void
152  {
153  read_char();
154  }
155 
156  namespace
157  {
158  bool
159  is_ident_char(char c, bool first_char)
160  {
161  if(is_within_inclusive_as_int('a', c, 'z'))
162  {
163  return true;
164  }
165  if(is_within_inclusive_as_int('A', c, 'Z'))
166  {
167  return true;
168  }
169  if(is_within_inclusive_as_int('0', c, '9'))
170  {
171  return !first_char;
172  }
173  if(c == '_')
174  {
175  return true;
176  }
177 
178  return false;
179  }
180  }
181 
182  bool
184  {
185  return is_ident_char(c, true);
186  }
187 
188  std::string
190  {
191  auto ss = StringBuilder{};
192  bool first = true;
193  while(is_ident_char(peek_char(), first))
194  {
195  first = false;
196  ss.add_char(read_char());
197  }
198  return ss.to_string();
199  }
200 
201  std::string
203  {
204  auto ss = StringBuilder{};
205  const char quote = '\"';
206  if(peek_char() != quote)
207  {
208  return "";
209  }
210  advance_char(); // skip " char
211  while(peek_char() != quote)
212  {
213  const char c = read_char();
214  if(c == '\\')
215  {
216  const char nc = read_char();
217  if(nc == '\\')
218  {
219  ss.add_char('\\');
220  }
221  else if(nc == 't')
222  {
223  ss.add_char('\t');
224  }
225  else if(nc == '\n')
226  {
227  ss.add_char('\n');
228  }
229  else if(nc == '\"')
230  {
231  ss.add_char('\"');
232  }
233  else
234  {
235  ss.add_char(nc);
236  }
237  }
238  else
239  {
240  ss.add_char(c);
241  }
242  }
243  const char c = read_char();
244  if(c != quote)
245  {
246  return "";
247  }
248  return ss.to_string();
249  }
250 
251  std::string
253  {
254  auto ss = StringBuilder{};
255  while(!is_newline(peek_char()))
256  {
257  const char c = read_char();
258  if(c == 0)
259  {
260  return ss.to_string();
261  }
262  ss.add_char(c);
263  }
264  advance_char(); // skip the newline
265  return ss.to_string();
266  }
267 
268  namespace
269  {
270  bool
271  is_space_character(char c, bool include_newline)
272  {
273  switch(c)
274  {
275  case ' ':
276  case '\t': return true;
277  case '\n':
278  case '\r': return include_newline;
279  default: return false;
280  }
281  }
282  }
283 
284  void
285  TextfileParser::skip_spaces(bool include_newline)
286  {
287  while(is_space_character(peek_char(), include_newline))
288  {
289  read_char();
290  }
291  }
292 
293  bool
295  {
296  return file->has_more();
297  }
298 
299  int
301  {
302  return location.line;
303  }
304 
305  int
307  {
308  return location.column;
309  }
310 
311 }
312 
#define ASSERT(x)
Definition: assert.h:29
std::string from_char_to_string(char c, CharToStringStyle style)
Definition: stringutils.cc:168
std::shared_ptr< Textfile > create_from_string(const std::string &str)
bool is_ident_start(char c)
bool is_within_inclusive_as_int(int min, int c, int max)
Definition: numeric.cc:116
String utility functions.
std::string to_string()
Complete the builder and return the resulting string.
StringBuilder & add_char(char c)
Parses a text file in memory.
bool expect_char(char c)
if peekchar(0) is c then it is read and function returns true, otherwise false
TextfileParser(std::shared_ptr< detail::Textfile > afile)
void skip_spaces(bool include_newline)
std::string peek_string(int advance=0)
like PeekChar but returns human readable strings for some chars
std::string read_to_end_of_line()
detail::LocationInFile location
std::shared_ptr< detail::Textfile > file
static TextfileParser from_string(const std::string &str)
char peek_char(int advance=0)
advance = 0 - next char, 1-the one after that, negative values are not allowed
char peek(int advance) override
bool has_more() const override