Parse semver 2.0.0-compatible string to Version_data structure. Version text parser is implemented as a state machine. In each step one successive character from version string is consumed and is either added to current token or triggers state transition. Hooks can be injected into state transitions for validation/customization purposes. */
| 139 | injected into state transitions for validation/customization purposes. |
| 140 | */ |
| 141 | Version_data Semver200_parser::parse(const string& s) const { |
| 142 | string major; |
| 143 | string minor; |
| 144 | string patch; |
| 145 | string prerelease_id; |
| 146 | string build_id; |
| 147 | Prerelease_identifiers prerelease; |
| 148 | Build_identifiers build; |
| 149 | Parser_state cstate{ Parser_state::major }; |
| 150 | Parser_state pstate; |
| 151 | |
| 152 | auto prerelease_hook = [&](string& id) { |
| 153 | prerelease_hook_impl(id, prerelease); |
| 154 | }; |
| 155 | |
| 156 | auto build_hook = [&](string& id) { |
| 157 | build_hook_impl(id, pstate, build, prerelease_id, prerelease); |
| 158 | }; |
| 159 | |
| 160 | // State transition tables |
| 161 | auto major_trans = { |
| 162 | mkx('.', Parser_state::minor, {}) |
| 163 | }; |
| 164 | auto minor_trans = { |
| 165 | mkx('.', Parser_state::patch, {}) |
| 166 | }; |
| 167 | auto patch_trans = { |
| 168 | mkx('-', Parser_state::prerelease, {}), |
| 169 | mkx('+', Parser_state::build, {}) |
| 170 | }; |
| 171 | auto prerelease_trans = { |
| 172 | // When identifier separator (.) is found, stay in the same state but invoke hook |
| 173 | // in order to process each individual identifier separately. |
| 174 | mkx('.', Parser_state::prerelease, prerelease_hook), |
| 175 | mkx('+', Parser_state::build, {}) |
| 176 | }; |
| 177 | auto build_trans = { |
| 178 | // Same stay-in-the-same-state-but-invoke-hook trick from above. |
| 179 | mkx('.', Parser_state::build, build_hook) |
| 180 | }; |
| 181 | |
| 182 | State_machine state_machine = { |
| 183 | {Parser_state::major, State{major_trans, major, normal_version_validator}}, |
| 184 | {Parser_state::minor, State{minor_trans, minor, normal_version_validator}}, |
| 185 | {Parser_state::patch, State{patch_trans, patch, normal_version_validator}}, |
| 186 | {Parser_state::prerelease, State{prerelease_trans, prerelease_id, prerelease_version_validator}}, |
| 187 | {Parser_state::build, State{build_trans, build_id, prerelease_version_validator}} |
| 188 | }; |
| 189 | |
| 190 | // Main loop. |
| 191 | for (const auto& c : s) { |
| 192 | auto state = state_machine.at(cstate); |
| 193 | process_char(c, cstate, pstate, get<0>(state), get<1>(state), get<2>(state)); |
| 194 | } |
| 195 | |
| 196 | // Trigger appropriate hooks in order to process last token, because no state transition was |
| 197 | // triggered for it. |
| 198 | if (cstate == Parser_state::prerelease) { |
nothing calls this directly
no test coverage detected