From 95d725d80a76e74549329dfdb74f8147c1b075e7 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Tue, 1 Jan 2019 13:06:13 +0800 Subject: Refactor of `use` items to fully-group imports from a single use --- src/parse/root.cpp | 202 ++++++++++++++++++++--------------------------------- 1 file changed, 77 insertions(+), 125 deletions(-) (limited to 'src/parse/root.cpp') diff --git a/src/parse/root.cpp b/src/parse/root.cpp index 2db03c99..28a49287 100644 --- a/src/parse/root.cpp +++ b/src/parse/root.cpp @@ -1322,55 +1322,74 @@ AST::ExternBlock Parse_ExternBlock(TokenStream& lex, ::std::string abi, ::AST::A return rv; } -void Parse_Use_Wildcard(Span sp, AST::Path base_path, ::std::function fcn) +/// Parse multiple items from a use "statement" +void Parse_Use_Inner(TokenStream& lex, ::std::vector& entries, AST::Path& path) { - fcn( AST::UseStmt(mv$(sp), mv$(base_path)), "" ); // HACK! Empty path indicates wilcard import -} -void Parse_Use_Set(TokenStream& lex, const ProtoSpan& ps, const AST::Path& base_path, ::std::function fcn) -{ - TRACE_FUNCTION; - Token tok; - do { - AST::Path path; - ::std::string name; - if( GET_TOK(tok, lex) == TOK_RWORD_SELF ) { - path = ::AST::Path(base_path); - name = base_path[base_path.size()-1].name(); - } - else if( tok.type() == TOK_BRACE_CLOSE ) { - break ; - } - else { - path = ::AST::Path(base_path); - while(1) - { - CHECK_TOK(tok, TOK_IDENT); - path += AST::PathNode(tok.str(), {}); - if( !TARGETVER_1_29 ) - break; - if( lex.lookahead(0) != TOK_DOUBLE_COLON ) - break; - GET_CHECK_TOK(tok, lex, TOK_DOUBLE_COLON); - GET_TOK(tok, lex); + do + { + switch( GET_TOK(tok, lex) ) + { + case TOK_IDENT: + path.append( AST::PathNode( mv$(tok.str()), {}) ); + break; + case TOK_BRACE_OPEN: + // Can't be an empty list + if( LOOK_AHEAD(lex) == TOK_BRACE_CLOSE ) { + throw ParseError::Unexpected(lex, tok); } - name = mv$(tok.str()); - } + // Keep looping until a comma + do { + if( LOOK_AHEAD(lex) == TOK_BRACE_CLOSE ) { + // Trailing comma + GET_TOK(tok, lex); + break; + } + // - Handle `self` in braces differently + else if( LOOK_AHEAD(lex) == TOK_RWORD_SELF ) { + GET_TOK(tok, lex); + auto name = path.nodes().back().name(); + entries.push_back({ lex.point_span(), AST::Path(path), ::std::move(name) }); + } + else { + size_t l = path.nodes().size(); - if( GET_TOK(tok, lex) == TOK_RWORD_AS ) { - GET_CHECK_TOK(tok, lex, TOK_IDENT); - name = mv$(tok.str()); - } - else { - PUTBACK(tok, lex); + Parse_Use_Inner(lex, entries, path); + + assert(l <= path.nodes().size()); + path.nodes().resize( l ); + } + } while( GET_TOK(tok, lex) == TOK_COMMA ); + CHECK_TOK(tok, TOK_BRACE_CLOSE); + return; + case TOK_STAR: + entries.push_back({ lex.point_span(), AST::Path(path), "" }); + return ; + default: + throw ParseError::Unexpected(lex, tok); } - fcn(AST::UseStmt(lex.end_span(ps), mv$(path)), mv$(name)); - } while( GET_TOK(tok, lex) == TOK_COMMA ); - PUTBACK(tok, lex); -} + } while( GET_TOK(tok, lex) == TOK_DOUBLE_COLON ); + + ::std::string name; -void Parse_Use(TokenStream& lex, ::std::function fcn) + // NOTE: The above loop has to run once, so the last token HAS to have been an ident + if( tok.type() == TOK_RWORD_AS ) + { + GET_CHECK_TOK(tok, lex, TOK_IDENT); + name = mv$(tok.str()); + } + else + { + PUTBACK(tok, lex); + ASSERT_BUG(lex.point_span(), path.nodes().size() > 0, "`use` with no path"); + name = path.nodes().back().name(); + } + + // TODO: Get a span covering the final node. + entries.push_back({ lex.point_span(), AST::Path(path), ::std::move(name) }); +} +::AST::UseItem Parse_Use(TokenStream& lex) { TRACE_FUNCTION; @@ -1379,10 +1398,13 @@ void Parse_Use(TokenStream& lex, ::std::function nodes; ProtoSpan span_start = lex.start_span(); + ::std::vector entries; + switch( GET_TOK(tok, lex) ) { case TOK_RWORD_SELF: path = AST::Path( AST::Path::TagSelf(), {} ); // relative path + GET_CHECK_TOK(tok, lex, TOK_DOUBLE_COLON); break; case TOK_RWORD_SUPER: { unsigned int count = 1; @@ -1392,11 +1414,11 @@ void Parse_Use(TokenStream& lex, ::std::function 0, "`use` with no path"); - name = path.nodes().back().name(); + break; } - fcn( AST::UseStmt(lex.end_span(span_start), mv$(path)), name); + Parse_Use_Inner(lex, entries, path); + + return AST::UseItem { lex.end_span(span_start), mv$(entries) }; } @@ -1655,16 +1635,7 @@ namespace { switch( GET_TOK(tok, lex) ) { case TOK_RWORD_USE: - // NOTE: The only problem here is with things like `use foo::{a, b, c}` - all others are a single statement. - // - These are caught by the condition in the closure - Parse_Use(lex, [&](AST::UseStmt p, std::string s) { - DEBUG(mod_path << " - use " << p << " as '" << s << "'"); - if( !item_data.is_None() ) - TODO(lex.point_span(), "Encode multi-item use statements as a single Item"); - item_data = ::AST::Item(mv$(p)); - item_name = mv$(s); - }); - assert( !item_data.is_None() ); + item_data = Parse_Use(lex); GET_CHECK_TOK(tok, lex, TOK_SEMICOLON); break; @@ -2072,26 +2043,7 @@ void Parse_Mod_Item(TokenStream& lex, AST::Module& mod, AST::AttributeList meta_ SET_MODULE(lex, mod); lex.parse_state().parent_attrs = &meta_items; - //TRACE_FUNCTION; - Token tok; - - // `use ...` - // TODO: This doesn't spot `pub(path) use`. - if( LOOK_AHEAD(lex) == TOK_RWORD_USE || (lex.lookahead(0) == TOK_RWORD_PUB && lex.lookahead(1) == TOK_RWORD_USE) ) - { - bool is_public = Parse_Publicity(lex); - GET_CHECK_TOK(tok, lex, TOK_RWORD_USE); - - Parse_Use(lex, [&mod,is_public,&meta_items](AST::UseStmt p, std::string s) { - DEBUG(mod.path() << " - use " << p << " as '" << s << "'"); - mod.add_alias(is_public, mv$(p), s, meta_items.clone()); - }); - GET_CHECK_TOK(tok, lex, TOK_SEMICOLON); - } - else - { - mod.add_item( Parse_Mod_Item_S(lex, mod.m_file_info, mod.path(), mv$(meta_items)) ); - } + mod.add_item( Parse_Mod_Item_S(lex, mod.m_file_info, mod.path(), mv$(meta_items)) ); } void Parse_ModRoot_Items(TokenStream& lex, AST::Module& mod) -- cgit v1.2.3