mirror of
https://github.com/Laupetin/OpenAssetTools.git
synced 2025-04-20 16:15:43 +00:00
119 lines
4.1 KiB
C++
119 lines
4.1 KiB
C++
#include "SequenceReorder.h"
|
|
|
|
#include "Parsing/Commands/Matcher/CommandsCommonMatchers.h"
|
|
#include "Parsing/Commands/Matcher/CommandsMatcherFactory.h"
|
|
|
|
#include <list>
|
|
|
|
namespace
|
|
{
|
|
static constexpr auto TAG_FIND_FIRST = 1;
|
|
|
|
static constexpr auto CAPTURE_START = 1;
|
|
static constexpr auto CAPTURE_TYPE = 2;
|
|
static constexpr auto CAPTURE_ENTRY = 3;
|
|
|
|
StructureInformation* GetType(CommandsParserState* state, SequenceResult<CommandsParserValue>& result)
|
|
{
|
|
if (result.HasNextCapture(CAPTURE_TYPE))
|
|
{
|
|
const auto& typeNameToken = result.NextCapture(CAPTURE_TYPE);
|
|
StructureInformation* information;
|
|
std::vector<MemberInformation*> memberChain;
|
|
|
|
if (!state->GetTypenameAndMembersFromTypename(typeNameToken.TypeNameValue(), information, memberChain))
|
|
throw ParsingException(typeNameToken.GetPos(), "Unknown type");
|
|
|
|
if (memberChain.empty())
|
|
return information;
|
|
|
|
auto* lastMember = memberChain.back();
|
|
|
|
if (lastMember->m_type == nullptr)
|
|
throw ParsingException(typeNameToken.GetPos(), "Member type must either be struct or union");
|
|
|
|
return lastMember->m_type;
|
|
}
|
|
|
|
if (state->GetInUse() != nullptr)
|
|
return state->GetInUse();
|
|
|
|
throw ParsingException(result.NextCapture(CAPTURE_START).GetPos(), "No type is used. Therefore one needs to be specified directly.");
|
|
}
|
|
} // namespace
|
|
|
|
SequenceReorder::SequenceReorder()
|
|
{
|
|
const CommandsMatcherFactory create(this);
|
|
|
|
AddLabeledMatchers(CommandsCommonMatchers::Typename(this), CommandsCommonMatchers::LABEL_TYPENAME);
|
|
AddMatchers({
|
|
create.Keyword("reorder").Capture(CAPTURE_START),
|
|
create.Optional(create.Label(CommandsCommonMatchers::LABEL_TYPENAME).Capture(CAPTURE_TYPE)),
|
|
create.Char(':'),
|
|
create.Optional(create
|
|
.And({
|
|
create.Char('.'),
|
|
create.Char('.'),
|
|
create.Char('.'),
|
|
})
|
|
.Tag(TAG_FIND_FIRST)),
|
|
create.Loop(create.Identifier().Capture(CAPTURE_ENTRY)),
|
|
create.Char(';'),
|
|
});
|
|
}
|
|
|
|
void SequenceReorder::ProcessMatch(CommandsParserState* state, SequenceResult<CommandsParserValue>& result) const
|
|
{
|
|
auto* information = GetType(state, result);
|
|
auto findFirst = result.PeekAndRemoveIfTag(TAG_FIND_FIRST) == TAG_FIND_FIRST;
|
|
|
|
std::string firstVariableName;
|
|
if (findFirst)
|
|
firstVariableName = result.NextCapture(CAPTURE_ENTRY).IdentifierValue();
|
|
|
|
std::vector<std::unique_ptr<MemberInformation>> newMembers;
|
|
std::list<std::unique_ptr<MemberInformation>> oldMembers;
|
|
|
|
for (auto& oldMember : information->m_ordered_members)
|
|
oldMembers.emplace_back(std::move(oldMember));
|
|
|
|
while (result.HasNextCapture(CAPTURE_ENTRY))
|
|
{
|
|
const auto& entryToken = result.NextCapture(CAPTURE_ENTRY);
|
|
const auto& nextVariableName = entryToken.IdentifierValue();
|
|
auto foundEntry = false;
|
|
|
|
for (auto i = oldMembers.begin(); i != oldMembers.end(); ++i)
|
|
{
|
|
if (i->get()->m_member->m_name == nextVariableName)
|
|
{
|
|
newMembers.emplace_back(std::move(*i));
|
|
oldMembers.erase(i);
|
|
foundEntry = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!foundEntry)
|
|
throw ParsingException(entryToken.GetPos(), "Could not find member with specified name");
|
|
}
|
|
|
|
information->m_ordered_members.clear();
|
|
|
|
while (findFirst && !oldMembers.empty())
|
|
{
|
|
if (oldMembers.front()->m_member->m_name == firstVariableName)
|
|
findFirst = false;
|
|
|
|
information->m_ordered_members.push_back(std::move(oldMembers.front()));
|
|
oldMembers.pop_front();
|
|
}
|
|
|
|
for (auto& newMember : newMembers)
|
|
information->m_ordered_members.push_back(std::move(newMember));
|
|
|
|
for (auto& oldMember : oldMembers)
|
|
information->m_ordered_members.emplace_back(std::move(oldMember));
|
|
}
|