Vcsn  2.4
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  signature_printer 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")
132  res = expressionset_();
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 == "seriesset")
140  res = seriesset_();
141  else if (w == "std::tuple")
142  res = tuple_();
143  else if (has(weightsets_, w))
144  res = weightset_(w);
145  else
146  // int,
147  // std::integral_constant<unsigned, 2>,
148  // boost::optional<unsigned>,
149  // std::vector<unsigned>,
150  // const std::set<std::pair<std::string, std::string>>,
151  // etc.
152  {
153  if (peek_() == '<')
154  w += parameters_();
155  res = std::make_shared<other>(w);
156  }
157  return res;
158  }
159 
163  std::shared_ptr<const genset> genset_()
164  {
165  if (peek_() == '<')
166  {
167  eat_('<');
168  auto res = genset_(word_());
169  eat_('>');
170  return res;
171  }
172  else
173  return genset_("char_letters");
174  }
175 
178  std::shared_ptr<const genset> genset_(std::string letter_type)
179  {
180  if (letter_type == "char" || letter_type == "string")
181  letter_type += "_letters";
182  std::string gens;
183  if (peek_() == '(')
184  {
185  gens += '(';
186  int c = is_.get();
187  while ((c = is_.get()) != EOF && c != ')')
188  {
189  gens += c;
190  if (c == '\\')
191  {
192  c = is_.get();
193  require(c != EOF, "unexpected end of file");
194  gens += c;
195  }
196  }
197  gens += ')';
198  }
199  return std::make_shared<const genset>(letter_type, gens);
200  }
201 
203  std::shared_ptr<context> context_()
204  {
205  return context_(word_());
206  }
207 
209  std::shared_ptr<context> context_(std::string w)
210  {
211  bool close = false;
212  if (w == "context")
213  {
214  eat_('<');
215  close = true;
216  w = word_();
217  }
218  auto ls = labelset_(w);
219  eat_(',');
220  auto ws = weightset_();
221  if (close)
222  eat_('>');
223  return std::make_shared<context>(ls, ws);
224  }
225 
227  std::shared_ptr<ast_node> labelset_()
228  {
229  return labelset_(word_());
230  }
231 
233  std::shared_ptr<ast_node> 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 std::make_shared<nullableset>(std::make_shared<letterset>
240  (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 
272  std::shared_ptr<ast_node> weightset_()
273  {
274  return weightset_(word_());
275  }
276 
278  std::shared_ptr<ast_node> weightset_(const std::string& ws)
279  {
280  if (has(weightsets_, ws))
281  return std::make_shared<weightset>(ws);
282  else if (ws == "expressionset")
283  return expressionset_();
284  else if (ws == "seriesset")
285  return seriesset_();
286  else if (ws == "polynomialset")
287  return polynomialset_();
288  else if (ws == "lat")
289  return tupleset_();
290  else
291  raise("invalid weightset name: ", str_escape(ws));
292  }
293 
295  std::shared_ptr<automaton> automaton_()
296  {
297  return automaton_(word_());
298  }
299 
301  std::shared_ptr<automaton> automaton_(std::string prefix)
302  {
303  auto res = std::shared_ptr<automaton>{};
304  // focus_automaton<TapeNum, Aut>.
305  if (prefix == "focus_automaton")
306  {
307  eat_('<');
308  res = std::make_shared<automaton>(prefix,
309  std::make_shared<other>(word_()));
310  eat_(',');
311  res->get_content().emplace_back(automaton_());
312  eat_('>');
313  }
314  // xxx_automaton<Aut>.
315  else if (prefix == "delay_automaton"
316  || prefix == "expression_automaton"
317  || prefix == "filter_automaton"
318  || prefix == "insplit_automaton"
319  || prefix == "lazy_proper_automaton"
320  || prefix == "name_automaton"
321  || prefix == "pair_automaton"
322  || prefix == "partition_automaton"
323  || prefix == "permutation_automaton"
324  || prefix == "scc_automaton"
325  || prefix == "synchronized_automaton"
326  || prefix == "transpose_automaton")
327  {
328  eat_('<');
329  res = std::make_shared<automaton>(prefix, automaton_());
330  eat_('>');
331  }
332  // xxx_automaton<Aut, Tag, Lazy>.
333  else if (prefix == "determinized_automaton")
334  {
335  eat_('<');
336  res = std::make_shared<automaton>(prefix, automaton_());
337  eat_(',');
338  res->get_content().emplace_back(any_());
339  eat_(',');
340  res->get_content().emplace_back(any_());
341  eat_('>');
342  }
343  // mutable_automaton<Context>.
344  else if (prefix == "mutable_automaton")
345  {
346  eat_('<');
347  res = std::make_shared<automaton>(prefix, context_());
348  eat_('>');
349  }
350  // xxx_automaton<ExpresionSet>.
351  else if (prefix == "derived_term_automaton")
352  {
353  eat_("<expressionset");
354  res = std::make_shared<automaton>(prefix, expressionset_());
355  eat_('>');
356  }
357  // xxx_automaton<Aut...>.
358  else if (prefix == "compose_automaton"
359  || prefix == "product_automaton"
360  || prefix == "tuple_automaton")
361  {
362  eat_('<');
363  std::string w = "";
364  if (prefix != "tuple_automaton")
365  {
366  w = word_();
367  eat_(',');
368  }
369  res = std::make_shared<automaton>(prefix,
370  automaton_(word_()));
371  if (prefix != "tuple_automaton")
372  {
373  auto& c = res->get_content();
374  c.insert(c.begin(), std::make_shared<other>(w));
375  }
376  while (peek_() == ',')
377  {
378  eat_(',');
379  res->get_content().emplace_back(automaton_());
380  }
381  eat_('>');
382  }
383  else
384  raise("invalid automaton name: ", str_escape(prefix));
385  return res;
386  }
387 
389  std::shared_ptr<tuple> tuple_()
390  {
391  eat_('<');
392  typename tuple::value_t res;
393  res.emplace_back(any_());
394  while (peek_() == ',')
395  {
396  eat_(',');
397  res.emplace_back(any_());
398  }
399  eat_('>');
400  return std::make_shared<tuple>(res);
401  }
402 
404  std::shared_ptr<tupleset> tupleset_()
405  {
406  eat_('<');
407  typename tupleset::value_t res;
408  res.emplace_back(labelset_or_weightset_());
409  while (peek_() == ',')
410  {
411  eat_(',');
412  res.emplace_back(labelset_or_weightset_());
413  }
414  eat_('>');
415  return std::make_shared<tupleset>(res);
416  }
417 
419  std::shared_ptr<expressionset> expressionset_()
420  {
421  eat_('<');
422  auto context = context_();
423  eat_('>');
424  auto ids = rat::identities{};
425  if (peek_() == '(')
426  {
427  eat_('(');
428  is_ >> ids;
429  eat_(')');
430  }
431  return std::make_shared<expressionset>(context, ids);
432  }
433 
435  std::shared_ptr<expressionset> seriesset_()
436  {
437  eat_('<');
438  auto context = context_();
439  eat_('>');
440  return std::make_shared<expressionset>(context,
442  }
443 
445  std::shared_ptr<expansionset> expansionset_()
446  {
447  eat_('<');
448  eat_("expressionset");
449  auto res = std::make_shared<expansionset>(expressionset_());
450  eat_('>');
451  return res;
452  }
453 
455  std::shared_ptr<polynomialset> polynomialset_()
456  {
457  eat_('<');
458  auto res = std::make_shared<polynomialset>(context_());
459  eat_('>');
460  return res;
461  }
462 
464  std::shared_ptr<ast_node> labelset_or_weightset_()
465  {
466  return labelset_or_weightset_(word_());
467  }
468 
470  std::shared_ptr<ast_node> labelset_or_weightset_(const std::string& w)
471  {
472  if (w == "lat")
473  return tupleset_();
474  else if (w == "expressionset")
475  return expressionset_();
476  else if (w == "seriesset")
477  return seriesset_();
478  else if (has(labelsets_, w))
479  return labelset_(w);
480  else if (has(weightsets_, w))
481  return weightset_(w);
482  else
483  raise("invalid weightset or labelset name: " + w);
484  }
485 
487  std::istringstream& is_;
488 
490  std::set<std::string> weightsets_ =
491  {
492  "b",
493  "f2",
494  "log",
495  "nmin",
496  "q",
497  "qmp",
498  "r",
499  "rmin",
500  "z",
501  "zmin",
502  };
503 
505  std::set<std::string> labelsets_ =
506  {
507  "lal",
508  "lal_char",
509  "lan",
510  "lan_char",
511  "lao",
512  "law",
513  "law_char",
514  "letterset",
515  "nullableset",
516  "wordset",
517  };
518  };
519 
520  std::shared_ptr<ast_node> parse_context(const std::string& ctx)
521  {
522  std::istringstream is{ctx};
523  auto parser = ast::context_parser{is};
524  try
525  {
526  return parser.parse_context();
527  }
528  catch (const std::runtime_error& e)
529  {
530  raise(e, " while reading context: ", ctx);
531  }
532  }
533 
534  std::shared_ptr<ast_node> parse_type(const std::string& type)
535  {
536  std::istringstream is{type};
537  auto parser = ast::context_parser{is};
538  try
539  {
540  return parser.parse();
541  }
542  catch (const std::runtime_error& e)
543  {
544  raise(e, " while reading type: ", type);
545  }
546  }
547  }
548 }
auto prefix(const Aut &aut) -> decltype(::vcsn::copy(aut))
Definition: prefix.hh:69
char eat(std::istream &is, char c)
Check lookahead character and advance.
Definition: stream.cc:90
return res
Definition: multiply.hh:398
std::shared_ptr< ast_node > parse()
Accept anything.
static identities ids(const driver &d)
Get the identities of the driver.
Definition: parse.cc:89
std::shared_ptr< ast_node > labelset_()
.
Parser of snames.
std::shared_ptr< expressionset > expressionset_()
"expressionset" "\<" "\>", possibly followed by identities.
Linear plus distribution. Used for series identities.
Definition: identities.hh:42
std::vector< std::shared_ptr< ast_node >> value_t
Definition: type-ast.hh:61
const std::string & eat_(const std::string &s)
Accept this string, possibly preceded by spaces.
int peek_()
The next character, possibly preceded by spaces.
std::istringstream & is_
The stream we are parsing.
std::shared_ptr< const genset > genset_()
An optional generator set in brackets (e.g., or ).
void require(Bool b, Args &&...args)
If b is not verified, raise an error with args as message.
Definition: raise.hh:91
std::shared_ptr< ast_node > any_()
Accept anything.
std::set< std::string > labelsets_
The set of weightset names.
std::shared_ptr< expansionset > expansionset_()
"expansionset" "\<" "\>".
std::set< std::string > weightsets_
The set of terminal weightset names.
std::shared_ptr< automaton > automaton_(std::string prefix)
"\<" "\>".
std::shared_ptr< ast_node > labelset_or_weightset_(const std::string &w)
|
std::shared_ptr< const genset > genset_(std::string letter_type)
A generator set (e.g., char_letters(abc) or char).
std::string type(const automaton &a)
The implementation type of a.
Definition: others.cc:239
std::vector< std::shared_ptr< ast_node >> value_t
Definition: type-ast.hh:88
Definition: a-star.hh:8
std::string word_()
The next word in the stream.
std::shared_ptr< ast_node > labelset_or_weightset_()
|
std::shared_ptr< ast_node > parse_context(const std::string &ctx)
Parse a context, and return its AST.
std::shared_ptr< ast_node > parse_type(const std::string &type)
Parse a type, and return its AST.
void skip_space(std::istream &is)
Ignore spaces.
Definition: stream.cc:163
std::shared_ptr< ast_node > weightset_(const std::string &ws)
.
context_parser(std::istringstream &is)
std::shared_ptr< ast_node > labelset_(const std::string &ls)
.
std::shared_ptr< context > context_(std::string w)
, .
std::shared_ptr< tupleset > tupleset_()
"\<" ( | ",")+ "\>".
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< expressionset > seriesset_()
No optional argument.
An expressionset can implement several different sets of identities on expressions.
Definition: identities.hh:21
ATTRIBUTE_NORETURN void fail_reading(std::istream &is, Args &&...args)
Throw an exception after failing to read from is.
Definition: stream.hh:68
void check_eof_(std::shared_ptr< ast_node > res)
We managed to read res in is, check that is_ is finished.
Indentation relative functions.
std::shared_ptr< context > context_()
, .
char eat_(char c)
Accept this character, possibly preceded by spaces.
std::shared_ptr< polynomialset > polynomialset_()
"polynomialset" "\<" "\>".
std::shared_ptr< automaton > automaton_()
"\<" "\>".
std::shared_ptr< tuple > tuple_()
"\<" ( ",")* "\>".
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
std::string parameters_()
The next parameters in the stream.
std::shared_ptr< ast_node > weightset_()
.
std::shared_ptr< ast_node > parse_context()
Accept only a valid context.