1 #ifndef GARLIC_PARSING_MODULE
2 #define GARLIC_PARSING_MODULE
8 #include "constraints.h"
10 #include "../utility.h"
12 namespace garlic::parsing {
16 template<
typename Key,
typename Value>
17 using table = std::unordered_map<Key, Value>;
19 using field_pointer = std::shared_ptr<Field>;
20 using model_pointer = std::shared_ptr<Model>;
28 struct field_dependent_record {
29 sequence<field_pointer> fields;
30 sequence<model_field> models;
31 sequence<text> aliases;
32 sequence<Constraint> constraints;
35 struct deferred_field_record {
44 struct parser_ambassador {
47 template<GARLIC_VIEW Layer,
typename Callable>
48 inline void parse_constraint(
const Layer& value, Callable&& cb) {
49 parser.parse_constraint(value, cb);
52 field_pointer find_field(
const text& name) {
53 field_pointer result =
nullptr;
54 parser.find_field(name, [&result](
const auto& ptr) {
60 void add_field_dependency(text&& name, Constraint constraint) {
61 parser.field_dependents_[name].constraints.push_back(constraint);
65 table<text, field_dependent_record> field_dependents_;
66 table<model_pointer, table<text, deferred_field_record>> model_deferred_fields_;
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());
79 auto add_annotation = [&layer, &field](text&& name) {
80 get_member(layer, name.data(), [&field, &name](
const auto& item) {
82 field.annotations().emplace(std::move(name), decode<text>(item).clone());
86 add_annotation(
"label");
87 add_annotation(
"description");
88 add_annotation(
"message");
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());
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());
105 this->process_model_inheritance(model, layer);
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()) {
111 parse_field_reference(name, layer, ok, fail);
115 auto ptr = make_field(name.clone());
116 auto complete =
true;
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);
124 field_dependents_[reference_name].fields.push_back(ptr);
127 this->process_field_annotations(*ptr, layer);
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));
137 get_member(layer,
"ignore_details", [&ptr](
const auto& value){
138 ptr->set_ignore_details(value.get_bool());
141 auto optional = get(layer,
"optional",
false);
143 ok(std::move(ptr), complete, optional);
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();
154 auto ready = this->find_field(
155 field_name, [&ok, &optional](
const auto& ptr) {
156 ok(ptr,
true, optional);
160 field_dependents_[field_name].aliases.push_back(name);
162 fail(field_name, optional);
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()) {
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(
182 .model = std::move(model),
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 };
191 Model::FieldDescriptor ready_field;
192 deferred_field_record deferred_field;
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()) {}
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)
205 info.status = field_status::ready;
206 info.ready_field = item.second;
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)
213 info.status = field_status::deferred;
214 info.deferred_field = item.second;
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;
223 get_member(layer,
"inherit", [&apply_inheritance](
const auto& inherit) {
224 if (inherit.is_string()) {
225 apply_inheritance(decode<text>(inherit));
228 for (
const auto& model_name : inherit.get_list()) {
229 apply_inheritance(decode<text>(model_name));
232 for (
const auto& item : fields) {
233 switch (item.second.status) {
234 case field_status::deferred:
235 add_deferred_model_field(
238 item.second.deferred_field.field_name.view(),
239 item.second.deferred_field.required);
241 case field_status::ready:
244 item.second.ready_field.field,
245 item.second.ready_field.required);
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());
257 for (
const auto& item : layer.get_object()) {
258 if (strncmp(item.key.get_cstr(),
".meta", 5) == 0) {
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);
265 [
this, &model_ptr, &item](
const text& name,
auto optional) {
266 add_deferred_model_field(model_ptr, decode<text>(item.key), name.view(), !optional);
270 get_member(layer,
".meta", [
this, &model_ptr](
const auto& meta) {
271 this->process_model_meta(model_ptr, meta);
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));
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>},
296 if (layer.is_string()) {
297 parse_field_constraint(layer, cb);
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}));
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)));
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));
323 void resolve_field(
const text& key,
const field_pointer& ptr) {
324 if (
auto it = field_dependents_.find(key); it != field_dependents_.end()) {
327 for (
auto& field : it->second.fields) {
328 field->inherit_constraints_from(*ptr);
331 if (!field->name().empty()) {
332 this->resolve_field(field->name(), field);
337 for (
auto& member : it->second.models) {
338 member.model->add_field(member.key.clone(), ptr, member.required);
342 for (
auto& alias : it->second.aliases) {
343 this->add_field(alias.clone(), ptr,
true);
346 for(
auto& constraint : it->second.constraints) {
347 constraint.context_for<field_tag>().set_field(ptr);
351 field_dependents_.erase(it);
355 void add_field(text&& key, field_pointer ptr,
bool complete) noexcept {
357 this->resolve_field(key, ptr);
359 field_dependents_[key];
361 module_.add_field(std::move(key), std::move(ptr));
365 ModuleParser(Module& module) : module_(module) {}
367 template<GARLIC_VIEW Layer>
368 std::error_code parse(Layer&& layer) {
370 get_member(layer,
"fields", [
this](
const auto& value) {
371 for (
const auto& item : value.get_object()) {
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);
382 get_member(layer,
"models", [
this](
const auto& value) {
383 for(
const auto& item : value.get_object()) {
385 decode<text>(item.key), item.value,
386 [this](auto&& ptr) { module_.add_model(std::move(ptr)); });
390 return (field_dependents_.size() ? GarlicError::UndefinedObject : std::error_code());
402 template<GARLIC_VIEW Layer>
403 static tl::expected<Module, std::error_code>
405 if (!layer.is_object())
406 return tl::make_unexpected(GarlicError::InvalidModule);
409 auto parser = ModuleParser(module);
410 if (
auto error = parser.parse(layer); error)
411 return tl::make_unexpected(error);