tudocomp
– The TU Dortmund Compression Framework
AlgorithmStringParser.hpp
Go to the documentation of this file.
1 #pragma once
2 
7 
8 #include <unordered_map>
9 
10 #include <tudocomp/OptionValue.hpp>
11 
12 namespace tdc {
14  namespace eval {
15  using AlgorithmTypes = std::unordered_map<
16  std::string, std::vector<decl::Algorithm>>;
17 
18  inline void check_string_not_string(ast::Value& v) {
19  if (v.is_invokation()) {
20  std::stringstream ss;
21  ss << "option parser: ";
22  ss << "trying to evaluate " << v << " as a string";
23  throw std::runtime_error(ss.str());
24  }
25  }
26 
27  inline void check_static_override_fits_to_be_evaled_algo(
28  ast::Value& fixed_static_args, ast::Value& v)
29  {
30  // TODO: Nice error
31  // Check that the static "overrides" fit the
32  // to-be-evaluated algorithm
33  CHECK(fixed_static_args.is_invokation());
34  CHECK_EQ(fixed_static_args.invokation_name(), v.invokation_name());
35  }
36 
37  inline void check_arg_has_value(decl::Arg& arg, ast::Value& arg_value) {
38  if (arg_value.is_empty()) {
39  std::stringstream ss;
40  ss << "option parser: ";
41  ss << "argument '" << arg.name() << "' of type '"
42  << arg.type()
43  << "' has not been assigned a value";
44  throw std::runtime_error(ss.str());
45  }
46  if (arg_value.is_invokation()) {
47  if (std::any_of(arg_value.invokation_arguments().begin(),
48  arg_value.invokation_arguments().end(),
49  [](ast::Arg& arg) -> bool {
50  return arg.has_type(); }))
51  {
52  std::stringstream ss;
53  ss << "option parser: ";
54  ss << "argument '" << arg.name() << "' of type '"
55  << arg.type()
56  << "' has has types in its expression form: " << arg_value;
57  throw std::runtime_error(ss.str());
58  }
59  }
60  }
61 
62  inline void check_algorithm_known(decl::Algorithm* found,
63  ast::Value& v,
64  std::vector<decl::Algorithm> candidates) {
65  if (found == nullptr) {
66  std::stringstream ss;
67 
68  ss << "option parser: ";
69  ss << "algorithm '" << v.invokation_name() << "'";
70  ss << " is not known to the evaluation engine. Currently known algorithms: [";
71  for (auto& x : candidates) {
72  ss << x.name() << ", ";
73  }
74  ss << "]";
75 
76  throw std::runtime_error(ss.str());
77  }
78  }
79 
80  inline void check_argument_defined(const View& arg, const decl::Algorithm& algo) {
81  for (auto& signature_arg : algo.arguments()) {
82  if(arg == signature_arg.name()) return; // found
83  }
84 
85  // not found
86  std::stringstream ss;
87 
88  ss << "option parser: ";
89  ss << "unknown option '" << arg << "' for ";
90  ss << "algorithm '" << algo.name() << "'.";
91  throw std::runtime_error(ss.str());
92  }
93 
94  inline OptionValue eval(ast::Value&& v,
95  View type,
96  AlgorithmTypes& types,
97  bool pattern,
98  ast::Value&& fixed_static_args = ast::Value())
99  {
100  // Check for build-in types
101  if (type == "string") {
102  check_string_not_string(v);
103  return OptionValue(std::move(v.string_value()));
104  }
105 
106  bool has_fixed_static_args = !fixed_static_args.is_empty();
107 
108  if (has_fixed_static_args) {
109  check_static_override_fits_to_be_evaled_algo(fixed_static_args, v);
110  auto& a = fixed_static_args.invokation_arguments();
111  std::reverse(a.begin(), a.end());
112  }
113 
114  // Find the exact signature of the algorithm
115  // TODO: Nice error
116  CHECK(types.count(type) > 0);
117  // TODO: Nice error
118  CHECK(v.is_invokation());
119  auto& candidates = types[type];
120  decl::Algorithm* found = nullptr;
121  for (auto& candidate : candidates) {
122  if (candidate.name() == v.invokation_name()) {
123  found = &candidate;
124  }
125  }
126  check_algorithm_known(found, v, candidates);
127 
128  // Signature found, evaluate by walking v and signature
129  auto& v_signature = *found;
130 
131  // Prepare return value
132  ds::InputRestrictionsAndFlags r_ds_flags = v_signature.textds_flags();
133  std::string r_name = v_signature.name();
134  std::vector<pattern::Arg> r_static_args;
135  AlgorithmValue::ArgumentMap r_dynamic_args;
136 
137  // Step 1: Find argument name of each option in the invokation's
138  // signature
139 
140  std::vector<View> v_argument_names;
141  {
142  // no positional allowed after the first keyword arg
143  bool positional_ok = true;
144  size_t i = 0;
145  for (auto& unevaluated_arg : v.invokation_arguments()) {
146  // Sanity check, should be caught from outer recursive call
147  DCHECK(!unevaluated_arg.has_type());
148 
149  // find argument name for each position in the
150  // unevaluated argument list
151  View argument_name("");
152  if (!unevaluated_arg.has_keyword()) {
153  // postional arg
154  // TODO: Nice error
155  CHECK(positional_ok);
156  // assume argument name from current position
157 
158  // TODO: Nice error
159  argument_name = v_signature.arguments().at(i).name();
160  i++;
161  } else {
162  // keyword arg
163  positional_ok = false;
164  // assume argument name from keyword
165 
166  argument_name = unevaluated_arg.keyword();
167  }
168 
169  check_argument_defined(argument_name, v_signature);
170  v_argument_names.push_back(argument_name);
171  }
172  }
173 
174  // Step 2: Walk signature's arguments and produce evaluated
175  // data for each one
176 
177  for (auto& signature_arg : v_signature.arguments()) {
178  if (pattern && !signature_arg.is_static()) {
179  // If we are evaluateing patterns, ignore dynamic arguments
180  continue;
181  }
182 
183  int found = -1;
184  for (size_t i = 0; i < v_argument_names.size(); i++) {
185  if (v_argument_names[i] == signature_arg.name()) {
186  found = i;
187  }
188  }
189 
190  // logic here: if override by static,
191  // try to use static
192  // error on non-default given that mismatches
193  // important!
194  // merge, not use either-or!
195 
196  ast::Value arg_value;
197  ast::Value arg_fixed_static_value;
198 
199  if (found != -1) {
200  // use
201  arg_value = v.invokation_arguments()[found].value();
202  } else if (signature_arg.has_default()) {
203  arg_value = signature_arg.default_value();
204  }
205 
206  // after value has been selected, override parts if static;
207 
208  if (has_fixed_static_args) {
209  if (signature_arg.is_static()) {
210  // TODO: Nice error
211  CHECK(fixed_static_args
212  .invokation_arguments()
213  .size() > 0);
214  {
215  auto& current_fixed_static = fixed_static_args
216  .invokation_arguments().back();
217 
218  // TODO: Nice error
219  CHECK(current_fixed_static.keyword()
220  == signature_arg.name());
221 
222  arg_fixed_static_value = current_fixed_static.value();
223 
224  if (found == -1) {
225  arg_value = std::move(current_fixed_static.value());
226  }
227  }
228 
229  fixed_static_args
230  .invokation_arguments()
231  .pop_back();
232  }
233  }
234 
235  check_arg_has_value(signature_arg, arg_value);
236 
237  // Recursivly evaluate the argument
238  OptionValue arg_evaluated
239  = eval(std::move(arg_value),
240  signature_arg.type(),
241  types,
242  pattern,
243  std::move(arg_fixed_static_value));
244 
245  if (signature_arg.is_static()
246  && arg_evaluated.as_algorithm().static_selection().name() != "")
247  {
248  r_static_args.push_back(
249  pattern::Arg(
250  std::string(signature_arg.name()),
251  pattern::Algorithm(arg_evaluated.as_algorithm().static_selection())));
252  }
253 
254  r_dynamic_args[signature_arg.name()]
255  = std::move(arg_evaluated);
256 
257  }
258 
259  // Step 2.5: Check that all fixed static args have been used
260 
261  if (has_fixed_static_args) {
262  CHECK(fixed_static_args.invokation_arguments().size() == 0);
263  }
264 
265  // Step 3: Return
266  auto tmp = std::make_unique<pattern::Algorithm>(
267  std::string(r_name),
268  std::move(r_static_args));
269 
270  auto fr = OptionValue(AlgorithmValue(
271  std::move(r_name),
272  std::move(r_dynamic_args),
273  std::move(tmp),
274  r_ds_flags));
275 
276  return fr;
277  }
278 
279  inline OptionValue cl_eval(ast::Value&& v,
280  View type,
281  AlgorithmTypes& types,
282  ast::Value&& fixed_static_args = ast::Value()) {
283  return eval(std::move(v),
284  type,
285  types,
286  false,
287  std::move(fixed_static_args));
288  }
289  inline pattern::Algorithm pattern_eval(ast::Value&& v,
290  View type,
291  AlgorithmTypes& types) {
292  return std::move(eval(std::move(v),
293  type,
294  types,
295  true).as_algorithm().static_selection());
296  }
297  }
299 }
300 
Contains the text compression and encoding framework.
Definition: namespaces.hpp:11
std::map< std::string, OptionValue > ArgumentMap
Definition: OptionValue.hpp:37
ByteView View
Definition: View.hpp:25