mirror of
https://github.com/Laupetin/OpenAssetTools.git
synced 2025-10-26 00:05:52 +00:00
Extract commonly used Parser code to new Parser component
This commit is contained in:
103
src/Parser/Parsing/Matcher/AbstractMatcher.h
Normal file
103
src/Parser/Parsing/Matcher/AbstractMatcher.h
Normal file
@@ -0,0 +1,103 @@
|
||||
#pragma once
|
||||
|
||||
#include <functional>
|
||||
|
||||
#include "Parsing/IParserValue.h"
|
||||
#include "Parsing/ILexer.h"
|
||||
#include "Parsing/Matcher/MatcherResult.h"
|
||||
|
||||
template <typename TokenType>
|
||||
class AbstractMatcher
|
||||
{
|
||||
// TokenType must inherit IParserValue
|
||||
static_assert(std::is_base_of<IParserValue, TokenType>::value);
|
||||
|
||||
public:
|
||||
static constexpr int NO_ID = -1;
|
||||
|
||||
typedef std::vector<std::reference_wrapper<const TokenType>> token_list_t;
|
||||
|
||||
private:
|
||||
int m_tag_id;
|
||||
int m_capture_id;
|
||||
bool m_no_consume;
|
||||
std::function<TokenType(token_list_t&)> m_transform_func;
|
||||
|
||||
protected:
|
||||
AbstractMatcher()
|
||||
: m_tag_id(NO_ID),
|
||||
m_capture_id(NO_ID),
|
||||
m_no_consume(false)
|
||||
{
|
||||
}
|
||||
|
||||
virtual MatcherResult<TokenType> CanMatch(ILexer<TokenType>* lexer, unsigned tokenOffset) = 0;
|
||||
|
||||
public:
|
||||
virtual ~AbstractMatcher() = default;
|
||||
AbstractMatcher(const AbstractMatcher& other) = default;
|
||||
AbstractMatcher(AbstractMatcher&& other) noexcept = default;
|
||||
AbstractMatcher& operator=(const AbstractMatcher& other) = default;
|
||||
AbstractMatcher& operator=(AbstractMatcher&& other) noexcept = default;
|
||||
|
||||
void SetTag(const int tagId)
|
||||
{
|
||||
m_tag_id = tagId;
|
||||
}
|
||||
|
||||
void SetCapture(const int captureId)
|
||||
{
|
||||
m_capture_id = captureId;
|
||||
}
|
||||
|
||||
void SetConsume(const bool value)
|
||||
{
|
||||
m_no_consume = !value;
|
||||
}
|
||||
|
||||
void SetTransform(std::function<TokenType(std::vector<std::reference_wrapper<const TokenType>>&)> transform)
|
||||
{
|
||||
m_transform_func = std::move(transform);
|
||||
}
|
||||
|
||||
MatcherResult<TokenType> Match(ILexer<TokenType>* lexer, const unsigned tokenOffset)
|
||||
{
|
||||
MatcherResult<TokenType> result = CanMatch(lexer, tokenOffset);
|
||||
|
||||
if (!result.m_matches)
|
||||
return result;
|
||||
|
||||
if (m_tag_id != NO_ID)
|
||||
result.m_tags.insert(result.m_tags.begin(), m_tag_id);
|
||||
|
||||
if (m_transform_func)
|
||||
{
|
||||
std::vector<std::reference_wrapper<const TokenType>> tokens;
|
||||
tokens.reserve(result.m_consumed_token_count);
|
||||
|
||||
for (auto i = 0u; i < result.m_consumed_token_count; i++)
|
||||
tokens.emplace_back(lexer->GetToken(tokenOffset + i));
|
||||
|
||||
result.m_fabricated_tokens.push_back(m_transform_func(tokens));
|
||||
|
||||
result.m_matched_tokens.clear();
|
||||
result.m_matched_tokens.emplace_back(result.m_fabricated_tokens.size() - 1, true);
|
||||
}
|
||||
else if(result.m_matched_tokens.empty())
|
||||
{
|
||||
for (auto i = 0u; i < result.m_consumed_token_count; i++)
|
||||
result.m_matched_tokens.emplace_back(tokenOffset + i, false);
|
||||
}
|
||||
|
||||
if (m_capture_id != NO_ID)
|
||||
{
|
||||
for (const auto& match : result.m_matched_tokens)
|
||||
result.m_captures.emplace_back(m_capture_id, match);
|
||||
}
|
||||
|
||||
if (m_no_consume)
|
||||
result.m_consumed_token_count = 0;
|
||||
|
||||
return result;
|
||||
}
|
||||
};
|
||||
117
src/Parser/Parsing/Matcher/AbstractMatcherFactory.h
Normal file
117
src/Parser/Parsing/Matcher/AbstractMatcherFactory.h
Normal file
@@ -0,0 +1,117 @@
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "Utils/ClassUtils.h"
|
||||
#include "AbstractMatcher.h"
|
||||
#include "MatcherAnd.h"
|
||||
#include "MatcherLabel.h"
|
||||
#include "MatcherLoop.h"
|
||||
#include "MatcherOptional.h"
|
||||
#include "MatcherOr.h"
|
||||
#include "Parsing/IParserValue.h"
|
||||
|
||||
template <typename TokenType>
|
||||
class MatcherFactoryWrapper
|
||||
{
|
||||
// TokenType must inherit IParserValue
|
||||
static_assert(std::is_base_of<IParserValue, TokenType>::value);
|
||||
|
||||
std::unique_ptr<AbstractMatcher<TokenType>> m_matcher;
|
||||
|
||||
public:
|
||||
typedef typename AbstractMatcher<TokenType>::token_list_t token_list_t;
|
||||
|
||||
explicit MatcherFactoryWrapper(std::unique_ptr<AbstractMatcher<TokenType>> matcher)
|
||||
: m_matcher(std::move(matcher))
|
||||
{
|
||||
}
|
||||
|
||||
MatcherFactoryWrapper<TokenType>& Tag(const int tagId)
|
||||
{
|
||||
m_matcher->SetTag(tagId);
|
||||
return *this;
|
||||
}
|
||||
|
||||
MatcherFactoryWrapper<TokenType>& Capture(const int captureId)
|
||||
{
|
||||
m_matcher->SetCapture(captureId);
|
||||
return *this;
|
||||
}
|
||||
|
||||
MatcherFactoryWrapper<TokenType>& NoConsume()
|
||||
{
|
||||
m_matcher->SetConsume(false);
|
||||
return *this;
|
||||
}
|
||||
|
||||
MatcherFactoryWrapper<TokenType>& Transform(std::function<TokenType(token_list_t&)> transform)
|
||||
{
|
||||
m_matcher->SetTransform(std::move(transform));
|
||||
return *this;
|
||||
}
|
||||
|
||||
std::unique_ptr<AbstractMatcher<TokenType>> Build()
|
||||
{
|
||||
return std::move(m_matcher);
|
||||
}
|
||||
|
||||
// ReSharper disable once CppNonExplicitConversionOperator
|
||||
operator std::unique_ptr<AbstractMatcher<TokenType>>()
|
||||
{
|
||||
return Build();
|
||||
}
|
||||
|
||||
// ReSharper disable once CppNonExplicitConversionOperator
|
||||
operator Movable<std::unique_ptr<AbstractMatcher<TokenType>>>()
|
||||
{
|
||||
return Build();
|
||||
}
|
||||
};
|
||||
|
||||
template <typename TokenType>
|
||||
class AbstractMatcherFactory
|
||||
{
|
||||
// TokenType must inherit IParserValue
|
||||
static_assert(std::is_base_of<IParserValue, TokenType>::value);
|
||||
|
||||
const IMatcherForLabelSupplier<TokenType>* m_label_supplier;
|
||||
|
||||
public:
|
||||
typedef typename AbstractMatcher<TokenType>::token_list_t token_list_t;
|
||||
|
||||
explicit AbstractMatcherFactory(const IMatcherForLabelSupplier<TokenType>* labelSupplier)
|
||||
: m_label_supplier(labelSupplier)
|
||||
{
|
||||
}
|
||||
|
||||
_NODISCARD MatcherFactoryWrapper<TokenType> And(std::initializer_list<Movable<std::unique_ptr<AbstractMatcher<TokenType>>>> matchers) const
|
||||
{
|
||||
return MatcherFactoryWrapper<TokenType>(std::make_unique<MatcherAnd<TokenType>>(matchers));
|
||||
}
|
||||
|
||||
_NODISCARD MatcherFactoryWrapper<TokenType> Or(std::initializer_list<Movable<std::unique_ptr<AbstractMatcher<TokenType>>>> matchers) const
|
||||
{
|
||||
return MatcherFactoryWrapper<TokenType>(std::make_unique<MatcherOr<TokenType>>(matchers));
|
||||
}
|
||||
|
||||
_NODISCARD MatcherFactoryWrapper<TokenType> Loop(std::unique_ptr<AbstractMatcher<TokenType>> matcher) const
|
||||
{
|
||||
return MatcherFactoryWrapper<TokenType>(std::make_unique<MatcherLoop<TokenType>>(std::move(matcher)));
|
||||
}
|
||||
|
||||
_NODISCARD MatcherFactoryWrapper<TokenType> OptionalLoop(std::unique_ptr<AbstractMatcher<TokenType>> matcher) const
|
||||
{
|
||||
return MatcherFactoryWrapper<TokenType>(std::make_unique<MatcherOptional<TokenType>>(std::make_unique<MatcherLoop<TokenType>>(std::move(matcher))));
|
||||
}
|
||||
|
||||
_NODISCARD MatcherFactoryWrapper<TokenType> Optional(std::unique_ptr<AbstractMatcher<TokenType>> matcher) const
|
||||
{
|
||||
return MatcherFactoryWrapper<TokenType>(std::make_unique<MatcherOptional<TokenType>>(std::move(matcher)));
|
||||
}
|
||||
|
||||
_NODISCARD MatcherFactoryWrapper<TokenType> Label(const int label) const
|
||||
{
|
||||
return MatcherFactoryWrapper<TokenType>(std::make_unique<MatcherLabel<TokenType>>(m_label_supplier, label));
|
||||
}
|
||||
};
|
||||
40
src/Parser/Parsing/Matcher/MatcherAnd.h
Normal file
40
src/Parser/Parsing/Matcher/MatcherAnd.h
Normal file
@@ -0,0 +1,40 @@
|
||||
#pragma once
|
||||
|
||||
#include <iterator>
|
||||
#include <memory>
|
||||
|
||||
#include "Parsing/IParserValue.h"
|
||||
#include "AbstractMatcher.h"
|
||||
|
||||
template <typename TokenType>
|
||||
class MatcherAnd final : public AbstractMatcher<TokenType>
|
||||
{
|
||||
// TokenType must inherit IParserValue
|
||||
static_assert(std::is_base_of<IParserValue, TokenType>::value);
|
||||
|
||||
std::vector<std::unique_ptr<AbstractMatcher<TokenType>>> m_matchers;
|
||||
|
||||
protected:
|
||||
MatcherResult<TokenType> CanMatch(ILexer<TokenType>* lexer, const unsigned tokenOffset) override
|
||||
{
|
||||
auto matchResult = MatcherResult<TokenType>::Match(0);
|
||||
|
||||
for (const std::unique_ptr<AbstractMatcher<TokenType>>& matcher : m_matchers)
|
||||
{
|
||||
MatcherResult<TokenType> result = matcher->Match(lexer, tokenOffset + matchResult.m_consumed_token_count);
|
||||
|
||||
if (!result.m_matches)
|
||||
return MatcherResult<TokenType>::NoMatch();
|
||||
|
||||
matchResult.Absorb(std::move(result));
|
||||
}
|
||||
|
||||
return matchResult;
|
||||
}
|
||||
|
||||
public:
|
||||
MatcherAnd(std::initializer_list<Movable<std::unique_ptr<AbstractMatcher<TokenType>>>> matchers)
|
||||
: m_matchers(std::make_move_iterator(matchers.begin()), std::make_move_iterator(matchers.end()))
|
||||
{
|
||||
}
|
||||
};
|
||||
50
src/Parser/Parsing/Matcher/MatcherLabel.h
Normal file
50
src/Parser/Parsing/Matcher/MatcherLabel.h
Normal file
@@ -0,0 +1,50 @@
|
||||
#pragma once
|
||||
|
||||
#include "Utils/ClassUtils.h"
|
||||
#include "Parsing/IParserValue.h"
|
||||
#include "AbstractMatcher.h"
|
||||
|
||||
template <typename TokenType>
|
||||
class IMatcherForLabelSupplier
|
||||
{
|
||||
// TokenType must inherit IParserValue
|
||||
static_assert(std::is_base_of<IParserValue, TokenType>::value);
|
||||
|
||||
public:
|
||||
IMatcherForLabelSupplier() = default;
|
||||
virtual ~IMatcherForLabelSupplier() = default;
|
||||
IMatcherForLabelSupplier(const IMatcherForLabelSupplier& other) = default;
|
||||
IMatcherForLabelSupplier(IMatcherForLabelSupplier&& other) noexcept = default;
|
||||
IMatcherForLabelSupplier& operator=(const IMatcherForLabelSupplier& other) = default;
|
||||
IMatcherForLabelSupplier& operator=(IMatcherForLabelSupplier&& other) noexcept = default;
|
||||
|
||||
_NODISCARD virtual AbstractMatcher<TokenType>* GetMatcherForLabel(int label) const = 0;
|
||||
};
|
||||
|
||||
template <typename TokenType>
|
||||
class MatcherLabel final : public AbstractMatcher<TokenType>
|
||||
{
|
||||
// TokenType must inherit IParserValue
|
||||
static_assert(std::is_base_of<IParserValue, TokenType>::value);
|
||||
|
||||
const IMatcherForLabelSupplier<TokenType>* m_supplier;
|
||||
int m_label;
|
||||
|
||||
protected:
|
||||
MatcherResult<TokenType> CanMatch(ILexer<TokenType>* lexer, unsigned tokenOffset) override
|
||||
{
|
||||
AbstractMatcher<TokenType>* matcher = m_supplier->GetMatcherForLabel(m_label);
|
||||
|
||||
if (matcher)
|
||||
return matcher->Match(lexer, tokenOffset);
|
||||
|
||||
return MatcherResult<TokenType>::NoMatch();
|
||||
}
|
||||
|
||||
public:
|
||||
MatcherLabel(const IMatcherForLabelSupplier<TokenType>* supplier, const int label)
|
||||
: m_supplier(supplier),
|
||||
m_label(label)
|
||||
{
|
||||
}
|
||||
};
|
||||
44
src/Parser/Parsing/Matcher/MatcherLoop.h
Normal file
44
src/Parser/Parsing/Matcher/MatcherLoop.h
Normal file
@@ -0,0 +1,44 @@
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "Parsing/IParserValue.h"
|
||||
#include "AbstractMatcher.h"
|
||||
|
||||
template <typename TokenType>
|
||||
class MatcherLoop final : public AbstractMatcher<TokenType>
|
||||
{
|
||||
// TokenType must inherit IParserValue
|
||||
static_assert(std::is_base_of<IParserValue, TokenType>::value);
|
||||
|
||||
std::unique_ptr<AbstractMatcher<TokenType>> m_matcher;
|
||||
|
||||
protected:
|
||||
MatcherResult<TokenType> CanMatch(ILexer<TokenType>* lexer, const unsigned tokenOffset) override
|
||||
{
|
||||
auto matchResult = MatcherResult<TokenType>::Match(0);
|
||||
auto loopedAtLeastOnce = false;
|
||||
|
||||
while(true)
|
||||
{
|
||||
auto result = m_matcher->Match(lexer, tokenOffset + matchResult.m_consumed_token_count);
|
||||
|
||||
if(!result.m_matches)
|
||||
{
|
||||
if (loopedAtLeastOnce)
|
||||
return matchResult;
|
||||
|
||||
return MatcherResult<TokenType>::NoMatch();
|
||||
}
|
||||
|
||||
loopedAtLeastOnce = true;
|
||||
matchResult.Absorb(std::move(result));
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
explicit MatcherLoop(std::unique_ptr<AbstractMatcher<TokenType>> matcher)
|
||||
: m_matcher(std::move(matcher))
|
||||
{
|
||||
}
|
||||
};
|
||||
32
src/Parser/Parsing/Matcher/MatcherOptional.h
Normal file
32
src/Parser/Parsing/Matcher/MatcherOptional.h
Normal file
@@ -0,0 +1,32 @@
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "Parsing/IParserValue.h"
|
||||
#include "AbstractMatcher.h"
|
||||
|
||||
template <typename TokenType>
|
||||
class MatcherOptional final : public AbstractMatcher<TokenType>
|
||||
{
|
||||
// TokenType must inherit IParserValue
|
||||
static_assert(std::is_base_of<IParserValue, TokenType>::value);
|
||||
|
||||
std::unique_ptr<AbstractMatcher<TokenType>> m_matcher;
|
||||
|
||||
protected:
|
||||
MatcherResult<TokenType> CanMatch(ILexer<TokenType>* lexer, unsigned tokenOffset) override
|
||||
{
|
||||
auto result = m_matcher->Match(lexer, tokenOffset);
|
||||
|
||||
if (result.m_matches)
|
||||
return result;
|
||||
|
||||
return MatcherResult<TokenType>::Match(0);
|
||||
}
|
||||
|
||||
public:
|
||||
explicit MatcherOptional(std::unique_ptr<AbstractMatcher<TokenType>> matcher)
|
||||
: m_matcher(std::move(matcher))
|
||||
{
|
||||
}
|
||||
};
|
||||
38
src/Parser/Parsing/Matcher/MatcherOr.h
Normal file
38
src/Parser/Parsing/Matcher/MatcherOr.h
Normal file
@@ -0,0 +1,38 @@
|
||||
#pragma once
|
||||
|
||||
#include <iterator>
|
||||
#include <memory>
|
||||
|
||||
#include "Parsing/IParserValue.h"
|
||||
#include "AbstractMatcher.h"
|
||||
|
||||
template <typename TokenType>
|
||||
class MatcherOr final : public AbstractMatcher<TokenType>
|
||||
{
|
||||
// TokenType must inherit IParserValue
|
||||
static_assert(std::is_base_of<IParserValue, TokenType>::value);
|
||||
|
||||
std::vector<std::unique_ptr<AbstractMatcher<TokenType>>> m_matchers;
|
||||
|
||||
protected:
|
||||
MatcherResult<TokenType> CanMatch(ILexer<TokenType>* lexer, unsigned tokenOffset) override
|
||||
{
|
||||
for (const std::unique_ptr<AbstractMatcher<TokenType>>& matcher : m_matchers)
|
||||
{
|
||||
MatcherResult<TokenType> result = matcher->Match(lexer, tokenOffset);
|
||||
|
||||
if (!result.m_matches)
|
||||
continue;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
return MatcherResult<TokenType>::NoMatch();
|
||||
}
|
||||
|
||||
public:
|
||||
MatcherOr(std::initializer_list<Movable<std::unique_ptr<AbstractMatcher<TokenType>>>> matchers)
|
||||
: m_matchers(std::make_move_iterator(matchers.begin()), std::make_move_iterator(matchers.end()))
|
||||
{
|
||||
}
|
||||
};
|
||||
124
src/Parser/Parsing/Matcher/MatcherResult.h
Normal file
124
src/Parser/Parsing/Matcher/MatcherResult.h
Normal file
@@ -0,0 +1,124 @@
|
||||
#pragma once
|
||||
|
||||
#include <iterator>
|
||||
#include <vector>
|
||||
|
||||
#include "Utils/ClassUtils.h"
|
||||
#include "Parsing/IParserValue.h"
|
||||
|
||||
template <typename TokenType>
|
||||
class MatcherResult
|
||||
{
|
||||
// TokenType must inherit IParserValue
|
||||
static_assert(std::is_base_of<IParserValue, TokenType>::value);
|
||||
|
||||
public:
|
||||
class TokenIndex
|
||||
{
|
||||
static constexpr unsigned FABRICATED_FLAG_MASK = std::numeric_limits<unsigned>::max() ^ std::numeric_limits<int>::max();
|
||||
static constexpr unsigned TOKEN_INDEX_MASK = ~FABRICATED_FLAG_MASK;
|
||||
|
||||
unsigned m_token_index;
|
||||
|
||||
public:
|
||||
TokenIndex(const unsigned index, const bool isFabricated)
|
||||
{
|
||||
m_token_index = index & TOKEN_INDEX_MASK;
|
||||
if (isFabricated)
|
||||
m_token_index |= FABRICATED_FLAG_MASK;
|
||||
}
|
||||
|
||||
_NODISCARD bool IsFabricated() const
|
||||
{
|
||||
return m_token_index & FABRICATED_FLAG_MASK;
|
||||
}
|
||||
|
||||
_NODISCARD unsigned GetTokenIndex() const
|
||||
{
|
||||
return m_token_index & TOKEN_INDEX_MASK;
|
||||
}
|
||||
};
|
||||
|
||||
class Capture
|
||||
{
|
||||
public:
|
||||
int m_capture_id;
|
||||
TokenIndex m_token_index;
|
||||
|
||||
Capture(const int captureId, const unsigned tokenIndex)
|
||||
: Capture(captureId, tokenIndex, false)
|
||||
{
|
||||
}
|
||||
|
||||
Capture(const int captureId, const unsigned tokenIndex, const bool isFabricated)
|
||||
: m_capture_id(captureId),
|
||||
m_token_index(tokenIndex, isFabricated)
|
||||
{
|
||||
}
|
||||
|
||||
Capture(const int captureId, const TokenIndex index)
|
||||
: m_capture_id(captureId),
|
||||
m_token_index(index)
|
||||
{
|
||||
}
|
||||
|
||||
_NODISCARD int GetCaptureId() const
|
||||
{
|
||||
return m_capture_id;
|
||||
}
|
||||
};
|
||||
|
||||
bool m_matches;
|
||||
unsigned m_consumed_token_count;
|
||||
std::vector<int> m_tags;
|
||||
std::vector<Capture> m_captures;
|
||||
std::vector<TokenIndex> m_matched_tokens;
|
||||
std::vector<TokenType> m_fabricated_tokens;
|
||||
|
||||
private:
|
||||
MatcherResult(const bool matches, const unsigned consumedTokenCount)
|
||||
: m_matches(matches),
|
||||
m_consumed_token_count(consumedTokenCount)
|
||||
{
|
||||
}
|
||||
|
||||
public:
|
||||
static MatcherResult Match(unsigned consumedTokenCount)
|
||||
{
|
||||
return MatcherResult(true, consumedTokenCount);
|
||||
}
|
||||
|
||||
static MatcherResult NoMatch()
|
||||
{
|
||||
return MatcherResult(false, 0);
|
||||
}
|
||||
|
||||
void Absorb(MatcherResult<TokenType>&& other)
|
||||
{
|
||||
m_consumed_token_count += other.m_consumed_token_count;
|
||||
|
||||
if (!other.m_tags.empty())
|
||||
std::copy(other.m_tags.begin(), other.m_tags.end(), std::back_inserter(m_tags));
|
||||
|
||||
for (const auto& capture : other.m_captures)
|
||||
{
|
||||
if (capture.m_token_index.IsFabricated())
|
||||
m_captures.emplace_back(capture.GetCaptureId(), TokenIndex(m_fabricated_tokens.size() + capture.m_token_index.GetTokenIndex(), true));
|
||||
else
|
||||
m_captures.emplace_back(capture.GetCaptureId(), capture.m_token_index);
|
||||
}
|
||||
|
||||
for (const auto& token : other.m_matched_tokens)
|
||||
{
|
||||
if (token.IsFabricated())
|
||||
m_matched_tokens.emplace_back(m_fabricated_tokens.size() + token.GetTokenIndex(), true);
|
||||
else
|
||||
m_matched_tokens.emplace_back(token.GetTokenIndex(), false);
|
||||
}
|
||||
|
||||
for (auto& fabricated : other.m_fabricated_tokens)
|
||||
{
|
||||
m_fabricated_tokens.emplace_back(std::move(fabricated));
|
||||
}
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user