From 30edd863f98df929326f2706c9a2ed32730a225b Mon Sep 17 00:00:00 2001 From: John Hodge Date: Mon, 7 Mar 2016 11:09:38 +0800 Subject: Expand - Start on macro_rules expanding --- src/ast/ast.hpp | 4 ++- src/expand/macro_rules.cpp | 50 +++++++++++++++++++++++++++ src/expand/macro_rules.hpp | 15 ++++++++ src/expand/mod.cpp | 85 +++++++++++++++++++++++++++++++++++++--------- src/macros.cpp | 28 +++++++-------- src/macros.hpp | 1 + src/parse/common.hpp | 1 + 7 files changed, 152 insertions(+), 32 deletions(-) create mode 100644 src/expand/macro_rules.hpp (limited to 'src') diff --git a/src/ast/ast.hpp b/src/ast/ast.hpp index ea518eab..93652a9a 100644 --- a/src/ast/ast.hpp +++ b/src/ast/ast.hpp @@ -431,7 +431,9 @@ public: void add_macro(bool is_exported, ::std::string name, MacroRules macro) { m_macros.push_back( Named( move(name), move(macro), is_exported ) ); } - void add_macro_import(const Crate& crate, ::std::string mod, ::std::string name); + void add_macro_import(::std::string name, const MacroRules& mr) { + m_macro_import_res.push_back( NamedNS( mv$(name), &mr, false ) ); + } void add_macro_invocation(MacroInvocation item) { m_macro_invocations.push_back( mv$(item) ); } diff --git a/src/expand/macro_rules.cpp b/src/expand/macro_rules.cpp index d860aaa3..4ef39c01 100644 --- a/src/expand/macro_rules.cpp +++ b/src/expand/macro_rules.cpp @@ -3,6 +3,7 @@ #include "../ast/expr.hpp" #include "../ast/ast.hpp" #include "../parse/common.hpp" +#include "macro_rules.hpp" class CMacroRulesExpander: public ExpandProcMacro @@ -18,11 +19,60 @@ class CMacroRulesExpander: TTStream lex(tt); auto mac = Parse_MacroRules(lex); // TODO: Place into current module using `ident` as the name + mod.add_macro( false, ident, mac ); return AST::Expr(); } }; +class CMacroUseHandler: + public ExpandDecorator +{ + AttrStage stage() const override { return AttrStage::EarlyPost; } + + void handle(const AST::MetaItem& mi, AST::Crate& crate, const AST::Path& path, AST::Module& mod, AST::Item& i) const override + { + if( !i.is_Module() ) + throw ::std::runtime_error("ERROR: Use of #[macro_use] on non-module"); + + const auto& submod = i.as_Module().e; + + if( mi.has_sub_items() ) + { + } + else + { + for( const auto& mr : submod.macros() ) + { + mod.add_macro_import( mr.name, mr.data ); + } + } + + throw ::std::runtime_error("TODO: #[macro_use]"); + } + +}; + +AST::Expr Macro_Invoke(const char* name, const MacroRules& rules, const TokenTree& tt, AST::Module& mod, MacroPosition position) +{ + auto out_tt = Macro_InvokeRules(name, rules, tt); + TokenStream& lex = *out_tt; + // TODO: Expand out_tt + switch(position) + { + case MacroPosition::Item: { + LList l(nullptr, &mod); + Parse_ModRoot_Items(lex, mod, l, false, "-"); + return AST::Expr(); + } + default: + throw ::std::runtime_error("TODO: Macro in non-item position"); + //case MacroPosition::Stmt: { + // break; } + } +} + STATIC_MACRO("macro_rules", CMacroRulesExpander); +STATIC_DECORATOR("macro_use", CMacroUseHandler); diff --git a/src/expand/macro_rules.hpp b/src/expand/macro_rules.hpp new file mode 100644 index 00000000..81e9b18a --- /dev/null +++ b/src/expand/macro_rules.hpp @@ -0,0 +1,15 @@ +/** + * Binding header for the macro_rules syntax extension + */ +#pragma once + +#include +#include "../macros.hpp" + +namespace AST { + class Expr; + class Module; +} +class TokenTree; + +extern AST::Expr Macro_Invoke(const char* name, const MacroRules& rules, const TokenTree& tt, AST::Module& mod, MacroPosition position); diff --git a/src/expand/mod.cpp b/src/expand/mod.cpp index 368360bd..cb7667f8 100644 --- a/src/expand/mod.cpp +++ b/src/expand/mod.cpp @@ -5,6 +5,7 @@ #include #include #include +#include "macro_rules.hpp" ::std::map< ::std::string, ::std::unique_ptr > g_decorators; ::std::map< ::std::string, ::std::unique_ptr > g_macros; @@ -21,41 +22,93 @@ void Expand_Attrs(const ::AST::MetaItems& attrs, AttrStage stage, ::AST::Crate& for( auto& a : attrs.m_items ) { for( auto& d : g_decorators ) { - if( d.first == a.name() && d.second->stage() == stage ) { - d.second->handle(a, crate, path, mod, item); + if( d.first == a.name() ) { + DEBUG("#[" << d.first << "]"); + if( d.second->stage() == stage ) { + d.second->handle(a, crate, path, mod, item); + } } } } } +AST::Expr Expand_Macro(bool is_early, ::AST::Module& mod, ::AST::MacroInvocation& mi, MacroPosition pos) +{ + for( const auto& m : g_macros ) + { + if( mi.name() == m.first && m.second->expand_early() == is_early ) + { + auto e = m.second->expand(mi.input_ident(), mi.input_tt(), mod, MacroPosition::Item); + mi.clear(); + return e; + } + } + + + for( const auto& mr : mod.macros() ) + { + if( mr.name == mi.name() ) + { + if( mi.input_ident() != "" ) + ; // TODO: ERROR - macro_rules! macros can't take an ident + + auto e = Macro_Invoke(mr.name.c_str(), mr.data, mi.input_tt(), mod, MacroPosition::Item); + mi.clear(); + return e; + } + } + for( const auto& mri : mod.macro_imports_res() ) + { + if( mri.name == mi.name() ) + { + if( mi.input_ident() != "" ) + ; // TODO: ERROR - macro_rules! macros can't take an ident + + auto e = Macro_Invoke(mi.name().c_str(), *mri.data, mi.input_tt(), mod, MacroPosition::Item); + mi.clear(); + return e; + } + } + + if( ! is_early ) { + // TODO: Error - Unknown macro name + throw ::std::runtime_error( FMT("Unknown macro '" << mi.name() << "'") ); + } + + // Leave valid and return an empty expression + return AST::Expr(); +} + void Expand_Mod(bool is_early, ::AST::Crate& crate, ::AST::Path modpath, ::AST::Module& mod) { TRACE_FUNCTION_F("is_early = " << is_early << ", modpath = " << modpath); // 1. Macros first - for( auto& mi : mod.macro_invs() ) + //for( auto& mi : mod.macro_invs() ) + for(unsigned int i = 0; i < mod.macro_invs().size(); i ++ ) { - if( mi.name() == "" ) - continue ; - for( auto& m : g_macros ) { - if( mi.name() == m.first && m.second->expand_early() == is_early ) { - m.second->expand(mi.input_ident(), mi.input_tt(), mod, MacroPosition::Item); - - mi.clear(); - break; + auto& mi = mod.macro_invs()[i]; + if( mi.name() != "" ) + { + // Move out of the module to avoid invalidation if a new macro invocation is added + auto mi_owned = mv$(mi); + + auto rv = Expand_Macro(is_early, mod, mi_owned, MacroPosition::Item); + if( rv.is_valid() ) + ; // TODO: ERROR - macro yeilded an expression in item position + + if( mi_owned.name() != "" ) + { + mod.macro_invs()[i] = mv$(mi_owned); } } - - if( ! is_early && mi.name() != "" ) { - // TODO: Error - Unknown macro name - throw ::std::runtime_error( FMT("Unknown macro '" << mi.name() << "'") ); - } } // 2. General items DEBUG("Items"); for( auto& i : mod.items() ) { + DEBUG("- " << i.name); ::AST::Path path = modpath + i.name; Expand_Attrs(i.data.attrs, (is_early ? AttrStage::EarlyPre : AttrStage::LatePre), crate, path, mod, i.data); diff --git a/src/macros.cpp b/src/macros.cpp index d7d30f4e..5a45156e 100644 --- a/src/macros.cpp +++ b/src/macros.cpp @@ -108,7 +108,6 @@ class MacroExpander: public: private: - const TokenStream& m_olex; const ::std::string m_crate_name; const ::std::vector& m_root_contents; const ParameterMappings m_mappings; @@ -131,7 +130,6 @@ private: public: MacroExpander(const MacroExpander& x): - m_olex(x.m_olex), m_crate_name(x.m_crate_name), m_root_contents(x.m_root_contents), m_mappings(x.m_mappings), @@ -140,8 +138,7 @@ public: { prep_counts(); } - MacroExpander(const TokenStream& olex, const ::std::vector& contents, ParameterMappings mappings, ::std::string crate_name): - m_olex(olex), + MacroExpander(const ::std::vector& contents, ParameterMappings mappings, ::std::string crate_name): m_crate_name(crate_name), m_root_contents(contents), m_mappings(mappings), @@ -354,7 +351,7 @@ bool Macro_HandlePattern(TTStream& lex, const MacroPatEnt& pat, unsigned int lay return true; } -::std::unique_ptr Macro_InvokeInt(const TokenStream& olex, const char *name, const MacroRules& rules, TokenTree input) +::std::unique_ptr Macro_InvokeRules(const char *name, const MacroRules& rules, TokenTree input) { TRACE_FUNCTION; @@ -396,7 +393,7 @@ bool Macro_HandlePattern(TTStream& lex, const MacroPatEnt& pat, unsigned int lay } DEBUG("TODO: Obtain crate name correctly"); - TokenStream* ret_ptr = new MacroExpander(olex, rule.m_contents, bound_tts, ""); + TokenStream* ret_ptr = new MacroExpander(rule.m_contents, bound_tts, ""); // HACK! Disable nested macro expansion //ret_ptr->parse_state().no_expand_macros = true; @@ -409,9 +406,10 @@ bool Macro_HandlePattern(TTStream& lex, const MacroPatEnt& pat, unsigned int lay i ++; } DEBUG(""); - throw ParseError::Todo(olex, "Error when macro fails to match"); + throw ParseError::Todo(/*source_span, */"Error when macro fails to match"); } +#if 0 ::std::unique_ptr Macro_Invoke(const TokenStream& olex, const ::std::string& name, TokenTree input) { DEBUG("Invoke " << name << " from " << olex.getPosition()); @@ -445,7 +443,7 @@ bool Macro_HandlePattern(TTStream& lex, const MacroPatEnt& pat, unsigned int lay t_macro_regs::iterator macro_reg = g_macro_registrations.find(name); if( macro_reg != g_macro_registrations.end() ) { - return Macro_InvokeInt(olex, macro_reg->first.c_str(), macro_reg->second, input); + return Macro_InvokeRules(olex.getPosition(), macro_reg->first.c_str(), macro_reg->second, input); } // Search import list @@ -459,7 +457,7 @@ bool Macro_HandlePattern(TTStream& lex, const MacroPatEnt& pat, unsigned int lay DEBUG("- [local] " << m.name); if( m.name == name ) { - return Macro_InvokeInt(olex, m.name.c_str(), m.data, input); + return Macro_InvokeRules(olex.getPosition(), m.name.c_str(), m.data, input); } } @@ -468,18 +466,18 @@ bool Macro_HandlePattern(TTStream& lex, const MacroPatEnt& pat, unsigned int lay DEBUG("- [imp]" << mi.name); if( mi.name == name ) { - return Macro_InvokeInt(olex, mi.name.c_str(), *mi.data, input); + return Macro_InvokeRules(olex.getPosition(), mi.name.c_str(), *mi.data, input); } } } throw ParseError::Generic(olex, FMT("Macro '" << name << "' was not found") ); } +#endif Position MacroExpander::getPosition() const { - DEBUG("olex.getPosition() = " << m_olex.getPosition()); return Position(FMT("Macro:" << ""), 0, m_offsets[0].read_pos); } Token MacroExpander::realGetToken() @@ -722,10 +720,10 @@ void Macro_Invoke_Concat_Once(::std::string& s, TokenStream& lex, enum eTokenTyp { // Special case, expand both concat! and stringify! internally // TODO: Invoke - auto tt = Parse_TT(lex, false); - auto slex = Macro_Invoke(lex, tok.str(), tt); - Macro_Invoke_Concat_Once(s, (*slex), exp); - GET_CHECK_TOK(tok, (*slex), TOK_EOF); + //auto tt = Parse_TT(lex, false); + //auto slex = Macro_Invoke(lex, tok.str(), tt); + //Macro_Invoke_Concat_Once(s, (*slex), exp); + //GET_CHECK_TOK(tok, (*slex), TOK_EOF); } else if( tok.type() == exp ) { diff --git a/src/macros.hpp b/src/macros.hpp index d7efec1a..14b4add2 100644 --- a/src/macros.hpp +++ b/src/macros.hpp @@ -149,6 +149,7 @@ typedef ::std::vector MacroRules; extern const LList* Macro_GetModule(); extern void Macro_SetModule(const LList& mod); +extern ::std::unique_ptr Macro_InvokeRules(const char *name, const MacroRules& rules, TokenTree input); extern ::std::unique_ptr Macro_Invoke(const TokenStream& lex, const ::std::string& name, TokenTree input); #endif // MACROS_HPP_INCLUDED diff --git a/src/parse/common.hpp b/src/parse/common.hpp index def67ef4..4b6ceb54 100644 --- a/src/parse/common.hpp +++ b/src/parse/common.hpp @@ -52,6 +52,7 @@ extern MacroRules Parse_MacroRules(TokenStream& lex); extern void Parse_ExternCrate(TokenStream& lex, AST::Module& mod, AST::MetaItems meta_items); extern void Parse_Mod_Item(TokenStream& lex, LList& modstack, bool file_controls_dir, const ::std::string& file_path, AST::Module& mod, bool is_public, AST::MetaItems meta_items); +extern void Parse_ModRoot_Items(TokenStream& lex, AST::Module& mod, LList& modstack, bool file_controls_dir, const ::std::string& path); extern AST::Function Parse_FunctionDef(TokenStream& lex, ::std::string abi, AST::MetaItems attrs, bool allow_self, bool can_be_prototype); -- cgit v1.2.3