mirror of
https://github.com/Laupetin/OpenAssetTools.git
synced 2025-06-21 12:17:53 -05:00
Extract commonly used Parser code to new Parser component
This commit is contained in:
93
src/Parser/Parsing/Sequence/AbstractSequence.h
Normal file
93
src/Parser/Parsing/Sequence/AbstractSequence.h
Normal file
@ -0,0 +1,93 @@
|
||||
#pragma once
|
||||
|
||||
#include <unordered_map>
|
||||
#include <cassert>
|
||||
|
||||
#include "SequenceResult.h"
|
||||
#include "Utils/ClassUtils.h"
|
||||
#include "Parsing/Matcher/AbstractMatcher.h"
|
||||
#include "Parsing/Matcher/MatcherAnd.h"
|
||||
#include "Parsing/Matcher/MatcherLabel.h"
|
||||
|
||||
template<typename TokenType, typename ParserState>
|
||||
class AbstractSequence : protected IMatcherForLabelSupplier<TokenType>
|
||||
{
|
||||
// TokenType must inherit IParserValue
|
||||
static_assert(std::is_base_of<IParserValue, TokenType>::value);
|
||||
|
||||
public:
|
||||
typedef AbstractMatcher<TokenType> matcher_t;
|
||||
|
||||
private:
|
||||
|
||||
std::unique_ptr<matcher_t> m_entry;
|
||||
std::unordered_map<int, std::unique_ptr<matcher_t>> m_matchers;
|
||||
|
||||
protected:
|
||||
static constexpr int ENTRY_LABEL = 0;
|
||||
|
||||
AbstractSequence() = default;
|
||||
|
||||
virtual void ProcessMatch(ParserState* state, SequenceResult<TokenType>& result) const = 0;
|
||||
|
||||
void AddMatchers(std::unique_ptr<matcher_t> matcher)
|
||||
{
|
||||
assert(!m_entry);
|
||||
m_entry = std::move(matcher);
|
||||
}
|
||||
|
||||
void AddMatchers(std::initializer_list<Movable<std::unique_ptr<matcher_t>>> matchers)
|
||||
{
|
||||
assert(!m_entry);
|
||||
m_entry = std::make_unique<MatcherAnd<TokenType>>(matchers);
|
||||
}
|
||||
|
||||
void AddLabeledMatchers(std::unique_ptr<matcher_t> matcher, const int label)
|
||||
{
|
||||
assert(m_matchers.find(label) == m_matchers.end());
|
||||
m_matchers.emplace(label, std::move(matcher));
|
||||
}
|
||||
|
||||
void AddLabeledMatchers(std::initializer_list<Movable<std::unique_ptr<matcher_t>>> matchers, const int label)
|
||||
{
|
||||
assert(m_matchers.find(label) == m_matchers.end());
|
||||
m_matchers.emplace(label, std::make_unique<MatcherAnd<TokenType>>(matchers));
|
||||
}
|
||||
|
||||
public:
|
||||
~AbstractSequence() override = default;
|
||||
AbstractSequence(const AbstractSequence& other) = default;
|
||||
AbstractSequence(AbstractSequence&& other) noexcept = default;
|
||||
AbstractSequence& operator=(const AbstractSequence& other) = default;
|
||||
AbstractSequence& operator=(AbstractSequence&& other) noexcept = default;
|
||||
|
||||
_NODISCARD matcher_t* GetMatcherForLabel(const int label) const override
|
||||
{
|
||||
if (label == 0)
|
||||
return m_entry.get();
|
||||
|
||||
const auto foundEntry = m_matchers.find(label);
|
||||
|
||||
if (foundEntry != m_matchers.end())
|
||||
return foundEntry->second.get();
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
_NODISCARD bool MatchSequence(ILexer<TokenType>* lexer, ParserState* state, unsigned& consumedTokenCount) const
|
||||
{
|
||||
if (!m_entry)
|
||||
return false;
|
||||
|
||||
auto result = m_entry->Match(lexer, 0);
|
||||
|
||||
if (result.m_matches)
|
||||
{
|
||||
SequenceResult<TokenType> sequenceResult(lexer, result);
|
||||
ProcessMatch(state, sequenceResult);
|
||||
consumedTokenCount = result.m_consumed_token_count;
|
||||
}
|
||||
|
||||
return result.m_matches;
|
||||
}
|
||||
};
|
100
src/Parser/Parsing/Sequence/SequenceResult.h
Normal file
100
src/Parser/Parsing/Sequence/SequenceResult.h
Normal file
@ -0,0 +1,100 @@
|
||||
#pragma once
|
||||
|
||||
#include <unordered_map>
|
||||
|
||||
#include "Utils/ClassUtils.h"
|
||||
#include "Parsing/Matcher/AbstractMatcher.h"
|
||||
#include "Parsing/Matcher/MatcherResult.h"
|
||||
#include "Parsing/ParsingException.h"
|
||||
|
||||
template <typename TokenType>
|
||||
class SequenceResult
|
||||
{
|
||||
class Capture
|
||||
{
|
||||
public:
|
||||
unsigned m_offset;
|
||||
std::vector<std::reference_wrapper<const TokenType>> m_tokens;
|
||||
|
||||
Capture()
|
||||
: m_offset(0)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
// TokenType must inherit IParserValue
|
||||
static_assert(std::is_base_of<IParserValue, TokenType>::value);
|
||||
|
||||
std::vector<int> m_tags;
|
||||
std::unordered_map<int, Capture> m_captures;
|
||||
|
||||
unsigned m_tag_offset;
|
||||
|
||||
public:
|
||||
SequenceResult(ILexer<TokenType>* lexer, const MatcherResult<TokenType>& result)
|
||||
: m_tags(result.m_tags),
|
||||
m_tag_offset(0)
|
||||
{
|
||||
for (const typename MatcherResult<TokenType>::Capture& capture : result.m_captures)
|
||||
{
|
||||
if (capture.m_token_index.IsFabricated())
|
||||
m_captures[capture.GetCaptureId()].m_tokens.push_back(result.m_fabricated_tokens[capture.m_token_index.GetTokenIndex()]);
|
||||
else
|
||||
m_captures[capture.GetCaptureId()].m_tokens.push_back(lexer->GetToken(capture.m_token_index.GetTokenIndex()));
|
||||
}
|
||||
}
|
||||
|
||||
_NODISCARD int PeekTag() const
|
||||
{
|
||||
if (m_tag_offset < m_tags.size())
|
||||
return m_tags[m_tag_offset];
|
||||
|
||||
return AbstractMatcher<TokenType>::NO_ID;
|
||||
}
|
||||
|
||||
int PeekAndRemoveIfTag(const int tag)
|
||||
{
|
||||
if (m_tag_offset < m_tags.size())
|
||||
{
|
||||
const auto result = m_tags[m_tag_offset];
|
||||
|
||||
if (result == tag)
|
||||
m_tag_offset++;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
return AbstractMatcher<TokenType>::NO_ID;
|
||||
}
|
||||
|
||||
int NextTag()
|
||||
{
|
||||
if (m_tag_offset < m_tags.size())
|
||||
return m_tags[m_tag_offset++];
|
||||
|
||||
return AbstractMatcher<TokenType>::NO_ID;
|
||||
}
|
||||
|
||||
_NODISCARD bool HasNextCapture(int captureId)
|
||||
{
|
||||
auto foundEntry = m_captures.find(captureId);
|
||||
|
||||
if (foundEntry == m_captures.end())
|
||||
return false;
|
||||
|
||||
return foundEntry->second.m_offset < foundEntry->second.m_tokens.size();
|
||||
}
|
||||
|
||||
const TokenType& NextCapture(int captureId)
|
||||
{
|
||||
auto foundEntry = m_captures.find(captureId);
|
||||
|
||||
if (foundEntry == m_captures.end())
|
||||
throw ParsingException(TokenPos(), "Tried to access next capture even though no captures exists!");
|
||||
|
||||
if(foundEntry->second.m_offset >= foundEntry->second.m_tokens.size())
|
||||
throw ParsingException(TokenPos(), "Tried to access next capture even though none exists!");
|
||||
|
||||
return foundEntry->second.m_tokens[foundEntry->second.m_offset++];
|
||||
}
|
||||
};
|
Reference in New Issue
Block a user