Skip to main content

oak_fsharp/parser/
mod.rs

1/// Element type module
2pub mod element_type;
3
4use crate::{
5    language::FSharpLanguage,
6    lexer::{FSharpLexer, token_type::FSharpTokenType},
7    parser::element_type::FSharpElementType,
8};
9use oak_core::{
10    GreenNode, OakError,
11    parser::{ParseCache, ParseOutput, Parser, ParserState, parse_with_lexer},
12    source::{Source, TextEdit},
13};
14
15pub(crate) type State<'a, S> = ParserState<'a, FSharpLanguage, S>;
16
17/// F# parser
18pub struct FSharpParser<'config> {
19    pub(crate) config: &'config FSharpLanguage,
20}
21
22impl<'config> FSharpParser<'config> {
23    /// Creates a new FSharpParser
24    pub fn new(config: &'config FSharpLanguage) -> Self {
25        Self { config }
26    }
27
28    fn parse_namespace<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), OakError> {
29        let checkpoint = state.checkpoint();
30        state.expect(FSharpTokenType::Namespace)?;
31
32        // Parse namespace name (e.g. System.Collections)
33        while state.not_at_end() && state.at(FSharpTokenType::Identifier) {
34            state.bump();
35            if state.at(FSharpTokenType::Dot) { state.bump() } else { break }
36        }
37
38        state.finish_at(checkpoint, FSharpElementType::Namespace);
39        Ok(())
40    }
41
42    fn parse_module<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), OakError> {
43        let checkpoint = state.checkpoint();
44        state.expect(FSharpTokenType::Module)?;
45
46        if state.at(FSharpTokenType::Identifier) {
47            state.bump()
48        }
49
50        state.finish_at(checkpoint, FSharpElementType::Module);
51        Ok(())
52    }
53
54    fn parse_open<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), OakError> {
55        let checkpoint = state.checkpoint();
56        state.expect(FSharpTokenType::Open)?;
57
58        // Parse namespace/module name to open
59        while state.not_at_end() && state.at(FSharpTokenType::Identifier) {
60            state.bump();
61            if state.at(FSharpTokenType::Dot) { state.bump() } else { break }
62        }
63
64        state.finish_at(checkpoint, FSharpElementType::Open);
65        Ok(())
66    }
67
68    fn parse_binding<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), OakError> {
69        let checkpoint = state.checkpoint();
70        state.expect(FSharpTokenType::Let)?;
71
72        if state.eat(FSharpTokenType::Rec) {
73            // optional rec
74        }
75
76        // Name
77        state.expect(FSharpTokenType::Identifier)?;
78
79        // Parameters (optional)
80        while state.not_at_end() && state.at(FSharpTokenType::Identifier) {
81            state.bump()
82        }
83
84        // Equals
85        state.expect(FSharpTokenType::Equal)?;
86
87        // Expression
88        self.parse_expression(state)?;
89
90        state.finish_at(checkpoint, FSharpElementType::Let);
91        Ok(())
92    }
93
94    fn parse_expression<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), OakError> {
95        let checkpoint = state.checkpoint();
96        let kind = state.peek_kind();
97        match kind {
98            Some(FSharpTokenType::If) => {
99                state.expect(FSharpTokenType::If)?;
100                self.parse_expression(state)?;
101                state.expect(FSharpTokenType::Then)?;
102                self.parse_expression(state)?;
103                if state.eat(FSharpTokenType::Else) {
104                    self.parse_expression(state)?
105                }
106                state.finish_at(checkpoint, FSharpElementType::If);
107            }
108            Some(FSharpTokenType::Match) => {
109                self.parse_match_expression(state, checkpoint)?;
110            }
111            Some(FSharpTokenType::Let) => {
112                self.parse_let_expression(state, checkpoint)?;
113            }
114            Some(FSharpTokenType::Fun) => {
115                self.parse_lambda_expression(state, checkpoint)?;
116            }
117            Some(FSharpTokenType::Function) => {
118                self.parse_function_expression(state, checkpoint)?;
119            }
120            Some(FSharpTokenType::Open) => {
121                self.parse_open(state)?;
122            }
123            Some(FSharpTokenType::LeftParen) => {
124                self.parse_parenthesized_expression(state, checkpoint)?;
125            }
126            Some(FSharpTokenType::LeftBracket) => {
127                self.parse_list_or_array_expression(state, checkpoint)?;
128            }
129            Some(FSharpTokenType::LeftBrace) => {
130                self.parse_record_expression(state, checkpoint)?;
131            }
132            Some(FSharpTokenType::Identifier) => {
133                self.parse_identifier_expression(state, checkpoint)?;
134            }
135            Some(FSharpTokenType::IntegerLiteral) | Some(FSharpTokenType::FloatLiteral) | Some(FSharpTokenType::StringLiteral) | Some(FSharpTokenType::CharLiteral) => {
136                self.parse_literal_expression(state, checkpoint)?;
137            }
138            _ => {
139                // Simple expression: consume until end of line or specific delimiters
140                while state.not_at_end() {
141                    let kind = state.peek_kind();
142                    if matches!(kind, Some(FSharpTokenType::Newline | FSharpTokenType::Then | FSharpTokenType::Else | FSharpTokenType::In | FSharpTokenType::PipeRight | FSharpTokenType::PipeGreater)) {
143                        break;
144                    }
145                    state.bump()
146                }
147                // If we didn't consume anything, just bump one to avoid infinite loop
148                if state.checkpoint().0 == checkpoint.0 {
149                    state.bump()
150                }
151                state.finish_at(checkpoint, FSharpElementType::Expression);
152            }
153        }
154        Ok(())
155    }
156
157    fn parse_function_expression<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>, checkpoint: (usize, usize)) -> Result<(), OakError> {
158        state.expect(FSharpTokenType::Function)?;
159
160        // Parse function parameters with optional type annotations
161        while state.not_at_end() && state.at(FSharpTokenType::Identifier) {
162            state.bump();
163            // Check for type annotation
164            if state.eat(FSharpTokenType::Colon) {
165                self.parse_type(state)?;
166            }
167        }
168
169        // Parse match cases
170        while state.not_at_end() && !state.at(FSharpTokenType::End) {
171            self.parse_match_case(state)?;
172        }
173
174        state.eat(FSharpTokenType::End);
175        state.finish_at(checkpoint, FSharpElementType::Function);
176        Ok(())
177    }
178
179    fn parse_match_expression<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>, checkpoint: (usize, usize)) -> Result<(), OakError> {
180        state.expect(FSharpTokenType::Match)?;
181        self.parse_expression(state)?;
182        state.expect(FSharpTokenType::With)?;
183
184        while state.not_at_end() && !state.at(FSharpTokenType::End) {
185            self.parse_match_case(state)?;
186        }
187
188        state.eat(FSharpTokenType::End);
189        state.finish_at(checkpoint, FSharpElementType::Match);
190        Ok(())
191    }
192
193    fn parse_match_case<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), OakError> {
194        let checkpoint = state.checkpoint();
195
196        // Parse pattern
197        self.parse_pattern(state)?;
198
199        // Optional guard
200        if state.eat(FSharpTokenType::When) {
201            self.parse_expression(state)?;
202        }
203
204        state.expect(FSharpTokenType::Arrow)?;
205        self.parse_expression(state)?;
206
207        state.finish_at(checkpoint, FSharpElementType::MatchCase);
208        Ok(())
209    }
210
211    fn parse_pattern<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), OakError> {
212        let checkpoint = state.checkpoint();
213        let kind = state.peek_kind();
214
215        match kind {
216            Some(FSharpTokenType::Underscore) => {
217                state.bump();
218                state.finish_at(checkpoint, FSharpElementType::WildcardPattern);
219            }
220            Some(FSharpTokenType::Identifier) => {
221                state.bump();
222                // Check for active pattern
223                if state.at(FSharpTokenType::LeftParen) {
224                    state.bump();
225                    // Parse active pattern parameters
226                    while state.not_at_end() && !state.at(FSharpTokenType::RightParen) {
227                        self.parse_expression(state)?;
228                        if state.at(FSharpTokenType::Comma) {
229                            state.bump();
230                        }
231                    }
232                    state.expect(FSharpTokenType::RightParen)?;
233                    state.finish_at(checkpoint, FSharpElementType::ActivePattern);
234                }
235                else if state.at(FSharpTokenType::Pipe) {
236                    // Check for partial active pattern
237                    state.bump();
238                    if state.at(FSharpTokenType::Identifier) {
239                        state.bump();
240                    }
241                    state.finish_at(checkpoint, FSharpElementType::ActivePattern);
242                }
243                else {
244                    state.finish_at(checkpoint, FSharpElementType::IdentifierPattern);
245                }
246            }
247            Some(FSharpTokenType::LeftParen) => {
248                state.bump();
249                while state.not_at_end() && !state.at(FSharpTokenType::RightParen) {
250                    self.parse_pattern(state)?;
251                    if state.at(FSharpTokenType::Comma) {
252                        state.bump();
253                    }
254                }
255                state.expect(FSharpTokenType::RightParen)?;
256                state.finish_at(checkpoint, FSharpElementType::TuplePattern);
257            }
258            Some(FSharpTokenType::LeftBracket) => {
259                state.bump();
260                while state.not_at_end() && !state.at(FSharpTokenType::RightBracket) {
261                    self.parse_pattern(state)?;
262                    if state.at(FSharpTokenType::Comma) {
263                        state.bump();
264                    }
265                }
266                state.expect(FSharpTokenType::RightBracket)?;
267                state.finish_at(checkpoint, FSharpElementType::ListPattern);
268            }
269            Some(FSharpTokenType::Pipe) => {
270                // Parse partial active pattern case
271                state.bump();
272                if state.at(FSharpTokenType::Identifier) {
273                    state.bump();
274                }
275                state.finish_at(checkpoint, FSharpElementType::ActivePattern);
276            }
277            _ => {
278                state.bump();
279                state.finish_at(checkpoint, FSharpElementType::Pattern);
280            }
281        }
282        Ok(())
283    }
284
285    fn parse_let_expression<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>, checkpoint: (usize, usize)) -> Result<(), OakError> {
286        state.expect(FSharpTokenType::Let)?;
287
288        let is_rec = state.eat(FSharpTokenType::Rec);
289
290        // Parse binding name
291        state.expect(FSharpTokenType::Identifier)?;
292
293        // Parse parameters
294        while state.not_at_end() && state.at(FSharpTokenType::Identifier) {
295            state.bump();
296        }
297
298        // Optional type annotation
299        if state.eat(FSharpTokenType::Colon) {
300            self.parse_type(state)?;
301        }
302
303        state.expect(FSharpTokenType::Equal)?;
304        self.parse_expression(state)?;
305
306        if state.eat(FSharpTokenType::In) {
307            self.parse_expression(state)?;
308        }
309
310        state.finish_at(checkpoint, FSharpElementType::Let);
311        Ok(())
312    }
313
314    fn parse_lambda_expression<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>, checkpoint: (usize, usize)) -> Result<(), OakError> {
315        state.expect(FSharpTokenType::Fun)?;
316
317        // Parse parameters
318        while state.not_at_end() && state.at(FSharpTokenType::Identifier) {
319            state.bump();
320        }
321
322        state.expect(FSharpTokenType::Arrow)?;
323        self.parse_expression(state)?;
324
325        state.finish_at(checkpoint, FSharpElementType::Lambda);
326        Ok(())
327    }
328
329    fn parse_parenthesized_expression<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>, checkpoint: (usize, usize)) -> Result<(), OakError> {
330        state.bump(); // LeftParen
331        self.parse_expression(state)?;
332        state.expect(FSharpTokenType::RightParen)?;
333        state.finish_at(checkpoint, FSharpElementType::Parenthesized);
334        Ok(())
335    }
336
337    fn parse_list_or_array_expression<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>, checkpoint: (usize, usize)) -> Result<(), OakError> {
338        state.bump(); // LeftBracket
339
340        while state.not_at_end() && !state.at(FSharpTokenType::RightBracket) {
341            self.parse_expression(state)?;
342            if state.at(FSharpTokenType::Comma) {
343                state.bump();
344            }
345        }
346
347        state.expect(FSharpTokenType::RightBracket)?;
348        state.finish_at(checkpoint, FSharpElementType::List);
349        Ok(())
350    }
351
352    fn parse_record_expression<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>, checkpoint: (usize, usize)) -> Result<(), OakError> {
353        state.bump(); // LeftBrace
354
355        while state.not_at_end() && !state.at(FSharpTokenType::RightBrace) {
356            state.expect(FSharpTokenType::Identifier)?;
357            state.expect(FSharpTokenType::Equal)?;
358            self.parse_expression(state)?;
359            if state.at(FSharpTokenType::Comma) {
360                state.bump();
361            }
362        }
363
364        state.expect(FSharpTokenType::RightBrace)?;
365        state.finish_at(checkpoint, FSharpElementType::Record);
366        Ok(())
367    }
368
369    fn parse_identifier_expression<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>, checkpoint: (usize, usize)) -> Result<(), OakError> {
370        state.bump(); // Identifier
371
372        // Check for function application
373        if state.not_at_end() && !matches!(state.peek_kind(), Some(FSharpTokenType::Newline | FSharpTokenType::Then | FSharpTokenType::Else | FSharpTokenType::In | FSharpTokenType::PipeRight | FSharpTokenType::PipeGreater)) {
374            self.parse_expression(state)?;
375            state.finish_at(checkpoint, FSharpElementType::Application);
376        }
377        else {
378            state.finish_at(checkpoint, FSharpElementType::Identifier);
379        }
380        Ok(())
381    }
382
383    fn parse_literal_expression<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>, checkpoint: (usize, usize)) -> Result<(), OakError> {
384        state.bump(); // Literal
385        state.finish_at(checkpoint, FSharpElementType::Literal);
386        Ok(())
387    }
388
389    fn parse_type<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), OakError> {
390        // Simple type parsing
391        while state.not_at_end() && !matches!(state.peek_kind(), Some(FSharpTokenType::Equal | FSharpTokenType::Newline)) {
392            state.bump();
393        }
394        Ok(())
395    }
396}
397
398impl<'config> Parser<FSharpLanguage> for FSharpParser<'config> {
399    fn parse<'a, S: Source + ?Sized>(&self, text: &'a S, edits: &[TextEdit], cache: &'a mut impl ParseCache<FSharpLanguage>) -> ParseOutput<'a, FSharpLanguage> {
400        let lexer = FSharpLexer::new(self.config);
401        parse_with_lexer(&lexer, text, edits, cache, |state| {
402            let cp = (0, 0); // Ensure the root node includes initial trivia skipped during state initialization
403            while state.not_at_end() {
404                let kind = state.peek_kind();
405                match kind {
406                    Some(FSharpTokenType::Namespace) => self.parse_namespace(state)?,
407                    Some(FSharpTokenType::Module) => self.parse_module(state)?,
408                    Some(FSharpTokenType::Open) => self.parse_open(state)?,
409                    Some(FSharpTokenType::Let) => self.parse_binding(state)?,
410                    _ => state.bump(),
411                }
412            }
413
414            Ok(state.finish_at(cp, FSharpElementType::Root))
415        })
416    }
417}