1use crate::{kind::TypeScriptSyntaxKind, language::TypeScriptLanguage, lexer::TypeScriptLexer};
2use oak_core::{
3 GreenNode, OakError, TextEdit, TokenType,
4 parser::{
5 ParseCache, ParseOutput, Parser, ParserState, parse_with_lexer,
6 pratt::{Associativity, Pratt, PrattParser, binary},
7 },
8 source::Source,
9};
10
11pub(crate) type State<'a, S> = ParserState<'a, TypeScriptLanguage, S>;
12
13pub struct TypeScriptParser<'config> {
14 pub(crate) config: &'config TypeScriptLanguage,
15}
16
17impl<'config> Pratt<TypeScriptLanguage> for TypeScriptParser<'config> {
18 fn primary<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> &'a GreenNode<'a, TypeScriptLanguage> {
19 use crate::kind::TypeScriptSyntaxKind::*;
20 let cp = state.checkpoint();
21 match state.peek_kind() {
22 Some(IdentifierName) => {
23 state.bump();
24 state.finish_at(cp, IdentifierName.into())
25 }
26 Some(NumericLiteral) | Some(StringLiteral) | Some(True) | Some(False) | Some(Null) => {
27 state.bump();
28 state.finish_at(cp, NumericLiteral.into()) }
30 Some(LeftParen) => {
31 state.bump();
32 PrattParser::parse(state, 0, self);
33 state.expect(RightParen).ok();
34 state.finish_at(cp, BinaryExpression.into()) }
36 _ => {
37 state.bump();
38 state.finish_at(cp, Error.into())
39 }
40 }
41 }
42
43 fn prefix<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> &'a GreenNode<'a, TypeScriptLanguage> {
44 self.primary(state)
45 }
46
47 fn infix<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>, left: &'a GreenNode<'a, TypeScriptLanguage>, min_precedence: u8) -> Option<&'a GreenNode<'a, TypeScriptLanguage>> {
48 use crate::kind::TypeScriptSyntaxKind::*;
49 let kind = state.peek_kind()?;
50
51 let (prec, assoc) = match kind {
52 Equal
53 | PlusEqual
54 | MinusEqual
55 | StarEqual
56 | SlashEqual
57 | PercentEqual
58 | StarStarEqual
59 | LeftShiftEqual
60 | RightShiftEqual
61 | UnsignedRightShiftEqual
62 | AmpersandEqual
63 | PipeEqual
64 | CaretEqual
65 | AmpersandAmpersandEqual
66 | PipePipeEqual
67 | QuestionQuestionEqual => (1, Associativity::Right),
68 PipePipe => (2, Associativity::Left),
69 AmpersandAmpersand => (3, Associativity::Left),
70 EqualEqual | NotEqual | EqualEqualEqual | NotEqualEqual => (4, Associativity::Left),
71 As => (14, Associativity::Left),
72 Plus | Minus => (10, Associativity::Left),
73 Star | Slash | Percent => (11, Associativity::Left),
74 LeftParen | Dot => (15, Associativity::Left),
75 _ => return None,
76 };
77
78 if prec < min_precedence {
79 return None;
80 }
81
82 match kind {
83 LeftParen => {
84 let cp = state.checkpoint();
85 state.push_child(left);
86 state.expect(LeftParen).ok();
87 while state.not_at_end() && !state.at(RightParen) {
88 state.advance();
89 }
90 state.expect(RightParen).ok();
91 Some(state.finish_at(cp, CallExpression.into()))
92 }
93 Dot => {
94 let cp = state.checkpoint();
95 state.push_child(left);
96 state.expect(Dot).ok();
97 state.expect(IdentifierName).ok();
98 Some(state.finish_at(cp, MemberExpression.into()))
99 }
100 As => {
101 let cp = state.checkpoint();
102 state.push_child(left);
103 state.expect(As).ok();
104 state.advance();
106 Some(state.finish_at(cp, AsExpression.into()))
107 }
108 _ => Some(binary(state, left, kind, prec, assoc, BinaryExpression.into(), |s, p| PrattParser::parse(s, p, self))),
109 }
110 }
111}
112
113impl<'config> TypeScriptParser<'config> {
114 pub fn new(config: &'config TypeScriptLanguage) -> Self {
115 Self { config }
116 }
117
118 pub(crate) fn parse_statement<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), OakError> {
119 use crate::kind::TypeScriptSyntaxKind::*;
120 match state.peek_kind() {
121 Some(Var) | Some(Let) | Some(Const) => self.parse_variable_declaration(state)?,
122 Some(Function) => self.parse_function_declaration(state)?,
123 Some(Class) => self.parse_class_declaration(state)?,
124 Some(Interface) => self.parse_interface_declaration(state)?,
125 Some(Enum) => self.parse_enum_declaration(state)?,
126 Some(Type) => self.parse_type_alias_declaration(state)?,
127 Some(Namespace) | Some(Module) => self.parse_namespace_declaration(state)?,
128 Some(Import) => self.parse_import_declaration(state)?,
129 Some(Export) => self.parse_export_declaration(state)?,
130 Some(If) => self.parse_if_statement(state)?,
131 Some(For) => self.parse_for_statement(state)?,
132 Some(While) => self.parse_while_statement(state)?,
133 Some(Return) => self.parse_return_statement(state)?,
134 Some(LeftBrace) => self.parse_block(state)?,
135 _ => {
136 PrattParser::parse(state, 0, self);
137 state.eat(Semicolon);
138 }
139 }
140 Ok(())
141 }
142
143 fn parse_variable_declaration<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), OakError> {
144 use crate::kind::TypeScriptSyntaxKind::*;
145 let cp = state.checkpoint();
146 state.bump(); while state.at(IdentifierName) {
148 state.bump();
149 if state.eat(Equal) {
150 PrattParser::parse(state, 0, self);
151 }
152 if !state.eat(Comma) {
153 break;
154 }
155 }
156 state.eat(Semicolon);
157 state.finish_at(cp, VariableDeclaration.into());
158 Ok(())
159 }
160
161 fn parse_function_declaration<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), OakError> {
162 use crate::kind::TypeScriptSyntaxKind::*;
163 let cp = state.checkpoint();
164 state.bump(); state.expect(IdentifierName).ok();
166 self.parse_parameters(state)?;
167 self.parse_block(state)?;
168 state.finish_at(cp, FunctionDeclaration.into());
169 Ok(())
170 }
171
172 fn parse_class_declaration<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), OakError> {
173 use crate::kind::TypeScriptSyntaxKind::*;
174 let cp = state.checkpoint();
175 state.bump(); state.expect(IdentifierName).ok();
177 if state.eat(Extends) {
178 state.expect(IdentifierName).ok();
179 }
180 self.parse_block(state)?;
181 state.finish_at(cp, ClassDeclaration.into());
182 Ok(())
183 }
184
185 fn parse_interface_declaration<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), OakError> {
186 use crate::kind::TypeScriptSyntaxKind::*;
187 let cp = state.checkpoint();
188 state.bump(); state.expect(IdentifierName).ok();
190 self.parse_block(state)?;
191 state.finish_at(cp, InterfaceDeclaration.into());
192 Ok(())
193 }
194
195 fn parse_enum_declaration<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), OakError> {
196 use crate::kind::TypeScriptSyntaxKind::*;
197 let cp = state.checkpoint();
198 state.bump(); state.expect(IdentifierName).ok();
200 self.parse_block(state)?;
201 state.finish_at(cp, EnumDeclaration.into());
202 Ok(())
203 }
204
205 fn parse_type_alias_declaration<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), OakError> {
206 use crate::kind::TypeScriptSyntaxKind::*;
207 let cp = state.checkpoint();
208 state.bump(); state.expect(IdentifierName).ok();
210 state.expect(Equal).ok();
211 while state.not_at_end() && !state.at(Semicolon) {
212 state.advance();
213 }
214 state.eat(Semicolon);
215 state.finish_at(cp, TypeAliasDeclaration.into());
216 Ok(())
217 }
218
219 fn parse_namespace_declaration<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), OakError> {
220 use crate::kind::TypeScriptSyntaxKind::*;
221 let cp = state.checkpoint();
222 state.bump(); state.expect(IdentifierName).ok();
224 self.parse_block(state)?;
225 state.finish_at(cp, NamespaceDeclaration.into());
226 Ok(())
227 }
228
229 fn parse_import_declaration<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), OakError> {
230 use crate::kind::TypeScriptSyntaxKind::*;
231 let cp = state.checkpoint();
232 state.bump(); while state.not_at_end() && !state.at(Semicolon) {
234 state.advance();
235 }
236 state.eat(Semicolon);
237 state.finish_at(cp, ImportDeclaration.into());
238 Ok(())
239 }
240
241 fn parse_export_declaration<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), OakError> {
242 use crate::kind::TypeScriptSyntaxKind::*;
243 let cp = state.checkpoint();
244 state.bump(); self.parse_statement(state)?;
246 state.finish_at(cp, ExportDeclaration.into());
247 Ok(())
248 }
249
250 fn parse_if_statement<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), OakError> {
251 use crate::kind::TypeScriptSyntaxKind::*;
252 let cp = state.checkpoint();
253 state.bump(); state.expect(LeftParen).ok();
255 PrattParser::parse(state, 0, self);
256 state.expect(RightParen).ok();
257 self.parse_statement(state)?;
258 if state.eat(Else) {
259 self.parse_statement(state)?;
260 }
261 state.finish_at(cp, IfStatement.into());
262 Ok(())
263 }
264
265 fn parse_for_statement<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), OakError> {
266 use crate::kind::TypeScriptSyntaxKind::*;
267 let cp = state.checkpoint();
268 state.bump(); state.expect(LeftParen).ok();
270 while state.not_at_end() && !state.at(RightParen) {
271 state.advance();
272 }
273 state.expect(RightParen).ok();
274 self.parse_statement(state)?;
275 state.finish_at(cp, ForStatement.into());
276 Ok(())
277 }
278
279 fn parse_while_statement<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), OakError> {
280 use crate::kind::TypeScriptSyntaxKind::*;
281 let cp = state.checkpoint();
282 state.bump(); state.expect(LeftParen).ok();
284 PrattParser::parse(state, 0, self);
285 state.expect(RightParen).ok();
286 self.parse_statement(state)?;
287 state.finish_at(cp, WhileStatement.into());
288 Ok(())
289 }
290
291 fn parse_parameters<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), OakError> {
292 use crate::kind::TypeScriptSyntaxKind::*;
293 state.expect(LeftParen).ok();
294 while state.not_at_end() && !state.at(RightParen) {
295 state.advance();
296 }
297 state.expect(RightParen).ok();
298 Ok(())
299 }
300
301 fn parse_block<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), OakError> {
302 use crate::kind::TypeScriptSyntaxKind::*;
303 let cp = state.checkpoint();
304 state.expect(LeftBrace).ok();
305 while state.not_at_end() && !state.at(RightBrace) {
306 self.parse_statement(state)?;
307 }
308 state.expect(RightBrace).ok();
309 state.finish_at(cp, BlockStatement.into());
310 Ok(())
311 }
312
313 fn parse_return_statement<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), OakError> {
314 use crate::kind::TypeScriptSyntaxKind::*;
315 let cp = state.checkpoint();
316 state.bump(); if !state.at(Semicolon) && !state.at(RightBrace) {
318 PrattParser::parse(state, 0, self);
319 }
320 state.eat(Semicolon);
321 state.finish_at(cp, ReturnStatement.into());
322 Ok(())
323 }
324}
325
326impl<'config> Parser<TypeScriptLanguage> for TypeScriptParser<'config> {
327 fn parse<'a, S: Source + ?Sized>(&self, text: &'a S, edits: &[TextEdit], cache: &'a mut impl ParseCache<TypeScriptLanguage>) -> ParseOutput<'a, TypeScriptLanguage> {
328 let lexer = TypeScriptLexer::new(self.config);
329 parse_with_lexer(&lexer, text, edits, cache, |state| {
330 let checkpoint = state.checkpoint();
331 while state.not_at_end() {
332 if state.current().map(|t| t.kind.is_ignored()).unwrap_or(false) {
333 state.advance();
334 continue;
335 }
336 self.parse_statement(state).ok();
337 }
338 Ok(state.finish_at(checkpoint, TypeScriptSyntaxKind::SourceFile.into()))
339 })
340 }
341}