diff options
Diffstat (limited to 'crates/parser/src/grammar/items/use_item.rs')
-rw-r--r-- | crates/parser/src/grammar/items/use_item.rs | 132 |
1 files changed, 132 insertions, 0 deletions
diff --git a/crates/parser/src/grammar/items/use_item.rs b/crates/parser/src/grammar/items/use_item.rs new file mode 100644 index 000000000..20e6a13cf --- /dev/null +++ b/crates/parser/src/grammar/items/use_item.rs | |||
@@ -0,0 +1,132 @@ | |||
1 | //! FIXME: write short doc here | ||
2 | |||
3 | use super::*; | ||
4 | |||
5 | pub(super) fn use_(p: &mut Parser, m: Marker) { | ||
6 | assert!(p.at(T![use])); | ||
7 | p.bump(T![use]); | ||
8 | use_tree(p, true); | ||
9 | p.expect(T![;]); | ||
10 | m.complete(p, USE); | ||
11 | } | ||
12 | |||
13 | /// Parse a use 'tree', such as `some::path` in `use some::path;` | ||
14 | /// Note that this is called both by `use_item` and `use_tree_list`, | ||
15 | /// so handles both `some::path::{inner::path}` and `inner::path` in | ||
16 | /// `use some::path::{inner::path};` | ||
17 | fn use_tree(p: &mut Parser, top_level: bool) { | ||
18 | let m = p.start(); | ||
19 | match p.current() { | ||
20 | // Finish the use_tree for cases of e.g. | ||
21 | // `use some::path::{self, *};` or `use *;` | ||
22 | // This does not handle cases such as `use some::path::*` | ||
23 | // N.B. in Rust 2015 `use *;` imports all from crate root | ||
24 | // however in Rust 2018 `use *;` errors: ('cannot glob-import all possible crates') | ||
25 | // FIXME: Add this error (if not out of scope) | ||
26 | |||
27 | // test use_star | ||
28 | // use *; | ||
29 | // use ::*; | ||
30 | // use some::path::{*}; | ||
31 | // use some::path::{::*}; | ||
32 | T![*] => p.bump(T![*]), | ||
33 | T![:] if p.at(T![::]) && p.nth(2) == T![*] => { | ||
34 | // Parse `use ::*;`, which imports all from the crate root in Rust 2015 | ||
35 | // This is invalid inside a use_tree_list, (e.g. `use some::path::{::*}`) | ||
36 | // but still parses and errors later: ('crate root in paths can only be used in start position') | ||
37 | // FIXME: Add this error (if not out of scope) | ||
38 | // In Rust 2018, it is always invalid (see above) | ||
39 | p.bump(T![::]); | ||
40 | p.bump(T![*]); | ||
41 | } | ||
42 | // Open a use tree list | ||
43 | // Handles cases such as `use {some::path};` or `{inner::path}` in | ||
44 | // `use some::path::{{inner::path}, other::path}` | ||
45 | |||
46 | // test use_tree_list | ||
47 | // use {crate::path::from::root, or::path::from::crate_name}; // Rust 2018 (with a crate named `or`) | ||
48 | // use {path::from::root}; // Rust 2015 | ||
49 | // use ::{some::arbritrary::path}; // Rust 2015 | ||
50 | // use ::{{{root::export}}}; // Nonsensical but perfectly legal nesting | ||
51 | T!['{'] => { | ||
52 | use_tree_list(p); | ||
53 | } | ||
54 | T![:] if p.at(T![::]) && p.nth(2) == T!['{'] => { | ||
55 | p.bump(T![::]); | ||
56 | use_tree_list(p); | ||
57 | } | ||
58 | // Parse a 'standard' path. | ||
59 | // Also handles aliases (e.g. `use something as something_else`) | ||
60 | |||
61 | // test use_path | ||
62 | // use ::crate_name; // Rust 2018 - All flavours | ||
63 | // use crate_name; // Rust 2018 - Anchored paths | ||
64 | // use item_in_scope_or_crate_name; // Rust 2018 - Uniform Paths | ||
65 | // | ||
66 | // use self::module::Item; | ||
67 | // use crate::Item; | ||
68 | // use self::some::Struct; | ||
69 | // use crate_name::some_item; | ||
70 | _ if paths::is_use_path_start(p) => { | ||
71 | paths::use_path(p); | ||
72 | match p.current() { | ||
73 | T![as] => { | ||
74 | // test use_alias | ||
75 | // use some::path as some_name; | ||
76 | // use some::{ | ||
77 | // other::path as some_other_name, | ||
78 | // different::path as different_name, | ||
79 | // yet::another::path, | ||
80 | // running::out::of::synonyms::for_::different::* | ||
81 | // }; | ||
82 | // use Trait as _; | ||
83 | opt_rename(p); | ||
84 | } | ||
85 | T![:] if p.at(T![::]) => { | ||
86 | p.bump(T![::]); | ||
87 | match p.current() { | ||
88 | T![*] => { | ||
89 | p.bump(T![*]); | ||
90 | } | ||
91 | // test use_tree_list_after_path | ||
92 | // use crate::{Item}; | ||
93 | // use self::{Item}; | ||
94 | T!['{'] => use_tree_list(p), | ||
95 | _ => { | ||
96 | // is this unreachable? | ||
97 | p.error("expected `{` or `*`"); | ||
98 | } | ||
99 | } | ||
100 | } | ||
101 | _ => (), | ||
102 | } | ||
103 | } | ||
104 | _ => { | ||
105 | m.abandon(p); | ||
106 | let msg = "expected one of `*`, `::`, `{`, `self`, `super` or an identifier"; | ||
107 | if top_level { | ||
108 | p.err_recover(msg, ITEM_RECOVERY_SET); | ||
109 | } else { | ||
110 | // if we are parsing a nested tree, we have to eat a token to | ||
111 | // main balanced `{}` | ||
112 | p.err_and_bump(msg); | ||
113 | } | ||
114 | return; | ||
115 | } | ||
116 | } | ||
117 | m.complete(p, USE_TREE); | ||
118 | } | ||
119 | |||
120 | pub(crate) fn use_tree_list(p: &mut Parser) { | ||
121 | assert!(p.at(T!['{'])); | ||
122 | let m = p.start(); | ||
123 | p.bump(T!['{']); | ||
124 | while !p.at(EOF) && !p.at(T!['}']) { | ||
125 | use_tree(p, false); | ||
126 | if !p.at(T!['}']) { | ||
127 | p.expect(T![,]); | ||
128 | } | ||
129 | } | ||
130 | p.expect(T!['}']); | ||
131 | m.complete(p, USE_TREE_LIST); | ||
132 | } | ||