Vcsn  2.8
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/raise.hh>
9 #include <vcsn/misc/set.hh>
10 #include <vcsn/misc/stream.hh>
11 
12 namespace vcsn
13 {
14  namespace ast
15  {
18  {
19  public:
20  context_parser(std::istringstream& is)
21  : is_(is)
22  {}
23 
25  std::shared_ptr<ast_node> parse()
26  {
27  auto res = any_();
28  check_eof_(res);
29  return res;
30  }
31 
33  std::shared_ptr<ast_node> parse_context()
34  {
35  auto res = context_();
36  check_eof_(res);
37  return res;
38  }
39 
40  private:
42  int peek_()
43  {
44  skip_space(is_);
45  return is_.peek();
46  }
47 
49  char eat_(char c)
50  {
51  skip_space(is_);
52  return eat(is_, c);
53  }
54 
56  const std::string& eat_(const std::string& s)
57  {
58  skip_space(is_);
59  return eat(is_, s);
60  }
61 
64  void check_eof_(std::shared_ptr<ast_node> res)
65  {
66  if (peek_() != EOF)
67  {
68  std::ostringstream o;
69  auto printer = signature_printer{o, true};
70  res->accept(printer);
72  "unexpected trailing characters after '",
73  o.str(), "'");
74  }
75  }
76 
79  std::string word_()
80  {
81  skip_space(is_);
82  std::string res;
83  int c;
84  while ((c = is_.peek()) != EOF)
85  if (c == '<' || c == ',' || c == '>' || c == '(')
86  break;
87  else
88  {
89  res += c;
90  is_.ignore();
91  }
92  // Keep inner spaces, but not trailing spaces.
93  boost::algorithm::trim_right(res);
94  return res;
95  }
96 
100  std::string parameters_()
101  {
102  auto res = std::string{};
103  res += eat_('<');
104  auto nesting = 1;
105  int c;
106  while ((c = peek_()) != EOF)
107  {
108  if (c == '<')
109  ++nesting;
110  else if (c == '>' && --nesting == 0)
111  break;
112  res += c;
113  is_.ignore();
114  }
115  res += eat_('>');
116  return res;
117  }
118 
120  std::shared_ptr<ast_node> any_()
121  {
122  auto w = word_();
123  auto res = std::shared_ptr<ast_node>{};
124  if (boost::ends_with(w, "_automaton"))
125  res = automaton_(w);
126  else if (w == "context")
127  res = context_(w);
128  else if (w == "expansionset")
129  res = expansionset_();
130  else if (w == "expressionset" || w == "seriesset")
131  res = expressionset_(w);
132  else if (has(labelsets_, w))
133  res = labelset_(w);
134  else if (w == "lat")
135  res = tupleset_();
136  else if (w == "polynomialset")
137  res = polynomialset_();
138  else if (w == "std::tuple")
139  res = tuple_();
140  else if (has(weightsets_, w))
141  res = weightset_(w);
142  else
143  // int,
144  // std::integral_constant<unsigned, 2>,
145  // boost::optional<unsigned>,
146  // std::vector<unsigned>,
147  // const std::set<std::pair<std::string, std::string>>,
148  // etc.
149  {
150  if (peek_() == '<')
151  w += parameters_();
152  res = std::make_shared<other>(w);
153  }
154  return res;
155  }
156 
160  std::shared_ptr<const genset> genset_()
161  {
162  if (peek_() == '<')
163  {
164  eat_('<');
165  auto res = genset_(word_());
166  eat_('>');
167  return res;
168  }
169  else
170  return genset_("char_letters");
171  }
172 
175  std::shared_ptr<const genset> genset_(std::string letter_type)
176  {
177  if (letter_type == "char" || letter_type == "string")
178  letter_type += "_letters";
179  std::string gens;
180  if (peek_() == '(')
181  {
182  gens += '(';
183  int c = is_.get();
184  while ((c = is_.get()) != EOF && c != ')')
185  {
186  gens += c;
187  if (c == '\\')
188  {
189  c = is_.get();
190  require(c != EOF, "unexpected end of file");
191  gens += c;
192  }
193  }
194  gens += ')';
195  }
196  return std::make_shared<const genset>(letter_type, gens);
197  }
198 
200  std::shared_ptr<context> context_()
201  {
202  return context_(word_());
203  }
204 
206  std::shared_ptr<context> context_(std::string w)
207  {
208  bool close = false;
209  if (w == "context")
210  {
211  eat_('<');
212  close = true;
213  w = word_();
214  }
215  auto ls = labelset_(w);
216  eat_(',');
217  auto ws = weightset_();
218  if (close)
219  eat_('>');
220  return std::make_shared<context>(ls, ws);
221  }
222 
224  std::shared_ptr<ast_node> labelset_()
225  {
226  return labelset_(word_());
227  }
228 
230  std::shared_ptr<ast_node> labelset_(const std::string& ls)
231  {
232  if (ls == "lal_char")
233  return std::make_shared<letterset>(genset_("char_letters"));
234  else if (ls == "lan")
235  // lan<GENSET> => nullableset<letterset<GENSET>>.
236  return std::make_shared<nullableset>(std::make_shared<letterset>
237  (genset_()));
238  else if (ls == "lan_char")
239  return std::make_shared<nullableset>(std::make_shared<letterset>
240  (genset_("char_letters")));
241  else if (ls == "lao")
242  return std::make_shared<oneset>();
243  else if (ls == "lat")
244  return tupleset_();
245  else if (ls == "law_char")
246  return std::make_shared<wordset>(genset_("char_letters"));
247  else if (ls == "lal" || ls == "letterset")
248  return std::make_shared<letterset>(genset_());
249  else if (ls == "law" || ls == "wordset")
250  return std::make_shared<wordset>(genset_());
251  else if (ls == "nullableset")
252  {
253  eat_('<');
254  auto res = labelset_();
255  eat_('>');
256  if (!res->has_one())
257  res = std::make_shared<nullableset>(res);
258  return res;
259  }
260  else if (ls == "expressionset" || ls == "seriesset")
261  return expressionset_(ls);
262  else
263  raise("invalid labelset name: ", str_quote(ls));
264  }
265 
267  std::shared_ptr<ast_node> weightset_()
268  {
269  return weightset_(word_());
270  }
271 
273  std::shared_ptr<ast_node> weightset_(const std::string& ws)
274  {
275  if (has(weightsets_, ws))
276  return std::make_shared<weightset>(ws);
277  else if (ws == "expressionset" || ws == "seriesset")
278  return expressionset_(ws);
279  else if (ws == "polynomialset")
280  return polynomialset_();
281  else if (ws == "lat")
282  return tupleset_();
283  else
284  raise("invalid weightset name: ", str_quote(ws));
285  }
286 
288  std::shared_ptr<automaton> automaton_()
289  {
290  return automaton_(word_());
291  }
292 
294  std::shared_ptr<automaton> automaton_(std::string prefix)
295  {
296  auto res = std::shared_ptr<automaton>{};
297  // focus_automaton<TapeNum, Aut>.
298  if (prefix == "focus_automaton")
299  {
300  eat_('<');
301  res = std::make_shared<automaton>(prefix,
302  std::make_shared<other>(word_()));
303  eat_(',');
304  res->get_content().emplace_back(automaton_());
305  eat_('>');
306  }
307  // xxx_automaton<Aut>.
308  else if (prefix == "delay_automaton"
309  || prefix == "expression_automaton"
310  || prefix == "filter_automaton"
311  || prefix == "insplit_automaton"
312  || prefix == "lazy_proper_automaton"
313  || prefix == "name_automaton"
314  || prefix == "pair_automaton"
315  || prefix == "partition_automaton"
316  || prefix == "permutation_automaton"
317  || prefix == "scc_automaton"
318  || prefix == "synchronized_automaton"
319  || prefix == "transpose_automaton")
320  {
321  eat_('<');
322  res = std::make_shared<automaton>(prefix, automaton_());
323  eat_('>');
324  }
325  // xxx_automaton<Aut, Tag, Lazy>.
326  else if (prefix == "determinized_automaton")
327  {
328  eat_('<');
329  res = std::make_shared<automaton>(prefix, automaton_());
330  eat_(',');
331  res->get_content().emplace_back(any_());
332  eat_(',');
333  res->get_content().emplace_back(any_());
334  eat_('>');
335  }
336  // mutable_automaton<Context>.
337  else if (prefix == "mutable_automaton")
338  {
339  eat_('<');
340  res = std::make_shared<automaton>(prefix, context_());
341  eat_('>');
342  }
343  // xxx_automaton<ExpresionSet>.
344  else if (prefix == "derived_term_automaton")
345  {
346  eat_('<');
347  res = std::make_shared<automaton>(prefix, expressionset_());
348  eat_('>');
349  }
350  // xxx_automaton<Aut...>.
351  else if (prefix == "compose_automaton"
352  || prefix == "product_automaton"
353  || prefix == "tuple_automaton")
354  {
355  eat_('<');
356  std::string w = "";
357  if (prefix != "tuple_automaton")
358  {
359  w = word_();
360  eat_(',');
361  }
362  res = std::make_shared<automaton>(prefix,
363  automaton_(word_()));
364  if (prefix != "tuple_automaton")
365  {
366  auto& c = res->get_content();
367  c.insert(c.begin(), std::make_shared<other>(w));
368  }
369  while (peek_() == ',')
370  {
371  eat_(',');
372  res->get_content().emplace_back(automaton_());
373  }
374  eat_('>');
375  }
376  else
377  raise("invalid automaton name: ", str_quote(prefix));
378  return res;
379  }
380 
382  std::shared_ptr<tuple> tuple_()
383  {
384  eat_('<');
385  typename tuple::value_t res;
386  res.emplace_back(any_());
387  while (peek_() == ',')
388  {
389  eat_(',');
390  res.emplace_back(any_());
391  }
392  eat_('>');
393  return std::make_shared<tuple>(res);
394  }
395 
397  std::shared_ptr<tupleset> tupleset_()
398  {
399  eat_('<');
400  auto res = typename tupleset::value_t{};
401  res.emplace_back(labelset_or_weightset_());
402  while (peek_() == ',')
403  {
404  eat_(',');
405  res.emplace_back(labelset_or_weightset_());
406  }
407  eat_('>');
408  return std::make_shared<tupleset>(res);
409  }
410 
413  std::shared_ptr<expressionset> expressionset_()
414  {
415  return expressionset_(word_());
416  }
417 
420  std::shared_ptr<expressionset> expressionset_(const std::string& w)
421  {
422  require(w == "expressionset" || w == "seriesset",
423  "invalid expressionset type: ", w,
424  " expected expressionset or seriesset");
425  eat_('<');
426  auto context = context_();
427  eat_('>');
428  auto ids =
429  w == "seriesset" ? rat::identities::distributive : rat::identities{};
430  if (peek_() == '(')
431  {
432  eat_('(');
433  is_ >> ids;
434  eat_(')');
435  }
436  return std::make_shared<expressionset>(context, ids);
437  }
438 
440  std::shared_ptr<expansionset> expansionset_()
441  {
442  eat_('<');
443  auto res = std::make_shared<expansionset>(expressionset_());
444  eat_('>');
445  return res;
446  }
447 
449  std::shared_ptr<polynomialset> polynomialset_()
450  {
451  eat_('<');
452  auto res = std::make_shared<polynomialset>(context_());
453  eat_('>');
454  return res;
455  }
456 
458  std::shared_ptr<ast_node> labelset_or_weightset_()
459  {
460  return labelset_or_weightset_(word_());
461  }
462 
464  std::shared_ptr<ast_node> labelset_or_weightset_(const std::string& w)
465  {
466  if (w == "lat")
467  return tupleset_();
468  else if (w == "expressionset" || w == "seriesset")
469  return expressionset_(w);
470  else if (has(labelsets_, w))
471  return labelset_(w);
472  else if (has(weightsets_, w))
473  return weightset_(w);
474  else
475  raise("invalid weightset or labelset name: ", str_quote(w));
476  }
477 
479  std::istringstream& is_;
480 
482  std::set<std::string> weightsets_ =
483  {
484  "b",
485  "f2",
486  "log",
487  "nmin",
488  "q",
489  "qmp",
490  "r",
491  "rmin",
492  "z",
493  "zmin",
494  };
495 
497  std::set<std::string> labelsets_ =
498  {
499  "lal",
500  "lal_char",
501  "lan",
502  "lan_char",
503  "lao",
504  "law",
505  "law_char",
506  "letterset",
507  "nullableset",
508  "wordset",
509  };
510  };
511 
512  std::shared_ptr<ast_node> parse_context(const std::string& ctx)
513  {
514  std::istringstream is{ctx};
515  auto parser = ast::context_parser{is};
516  try
517  {
518  return parser.parse_context();
519  }
520  catch (const std::runtime_error& e)
521  {
522  raise(e, " while reading context: ", str_quote(ctx));
523  }
524  }
525 
526  std::shared_ptr<ast_node> parse_type(const std::string& type)
527  {
528  std::istringstream is{type};
529  auto parser = ast::context_parser{is};
530  try
531  {
532  return parser.parse();
533  }
534  catch (const std::runtime_error& e)
535  {
536  raise(e, " while reading type: ", str_quote(type));
537  }
538  }
539  }
540 }
Linear plus distribution. Used for series identities.
Definition: identities.hh:41
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:26
std::shared_ptr< ast_node > labelset_or_weightset_()
<LabelSet> | <WeightSet>
std::set< std::string > labelsets_
The set of weightset names.
auto prefix(const Aut &aut) -> decltype(::vcsn::copy(aut))
Definition: prefix.hh:69
std::shared_ptr< ast_node > weightset_(const std::string &ws)
<WeightSet>.
std::shared_ptr< ast_node > weightset_()
<WeightSet>.
std::string parameters_()
The next parameters in the stream.
std::shared_ptr< expansionset > expansionset_()
"expansionset" "<" <Expressionset> ">".
char eat(std::istream &is, char c)
Check lookahead character and advance.
Definition: stream.cc:147
const std::string & eat_(const std::string &s)
Accept this string, possibly preceded by spaces.
void skip_space(std::istream &is)
Ignore spaces.
Definition: stream.cc:222
std::shared_ptr< const genset > genset_(std::string letter_type)
A generator set (e.g., char_letters(abc) or char).
std::shared_ptr< ast_node > parse_type(const std::string &type)
Parse a type, and return its AST.
std::string word_()
The next word in the stream.
ATTRIBUTE_NORETURN void fail_reading(std::istream &is, Args &&... args)
Throw an exception after failing to read from is.
Definition: stream.hh:76
std::shared_ptr< context > context_(std::string w)
<LabelSet>, <WeightSet>.
std::shared_ptr< ast_node > any_()
Accept anything.
An expressionset can implement several different sets of identities on expressions.
Definition: identities.hh:20
std::vector< std::shared_ptr< ast_node > > value_t
Definition: type-ast.hh:89
Parser of snames.
std::shared_ptr< tupleset > tupleset_()
"<" (<LabelSet> | <WeightSet> ",")+ ">".
std::shared_ptr< expressionset > expressionset_(const std::string &w)
"expressionset" "<" <Context> ">", possibly followed by identities.
std::shared_ptr< ast_node > labelset_(const std::string &ls)
<LabelSet>.
std::shared_ptr< automaton > automaton_(std::string prefix)
<Automaton> "<" <Context> ">".
std::istringstream & is_
The stream we are parsing.
int peek_()
The next character, possibly preceded by spaces.
std::shared_ptr< polynomialset > polynomialset_()
"polynomialset" "<" <Context> ">".
std::vector< std::shared_ptr< ast_node > > value_t
Definition: type-ast.hh:61
std::shared_ptr< context > context_()
<LabelSet>, <WeightSet>.
Definition: a-star.hh:8
std::shared_ptr< ast_node > parse()
Accept anything.
context_parser(std::istringstream &is)
std::shared_ptr< ast_node > parse_context()
Accept only a valid context.
std::shared_ptr< const genset > genset_()
An optional generator set in brackets (e.g., <char_letters(abc)> or <char>).
std::shared_ptr< ast_node > labelset_()
<LabelSet>.
std::set< std::string > weightsets_
The set of terminal weightset names.
char eat_(char c)
Accept this character, possibly preceded by spaces.
std::string str_quote(Args &&... args)
Convert to a string, in quotes.
Definition: escape.hh:49
std::shared_ptr< tuple > tuple_()
"<" (<Any> ",")* ">".
static identities ids(const driver &d)
Get the identities of the driver.
Definition: parse.cc:91
void require(Bool b, Args &&... args)
If b is not verified, raise an error with args as message.
Definition: raise.hh:87
std::shared_ptr< automaton > automaton_()
<Automaton> "<" <Context> ">".
void check_eof_(std::shared_ptr< ast_node > res)
We managed to read res in is, check that is_ is finished.
std::shared_ptr< expressionset > expressionset_()
("expressionset"|"seriesset") "<" <Context> ">", possibly followed by identities. ...
return res
Definition: multiply.hh:399
std::shared_ptr< ast_node > labelset_or_weightset_(const std::string &w)
<LabelSet> | <WeightSet>