| 113 | } |
| 114 | |
| 115 | IRoot* ResolveReference( const std::string& reference, const std::unordered_map<std::string, IRoot*>& roots ) |
| 116 | { |
| 117 | if( reference.empty() ) |
| 118 | { |
| 119 | return nullptr; |
| 120 | } |
| 121 | |
| 122 | static const std::regex tokens( "((\\.[a-zA-Z_][a-zA-Z_0-9]*)|(\\[-?[0-9]+\\])|(\\[\"[^\"]*\"\\])).*" ); |
| 123 | static const std::regex root( "([a-zA-Z_][a-zA-Z_0-9]*).*" ); |
| 124 | |
| 125 | auto start = begin( reference ); |
| 126 | auto finish = end( reference ); |
| 127 | std::smatch match; |
| 128 | if( !std::regex_match( start, finish, match, root ) ) |
| 129 | { |
| 130 | return nullptr; |
| 131 | } |
| 132 | auto found = roots.find( match[1].str() ); |
| 133 | if( found == roots.end() ) |
| 134 | { |
| 135 | return nullptr; |
| 136 | } |
| 137 | auto object = found->second; |
| 138 | start += match[1].length(); |
| 139 | |
| 140 | while( object && start != finish ) |
| 141 | { |
| 142 | if( !std::regex_match( start, finish, match, tokens ) ) |
| 143 | { |
| 144 | return nullptr; |
| 145 | } |
| 146 | if( match[2].length() ) |
| 147 | { |
| 148 | auto attrName = match[2].str().substr( 1 ); |
| 149 | object = GetIRootAttribute( object, attrName ); |
| 150 | } |
| 151 | else if( match[3].length() ) |
| 152 | { |
| 153 | auto index = std::atoi( match[3].str().c_str() + 1 ); |
| 154 | object = GetListElement( object, ssize_t( index ) ); |
| 155 | } |
| 156 | else if( match[4].length() ) |
| 157 | { |
| 158 | auto name = match[4].str(); |
| 159 | name = name.substr( 2, name.length() - 4 ); |
| 160 | object = GetListElement( object, name ); |
| 161 | } |
| 162 | else |
| 163 | { |
| 164 | object = nullptr; |
| 165 | } |
| 166 | start += match[1].length(); |
| 167 | } |
| 168 | return object; |
| 169 | } |
| 170 | } |
| 171 | |
| 172 |
no test coverage detected