Created
April 12, 2014 15:06
-
-
Save vittorioromeo/10540197 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #include <SSVUtils/SSVUtils.hpp> | |
| namespace Eng | |
| { | |
| template<typename TTokenType, typename TTokenDataType, typename TASTType> struct LangSpec | |
| { | |
| using TokenType = TTokenType; | |
| using TokenDataType = TTokenDataType; | |
| using ASTType = TASTType; | |
| }; | |
| template<typename TL> using TokenType = typename TL::TokenType; | |
| template<typename TL> using TokenDataType = typename TL::TokenDataType; | |
| template<typename TL> using ASTType = typename TL::ASTType; | |
| template<typename TL> class Token | |
| { | |
| private: | |
| TokenType<TL> type; | |
| TokenDataType<TL> data; | |
| public: | |
| inline Token(const TokenType<TL>& mType) noexcept : type{mType} { } | |
| inline Token(const TokenType<TL>& mType, const TokenDataType<TL>& mData) : Token{mType}, data{mData} { } | |
| inline const TokenType<TL>& getType() const noexcept { return type; } | |
| inline const TokenDataType<TL>& getData() const noexcept { return data; } | |
| }; | |
| template<typename TL> class ASTImpl | |
| {}; | |
| template<typename TL> class ASTNode | |
| { | |
| private: | |
| ASTType<TL> type; | |
| ssvu::Uptr<ASTImpl<TL>> impl; | |
| ASTNode<TL>* parent{nullptr}; | |
| std::vector<ssvu::Uptr<ASTNode<TL>>> children; | |
| public: | |
| template<typename T, typename... TArgs> T& emplaceChild(TArgs&&... mArgs) | |
| { | |
| auto& result(ssvu::getEmplaceUptr<T>(children, std::forward<TArgs>(mArgs)...)); | |
| result.parent = this; | |
| return result; | |
| } | |
| inline ASTImpl<TL>* getImpl() noexcept { return impl.get(); } | |
| inline ASTNode<TL>* getParent() noexcept { return parent; } | |
| inline decltype(children)& getChildren() noexcept { return children; } | |
| template<typename T> T& getImplAs() noexcept | |
| { | |
| SSVU_ASSERT(impl != nullptr); | |
| return *reinterpret_cast<T*>(impl.get()); | |
| } | |
| }; | |
| enum class ParseletType{Token, Node}; | |
| template<typename TL> class Parselet | |
| { | |
| private: | |
| ParseletType type; | |
| union | |
| { | |
| Token<TL> token; | |
| ASTNode<TL> node; | |
| }; | |
| public: | |
| inline ParseletType getType() const noexcept { return type; } | |
| inline decltype(token)& getToken() noexcept { SSVU_ASSERT(type == ParseletType::Token); return token; } | |
| inline decltype(node)& getNode() noexcept { SSVU_ASSERT(type == ParseletType::Node); return node; } | |
| }; | |
| template<typename TL> class RulePart | |
| { | |
| private: | |
| ParseletType type; | |
| union | |
| { | |
| TokenType<TL> tokenType; | |
| ASTType<TL> astType; | |
| }; | |
| public: | |
| inline RulePart(TokenType<TL> mTokenType) noexcept : type{ParseletType::Token}, tokenType{mTokenType} { } | |
| inline RulePart(ASTType<TL> mASTType) noexcept : type{ParseletType::Node}, astType{mASTType} { } | |
| inline ParseletType getType() const noexcept { return type; } | |
| inline const decltype(tokenType)& getTokenType() const noexcept { SSVU_ASSERT(type == ParseletType::Token); return tokenType; } | |
| inline const decltype(astType)& getASTType() const noexcept { SSVU_ASSERT(type == ParseletType::Token); return astType; } | |
| inline bool operator==(const RulePart<TL>& mRhs) const noexcept | |
| { | |
| if(type != mRhs.type) return false; | |
| if(type == ParseletType::Token && tokenType == mRhs.tokenType) return true; | |
| if(type == ParseletType::Node && astType == mRhs.astType) return true; | |
| return false; | |
| } | |
| inline bool operator!=(const RulePart<TL>& mRhs) const noexcept { return !this->operator==(mRhs); } | |
| }; | |
| template<typename TL> class RuleKey | |
| { | |
| private: | |
| std::vector<RulePart<TL>> ruleParts; | |
| template<typename T> inline void ctorImpl(T mP) { ruleParts.emplace_back(mP); } | |
| template<typename T1, typename T2, typename... TArgs> inline void ctorImpl(T1 mP1, T2 mP2, TArgs... mArgs) | |
| { | |
| ctorImpl(mP1); ctorImpl(mP2, mArgs...); | |
| } | |
| template<std::size_t TIdx> inline bool matchesImpl(const RulePart<TL>& mPart) const { return mPart == ruleParts.at(TIdx); } | |
| template<std::size_t TIdx, typename T1, typename T2, typename... TArgs> inline bool matchesImpl(T1 mP1, T2 mP2, TArgs... mArgs) const | |
| { | |
| return !matchesImpl<TIdx>(mP1) ? false : matchesImpl<TIdx + 1>(mP2, mArgs...); | |
| } | |
| public: | |
| template<typename... TArgs> inline RuleKey(TArgs... mArgs) | |
| { | |
| ctorImpl(mArgs...); | |
| } | |
| template<typename... TArgs> inline bool matches(TArgs... mArgs) | |
| { | |
| return sizeof...(TArgs) != ruleParts.size() ? false : matchesImpl<0>(mArgs...); | |
| } | |
| }; | |
| template<typename TL> class Rule | |
| { | |
| private: | |
| RuleKey<TL> ruleKey; | |
| ASTType<TL> result; | |
| ssvu::Func<ssvu::Uptr<ASTImpl<TL>>(const std::vector<Parselet<TL>>&)> func; | |
| public: | |
| inline Rule(RuleKey<TL> mKey, ASTType<TL> mResult, const decltype(func)& mFunc) : | |
| ruleKey{std::move(mKey)}, result{mResult}, func{mFunc} { } | |
| }; | |
| template<typename TL> class RuleSet | |
| { | |
| private: | |
| public: | |
| template<typename... TArgs> inline void createRule(TArgs&&... mArgs) | |
| { | |
| Rule<TL> result(std::forward<TArgs>(mArgs)...); | |
| } | |
| }; | |
| template<typename TL> class Parser | |
| { | |
| private: | |
| std::vector<Token<TL>> sourceStack; | |
| std::vector<Parselet<TL>> parseStack, nodeStack; | |
| public: | |
| inline void pushOnSource(Token<TL> mToken) { sourceStack.emplace_back(std::move(mToken)); } | |
| inline void pushOnParse(Parselet<TL> mParselet) { parseStack.emplace_back(std::move(mParselet)); } | |
| inline void pushOnNode(Parselet<TL> mParselet) { nodeStack.emplace_back(std::move(mParselet)); } | |
| inline void shift() | |
| { | |
| SSVU_ASSERT(!sourceStack.empty()); | |
| // Take top of source stack | |
| const auto& tkn(sourceStack.back()); | |
| // Push it both on parse and node stacks | |
| pushOnParse(tkn); | |
| pushOnNode(tkn); | |
| // Pop from source stack | |
| sourceStack.pop_back(); | |
| } | |
| inline void reduceRecursively() | |
| { | |
| } | |
| }; | |
| } | |
| namespace Lang | |
| { | |
| enum class Tkn | |
| { | |
| Number, | |
| POpen, | |
| PClose | |
| }; | |
| struct TknData { }; | |
| enum class ASTT | |
| { | |
| Expr, | |
| Number | |
| }; | |
| using Spec = Eng::LangSpec<Tkn, TknData, ASTT>; | |
| struct ASTExpr : public Eng::ASTImpl<Spec> | |
| { | |
| inline virtual void eval() { } | |
| }; | |
| struct ASTNumber : public ASTExpr | |
| { | |
| int value; | |
| inline ASTNumber(int mValue) : value{mValue} { } | |
| inline void eval() override { } | |
| }; | |
| } | |
| int main() | |
| { | |
| using namespace Eng; | |
| using namespace Lang; | |
| RuleSet<Spec> ruleSet; | |
| ruleSet.createRule(RuleKey<Spec>{Tkn::Number}, ASTT::Number, [](const std::vector<Parselet<Spec>>& mParselets) | |
| { | |
| //return std::make_unique<ASTNumber>(mParselets[0].getToken()) | |
| return std::make_unique<ASTNumber>(1); | |
| }); | |
| //ruleSet.createRule(RuleKey<Spec>{ASTT::Expr, Tkn::Plus, ASTT::Expr}, ASTT::AddOp); | |
| RuleKey<Spec> testKey{Tkn::Number, ASTT::Number}; | |
| ssvu::lo() << testKey.matches(Tkn::Number, ASTT::Number) << std::endl; | |
| //ssvu::lo() << testKey.matches(ASTT::Number, Tkn::Number) << std::endl; | |
| return 0; | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment