Skip to main content

oak_go/parser/
mod.rs

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