Reduce code complexity by moving to data-driven algorithms.

This commit is contained in:
Marko Zivanovic
2015-10-09 23:30:19 +02:00
parent 59d46ce4f8
commit b6ea8dcc52
2 changed files with 62 additions and 30 deletions
+16 -8
View File
@@ -35,23 +35,28 @@ namespace {
using Validator = function<void(const string&, const char)>;
using State_transition_hook = function<void(string&)>;
/// State transition is described by a character that triggers it, a cstate to transition to and
/// State transition is described by a character that triggers it, a state to transition to and
/// optional hook to be invoked on transition.
using Transition = tuple<const char, Parser_state, State_transition_hook>;
using Transitions = vector<Transition>;
using State = tuple<Transitions, string&, Validator>;
using State_machine = map<Parser_state, State>;
// Ranges of characters allowed in prerelease and build identifiers.
const vector<pair<char, char>> allowed_prerel_id_chars = {
{ '0', '9' },{ 'A','Z' },{ 'a','z' },{ '.','.' },{ '-','-' }
};
inline Transition mkx(const char c, Parser_state p, State_transition_hook pth) {
return make_tuple(c, p, pth);
}
/// Advance parser cstate machine by a single step.
/// Advance parser state machine by a single step.
/**
Perform single step of parser cstate machine: if character matches one from transition tables -
trigger transition to next cstate; otherwise, validate if current token is in legal cstate
Perform single step of parser state machine: if character matches one from transition tables -
trigger transition to next state; otherwise, validate if current token is in legal state
(throw Parse_error if not) and then add character to current token; State transition includes
preparing various vars for next cstate and invoking cstate transition hook (if specified) which is
preparing various vars for next state and invoking state transition hook (if specified) which is
where whole tokens are validated.
*/
inline void process_char(const char c, Parser_state& cstate, Parser_state& pstate,
@@ -74,9 +79,13 @@ namespace {
if (tgt.compare(0, 1, "0") == 0) throw version::Parse_error("leading 0 not allowed");
}
/// Validate prerelease and build version components.
/// Validate that prerelease and build version identifiers are comprised of allowed chars only.
inline void prerelease_version_validator(const string&, const char c) {
if ((c < '0' || c > '9') && (c < 'A' || c > 'Z') && (c < 'a' || c > 'z') && c != '.' && c != '-')
bool res = false;
for (const auto& r : allowed_prerel_id_chars) {
res |= (c >= r.first && c <= r.second);
}
if (!res)
throw version::Parse_error("invalid character encountered: " + string(1, c));
}
@@ -113,7 +122,6 @@ namespace {
id.clear();
}
}
namespace version {