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