summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/ast/ast.cpp2
-rw-r--r--src/ast/ast.hpp3
-rw-r--r--src/ast/macro.hpp12
-rw-r--r--src/expand/macro_rules.cpp28
-rw-r--r--src/expand/mod.cpp110
-rw-r--r--src/include/main_bindings.hpp5
-rw-r--r--src/include/synext.hpp28
-rw-r--r--src/main.cpp5
-rw-r--r--src/parse/common.hpp2
-rw-r--r--src/parse/expr.cpp48
-rw-r--r--src/parse/macro_rules.cpp245
-rw-r--r--src/parse/root.cpp266
-rw-r--r--src/synexts/derive.cpp2
-rw-r--r--src/synexts/lang_item.cpp2
14 files changed, 418 insertions, 340 deletions
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),