module.h
Go to the documentation of this file.
1 #ifndef GARLIC_PARSING_MODULE
2 #define GARLIC_PARSING_MODULE
3 
8 #include "constraints.h"
9 #include "../module.h"
10 #include "../utility.h"
11 
12 namespace garlic::parsing {
13 
14  class ModuleParser {
15  private:
16  template<typename Key, typename Value>
17  using table = std::unordered_map<Key, Value>;
18 
19  using field_pointer = std::shared_ptr<Field>;
20  using model_pointer = std::shared_ptr<Model>;
21 
22  struct model_field {
23  text key;
24  model_pointer model;
25  bool required;
26  };
27 
28  struct field_dependent_record {
29  sequence<field_pointer> fields;
30  sequence<model_field> models;
31  sequence<text> aliases;
32  sequence<Constraint> constraints; // field constraints.
33  };
34 
35  struct deferred_field_record {
36  text field_name;
37  bool required;
38  };
39 
40  /*
41  * This object allows for external parsers to use some of the internal
42  * parsing functions.
43  */
44  struct parser_ambassador {
45  ModuleParser& parser;
46 
47  template<GARLIC_VIEW Layer, typename Callable>
48  inline void parse_constraint(const Layer& value, Callable&& cb) {
49  parser.parse_constraint(value, cb);
50  }
51 
52  field_pointer find_field(const text& name) {
53  field_pointer result = nullptr;
54  parser.find_field(name, [&result](const auto& ptr) {
55  result = ptr;
56  });
57  return result;
58  }
59 
60  void add_field_dependency(text&& name, Constraint constraint) {
61  parser.field_dependents_[name].constraints.push_back(constraint);
62  }
63  };
64 
65  table<text, field_dependent_record> field_dependents_; // field to its dependents.
66  table<model_pointer, table<text, deferred_field_record>> model_deferred_fields_;
67  Module& module_;
68 
69  template<GARLIC_VIEW Input>
70  void process_field_annotations(Field& field, Input&& layer) {
71  get_member(layer, "annotations", [&field](const auto& item) {
72  for (const auto& member : item.get_object()) {
73  field.annotations().emplace(
74  decode<text>(member.key).clone(),
75  decode<text>(member.value).clone());
76  }
77  });
78 
79  auto add_annotation = [&layer, &field](text&& name) {
80  get_member(layer, name.data(), [&field, &name](const auto& item) {
81  // since name is from stack, no need to copy its content.
82  field.annotations().emplace(std::move(name), decode<text>(item).clone());
83  });
84  };
85 
86  add_annotation("label");
87  add_annotation("description");
88  add_annotation("message");
89  }
90 
91  template<GARLIC_VIEW Layer>
92  void process_model_meta(model_pointer model, Layer&& layer) {
93  get_member(layer, "description", [&model](const auto& item) {
94  model->annotations().emplace("description", decode<text>(item).clone());
95  });
96 
97  get_member(layer, "annotations", [&model](const auto& item) {
98  std::for_each(item.begin_member(), item.end_member(), [&model](const auto& meta_member) {
99  model->annotations().emplace(
100  decode<text>(meta_member.key).clone(),
101  decode<text>(meta_member.value).clone());
102  });
103  });
104 
105  this->process_model_inheritance(model, layer);
106  }
107 
108  template<GARLIC_VIEW Layer, typename SuccessCallable, typename FailCallable>
109  void parse_field(const text& name, Layer&& layer, SuccessCallable&& ok, FailCallable&& fail) noexcept {
110  if (layer.is_string()) { // it is an alias, just process the referenced field.
111  parse_field_reference(name, layer, ok, fail);
112  return;
113  }
114 
115  auto ptr = make_field(name.clone());
116  auto complete = true;
117 
118  get_member(layer, "type", [this, &ptr, &complete](const auto& value) {
119  auto reference_name = decode<text>(value);
120  complete = this->find_field(reference_name, [&ptr](const auto& field) {
121  ptr->inherit_constraints_from(*field);
122  });
123  if (!complete)
124  field_dependents_[reference_name].fields.push_back(ptr);
125  });
126 
127  this->process_field_annotations(*ptr, layer);
128 
129  get_member(layer, "constraints", [this, &ptr](const auto& value) {
130  for (const auto& constraint_info : value.get_list()) {
131  this->parse_constraint(constraint_info, [&ptr](auto&& constraint) {
132  ptr->add_constraint(std::move(constraint));
133  });
134  }
135  });
136 
137  get_member(layer, "ignore_details", [&ptr](const auto& value){
138  ptr->set_ignore_details(value.get_bool());
139  });
140 
141  auto optional = get(layer, "optional", false);
142 
143  ok(std::move(ptr), complete, optional);
144  }
145 
146  template<GARLIC_VIEW Layer, typename SuccessCallable, typename FailCallable>
147  void parse_field_reference(const text& name, Layer&& layer, SuccessCallable&& ok, FailCallable&& fail) noexcept {
148  auto field_name = decode<text>(layer);
149  auto optional = false;
150  if (field_name.back() == '?') {
151  field_name.pop_back();
152  optional = true;
153  }
154  auto ready = this->find_field(
155  field_name, [&ok, &optional](const auto& ptr) {
156  ok(ptr, true, optional);
157  });
158  if (!ready) {
159  if (!name.empty())
160  field_dependents_[field_name].aliases.push_back(name);
161 
162  fail(field_name, optional);
163  }
164  }
165 
166  template<typename Callback>
167  bool find_field(const text& name, Callback&& cb) noexcept {
168  if (auto it = module_.find_field(name); it != module_.end_fields()) {
169  if (field_dependents_.find(name) == field_dependents_.end()) {
170  cb(it->second);
171  return true;
172  }
173  }
174  return false;
175  }
176 
177  void add_deferred_model_field(model_pointer model, text&& key, text&& field, bool required) {
178  model_deferred_fields_[model].emplace(key, deferred_field_record { .field_name = field, .required = required });
179  field_dependents_[field].models.push_back(
180  model_field {
181  .key = key,
182  .model = std::move(model),
183  .required = required
184  });
185  }
186 
187  template<GARLIC_VIEW Layer>
188  void process_model_inheritance(model_pointer model, Layer&& layer) noexcept {
189  enum class field_status : uint8_t { deferred, ready, excluded };
190  struct field_info {
191  Model::FieldDescriptor ready_field;
192  deferred_field_record deferred_field;
193  field_status status;
194  };
195  table<text, field_info> fields;
196  auto apply_inheritance = [this, &fields, &model](text&& model_name) {
197  auto it = module_.find_model(model_name);
198  if (it == module_.end_models()) {} // report parsing error here.
199  std::for_each(
200  it->second->begin_fields(), it->second->end_fields(),
201  [&fields](const auto& item) {
202  auto& info = fields[item.first];
203  if (info.status == field_status::excluded)
204  return;
205  info.status = field_status::ready;
206  info.ready_field = item.second;
207  });
208  find(model_deferred_fields_, it->second, [&fields](const auto& deferred_fields) {
209  for (const auto& item : deferred_fields.second) {
210  auto& info = fields[item.first];
211  if (info.status == field_status::excluded)
212  continue;
213  info.status = field_status::deferred;
214  info.deferred_field = item.second;
215  }
216  });
217  };
218  get_member(layer, "exclude_fields", [&fields](const auto& excludes) {
219  for (const auto& field : excludes.get_list()) {
220  fields[decode<text>(field)].status = field_status::excluded;
221  }
222  });
223  get_member(layer, "inherit", [&apply_inheritance](const auto& inherit) {
224  if (inherit.is_string()) {
225  apply_inheritance(decode<text>(inherit));
226  return;
227  }
228  for (const auto& model_name : inherit.get_list()) {
229  apply_inheritance(decode<text>(model_name));
230  }
231  });
232  for (const auto& item : fields) {
233  switch (item.second.status) {
234  case field_status::deferred:
235  add_deferred_model_field(
236  model,
237  item.first.view(),
238  item.second.deferred_field.field_name.view(),
239  item.second.deferred_field.required);
240  break;
241  case field_status::ready:
242  model->add_field(
243  item.first.clone(),
244  item.second.ready_field.field,
245  item.second.ready_field.required);
246  break;
247  default:
248  continue;
249  }
250  }
251  }
252 
253  template<GARLIC_VIEW Layer, typename Callable>
254  void parse_model(text&& name, Layer&& layer, Callable&& cb) {
255  auto model_ptr = make_model(name.clone());
256 
257  for (const auto& item : layer.get_object()) {
258  if (strncmp(item.key.get_cstr(), ".meta", 5) == 0) {
259  continue;
260  }
261  this->parse_field(text::no_text(), item.value,
262  [&model_ptr, &item](auto ptr, auto complete, auto optional) {
263  model_ptr->add_field(decode<text>(item.key).clone(), ptr, !optional);
264  },
265  [this, &model_ptr, &item](const text& name, auto optional) {
266  add_deferred_model_field(model_ptr, decode<text>(item.key), name.view(), !optional);
267  });
268  }
269 
270  get_member(layer, ".meta", [this, &model_ptr](const auto& meta) {
271  this->process_model_meta(model_ptr, meta);
272  });
273 
274  auto model_field = make_field(
275  model_ptr->name().view(),
276  {make_constraint<model_tag>(model_ptr)});
277  this->add_field(model_ptr->name().view(), model_field, true);
278  cb(std::move(model_ptr));
279  }
280 
281  template<GARLIC_VIEW Layer, typename Callable>
282  void parse_constraint(Layer&& layer, Callable&& cb) noexcept {
283  typedef Constraint (*ConstraintInitializer)(const Layer&, parser_ambassador);
284  static const table<text, ConstraintInitializer> ctors = {
285  {"regex", &parsing::parse_regex<Layer>},
286  {"range", &parsing::parse_range<Layer>},
287  {"field", &parsing::parse_field<Layer>},
288  {"any", &parsing::parse_any<Layer>},
289  {"all", &parsing::parse_all<Layer>},
290  {"list", &parsing::parse_list<Layer>},
291  {"tuple", &parsing::parse_tuple<Layer>},
292  {"map", &parsing::parse_map<Layer>},
293  {"literal", &parsing::parse_literal<Layer>},
294  };
295 
296  if (layer.is_string()) {
297  parse_field_constraint(layer, cb);
298  return;
299  }
300 
301  get_member(layer, "type",
302  [this, &layer, &cb](const auto& item) {
303  if (auto it = ctors.find(decode<text>(item)); it != ctors.end()) {
304  cb(it->second(layer, parser_ambassador{*this}));
305  }
306  });
307  }
308 
309  template<GARLIC_VIEW Layer, typename Callable>
310  void parse_field_constraint(Layer&& layer, Callable&& cb) {
311  auto reference_key = decode<text>(layer);
312  auto ready = this->find_field(reference_key,
313  [this, &cb](const auto& ptr) {
314  cb(make_constraint<field_tag>(std::make_shared<field_pointer>(ptr)));
315  });
316  if (!ready) {
317  auto constraint = make_constraint<field_tag>(std::make_shared<field_pointer>(nullptr));
318  field_dependents_[std::move(reference_key)].constraints.push_back(constraint);
319  cb(std::move(constraint));
320  }
321  }
322 
323  void resolve_field(const text& key, const field_pointer& ptr) {
324  if (auto it = field_dependents_.find(key); it != field_dependents_.end()) {
325  // apply the constraints to the fields that inherited from this field.
326  //const auto& src_constraints = ptr->properties_.constraints;
327  for (auto& field : it->second.fields) {
328  field->inherit_constraints_from(*ptr);
329  // if the field is a named one, it can be resolved as it is complete now.
330  // anonymous fields can be skipped.
331  if (!field->name().empty()) {
332  this->resolve_field(field->name(), field);
333  }
334  }
335 
336  // add the field to the depending models.
337  for (auto& member : it->second.models) {
338  member.model->add_field(member.key.clone(), ptr, member.required);
339  }
340 
341  // register all the field aliases.
342  for (auto& alias : it->second.aliases) {
343  this->add_field(alias.clone(), ptr, true);
344  }
345 
346  for(auto& constraint : it->second.constraints) {
347  constraint.context_for<field_tag>().set_field(ptr);
348  }
349 
350  // remove it from the context.
351  field_dependents_.erase(it);
352  }
353  }
354 
355  void add_field(text&& key, field_pointer ptr, bool complete) noexcept {
356  if (complete) {
357  this->resolve_field(key, ptr); // resolve all the dependencies.
358  } else {
359  field_dependents_[key]; // create a record so it would be deemed as incomplete.
360  }
361  module_.add_field(std::move(key), std::move(ptr)); // register the field.
362  }
363 
364  public:
365  ModuleParser(Module& module) : module_(module) {}
366 
367  template<GARLIC_VIEW Layer>
368  std::error_code parse(Layer&& layer) {
369  // Load the fields first.
370  get_member(layer, "fields", [this](const auto& value) {
371  for (const auto& item : value.get_object()) {
372  this->parse_field(
373  decode<text>(item.key), item.value,
374  [this, &item](auto ptr, auto complete, auto) {
375  this->add_field(decode<text>(item.key).clone(), std::move(ptr), complete);
376  },
377  [](...){});
378  }
379  });
380 
381  // Load the models.
382  get_member(layer, "models", [this](const auto& value) {
383  for(const auto& item : value.get_object()) {
384  this->parse_model(
385  decode<text>(item.key), item.value,
386  [this](auto&& ptr) { module_.add_model(std::move(ptr)); });
387  }
388  });
389 
390  return (field_dependents_.size() ? GarlicError::UndefinedObject : std::error_code());
391  }
392  };
393 
395 
402  template<GARLIC_VIEW Layer>
403  static tl::expected<Module, std::error_code>
404  load_module(Layer&& layer) noexcept {
405  if (!layer.is_object())
406  return tl::make_unexpected(GarlicError::InvalidModule);
407 
408  Module module;
409  auto parser = ModuleParser(module);
410  if (auto error = parser.parse(layer); error)
411  return tl::make_unexpected(error);
412 
413  return module;
414  }
415 
416 }
417 
418 #endif /* end of include guard: GARLIC_PARSING_MODULE */
garlic::Module
A Module is a repository of models, fields and constraints.
Definition: module.h:39
garlic::parsing::load_module
static tl::expected< Module, std::error_code > load_module(Layer &&layer) noexcept
Loads a Module from any layer.
Definition: module.h:404