aboutsummaryrefslogtreecommitdiff
path: root/crates/parser/src/grammar/paths.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/parser/src/grammar/paths.rs')
-rw-r--r--crates/parser/src/grammar/paths.rs115
1 files changed, 115 insertions, 0 deletions
diff --git a/crates/parser/src/grammar/paths.rs b/crates/parser/src/grammar/paths.rs
new file mode 100644
index 000000000..52562afa4
--- /dev/null
+++ b/crates/parser/src/grammar/paths.rs
@@ -0,0 +1,115 @@
1//! FIXME: write short doc here
2
3use super::*;
4
5pub(super) const PATH_FIRST: TokenSet =
6 token_set![IDENT, T![self], T![super], T![crate], T![:], T![<]];
7
8pub(super) fn is_path_start(p: &Parser) -> bool {
9 is_use_path_start(p) || p.at(T![<])
10}
11
12pub(super) fn is_use_path_start(p: &Parser) -> bool {
13 match p.current() {
14 IDENT | T![self] | T![super] | T![crate] => true,
15 T![:] if p.at(T![::]) => true,
16 _ => false,
17 }
18}
19
20pub(super) fn use_path(p: &mut Parser) {
21 path(p, Mode::Use)
22}
23
24pub(crate) fn type_path(p: &mut Parser) {
25 path(p, Mode::Type)
26}
27
28pub(super) fn expr_path(p: &mut Parser) {
29 path(p, Mode::Expr)
30}
31
32#[derive(Clone, Copy, Eq, PartialEq)]
33enum Mode {
34 Use,
35 Type,
36 Expr,
37}
38
39fn path(p: &mut Parser, mode: Mode) {
40 let path = p.start();
41 path_segment(p, mode, true);
42 let mut qual = path.complete(p, PATH);
43 loop {
44 let use_tree = matches!(p.nth(2), T![*] | T!['{']);
45 if p.at(T![::]) && !use_tree {
46 let path = qual.precede(p);
47 p.bump(T![::]);
48 path_segment(p, mode, false);
49 let path = path.complete(p, PATH);
50 qual = path;
51 } else {
52 break;
53 }
54 }
55}
56
57fn path_segment(p: &mut Parser, mode: Mode, first: bool) {
58 let m = p.start();
59 // test qual_paths
60 // type X = <A as B>::Output;
61 // fn foo() { <usize as Default>::default(); }
62 if first && p.eat(T![<]) {
63 types::type_(p);
64 if p.eat(T![as]) {
65 if is_use_path_start(p) {
66 types::path_type(p);
67 } else {
68 p.error("expected a trait");
69 }
70 }
71 p.expect(T![>]);
72 } else {
73 let mut empty = true;
74 if first {
75 p.eat(T![::]);
76 empty = false;
77 }
78 match p.current() {
79 IDENT => {
80 name_ref(p);
81 opt_path_type_args(p, mode);
82 }
83 // test crate_path
84 // use crate::foo;
85 T![self] | T![super] | T![crate] => p.bump_any(),
86 _ => {
87 p.err_recover("expected identifier", items::ITEM_RECOVERY_SET);
88 if empty {
89 // test_err empty_segment
90 // use crate::;
91 m.abandon(p);
92 return;
93 }
94 }
95 };
96 }
97 m.complete(p, PATH_SEGMENT);
98}
99
100fn opt_path_type_args(p: &mut Parser, mode: Mode) {
101 match mode {
102 Mode::Use => {}
103 Mode::Type => {
104 // test path_fn_trait_args
105 // type F = Box<Fn(i32) -> ()>;
106 if p.at(T!['(']) {
107 params::param_list_fn_trait(p);
108 opt_ret_type(p);
109 } else {
110 type_args::opt_generic_arg_list(p, false)
111 }
112 }
113 Mode::Expr => type_args::opt_generic_arg_list(p, true),
114 }
115}