diff options
Diffstat (limited to 'src/parser_api.rs')
-rw-r--r-- | src/parser_api.rs | 164 |
1 files changed, 164 insertions, 0 deletions
diff --git a/src/parser_api.rs b/src/parser_api.rs new file mode 100644 index 000000000..5a0da32c9 --- /dev/null +++ b/src/parser_api.rs | |||
@@ -0,0 +1,164 @@ | |||
1 | use { | ||
2 | parser_impl::ParserImpl, | ||
3 | SyntaxKind::{self, ERROR}, | ||
4 | }; | ||
5 | |||
6 | pub(crate) struct TokenSet { | ||
7 | pub tokens: &'static [SyntaxKind], | ||
8 | } | ||
9 | |||
10 | impl TokenSet { | ||
11 | pub fn contains(&self, kind: SyntaxKind) -> bool { | ||
12 | self.tokens.contains(&kind) | ||
13 | } | ||
14 | } | ||
15 | |||
16 | #[macro_export] | ||
17 | macro_rules! token_set { | ||
18 | ($($t:ident),*) => { | ||
19 | TokenSet { | ||
20 | tokens: &[$($t),*], | ||
21 | } | ||
22 | }; | ||
23 | |||
24 | ($($t:ident),* ,) => { | ||
25 | token_set!($($t),*) | ||
26 | }; | ||
27 | } | ||
28 | |||
29 | /// `Parser` struct provides the low-level API for | ||
30 | /// navigating through the stream of tokens and | ||
31 | /// constructing the parse tree. The actual parsing | ||
32 | /// happens in the `grammar` module. | ||
33 | /// | ||
34 | /// However, the result of this `Parser` is not a real | ||
35 | /// tree, but rather a flat stream of events of the form | ||
36 | /// "start expression, consume number literal, | ||
37 | /// finish expression". See `Event` docs for more. | ||
38 | pub(crate) struct Parser<'t>(pub(super) ParserImpl<'t>); | ||
39 | |||
40 | impl<'t> Parser<'t> { | ||
41 | /// Returns the kind of the current token. | ||
42 | /// If parser has already reached the end of input, | ||
43 | /// the special `EOF` kind is returned. | ||
44 | pub(crate) fn current(&self) -> SyntaxKind { | ||
45 | self.nth(0) | ||
46 | } | ||
47 | |||
48 | /// Lookahead operation: returns the kind of the next nth | ||
49 | /// token. | ||
50 | pub(crate) fn nth(&self, n: u32) -> SyntaxKind { | ||
51 | self.0.nth(n) | ||
52 | } | ||
53 | |||
54 | /// Checks if the current token is `kind`. | ||
55 | pub(crate) fn at(&self, kind: SyntaxKind) -> bool { | ||
56 | self.current() == kind | ||
57 | } | ||
58 | |||
59 | /// Checks if the current token is contextual keyword with text `t`. | ||
60 | pub(crate) fn at_contextual_kw(&self, t: &str) -> bool { | ||
61 | self.0.at_kw(t) | ||
62 | } | ||
63 | |||
64 | /// Starts a new node in the syntax tree. All nodes and tokens | ||
65 | /// consumed between the `start` and the corresponding `Marker::complete` | ||
66 | /// belong to the same node. | ||
67 | pub(crate) fn start(&mut self) -> Marker { | ||
68 | Marker(self.0.start()) | ||
69 | } | ||
70 | |||
71 | /// Advances the parser by one token. | ||
72 | pub(crate) fn bump(&mut self) { | ||
73 | self.0.bump(); | ||
74 | } | ||
75 | |||
76 | /// Advances the parser by one token, remapping its kind. | ||
77 | /// This is useful to create contextual keywords from | ||
78 | /// identifiers. For example, the lexer creates an `union` | ||
79 | /// *identifier* token, but the parser remaps it to the | ||
80 | /// `union` keyword, and keyword is what ends up in the | ||
81 | /// final tree. | ||
82 | pub(crate) fn bump_remap(&mut self, kind: SyntaxKind) { | ||
83 | self.0.bump_remap(kind); | ||
84 | } | ||
85 | |||
86 | /// Emit error with the `message` | ||
87 | /// TODO: this should be much more fancy and support | ||
88 | /// structured errors with spans and notes, like rustc | ||
89 | /// does. | ||
90 | pub(crate) fn error<T: Into<String>>(&mut self, message: T) { | ||
91 | self.0.error(message.into()) | ||
92 | } | ||
93 | |||
94 | /// Consume the next token if it is `kind`. | ||
95 | pub(crate) fn eat(&mut self, kind: SyntaxKind) -> bool { | ||
96 | if !self.at(kind) { | ||
97 | return false; | ||
98 | } | ||
99 | self.bump(); | ||
100 | true | ||
101 | } | ||
102 | |||
103 | /// Consume the next token if it is `kind` or emit an error | ||
104 | /// otherwise. | ||
105 | pub(crate) fn expect(&mut self, kind: SyntaxKind) -> bool { | ||
106 | if self.eat(kind) { | ||
107 | return true; | ||
108 | } | ||
109 | self.error(format!("expected {:?}", kind)); | ||
110 | false | ||
111 | } | ||
112 | |||
113 | /// Create an error node and consume the next token. | ||
114 | pub(crate) fn err_and_bump(&mut self, message: &str) { | ||
115 | let m = self.start(); | ||
116 | self.error(message); | ||
117 | self.bump(); | ||
118 | m.complete(self, ERROR); | ||
119 | } | ||
120 | } | ||
121 | |||
122 | /// See `Parser::start`. | ||
123 | pub(crate) struct Marker(u32); | ||
124 | |||
125 | impl Marker { | ||
126 | /// Finishes the syntax tree node and assigns `kind` to it. | ||
127 | pub(crate) fn complete(self, p: &mut Parser, kind: SyntaxKind) -> CompletedMarker { | ||
128 | let pos = self.0; | ||
129 | ::std::mem::forget(self); | ||
130 | p.0.complete(pos, kind); | ||
131 | CompletedMarker(pos) | ||
132 | } | ||
133 | |||
134 | /// Abandons the syntax tree node. All its children | ||
135 | /// are attached to its parent instead. | ||
136 | pub(crate) fn abandon(self, p: &mut Parser) { | ||
137 | let pos = self.0; | ||
138 | ::std::mem::forget(self); | ||
139 | p.0.abandon(pos); | ||
140 | } | ||
141 | } | ||
142 | |||
143 | impl Drop for Marker { | ||
144 | fn drop(&mut self) { | ||
145 | if !::std::thread::panicking() { | ||
146 | panic!("Marker must be either completed or abandoned"); | ||
147 | } | ||
148 | } | ||
149 | } | ||
150 | |||
151 | pub(crate) struct CompletedMarker(u32); | ||
152 | |||
153 | impl CompletedMarker { | ||
154 | /// This one is tricky :-) | ||
155 | /// This method allows to create a new node which starts | ||
156 | /// *before* the current one. That is, parser could start | ||
157 | /// node `A`, then complete it, and then after parsing the | ||
158 | /// whole `A`, decide that it should have started some node | ||
159 | /// `B` before starting `A`. `precede` allows to do exactly | ||
160 | /// that. See also docs about `forward_parent` in `Event::Start`. | ||
161 | pub(crate) fn precede(self, p: &mut Parser) -> Marker { | ||
162 | Marker(p.0.precede(self.0)) | ||
163 | } | ||
164 | } | ||