mirror of
https://github.com/Laupetin/OpenAssetTools.git
synced 2025-04-19 15:52:53 +00:00
Matcher and sequence testing stuffs
This commit is contained in:
parent
0f70f9586c
commit
37232e3176
@ -1,7 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "CommandsParserValue.h"
|
#include "CommandsParserValue.h"
|
||||||
#include "Parsing/AbstractLexer.h"
|
#include "Parsing/Impl/AbstractLexer.h"
|
||||||
|
|
||||||
class CommandsLexer final : public AbstractLexer<CommandsParserValue>
|
class CommandsLexer final : public AbstractLexer<CommandsParserValue>
|
||||||
{
|
{
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
|
||||||
#include "HeaderParserValue.h"
|
#include "HeaderParserValue.h"
|
||||||
#include "Parsing/AbstractLexer.h"
|
#include "Parsing/Impl/AbstractLexer.h"
|
||||||
|
|
||||||
class HeaderLexer final : public AbstractLexer<HeaderParserValue>
|
class HeaderLexer final : public AbstractLexer<HeaderParserValue>
|
||||||
{
|
{
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
#include "HeaderLexer.h"
|
#include "HeaderLexer.h"
|
||||||
#include "HeaderParserState.h"
|
#include "HeaderParserState.h"
|
||||||
#include "Parsing/AbstractParser.h"
|
#include "Parsing/Impl/AbstractParser.h"
|
||||||
#include "Persistence/IDataRepository.h"
|
#include "Persistence/IDataRepository.h"
|
||||||
|
|
||||||
class HeaderParser final : public AbstractParser<HeaderParserValue, HeaderParserState>
|
class HeaderParser final : public AbstractParser<HeaderParserValue, HeaderParserState>
|
||||||
|
@ -5,7 +5,7 @@ HeaderMatcherCharacter::HeaderMatcherCharacter(const char c)
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
MatcherResult<HeaderParserValue> HeaderMatcherCharacter::CanMatch(AbstractLexer<HeaderParserValue>* lexer, const unsigned tokenOffset)
|
MatcherResult<HeaderParserValue> HeaderMatcherCharacter::CanMatch(ILexer<HeaderParserValue>* lexer, const unsigned tokenOffset)
|
||||||
{
|
{
|
||||||
const auto& token = lexer->GetToken(tokenOffset);
|
const auto& token = lexer->GetToken(tokenOffset);
|
||||||
return token.m_type == HeaderParserValueType::CHARACTER && token.CharacterValue() == m_char
|
return token.m_type == HeaderParserValueType::CHARACTER && token.CharacterValue() == m_char
|
||||||
|
@ -8,7 +8,7 @@ class HeaderMatcherCharacter final : public AbstractMatcher<HeaderParserValue>
|
|||||||
char m_char;
|
char m_char;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
MatcherResult<HeaderParserValue> CanMatch(AbstractLexer<HeaderParserValue>* lexer, unsigned tokenOffset) override;
|
MatcherResult<HeaderParserValue> CanMatch(ILexer<HeaderParserValue>* lexer, unsigned tokenOffset) override;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit HeaderMatcherCharacter(char c);
|
explicit HeaderMatcherCharacter(char c);
|
||||||
|
@ -13,6 +13,11 @@ MatcherFactoryWrapper<HeaderParserValue> HeaderMatcherFactory::Type(HeaderParser
|
|||||||
return MatcherFactoryWrapper<HeaderParserValue>(std::make_unique<HeaderMatcherValueType>(type));
|
return MatcherFactoryWrapper<HeaderParserValue>(std::make_unique<HeaderMatcherValueType>(type));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MatcherFactoryWrapper<HeaderParserValue> HeaderMatcherFactory::Identifier() const
|
||||||
|
{
|
||||||
|
return MatcherFactoryWrapper<HeaderParserValue>(std::make_unique<HeaderMatcherValueType>(HeaderParserValueType::IDENTIFIER));
|
||||||
|
}
|
||||||
|
|
||||||
MatcherFactoryWrapper<HeaderParserValue> HeaderMatcherFactory::Char(char c) const
|
MatcherFactoryWrapper<HeaderParserValue> HeaderMatcherFactory::Char(char c) const
|
||||||
{
|
{
|
||||||
return MatcherFactoryWrapper<HeaderParserValue>(std::make_unique<HeaderMatcherCharacter>(c));
|
return MatcherFactoryWrapper<HeaderParserValue>(std::make_unique<HeaderMatcherCharacter>(c));
|
||||||
|
@ -9,5 +9,6 @@ public:
|
|||||||
explicit HeaderMatcherFactory(const IMatcherForLabelSupplier<HeaderParserValue>* labelSupplier);
|
explicit HeaderMatcherFactory(const IMatcherForLabelSupplier<HeaderParserValue>* labelSupplier);
|
||||||
|
|
||||||
_NODISCARD MatcherFactoryWrapper<HeaderParserValue> Type(HeaderParserValueType type) const;
|
_NODISCARD MatcherFactoryWrapper<HeaderParserValue> Type(HeaderParserValueType type) const;
|
||||||
|
_NODISCARD MatcherFactoryWrapper<HeaderParserValue> Identifier() const;
|
||||||
_NODISCARD MatcherFactoryWrapper<HeaderParserValue> Char(char c) const;
|
_NODISCARD MatcherFactoryWrapper<HeaderParserValue> Char(char c) const;
|
||||||
};
|
};
|
||||||
|
@ -5,7 +5,7 @@ HeaderMatcherValueType::HeaderMatcherValueType(HeaderParserValueType type)
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
MatcherResult<HeaderParserValue> HeaderMatcherValueType::CanMatch(AbstractLexer<HeaderParserValue>* lexer, const unsigned tokenOffset)
|
MatcherResult<HeaderParserValue> HeaderMatcherValueType::CanMatch(ILexer<HeaderParserValue>* lexer, const unsigned tokenOffset)
|
||||||
{
|
{
|
||||||
return lexer->GetToken(tokenOffset).m_type == m_type
|
return lexer->GetToken(tokenOffset).m_type == m_type
|
||||||
? MatcherResult<HeaderParserValue>::Match(1)
|
? MatcherResult<HeaderParserValue>::Match(1)
|
||||||
|
@ -8,7 +8,7 @@ class HeaderMatcherValueType final : public AbstractMatcher<HeaderParserValue>
|
|||||||
HeaderParserValueType m_type;
|
HeaderParserValueType m_type;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
MatcherResult<HeaderParserValue> CanMatch(AbstractLexer<HeaderParserValue>* lexer, unsigned tokenOffset) override;
|
MatcherResult<HeaderParserValue> CanMatch(ILexer<HeaderParserValue>* lexer, unsigned tokenOffset) override;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit HeaderMatcherValueType(HeaderParserValueType type);
|
explicit HeaderMatcherValueType(HeaderParserValueType type);
|
||||||
|
@ -13,6 +13,6 @@ SequenceNamespace::SequenceNamespace()
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void SequenceNamespace::ProcessMatch(HeaderParserState* state, const SequenceResult<HeaderParserValue>& result) const
|
void SequenceNamespace::ProcessMatch(HeaderParserState* state, SequenceResult<HeaderParserValue>& result) const
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -1,15 +1,16 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "Parsing/Header/Impl/HeaderParser.h"
|
||||||
#include "Parsing/Sequence/AbstractSequence.h"
|
#include "Parsing/Sequence/AbstractSequence.h"
|
||||||
#include "Parsing/Header/Impl/HeaderParserState.h"
|
#include "Parsing/Header/Impl/HeaderParserState.h"
|
||||||
#include "Parsing/Header/Impl/HeaderParserValue.h"
|
#include "Parsing/Header/Impl/HeaderParserValue.h"
|
||||||
|
|
||||||
class SequenceNamespace final : public AbstractSequence<HeaderParserValue, HeaderParserState>
|
class SequenceNamespace final : public HeaderParser::sequence_t
|
||||||
{
|
{
|
||||||
static constexpr int CAPTURE_NAME = 0;
|
static constexpr int CAPTURE_NAME = 0;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void ProcessMatch(HeaderParserState* state, const SequenceResult<HeaderParserValue>& result) const override;
|
void ProcessMatch(HeaderParserState* state, SequenceResult<HeaderParserValue>& result) const override;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
SequenceNamespace();
|
SequenceNamespace();
|
||||||
|
@ -1,9 +1,14 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "Parsing/IParserValue.h"
|
||||||
|
|
||||||
|
template<typename TokenType>
|
||||||
class ILexer
|
class ILexer
|
||||||
{
|
{
|
||||||
public:
|
// TokenType must inherit IParserValue
|
||||||
|
static_assert(std::is_base_of<IParserValue, TokenType>::value);
|
||||||
|
|
||||||
|
public:
|
||||||
ILexer() = default;
|
ILexer() = default;
|
||||||
virtual ~ILexer() = default;
|
virtual ~ILexer() = default;
|
||||||
ILexer(const ILexer& other) = default;
|
ILexer(const ILexer& other) = default;
|
||||||
@ -11,5 +16,9 @@ public:
|
|||||||
ILexer& operator=(const ILexer& other) = default;
|
ILexer& operator=(const ILexer& other) = default;
|
||||||
ILexer& operator=(ILexer&& other) noexcept = default;
|
ILexer& operator=(ILexer&& other) noexcept = default;
|
||||||
|
|
||||||
|
virtual const TokenType& GetToken(unsigned index) = 0;
|
||||||
virtual void PopTokens(int amount) = 0;
|
virtual void PopTokens(int amount) = 0;
|
||||||
|
|
||||||
|
_NODISCARD virtual bool IsEof() = 0;
|
||||||
|
_NODISCARD virtual const TokenPos& GetPos() = 0;
|
||||||
};
|
};
|
||||||
|
14
src/ZoneCodeGeneratorLib/Parsing/IParser.h
Normal file
14
src/ZoneCodeGeneratorLib/Parsing/IParser.h
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
class IParser
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
IParser() = default;
|
||||||
|
virtual ~IParser() = default;
|
||||||
|
IParser(const IParser& other) = default;
|
||||||
|
IParser(IParser&& other) noexcept = default;
|
||||||
|
IParser& operator=(const IParser& other) = default;
|
||||||
|
IParser& operator=(IParser&& other) noexcept = default;
|
||||||
|
|
||||||
|
virtual bool Parse() = 0;
|
||||||
|
};
|
@ -4,13 +4,12 @@
|
|||||||
#include <deque>
|
#include <deque>
|
||||||
|
|
||||||
#include "Utils/ClassUtils.h"
|
#include "Utils/ClassUtils.h"
|
||||||
#include "ILexer.h"
|
#include "Parsing/ILexer.h"
|
||||||
#include "IParserValue.h"
|
#include "Parsing/IParserLineStream.h"
|
||||||
#include "IParserLineStream.h"
|
#include "Parsing/ParsingException.h"
|
||||||
#include "ParsingException.h"
|
|
||||||
|
|
||||||
template <typename TokenType>
|
template <typename TokenType>
|
||||||
class AbstractLexer : public ILexer
|
class AbstractLexer : public ILexer<TokenType>
|
||||||
{
|
{
|
||||||
// TokenType must inherit IParserValue
|
// TokenType must inherit IParserValue
|
||||||
static_assert(std::is_base_of<IParserValue, TokenType>::value);
|
static_assert(std::is_base_of<IParserValue, TokenType>::value);
|
||||||
@ -278,7 +277,7 @@ protected:
|
|||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
const TokenType& GetToken(unsigned index)
|
const TokenType& GetToken(unsigned index) override
|
||||||
{
|
{
|
||||||
assert(index >= 0);
|
assert(index >= 0);
|
||||||
while (index >= m_token_cache.size())
|
while (index >= m_token_cache.size())
|
||||||
@ -292,12 +291,12 @@ public:
|
|||||||
m_token_cache.erase(m_token_cache.begin(), m_token_cache.begin() + amount);
|
m_token_cache.erase(m_token_cache.begin(), m_token_cache.begin() + amount);
|
||||||
}
|
}
|
||||||
|
|
||||||
_NODISCARD bool IsEof()
|
_NODISCARD bool IsEof() override
|
||||||
{
|
{
|
||||||
return GetToken(0).IsEof();
|
return GetToken(0).IsEof();
|
||||||
}
|
}
|
||||||
|
|
||||||
_NODISCARD const TokenPos& GetPos()
|
_NODISCARD const TokenPos& GetPos() override
|
||||||
{
|
{
|
||||||
return GetToken(0).GetPos();
|
return GetToken(0).GetPos();
|
||||||
}
|
}
|
@ -3,11 +3,13 @@
|
|||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "AbstractLexer.h"
|
#include "Parsing/IParser.h"
|
||||||
#include "Sequence/AbstractSequence.h"
|
#include "Parsing/ILexer.h"
|
||||||
|
#include "Parsing/Sequence/AbstractSequence.h"
|
||||||
|
#include "Parsing/ParsingException.h"
|
||||||
|
|
||||||
template <typename TokenType, typename ParserState>
|
template <typename TokenType, typename ParserState>
|
||||||
class AbstractParser
|
class AbstractParser : public IParser
|
||||||
{
|
{
|
||||||
// TokenType must inherit IParserValue
|
// TokenType must inherit IParserValue
|
||||||
static_assert(std::is_base_of<IParserValue, TokenType>::value);
|
static_assert(std::is_base_of<IParserValue, TokenType>::value);
|
||||||
@ -16,10 +18,10 @@ public:
|
|||||||
typedef AbstractSequence<TokenType, ParserState> sequence_t;
|
typedef AbstractSequence<TokenType, ParserState> sequence_t;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
AbstractLexer<TokenType>* m_lexer;
|
ILexer<TokenType>* m_lexer;
|
||||||
std::unique_ptr<ParserState> m_state;
|
std::unique_ptr<ParserState> m_state;
|
||||||
|
|
||||||
explicit AbstractParser(AbstractLexer<TokenType>* lexer, std::unique_ptr<ParserState> state)
|
explicit AbstractParser(ILexer<TokenType>* lexer, std::unique_ptr<ParserState> state)
|
||||||
: m_lexer(lexer),
|
: m_lexer(lexer),
|
||||||
m_state(std::move(state))
|
m_state(std::move(state))
|
||||||
{
|
{
|
||||||
@ -34,7 +36,7 @@ public:
|
|||||||
AbstractParser& operator=(const AbstractParser& other) = default;
|
AbstractParser& operator=(const AbstractParser& other) = default;
|
||||||
AbstractParser& operator=(AbstractParser&& other) noexcept = default;
|
AbstractParser& operator=(AbstractParser&& other) noexcept = default;
|
||||||
|
|
||||||
bool Parse()
|
bool Parse() override
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
@ -3,7 +3,7 @@
|
|||||||
#include <functional>
|
#include <functional>
|
||||||
|
|
||||||
#include "Parsing/IParserValue.h"
|
#include "Parsing/IParserValue.h"
|
||||||
#include "Parsing/AbstractLexer.h"
|
#include "Parsing/ILexer.h"
|
||||||
#include "Parsing/Matcher/MatcherResult.h"
|
#include "Parsing/Matcher/MatcherResult.h"
|
||||||
|
|
||||||
template <typename TokenType>
|
template <typename TokenType>
|
||||||
@ -19,7 +19,7 @@ private:
|
|||||||
int m_tag_id;
|
int m_tag_id;
|
||||||
int m_capture_id;
|
int m_capture_id;
|
||||||
bool m_no_consume;
|
bool m_no_consume;
|
||||||
std::function<TokenType(std::vector<std::reference_wrapper<const TokenType>>)> m_transform_func;
|
std::function<TokenType(std::vector<std::reference_wrapper<const TokenType>>&)> m_transform_func;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
AbstractMatcher()
|
AbstractMatcher()
|
||||||
@ -29,7 +29,7 @@ protected:
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual MatcherResult<TokenType> CanMatch(AbstractLexer<TokenType>* lexer, unsigned tokenOffset) = 0;
|
virtual MatcherResult<TokenType> CanMatch(ILexer<TokenType>* lexer, unsigned tokenOffset) = 0;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
virtual ~AbstractMatcher() = default;
|
virtual ~AbstractMatcher() = default;
|
||||||
@ -53,12 +53,12 @@ public:
|
|||||||
m_no_consume = !value;
|
m_no_consume = !value;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetTransform(std::function<TokenType(std::vector<std::reference_wrapper<const TokenType>>)> transform)
|
void SetTransform(std::function<TokenType(std::vector<std::reference_wrapper<const TokenType>>&)> transform)
|
||||||
{
|
{
|
||||||
m_transform_func = std::move(transform);
|
m_transform_func = std::move(transform);
|
||||||
}
|
}
|
||||||
|
|
||||||
MatcherResult<TokenType> Match(AbstractLexer<TokenType>* lexer, const unsigned tokenOffset)
|
MatcherResult<TokenType> Match(ILexer<TokenType>* lexer, const unsigned tokenOffset)
|
||||||
{
|
{
|
||||||
MatcherResult<TokenType> result = CanMatch(lexer, tokenOffset);
|
MatcherResult<TokenType> result = CanMatch(lexer, tokenOffset);
|
||||||
|
|
||||||
|
@ -43,7 +43,7 @@ public:
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
MatcherFactoryWrapper<TokenType>& Transform(std::function<TokenType(std::vector<std::reference_wrapper<const TokenType>>)> transform)
|
MatcherFactoryWrapper<TokenType>& Transform(std::function<TokenType(std::vector<std::reference_wrapper<const TokenType>>&)> transform)
|
||||||
{
|
{
|
||||||
m_matcher->SetTransform(std::move(transform));
|
m_matcher->SetTransform(std::move(transform));
|
||||||
return *this;
|
return *this;
|
||||||
@ -81,14 +81,14 @@ public:
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
_NODISCARD MatcherFactoryWrapper<TokenType> And(std::initializer_list<std::unique_ptr<AbstractMatcher<TokenType>>> matchers) const
|
_NODISCARD MatcherFactoryWrapper<TokenType> And(std::initializer_list<Movable<std::unique_ptr<AbstractMatcher<TokenType>>>> matchers) const
|
||||||
{
|
{
|
||||||
return MatcherFactoryWrapper<TokenType>(std::make_unique<MatcherAnd<TokenType>>(std::move(matchers)));
|
return MatcherFactoryWrapper<TokenType>(std::make_unique<MatcherAnd<TokenType>>(matchers));
|
||||||
}
|
}
|
||||||
|
|
||||||
_NODISCARD MatcherFactoryWrapper<TokenType> Or(std::initializer_list<std::unique_ptr<AbstractMatcher<TokenType>>> matchers) const
|
_NODISCARD MatcherFactoryWrapper<TokenType> Or(std::initializer_list<Movable<std::unique_ptr<AbstractMatcher<TokenType>>>> matchers) const
|
||||||
{
|
{
|
||||||
return MatcherFactoryWrapper<TokenType>(std::make_unique<MatcherOr<TokenType>>(std::move(matchers)));
|
return MatcherFactoryWrapper<TokenType>(std::make_unique<MatcherOr<TokenType>>(matchers));
|
||||||
}
|
}
|
||||||
|
|
||||||
_NODISCARD MatcherFactoryWrapper<TokenType> Loop(std::unique_ptr<AbstractMatcher<TokenType>> matcher) const
|
_NODISCARD MatcherFactoryWrapper<TokenType> Loop(std::unique_ptr<AbstractMatcher<TokenType>> matcher) const
|
||||||
@ -108,6 +108,6 @@ public:
|
|||||||
|
|
||||||
_NODISCARD MatcherFactoryWrapper<TokenType> Label(const int label) const
|
_NODISCARD MatcherFactoryWrapper<TokenType> Label(const int label) const
|
||||||
{
|
{
|
||||||
return MatcherFactoryWrapper<TokenType>(std::make_unique<MatcherLabel<TokenType>>(label));
|
return MatcherFactoryWrapper<TokenType>(std::make_unique<MatcherLabel<TokenType>>(m_label_supplier, label));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -15,7 +15,7 @@ class MatcherAnd final : public AbstractMatcher<TokenType>
|
|||||||
std::vector<std::unique_ptr<AbstractMatcher<TokenType>>> m_matchers;
|
std::vector<std::unique_ptr<AbstractMatcher<TokenType>>> m_matchers;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
MatcherResult<TokenType> CanMatch(AbstractLexer<TokenType>* lexer, const unsigned tokenOffset) override
|
MatcherResult<TokenType> CanMatch(ILexer<TokenType>* lexer, const unsigned tokenOffset) override
|
||||||
{
|
{
|
||||||
auto matchResult = MatcherResult<TokenType>::Match(0);
|
auto matchResult = MatcherResult<TokenType>::Match(0);
|
||||||
|
|
||||||
|
@ -31,7 +31,7 @@ class MatcherLabel final : public AbstractMatcher<TokenType>
|
|||||||
int m_label;
|
int m_label;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
MatcherResult<TokenType> CanMatch(AbstractLexer<TokenType>* lexer, unsigned tokenOffset) override
|
MatcherResult<TokenType> CanMatch(ILexer<TokenType>* lexer, unsigned tokenOffset) override
|
||||||
{
|
{
|
||||||
AbstractMatcher<TokenType>* matcher = m_supplier->GetMatcherForLabel(m_label);
|
AbstractMatcher<TokenType>* matcher = m_supplier->GetMatcherForLabel(m_label);
|
||||||
|
|
||||||
|
@ -14,7 +14,7 @@ class MatcherLoop final : public AbstractMatcher<TokenType>
|
|||||||
std::unique_ptr<AbstractMatcher<TokenType>> m_matcher;
|
std::unique_ptr<AbstractMatcher<TokenType>> m_matcher;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
MatcherResult<TokenType> CanMatch(AbstractLexer<TokenType>* lexer, const unsigned tokenOffset) override
|
MatcherResult<TokenType> CanMatch(ILexer<TokenType>* lexer, const unsigned tokenOffset) override
|
||||||
{
|
{
|
||||||
auto matchResult = MatcherResult<TokenType>::Match(0);
|
auto matchResult = MatcherResult<TokenType>::Match(0);
|
||||||
auto loopedAtLeastOnce = false;
|
auto loopedAtLeastOnce = false;
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <iterator>
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
#include "Parsing/IParserValue.h"
|
#include "Parsing/IParserValue.h"
|
||||||
@ -15,7 +14,7 @@ class MatcherOptional final : public AbstractMatcher<TokenType>
|
|||||||
std::unique_ptr<AbstractMatcher<TokenType>> m_matcher;
|
std::unique_ptr<AbstractMatcher<TokenType>> m_matcher;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
MatcherResult<TokenType> CanMatch(AbstractLexer<TokenType>* lexer, unsigned tokenOffset) override
|
MatcherResult<TokenType> CanMatch(ILexer<TokenType>* lexer, unsigned tokenOffset) override
|
||||||
{
|
{
|
||||||
auto result = m_matcher->Match(lexer, tokenOffset);
|
auto result = m_matcher->Match(lexer, tokenOffset);
|
||||||
|
|
||||||
|
@ -15,11 +15,11 @@ class MatcherOr final : public AbstractMatcher<TokenType>
|
|||||||
std::vector<std::unique_ptr<AbstractMatcher<TokenType>>> m_matchers;
|
std::vector<std::unique_ptr<AbstractMatcher<TokenType>>> m_matchers;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
MatcherResult<TokenType> CanMatch(AbstractLexer<TokenType>* lexer, unsigned tokenOffset) override
|
MatcherResult<TokenType> CanMatch(ILexer<TokenType>* lexer, unsigned tokenOffset) override
|
||||||
{
|
{
|
||||||
for (const auto& matcher : m_matchers)
|
for (const std::unique_ptr<AbstractMatcher<TokenType>>& matcher : m_matchers)
|
||||||
{
|
{
|
||||||
const auto result = matcher->Match(lexer, tokenOffset);
|
MatcherResult<TokenType> result = matcher->Match(lexer, tokenOffset);
|
||||||
|
|
||||||
if (!result.m_matches)
|
if (!result.m_matches)
|
||||||
continue;
|
continue;
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
#include "SequenceResult.h"
|
#include "SequenceResult.h"
|
||||||
#include "Utils/ClassUtils.h"
|
#include "Utils/ClassUtils.h"
|
||||||
@ -27,7 +28,7 @@ protected:
|
|||||||
|
|
||||||
AbstractSequence() = default;
|
AbstractSequence() = default;
|
||||||
|
|
||||||
virtual void ProcessMatch(ParserState* state, const SequenceResult<TokenType>& result) const = 0;
|
virtual void ProcessMatch(ParserState* state, SequenceResult<TokenType>& result) const = 0;
|
||||||
|
|
||||||
void AddMatchers(std::initializer_list<Movable<std::unique_ptr<matcher_t>>> matchers)
|
void AddMatchers(std::initializer_list<Movable<std::unique_ptr<matcher_t>>> matchers)
|
||||||
{
|
{
|
||||||
@ -35,7 +36,7 @@ protected:
|
|||||||
m_entry = std::make_unique<MatcherAnd<TokenType>>(matchers);
|
m_entry = std::make_unique<MatcherAnd<TokenType>>(matchers);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AddLabeledMatchers(int label, std::initializer_list<Movable<std::unique_ptr<matcher_t>>> matchers)
|
void AddLabeledMatchers(std::initializer_list<Movable<std::unique_ptr<matcher_t>>> matchers, const int label)
|
||||||
{
|
{
|
||||||
assert(m_matchers.find(label) == m_matchers.end());
|
assert(m_matchers.find(label) == m_matchers.end());
|
||||||
m_matchers.emplace(label, std::make_unique<MatcherAnd<TokenType>>(matchers));
|
m_matchers.emplace(label, std::make_unique<MatcherAnd<TokenType>>(matchers));
|
||||||
@ -61,7 +62,7 @@ public:
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
_NODISCARD bool MatchSequence(AbstractLexer<TokenType>* lexer, ParserState* state, unsigned& consumedTokenCount) const
|
_NODISCARD bool MatchSequence(ILexer<TokenType>* lexer, ParserState* state, unsigned& consumedTokenCount) const
|
||||||
{
|
{
|
||||||
if (!m_entry)
|
if (!m_entry)
|
||||||
return false;
|
return false;
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
#include "Utils/ClassUtils.h"
|
#include "Utils/ClassUtils.h"
|
||||||
#include "Parsing/Matcher/AbstractMatcher.h"
|
#include "Parsing/Matcher/AbstractMatcher.h"
|
||||||
#include "Parsing/Matcher/MatcherResult.h"
|
#include "Parsing/Matcher/MatcherResult.h"
|
||||||
|
#include "Parsing/ParsingException.h"
|
||||||
|
|
||||||
template <typename TokenType>
|
template <typename TokenType>
|
||||||
class SequenceResult
|
class SequenceResult
|
||||||
@ -30,7 +31,7 @@ class SequenceResult
|
|||||||
unsigned m_tag_offset;
|
unsigned m_tag_offset;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
SequenceResult(AbstractLexer<TokenType>* lexer, const MatcherResult<TokenType>& result)
|
SequenceResult(ILexer<TokenType>* lexer, const MatcherResult<TokenType>& result)
|
||||||
: m_tags(result.m_tags),
|
: m_tags(result.m_tags),
|
||||||
m_tag_offset(0)
|
m_tag_offset(0)
|
||||||
{
|
{
|
||||||
|
@ -1,14 +1,7 @@
|
|||||||
#include <utility>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
#include "ZoneCodeGenerator.h"
|
#include "ZoneCodeGenerator.h"
|
||||||
|
|
||||||
int main(const int argc, const char** argv)
|
int main(const int argc, const char** argv)
|
||||||
{
|
{
|
||||||
int i = 5;
|
|
||||||
std::vector<std::pair<int, const int&>> asdf;
|
|
||||||
asdf.emplace_back(1, i);
|
|
||||||
|
|
||||||
const ZoneCodeGenerator zoneCodeGenerator;
|
const ZoneCodeGenerator zoneCodeGenerator;
|
||||||
return zoneCodeGenerator.Run(argc, argv);
|
return zoneCodeGenerator.Run(argc, argv);
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
#include "Parsing/Commands/Impl/CommandsLexer.h"
|
#include "Parsing/Commands/Impl/CommandsLexer.h"
|
||||||
#include "Parsing/Mock/MockParserLineStream.h"
|
#include "Parsing/Mock/MockParserLineStream.h"
|
||||||
|
|
||||||
namespace test::parsing::commands
|
namespace test::parsing::commands::impl::commands_lexer
|
||||||
{
|
{
|
||||||
TEST_CASE("CommandsLexer: ", "[parsing][commands]")
|
TEST_CASE("CommandsLexer: ", "[parsing][commands]")
|
||||||
{
|
{
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
#include "Parsing/Header/Impl/HeaderLexer.h"
|
#include "Parsing/Header/Impl/HeaderLexer.h"
|
||||||
#include "Parsing/Mock/MockParserLineStream.h"
|
#include "Parsing/Mock/MockParserLineStream.h"
|
||||||
|
|
||||||
namespace test::parsing::header
|
namespace test::parsing::header::impl::header_lexer
|
||||||
{
|
{
|
||||||
void ExpectCharacterToken(HeaderLexer& lexer, char c)
|
void ExpectCharacterToken(HeaderLexer& lexer, char c)
|
||||||
{
|
{
|
||||||
|
@ -0,0 +1,26 @@
|
|||||||
|
#include <catch2/catch.hpp>
|
||||||
|
|
||||||
|
#include "Parsing/Header/Sequence/SequenceNamespace.h"
|
||||||
|
#include "Parsing/Mock/MockLexer.h"
|
||||||
|
|
||||||
|
namespace test::parsing::header::sequence::sequence_namespace
|
||||||
|
{
|
||||||
|
TEST_CASE("SequenceNamespace: Ensure can parse simple namespace directive", "[parsing][parsingstream]")
|
||||||
|
{
|
||||||
|
const TokenPos pos;
|
||||||
|
const auto lexer = std::make_unique<MockLexer<HeaderParserValue>>(MockLexer<HeaderParserValue>(
|
||||||
|
{
|
||||||
|
HeaderParserValue::Keyword(pos, HeaderParserValueType::NAMESPACE),
|
||||||
|
HeaderParserValue::Identifier(pos, new std::string("test_namespace")),
|
||||||
|
HeaderParserValue::Character(pos, '{')
|
||||||
|
}, HeaderParserValue::EndOfFile(pos)));
|
||||||
|
|
||||||
|
const auto sequence = std::make_unique<SequenceNamespace>();
|
||||||
|
const auto state = std::make_unique<HeaderParserState>();
|
||||||
|
|
||||||
|
unsigned consumedTokenCount;
|
||||||
|
auto result = sequence->MatchSequence(lexer.get(), state.get(), consumedTokenCount);
|
||||||
|
|
||||||
|
REQUIRE(result);
|
||||||
|
}
|
||||||
|
}
|
@ -1,10 +1,9 @@
|
|||||||
#include <catch2/catch.hpp>
|
#include <catch2/catch.hpp>
|
||||||
|
|
||||||
|
|
||||||
#include "Parsing/Impl/CommentRemovingStreamProxy.h"
|
#include "Parsing/Impl/CommentRemovingStreamProxy.h"
|
||||||
#include "Parsing/Mock/MockParserLineStream.h"
|
#include "Parsing/Mock/MockParserLineStream.h"
|
||||||
|
|
||||||
namespace test::parsing
|
namespace test::parsing::impl::comment_removing_stream_proxy
|
||||||
{
|
{
|
||||||
TEST_CASE("CommentRemovingStreamProxy: Ensure simple single line comment is working", "[parsing][parsingstream]")
|
TEST_CASE("CommentRemovingStreamProxy: Ensure simple single line comment is working", "[parsing][parsingstream]")
|
||||||
{
|
{
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
#include "Parsing/Impl/DefinesStreamProxy.h"
|
#include "Parsing/Impl/DefinesStreamProxy.h"
|
||||||
#include "Parsing/Mock/MockParserLineStream.h"
|
#include "Parsing/Mock/MockParserLineStream.h"
|
||||||
|
|
||||||
namespace test::parsing
|
namespace test::parsing::impl::defines_stream_proxy
|
||||||
{
|
{
|
||||||
void ExpectLine(IParserLineStream* stream, const int lineNumber, const std::string& value)
|
void ExpectLine(IParserLineStream* stream, const int lineNumber, const std::string& value)
|
||||||
{
|
{
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
#include "Parsing/Impl/IncludingStreamProxy.h"
|
#include "Parsing/Impl/IncludingStreamProxy.h"
|
||||||
#include "Parsing/Mock/MockParserLineStream.h"
|
#include "Parsing/Mock/MockParserLineStream.h"
|
||||||
|
|
||||||
namespace test::parsing
|
namespace test::parsing::impl::including_stream_proxy
|
||||||
{
|
{
|
||||||
TEST_CASE("IncludingStreamProxy: Ensure simple include is working", "[parsing][parsingstream]")
|
TEST_CASE("IncludingStreamProxy: Ensure simple include is working", "[parsing][parsingstream]")
|
||||||
{
|
{
|
||||||
|
848
test/ZoneCodeGeneratorLibTests/Parsing/Matcher/MatcherTests.cpp
Normal file
848
test/ZoneCodeGeneratorLibTests/Parsing/Matcher/MatcherTests.cpp
Normal file
@ -0,0 +1,848 @@
|
|||||||
|
#include <catch2/catch.hpp>
|
||||||
|
|
||||||
|
#include "Utils/ClassUtils.h"
|
||||||
|
#include "Parsing/Header/Impl/HeaderParserValue.h"
|
||||||
|
#include "Parsing/Header/Matcher/HeaderMatcherFactory.h"
|
||||||
|
#include "Parsing/Impl/DefinesStreamProxy.h"
|
||||||
|
#include "Parsing/Mock/MockLexer.h"
|
||||||
|
#include "Parsing/Mock/MockSequence.h"
|
||||||
|
|
||||||
|
namespace test::parsing::matcher
|
||||||
|
{
|
||||||
|
// This class uses the header implementation of IParserValues
|
||||||
|
// This should not make a difference in behaviour and only affects test data
|
||||||
|
|
||||||
|
typedef MockLexer<HeaderParserValue> lexer_t;
|
||||||
|
typedef MockSequence<HeaderParserValue> sequence_t;
|
||||||
|
typedef sequence_t::parent_t::matcher_t matcher_t;
|
||||||
|
typedef SequenceResult<HeaderParserValue> sequence_result_t;
|
||||||
|
typedef HeaderMatcherFactory factory_t;
|
||||||
|
|
||||||
|
class MatchersTestsHelper
|
||||||
|
{
|
||||||
|
std::unique_ptr<MockSequenceState> m_mock_state;
|
||||||
|
std::unique_ptr<lexer_t> m_lexer;
|
||||||
|
std::unique_ptr<sequence_t> m_sequence;
|
||||||
|
|
||||||
|
unsigned m_consumed_token_count;
|
||||||
|
|
||||||
|
public:
|
||||||
|
MatchersTestsHelper()
|
||||||
|
: m_mock_state(std::make_unique<MockSequenceState>()),
|
||||||
|
m_sequence(std::make_unique<sequence_t>()),
|
||||||
|
m_consumed_token_count(0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void Tokens(std::initializer_list<Movable<HeaderParserValue>> tokens)
|
||||||
|
{
|
||||||
|
m_lexer = std::make_unique<lexer_t>(tokens, HeaderParserValue::EndOfFile(TokenPos()));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Matchers(const std::initializer_list<Movable<std::unique_ptr<matcher_t>>> matchers) const
|
||||||
|
{
|
||||||
|
m_sequence->AddMockMatchers(matchers);
|
||||||
|
}
|
||||||
|
|
||||||
|
void LabeledMatchers(const std::initializer_list<Movable<std::unique_ptr<matcher_t>>> matchers, const int label) const
|
||||||
|
{
|
||||||
|
m_sequence->AddMockLabeledMatchers(matchers, label);
|
||||||
|
}
|
||||||
|
|
||||||
|
_NODISCARD factory_t Factory() const
|
||||||
|
{
|
||||||
|
return HeaderMatcherFactory(m_sequence->GetLabelSupplier());
|
||||||
|
}
|
||||||
|
|
||||||
|
void MatchCallback(std::function<void(sequence_result_t& result)> cb) const
|
||||||
|
{
|
||||||
|
m_sequence->Handle(std::move(cb));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PerformTest()
|
||||||
|
{
|
||||||
|
// Tokens must be set first
|
||||||
|
REQUIRE(m_lexer.get() != nullptr);
|
||||||
|
return m_sequence->MatchSequence(m_lexer.get(), m_mock_state.get(), m_consumed_token_count);
|
||||||
|
}
|
||||||
|
|
||||||
|
_NODISCARD unsigned GetConsumedTokenCount() const
|
||||||
|
{
|
||||||
|
return m_consumed_token_count;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
TEST_CASE("Matcher: Ensure can match simple AND token sequence", "[parsing][matcher]")
|
||||||
|
{
|
||||||
|
MatchersTestsHelper test;
|
||||||
|
const TokenPos pos;
|
||||||
|
test.Tokens({
|
||||||
|
HeaderParserValue::Keyword(pos, HeaderParserValueType::NAMESPACE),
|
||||||
|
HeaderParserValue::Identifier(pos, new std::string("test_namespace")),
|
||||||
|
HeaderParserValue::Character(pos, '{'),
|
||||||
|
HeaderParserValue::Invalid(pos)
|
||||||
|
});
|
||||||
|
const auto create = test.Factory();
|
||||||
|
test.Matchers({
|
||||||
|
create.Type(HeaderParserValueType::NAMESPACE),
|
||||||
|
create.Identifier(),
|
||||||
|
create.Char('{')
|
||||||
|
});
|
||||||
|
|
||||||
|
REQUIRE(test.PerformTest());
|
||||||
|
REQUIRE(test.GetConsumedTokenCount() == 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Matcher: Ensure AND matcher can fail", "[parsing][matcher]")
|
||||||
|
{
|
||||||
|
MatchersTestsHelper test;
|
||||||
|
const TokenPos pos;
|
||||||
|
test.Tokens({
|
||||||
|
HeaderParserValue::Keyword(pos, HeaderParserValueType::NAMESPACE),
|
||||||
|
HeaderParserValue::Identifier(pos, new std::string("test_namespace")),
|
||||||
|
HeaderParserValue::Character(pos, '{'),
|
||||||
|
HeaderParserValue::Invalid(pos)
|
||||||
|
});
|
||||||
|
const auto create = test.Factory();
|
||||||
|
test.Matchers({
|
||||||
|
create.Type(HeaderParserValueType::NAMESPACE),
|
||||||
|
create.Identifier(),
|
||||||
|
create.Char('+')
|
||||||
|
});
|
||||||
|
|
||||||
|
REQUIRE(!test.PerformTest());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Matcher: Ensure match callback is called", "[parsing][matcher]")
|
||||||
|
{
|
||||||
|
MatchersTestsHelper test;
|
||||||
|
const TokenPos pos;
|
||||||
|
auto callbackCalled = false;
|
||||||
|
test.Tokens({
|
||||||
|
HeaderParserValue::Keyword(pos, HeaderParserValueType::NAMESPACE),
|
||||||
|
HeaderParserValue::Identifier(pos, new std::string("test_namespace")),
|
||||||
|
HeaderParserValue::Character(pos, '{'),
|
||||||
|
HeaderParserValue::Invalid(pos)
|
||||||
|
});
|
||||||
|
const auto create = test.Factory();
|
||||||
|
test.Matchers({
|
||||||
|
create.Type(HeaderParserValueType::NAMESPACE)
|
||||||
|
});
|
||||||
|
test.MatchCallback([&callbackCalled](sequence_result_t& result)
|
||||||
|
{
|
||||||
|
callbackCalled = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
REQUIRE(test.PerformTest());
|
||||||
|
REQUIRE(callbackCalled);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Matcher: Ensure match callback is not called on fail", "[parsing][matcher]")
|
||||||
|
{
|
||||||
|
MatchersTestsHelper test;
|
||||||
|
const TokenPos pos;
|
||||||
|
auto callbackCalled = false;
|
||||||
|
test.Tokens({
|
||||||
|
HeaderParserValue::Keyword(pos, HeaderParserValueType::STRUCT),
|
||||||
|
HeaderParserValue::Invalid(pos)
|
||||||
|
});
|
||||||
|
const auto create = test.Factory();
|
||||||
|
test.Matchers({
|
||||||
|
create.Type(HeaderParserValueType::NAMESPACE)
|
||||||
|
});
|
||||||
|
test.MatchCallback([&callbackCalled](sequence_result_t& result)
|
||||||
|
{
|
||||||
|
callbackCalled = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
REQUIRE(!test.PerformTest());
|
||||||
|
REQUIRE(!callbackCalled);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Matcher: Ensure can match simple OR token sequence", "[parsing][matcher]")
|
||||||
|
{
|
||||||
|
static constexpr auto TAG_NAMESPACE = 1;
|
||||||
|
static constexpr auto TAG_STRUCT = 2;
|
||||||
|
|
||||||
|
MatchersTestsHelper test;
|
||||||
|
const TokenPos pos;
|
||||||
|
const auto create = test.Factory();
|
||||||
|
test.Matchers({
|
||||||
|
create.Or({
|
||||||
|
create.Type(HeaderParserValueType::NAMESPACE).Tag(TAG_NAMESPACE),
|
||||||
|
create.Type(HeaderParserValueType::STRUCT).Tag(TAG_STRUCT),
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
test.Tokens({
|
||||||
|
HeaderParserValue::Keyword(pos, HeaderParserValueType::NAMESPACE),
|
||||||
|
HeaderParserValue::Identifier(pos, new std::string("test_namespace")),
|
||||||
|
HeaderParserValue::Character(pos, '{'),
|
||||||
|
HeaderParserValue::Invalid(pos)
|
||||||
|
});
|
||||||
|
test.MatchCallback([](sequence_result_t& result)
|
||||||
|
{
|
||||||
|
REQUIRE(result.NextTag() == TAG_NAMESPACE);
|
||||||
|
});
|
||||||
|
|
||||||
|
REQUIRE(test.PerformTest());
|
||||||
|
REQUIRE(test.GetConsumedTokenCount() == 1);
|
||||||
|
|
||||||
|
test.Tokens({
|
||||||
|
HeaderParserValue::Keyword(pos, HeaderParserValueType::STRUCT),
|
||||||
|
HeaderParserValue::Identifier(pos, new std::string("test_struct")),
|
||||||
|
HeaderParserValue::Character(pos, '{'),
|
||||||
|
HeaderParserValue::Invalid(pos)
|
||||||
|
});
|
||||||
|
test.MatchCallback([](sequence_result_t& result)
|
||||||
|
{
|
||||||
|
REQUIRE(result.NextTag() == TAG_STRUCT);
|
||||||
|
});
|
||||||
|
|
||||||
|
REQUIRE(test.PerformTest());
|
||||||
|
REQUIRE(test.GetConsumedTokenCount() == 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Matcher: Ensure OR matcher can fail", "[parsing][matcher]")
|
||||||
|
{
|
||||||
|
static constexpr auto TAG_NAMESPACE = 1;
|
||||||
|
static constexpr auto TAG_STRUCT = 2;
|
||||||
|
|
||||||
|
MatchersTestsHelper test;
|
||||||
|
const TokenPos pos;
|
||||||
|
const auto create = test.Factory();
|
||||||
|
test.Matchers({
|
||||||
|
create.Or({
|
||||||
|
create.Type(HeaderParserValueType::NAMESPACE).Tag(TAG_NAMESPACE),
|
||||||
|
create.Type(HeaderParserValueType::STRUCT).Tag(TAG_STRUCT),
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
test.Tokens({
|
||||||
|
HeaderParserValue::Keyword(pos, HeaderParserValueType::ENUM),
|
||||||
|
HeaderParserValue::Identifier(pos, new std::string("test_namespace")),
|
||||||
|
HeaderParserValue::Character(pos, '{'),
|
||||||
|
HeaderParserValue::Invalid(pos)
|
||||||
|
});
|
||||||
|
test.MatchCallback([](sequence_result_t& result)
|
||||||
|
{
|
||||||
|
FAIL();
|
||||||
|
});
|
||||||
|
|
||||||
|
REQUIRE(!test.PerformTest());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Matcher: Ensure can match simple LOOP token sequence", "[parsing][matcher]")
|
||||||
|
{
|
||||||
|
static constexpr auto TAG_NAMESPACE = 1;
|
||||||
|
static constexpr auto TAG_STRUCT = 2;
|
||||||
|
|
||||||
|
MatchersTestsHelper test;
|
||||||
|
const TokenPos pos;
|
||||||
|
const auto create = test.Factory();
|
||||||
|
test.Matchers({
|
||||||
|
create.Loop(create.Type(HeaderParserValueType::NAMESPACE).Tag(TAG_NAMESPACE)),
|
||||||
|
create.Type(HeaderParserValueType::STRUCT).Tag(TAG_STRUCT)
|
||||||
|
});
|
||||||
|
|
||||||
|
test.Tokens({
|
||||||
|
HeaderParserValue::Keyword(pos, HeaderParserValueType::NAMESPACE),
|
||||||
|
HeaderParserValue::Keyword(pos, HeaderParserValueType::NAMESPACE),
|
||||||
|
HeaderParserValue::Keyword(pos, HeaderParserValueType::NAMESPACE),
|
||||||
|
HeaderParserValue::Keyword(pos, HeaderParserValueType::STRUCT),
|
||||||
|
HeaderParserValue::Invalid(pos)
|
||||||
|
});
|
||||||
|
test.MatchCallback([](sequence_result_t& result)
|
||||||
|
{
|
||||||
|
REQUIRE(result.NextTag() == TAG_NAMESPACE);
|
||||||
|
REQUIRE(result.NextTag() == TAG_NAMESPACE);
|
||||||
|
REQUIRE(result.NextTag() == TAG_NAMESPACE);
|
||||||
|
REQUIRE(result.NextTag() == TAG_STRUCT);
|
||||||
|
});
|
||||||
|
|
||||||
|
REQUIRE(test.PerformTest());
|
||||||
|
REQUIRE(test.GetConsumedTokenCount() == 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Matcher: Ensure LOOP token sequence must be called at least once to succeed", "[parsing][matcher]")
|
||||||
|
{
|
||||||
|
static constexpr auto TAG_NAMESPACE = 1;
|
||||||
|
static constexpr auto TAG_STRUCT = 2;
|
||||||
|
|
||||||
|
MatchersTestsHelper test;
|
||||||
|
const TokenPos pos;
|
||||||
|
const auto create = test.Factory();
|
||||||
|
test.Matchers({
|
||||||
|
create.Loop(create.Type(HeaderParserValueType::NAMESPACE).Tag(TAG_NAMESPACE)),
|
||||||
|
create.Type(HeaderParserValueType::STRUCT).Tag(TAG_STRUCT)
|
||||||
|
});
|
||||||
|
|
||||||
|
test.Tokens({
|
||||||
|
HeaderParserValue::Keyword(pos, HeaderParserValueType::STRUCT),
|
||||||
|
HeaderParserValue::Invalid(pos)
|
||||||
|
});
|
||||||
|
|
||||||
|
REQUIRE(!test.PerformTest());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Matcher: Ensure OPTIONAL_LOOP token sequence can be called zero times", "[parsing][matcher]")
|
||||||
|
{
|
||||||
|
static constexpr auto TAG_NAMESPACE = 1;
|
||||||
|
static constexpr auto TAG_STRUCT = 2;
|
||||||
|
|
||||||
|
MatchersTestsHelper test;
|
||||||
|
const TokenPos pos;
|
||||||
|
const auto create = test.Factory();
|
||||||
|
test.Matchers({
|
||||||
|
create.OptionalLoop(create.Type(HeaderParserValueType::NAMESPACE).Tag(TAG_NAMESPACE)),
|
||||||
|
create.Type(HeaderParserValueType::STRUCT).Tag(TAG_STRUCT)
|
||||||
|
});
|
||||||
|
|
||||||
|
test.Tokens({
|
||||||
|
HeaderParserValue::Keyword(pos, HeaderParserValueType::STRUCT),
|
||||||
|
HeaderParserValue::Invalid(pos)
|
||||||
|
});
|
||||||
|
|
||||||
|
REQUIRE(test.PerformTest());
|
||||||
|
REQUIRE(test.GetConsumedTokenCount() == 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Matcher: Ensure OPTIONAL token sequence can be called zero times", "[parsing][matcher]")
|
||||||
|
{
|
||||||
|
static constexpr auto TAG_NAMESPACE = 1;
|
||||||
|
static constexpr auto TAG_STRUCT = 2;
|
||||||
|
static constexpr auto TAG_ENUM = 3;
|
||||||
|
|
||||||
|
MatchersTestsHelper test;
|
||||||
|
const TokenPos pos;
|
||||||
|
const auto create = test.Factory();
|
||||||
|
test.Matchers({
|
||||||
|
create.Type(HeaderParserValueType::NAMESPACE).Tag(TAG_NAMESPACE),
|
||||||
|
create.Optional(create.Type(HeaderParserValueType::STRUCT).Tag(TAG_STRUCT)),
|
||||||
|
create.Type(HeaderParserValueType::ENUM).Tag(TAG_ENUM)
|
||||||
|
});
|
||||||
|
|
||||||
|
test.Tokens({
|
||||||
|
HeaderParserValue::Keyword(pos, HeaderParserValueType::NAMESPACE),
|
||||||
|
HeaderParserValue::Keyword(pos, HeaderParserValueType::ENUM),
|
||||||
|
HeaderParserValue::Invalid(pos)
|
||||||
|
});
|
||||||
|
|
||||||
|
REQUIRE(test.PerformTest());
|
||||||
|
REQUIRE(test.GetConsumedTokenCount() == 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Matcher: Ensure OPTIONAL token sequence can be called once", "[parsing][matcher]")
|
||||||
|
{
|
||||||
|
static constexpr auto TAG_NAMESPACE = 1;
|
||||||
|
static constexpr auto TAG_STRUCT = 2;
|
||||||
|
static constexpr auto TAG_ENUM = 3;
|
||||||
|
|
||||||
|
MatchersTestsHelper test;
|
||||||
|
const TokenPos pos;
|
||||||
|
const auto create = test.Factory();
|
||||||
|
test.Matchers({
|
||||||
|
create.Type(HeaderParserValueType::NAMESPACE).Tag(TAG_NAMESPACE),
|
||||||
|
create.Optional(create.Type(HeaderParserValueType::STRUCT).Tag(TAG_STRUCT)),
|
||||||
|
create.Type(HeaderParserValueType::ENUM).Tag(TAG_ENUM)
|
||||||
|
});
|
||||||
|
|
||||||
|
test.Tokens({
|
||||||
|
HeaderParserValue::Keyword(pos, HeaderParserValueType::NAMESPACE),
|
||||||
|
HeaderParserValue::Keyword(pos, HeaderParserValueType::STRUCT),
|
||||||
|
HeaderParserValue::Keyword(pos, HeaderParserValueType::ENUM),
|
||||||
|
HeaderParserValue::Invalid(pos)
|
||||||
|
});
|
||||||
|
|
||||||
|
REQUIRE(test.PerformTest());
|
||||||
|
REQUIRE(test.GetConsumedTokenCount() == 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Matcher: Ensure OPTIONAL token sequence can not be called more than once", "[parsing][matcher]")
|
||||||
|
{
|
||||||
|
static constexpr auto TAG_NAMESPACE = 1;
|
||||||
|
static constexpr auto TAG_STRUCT = 2;
|
||||||
|
static constexpr auto TAG_ENUM = 3;
|
||||||
|
|
||||||
|
MatchersTestsHelper test;
|
||||||
|
const TokenPos pos;
|
||||||
|
const auto create = test.Factory();
|
||||||
|
test.Matchers({
|
||||||
|
create.Type(HeaderParserValueType::NAMESPACE).Tag(TAG_NAMESPACE),
|
||||||
|
create.Optional(create.Type(HeaderParserValueType::STRUCT).Tag(TAG_STRUCT)),
|
||||||
|
create.Type(HeaderParserValueType::ENUM).Tag(TAG_ENUM)
|
||||||
|
});
|
||||||
|
|
||||||
|
test.Tokens({
|
||||||
|
HeaderParserValue::Keyword(pos, HeaderParserValueType::NAMESPACE),
|
||||||
|
HeaderParserValue::Keyword(pos, HeaderParserValueType::STRUCT),
|
||||||
|
HeaderParserValue::Keyword(pos, HeaderParserValueType::STRUCT),
|
||||||
|
HeaderParserValue::Keyword(pos, HeaderParserValueType::ENUM),
|
||||||
|
HeaderParserValue::Invalid(pos)
|
||||||
|
});
|
||||||
|
|
||||||
|
REQUIRE(!test.PerformTest());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Matcher: Ensure LOOP matchers are greedy", "[parsing][matcher]")
|
||||||
|
{
|
||||||
|
static constexpr auto TAG_NAMESPACE = 1;
|
||||||
|
static constexpr auto TAG_STRUCT = 2;
|
||||||
|
static constexpr auto TAG_ENUM = 3;
|
||||||
|
static constexpr auto TAG_TYPEDEF = 4;
|
||||||
|
|
||||||
|
MatchersTestsHelper test;
|
||||||
|
const TokenPos pos;
|
||||||
|
const auto create = test.Factory();
|
||||||
|
test.Matchers({
|
||||||
|
create.Type(HeaderParserValueType::NAMESPACE).Tag(TAG_NAMESPACE),
|
||||||
|
create.Loop(create.Or({
|
||||||
|
create.Type(HeaderParserValueType::STRUCT).Tag(TAG_STRUCT),
|
||||||
|
create.Type(HeaderParserValueType::TYPEDEF).Tag(TAG_TYPEDEF)
|
||||||
|
})),
|
||||||
|
create.Or({
|
||||||
|
create.Type(HeaderParserValueType::TYPEDEF).Tag(TAG_TYPEDEF),
|
||||||
|
create.Type(HeaderParserValueType::ENUM).Tag(TAG_ENUM)
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
test.Tokens({
|
||||||
|
HeaderParserValue::Keyword(pos, HeaderParserValueType::NAMESPACE),
|
||||||
|
HeaderParserValue::Keyword(pos, HeaderParserValueType::STRUCT),
|
||||||
|
HeaderParserValue::Keyword(pos, HeaderParserValueType::STRUCT),
|
||||||
|
HeaderParserValue::Keyword(pos, HeaderParserValueType::TYPEDEF),
|
||||||
|
HeaderParserValue::Keyword(pos, HeaderParserValueType::STRUCT),
|
||||||
|
HeaderParserValue::Keyword(pos, HeaderParserValueType::TYPEDEF),
|
||||||
|
HeaderParserValue::Keyword(pos, HeaderParserValueType::ENUM),
|
||||||
|
HeaderParserValue::Invalid(pos)
|
||||||
|
});
|
||||||
|
|
||||||
|
test.MatchCallback([](sequence_result_t& result)
|
||||||
|
{
|
||||||
|
REQUIRE(result.NextTag() == TAG_NAMESPACE);
|
||||||
|
REQUIRE(result.NextTag() == TAG_STRUCT);
|
||||||
|
REQUIRE(result.NextTag() == TAG_STRUCT);
|
||||||
|
REQUIRE(result.NextTag() == TAG_TYPEDEF);
|
||||||
|
REQUIRE(result.NextTag() == TAG_STRUCT);
|
||||||
|
REQUIRE(result.NextTag() == TAG_TYPEDEF);
|
||||||
|
REQUIRE(result.NextTag() == TAG_ENUM);
|
||||||
|
});
|
||||||
|
|
||||||
|
REQUIRE(test.PerformTest());
|
||||||
|
REQUIRE(test.GetConsumedTokenCount() == 7);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Matcher: Ensure LABEL matcher are working", "[parsing][matcher]")
|
||||||
|
{
|
||||||
|
static constexpr auto TAG_NAMESPACE = 1;
|
||||||
|
static constexpr auto TAG_STRUCT = 2;
|
||||||
|
|
||||||
|
static constexpr auto LABEL_TEST = 1;
|
||||||
|
|
||||||
|
MatchersTestsHelper test;
|
||||||
|
const TokenPos pos;
|
||||||
|
const auto create = test.Factory();
|
||||||
|
test.Matchers(
|
||||||
|
{
|
||||||
|
create.Type(HeaderParserValueType::NAMESPACE).Tag(TAG_NAMESPACE),
|
||||||
|
create.Label(LABEL_TEST)
|
||||||
|
});
|
||||||
|
test.LabeledMatchers(
|
||||||
|
{
|
||||||
|
create.Type(HeaderParserValueType::STRUCT).Tag(TAG_STRUCT),
|
||||||
|
create.Type(HeaderParserValueType::STRUCT).Tag(TAG_STRUCT)
|
||||||
|
}, LABEL_TEST);
|
||||||
|
|
||||||
|
test.Tokens({
|
||||||
|
HeaderParserValue::Keyword(pos, HeaderParserValueType::NAMESPACE),
|
||||||
|
HeaderParserValue::Keyword(pos, HeaderParserValueType::STRUCT),
|
||||||
|
HeaderParserValue::Keyword(pos, HeaderParserValueType::STRUCT),
|
||||||
|
HeaderParserValue::Invalid(pos)
|
||||||
|
});
|
||||||
|
|
||||||
|
test.MatchCallback([](sequence_result_t& result)
|
||||||
|
{
|
||||||
|
REQUIRE(result.NextTag() == TAG_NAMESPACE);
|
||||||
|
REQUIRE(result.NextTag() == TAG_STRUCT);
|
||||||
|
REQUIRE(result.NextTag() == TAG_STRUCT);
|
||||||
|
});
|
||||||
|
|
||||||
|
REQUIRE(test.PerformTest());
|
||||||
|
REQUIRE(test.GetConsumedTokenCount() == 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Matcher: Ensure LABEL matchers can refer to themselves are working", "[parsing][matcher]")
|
||||||
|
{
|
||||||
|
static constexpr auto TAG_NAMESPACE = 1;
|
||||||
|
static constexpr auto TAG_STRUCT = 2;
|
||||||
|
|
||||||
|
static constexpr auto LABEL_TEST = 1;
|
||||||
|
|
||||||
|
MatchersTestsHelper test;
|
||||||
|
const TokenPos pos;
|
||||||
|
const auto create = test.Factory();
|
||||||
|
test.Matchers(
|
||||||
|
{
|
||||||
|
create.Type(HeaderParserValueType::NAMESPACE).Tag(TAG_NAMESPACE),
|
||||||
|
create.Label(LABEL_TEST)
|
||||||
|
});
|
||||||
|
test.LabeledMatchers(
|
||||||
|
{
|
||||||
|
create.Type(HeaderParserValueType::STRUCT).Tag(TAG_STRUCT),
|
||||||
|
create.Optional(create.Label(LABEL_TEST))
|
||||||
|
}, LABEL_TEST);
|
||||||
|
|
||||||
|
test.Tokens({
|
||||||
|
HeaderParserValue::Keyword(pos, HeaderParserValueType::NAMESPACE),
|
||||||
|
HeaderParserValue::Keyword(pos, HeaderParserValueType::STRUCT),
|
||||||
|
HeaderParserValue::Keyword(pos, HeaderParserValueType::STRUCT),
|
||||||
|
HeaderParserValue::Keyword(pos, HeaderParserValueType::STRUCT),
|
||||||
|
HeaderParserValue::Invalid(pos)
|
||||||
|
});
|
||||||
|
|
||||||
|
test.MatchCallback([](sequence_result_t& result)
|
||||||
|
{
|
||||||
|
REQUIRE(result.NextTag() == TAG_NAMESPACE);
|
||||||
|
REQUIRE(result.NextTag() == TAG_STRUCT);
|
||||||
|
REQUIRE(result.NextTag() == TAG_STRUCT);
|
||||||
|
REQUIRE(result.NextTag() == TAG_STRUCT);
|
||||||
|
});
|
||||||
|
|
||||||
|
REQUIRE(test.PerformTest());
|
||||||
|
REQUIRE(test.GetConsumedTokenCount() == 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Matcher: Can capture tokens", "[parsing][matcher]")
|
||||||
|
{
|
||||||
|
static constexpr auto TAG_NAMESPACE = 1;
|
||||||
|
|
||||||
|
static constexpr auto CAPTURE_NAMESPACE_NAME = 1;
|
||||||
|
|
||||||
|
MatchersTestsHelper test;
|
||||||
|
const TokenPos pos;
|
||||||
|
const auto create = test.Factory();
|
||||||
|
test.Matchers({
|
||||||
|
create.Type(HeaderParserValueType::NAMESPACE).Tag(TAG_NAMESPACE),
|
||||||
|
create.Identifier().Capture(CAPTURE_NAMESPACE_NAME),
|
||||||
|
create.Char('{')
|
||||||
|
});
|
||||||
|
|
||||||
|
test.Tokens({
|
||||||
|
HeaderParserValue::Keyword(pos, HeaderParserValueType::NAMESPACE),
|
||||||
|
HeaderParserValue::Identifier(pos, new std::string("hello_world")),
|
||||||
|
HeaderParserValue::Character(pos, '{'),
|
||||||
|
HeaderParserValue::Invalid(pos)
|
||||||
|
});
|
||||||
|
|
||||||
|
test.MatchCallback([](sequence_result_t& result)
|
||||||
|
{
|
||||||
|
REQUIRE(result.NextTag() == TAG_NAMESPACE);
|
||||||
|
REQUIRE(result.NextTag() == matcher_t::NO_ID);
|
||||||
|
|
||||||
|
REQUIRE(result.HasNextCapture(CAPTURE_NAMESPACE_NAME));
|
||||||
|
{
|
||||||
|
const auto& capture = result.NextCapture(CAPTURE_NAMESPACE_NAME);
|
||||||
|
REQUIRE(capture.m_type == HeaderParserValueType::IDENTIFIER);
|
||||||
|
REQUIRE(capture.IdentifierValue() == "hello_world");
|
||||||
|
}
|
||||||
|
|
||||||
|
REQUIRE(!result.HasNextCapture(CAPTURE_NAMESPACE_NAME));
|
||||||
|
});
|
||||||
|
|
||||||
|
REQUIRE(test.PerformTest());
|
||||||
|
REQUIRE(test.GetConsumedTokenCount() == 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Matcher: Can capture in OR matchers", "[parsing][matcher]")
|
||||||
|
{
|
||||||
|
static constexpr auto TAG_NAMESPACE = 1;
|
||||||
|
static constexpr auto TAG_STRUCT = 2;
|
||||||
|
|
||||||
|
static constexpr auto CAPTURE_NAMESPACE_NAME = 1;
|
||||||
|
static constexpr auto CAPTURE_STRUCT_NAME = 2;
|
||||||
|
|
||||||
|
MatchersTestsHelper test;
|
||||||
|
const TokenPos pos;
|
||||||
|
const auto create = test.Factory();
|
||||||
|
test.Matchers({
|
||||||
|
create.Or({
|
||||||
|
create.And({
|
||||||
|
create.Type(HeaderParserValueType::NAMESPACE).Tag(TAG_NAMESPACE),
|
||||||
|
create.Identifier().Capture(CAPTURE_NAMESPACE_NAME),
|
||||||
|
}),
|
||||||
|
create.And({
|
||||||
|
create.Type(HeaderParserValueType::STRUCT).Tag(TAG_STRUCT),
|
||||||
|
create.Identifier().Capture(CAPTURE_STRUCT_NAME),
|
||||||
|
})
|
||||||
|
}),
|
||||||
|
create.Char('{')
|
||||||
|
});
|
||||||
|
|
||||||
|
test.Tokens({
|
||||||
|
HeaderParserValue::Keyword(pos, HeaderParserValueType::NAMESPACE),
|
||||||
|
HeaderParserValue::Identifier(pos, new std::string("hello_world")),
|
||||||
|
HeaderParserValue::Character(pos, '{'),
|
||||||
|
HeaderParserValue::Invalid(pos)
|
||||||
|
});
|
||||||
|
test.MatchCallback([](sequence_result_t& result)
|
||||||
|
{
|
||||||
|
REQUIRE(result.NextTag() == TAG_NAMESPACE);
|
||||||
|
REQUIRE(result.NextTag() == matcher_t::NO_ID);
|
||||||
|
|
||||||
|
REQUIRE(result.HasNextCapture(CAPTURE_NAMESPACE_NAME));
|
||||||
|
{
|
||||||
|
const auto& capture = result.NextCapture(CAPTURE_NAMESPACE_NAME);
|
||||||
|
REQUIRE(capture.m_type == HeaderParserValueType::IDENTIFIER);
|
||||||
|
REQUIRE(capture.IdentifierValue() == "hello_world");
|
||||||
|
}
|
||||||
|
|
||||||
|
REQUIRE(!result.HasNextCapture(CAPTURE_NAMESPACE_NAME));
|
||||||
|
});
|
||||||
|
|
||||||
|
REQUIRE(test.PerformTest());
|
||||||
|
REQUIRE(test.GetConsumedTokenCount() == 3);
|
||||||
|
|
||||||
|
test.Tokens({
|
||||||
|
HeaderParserValue::Keyword(pos, HeaderParserValueType::STRUCT),
|
||||||
|
HeaderParserValue::Identifier(pos, new std::string("bye_struct")),
|
||||||
|
HeaderParserValue::Character(pos, '{'),
|
||||||
|
HeaderParserValue::Invalid(pos)
|
||||||
|
});
|
||||||
|
test.MatchCallback([](sequence_result_t& result)
|
||||||
|
{
|
||||||
|
REQUIRE(result.NextTag() == TAG_STRUCT);
|
||||||
|
REQUIRE(result.NextTag() == matcher_t::NO_ID);
|
||||||
|
|
||||||
|
REQUIRE(result.HasNextCapture(CAPTURE_STRUCT_NAME));
|
||||||
|
{
|
||||||
|
const auto& capture = result.NextCapture(CAPTURE_STRUCT_NAME);
|
||||||
|
REQUIRE(capture.m_type == HeaderParserValueType::IDENTIFIER);
|
||||||
|
REQUIRE(capture.IdentifierValue() == "bye_struct");
|
||||||
|
}
|
||||||
|
|
||||||
|
REQUIRE(!result.HasNextCapture(CAPTURE_STRUCT_NAME));
|
||||||
|
});
|
||||||
|
|
||||||
|
REQUIRE(test.PerformTest());
|
||||||
|
REQUIRE(test.GetConsumedTokenCount() == 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Matcher: Can capture in LOOP matchers", "[parsing][matcher]")
|
||||||
|
{
|
||||||
|
static constexpr auto TAG_NAMESPACE = 1;
|
||||||
|
|
||||||
|
static constexpr auto CAPTURE_NAMESPACE_NAME = 1;
|
||||||
|
|
||||||
|
MatchersTestsHelper test;
|
||||||
|
const TokenPos pos;
|
||||||
|
const auto create = test.Factory();
|
||||||
|
test.Matchers({
|
||||||
|
create.Type(HeaderParserValueType::NAMESPACE).Tag(TAG_NAMESPACE),
|
||||||
|
create.Loop(create.Identifier().Capture(CAPTURE_NAMESPACE_NAME)),
|
||||||
|
create.Char('{')
|
||||||
|
});
|
||||||
|
|
||||||
|
test.Tokens({
|
||||||
|
HeaderParserValue::Keyword(pos, HeaderParserValueType::NAMESPACE),
|
||||||
|
HeaderParserValue::Identifier(pos, new std::string("hello_world")),
|
||||||
|
HeaderParserValue::Identifier(pos, new std::string("hello_universe")),
|
||||||
|
HeaderParserValue::Identifier(pos, new std::string("hello_everyone")),
|
||||||
|
HeaderParserValue::Character(pos, '{'),
|
||||||
|
HeaderParserValue::Invalid(pos)
|
||||||
|
});
|
||||||
|
|
||||||
|
test.MatchCallback([](sequence_result_t& result)
|
||||||
|
{
|
||||||
|
REQUIRE(result.NextTag() == TAG_NAMESPACE);
|
||||||
|
REQUIRE(result.NextTag() == matcher_t::NO_ID);
|
||||||
|
|
||||||
|
REQUIRE(result.HasNextCapture(CAPTURE_NAMESPACE_NAME));
|
||||||
|
{
|
||||||
|
const auto& capture = result.NextCapture(CAPTURE_NAMESPACE_NAME);
|
||||||
|
REQUIRE(capture.m_type == HeaderParserValueType::IDENTIFIER);
|
||||||
|
REQUIRE(capture.IdentifierValue() == "hello_world");
|
||||||
|
}
|
||||||
|
|
||||||
|
REQUIRE(result.HasNextCapture(CAPTURE_NAMESPACE_NAME));
|
||||||
|
{
|
||||||
|
const auto& capture = result.NextCapture(CAPTURE_NAMESPACE_NAME);
|
||||||
|
REQUIRE(capture.m_type == HeaderParserValueType::IDENTIFIER);
|
||||||
|
REQUIRE(capture.IdentifierValue() == "hello_universe");
|
||||||
|
}
|
||||||
|
|
||||||
|
REQUIRE(result.HasNextCapture(CAPTURE_NAMESPACE_NAME));
|
||||||
|
{
|
||||||
|
const auto& capture = result.NextCapture(CAPTURE_NAMESPACE_NAME);
|
||||||
|
REQUIRE(capture.m_type == HeaderParserValueType::IDENTIFIER);
|
||||||
|
REQUIRE(capture.IdentifierValue() == "hello_everyone");
|
||||||
|
}
|
||||||
|
|
||||||
|
REQUIRE(!result.HasNextCapture(CAPTURE_NAMESPACE_NAME));
|
||||||
|
});
|
||||||
|
|
||||||
|
REQUIRE(test.PerformTest());
|
||||||
|
REQUIRE(test.GetConsumedTokenCount() == 5);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Matcher: Capturing an AND group captures all matched tokens", "[parsing][matcher]")
|
||||||
|
{
|
||||||
|
static constexpr auto TAG_AND_GROUP = 1;
|
||||||
|
|
||||||
|
static constexpr auto CAPTURE_AND_GROUP = 1;
|
||||||
|
|
||||||
|
MatchersTestsHelper test;
|
||||||
|
const TokenPos pos;
|
||||||
|
const auto create = test.Factory();
|
||||||
|
test.Matchers({
|
||||||
|
create.And({
|
||||||
|
create.Type(HeaderParserValueType::NAMESPACE),
|
||||||
|
create.Identifier()
|
||||||
|
}).Tag(TAG_AND_GROUP).Capture(CAPTURE_AND_GROUP),
|
||||||
|
create.Char('{')
|
||||||
|
});
|
||||||
|
|
||||||
|
test.Tokens({
|
||||||
|
HeaderParserValue::Keyword(pos, HeaderParserValueType::NAMESPACE),
|
||||||
|
HeaderParserValue::Identifier(pos, new std::string("hello_world")),
|
||||||
|
HeaderParserValue::Character(pos, '{'),
|
||||||
|
HeaderParserValue::Invalid(pos)
|
||||||
|
});
|
||||||
|
|
||||||
|
test.MatchCallback([](sequence_result_t& result)
|
||||||
|
{
|
||||||
|
REQUIRE(result.NextTag() == TAG_AND_GROUP);
|
||||||
|
REQUIRE(result.NextTag() == matcher_t::NO_ID);
|
||||||
|
|
||||||
|
REQUIRE(result.HasNextCapture(CAPTURE_AND_GROUP));
|
||||||
|
REQUIRE(result.NextCapture(CAPTURE_AND_GROUP).m_type == HeaderParserValueType::NAMESPACE);
|
||||||
|
|
||||||
|
REQUIRE(result.HasNextCapture(CAPTURE_AND_GROUP));
|
||||||
|
{
|
||||||
|
const auto& capture = result.NextCapture(CAPTURE_AND_GROUP);
|
||||||
|
REQUIRE(capture.m_type == HeaderParserValueType::IDENTIFIER);
|
||||||
|
REQUIRE(capture.IdentifierValue() == "hello_world");
|
||||||
|
}
|
||||||
|
|
||||||
|
REQUIRE(!result.HasNextCapture(CAPTURE_AND_GROUP));
|
||||||
|
});
|
||||||
|
|
||||||
|
REQUIRE(test.PerformTest());
|
||||||
|
REQUIRE(test.GetConsumedTokenCount() == 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Matcher: Capturing an LOOP group captures all matched tokens", "[parsing][matcher]")
|
||||||
|
{
|
||||||
|
static constexpr auto TAG_LOOP_GROUP = 1;
|
||||||
|
|
||||||
|
static constexpr auto CAPTURE_LOOP_GROUP = 1;
|
||||||
|
|
||||||
|
MatchersTestsHelper test;
|
||||||
|
const TokenPos pos;
|
||||||
|
const auto create = test.Factory();
|
||||||
|
test.Matchers({
|
||||||
|
create.Loop(create.And({
|
||||||
|
create.Type(HeaderParserValueType::NAMESPACE),
|
||||||
|
create.Identifier()
|
||||||
|
})).Tag(TAG_LOOP_GROUP).Capture(CAPTURE_LOOP_GROUP),
|
||||||
|
create.Char('{')
|
||||||
|
});
|
||||||
|
|
||||||
|
test.Tokens({
|
||||||
|
HeaderParserValue::Keyword(pos, HeaderParserValueType::NAMESPACE),
|
||||||
|
HeaderParserValue::Identifier(pos, new std::string("hello_world")),
|
||||||
|
HeaderParserValue::Keyword(pos, HeaderParserValueType::NAMESPACE),
|
||||||
|
HeaderParserValue::Identifier(pos, new std::string("hello_universe")),
|
||||||
|
HeaderParserValue::Character(pos, '{'),
|
||||||
|
HeaderParserValue::Invalid(pos)
|
||||||
|
});
|
||||||
|
|
||||||
|
test.MatchCallback([](sequence_result_t& result)
|
||||||
|
{
|
||||||
|
REQUIRE(result.NextTag() == TAG_LOOP_GROUP);
|
||||||
|
REQUIRE(result.NextTag() == matcher_t::NO_ID);
|
||||||
|
|
||||||
|
REQUIRE(result.HasNextCapture(CAPTURE_LOOP_GROUP));
|
||||||
|
REQUIRE(result.NextCapture(CAPTURE_LOOP_GROUP).m_type == HeaderParserValueType::NAMESPACE);
|
||||||
|
|
||||||
|
REQUIRE(result.HasNextCapture(CAPTURE_LOOP_GROUP));
|
||||||
|
{
|
||||||
|
const auto& capture = result.NextCapture(CAPTURE_LOOP_GROUP);
|
||||||
|
REQUIRE(capture.m_type == HeaderParserValueType::IDENTIFIER);
|
||||||
|
REQUIRE(capture.IdentifierValue() == "hello_world");
|
||||||
|
}
|
||||||
|
|
||||||
|
REQUIRE(result.HasNextCapture(CAPTURE_LOOP_GROUP));
|
||||||
|
REQUIRE(result.NextCapture(CAPTURE_LOOP_GROUP).m_type == HeaderParserValueType::NAMESPACE);
|
||||||
|
|
||||||
|
REQUIRE(result.HasNextCapture(CAPTURE_LOOP_GROUP));
|
||||||
|
{
|
||||||
|
const auto& capture = result.NextCapture(CAPTURE_LOOP_GROUP);
|
||||||
|
REQUIRE(capture.m_type == HeaderParserValueType::IDENTIFIER);
|
||||||
|
REQUIRE(capture.IdentifierValue() == "hello_universe");
|
||||||
|
}
|
||||||
|
|
||||||
|
REQUIRE(!result.HasNextCapture(CAPTURE_LOOP_GROUP));
|
||||||
|
});
|
||||||
|
|
||||||
|
REQUIRE(test.PerformTest());
|
||||||
|
REQUIRE(test.GetConsumedTokenCount() == 5);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Matcher: Capture transform works", "[parsing][matcher]")
|
||||||
|
{
|
||||||
|
static constexpr auto LABEL_TYPENAME = 1;
|
||||||
|
|
||||||
|
static constexpr auto CAPTURE_TYPENAME = 1;
|
||||||
|
|
||||||
|
MatchersTestsHelper test;
|
||||||
|
const TokenPos pos;
|
||||||
|
const auto create = test.Factory();
|
||||||
|
test.Matchers(
|
||||||
|
{
|
||||||
|
create.Type(HeaderParserValueType::STRUCT),
|
||||||
|
create.Label(LABEL_TYPENAME).Capture(CAPTURE_TYPENAME),
|
||||||
|
create.Char('{')
|
||||||
|
});
|
||||||
|
test.LabeledMatchers(
|
||||||
|
{
|
||||||
|
create.And({
|
||||||
|
create.Identifier(),
|
||||||
|
create.OptionalLoop(create.And({
|
||||||
|
create.Char(':'),
|
||||||
|
create.Char(':'),
|
||||||
|
create.Identifier()
|
||||||
|
}))
|
||||||
|
}).Transform([](std::vector<std::reference_wrapper<const HeaderParserValue>>& values)
|
||||||
|
{
|
||||||
|
return HeaderParserValue::TypeName(values[0].get().GetPos(), new std::string());
|
||||||
|
})
|
||||||
|
}, LABEL_TYPENAME);
|
||||||
|
|
||||||
|
test.Tokens({
|
||||||
|
HeaderParserValue::Keyword(pos, HeaderParserValueType::STRUCT),
|
||||||
|
HeaderParserValue::Identifier(pos, new std::string("hello")),
|
||||||
|
HeaderParserValue::Character(pos, ':'),
|
||||||
|
HeaderParserValue::Character(pos, ':'),
|
||||||
|
HeaderParserValue::Identifier(pos, new std::string("world")),
|
||||||
|
HeaderParserValue::Character(pos, '{'),
|
||||||
|
HeaderParserValue::Invalid(pos)
|
||||||
|
});
|
||||||
|
|
||||||
|
test.MatchCallback([](sequence_result_t& result)
|
||||||
|
{
|
||||||
|
REQUIRE(result.NextTag() == matcher_t::NO_ID);
|
||||||
|
|
||||||
|
REQUIRE(result.HasNextCapture(CAPTURE_TYPENAME));
|
||||||
|
{
|
||||||
|
const auto& capture = result.NextCapture(CAPTURE_TYPENAME);
|
||||||
|
REQUIRE(capture.m_type == HeaderParserValueType::TYPE_NAME);
|
||||||
|
REQUIRE(capture.TypeNameValue() == "hello::world");
|
||||||
|
}
|
||||||
|
|
||||||
|
REQUIRE(!result.HasNextCapture(CAPTURE_TYPENAME));
|
||||||
|
});
|
||||||
|
|
||||||
|
REQUIRE(test.PerformTest());
|
||||||
|
REQUIRE(test.GetConsumedTokenCount() == 6);
|
||||||
|
}
|
||||||
|
}
|
61
test/ZoneCodeGeneratorLibTests/Parsing/Mock/MockLexer.h
Normal file
61
test/ZoneCodeGeneratorLibTests/Parsing/Mock/MockLexer.h
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <iterator>
|
||||||
|
|
||||||
|
#include "Utils/ClassUtils.h"
|
||||||
|
#include "Parsing/ILexer.h"
|
||||||
|
|
||||||
|
template <typename TokenType>
|
||||||
|
class MockLexer final : public ILexer<TokenType>
|
||||||
|
{
|
||||||
|
// TokenType must inherit IParserValue
|
||||||
|
static_assert(std::is_base_of<IParserValue, TokenType>::value);
|
||||||
|
|
||||||
|
std::vector<TokenType> m_tokens;
|
||||||
|
//std::vector<HeaderParserValue> m_tokens;
|
||||||
|
TokenType m_eof;
|
||||||
|
int m_pop_count;
|
||||||
|
|
||||||
|
public:
|
||||||
|
MockLexer(std::initializer_list<Movable<TokenType>> tokens, TokenType eof)
|
||||||
|
: m_tokens(std::make_move_iterator(tokens.begin()), std::make_move_iterator(tokens.end())),
|
||||||
|
m_eof(std::move(eof)),
|
||||||
|
m_pop_count(0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
~MockLexer() override = default;
|
||||||
|
MockLexer(const MockLexer& other) = delete;
|
||||||
|
MockLexer(MockLexer&& other) noexcept = default;
|
||||||
|
MockLexer& operator=(const MockLexer& other) = delete;
|
||||||
|
MockLexer& operator=(MockLexer&& other) noexcept = default;
|
||||||
|
|
||||||
|
const TokenType& GetToken(const unsigned index) override
|
||||||
|
{
|
||||||
|
if (index < m_tokens.size())
|
||||||
|
return m_tokens[index];
|
||||||
|
|
||||||
|
return m_eof;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PopTokens(const int amount) override
|
||||||
|
{
|
||||||
|
m_pop_count += amount;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsEof() override
|
||||||
|
{
|
||||||
|
return !m_tokens.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
const TokenPos& GetPos() override
|
||||||
|
{
|
||||||
|
return !m_tokens.empty() ? m_tokens[0].GetPos() : m_eof.GetPos();
|
||||||
|
}
|
||||||
|
|
||||||
|
_NODISCARD int GetPopCount() const
|
||||||
|
{
|
||||||
|
return m_pop_count;
|
||||||
|
}
|
||||||
|
};
|
49
test/ZoneCodeGeneratorLibTests/Parsing/Mock/MockSequence.h
Normal file
49
test/ZoneCodeGeneratorLibTests/Parsing/Mock/MockSequence.h
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Parsing/Sequence/AbstractSequence.h"
|
||||||
|
|
||||||
|
struct MockSequenceState
|
||||||
|
{
|
||||||
|
char m_dummy;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename TokenType>
|
||||||
|
class MockSequence final : public AbstractSequence<TokenType, MockSequenceState>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
typedef AbstractSequence<TokenType, MockSequenceState> parent_t;
|
||||||
|
|
||||||
|
private:
|
||||||
|
using parent_t::AddMatchers;
|
||||||
|
using parent_t::AddLabeledMatchers;
|
||||||
|
|
||||||
|
std::function<void(SequenceResult<TokenType>&)> m_handler;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void ProcessMatch(MockSequenceState* state, SequenceResult<TokenType>& result) const override
|
||||||
|
{
|
||||||
|
if (m_handler)
|
||||||
|
m_handler(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
void AddMockMatchers(std::initializer_list<Movable<std::unique_ptr<typename parent_t::matcher_t>>> matchers)
|
||||||
|
{
|
||||||
|
AddMatchers(matchers);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AddMockLabeledMatchers(std::initializer_list<Movable<std::unique_ptr<typename parent_t::matcher_t>>> matchers, const int label)
|
||||||
|
{
|
||||||
|
AddLabeledMatchers(matchers, label);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Handle(std::function<void(SequenceResult<TokenType>&)> handler)
|
||||||
|
{
|
||||||
|
m_handler = std::move(handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
IMatcherForLabelSupplier<TokenType>* GetLabelSupplier()
|
||||||
|
{
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
};
|
Loading…
x
Reference in New Issue
Block a user