aboutsummaryrefslogtreecommitdiff
path: root/src/parser/grammar
diff options
context:
space:
mode:
Diffstat (limited to 'src/parser/grammar')
-rw-r--r--src/parser/grammar/attributes.rs79
-rw-r--r--src/parser/grammar/expressions.rs20
-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
-rw-r--r--src/parser/grammar/mod.rs130
-rw-r--r--src/parser/grammar/paths.rs49
-rw-r--r--src/parser/grammar/type_params.rs75
-rw-r--r--src/parser/grammar/types.rs5
11 files changed, 775 insertions, 0 deletions
diff --git a/src/parser/grammar/attributes.rs b/src/parser/grammar/attributes.rs
new file mode 100644
index 000000000..8bf04afce
--- /dev/null
+++ b/src/parser/grammar/attributes.rs
@@ -0,0 +1,79 @@
1use super::*;
2
3pub(super) fn inner_attributes(p: &mut Parser) {
4 while p.at([POUND, EXCL]) {
5 attribute(p, true)
6 }
7}
8
9pub(super) fn outer_attributes(p: &mut Parser) {
10 while p.at(POUND) {
11 attribute(p, false)
12 }
13}
14
15fn attribute(p: &mut Parser, inner: bool) {
16 let attr = p.start();
17 assert!(p.at(POUND));
18 p.bump();
19
20 if inner {
21 assert!(p.at(EXCL));
22 p.bump();
23 }
24
25 if p.expect(L_BRACK) {
26 meta_item(p);
27 p.expect(R_BRACK);
28 }
29 attr.complete(p, ATTR);
30}
31
32fn meta_item(p: &mut Parser) {
33 if p.at(IDENT) {
34 let meta_item = p.start();
35 p.bump();
36 match p.current() {
37 EQ => {
38 p.bump();
39 if !expressions::literal(p) {
40 p.error().message("expected literal").emit();
41 }
42 }
43 L_PAREN => meta_item_arg_list(p),
44 _ => (),
45 }
46 meta_item.complete(p, META_ITEM);
47 } else {
48 p.error().message("expected attribute value").emit()
49 }
50}
51
52fn meta_item_arg_list(p: &mut Parser) {
53 assert!(p.at(L_PAREN));
54 p.bump();
55 loop {
56 match p.current() {
57 EOF | R_PAREN => break,
58 IDENT => meta_item(p),
59 c => if !expressions::literal(p) {
60 let message = "expected attribute";
61
62 if items::ITEM_FIRST.contains(c) {
63 p.error().message(message).emit();
64 return;
65 }
66
67 let err = p.start();
68 p.error().message(message).emit();
69 p.bump();
70 err.complete(p, ERROR);
71 continue;
72 },
73 }
74 if !p.at(R_PAREN) {
75 p.expect(COMMA);
76 }
77 }
78 p.expect(R_PAREN);
79}
diff --git a/src/parser/grammar/expressions.rs b/src/parser/grammar/expressions.rs
new file mode 100644
index 000000000..8caaf3553
--- /dev/null
+++ b/src/parser/grammar/expressions.rs
@@ -0,0 +1,20 @@
1use super::*;
2
3pub(super) fn literal(p: &mut Parser) -> bool {
4 match p.current() {
5 TRUE_KW | FALSE_KW | INT_NUMBER | FLOAT_NUMBER | BYTE | CHAR | STRING | RAW_STRING
6 | BYTE_STRING | RAW_BYTE_STRING => {
7 let lit = p.start();
8 p.bump();
9 lit.complete(p, LITERAL);
10 true
11 }
12 _ => false,
13 }
14}
15
16pub(super) fn expr(p: &mut Parser) {
17 if !literal(p) {
18 p.error().message("expected expression").emit();
19 }
20}
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}
diff --git a/src/parser/grammar/mod.rs b/src/parser/grammar/mod.rs
new file mode 100644
index 000000000..afce308d0
--- /dev/null
+++ b/src/parser/grammar/mod.rs
@@ -0,0 +1,130 @@
1use super::parser::{Parser, TokenSet};
2use SyntaxKind;
3use syntax_kinds::*;
4
5mod items;
6mod attributes;
7mod expressions;
8mod types;
9mod paths;
10mod type_params;
11
12pub(crate) fn file(p: &mut Parser) {
13 let file = p.start();
14 p.eat(SHEBANG);
15 items::mod_contents(p, false);
16 file.complete(p, FILE);
17}
18
19fn visibility(p: &mut Parser) {
20 if p.at(PUB_KW) {
21 let vis = p.start();
22 p.bump();
23 if p.at(L_PAREN) {
24 match p.nth(1) {
25 CRATE_KW | SELF_KW | SUPER_KW => {
26 p.bump();
27 p.bump();
28 p.expect(R_PAREN);
29 }
30 IN_KW => {
31 p.bump();
32 p.bump();
33 paths::use_path(p);
34 p.expect(R_PAREN);
35 }
36 _ => (),
37 }
38 }
39 vis.complete(p, VISIBILITY);
40 }
41}
42
43fn alias(p: &mut Parser) -> bool {
44 if p.at(AS_KW) {
45 let alias = p.start();
46 p.bump();
47 p.expect(IDENT);
48 alias.complete(p, ALIAS);
49 }
50 true //FIXME: return false if three are errors
51}
52
53fn error_block(p: &mut Parser, message: &str) {
54 assert!(p.at(L_CURLY));
55 let err = p.start();
56 p.error().message(message).emit();
57 p.bump();
58 let mut level: u32 = 1;
59 while level > 0 && !p.at(EOF) {
60 match p.current() {
61 L_CURLY => level += 1,
62 R_CURLY => level -= 1,
63 _ => (),
64 }
65 p.bump();
66 }
67 err.complete(p, ERROR);
68}
69
70impl<'p> Parser<'p> {
71 fn at<L: Lookahead>(&self, l: L) -> bool {
72 l.is_ahead(self)
73 }
74
75 fn err_and_bump(&mut self, message: &str) {
76 let err = self.start();
77 self.error().message(message).emit();
78 self.bump();
79 err.complete(self, ERROR);
80 }
81
82 fn expect(&mut self, kind: SyntaxKind) -> bool {
83 if self.at(kind) {
84 self.bump();
85 true
86 } else {
87 self.error().message(format!("expected {:?}", kind)).emit();
88 false
89 }
90 }
91
92 fn eat(&mut self, kind: SyntaxKind) -> bool {
93 self.current() == kind && {
94 self.bump();
95 true
96 }
97 }
98}
99
100trait Lookahead: Copy {
101 fn is_ahead(self, p: &Parser) -> bool;
102}
103
104impl Lookahead for SyntaxKind {
105 fn is_ahead(self, p: &Parser) -> bool {
106 p.current() == self
107 }
108}
109
110impl Lookahead for [SyntaxKind; 2] {
111 fn is_ahead(self, p: &Parser) -> bool {
112 p.current() == self[0] && p.nth(1) == self[1]
113 }
114}
115
116impl Lookahead for [SyntaxKind; 3] {
117 fn is_ahead(self, p: &Parser) -> bool {
118 p.current() == self[0] && p.nth(1) == self[1] && p.nth(2) == self[2]
119 }
120}
121
122#[derive(Clone, Copy)]
123struct AnyOf<'a>(&'a [SyntaxKind]);
124
125impl<'a> Lookahead for AnyOf<'a> {
126 fn is_ahead(self, p: &Parser) -> bool {
127 let curr = p.current();
128 self.0.iter().any(|&k| k == curr)
129 }
130}
diff --git a/src/parser/grammar/paths.rs b/src/parser/grammar/paths.rs
new file mode 100644
index 000000000..6efac2610
--- /dev/null
+++ b/src/parser/grammar/paths.rs
@@ -0,0 +1,49 @@
1use super::*;
2
3pub(super) fn is_path_start(p: &Parser) -> bool {
4 AnyOf(&[IDENT, SELF_KW, SUPER_KW, COLONCOLON]).is_ahead(p)
5}
6
7pub(super) fn use_path(p: &mut Parser) {
8 path(p)
9}
10
11pub(super) fn type_path(p: &mut Parser) {
12 path(p)
13}
14
15fn path(p: &mut Parser) {
16 if !is_path_start(p) {
17 return;
18 }
19 let path = p.start();
20 path_segment(p, true);
21 let mut qual = path.complete(p, PATH);
22 loop {
23 let use_tree = match p.nth(1) {
24 STAR | L_CURLY => true,
25 _ => false,
26 };
27 if p.at(COLONCOLON) && !use_tree {
28 let path = qual.precede(p);
29 p.bump();
30 path_segment(p, false);
31 let path = path.complete(p, PATH);
32 qual = path;
33 } else {
34 break;
35 }
36 }
37}
38
39fn path_segment(p: &mut Parser, first: bool) {
40 let segment = p.start();
41 if first {
42 p.eat(COLONCOLON);
43 }
44 match p.current() {
45 IDENT | SELF_KW | SUPER_KW => p.bump(),
46 _ => p.error().message("expected identifier").emit(),
47 };
48 segment.complete(p, PATH_SEGMENT);
49}
diff --git a/src/parser/grammar/type_params.rs b/src/parser/grammar/type_params.rs
new file mode 100644
index 000000000..12c9a5362
--- /dev/null
+++ b/src/parser/grammar/type_params.rs
@@ -0,0 +1,75 @@
1use super::*;
2
3pub(super) fn list(p: &mut Parser) {
4 if !p.at(L_ANGLE) {
5 return;
6 }
7 let m = p.start();
8 p.bump();
9
10 while !p.at(EOF) && !p.at(R_ANGLE) {
11 match p.current() {
12 LIFETIME => lifetime_param(p),
13 IDENT => type_param(p),
14 _ => p.err_and_bump("expected type parameter"),
15 }
16 if !p.at(R_ANGLE) && !p.expect(COMMA) {
17 break;
18 }
19 }
20 p.expect(R_ANGLE);
21 m.complete(p, TYPE_PARAM_LIST);
22
23 fn lifetime_param(p: &mut Parser) {
24 assert!(p.at(LIFETIME));
25 let m = p.start();
26 p.bump();
27 if p.eat(COLON) {
28 while p.at(LIFETIME) {
29 p.bump();
30 if !p.eat(PLUS) {
31 break;
32 }
33 }
34 }
35 m.complete(p, LIFETIME_PARAM);
36 }
37
38 fn type_param(p: &mut Parser) {
39 assert!(p.at(IDENT));
40 let m = p.start();
41 p.bump();
42 if p.eat(COLON) {
43 loop {
44 let has_paren = p.eat(L_PAREN);
45 p.eat(QUESTION);
46 if p.at(FOR_KW) {
47 //TODO
48 }
49 if p.at(LIFETIME) {
50 p.bump();
51 } else if paths::is_path_start(p) {
52 paths::type_path(p);
53 } else {
54 break;
55 }
56 if has_paren {
57 p.expect(R_PAREN);
58 }
59 if !p.eat(PLUS) {
60 break;
61 }
62 }
63 }
64 if p.at(EQ) {
65 types::type_ref(p)
66 }
67 m.complete(p, TYPE_PARAM);
68 }
69}
70
71pub(super) fn where_clause(p: &mut Parser) {
72 if p.at(WHERE_KW) {
73 p.bump();
74 }
75}
diff --git a/src/parser/grammar/types.rs b/src/parser/grammar/types.rs
new file mode 100644
index 000000000..1a3d44a0a
--- /dev/null
+++ b/src/parser/grammar/types.rs
@@ -0,0 +1,5 @@
1use super::*;
2
3pub(super) fn type_ref(p: &mut Parser) {
4 p.expect(IDENT);
5}