27 #include "cif++/condition.hpp" 28 #include "cif++/dictionary_parser.hpp" 29 #include "cif++/file.hpp" 30 #include "cif++/parser.hpp" 42 , m_validator(validator)
48 std::unique_ptr<datablock> dict;
49 auto savedDatablock = m_datablock;
53 while (m_lookahead != CIFToken::Eof)
57 case CIFToken::GLOBAL:
63 dict.reset(
new datablock(m_token_value));
64 m_datablock = dict.get();
73 catch (
const std::exception &ex)
79 for (
auto &ic : mCategoryValidators)
80 m_validator.add_category_validator(std::move(ic));
81 mCategoryValidators.clear();
83 for (
auto &iv : mItemValidators)
85 auto cv = m_validator.get_validator_for_category(iv.first);
87 error(
"Undefined category '" + iv.first);
89 for (
auto &v : iv.second)
90 const_cast<category_validator *
>(cv)->addItemValidator(std::move(v));
99 datablock::iterator info;
101 std::tie(info, is_new) = m_datablock->emplace(
"dictionary");
102 if (not is_new and not info->empty())
104 auto r = info->front();
105 m_validator.set_name(r[
"title"].as<std::string>());
106 m_validator.version(r[
"version"].as<std::string>());
109 m_datablock = savedDatablock;
111 mItemValidators.clear();
115 void parse_save_frame()
override 117 if (not m_collected_item_types)
118 m_collected_item_types = collect_item_types();
120 std::string saveFrameName = m_token_value;
122 if (saveFrameName.empty())
123 error(
"Invalid save frame, should contain more than just 'save_' here");
125 bool isCategorySaveFrame = m_token_value[0] !=
'_';
127 datablock dict(m_token_value);
128 datablock::iterator cat = dict.end();
130 match(CIFToken::SAVE);
131 while (m_lookahead == CIFToken::LOOP
or m_lookahead == CIFToken::Tag)
133 if (m_lookahead == CIFToken::LOOP)
137 match(CIFToken::LOOP);
139 std::vector<std::string> tags;
140 while (m_lookahead == CIFToken::Tag)
142 std::string catName, item_name;
145 if (cat == dict.end())
146 std::tie(cat, std::ignore) = dict.emplace(catName);
147 else if (not
iequals(cat->name(), catName))
148 error(
"inconsistent categories in loop_");
150 tags.push_back(item_name);
151 match(CIFToken::Tag);
154 while (m_lookahead == CIFToken::Value)
157 auto row = cat->back();
159 for (
auto tag : tags)
161 row[tag] = m_token_value;
162 match(CIFToken::Value);
170 std::string catName, item_name;
173 if (cat == dict.end()
or not
iequals(cat->name(), catName))
174 std::tie(cat, std::ignore) = dict.emplace(catName);
176 match(CIFToken::Tag);
180 cat->back()[item_name] = m_token_value;
182 match(CIFToken::Value);
186 match(CIFToken::SAVE);
188 if (isCategorySaveFrame)
190 std::string category = dict[
"category"].front().get<std::string>(
"id");
192 std::vector<std::string> keys;
193 for (
auto k : dict[
"category_key"])
194 keys.push_back(std::get<1>(
split_tag_name(
k[
"name"].as<std::string>())));
197 for (
auto g : dict[
"category_group"])
198 groups.insert(
g[
"id"].as<std::string>());
200 mCategoryValidators.push_back(category_validator{ category, keys, groups });
205 std::string typeCode = dict[
"item_type"].front().get<std::string>(
"code");
207 const type_validator *tv =
nullptr;
208 if (not(typeCode.empty()
or typeCode ==
"?"))
209 tv = m_validator.get_validator_for_type(typeCode);
212 for (
auto e : dict[
"item_enumeration"])
213 ess.insert(e[
"value"].as<std::string>());
215 std::string defaultValue = dict[
"item_default"].front().get<std::string>(
"value");
216 bool defaultIsNull =
false;
217 if (defaultValue.empty())
220 for (
auto r : dict[
"_item_default"])
222 defaultIsNull = r[
"value"].is_null();
228 for (
auto i : dict[
"item"])
230 std::string tagName, category, mandatory;
231 cif::tie(tagName, category, mandatory) =
i.get(
"name",
"category_id",
"mandatory_code");
233 std::string cat_name, item_name;
236 if (cat_name.empty()
or item_name.empty())
237 error(
"Invalid tag name in _item.name " + tagName);
239 if (not
iequals(category, cat_name) and not(category.empty()
or category ==
"?"))
240 error(
"specified category id does match the implicit category name for tag '" + tagName +
'\'');
244 auto &ivs = mItemValidators[category];
246 auto vi =
find(ivs.begin(), ivs.end(), item_validator{ item_name });
248 ivs.push_back(item_validator{ item_name, iequals(mandatory,
"yes"), tv, ess, defaultValue, defaultIsNull });
252 if (vi->m_mandatory != (
iequals(mandatory,
"yes")))
256 std::cerr <<
"inconsistent mandatory value for " << tagName <<
" in dictionary" << std::endl;
258 if (
iequals(tagName, saveFrameName))
259 std::cerr <<
"choosing " << mandatory << std::endl;
261 std::cerr <<
"choosing " << (vi->m_mandatory ?
"Y" :
"N") << std::endl;
264 if (
iequals(tagName, saveFrameName))
265 vi->m_mandatory = (
iequals(mandatory,
"yes"));
268 if (vi->m_type !=
nullptr and tv !=
nullptr and vi->m_type != tv)
271 std::cerr <<
"inconsistent type for " << tagName <<
" in dictionary" << std::endl;
275 if (vi->m_type ==
nullptr)
278 vi->m_enums.insert(ess.begin(), ess.end());
286 for (
auto i : dict[
"item_linked"])
288 mLinkedItems.emplace(
i.get<std::string,std::string>(
"child_name",
"parent_name"));
296 error(
"no datablock");
298 auto &dict = *m_datablock;
302 using key_type = std::tuple<std::string, std::string, int>;
304 std::map<key_type, size_t> linkIndex;
307 std::vector<std::tuple<std::vector<std::string>, std::vector<std::string>>> linkKeys;
309 auto addLink = [&](
size_t ix,
const std::string &pk,
const std::string &ck)
311 auto &&[pkeys, ckeys] = linkKeys.at(ix);
314 for (
size_t i = 0;
i < pkeys.size(); ++
i)
316 if (pkeys[
i] == pk and ckeys[
i] == ck)
330 auto &linkedGroupList = dict[
"pdbx_item_linked_group_list"];
332 for (
auto gl : linkedGroupList)
334 std::string child, parent;
336 cif::tie(child, parent, link_group_id) = gl.get(
"child_name",
"parent_name",
"link_group_id");
338 auto civ = m_validator.get_validator_for_item(child);
340 error(
"in pdbx_item_linked_group_list, item '" + child +
"' is not specified");
342 auto piv = m_validator.get_validator_for_item(parent);
344 error(
"in pdbx_item_linked_group_list, item '" + parent +
"' is not specified");
346 key_type key{ piv->m_category->m_name, civ->m_category->m_name, link_group_id };
347 if (not linkIndex.count(key))
349 linkIndex[key] = linkKeys.size();
350 linkKeys.push_back({});
353 size_t ix = linkIndex.at(key);
354 addLink(ix, piv->m_tag, civ->m_tag);
358 if (linkedGroupList.empty())
361 for (
auto li : mLinkedItems)
363 std::string child, parent;
364 std::tie(child, parent) = li;
366 auto civ = m_validator.get_validator_for_item(child);
368 error(
"in pdbx_item_linked_group_list, item '" + child +
"' is not specified");
370 auto piv = m_validator.get_validator_for_item(parent);
372 error(
"in pdbx_item_linked_group_list, item '" + parent +
"' is not specified");
374 key_type key{ piv->m_category->m_name, civ->m_category->m_name, 0 };
375 if (not linkIndex.count(key))
377 linkIndex[key] = linkKeys.size();
378 linkKeys.push_back({});
381 size_t ix = linkIndex.at(key);
382 addLink(ix, piv->m_tag, civ->m_tag);
386 auto &linkedGroup = dict[
"pdbx_item_linked_group"];
389 for (
auto &kv : linkIndex)
391 link_validator link = {};
392 std::tie(link.m_parent_category, link.m_child_category, link.m_link_group_id) = kv.first;
394 std::tie(link.m_parent_keys, link.m_child_keys) = linkKeys[kv.second];
397 for (
auto r : linkedGroup.find(
"category_id"_key == link.m_child_category and
"link_group_id"_key == link.m_link_group_id))
399 link.m_link_group_label = r[
"label"].as<std::string>();
403 m_validator.add_link_validator(std::move(link));
408 for (
auto &cv : m_validator.m_category_validators)
410 for (
auto &iv : cv.m_item_validators)
413 std::cerr <<
"Missing item_type for " << iv.m_tag << std::endl;
418 bool collect_item_types()
423 error(
"no datablock");
425 auto &dict = *m_datablock;
427 for (
auto t : dict[
"item_type_list"])
429 std::string code, primitiveCode, construct;
430 cif::tie(code, primitiveCode, construct) = t.get(
"code",
"primitive_code",
"construct");
442 m_validator.add_type_validator(std::move(v));
444 catch (
const std::exception &)
446 std::throw_with_nested(parse_error( 0,
"error in regular expression"));
455 std::cerr <<
"Added type " << code <<
" (" << primitiveCode <<
") => " << construct << std::endl;
463 validator &m_validator;
464 bool m_collected_item_types =
false;
466 std::vector<category_validator> mCategoryValidators;
467 std::map<std::string, std::vector<item_validator>> mItemValidators;
468 std::set<std::tuple<std::string, std::string>> mLinkedItems;
475 validator result(name);
void replace_all(std::string &s, std::string_view what, std::string_view with)
std::vector< SelLine >::iterator find(std::vector< SelLine > &text, const std::string &img_name)
validator parse_dictionary(std::string_view name, std::istream &is)
DDL_PrimitiveType map_to_primitive_type(std::string_view s)
bool iequals(std::string_view a, std::string_view b)
ql0001_ & k(htemp+1),(cvec+1),(atemp+1),(bj+1),(bl+1),(bu+1),(x+1),(clamda+1), &iout, infoqp, &zero,(w+1), &lenw,(iw+1), &leniw, &glob_grd.epsmac
std::tuple< std::string, std::string > split_tag_name(std::string_view tag)
basic_istream< char, std::char_traits< char > > istream
dictionary_parser(validator &validator, std::istream &is, file &f)