diff options
author | John Hodge <tpg@mutabah.net> | 2016-03-06 22:07:41 +0800 |
---|---|---|
committer | John Hodge <tpg@mutabah.net> | 2016-03-06 22:07:41 +0800 |
commit | 150a481100bba025bc5132338ae3d37f19de5bfc (patch) | |
tree | ff93347bccdd826ae1bc0ce1aeb4710c8210e852 | |
parent | 1573cf55ff6f38f51716bfe92b70341fa5489c74 (diff) | |
download | mrust-150a481100bba025bc5132338ae3d37f19de5bfc.tar.gz |
Move macro_rules parsing and expansion to expand/synexts
-rw-r--r-- | Makefile | 4 | ||||
-rw-r--r-- | src/ast/ast.cpp | 2 | ||||
-rw-r--r-- | src/ast/ast.hpp | 3 | ||||
-rw-r--r-- | src/ast/macro.hpp | 12 | ||||
-rw-r--r-- | src/expand/macro_rules.cpp | 28 | ||||
-rw-r--r-- | src/expand/mod.cpp | 110 | ||||
-rw-r--r-- | src/include/main_bindings.hpp | 5 | ||||
-rw-r--r-- | src/include/synext.hpp | 28 | ||||
-rw-r--r-- | src/main.cpp | 5 | ||||
-rw-r--r-- | src/parse/common.hpp | 2 | ||||
-rw-r--r-- | src/parse/expr.cpp | 48 | ||||
-rw-r--r-- | src/parse/macro_rules.cpp | 245 | ||||
-rw-r--r-- | src/parse/root.cpp | 266 | ||||
-rw-r--r-- | src/synexts/derive.cpp | 2 | ||||
-rw-r--r-- | src/synexts/lang_item.cpp | 2 |
15 files changed, 420 insertions, 342 deletions
@@ -28,8 +28,8 @@ OBJ += span.o OBJ += ast/ast.o ast/crate.o ast/path.o ast/expr.o ast/pattern.o OBJ += ast/provided_module.o OBJ += parse/parseerror.o parse/lex.o -OBJ += parse/root.o parse/paths.o parse/types.o parse/expr.o parse/pattern.o -OBJ += expand/mod.o +OBJ += parse/root.o parse/paths.o parse/types.o parse/expr.o parse/pattern.o parse/macro_rules.o +OBJ += expand/mod.o expand/macro_rules.o OBJ += dump_as_rust.o OBJ += convert/ast_iterate.o #OBJ += convert/decorators.o diff --git a/src/ast/ast.cpp b/src/ast/ast.cpp index 33741397..a413c64e 100644 --- a/src/ast/ast.cpp +++ b/src/ast/ast.cpp @@ -345,7 +345,7 @@ template<typename T> typename ::std::vector<Named<T> >::const_iterator find_named(const ::std::vector<Named<T> >& vec, const ::std::string& name)
{
return ::std::find_if(vec.begin(), vec.end(), [&name](const Named<T>& x) {
- DEBUG("find_named - x.name = " << x.name);
+ //DEBUG("find_named - x.name = " << x.name);
return x.name == name;
});
}
diff --git a/src/ast/ast.hpp b/src/ast/ast.hpp index 9eba0307..ea518eab 100644 --- a/src/ast/ast.hpp +++ b/src/ast/ast.hpp @@ -435,6 +435,8 @@ public: void add_macro_invocation(MacroInvocation item) {
m_macro_invocations.push_back( mv$(item) );
}
+
+
unsigned int add_anon_module(Module* mod_ptr) {
auto it = ::std::find(m_anon_modules.begin(), m_anon_modules.end(), mod_ptr);
@@ -505,6 +507,7 @@ public: const ::std::vector<Module*>& anon_mods() const { return m_anon_modules; }
+ ::std::vector<MacroInvocation>& macro_invs() { return m_macro_invocations; }
const NamedList<MacroRules>& macros() const { return m_macros; }
const ::std::vector<NamedNS<const MacroRules*> > macro_imports_res() const { return m_macro_import_res; }
diff --git a/src/ast/macro.hpp b/src/ast/macro.hpp index d80db7bf..4696c732 100644 --- a/src/ast/macro.hpp +++ b/src/ast/macro.hpp @@ -33,6 +33,18 @@ public: return ::std::unique_ptr<MacroInvocation>(i); } + void clear() { + m_macro_name = ""; + m_ident = ""; + m_input = TokenTree(); + } + + const ::std::string& name() const { return m_macro_name; } + + const ::std::string& input_ident() const { return m_ident; } + const TokenTree& input_tt() const { return m_input; } + + SERIALISABLE_PROTOTYPES(); friend ::std::ostream& operator<<(::std::ostream& os, const MacroInvocation& x) { diff --git a/src/expand/macro_rules.cpp b/src/expand/macro_rules.cpp new file mode 100644 index 00000000..d860aaa3 --- /dev/null +++ b/src/expand/macro_rules.cpp @@ -0,0 +1,28 @@ + +#include <synext.hpp> +#include "../ast/expr.hpp" +#include "../ast/ast.hpp" +#include "../parse/common.hpp" + +class CMacroRulesExpander: + public ExpandProcMacro +{ + bool expand_early() const override { return true; } + + AST::Expr expand(const ::std::string& ident, const TokenTree& tt, AST::Module& mod, MacroPosition position) + { + if( ident == "" ) { + throw ::std::runtime_error( "ERROR: macro_rules! requires an identifier" ); + } + + TTStream lex(tt); + auto mac = Parse_MacroRules(lex); + // TODO: Place into current module using `ident` as the name + + return AST::Expr(); + } +}; + + +STATIC_MACRO("macro_rules", CMacroRulesExpander); + diff --git a/src/expand/mod.cpp b/src/expand/mod.cpp index ee6fcfe5..368360bd 100644 --- a/src/expand/mod.cpp +++ b/src/expand/mod.cpp @@ -12,28 +12,60 @@ void Register_Synext_Decorator(::std::string name, ::std::unique_ptr<ExpandDecorator> handler) { g_decorators[name] = mv$(handler); } +void Register_Synext_Macro(::std::string name, ::std::unique_ptr<ExpandProcMacro> handler) { + g_macros[name] = mv$(handler); +} -void Expand_Decorators_Mod(::AST::Crate& crate, bool is_before_macros, ::AST::Path modpath, ::AST::Module& mod) +void Expand_Attrs(const ::AST::MetaItems& attrs, AttrStage stage, ::AST::Crate& crate, const ::AST::Path& path, ::AST::Module& mod, ::AST::Item& item) { - TRACE_FUNCTION_F("modpath = " << modpath); - for( auto& i : mod.items() ) + for( auto& a : attrs.m_items ) { - ::AST::Path path = modpath + i.name; - for( auto& a : i.data.attrs.m_items ) - { - for( auto& d : g_decorators ) { - if( d.first == a.name() && d.second->expand_before_macros() == is_before_macros ) { - d.second->handle(a, crate, path, mod, i.data); - } + for( auto& d : g_decorators ) { + if( d.first == a.name() && d.second->stage() == stage ) { + d.second->handle(a, crate, path, mod, item); + } + } + } +} + +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() ) + { + 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; } } + 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() ) + { + ::AST::Path path = modpath + i.name; + + Expand_Attrs(i.data.attrs, (is_early ? AttrStage::EarlyPre : AttrStage::LatePre), crate, path, mod, i.data); + TU_MATCH(::AST::Item, (i.data), (e), (None, // Skip, nothing ), (Module, - Expand_Decorators_Mod(crate, is_before_macros, path, e.e); + Expand_Mod(is_early, crate, path, e.e); ), (Crate, // Skip, no recursion @@ -57,15 +89,19 @@ void Expand_Decorators_Mod(::AST::Crate& crate, bool is_before_macros, ::AST::Pa // TODO: ) ) + + Expand_Attrs(i.data.attrs, (is_early ? AttrStage::EarlyPost : AttrStage::LatePost), crate, path, mod, i.data); } + + // 3. Post-recurse macros (everything else) } -void Expand_Decorators(::AST::Crate& crate, bool is_before_macros) +void Expand(::AST::Crate& crate) { // 1. Crate attributes for( auto& a : crate.m_attrs.m_items ) { for( auto& d : g_decorators ) { - if( d.first == a.name() && d.second->expand_before_macros() == is_before_macros ) { + if( d.first == a.name() && d.second->stage() == AttrStage::EarlyPre ) { d.second->handle(a, crate); } } @@ -75,37 +111,35 @@ void Expand_Decorators(::AST::Crate& crate, bool is_before_macros) for( auto& a : crate.m_attrs.m_items ) { for( auto& d : g_decorators ) { - if( d.first == a.name() && d.second->expand_before_macros() == is_before_macros ) { + if( d.first == a.name() && d.second->stage() == AttrStage::EarlyPre ) { //d.second->handle(a, crate, ::AST::Path(), crate.m_root_module, crate.m_root_module); } } } // 3. Module tree - Expand_Decorators_Mod(crate, is_before_macros, ::AST::Path(), crate.m_root_module); -} - -/// Expand decorators that apply before macros are expanded -/// - E.g. #[cfg] #![no_std] ... -void Expand_Decorators_Pre(::AST::Crate& crate) -{ - Expand_Decorators(crate, true); -} - -/// Expand macros -void Expand_Macros(::AST::Crate& crate) -{ -} - -/// Expand decorators that apply _after_ macros -/// - E.g. #[derive] -void Expand_Decorators_Post(::AST::Crate& crate) -{ - Expand_Decorators(crate, false); + Expand_Mod(true , crate, ::AST::Path(), crate.m_root_module); + Expand_Mod(false, crate, ::AST::Path(), crate.m_root_module); + + // Post-process + #if 0 + for( auto& a : crate.m_attrs.m_items ) + { + for( auto& d : g_decorators ) { + if( d.first == a.name() && d.second->expand_before_macros() == false ) { + //d.second->handle(a, crate, ::AST::Path(), crate.m_root_module, crate.m_root_module); + } + } + } + for( auto& a : crate.m_attrs.m_items ) + { + for( auto& d : g_decorators ) { + if( d.first == a.name() && d.second->expand_before_macros() == false ) { + d.second->handle(a, crate); + } + } + } + #endif } -/// Expand syntax sugar (e.g. for loops) -void Expand_Sugar(::AST::Crate& crate) -{ -} diff --git a/src/include/main_bindings.hpp b/src/include/main_bindings.hpp index dc9ef9eb..016b2f27 100644 --- a/src/include/main_bindings.hpp +++ b/src/include/main_bindings.hpp @@ -14,10 +14,7 @@ namespace AST { extern AST::Crate Parse_Crate(::std::string mainfile); -extern void Expand_Decorators_Pre(::AST::Crate& crate); -extern void Expand_Macros(::AST::Crate& crate); -extern void Expand_Decorators_Post(::AST::Crate& crate); -extern void Expand_Sugar(::AST::Crate& crate); +extern void Expand(::AST::Crate& crate); /// Process #[] decorators extern void Process_Decorators(AST::Crate& crate); diff --git a/src/include/synext.hpp b/src/include/synext.hpp index 6d229aef..f8d128f7 100644 --- a/src/include/synext.hpp +++ b/src/include/synext.hpp @@ -26,11 +26,18 @@ class TokenTree; #include <string> #include <memory> +enum class AttrStage +{ + EarlyPre, + EarlyPost, + LatePre, + LatePost, +}; class ExpandDecorator { public: - virtual bool expand_before_macros() const = 0; + virtual AttrStage stage() const = 0; virtual void handle(const AST::MetaItem& mi, AST::Crate& crate) const {} virtual void handle(const AST::MetaItem& mi, AST::Crate& crate, AST::MacroInvocation& mac) const {} @@ -38,11 +45,21 @@ public: virtual void handle(const AST::MetaItem& mi, AST::ExprNode& expr) const {}; }; +enum class MacroPosition +{ + Item, + Stmt, + Expr, + Type, + Pattern, +}; class ExpandProcMacro { public: - virtual AST::Expr expand(const ::std::string& ident, const TokenTree& tt, AST::Module& mod) = 0; + virtual bool expand_early() const = 0; + + virtual AST::Expr expand(const ::std::string& ident, const TokenTree& tt, AST::Module& mod, MacroPosition position) = 0; }; #define STATIC_DECORATOR(ident, _handler_class) \ @@ -51,8 +68,15 @@ public: Register_Synext_Decorator( ident, ::std::unique_ptr<ExpandDecorator>(new _handler_class()) ); \ } \ } s_register_##_handler_class; +#define STATIC_MACRO(ident, _handler_class) \ + struct register_##_handler_class##_c {\ + register_##_handler_class##_c() {\ + Register_Synext_Macro( ident, ::std::unique_ptr<ExpandProcMacro>(new _handler_class()) ); \ + } \ + } s_register_##_handler_class; extern void Register_Synext_Decorator(::std::string name, ::std::unique_ptr<ExpandDecorator> handler); +extern void Register_Synext_Macro(::std::string name, ::std::unique_ptr<ExpandProcMacro> handler); #endif diff --git a/src/main.cpp b/src/main.cpp index aed42260..47be9ebc 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -89,10 +89,7 @@ int main(int argc, char *argv[]) // Iterate all items in the AST, applying syntax extensions
CompilePhaseV("Expand", [&]() {
- Expand_Decorators_Pre(crate);
- Expand_Macros(crate);
- Expand_Decorators_Post(crate);
- Expand_Sugar(crate);
+ Expand(crate);
});
// Run a quick post-parse pass
diff --git a/src/parse/common.hpp b/src/parse/common.hpp index e9b55eb2..def67ef4 100644 --- a/src/parse/common.hpp +++ b/src/parse/common.hpp @@ -48,7 +48,7 @@ extern AST::Struct Parse_Struct(TokenStream& lex, const AST::MetaItems& meta_ite extern AST::Enum Parse_EnumDef(TokenStream& lex, const AST::MetaItems& meta_items);
extern AST::Trait Parse_TraitDef(TokenStream& lex, const AST::MetaItems& meta_items);
extern void Parse_Impl(TokenStream& lex, AST::Module& mod, AST::MetaItems attrs, bool is_unsafe=false);
-extern void Parse_MacroRules(TokenStream& lex, AST::Module& mod, AST::MetaItems meta_items);
+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<AST::Module*>& modstack, bool file_controls_dir, const ::std::string& file_path, AST::Module& mod, bool is_public, AST::MetaItems meta_items);
diff --git a/src/parse/expr.cpp b/src/parse/expr.cpp index e082dfa3..11818a45 100644 --- a/src/parse/expr.cpp +++ b/src/parse/expr.cpp @@ -30,6 +30,7 @@ ExprNodeP Parse_WhileStmt(TokenStream& lex, ::std::string lifetime); ExprNodeP Parse_ForStmt(TokenStream& lex, ::std::string lifetime);
ExprNodeP Parse_Expr_Match(TokenStream& lex);
ExprNodeP Parse_Expr1(TokenStream& lex);
+ExprNodeP Parse_ExprMacro(TokenStream& lex, Token tok);
AST::Expr Parse_Expr(TokenStream& lex, bool const_only)
{
@@ -105,15 +106,6 @@ ExprNodeP Parse_ExprBlockNode(TokenStream& lex) Parse_Mod_Item(lex, modstack, false,"!", *local_mod, false, mv$(item_attrs));
break;
}
- if(0)
- // Macros - If not macro_rules, fall though to expression
- case TOK_MACRO:
- if( tok.str() == "macro_rules" )
- {
- keep_mod = true;
- Parse_MacroRules(lex, *local_mod, ::std::move(item_attrs));
- break;
- }
// fall
default: {
lex.putback(tok);
@@ -224,6 +216,11 @@ ExprNodeP Parse_ExprBlockLine(TokenStream& lex, bool *expect_end) return rv;
}
+ case TOK_MACRO:
+ // If a braced macro invocation is the first part of a statement, don't expect a semicolon
+ if( LOOK_AHEAD(lex) == TOK_BRACE_OPEN || (lex.lookahead(0) == TOK_IDENT && lex.lookahead(1) == TOK_BRACE_OPEN) ) {
+ return Parse_ExprMacro(lex, tok);
+ }
// Fall through to the statement code
default: {
lex.putback(tok);
@@ -1173,25 +1170,28 @@ ExprNodeP Parse_ExprVal(TokenStream& lex) }
}
throw ParseError::BugCheck(lex, "Array literal fell");
- case TOK_MACRO: {
- ::std::string name = tok.str();
- ::std::string ident;
- if( GET_TOK(tok, lex) == TOK_IDENT ) {
- ident = mv$(tok.str());
- }
- else {
- lex.putback(tok);
- }
- TokenTree tt = Parse_TT(lex, true);
- if( tt.is_token() ) {
- throw ParseError::Unexpected(lex, tt.tok());
- }
- return NEWNODE(AST::ExprNode_Macro, mv$(name), mv$(ident), mv$(tt));
- }
+ case TOK_MACRO:
+ return Parse_ExprMacro(lex, tok);
default:
throw ParseError::Unexpected(lex, tok);
}
}
+ExprNodeP Parse_ExprMacro(TokenStream& lex, Token tok)
+{
+ ::std::string name = tok.str();
+ ::std::string ident;
+ if( GET_TOK(tok, lex) == TOK_IDENT ) {
+ ident = mv$(tok.str());
+ }
+ else {
+ lex.putback(tok);
+ }
+ TokenTree tt = Parse_TT(lex, true);
+ if( tt.is_token() ) {
+ throw ParseError::Unexpected(lex, tt.tok());
+ }
+ return NEWNODE(AST::ExprNode_Macro, mv$(name), mv$(ident), mv$(tt));
+}
// Token Tree Parsing
TokenTree Parse_TT(TokenStream& lex, bool unwrapped)
diff --git a/src/parse/macro_rules.cpp b/src/parse/macro_rules.cpp new file mode 100644 index 00000000..b4698fa7 --- /dev/null +++ b/src/parse/macro_rules.cpp @@ -0,0 +1,245 @@ +#include <common.hpp> +#include "../parse/common.hpp" +#include "../parse/parseerror.hpp" +#include "../macros.hpp" + +MacroRules Parse_MacroRules(TokenStream& lex); + +::std::vector<MacroPatEnt> Parse_MacroRules_Pat(TokenStream& lex, bool allow_sub, enum eTokenType open, enum eTokenType close) +{ + TRACE_FUNCTION; + Token tok; + + ::std::vector<MacroPatEnt> ret; + + int depth = 0; + while( GET_TOK(tok, lex) != close || depth > 0 ) + { + if( tok.type() == open ) + { + depth ++; + } + else if( tok.type() == close ) + { + if(depth == 0) + throw ParseError::Generic(FMT("Unmatched " << Token(close) << " in macro pattern")); + depth --; + } + + switch(tok.type()) + { + case TOK_DOLLAR: + switch( GET_TOK(tok, lex) ) + { + case TOK_IDENT: { + ::std::string name = tok.str(); + GET_CHECK_TOK(tok, lex, TOK_COLON); + GET_CHECK_TOK(tok, lex, TOK_IDENT); + ::std::string type = tok.str(); + if(0) + ; + else if( type == "tt" ) + ret.push_back( MacroPatEnt(name, MacroPatEnt::PAT_TT) ); + else if( type == "pat" ) + ret.push_back( MacroPatEnt(name, MacroPatEnt::PAT_PAT) ); + else if( type == "ident" ) + ret.push_back( MacroPatEnt(name, MacroPatEnt::PAT_IDENT) ); + else if( type == "path" ) + ret.push_back( MacroPatEnt(name, MacroPatEnt::PAT_PATH) ); + else if( type == "expr" ) + ret.push_back( MacroPatEnt(name, MacroPatEnt::PAT_EXPR) ); + else if( type == "ty" ) + ret.push_back( MacroPatEnt(name, MacroPatEnt::PAT_TYPE) ); + else if( type == "meta" ) + ret.push_back( MacroPatEnt(name, MacroPatEnt::PAT_META) ); + else if( type == "block" ) + ret.push_back( MacroPatEnt(name, MacroPatEnt::PAT_BLOCK) ); + else + throw ParseError::Generic(lex, FMT("Unknown fragment type '" << type << "'")); + break; } + case TOK_PAREN_OPEN: + if( allow_sub ) + { + auto subpat = Parse_MacroRules_Pat(lex, true, TOK_PAREN_OPEN, TOK_PAREN_CLOSE); + enum eTokenType joiner = TOK_NULL; + GET_TOK(tok, lex); + if( tok.type() != TOK_PLUS && tok.type() != TOK_STAR ) + { + DEBUG("Joiner = " << tok); + joiner = tok.type(); + GET_TOK(tok, lex); + } + DEBUG("tok = " << tok); + switch(tok.type()) + { + case TOK_PLUS: + DEBUG("$()+ " << subpat); + ret.push_back( MacroPatEnt(Token(joiner), true, ::std::move(subpat)) ); + break; + case TOK_STAR: + DEBUG("$()* " << subpat); + ret.push_back( MacroPatEnt(Token(joiner), false, ::std::move(subpat)) ); + break; + default: + throw ParseError::Unexpected(lex, tok); + } + } + else + { + throw ParseError::Generic(lex, FMT("Nested repetitions in macro")); + } + break; + default: + throw ParseError::Unexpected(lex, tok); + } + break; + case TOK_EOF: + throw ParseError::Unexpected(lex, tok); + default: + ret.push_back( MacroPatEnt(tok) ); + break; + } + } + + return ret; +} + +::std::vector<MacroRuleEnt> Parse_MacroRules_Cont(TokenStream& lex, bool allow_sub, enum eTokenType open, enum eTokenType close) +{ + TRACE_FUNCTION; + + Token tok; + ::std::vector<MacroRuleEnt> ret; + + int depth = 0; + while( GET_TOK(tok, lex) != close || depth > 0 ) + { + if( tok.type() == TOK_EOF ) { + throw ParseError::Unexpected(lex, tok); + } + if( tok.type() == TOK_NULL ) continue ; + + if( tok.type() == open ) + { + DEBUG("depth++"); + depth ++; + } + else if( tok.type() == close ) + { + DEBUG("depth--"); + if(depth == 0) + throw ParseError::Generic(FMT("Unmatched " << Token(close) << " in macro content")); + depth --; + } + + if( tok.type() == TOK_DOLLAR ) + { + GET_TOK(tok, lex); + + if( tok.type() == TOK_PAREN_OPEN ) + { + if( !allow_sub ) + throw ParseError::Unexpected(lex, tok); + + auto content = Parse_MacroRules_Cont(lex, true, TOK_PAREN_OPEN, TOK_PAREN_CLOSE); + + GET_TOK(tok, lex); + enum eTokenType joiner = TOK_NULL; + if( tok.type() != TOK_PLUS && tok.type() != TOK_STAR ) + { + joiner = tok.type(); + GET_TOK(tok, lex); + } + DEBUG("joiner = " << Token(joiner) << ", content = " << content); + switch(tok.type()) + { + case TOK_STAR: + ret.push_back( MacroRuleEnt(joiner, ::std::move(content)) ); + break; + case TOK_PLUS: + // TODO: Ensure that the plusses match + ret.push_back( MacroRuleEnt(joiner, ::std::move(content)) ); + break; + default: + throw ParseError::Unexpected(lex, tok); + } + + } + else if( tok.type() == TOK_IDENT ) + { + ret.push_back( MacroRuleEnt(tok.str()) ); + } + else if( tok.type() == TOK_RWORD_CRATE ) + { + ret.push_back( MacroRuleEnt("*crate") ); + } + else + { + throw ParseError::Unexpected(lex, tok); + } + } + else + { + ret.push_back( MacroRuleEnt(tok) ); + } + } + + return ret; +} + +MacroRule Parse_MacroRules_Var(TokenStream& lex) +{ + TRACE_FUNCTION; + Token tok; + + MacroRule rule; + + // Pattern + enum eTokenType close; + switch(GET_TOK(tok, lex)) + { + case TOK_BRACE_OPEN: close = TOK_BRACE_CLOSE; break; + case TOK_PAREN_OPEN: close = TOK_PAREN_CLOSE; break; + default: + throw ParseError::Unexpected(lex, tok); + } + // - Pattern entries + rule.m_pattern = Parse_MacroRules_Pat(lex, true, tok.type(), close); + + GET_CHECK_TOK(tok, lex, TOK_FATARROW); + + // Replacement + switch(GET_TOK(tok, lex)) + { + case TOK_BRACE_OPEN: close = TOK_BRACE_CLOSE; break; + case TOK_PAREN_OPEN: close = TOK_PAREN_CLOSE; break; + default: + throw ParseError::Unexpected(lex, tok); + } + rule.m_contents = Parse_MacroRules_Cont(lex, true, tok.type(), close); + + DEBUG("Rule - ["<<rule.m_pattern<<"] => "<<rule.m_contents<<""); + + return rule; +} + +MacroRules Parse_MacroRules(TokenStream& lex) +{ + TRACE_FUNCTION_F(""); + + Token tok; + + ::std::vector<MacroRule> rules; + while( GET_TOK(tok, lex) != TOK_EOF ) + { + lex.putback(tok); + + rules.push_back( Parse_MacroRules_Var(lex) ); + if(GET_TOK(tok, lex) != TOK_SEMICOLON) { + CHECK_TOK(tok, TOK_EOF); + break; + } + } + + return MacroRules(mv$(rules)); +} diff --git a/src/parse/root.cpp b/src/parse/root.cpp index 9b910504..faa2b9bb 100644 --- a/src/parse/root.cpp +++ b/src/parse/root.cpp @@ -1205,261 +1205,6 @@ void Parse_Use(TokenStream& lex, ::std::function<void(AST::Path, ::std::string)> fcn(path, name);
}
-::std::vector<MacroPatEnt> Parse_MacroRules_Pat(TokenStream& lex, bool allow_sub, enum eTokenType open, enum eTokenType close)
-{
- TRACE_FUNCTION;
- Token tok;
-
- ::std::vector<MacroPatEnt> ret;
-
- int depth = 0;
- while( GET_TOK(tok, lex) != close || depth > 0 )
- {
- if( tok.type() == open )
- {
- depth ++;
- }
- else if( tok.type() == close )
- {
- if(depth == 0)
- throw ParseError::Generic(FMT("Unmatched " << Token(close) << " in macro pattern"));
- depth --;
- }
-
- switch(tok.type())
- {
- case TOK_DOLLAR:
- switch( GET_TOK(tok, lex) )
- {
- case TOK_IDENT: {
- ::std::string name = tok.str();
- GET_CHECK_TOK(tok, lex, TOK_COLON);
- GET_CHECK_TOK(tok, lex, TOK_IDENT);
- ::std::string type = tok.str();
- if(0)
- ;
- else if( type == "tt" )
- ret.push_back( MacroPatEnt(name, MacroPatEnt::PAT_TT) );
- else if( type == "pat" )
- ret.push_back( MacroPatEnt(name, MacroPatEnt::PAT_PAT) );
- else if( type == "ident" )
- ret.push_back( MacroPatEnt(name, MacroPatEnt::PAT_IDENT) );
- else if( type == "path" )
- ret.push_back( MacroPatEnt(name, MacroPatEnt::PAT_PATH) );
- else if( type == "expr" )
- ret.push_back( MacroPatEnt(name, MacroPatEnt::PAT_EXPR) );
- else if( type == "ty" )
- ret.push_back( MacroPatEnt(name, MacroPatEnt::PAT_TYPE) );
- else if( type == "meta" )
- ret.push_back( MacroPatEnt(name, MacroPatEnt::PAT_META) );
- else if( type == "block" )
- ret.push_back( MacroPatEnt(name, MacroPatEnt::PAT_BLOCK) );
- else
- throw ParseError::Generic(lex, FMT("Unknown fragment type '" << type << "'"));
- break; }
- case TOK_PAREN_OPEN:
- if( allow_sub )
- {
- auto subpat = Parse_MacroRules_Pat(lex, true, TOK_PAREN_OPEN, TOK_PAREN_CLOSE);
- enum eTokenType joiner = TOK_NULL;
- GET_TOK(tok, lex);
- if( tok.type() != TOK_PLUS && tok.type() != TOK_STAR )
- {
- DEBUG("Joiner = " << tok);
- joiner = tok.type();
- GET_TOK(tok, lex);
- }
- DEBUG("tok = " << tok);
- switch(tok.type())
- {
- case TOK_PLUS:
- DEBUG("$()+ " << subpat);
- ret.push_back( MacroPatEnt(Token(joiner), true, ::std::move(subpat)) );
- break;
- case TOK_STAR:
- DEBUG("$()* " << subpat);
- ret.push_back( MacroPatEnt(Token(joiner), false, ::std::move(subpat)) );
- break;
- default:
- throw ParseError::Unexpected(lex, tok);
- }
- }
- else
- {
- throw ParseError::Generic(lex, FMT("Nested repetitions in macro"));
- }
- break;
- default:
- throw ParseError::Unexpected(lex, tok);
- }
- break;
- case TOK_EOF:
- throw ParseError::Unexpected(lex, tok);
- default:
- ret.push_back( MacroPatEnt(tok) );
- break;
- }
- }
-
- return ret;
-}
-
-::std::vector<MacroRuleEnt> Parse_MacroRules_Cont(TokenStream& lex, bool allow_sub, enum eTokenType open, enum eTokenType close)
-{
- TRACE_FUNCTION;
-
- Token tok;
- ::std::vector<MacroRuleEnt> ret;
-
- int depth = 0;
- while( GET_TOK(tok, lex) != close || depth > 0 )
- {
- if( tok.type() == TOK_EOF ) {
- throw ParseError::Unexpected(lex, tok);
- }
- if( tok.type() == TOK_NULL ) continue ;
-
- if( tok.type() == open )
- {
- DEBUG("depth++");
- depth ++;
- }
- else if( tok.type() == close )
- {
- DEBUG("depth--");
- if(depth == 0)
- throw ParseError::Generic(FMT("Unmatched " << Token(close) << " in macro content"));
- depth --;
- }
-
- if( tok.type() == TOK_DOLLAR )
- {
- GET_TOK(tok, lex);
-
- if( tok.type() == TOK_PAREN_OPEN )
- {
- if( !allow_sub )
- throw ParseError::Unexpected(lex, tok);
-
- auto content = Parse_MacroRules_Cont(lex, true, TOK_PAREN_OPEN, TOK_PAREN_CLOSE);
-
- GET_TOK(tok, lex);
- enum eTokenType joiner = TOK_NULL;
- if( tok.type() != TOK_PLUS && tok.type() != TOK_STAR )
- {
- joiner = tok.type();
- GET_TOK(tok, lex);
- }
- DEBUG("joiner = " << Token(joiner) << ", content = " << content);
- switch(tok.type())
- {
- case TOK_STAR:
- ret.push_back( MacroRuleEnt(joiner, ::std::move(content)) );
- break;
- case TOK_PLUS:
- // TODO: Ensure that the plusses match
- ret.push_back( MacroRuleEnt(joiner, ::std::move(content)) );
- break;
- default:
- throw ParseError::Unexpected(lex, tok);
- }
-
- }
- else if( tok.type() == TOK_IDENT )
- {
- ret.push_back( MacroRuleEnt(tok.str()) );
- }
- else if( tok.type() == TOK_RWORD_CRATE )
- {
- ret.push_back( MacroRuleEnt("*crate") );
- }
- else
- {
- throw ParseError::Unexpected(lex, tok);
- }
- }
- else
- {
- ret.push_back( MacroRuleEnt(tok) );
- }
- }
-
- return ret;
-}
-
-MacroRule Parse_MacroRules_Var(TokenStream& lex)
-{
- TRACE_FUNCTION;
- Token tok;
-
- MacroRule rule;
-
- // Pattern
- enum eTokenType close;
- switch(GET_TOK(tok, lex))
- {
- case TOK_BRACE_OPEN: close = TOK_BRACE_CLOSE; break;
- case TOK_PAREN_OPEN: close = TOK_PAREN_CLOSE; break;
- default:
- throw ParseError::Unexpected(lex, tok);
- }
- // - Pattern entries
- rule.m_pattern = Parse_MacroRules_Pat(lex, true, tok.type(), close);
-
- GET_CHECK_TOK(tok, lex, TOK_FATARROW);
-
- // Replacement
- switch(GET_TOK(tok, lex))
- {
- case TOK_BRACE_OPEN: close = TOK_BRACE_CLOSE; break;
- case TOK_PAREN_OPEN: close = TOK_PAREN_CLOSE; break;
- default:
- throw ParseError::Unexpected(lex, tok);
- }
- rule.m_contents = Parse_MacroRules_Cont(lex, true, tok.type(), close);
-
- DEBUG("Rule - ["<<rule.m_pattern<<"] => "<<rule.m_contents<<"");
-
- return rule;
-}
-
-void Parse_MacroRules(TokenStream& lex, AST::Module& mod, AST::MetaItems meta_items)
-{
- TRACE_FUNCTION_F("meta_items="<<meta_items);
-
- Token tok;
-
- GET_CHECK_TOK(tok, lex, TOK_IDENT);
- ::std::string name = tok.str();
-
- eTokenType close;
- switch(GET_TOK(tok,lex))
- {
- case TOK_BRACE_OPEN: close = TOK_BRACE_CLOSE; break;
- case TOK_PAREN_OPEN: close = TOK_PAREN_CLOSE; break;
- case TOK_SQUARE_OPEN: close = TOK_SQUARE_CLOSE; break;
- default:
- // TODO: Synerror
- throw ParseError::Unexpected(lex, tok, {TOK_BRACE_OPEN, TOK_PAREN_OPEN, TOK_SQUARE_OPEN});
- break;
- }
-
- ::std::vector<MacroRule> rules;
- while( GET_TOK(tok, lex) != close )
- {
- lex.putback(tok);
-
- rules.push_back( Parse_MacroRules_Var(lex) );
- if(GET_TOK(tok, lex) != TOK_SEMICOLON) {
- CHECK_TOK(tok, TOK_BRACE_CLOSE);
- break;
- }
- }
-
- bool is_pub = meta_items.has("macro_export");
-
- mod.add_macro( is_pub, name, MacroRules(move(rules)) );
-}
::AST::MacroInvocation Parse_MacroInvocation(::AST::MetaItems meta_items, ::std::string name, TokenStream& lex)
{
@@ -1856,16 +1601,9 @@ void Parse_ModRoot_Items(TokenStream& lex, AST::Module& mod, LList<AST::Module*> if( GET_TOK(tok, lex) == TOK_MACRO )
{
::std::string name = mv$(tok.str());
- // `macro_rules! ...`
- //if( name == "macro_rules" )
- //{
- // Parse_MacroRules(lex, mod, mv$(meta_items));
- //}
- //else
- //{
- mod.add_macro_invocation( Parse_MacroInvocation( mv$(meta_items), mv$(name), lex ) );
- //}
+ mod.add_macro_invocation( Parse_MacroInvocation( mv$(meta_items), mv$(name), lex ) );
// - Silently consume ';' after the macro
+ // TODO: Check the tt next token before parsing to tell if this is needed
if( GET_TOK(tok, lex) != TOK_SEMICOLON )
lex.putback(tok);
continue ;
diff --git a/src/synexts/derive.cpp b/src/synexts/derive.cpp index 17fb0a96..ca0a2c3f 100644 --- a/src/synexts/derive.cpp +++ b/src/synexts/derive.cpp @@ -148,7 +148,7 @@ class Decorator_Derive: public ExpandDecorator { public: - bool expand_before_macros() const override { return false; } + AttrStage stage() const override { return AttrStage::LatePost; } void handle(const AST::MetaItem& attr, AST::Crate& crate, const AST::Path& path, AST::Module& mod, AST::Item& i) const override { TU_MATCH_DEF(::AST::Item, (i), (e), diff --git a/src/synexts/lang_item.cpp b/src/synexts/lang_item.cpp index a38a73f3..3df3a54f 100644 --- a/src/synexts/lang_item.cpp +++ b/src/synexts/lang_item.cpp @@ -85,7 +85,7 @@ class Decorator_LangItem: public ExpandDecorator { public: - bool expand_before_macros() const override { return true; } + AttrStage stage() const override { return AttrStage::EarlyPost; } void handle(const AST::MetaItem& attr, AST::Crate& crate, const AST::Path& path, AST::Module& mod, AST::Item& i) const override { TU_MATCH_DEF(::AST::Item, (i), (e), |