jes/src-c/core/CommandMap.cc
2018-07-25 20:47:02 -04:00

143 lines
4.1 KiB
C++

#include "CommandMap.h"
#include "Command.h"
#include <cstring>
void CommandMap::add(const char * s, uint32_t id,
std::shared_ptr<CommandMap> next_map, bool following_char)
{
size_t length = strlen(s);
if (length < 1u)
return;
std::vector<uint32_t> v(length);
for (size_t i = 0u; i < length; i++)
{
v[i] = s[i];
}
add(v, id, next_map, following_char);
}
void CommandMap::add(const std::vector<uint32_t> & s, uint32_t id,
std::shared_ptr<CommandMap> next_map, bool following_char)
{
Node * node = &m_root_node;
size_t length = s.size();
if (length < 1u)
return;
for (size_t i = 0u; i < length; i++)
{
const uint32_t c = s[i];
auto it = node->next_chars.find(c);
if (it != node->next_chars.end())
{
node = &*it->second;
}
else
{
auto new_node = std::make_shared<Node>();
node->next_chars[c] = new_node;
node = &*new_node;
}
}
uint8_t flags = Node::FLAG_TERMINATOR;
if (following_char)
flags |= Node::FLAG_FOLLOWING_CHAR;
node->id = id;
node->flags = flags;
node->next_map = next_map;
}
uint8_t CommandMap::lookup_command(const uint32_t * command_characters,
size_t length, Command & command) const
{
std::list<Command::Unit> units;
uint8_t scan_result = scan_units(units, command_characters, length, &m_root_node);
if (scan_result == COMMAND_COMPLETE)
{
int i = 0;
for (const auto & unit : units)
{
switch (i)
{
case 0:
command.main = unit;
break;
case 1:
command.motion = unit;
break;
}
i++;
}
}
return scan_result;
}
uint8_t CommandMap::scan_units(
std::list<Command::Unit> & units,
const uint32_t * command_characters, size_t length,
const Node * start_node) const
{
if (length < 1u)
return COMMAND_INCOMPLETE;
uint8_t result = COMMAND_INCOMPLETE;
uint8_t recurse_result = COMMAND_INVALID;
bool gathering_count = true;
Command::Unit unit;
const Node * node = start_node;
for (size_t i = 0u; i < length; i++)
{
uint32_t c = command_characters[i];
if (gathering_count &&
((('1' <= c) && (c <= '9')) ||
((c == '0') && (unit.count != 0u))))
{
unit.count *= 10u;
unit.count += (c - '0');
}
else
{
gathering_count = false;
auto it = node->next_chars.find(c);
if (it != node->next_chars.end())
{
node = &*it->second;
if (node->flags & Node::FLAG_TERMINATOR)
{
unit.id = node->id;
if (node->flags & Node::FLAG_FOLLOWING_CHAR)
{
if (i < (length - 1u))
{
unit.following_char = command_characters[i + 1u];
units.push_front(unit);
return COMMAND_COMPLETE;
}
return COMMAND_INCOMPLETE;
}
else if (node->next_map)
{
recurse_result = scan_units(units,
&command_characters[i + 1u],
length - i - 1u, &node->next_map->m_root_node);
if (recurse_result == COMMAND_COMPLETE)
{
units.push_front(unit);
return COMMAND_COMPLETE;
}
result = recurse_result;
}
else
{
units.push_front(unit);
return COMMAND_COMPLETE;
}
}
}
else
{
return recurse_result;
}
}
}
return result;
}