Skip to main content

oak_go/parser/
mod.rs

1pub mod element_type;
2
3use crate::{language::GoLanguage, lexer::GoLexer};
4use oak_core::{
5    OakError,
6    parser::{Associativity, ParseCache, ParseOutput, Parser, ParserState, Pratt, PrattParser, binary, parse_with_lexer, unary},
7    source::{Source, TextEdit},
8    tree::GreenNode,
9};
10
11pub(crate) type State<'a, S> = ParserState<'a, GoLanguage, S>;
12
13/// Go language parser
14pub struct GoParser<'config> {
15    pub(crate) config: &'config GoLanguage,
16}
17
18impl<'config> GoParser<'config> {
19    pub fn new(config: &'config GoLanguage) -> Self {
20        Self { config }
21    }
22
23    fn skip_trivia<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) {
24        while state.not_at_end() {
25            if let Some(kind) = state.peek_kind() {
26                if kind.is_ignored() {
27                    state.bump();
28                    continue;
29                };
30            }
31            break;
32        }
33    }
34
35    pub(crate) fn parse_statement<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), OakError> {
36        use crate::{GoElementType as E, GoTokenType as T};
37        self.skip_trivia(state);
38        match state.peek_kind() {
39            Some(T::Package) => self.parse_package_clause(state)?,
40            Some(T::Import) => self.parse_import_declaration(state)?,
41            Some(T::Func) => self.parse_function_declaration(state)?,
42            Some(T::Var) => self.parse_variable_declaration(state)?,
43            Some(T::Const) => self.parse_const_declaration(state)?,
44            Some(T::Type) => self.parse_type_declaration(state)?,
45            Some(T::If) => self.parse_if_statement(state)?,
46            Some(T::For) => self.parse_for_statement(state)?,
47            Some(T::Switch) => self.parse_switch_statement(state)?,
48            Some(T::Return) => self.parse_return_statement(state)?,
49            Some(T::LeftBrace) => self.parse_block(state)?,
50            _ => {
51                let cp = state.checkpoint();
52                PrattParser::parse(state, 0, self);
53
54                self.skip_trivia(state);
55                match state.peek_kind() {
56                    Some(T::Assign) => {
57                        state.bump();
58                        self.skip_trivia(state);
59                        PrattParser::parse(state, 0, self);
60                        state.finish_at(cp, E::AssignmentStatement);
61                    }
62                    Some(T::ColonAssign) => {
63                        state.bump();
64                        self.skip_trivia(state);
65                        PrattParser::parse(state, 0, self);
66                        state.finish_at(cp, E::ShortVarDecl);
67                    }
68                    _ => {
69                        // Pure expression statement
70                    }
71                }
72                self.skip_trivia(state);
73                state.eat(T::Semicolon);
74            }
75        }
76        self.skip_trivia(state);
77        Ok(())
78    }
79
80    fn parse_package_clause<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), OakError> {
81        use crate::{GoElementType as E, GoTokenType as T};
82        let cp = state.checkpoint();
83        state.expect(T::Package).ok();
84        self.skip_trivia(state);
85        state.expect(T::Identifier).ok();
86        state.finish_at(cp, E::PackageClause);
87        Ok(())
88    }
89
90    fn parse_import_declaration<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), OakError> {
91        use crate::{GoElementType as E, GoTokenType as T};
92        let cp = state.checkpoint();
93        state.expect(T::Import).ok();
94        if state.eat(T::LeftParen) {
95            while state.not_at_end() && !state.at(T::RightParen) {
96                state.advance();
97            }
98            state.expect(T::RightParen).ok();
99        }
100        else {
101            state.advance();
102        }
103        state.finish_at(cp, E::ImportDeclaration);
104        Ok(())
105    }
106
107    fn parse_function_declaration<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), OakError> {
108        use crate::{GoElementType as E, GoTokenType as T};
109        let cp = state.checkpoint();
110        state.expect(T::Func).ok();
111        self.skip_trivia(state);
112
113        // Parse receiver if present
114        if state.at(T::LeftParen) {
115            let rcp = state.checkpoint();
116            self.parse_parameter_list(state)?;
117            state.finish_at(rcp, E::Receiver);
118            self.skip_trivia(state);
119        }
120
121        // Parse function name
122        if state.at(T::Identifier) {
123            state.bump();
124            self.skip_trivia(state);
125        }
126
127        // Parse parameters
128        self.parse_parameter_list(state)?;
129        self.skip_trivia(state);
130
131        // Parse return types
132        if state.at(T::LeftParen) {
133            self.parse_parameter_list(state)?;
134            self.skip_trivia(state);
135        }
136        else if state.at(T::Identifier) || state.at(T::Star) {
137            // Single return type
138            let rtcp = state.checkpoint();
139            if state.eat(T::Star) {
140                self.skip_trivia(state);
141            }
142            state.expect(T::Identifier).ok();
143            state.finish_at(rtcp, E::Identifier); // Simplified
144            self.skip_trivia(state);
145        }
146
147        if state.at(T::LeftBrace) {
148            self.parse_block(state)?;
149        }
150        state.finish_at(cp, E::FunctionDeclaration);
151        Ok(())
152    }
153
154    fn parse_parameter_list<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), OakError> {
155        use crate::{GoElementType as E, GoTokenType as T};
156        let cp = state.checkpoint();
157        state.expect(T::LeftParen).ok();
158        self.skip_trivia(state);
159        while state.not_at_end() && !state.at(T::RightParen) {
160            let pcp = state.checkpoint();
161            // Parse identifier(s)
162            while state.at(T::Identifier) {
163                state.bump();
164                self.skip_trivia(state);
165                if !state.eat(T::Comma) {
166                    break;
167                }
168                self.skip_trivia(state);
169            }
170            // Parse type
171            if state.not_at_end() && !state.at(T::Comma) && !state.at(T::RightParen) {
172                if state.eat(T::Star) {
173                    self.skip_trivia(state);
174                }
175                if state.at(T::Identifier) {
176                    state.bump();
177                    self.skip_trivia(state);
178                }
179            }
180            state.finish_at(pcp, E::ParameterDecl);
181            self.skip_trivia(state);
182            if !state.eat(T::Comma) {
183                break;
184            }
185            self.skip_trivia(state);
186        }
187        state.expect(T::RightParen).ok();
188        state.finish_at(cp, E::ParameterList);
189        Ok(())
190    }
191
192    fn parse_variable_declaration<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), OakError> {
193        use crate::{GoElementType as E, GoTokenType as T};
194        let cp = state.checkpoint();
195        state.expect(T::Var).ok();
196        self.skip_trivia(state);
197
198        while state.at(T::Identifier) {
199            let vcp = state.checkpoint();
200            state.bump(); // name
201            self.skip_trivia(state);
202
203            // Optional type
204            if state.at(T::Identifier) {
205                state.bump();
206                self.skip_trivia(state);
207            }
208
209            // Optional assignment
210            if state.eat(T::Assign) {
211                self.skip_trivia(state);
212                PrattParser::parse(state, 0, self);
213            }
214
215            state.finish_at(vcp, E::VariableSpec);
216            self.skip_trivia(state);
217
218            if !state.eat(T::Comma) {
219                break;
220            }
221            self.skip_trivia(state);
222        }
223
224        state.eat(T::Semicolon);
225        state.finish_at(cp, E::VariableDeclaration);
226        Ok(())
227    }
228
229    fn parse_const_declaration<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), OakError> {
230        use crate::{GoElementType as E, GoTokenType as T};
231        let cp = state.checkpoint();
232        state.expect(T::Const).ok();
233        while state.at(T::Identifier) {
234            state.bump();
235            if !state.eat(T::Semicolon) {
236                break;
237            }
238        }
239        state.eat(T::Semicolon);
240        state.finish_at(cp, E::ConstDeclaration);
241        Ok(())
242    }
243
244    fn parse_type_declaration<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), OakError> {
245        use crate::{GoElementType as E, GoTokenType as T};
246        let cp = state.checkpoint();
247        state.expect(T::Type).ok();
248        while state.at(T::Identifier) {
249            state.bump();
250            if !state.eat(T::Semicolon) {
251                break;
252            }
253        }
254        state.eat(T::Semicolon);
255        state.finish_at(cp, E::TypeDeclaration);
256        Ok(())
257    }
258
259    fn parse_if_statement<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), OakError> {
260        use crate::{GoElementType as E, GoTokenType as T};
261        let cp = state.checkpoint();
262        state.expect(T::If).ok();
263        self.skip_trivia(state);
264
265        // Parse condition
266        if !state.at(T::LeftBrace) {
267            PrattParser::parse(state, 0, self);
268            self.skip_trivia(state);
269        }
270
271        self.parse_block(state)?;
272        self.skip_trivia(state);
273
274        if state.eat(T::Else) {
275            self.skip_trivia(state);
276            if state.at(T::If) {
277                self.parse_if_statement(state)?;
278            }
279            else {
280                self.parse_block(state)?;
281            }
282            self.skip_trivia(state);
283        }
284        state.finish_at(cp, E::IfStatement);
285        Ok(())
286    }
287
288    fn parse_for_statement<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), OakError> {
289        use crate::{GoElementType as E, GoTokenType as T};
290        let cp = state.checkpoint();
291        state.expect(T::For).ok();
292        self.skip_trivia(state);
293
294        // Try to parse init; condition; post
295        if !state.at(T::LeftBrace) {
296            // Parse at least one expression/statement
297            PrattParser::parse(state, 0, self);
298            self.skip_trivia(state);
299
300            if state.eat(T::Semicolon) {
301                self.skip_trivia(state);
302                // condition
303                if !state.at(T::Semicolon) {
304                    PrattParser::parse(state, 0, self);
305                    self.skip_trivia(state);
306                }
307                state.expect(T::Semicolon).ok();
308                self.skip_trivia(state);
309                // post
310                if !state.at(T::LeftBrace) {
311                    PrattParser::parse(state, 0, self);
312                    self.skip_trivia(state);
313                }
314            }
315        }
316
317        self.parse_block(state)?;
318        self.skip_trivia(state);
319        state.finish_at(cp, E::ForStatement);
320        Ok(())
321    }
322
323    fn parse_switch_statement<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), OakError> {
324        use crate::{GoElementType as E, GoTokenType as T};
325        let cp = state.checkpoint();
326        state.expect(T::Switch).ok();
327        while state.not_at_end() && !state.at(T::LeftBrace) {
328            state.advance();
329        }
330        self.parse_block(state)?;
331        state.finish_at(cp, E::SwitchStatement);
332        Ok(())
333    }
334
335    fn parse_return_statement<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), OakError> {
336        use crate::{GoElementType as E, GoTokenType as T};
337        let cp = state.checkpoint();
338        state.expect(T::Return).ok();
339        if !state.at(T::Semicolon) {
340            PrattParser::parse(state, 0, self);
341        }
342        state.eat(T::Semicolon);
343        state.finish_at(cp, E::ReturnStatement);
344        Ok(())
345    }
346
347    fn parse_block<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), OakError> {
348        use crate::{GoElementType as E, GoTokenType as T};
349        let cp = state.checkpoint();
350        state.expect(T::LeftBrace).ok();
351        self.skip_trivia(state);
352        while state.not_at_end() && !state.at(T::RightBrace) {
353            self.parse_statement(state)?;
354            self.skip_trivia(state);
355        }
356        state.expect(T::RightBrace).ok();
357        state.finish_at(cp, E::Block);
358        Ok(())
359    }
360}
361
362impl<'config> Pratt<GoLanguage> for GoParser<'config> {
363    fn primary<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> &'a GreenNode<'a, GoLanguage> {
364        use crate::{GoElementType as E, GoTokenType as T};
365        self.skip_trivia(state);
366        let cp = state.checkpoint();
367        let kind = match state.peek_kind() {
368            Some(k) => k,
369            None => {
370                state.bump();
371                return state.finish_at(cp, E::Error);
372            }
373        };
374
375        match kind {
376            T::Identifier => {
377                state.bump();
378                state.finish_at(cp, E::Identifier)
379            }
380            T::IntLiteral | T::FloatLiteral | T::StringLiteral | T::RuneLiteral | T::BoolLiteral | T::NilLiteral => {
381                state.bump();
382                state.finish_at(cp, kind.into())
383            }
384            T::LeftParen => {
385                state.bump();
386                self.skip_trivia(state);
387                PrattParser::parse(state, 0, self);
388                self.skip_trivia(state);
389                state.expect(T::RightParen).ok();
390                state.finish_at(cp, E::BinaryExpression) // Or ParenExpression
391            }
392            _ => {
393                state.bump();
394                state.finish_at(cp, E::Error)
395            }
396        }
397    }
398
399    fn prefix<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> &'a GreenNode<'a, GoLanguage> {
400        use crate::{GoElementType as E, GoTokenType as T};
401        let kind = match state.peek_kind() {
402            Some(k) => k,
403            None => return self.primary(state),
404        };
405
406        let prec = match kind {
407            T::Plus | T::Minus | T::LogicalNot | T::Caret | T::Star | T::Ampersand | T::Arrow => 7,
408            _ => return self.primary(state),
409        };
410
411        unary(state, kind, prec, E::BinaryExpression.into(), |st, p| PrattParser::parse(st, p, self))
412    }
413
414    fn infix<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>, left: &'a GreenNode<'a, GoLanguage>, min_precedence: u8) -> Option<&'a GreenNode<'a, GoLanguage>> {
415        use crate::{GoElementType as E, GoTokenType as T};
416        self.skip_trivia(state);
417        let kind = state.peek_kind()?;
418
419        if kind == T::LeftParen {
420            let prec = 8;
421            if prec < min_precedence {
422                return None;
423            }
424            let cp = state.checkpoint_before(left);
425            state.bump(); // (
426            self.skip_trivia(state);
427
428            let arg_cp = state.checkpoint();
429            let mut has_args = false;
430            while state.not_at_end() && !state.at(T::RightParen) {
431                PrattParser::parse(state, 0, self);
432                has_args = true;
433                self.skip_trivia(state);
434                if !state.eat(T::Comma) {
435                    break;
436                }
437                self.skip_trivia(state);
438            }
439            if has_args {
440                state.finish_at(arg_cp, E::ExpressionList);
441            }
442
443            state.expect(T::RightParen).ok();
444            return Some(state.finish_at(cp, E::CallExpression));
445        }
446
447        let (prec, assoc) = match kind {
448            T::Assign | T::ColonAssign => (1, Associativity::Right),
449            T::LogicalOr => (2, Associativity::Left),
450            T::LogicalAnd => (3, Associativity::Left),
451            T::Equal | T::NotEqual | T::Less | T::LessEqual | T::Greater | T::GreaterEqual => (4, Associativity::Left),
452            T::Plus | T::Minus | T::Pipe | T::Caret => (5, Associativity::Left),
453            T::Star | T::Slash | T::Percent | T::LeftShift | T::RightShift | T::Ampersand | T::AmpersandCaret => (6, Associativity::Left),
454            T::Dot => (8, Associativity::Left),
455            _ => return None,
456        };
457
458        if prec < min_precedence {
459            return None;
460        }
461
462        Some(binary(state, left, kind, prec, assoc, E::BinaryExpression.into(), |st, p| PrattParser::parse(st, p, self)))
463    }
464}
465
466impl<'config> Parser<GoLanguage> for GoParser<'config> {
467    fn parse<'a, S: Source + ?Sized>(&self, text: &'a S, edits: &[TextEdit], cache: &'a mut impl ParseCache<GoLanguage>) -> ParseOutput<'a, GoLanguage> {
468        let lexer = GoLexer::new(self.config);
469        parse_with_lexer(&lexer, text, edits, cache, |state| {
470            let cp = state.checkpoint();
471            while state.not_at_end() {
472                self.parse_statement(state)?
473            }
474            Ok(state.finish_at(cp, crate::parser::element_type::GoElementType::SourceFile))
475        })
476    }
477}