aboutsummaryrefslogtreecommitdiff
path: root/src/parser/grammar/items
diff options
context:
space:
mode:
Diffstat (limited to 'src/parser/grammar/items')
-rw-r--r--src/parser/grammar/items/consts.rs21
-rw-r--r--src/parser/grammar/items/mod.rs196
-rw-r--r--src/parser/grammar/items/structs.rs117
-rw-r--r--src/parser/grammar/items/traits.rs17
-rw-r--r--src/parser/grammar/items/use_item.rs66
5 files changed, 417 insertions, 0 deletions
diff --git a/src/parser/grammar/items/consts.rs b/src/parser/grammar/items/consts.rs
new file mode 100644
index 000000000..c9881d681
--- /dev/null
+++ b/src/parser/grammar/items/consts.rs
@@ -0,0 +1,21 @@
1use super::*;
2
3pub(super) fn static_item(p: &mut Parser) {
4 const_or_static(p, STATIC_KW)
5}
6
7pub(super) fn const_item(p: &mut Parser) {
8 const_or_static(p, CONST_KW)
9}
10
11fn const_or_static(p: &mut Parser, kw: SyntaxKind) {
12 assert!(p.at(kw));
13 p.bump();
14 p.eat(MUT_KW); // TODO: validator to forbid const mut
15 p.expect(IDENT);
16 p.expect(COLON);
17 types::type_ref(p);
18 p.expect(EQ);
19 expressions::expr(p);
20 p.expect(SEMI);
21}
diff --git a/src/parser/grammar/items/mod.rs b/src/parser/grammar/items/mod.rs
new file mode 100644
index 000000000..3612802e1
--- /dev/null
+++ b/src/parser/grammar/items/mod.rs
@@ -0,0 +1,196 @@
1use super::*;
2
3mod structs;
4mod use_item;
5mod consts;
6mod traits;
7
8pub(super) fn mod_contents(p: &mut Parser, stop_on_r_curly: bool) {
9 attributes::inner_attributes(p);
10 while !p.at(EOF) && !(stop_on_r_curly && p.at(R_CURLY)) {
11 item(p);
12 }
13}
14
15pub(super) const ITEM_FIRST: TokenSet = token_set![
16 EXTERN_KW, MOD_KW, USE_KW, STRUCT_KW, ENUM_KW, FN_KW, PUB_KW, POUND
17];
18
19fn item(p: &mut Parser) {
20 let item = p.start();
21 attributes::outer_attributes(p);
22 visibility(p);
23 let la = p.nth(1);
24 let item_kind = match p.current() {
25 USE_KW => {
26 use_item::use_item(p);
27 USE_ITEM
28 }
29 // test extern_crate
30 // extern crate foo;
31 EXTERN_KW if la == CRATE_KW => {
32 extern_crate_item(p);
33 EXTERN_CRATE_ITEM
34 }
35 EXTERN_KW => {
36 abi(p);
37 match p.current() {
38 // test extern_fn
39 // extern fn foo() {}
40 FN_KW => {
41 fn_item(p);
42 FN_ITEM
43 }
44 // test extern_block
45 // extern {}
46 L_CURLY => {
47 extern_block(p);
48 EXTERN_BLOCK
49 }
50 // test extern_struct
51 // extern struct Foo;
52 _ => {
53 item.abandon(p);
54 p.error().message("expected `fn` or `{`").emit();
55 return;
56 }
57 }
58 }
59 STATIC_KW => {
60 consts::static_item(p);
61 STATIC_ITEM
62 }
63 CONST_KW => match p.nth(1) {
64 // test const_fn
65 // const fn foo() {}
66 FN_KW => {
67 p.bump();
68 fn_item(p);
69 FN_ITEM
70 }
71 // test const_unsafe_fn
72 // const unsafe fn foo() {}
73 UNSAFE_KW if p.nth(2) == FN_KW => {
74 p.bump();
75 p.bump();
76 fn_item(p);
77 FN_ITEM
78 }
79 _ => {
80 consts::const_item(p);
81 CONST_ITEM
82 }
83 },
84 // TODO: auto trait
85 // test unsafe_trait
86 // unsafe trait T {}
87 UNSAFE_KW if la == TRAIT_KW => {
88 p.bump();
89 traits::trait_item(p);
90 TRAIT_ITEM
91 }
92 // TODO: default impl
93 // test unsafe_impl
94 // unsafe impl Foo {}
95 UNSAFE_KW if la == IMPL_KW => {
96 p.bump();
97 traits::impl_item(p);
98 IMPL_ITEM
99 }
100 MOD_KW => {
101 mod_item(p);
102 MOD_ITEM
103 }
104 STRUCT_KW => {
105 structs::struct_item(p);
106 STRUCT_ITEM
107 }
108 ENUM_KW => {
109 structs::enum_item(p);
110 ENUM_ITEM
111 }
112 FN_KW => {
113 fn_item(p);
114 FN_ITEM
115 }
116 L_CURLY => {
117 item.abandon(p);
118 error_block(p, "expected item");
119 return;
120 }
121 err_token => {
122 item.abandon(p);
123 let message = if err_token == SEMI {
124 //TODO: if the item is incomplete, this message is misleading
125 "expected item, found `;`\n\
126 consider removing this semicolon"
127 } else {
128 "expected item"
129 };
130 p.err_and_bump(message);
131 return;
132 }
133 };
134 item.complete(p, item_kind);
135}
136
137fn extern_crate_item(p: &mut Parser) {
138 assert!(p.at(EXTERN_KW));
139 p.bump();
140 assert!(p.at(CRATE_KW));
141 p.bump();
142
143 p.expect(IDENT) && alias(p) && p.expect(SEMI);
144}
145
146fn extern_block(p: &mut Parser) {
147 assert!(p.at(L_CURLY));
148 p.bump();
149 p.expect(R_CURLY);
150}
151
152fn mod_item(p: &mut Parser) {
153 assert!(p.at(MOD_KW));
154 p.bump();
155
156 if p.expect(IDENT) && !p.eat(SEMI) {
157 if p.expect(L_CURLY) {
158 mod_contents(p, true);
159 p.expect(R_CURLY);
160 }
161 }
162}
163
164fn abi(p: &mut Parser) {
165 assert!(p.at(EXTERN_KW));
166 let abi = p.start();
167 p.bump();
168 match p.current() {
169 STRING | RAW_STRING => p.bump(),
170 _ => (),
171 }
172 abi.complete(p, ABI);
173}
174
175fn fn_item(p: &mut Parser) {
176 assert!(p.at(FN_KW));
177 p.bump();
178
179 p.expect(IDENT);
180 if p.at(L_PAREN) {
181 fn_value_parameters(p);
182 } else {
183 p.error().message("expected function arguments").emit();
184 }
185
186 if p.at(L_CURLY) {
187 p.expect(L_CURLY);
188 p.expect(R_CURLY);
189 }
190
191 fn fn_value_parameters(p: &mut Parser) {
192 assert!(p.at(L_PAREN));
193 p.bump();
194 p.expect(R_PAREN);
195 }
196}
diff --git a/src/parser/grammar/items/structs.rs b/src/parser/grammar/items/structs.rs
new file mode 100644
index 000000000..69d95c698
--- /dev/null
+++ b/src/parser/grammar/items/structs.rs
@@ -0,0 +1,117 @@
1use super::*;
2
3pub(super) fn struct_item(p: &mut Parser) {
4 assert!(p.at(STRUCT_KW));
5 p.bump();
6
7 if !p.expect(IDENT) {
8 return;
9 }
10 type_params::list(p);
11 match p.current() {
12 WHERE_KW => {
13 type_params::where_clause(p);
14 match p.current() {
15 SEMI => {
16 p.bump();
17 return;
18 }
19 L_CURLY => named_fields(p),
20 _ => {
21 //TODO: special case `(` error message
22 p.error().message("expected `;` or `{`").emit();
23 return;
24 }
25 }
26 }
27 SEMI => {
28 p.bump();
29 return;
30 }
31 L_CURLY => named_fields(p),
32 L_PAREN => {
33 pos_fields(p);
34 p.expect(SEMI);
35 }
36 _ => {
37 p.error().message("expected `;`, `{`, or `(`").emit();
38 return;
39 }
40 }
41}
42
43pub(super) fn enum_item(p: &mut Parser) {
44 assert!(p.at(ENUM_KW));
45 p.bump();
46 p.expect(IDENT);
47 type_params::list(p);
48 type_params::where_clause(p);
49 if p.expect(L_CURLY) {
50 while !p.at(EOF) && !p.at(R_CURLY) {
51 let var = p.start();
52 attributes::outer_attributes(p);
53 if p.at(IDENT) {
54 p.bump();
55 match p.current() {
56 L_CURLY => named_fields(p),
57 L_PAREN => pos_fields(p),
58 EQ => {
59 p.bump();
60 expressions::expr(p);
61 }
62 _ => (),
63 }
64 var.complete(p, ENUM_VARIANT);
65 } else {
66 var.abandon(p);
67 p.err_and_bump("expected enum variant");
68 }
69 if !p.at(R_CURLY) {
70 p.expect(COMMA);
71 }
72 }
73 p.expect(R_CURLY);
74 }
75}
76
77fn named_fields(p: &mut Parser) {
78 assert!(p.at(L_CURLY));
79 p.bump();
80 while !p.at(R_CURLY) && !p.at(EOF) {
81 named_field(p);
82 if !p.at(R_CURLY) {
83 p.expect(COMMA);
84 }
85 }
86 p.expect(R_CURLY);
87
88 fn named_field(p: &mut Parser) {
89 let field = p.start();
90 visibility(p);
91 if p.expect(IDENT) {
92 p.expect(COLON);
93 types::type_ref(p);
94 field.complete(p, NAMED_FIELD);
95 } else {
96 field.abandon(p);
97 p.err_and_bump("expected field declaration");
98 }
99 }
100}
101
102fn pos_fields(p: &mut Parser) {
103 if !p.expect(L_PAREN) {
104 return;
105 }
106 while !p.at(R_PAREN) && !p.at(EOF) {
107 let pos_field = p.start();
108 visibility(p);
109 types::type_ref(p);
110 pos_field.complete(p, POS_FIELD);
111
112 if !p.at(R_PAREN) {
113 p.expect(COMMA);
114 }
115 }
116 p.expect(R_PAREN);
117}
diff --git a/src/parser/grammar/items/traits.rs b/src/parser/grammar/items/traits.rs
new file mode 100644
index 000000000..3bef9639f
--- /dev/null
+++ b/src/parser/grammar/items/traits.rs
@@ -0,0 +1,17 @@
1use super::*;
2
3pub(super) fn trait_item(p: &mut Parser) {
4 assert!(p.at(TRAIT_KW));
5 p.bump();
6 p.expect(IDENT);
7 p.expect(L_CURLY);
8 p.expect(R_CURLY);
9}
10
11pub(super) fn impl_item(p: &mut Parser) {
12 assert!(p.at(IMPL_KW));
13 p.bump();
14 p.expect(IDENT);
15 p.expect(L_CURLY);
16 p.expect(R_CURLY);
17}
diff --git a/src/parser/grammar/items/use_item.rs b/src/parser/grammar/items/use_item.rs
new file mode 100644
index 000000000..38e7b3f8a
--- /dev/null
+++ b/src/parser/grammar/items/use_item.rs
@@ -0,0 +1,66 @@
1use super::*;
2
3pub(super) fn use_item(p: &mut Parser) {
4 assert!(p.at(USE_KW));
5 p.bump();
6 use_tree(p);
7 p.expect(SEMI);
8}
9
10fn use_tree(p: &mut Parser) {
11 let la = p.nth(1);
12 let m = p.start();
13 match (p.current(), la) {
14 (STAR, _) => p.bump(),
15 (COLONCOLON, STAR) => {
16 p.bump();
17 p.bump();
18 }
19 (L_CURLY, _) | (COLONCOLON, L_CURLY) => {
20 if p.at(COLONCOLON) {
21 p.bump();
22 }
23 nested_trees(p);
24 }
25 _ if paths::is_path_start(p) => {
26 paths::use_path(p);
27 match p.current() {
28 AS_KW => {
29 alias(p);
30 }
31 COLONCOLON => {
32 p.bump();
33 match p.current() {
34 STAR => {
35 p.bump();
36 }
37 L_CURLY => nested_trees(p),
38 _ => {
39 // is this unreachable?
40 p.error().message("expected `{` or `*`").emit();
41 }
42 }
43 }
44 _ => (),
45 }
46 }
47 _ => {
48 m.abandon(p);
49 p.err_and_bump("expected one of `*`, `::`, `{`, `self`, `super`, `indent`");
50 return;
51 }
52 }
53 m.complete(p, USE_TREE);
54}
55
56fn nested_trees(p: &mut Parser) {
57 assert!(p.at(L_CURLY));
58 p.bump();
59 while !p.at(EOF) && !p.at(R_CURLY) {
60 use_tree(p);
61 if !p.at(R_CURLY) {
62 p.expect(COMMA);
63 }
64 }
65 p.expect(R_CURLY);
66}