diff options
author | John Hodge <tpg@ucc.asn.au> | 2019-01-05 16:32:14 +0800 |
---|---|---|
committer | John Hodge <tpg@ucc.asn.au> | 2019-01-05 16:32:14 +0800 |
commit | fa3bf839ff871f862697ee1d992f0e6175c2a25b (patch) | |
tree | 8e39fffa7cbba1e4e3cc030b277e61f9f00257b2 | |
parent | 0be0edd9de59072ca5b780993c2b0bbece0e7aa1 (diff) | |
download | mrust-fa3bf839ff871f862697ee1d992f0e6175c2a25b.tar.gz |
Expand - Macros in traits
-rw-r--r-- | src/expand/mod.cpp | 33 | ||||
-rw-r--r-- | src/parse/common.hpp | 1 | ||||
-rw-r--r-- | src/parse/root.cpp | 261 |
3 files changed, 167 insertions, 128 deletions
diff --git a/src/expand/mod.cpp b/src/expand/mod.cpp index da37dea7..e4764be1 100644 --- a/src/expand/mod.cpp +++ b/src/expand/mod.cpp @@ -953,7 +953,7 @@ void Expand_Impl(::AST::Crate& crate, LList<const AST::Module*> modstack, ::AST: TU_MATCH_DEF(AST::Item, (*i.data), (e), ( - throw ::std::runtime_error("BUG: Unknown item type in impl block"); + BUG(Span(), "Unknown item type in impl block - " << i.data->tag_str()); ), (None, ), (MacroInv, @@ -1214,17 +1214,44 @@ void Expand_Mod(::AST::Crate& crate, LList<const AST::Module*> modstack, ::AST:: ), (Trait, Expand_GenericParams(crate, modstack, mod, e.params()); - for(auto& ti : e.items()) + auto& trait_items = e.items(); + for(size_t idx = 0; idx < trait_items.size(); idx ++) { + auto& ti = trait_items[idx]; DEBUG(" - " << ti.name << " " << ti.data.tag_str()); auto attrs = mv$(ti.data.attrs); Expand_Attrs(attrs, AttrStage::Pre, crate, AST::Path(), mod, ti.data); TU_MATCH_DEF(AST::Item, (ti.data), (e), ( - throw ::std::runtime_error("BUG: Unknown item type in impl block"); + BUG(Span(), "Unknown item type in trait block - " << ti.data.tag_str()); ), (None, ), + (MacroInv, + if( e.name() != "" ) + { + TRACE_FUNCTION_F("Macro invoke " << e.name()); + // Move out of the module to avoid invalidation if a new macro invocation is added + auto mi_owned = mv$(e); + + auto ttl = Expand_Macro(crate, modstack, mod, mi_owned); + + if( ttl.get() ) + { + // Re-parse tt + size_t insert_pos = idx+1; + while( ttl->lookahead(0) != TOK_EOF ) + { + auto i = Parse_Trait_Item(*ttl); + trait_items.insert( trait_items.begin() + insert_pos, mv$(i) ); + insert_pos ++; + } + // - Any new macro invocations ends up at the end of the list and handled + } + // Move back in (using the index, as the old pointer may be invalid) + trait_items[idx].data.as_MacroInv() = mv$(mi_owned); + } + ), (Function, Expand_GenericParams(crate, modstack, mod, e.params()); for(auto& arg : e.args()) { diff --git a/src/parse/common.hpp b/src/parse/common.hpp index c742fe4f..c8f51520 100644 --- a/src/parse/common.hpp +++ b/src/parse/common.hpp @@ -50,6 +50,7 @@ extern TypeRef Parse_Type(TokenStream& lex, bool allow_trait_list = true); extern AST::Pattern Parse_Pattern(TokenStream& lex, bool is_refutable); extern void Parse_Impl_Item(TokenStream& lex, AST::Impl& impl); +extern AST::Named<AST::Item> Parse_Trait_Item(TokenStream& lex); extern void Parse_Mod_Item(TokenStream& lex, AST::Module& mod, AST::AttributeList meta_items); extern ::AST::Named<::AST::Item> Parse_Mod_Item_S(TokenStream& lex, const AST::Module::FileInfo& mod_fileinfo, const ::AST::Path& mod_path, AST::AttributeList meta_items); extern void Parse_ModRoot_Items(TokenStream& lex, AST::Module& mod); diff --git a/src/parse/root.cpp b/src/parse/root.cpp index 28a49287..c3fbfdd1 100644 --- a/src/parse/root.cpp +++ b/src/parse/root.cpp @@ -639,6 +639,141 @@ AST::Struct Parse_Struct(TokenStream& lex, const AST::AttributeList& meta_items) } } +AST::Named<AST::Item> Parse_Trait_Item(TokenStream& lex) +{ + Token tok; + + auto item_attrs = Parse_ItemAttrs(lex); + SET_ATTRS(lex, item_attrs); + + auto ps = lex.start_span(); + { + ::AST::MacroInvocation inv; + if( Parse_MacroInvocation_Opt(lex, inv) ) + { + return AST::Named<AST::Item>( "", AST::Item(mv$(inv)), false ); + } + } + + GET_TOK(tok, lex); + bool is_specialisable = false; + if( tok.type() == TOK_IDENT && tok.str() == "default" ) { + is_specialisable = true; + GET_TOK(tok, lex); + } + // TODO: Mark specialisation + (void)is_specialisable; + + bool fn_is_const = false; + bool fn_is_unsafe = false; + ::std::string abi = ABI_RUST; + + ::std::string name; + ::AST::Item rv; + switch(tok.type()) + { + case TOK_RWORD_STATIC: { + GET_CHECK_TOK(tok, lex, TOK_IDENT); + name = mv$(tok.str()); + GET_CHECK_TOK(tok, lex, TOK_COLON); + auto ty = Parse_Type(lex); + GET_CHECK_TOK(tok, lex, TOK_SEMICOLON); + + ::AST::Expr val; + if(GET_TOK(tok, lex) == TOK_EQUAL) { + val = Parse_Expr(lex); + GET_TOK(tok, lex); + } + CHECK_TOK(tok, TOK_SEMICOLON); + + rv = ::AST::Static(::AST::Static::STATIC, mv$(ty), val); + break; } + case TOK_RWORD_CONST: { + GET_CHECK_TOK(tok, lex, TOK_IDENT); + name = mv$(tok.str()); + GET_CHECK_TOK(tok, lex, TOK_COLON); + auto ty = Parse_Type(lex); + + ::AST::Expr val; + if(GET_TOK(tok, lex) == TOK_EQUAL) { + val = Parse_Expr(lex); + GET_TOK(tok, lex); + } + CHECK_TOK(tok, TOK_SEMICOLON); + + rv = ::AST::Static(AST::Static::CONST, mv$(ty), val); + break; } + // Associated type + case TOK_RWORD_TYPE: { + auto atype_params = ::AST::GenericParams { }; + GET_CHECK_TOK(tok, lex, TOK_IDENT); + name = mv$(tok.str()); + if( GET_TOK(tok, lex) == TOK_COLON ) + { + // Bounded associated type + Parse_TypeBound(lex, atype_params, TypeRef(lex.point_span(), "Self", 0xFFFF)); + GET_TOK(tok, lex); + } + if( tok.type() == TOK_RWORD_WHERE ) { + throw ParseError::Todo(lex, "Where clause on associated type"); + } + + TypeRef default_type = TypeRef( lex.point_span() ); + if( tok.type() == TOK_EQUAL ) { + default_type = Parse_Type(lex); + GET_TOK(tok, lex); + } + + CHECK_TOK(tok, TOK_SEMICOLON); + rv = ::AST::TypeAlias( mv$(atype_params), mv$(default_type) ); + break; } + + // Functions (possibly unsafe) + case TOK_RWORD_UNSAFE: + fn_is_unsafe = true; + if( GET_TOK(tok, lex) == TOK_RWORD_EXTERN ) + case TOK_RWORD_EXTERN: + { + abi = "C"; + if( GET_TOK(tok, lex) == TOK_STRING ) + abi = tok.str(); + else + PUTBACK(tok, lex); + + GET_TOK(tok, lex); + } + CHECK_TOK(tok, TOK_RWORD_FN); + case TOK_RWORD_FN: { + GET_CHECK_TOK(tok, lex, TOK_IDENT); + name = mv$(tok.str()); + // Self allowed, prototype-form allowed (optional names and no code) + auto fcn = Parse_FunctionDef(lex, abi, true, true, fn_is_unsafe, fn_is_const); + if( GET_TOK(tok, lex) == TOK_BRACE_OPEN ) + { + PUTBACK(tok, lex); + // Enter a new hygine scope for the function body. (TODO: Should this be in Parse_ExprBlock?) + lex.push_hygine(); + fcn.set_code( Parse_ExprBlock(lex) ); + lex.pop_hygine(); + } + else if( tok.type() == TOK_SEMICOLON ) + { + // Accept it + } + else + { + throw ParseError::Unexpected(lex, tok); + } + rv = ::std::move(fcn); + break; } + default: + throw ParseError::Unexpected(lex, tok); + } + + rv.attrs = ::std::move( item_attrs ); + return ::AST::Named<::AST::Item>( mv$(name), mv$(rv), true ); +} + AST::Trait Parse_TraitDef(TokenStream& lex, const AST::AttributeList& meta_items) { TRACE_FUNCTION; @@ -689,131 +824,7 @@ AST::Trait Parse_TraitDef(TokenStream& lex, const AST::AttributeList& meta_items { PUTBACK(tok, lex); - auto item_attrs = Parse_ItemAttrs(lex); - SET_ATTRS(lex, item_attrs); - - auto ps = lex.start_span(); - { - ::AST::MacroInvocation inv; - if( Parse_MacroInvocation_Opt(lex, inv) ) - { - trait.items().push_back( AST::Named<AST::Item>("", AST::Item(mv$(inv)), false) ); - continue ; - } - GET_TOK(tok, lex); - } - - bool is_specialisable = false; - if( tok.type() == TOK_IDENT && tok.str() == "default" ) { - is_specialisable = true; - GET_TOK(tok, lex); - } - // TODO: Mark specialisation - (void)is_specialisable; - - bool fn_is_const = false; - bool fn_is_unsafe = false; - ::std::string abi = ABI_RUST; - switch(tok.type()) - { - case TOK_RWORD_STATIC: { - GET_CHECK_TOK(tok, lex, TOK_IDENT); - auto name = mv$(tok.str()); - GET_CHECK_TOK(tok, lex, TOK_COLON); - auto ty = Parse_Type(lex); - GET_CHECK_TOK(tok, lex, TOK_SEMICOLON); - - ::AST::Expr val; - if(GET_TOK(tok, lex) == TOK_EQUAL) { - val = Parse_Expr(lex); - GET_TOK(tok, lex); - } - CHECK_TOK(tok, TOK_SEMICOLON); - - trait.add_static( mv$(name), mv$(item_attrs), ::AST::Static(AST::Static::STATIC, mv$(ty), val) ); - break; } - case TOK_RWORD_CONST: { - GET_CHECK_TOK(tok, lex, TOK_IDENT); - auto name = mv$(tok.str()); - GET_CHECK_TOK(tok, lex, TOK_COLON); - auto ty = Parse_Type(lex); - - ::AST::Expr val; - if(GET_TOK(tok, lex) == TOK_EQUAL) { - val = Parse_Expr(lex); - GET_TOK(tok, lex); - } - CHECK_TOK(tok, TOK_SEMICOLON); - - trait.add_static( mv$(name), mv$(item_attrs), ::AST::Static(AST::Static::CONST, mv$(ty), val) ); - break; } - // Associated type - case TOK_RWORD_TYPE: { - auto atype_params = ::AST::GenericParams { }; - GET_CHECK_TOK(tok, lex, TOK_IDENT); - auto name = mv$(tok.str()); - if( GET_TOK(tok, lex) == TOK_COLON ) - { - // Bounded associated type - Parse_TypeBound(lex, atype_params, TypeRef(lex.point_span(), "Self", 0xFFFF)); - GET_TOK(tok, lex); - } - if( tok.type() == TOK_RWORD_WHERE ) { - throw ParseError::Todo(lex, "Where clause on associated type"); - } - - TypeRef default_type = TypeRef( lex.point_span() ); - if( tok.type() == TOK_EQUAL ) { - default_type = Parse_Type(lex); - GET_TOK(tok, lex); - } - - CHECK_TOK(tok, TOK_SEMICOLON); - trait.add_type( ::std::move(name), mv$(item_attrs), ::std::move(default_type) ); - trait.items().back().data.as_Type().params() = mv$(atype_params); - break; } - - // Functions (possibly unsafe) - case TOK_RWORD_UNSAFE: - fn_is_unsafe = true; - if( GET_TOK(tok, lex) == TOK_RWORD_EXTERN ) - case TOK_RWORD_EXTERN: - { - abi = "C"; - if( GET_TOK(tok, lex) == TOK_STRING ) - abi = tok.str(); - else - PUTBACK(tok, lex); - - GET_TOK(tok, lex); - } - CHECK_TOK(tok, TOK_RWORD_FN); - case TOK_RWORD_FN: { - GET_CHECK_TOK(tok, lex, TOK_IDENT); - ::std::string name = mv$(tok.str()); - // Self allowed, prototype-form allowed (optional names and no code) - auto fcn = Parse_FunctionDef(lex, abi, true, true, fn_is_unsafe, fn_is_const); - if( GET_TOK(tok, lex) == TOK_BRACE_OPEN ) - { - PUTBACK(tok, lex); - // Enter a new hygine scope for the function body. (TODO: Should this be in Parse_ExprBlock?) - lex.push_hygine(); - fcn.set_code( Parse_ExprBlock(lex) ); - lex.pop_hygine(); - } - else if( tok.type() == TOK_SEMICOLON ) - { - // Accept it - } - else - { - throw ParseError::Unexpected(lex, tok); - } - trait.add_function( ::std::move(name), mv$(item_attrs), ::std::move(fcn) ); - break; } - default: - throw ParseError::Unexpected(lex, tok); - } + trait.items().push_back( Parse_Trait_Item(lex) ); } return trait; |