blob: 139bb5c478d87994bcb71f87539e917118b2f0d7 [file] [log] [blame]
Václav Kubernát0a2a2e82018-05-11 13:59:12 +02001/*
2 * Copyright (C) 2018 CESNET, https://photonics.cesnet.cz/
3 * Copyright (C) 2018 FIT CVUT, https://fit.cvut.cz/
4 *
5 * Written by Václav Kubernát <kubervac@fit.cvut.cz>
6 *
7*/
8
9#pragma once
10#include "CTree.hpp"
11
12class InvalidKeyException : public std::invalid_argument {
13public:
14 using std::invalid_argument::invalid_argument;
15 ~InvalidKeyException() override;
16};
17
18struct ParserContext {
19 ParserContext(const CTree& tree);
20 const CTree& m_tree;
21 std::string m_curPath;
22 std::string m_errorMsg;
23 std::string m_tmpListName;
24 std::set<std::string> m_tmpListKeys;
25 bool m_errorHandled = false;
26};
27
28struct keyValue_class {
29 template <typename T, typename Iterator, typename Context>
30 void on_success(Iterator const&, Iterator const&, T& ast, Context const& context)
31 {
32 auto& parserContext = x3::get<parser_context_tag>(context);
33 const CTree& tree = parserContext.m_tree;
34
35 if (parserContext.m_tmpListKeys.find(ast.first) != parserContext.m_tmpListKeys.end()) {
36 _pass(context) = false;
37 parserContext.m_errorMsg = "Key \"" + ast.first + "\" was entered more than once.";
38 } else if (tree.listHasKey(parserContext.m_curPath, parserContext.m_tmpListName, ast.first)) {
39 parserContext.m_tmpListKeys.insert(ast.first);
40 } else {
41 _pass(context) = false;
42 parserContext.m_errorMsg = parserContext.m_tmpListName + " is not indexed by \"" + ast.first + "\".";
43 }
44 }
45};
46struct identifier_class;
47
48struct listPrefix_class {
49 template <typename T, typename Iterator, typename Context>
50 void on_success(Iterator const&, Iterator const&, T& ast, Context const& context)
51 {
52 auto& parserContext = x3::get<parser_context_tag>(context);
53 const CTree& tree = parserContext.m_tree;
54
55 if (tree.isList(parserContext.m_curPath, ast)) {
56 parserContext.m_tmpListName = ast;
57 } else {
58 _pass(context) = false;
59 }
60 }
61};
62
63struct listSuffix_class {
64 template <typename T, typename Iterator, typename Context>
65 void on_success(Iterator const&, Iterator const&, T& ast, Context const& context)
66 {
67 auto& parserContext = x3::get<parser_context_tag>(context);
68 const CTree& tree = parserContext.m_tree;
69
70 const auto& keysNeeded = tree.listKeys(parserContext.m_curPath, parserContext.m_tmpListName);
71 std::set<std::string> keysSupplied;
72 for (const auto& it : ast)
73 keysSupplied.insert(it.first);
74
75 if (keysNeeded != keysSupplied) {
76 parserContext.m_errorMsg = "Not enough keys for " + parserContext.m_tmpListName + ". " +
77 "These keys were not supplied:";
78 std::set<std::string> missingKeys;
79 std::set_difference(keysNeeded.begin(), keysNeeded.end(),
80 keysSupplied.begin(), keysSupplied.end(),
81 std::inserter(missingKeys, missingKeys.end()));
82
83 for (const auto& it : missingKeys)
84 parserContext.m_errorMsg += " " + it;
85 parserContext.m_errorMsg += ".";
86
87 _pass(context) = false;
88 }
89 }
90};
91struct listElement_class {
92 template <typename T, typename Iterator, typename Context>
93 void on_success(Iterator const&, Iterator const&, T& ast, Context const& context)
94 {
95 auto& parserContext = x3::get<parser_context_tag>(context);
Václav Kubernát0b76a042018-05-16 20:16:47 +020096 parserContext.m_curPath = joinPaths(parserContext.m_curPath, ast.m_name);
Václav Kubernát0a2a2e82018-05-11 13:59:12 +020097 }
98
99 template <typename Iterator, typename Exception, typename Context>
100 x3::error_handler_result on_error(Iterator&, Iterator const&, Exception const& ex, Context const& context)
101 {
102 auto& parserContext = x3::get<parser_context_tag>(context);
103 auto& error_handler = x3::get<x3::error_handler_tag>(context).get();
104 if (parserContext.m_errorHandled) // someone already handled our error
105 return x3::error_handler_result::fail;
106
107 parserContext.m_errorHandled = true;
108
109 std::string message = parserContext.m_errorMsg;
110 error_handler(ex.where(), message);
111 return x3::error_handler_result::fail;
112 }
113};
114
115struct container_class {
116 template <typename T, typename Iterator, typename Context>
117 void on_success(Iterator const&, Iterator const&, T& ast, Context const& context)
118 {
119 auto& parserContext = x3::get<parser_context_tag>(context);
120 const auto& tree = parserContext.m_tree;
121
122 if (tree.isContainer(parserContext.m_curPath, ast.m_name)) {
123 parserContext.m_curPath = joinPaths(parserContext.m_curPath, ast.m_name);
124 } else {
125 _pass(context) = false;
126 }
127 }
128};
129
130struct path_class {
131 template <typename T, typename Iterator, typename Context>
132 void on_success(Iterator const&, Iterator const&, T&, Context const&)
133 {
134 }
135};
136
137struct cd_class {
138 template <typename T, typename Iterator, typename Context>
139 void on_success(Iterator const&, Iterator const&, T&, Context const&)
140 {
141 }
142
143 template <typename Iterator, typename Exception, typename Context>
144 x3::error_handler_result on_error(Iterator&, Iterator const&, Exception const& x, Context const& context)
145 {
146 auto& parserContext = x3::get<parser_context_tag>(context);
147 auto& error_handler = x3::get<x3::error_handler_tag>(context).get();
148 std::string message = "This isn't a list or a container or nothing.";
149 if (parserContext.m_errorHandled) // someone already handled our error
150 return x3::error_handler_result::fail;
151
152 parserContext.m_errorHandled = true;
153 error_handler(x.where(), message);
154 return x3::error_handler_result::fail;
155 }
156};