Skip to main content

oak_csharp/parser/
mod.rs

1//! Parser implementation for the C# language.
2
3use crate::language::CSharpLanguage;
4/// Element types for the C# parser.
5pub mod element_type;
6pub use element_type::CSharpElementType;
7use oak_core::{
8    GreenNode, OakError,
9    parser::{
10        ParseCache, ParseOutput, Parser, ParserState, parse_with_lexer,
11        pratt::{Associativity, Pratt, PrattParser, binary},
12    },
13    source::{Source, TextEdit},
14};
15
16pub(crate) type State<'a, S> = ParserState<'a, CSharpLanguage, S>;
17
18/// A parser for the C# language.
19///
20/// Implements the `Pratt` and `Parser` traits to provide a full C# parser
21/// capable of handling expressions, statements, and declarations.
22pub struct CSharpParser<'config> {
23    pub(crate) _language: &'config CSharpLanguage,
24}
25
26impl<'config> Pratt<CSharpLanguage> for CSharpParser<'config> {
27    fn primary<'a, S: oak_core::source::Source + ?Sized>(&self, state: &mut ParserState<'a, CSharpLanguage, S>) -> &'a GreenNode<'a, CSharpLanguage> {
28        use crate::lexer::token_type::CSharpTokenType;
29        let cp = state.checkpoint();
30        match state.peek_kind() {
31            Some(CSharpTokenType::Identifier) => {
32                state.bump();
33                state.finish_at(cp, crate::parser::element_type::CSharpElementType::IdentifierName)
34            }
35            Some(CSharpTokenType::Number)
36            | Some(CSharpTokenType::NumberLiteral)
37            | Some(CSharpTokenType::String)
38            | Some(CSharpTokenType::StringLiteral)
39            | Some(CSharpTokenType::TrueKeyword)
40            | Some(CSharpTokenType::FalseKeyword)
41            | Some(CSharpTokenType::NullKeyword) => {
42                state.bump();
43                state.finish_at(cp, crate::parser::element_type::CSharpElementType::LiteralExpression)
44            }
45            Some(CSharpTokenType::LeftParen) => {
46                state.bump();
47                PrattParser::parse(state, 0, self);
48                state.expect(CSharpTokenType::RightParen).ok();
49                state.finish_at(cp, crate::parser::element_type::CSharpElementType::ParenthesizedExpression)
50            }
51            Some(CSharpTokenType::This) => {
52                state.bump();
53                state.finish_at(cp, crate::parser::element_type::CSharpElementType::ThisExpression)
54            }
55            Some(CSharpTokenType::Base) => {
56                state.bump();
57                state.finish_at(cp, crate::parser::element_type::CSharpElementType::BaseExpression)
58            }
59            Some(CSharpTokenType::New) => {
60                state.bump();
61                self.parse_new_expression(state);
62                state.finish_at(cp, crate::parser::element_type::CSharpElementType::ObjectCreationExpression)
63            }
64            Some(CSharpTokenType::Await) => {
65                state.bump();
66                PrattParser::parse(state, 0, self);
67                state.finish_at(cp, crate::parser::element_type::CSharpElementType::AwaitExpression)
68            }
69            _ => {
70                state.bump();
71                state.finish_at(cp, crate::parser::element_type::CSharpElementType::Root)
72            }
73        }
74    }
75
76    fn prefix<'a, S: oak_core::source::Source + ?Sized>(&self, state: &mut ParserState<'a, CSharpLanguage, S>) -> &'a GreenNode<'a, CSharpLanguage> {
77        self.primary(state)
78    }
79
80    fn infix<'a, S: oak_core::source::Source + ?Sized>(&self, state: &mut ParserState<'a, CSharpLanguage, S>, left: &'a GreenNode<'a, CSharpLanguage>, min_precedence: u8) -> Option<&'a GreenNode<'a, CSharpLanguage>> {
81        use crate::{lexer::token_type::CSharpTokenType, parser::CSharpElementType::*};
82        let kind = state.peek_kind()?;
83
84        let (prec, assoc) = match kind {
85            CSharpTokenType::Assign
86            | CSharpTokenType::PlusAssign
87            | CSharpTokenType::MinusAssign
88            | CSharpTokenType::StarAssign
89            | CSharpTokenType::SlashAssign
90            | CSharpTokenType::PercentAssign
91            | CSharpTokenType::AndAssign
92            | CSharpTokenType::OrAssign
93            | CSharpTokenType::XorAssign
94            | CSharpTokenType::LeftShiftAssign
95            | CSharpTokenType::RightShiftAssign
96            | CSharpTokenType::QuestionQuestionAssign => (1, Associativity::Right),
97            CSharpTokenType::Lambda => (2, Associativity::Right),
98            CSharpTokenType::LogicalOr => (3, Associativity::Left),
99            CSharpTokenType::LogicalAnd => (4, Associativity::Left),
100            CSharpTokenType::Equal | CSharpTokenType::NotEqual | CSharpTokenType::Less | CSharpTokenType::Greater | CSharpTokenType::LessEqual | CSharpTokenType::GreaterEqual | CSharpTokenType::IsKeyword | CSharpTokenType::AsKeyword => {
101                (5, Associativity::Left)
102            }
103            CSharpTokenType::Plus | CSharpTokenType::Minus => (10, Associativity::Left),
104            CSharpTokenType::Star | CSharpTokenType::Slash | CSharpTokenType::Percent => (11, Associativity::Left),
105            CSharpTokenType::LeftParen | CSharpTokenType::LeftBracket | CSharpTokenType::Dot => (15, Associativity::Left),
106            _ => return None,
107        };
108
109        if prec < min_precedence {
110            return None;
111        }
112
113        match kind {
114            CSharpTokenType::LeftParen => {
115                let cp = state.checkpoint();
116                state.push_child(left);
117                state.expect(CSharpTokenType::LeftParen).ok();
118                while state.not_at_end() && !state.at(CSharpTokenType::RightParen) {
119                    PrattParser::parse(state, 0, self);
120                    if state.at(CSharpTokenType::Comma) {
121                        state.bump();
122                    }
123                }
124                state.expect(CSharpTokenType::RightParen).ok();
125                Some(state.finish_at(cp, crate::parser::element_type::CSharpElementType::InvocationExpression))
126            }
127            CSharpTokenType::LeftBracket => {
128                let cp = state.checkpoint();
129                state.push_child(left);
130                state.expect(CSharpTokenType::LeftBracket).ok();
131                while state.not_at_end() && !state.at(CSharpTokenType::RightBracket) {
132                    PrattParser::parse(state, 0, self);
133                    if state.at(CSharpTokenType::Comma) {
134                        state.bump();
135                    }
136                }
137                state.expect(CSharpTokenType::RightBracket).ok();
138                Some(state.finish_at(cp, crate::parser::element_type::CSharpElementType::ElementAccessExpression))
139            }
140            CSharpTokenType::Dot => {
141                let cp = state.checkpoint();
142                state.push_child(left);
143                state.expect(CSharpTokenType::Dot).ok();
144                state.expect(CSharpTokenType::Identifier).ok();
145                Some(state.finish_at(cp, crate::parser::element_type::CSharpElementType::MemberAccessExpression))
146            }
147            CSharpTokenType::Lambda => {
148                let cp = state.checkpoint();
149                state.push_child(left);
150                state.expect(CSharpTokenType::Lambda).ok();
151                PrattParser::parse(state, 0, self);
152                Some(state.finish_at(cp, crate::parser::element_type::CSharpElementType::LambdaExpression))
153            }
154            CSharpTokenType::Assign
155            | CSharpTokenType::PlusAssign
156            | CSharpTokenType::MinusAssign
157            | CSharpTokenType::StarAssign
158            | CSharpTokenType::SlashAssign
159            | CSharpTokenType::PercentAssign
160            | CSharpTokenType::AndAssign
161            | CSharpTokenType::OrAssign
162            | CSharpTokenType::XorAssign
163            | CSharpTokenType::LeftShiftAssign
164            | CSharpTokenType::RightShiftAssign
165            | CSharpTokenType::QuestionQuestionAssign => Some(binary(state, left, kind, prec, assoc, AssignmentExpression, |s, p| PrattParser::parse(s, p, self))),
166            _ => Some(binary(state, left, kind, prec, assoc, BinaryExpression, |s, p| PrattParser::parse(s, p, self))),
167        }
168    }
169}
170
171impl<'config> CSharpParser<'config> {
172    /// Creates a new C# parser.
173    pub fn new(language: &'config CSharpLanguage) -> Self {
174        Self { _language: language }
175    }
176
177    /// Parses a C# statement or declaration.
178    ///
179    /// This is the main dispatch method for the parser, routing to specific
180    /// methods based on the next token in the stream.
181    fn parse_statement<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), OakError> {
182        use crate::lexer::token_type::CSharpTokenType;
183        match state.peek_kind() {
184            Some(CSharpTokenType::Namespace) => self.parse_namespace_declaration(state)?,
185            Some(CSharpTokenType::Using) => self.parse_using_directive(state)?,
186            Some(CSharpTokenType::Class)
187            | Some(CSharpTokenType::Struct)
188            | Some(CSharpTokenType::Interface)
189            | Some(CSharpTokenType::Enum)
190            | Some(CSharpTokenType::Record)
191            | Some(CSharpTokenType::Delegate)
192            | Some(CSharpTokenType::Public)
193            | Some(CSharpTokenType::Private)
194            | Some(CSharpTokenType::Protected)
195            | Some(CSharpTokenType::Internal)
196            | Some(CSharpTokenType::Static)
197            | Some(CSharpTokenType::AsyncKeyword)
198            | Some(CSharpTokenType::Abstract)
199            | Some(CSharpTokenType::Virtual)
200            | Some(CSharpTokenType::Override) => self.parse_declaration(state)?,
201            Some(CSharpTokenType::If) => self.parse_if_statement(state)?,
202            Some(CSharpTokenType::While) => self.parse_while_statement(state)?,
203            Some(CSharpTokenType::For) => self.parse_for_statement(state)?,
204            Some(CSharpTokenType::Foreach) => self.parse_foreach_statement(state)?,
205            Some(CSharpTokenType::Return) => self.parse_return_statement(state)?,
206            Some(CSharpTokenType::Break) => {
207                let cp = state.checkpoint();
208                state.bump();
209                state.eat(CSharpTokenType::Semicolon);
210                state.finish_at(cp, crate::parser::CSharpElementType::BreakStatement);
211            }
212            Some(CSharpTokenType::Continue) => {
213                let cp = state.checkpoint();
214                state.bump();
215                state.eat(CSharpTokenType::Semicolon);
216                state.finish_at(cp, crate::parser::CSharpElementType::ContinueStatement);
217            }
218            Some(CSharpTokenType::Switch) => self.parse_switch_statement(state)?,
219            Some(CSharpTokenType::Try) => self.parse_try_statement(state)?,
220            Some(CSharpTokenType::LeftBrace) => self.parse_block(state)?,
221            _ => {
222                let cp = state.checkpoint();
223                PrattParser::parse(state, 0, self);
224                state.eat(CSharpTokenType::Semicolon);
225                state.finish_at(cp, crate::parser::CSharpElementType::ExpressionStatement);
226            }
227        }
228        Ok(())
229    }
230
231    /// Parses a `foreach` statement.
232    ///
233    /// Format: `foreach (Type var in collection) statement`
234    fn parse_foreach_statement<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), OakError> {
235        use crate::lexer::token_type::CSharpTokenType;
236        let cp = state.checkpoint();
237        state.bump(); // foreach
238        state.expect(CSharpTokenType::LeftParen).ok();
239        // type name in iterable
240        while state.not_at_end() && !state.at(CSharpTokenType::RightParen) {
241            state.bump();
242        }
243        state.expect(CSharpTokenType::RightParen).ok();
244        self.parse_statement(state)?;
245        state.finish_at(cp, crate::parser::element_type::CSharpElementType::ForeachStatement);
246        Ok(())
247    }
248
249    /// Parses a `namespace` declaration.
250    fn parse_namespace_declaration<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), OakError> {
251        use crate::lexer::token_type::CSharpTokenType;
252        let cp = state.checkpoint();
253        state.expect(CSharpTokenType::Namespace).ok();
254        while state.not_at_end() && !state.at(CSharpTokenType::LeftBrace) && !state.at(CSharpTokenType::Semicolon) {
255            state.bump();
256        }
257        if state.at(CSharpTokenType::LeftBrace) {
258            // Block-scoped namespace
259            self.parse_block(state)?;
260        }
261        else {
262            // File-scoped namespace (C# 10+)
263            state.eat(CSharpTokenType::Semicolon);
264        }
265        state.finish_at(cp, crate::parser::element_type::CSharpElementType::NamespaceDeclaration);
266        Ok(())
267    }
268
269    /// Parses a `using` directive.
270    fn parse_using_directive<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), OakError> {
271        use crate::lexer::token_type::CSharpTokenType;
272        let cp = state.checkpoint();
273        state.expect(CSharpTokenType::Using).ok();
274        while state.not_at_end() && !state.at(CSharpTokenType::Semicolon) {
275            state.bump();
276        }
277        state.eat(CSharpTokenType::Semicolon);
278        state.finish_at(cp, crate::parser::element_type::CSharpElementType::UsingDirective);
279        Ok(())
280    }
281
282    /// Parses an accessor block (e.g., `{ get; set; }` for properties).
283    fn parse_accessor_block<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), OakError> {
284        use crate::lexer::token_type::CSharpTokenType;
285        state.expect(CSharpTokenType::LeftBrace).ok();
286        while state.not_at_end() && !state.at(CSharpTokenType::RightBrace) {
287            match state.peek_kind() {
288                Some(CSharpTokenType::GetKeyword) | Some(CSharpTokenType::SetKeyword) | Some(CSharpTokenType::AddKeyword) | Some(CSharpTokenType::RemoveKeyword) => {
289                    state.bump();
290                    if state.at(CSharpTokenType::LeftBrace) {
291                        self.parse_block(state)?;
292                    }
293                    else {
294                        state.eat(CSharpTokenType::Semicolon);
295                    }
296                }
297                _ => {
298                    state.bump();
299                }
300            }
301        }
302        state.expect(CSharpTokenType::RightBrace).ok();
303        Ok(())
304    }
305
306    /// Parses a declaration (class, interface, struct, enum, record, delegate, event, field, property, or method).
307    fn parse_declaration<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), OakError> {
308        use crate::lexer::token_type::CSharpTokenType;
309        let cp = state.checkpoint();
310
311        // Handle modifiers
312        while state.not_at_end()
313            && matches!(
314                state.peek_kind(),
315                Some(CSharpTokenType::Public)
316                    | Some(CSharpTokenType::Private)
317                    | Some(CSharpTokenType::Protected)
318                    | Some(CSharpTokenType::Internal)
319                    | Some(CSharpTokenType::Static)
320                    | Some(CSharpTokenType::Readonly)
321                    | Some(CSharpTokenType::Abstract)
322                    | Some(CSharpTokenType::Virtual)
323                    | Some(CSharpTokenType::Override)
324                    | Some(CSharpTokenType::AsyncKeyword)
325            )
326        {
327            state.bump();
328        }
329
330        match state.peek_kind() {
331            Some(CSharpTokenType::Class) => {
332                state.bump();
333                state.expect(CSharpTokenType::Identifier).ok();
334                // Base types and generics
335                while state.not_at_end() && !state.at(CSharpTokenType::LeftBrace) {
336                    state.bump();
337                }
338                self.parse_block(state)?;
339                state.finish_at(cp, crate::parser::element_type::CSharpElementType::ClassDeclaration);
340            }
341            Some(CSharpTokenType::Interface) => {
342                state.bump();
343                state.expect(CSharpTokenType::Identifier).ok();
344                while state.not_at_end() && !state.at(CSharpTokenType::LeftBrace) {
345                    state.bump();
346                }
347                self.parse_block(state)?;
348                state.finish_at(cp, crate::parser::element_type::CSharpElementType::InterfaceDeclaration);
349            }
350            Some(CSharpTokenType::Struct) => {
351                state.bump();
352                state.expect(CSharpTokenType::Identifier).ok();
353                while state.not_at_end() && !state.at(CSharpTokenType::LeftBrace) {
354                    state.bump();
355                }
356                self.parse_block(state)?;
357                state.finish_at(cp, crate::parser::element_type::CSharpElementType::StructDeclaration);
358            }
359            Some(CSharpTokenType::Enum) => {
360                state.bump();
361                state.expect(CSharpTokenType::Identifier).ok();
362                self.parse_block(state)?;
363                state.finish_at(cp, crate::parser::element_type::CSharpElementType::EnumDeclaration);
364            }
365            Some(CSharpTokenType::Record) => {
366                state.bump();
367                // Check for record struct (C# 10+)
368                if state.eat(CSharpTokenType::Struct) {
369                    // Record struct
370                }
371                state.expect(CSharpTokenType::Identifier).ok();
372                while state.not_at_end() && !state.at(CSharpTokenType::LeftBrace) && !state.at(CSharpTokenType::Semicolon) {
373                    state.bump();
374                }
375                if state.at(CSharpTokenType::LeftBrace) {
376                    self.parse_block(state)?;
377                }
378                else {
379                    state.eat(CSharpTokenType::Semicolon);
380                }
381                state.finish_at(cp, crate::parser::element_type::CSharpElementType::RecordDeclaration);
382            }
383            Some(CSharpTokenType::Delegate) => {
384                state.bump();
385                // Type name (parameters);
386                while state.not_at_end() && !state.at(CSharpTokenType::Semicolon) {
387                    state.bump();
388                }
389                state.eat(CSharpTokenType::Semicolon);
390                state.finish_at(cp, crate::parser::element_type::CSharpElementType::DelegateDeclaration);
391            }
392            Some(CSharpTokenType::Event) => {
393                state.bump();
394                // Type name;
395                while state.not_at_end() && !state.at(CSharpTokenType::Semicolon) && !state.at(CSharpTokenType::LeftBrace) {
396                    state.bump();
397                }
398                if state.at(CSharpTokenType::LeftBrace) {
399                    self.parse_accessor_block(state)?;
400                }
401                else {
402                    state.eat(CSharpTokenType::Semicolon);
403                }
404                state.finish_at(cp, crate::parser::element_type::CSharpElementType::EventDeclaration);
405            }
406            _ => {
407                // Property, Method, or Field
408                // Simplified processing
409                state.bump(); // Type
410                while state.not_at_end() && !state.at(CSharpTokenType::Semicolon) && !state.at(CSharpTokenType::LeftBrace) && !state.at(CSharpTokenType::LeftParen) {
411                    state.bump();
412                }
413
414                if state.eat(CSharpTokenType::This) && state.at(CSharpTokenType::LeftBracket) {
415                    // Indexer
416                    state.bump(); // [
417                    while state.not_at_end() && !state.at(CSharpTokenType::RightBracket) {
418                        state.bump();
419                    }
420                    state.expect(CSharpTokenType::RightBracket).ok();
421                    self.parse_accessor_block(state)?;
422                    state.finish_at(cp, crate::parser::element_type::CSharpElementType::IndexerDeclaration);
423                }
424                else {
425                    state.expect(CSharpTokenType::Identifier).ok();
426                    if state.at(CSharpTokenType::LeftParen) {
427                        // Method
428                        state.bump(); // (
429                        while state.not_at_end() && !state.at(CSharpTokenType::RightParen) {
430                            state.bump();
431                        }
432                        state.expect(CSharpTokenType::RightParen).ok();
433                        if state.at(CSharpTokenType::LeftBrace) {
434                            self.parse_block(state)?;
435                        }
436                        else {
437                            state.eat(CSharpTokenType::Semicolon);
438                        }
439                        state.finish_at(cp, crate::parser::element_type::CSharpElementType::MethodDeclaration);
440                    }
441                    else if state.at(CSharpTokenType::LeftBrace) {
442                        // Property
443                        self.parse_accessor_block(state)?;
444                        state.finish_at(cp, crate::parser::element_type::CSharpElementType::PropertyDeclaration);
445                    }
446                    else {
447                        // Field
448                        state.eat(CSharpTokenType::Semicolon);
449                        state.finish_at(cp, crate::parser::element_type::CSharpElementType::FieldDeclaration);
450                    }
451                }
452            }
453        }
454        Ok(())
455    }
456
457    /// Parses an `if` statement.
458    fn parse_if_statement<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), OakError> {
459        use crate::lexer::token_type::CSharpTokenType;
460        let cp = state.checkpoint();
461        state.bump(); // if
462        state.expect(CSharpTokenType::LeftParen).ok();
463        PrattParser::parse(state, 0, self);
464        state.expect(CSharpTokenType::RightParen).ok();
465        self.parse_statement(state)?;
466        if state.eat(CSharpTokenType::Else) {
467            self.parse_statement(state)?;
468        }
469        state.finish_at(cp, crate::parser::element_type::CSharpElementType::IfStatement);
470        Ok(())
471    }
472
473    /// Parses a `while` statement.
474    fn parse_while_statement<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), OakError> {
475        use crate::lexer::token_type::CSharpTokenType;
476        let cp = state.checkpoint();
477        state.bump(); // while
478        state.expect(CSharpTokenType::LeftParen).ok();
479        PrattParser::parse(state, 0, self);
480        state.expect(CSharpTokenType::RightParen).ok();
481        self.parse_statement(state)?;
482        state.finish_at(cp, crate::parser::element_type::CSharpElementType::WhileStatement);
483        Ok(())
484    }
485
486    /// Parses a `for` statement.
487    fn parse_for_statement<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), OakError> {
488        use crate::lexer::token_type::CSharpTokenType;
489        let cp = state.checkpoint();
490        state.bump(); // for
491        state.expect(CSharpTokenType::LeftParen).ok();
492        PrattParser::parse(state, 0, self);
493        state.expect(CSharpTokenType::RightParen).ok();
494        self.parse_statement(state)?;
495        state.finish_at(cp, crate::parser::element_type::CSharpElementType::ForStatement);
496        Ok(())
497    }
498
499    /// Parses a block statement enclosed in braces `{ ... }`.
500    fn parse_block<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), OakError> {
501        use crate::lexer::token_type::CSharpTokenType;
502        let cp = state.checkpoint();
503        state.expect(CSharpTokenType::LeftBrace).ok();
504        while state.not_at_end() && !state.at(CSharpTokenType::RightBrace) {
505            self.parse_statement(state)?;
506        }
507        state.expect(CSharpTokenType::RightBrace).ok();
508        state.finish_at(cp, crate::parser::element_type::CSharpElementType::Block);
509        Ok(())
510    }
511
512    /// Parses a `return` statement.
513    fn parse_return_statement<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), OakError> {
514        use crate::lexer::token_type::CSharpTokenType;
515        let cp = state.checkpoint();
516        state.bump(); // return
517        if !state.at(CSharpTokenType::Semicolon) {
518            PrattParser::parse(state, 0, self);
519        }
520        state.eat(CSharpTokenType::Semicolon);
521        state.finish_at(cp, crate::parser::element_type::CSharpElementType::ReturnStatement);
522        Ok(())
523    }
524
525    /// Parses a new expression (object creation).
526    fn parse_new_expression<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) {
527        use crate::lexer::token_type::CSharpTokenType;
528        // Parse type name
529        while state.not_at_end() && !state.at(CSharpTokenType::LeftParen) && !state.at(CSharpTokenType::LeftBrace) {
530            state.bump();
531        }
532
533        // Parse constructor arguments
534        if state.at(CSharpTokenType::LeftParen) {
535            state.bump();
536            while state.not_at_end() && !state.at(CSharpTokenType::RightParen) {
537                PrattParser::parse(state, 0, self);
538                if state.at(CSharpTokenType::Comma) {
539                    state.bump();
540                }
541            }
542            state.expect(CSharpTokenType::RightParen).ok();
543        }
544
545        // Parse object initializer
546        if state.at(CSharpTokenType::LeftBrace) {
547            self.parse_block(state).ok();
548        }
549    }
550
551    /// Parses a `switch` statement.
552    fn parse_switch_statement<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), OakError> {
553        use crate::lexer::token_type::CSharpTokenType;
554        let cp = state.checkpoint();
555        state.bump(); // switch
556        state.expect(CSharpTokenType::LeftParen).ok();
557        PrattParser::parse(state, 0, self);
558        state.expect(CSharpTokenType::RightParen).ok();
559        state.expect(CSharpTokenType::LeftBrace).ok();
560
561        while state.not_at_end() && !state.at(CSharpTokenType::RightBrace) {
562            match state.peek_kind() {
563                Some(CSharpTokenType::Case) => {
564                    state.bump();
565                    PrattParser::parse(state, 0, self);
566                    state.expect(CSharpTokenType::Colon).ok();
567                    while state.not_at_end() && !state.at(CSharpTokenType::Case) && !state.at(CSharpTokenType::Default) && !state.at(CSharpTokenType::RightBrace) {
568                        self.parse_statement(state)?;
569                    }
570                }
571                Some(CSharpTokenType::Default) => {
572                    state.bump();
573                    state.expect(CSharpTokenType::Colon).ok();
574                    while state.not_at_end() && !state.at(CSharpTokenType::RightBrace) {
575                        self.parse_statement(state)?;
576                    }
577                }
578                _ => {
579                    state.bump();
580                }
581            }
582        }
583
584        state.expect(CSharpTokenType::RightBrace).ok();
585        state.finish_at(cp, crate::parser::element_type::CSharpElementType::SwitchStatement);
586        Ok(())
587    }
588
589    /// Parses a `try` statement with optional `catch` and `finally` blocks.
590    fn parse_try_statement<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), OakError> {
591        use crate::lexer::token_type::CSharpTokenType;
592        let cp = state.checkpoint();
593        state.bump(); // try
594        self.parse_block(state)?;
595
596        // Parse catch blocks
597        while state.not_at_end() && state.at(CSharpTokenType::Catch) {
598            state.bump(); // catch
599            if state.at(CSharpTokenType::LeftParen) {
600                state.bump();
601                while state.not_at_end() && !state.at(CSharpTokenType::RightParen) {
602                    state.bump();
603                }
604                state.expect(CSharpTokenType::RightParen).ok();
605            }
606            self.parse_block(state)?;
607        }
608
609        // Parse finally block
610        if state.not_at_end() && state.at(CSharpTokenType::Finally) {
611            state.bump(); // finally
612            self.parse_block(state)?;
613        }
614
615        state.finish_at(cp, crate::parser::element_type::CSharpElementType::TryStatement);
616        Ok(())
617    }
618}
619
620impl<'config> Parser<CSharpLanguage> for CSharpParser<'config> {
621    fn parse<'a, S: Source + ?Sized>(&self, text: &'a S, edits: &[TextEdit], cache: &'a mut impl ParseCache<CSharpLanguage>) -> ParseOutput<'a, CSharpLanguage> {
622        let lexer = crate::lexer::CSharpLexer::new(self._language);
623        parse_with_lexer(&lexer, text, edits, cache, |state| {
624            let cp = state.checkpoint();
625            while state.not_at_end() {
626                self.parse_statement(state)?;
627            }
628            Ok(state.finish_at(cp, crate::parser::element_type::CSharpElementType::Root))
629        })
630    }
631}