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