Vcsn  2.2
Be Rational
context-parser.cc
Go to the documentation of this file.
1 #include <boost/algorithm/string/predicate.hpp>
2 #include <boost/algorithm/string/trim.hpp>
3 
6 
7 #include <vcsn/misc/escape.hh>
8 #include <vcsn/misc/indent.hh>
9 #include <vcsn/misc/raise.hh>
10 
11 namespace vcsn
12 {
13  namespace ast
14  {
16  {
17  while (isspace(is_.peek()))
18  is_.ignore();
19  }
20 
22  {
23  skip_space_();
24  return is_.peek();
25  }
26 
27  char context_parser::eat_(char c)
28  {
29  skip_space_();
30  return eat(is_, c);
31  }
32 
33  const std::string& context_parser::eat_(const std::string& s)
34  {
35  skip_space_();
36  return eat(is_, s);
37  }
38 
39  void context_parser::check_eof_(std::shared_ptr<ast_node> res)
40  {
41  if (peek_() != EOF)
42  {
43  std::ostringstream o;
44  signature_printer printer(o, true);
45  res->accept(printer);
47  "unexpected trailing characters after '",
48  o.str(), "'");
49  }
50  }
51 
52  std::string context_parser::word_()
53  {
54  skip_space_();
55  std::string res;
56  int c;
57  while ((c = is_.peek()) != EOF)
58  if (c == '<' || c == ',' || c == '>' || c == '(')
59  break;
60  else
61  {
62  res += c;
63  is_.ignore();
64  }
65  // Keep inner spaces, but not trailing spaces.
66  boost::algorithm::trim_right(res);
67  return res;
68  }
69 
71  {
72  std::string res;
73  res += eat_('<');
74  auto nesting = 1;
75  int c;
76  while ((c = peek_()) != EOF)
77  {
78  if (c == '<')
79  ++nesting;
80  else if (c == '>' && --nesting == 0)
81  break;
82  res += c;
83  is_.ignore();
84  }
85  res += eat_('>');
86  return res;
87  }
88 
89  std::shared_ptr<ast_node> context_parser::parse()
90  {
91  auto res = any_();
92  check_eof_(res);
93  return res;
94  }
95 
96  std::shared_ptr<ast_node> context_parser::parse_context()
97  {
98  auto res = context_();
99  check_eof_(res);
100  return res;
101  }
102 
103  std::shared_ptr<ast_node> context_parser::any_()
104  {
105  std::string w = word_();
106  auto res = std::shared_ptr<ast_node>{};
107  if (boost::ends_with(w, "_automaton"))
108  res = automaton_(w);
109  else if (w == "context")
110  res = context_(w);
111  else if (w == "expansionset")
112  res = expansionset_();
113  else if (w == "expressionset")
114  res = expressionset_();
115  else if (has(labelsets_, w))
116  res = labelset_(w);
117  else if (w == "lat")
118  res = tupleset_();
119  else if (w == "polynomialset")
120  res = polynomialset_();
121  else if (w == "seriesset")
122  res = seriesset_();
123  else if (w == "std::tuple")
124  res = tuple_();
125  else if (has(weightsets_, w))
126  res = weightset_(w);
127  else
128  // int,
129  // std::integral_constant<unsigned, 2>,
130  // boost::optional<unsigned>,
131  // std::vector<unsigned>,
132  // const std::set<std::pair<std::string, std::string>>,
133  // etc.
134  {
135  if (peek_() == '<')
136  w += parameters_();
137  res = std::make_shared<other>(w);
138  }
139  return res;
140  }
141 
142  std::shared_ptr<ast_node>
144  {
145  return labelset_or_weightset_(word_());
146  }
147 
148  std::shared_ptr<ast_node>
150  {
151  if (w == "lat")
152  return tupleset_();
153  else if (w == "expressionset")
154  return expressionset_();
155  else if (w == "seriesset")
156  return seriesset_();
157  else if (has(labelsets_, w))
158  return labelset_(w);
159  else if (has(weightsets_, w))
160  return weightset_(w);
161  else
162  raise("invalid weightset or labelset name: " + w);
163  }
164 
165  std::shared_ptr<const genset>
166  context_parser::genset_(std::string letter_type)
167  {
168  if (letter_type == "char" || letter_type == "string")
169  letter_type += "_letters";
170  std::string gens;
171  if (peek_() == '(')
172  {
173  gens += '(';
174  int c = is_.get();
175  while ((c = is_.get()) != EOF && c != ')')
176  {
177  gens += c;
178  if (c == '\\')
179  {
180  c = is_.get();
181  require(c != EOF, "unexpected end of file");
182  gens += c;
183  }
184  }
185  gens += ')';
186  }
187  return std::make_shared<const genset>(letter_type, gens);
188  }
189 
190  std::shared_ptr<const genset>
192  {
193  if (peek_() == '<')
194  {
195  eat_('<');
196  auto res = genset_(word_());
197  eat_('>');
198  return res;
199  }
200  else
201  return genset_("char_letters");
202  }
203 
204  std::shared_ptr<context> context_parser::context_()
205  {
206  return context_(word_());
207  }
208 
209  std::shared_ptr<context>
211  {
212  bool close = false;
213  if (w == "context")
214  {
215  eat_('<');
216  close = true;
217  w = word_();
218  }
219  auto ls = labelset_(w);
220  eat_(',');
221  auto ws = weightset_();
222  if (close)
223  eat_('>');
224  return std::make_shared<context>(ls, ws);
225  }
226 
227  std::shared_ptr<ast_node> context_parser::labelset_()
228  {
229  return labelset_(word_());
230  }
231 
232  std::shared_ptr<ast_node>
233  context_parser::labelset_(const std::string& ls)
234  {
235  if (ls == "lal_char")
236  return std::make_shared<letterset>(genset_("char_letters"));
237  else if (ls == "lan")
238  // lan<GENSET> => nullableset<letterset<GENSET>>.
239  return
240  std::make_shared<nullableset>(std::make_shared<letterset>(genset_()));
241  else if (ls == "lan_char")
242  return std::make_shared<nullableset>(std::make_shared<letterset>
243  (genset_("char_letters")));
244  else if (ls == "lao")
245  return std::make_shared<oneset>();
246  else if (ls == "lat")
247  return tupleset_();
248  else if (ls == "law_char")
249  return std::make_shared<wordset>(genset_("char_letters"));
250  else if (ls == "lal" || ls == "letterset")
251  return std::make_shared<letterset>(genset_());
252  else if (ls == "law" || ls == "wordset")
253  return std::make_shared<wordset>(genset_());
254  else if (ls == "nullableset")
255  {
256  eat_('<');
257  auto res = labelset_();
258  eat_('>');
259  if (!res->has_one())
260  res = std::make_shared<nullableset>(res);
261  return res;
262  }
263  else if (ls == "expressionset")
264  return expressionset_();
265  else if (ls == "seriesset")
266  return seriesset_();
267  else
268  raise("invalid labelset name: ", str_escape(ls));
269  }
270 
271  std::shared_ptr<ast_node> context_parser::weightset_()
272  {
273  return weightset_(word_());
274  }
275 
276  std::shared_ptr<ast_node>
277  context_parser::weightset_(const std::string& ws)
278  {
279  if (has(weightsets_, ws))
280  return std::make_shared<weightset>(ws);
281  else if (ws == "expressionset")
282  return expressionset_();
283  else if (ws == "seriesset")
284  return seriesset_();
285  else if (ws == "polynomialset")
286  return polynomialset_();
287  else if (ws == "lat")
288  return tupleset_();
289  else
290  raise("invalid weightset name: ", str_escape(ws));
291  }
292 
293  std::shared_ptr<automaton>
295  {
296  return automaton_(word_());
297  }
298 
299  std::shared_ptr<automaton>
301  {
302  auto res = std::shared_ptr<automaton>{};
303  // focus_automaton<TapeNum, Aut>.
304  if (prefix == "focus_automaton")
305  {
306  eat_('<');
307  res = std::make_shared<automaton>(prefix,
308  std::make_shared<other>(word_()));
309  eat_(',');
310  res->get_content().emplace_back(automaton_());
311  eat_('>');
312  }
313  // xxx_automaton<Aut>.
314  else if (prefix == "delay_automaton"
315  || prefix == "expression_automaton"
316  || prefix == "filter_automaton"
317  || prefix == "insplit_automaton"
318  || prefix == "lazy_proper_automaton"
319  || prefix == "name_automaton"
320  || prefix == "pair_automaton"
321  || prefix == "partition_automaton"
322  || prefix == "permutation_automaton"
323  || prefix == "scc_automaton"
324  || prefix == "synchronized_automaton"
325  || prefix == "transpose_automaton")
326  {
327  eat_('<');
328  res = std::make_shared<automaton>(prefix, automaton_());
329  eat_('>');
330  }
331  // xxx_automaton<Aut, Tag, Lazy>.
332  else if (prefix == "determinized_automaton")
333  {
334  eat_('<');
335  res = std::make_shared<automaton>(prefix, automaton_());
336  eat_(',');
337  res->get_content().emplace_back(any_());
338  eat_(',');
339  res->get_content().emplace_back(any_());
340  eat_('>');
341  }
342  // mutable_automaton<Context>.
343  else if (prefix == "mutable_automaton")
344  {
345  eat_('<');
346  res = std::make_shared<automaton>(prefix, context_());
347  eat_('>');
348  }
349  // xxx_automaton<ExpresionSet>.
350  else if (prefix == "derived_term_automaton")
351  {
352  eat_("<expressionset");
353  res = std::make_shared<automaton>(prefix, expressionset_());
354  eat_('>');
355  }
356  // xxx_automaton<Aut...>.
357  else if (prefix == "compose_automaton"
358  || prefix == "product_automaton"
359  || prefix == "tuple_automaton")
360  {
361  eat_('<');
362  std::string w = "";
363  if (prefix != "tuple_automaton")
364  {
365  w = word_();
366  eat_(',');
367  }
368  res = std::make_shared<automaton>(prefix,
369  automaton_(word_()));
370  if (prefix != "tuple_automaton")
371  {
372  auto& c = res->get_content();
373  c.insert(c.begin(), std::make_shared<other>(w));
374  }
375  while (peek_() == ',')
376  {
377  eat_(',');
378  res->get_content().emplace_back(automaton_());
379  }
380  eat_('>');
381  }
382  else
383  raise("invalid automaton name: ", str_escape(prefix));
384  return res;
385  }
386 
387  std::shared_ptr<tuple>
389  {
390  eat_('<');
391  typename tuple::value_t res;
392  res.emplace_back(any_());
393  while (peek_() == ',')
394  {
395  eat_(',');
396  res.emplace_back(any_());
397  }
398  eat_('>');
399  return std::make_shared<tuple>(res);
400  }
401 
402  std::shared_ptr<tupleset>
404  {
405  eat_('<');
406  typename tupleset::value_t res;
407  res.emplace_back(labelset_or_weightset_());
408  while (peek_() == ',')
409  {
410  eat_(',');
411  res.emplace_back(labelset_or_weightset_());
412  }
413  eat_('>');
414  return std::make_shared<tupleset>(res);
415  }
416 
417  std::shared_ptr<expressionset>
419  {
420  eat_('<');
421  auto context = context_();
422  eat_('>');
423  auto ids = rat::identities{};
424  if (peek_() == '(')
425  {
426  eat_('(');
427  is_ >> ids;
428  eat_(')');
429  }
430  return std::make_shared<expressionset>(context, ids);
431  }
432 
433  std::shared_ptr<expressionset>
435  {
436  eat_('<');
437  auto context = context_();
438  eat_('>');
439  return std::make_shared<expressionset>(context,
441  }
442 
443  std::shared_ptr<expansionset> context_parser::expansionset_()
444  {
445  eat_('<');
446  eat_("expressionset");
447  auto res = std::make_shared<expansionset>(expressionset_());
448  eat_('>');
449  return res;
450  }
451 
452  std::shared_ptr<polynomialset> context_parser::polynomialset_()
453  {
454  eat_('<');
455  auto res = std::make_shared<polynomialset>(context_());
456  eat_('>');
457  return res;
458  }
459  }
460 }
std::string parameters_()
The next parameters in the stream.
std::shared_ptr< ast_node > labelset_()
.
std::shared_ptr< automaton > automaton_()
"\<" "\>".
An expressionset can implement several different sets of identities on expressions.
Definition: identities.hh:21
Definition: a-star.hh:8
void require(Bool b, Args &&...args)
If b is not verified, raise an error with args as message.
Definition: raise.hh:78
std::ostream & str_escape(std::ostream &os, const std::string &str, const char *special=nullptr)
Output a string, escaping special characters.
Definition: escape.cc:54
char eat_(char c)
Accept this character, possibly preceded by spaces.
std::shared_ptr< tuple > tuple_()
"\<" ( ",")* "\>".
std::shared_ptr< expressionset > expressionset_()
"expressionset" "\<" "\>", possibly followed by identities.
Indentation relative functions.
char eat(std::istream &is, char c)
Check lookahead character and advance.
Definition: stream.cc:37
Traditional plus distribution. Used for series identities.
Definition: identities.hh:42
std::shared_ptr< context > context_()
, .
auto prefix(const Aut &aut) -> decltype(::vcsn::copy(aut))
Definition: prefix.hh:69
std::shared_ptr< ast_node > parse_context()
Accept only a valid context.
std::vector< std::shared_ptr< ast_node >> value_t
Definition: type-ast.hh:61
std::shared_ptr< const detail::context_base > context
A dyn::context.
Definition: fwd.hh:43
std::shared_ptr< ast_node > labelset_or_weightset_()
|
void check_eof_(std::shared_ptr< ast_node > res)
We managed to read res in is, check that is_ is finished.
std::set< std::string > weightsets_
The set of terminal weightset names.
ATTRIBUTE_NORETURN void fail_reading(std::istream &is, Args &&...args)
Throw an exception after failing to read from is.
Definition: stream.hh:62
std::vector< std::shared_ptr< ast_node >> value_t
Definition: type-ast.hh:88
std::shared_ptr< ast_node > any_()
Accept anything.
std::shared_ptr< const genset > genset_()
An optional generator set in brackets (e.g., or ).
void skip_space_()
Skip white spaces.
std::shared_ptr< ast_node > parse()
Accept anything.
ATTRIBUTE_PURE bool has(const boost::container::flat_set< Key, Compare, Allocator > &s, const Key &e)
Whether e is member of s.
Definition: setalpha.hh:25
int peek_()
The next character, possibly preceded by spaces.
std::shared_ptr< polynomialset > polynomialset_()
"polynomialset" "\<" "\>".
std::shared_ptr< expansionset > expansionset_()
"expansionset" "\<" "\>".
std::istringstream & is_
The stream we are parsing.
static identities ids(const driver &d)
Get the identities of the driver.
Definition: parse.cc:89
std::set< std::string > labelsets_
The set of weightset names.
std::shared_ptr< ast_node > weightset_()
.
std::shared_ptr< expressionset > seriesset_()
No optional argument.
std::string word_()
The next word in the stream.
std::shared_ptr< tupleset > tupleset_()
"\<" ( | ",")+ "\>".