Skip to main content

oak_zig/parser/
mod.rs

1use crate::{kind::ZigSyntaxKind, language::ZigLanguage, lexer::ZigLexer};
2use oak_core::{
3    GreenNode, OakError,
4    parser::{
5        ParseCache, ParseOutput, Parser, ParserState, parse_with_lexer,
6        pratt::{Associativity, Pratt, PrattParser, binary, unary},
7    },
8    source::{Source, TextEdit},
9};
10
11pub(crate) type State<'a, S> = ParserState<'a, ZigLanguage, S>;
12
13pub struct ZigParser<'config> {
14    pub(crate) config: &'config ZigLanguage,
15}
16
17impl<'config> ZigParser<'config> {
18    pub fn new(config: &'config ZigLanguage) -> Self {
19        Self { config }
20    }
21}
22
23impl<'config> Pratt<ZigLanguage> for ZigParser<'config> {
24    fn primary<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> &'a GreenNode<'a, ZigLanguage> {
25        use crate::kind::ZigSyntaxKind::*;
26        let cp = state.checkpoint();
27        match state.peek_kind() {
28            Some(Identifier) => {
29                state.bump();
30                state.finish_at(cp, Identifier.into())
31            }
32            Some(IntegerLiteral) | Some(FloatLiteral) | Some(StringLiteral) | Some(CharLiteral) | Some(BooleanLiteral) | Some(Null) | Some(Undefined) => {
33                state.bump();
34                state.finish_at(cp, Root.into()) // Simplified
35            }
36            Some(LeftParen) => {
37                state.bump();
38                PrattParser::parse(state, 0, self);
39                state.expect(RightParen).ok();
40                state.finish_at(cp, Root.into())
41            }
42            _ => {
43                state.bump();
44                state.finish_at(cp, Error.into())
45            }
46        }
47    }
48
49    fn prefix<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> &'a GreenNode<'a, ZigLanguage> {
50        use crate::kind::ZigSyntaxKind::*;
51        let kind = match state.peek_kind() {
52            Some(k) => k,
53            None => return self.primary(state),
54        };
55
56        match kind {
57            Minus | Tilde | Exclamation | Ampersand | TryKeyword | AwaitKeyword => unary(state, kind, 12, Root.into(), |s, p| PrattParser::parse(s, p, self)),
58            _ => self.primary(state),
59        }
60    }
61
62    fn infix<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>, left: &'a GreenNode<'a, ZigLanguage>, min_precedence: u8) -> Option<&'a GreenNode<'a, ZigLanguage>> {
63        use crate::kind::ZigSyntaxKind::*;
64        let kind = state.peek_kind()?;
65
66        let (prec, assoc) = match kind {
67            Assign | PlusAssign | MinusAssign | StarAssign | SlashAssign | PercentAssign | AmpersandAssign | PipeAssign | CaretAssign | LessLessAssign | GreaterGreaterAssign => (1, Associativity::Right),
68            Or | OrOr => (2, Associativity::Left),
69            And | AndAnd => (3, Associativity::Left),
70            Equal | NotEqual | Less | Greater | LessEqual | GreaterEqual => (4, Associativity::Left),
71            Plus | Minus | PlusPercent | MinusPercent | PlusPlus => (5, Associativity::Left),
72            Star | Slash | Percent | StarPercent | StarStar => (6, Associativity::Left),
73            CatchKeyword | OrElse => (7, Associativity::Right),
74            Dot | LeftParen | LeftBracket => (10, Associativity::Left),
75            _ => return None,
76        };
77
78        if prec < min_precedence {
79            return None;
80        }
81
82        match kind {
83            Dot => {
84                let cp = state.checkpoint();
85                state.push_child(left);
86                state.bump();
87                state.expect(Identifier).ok();
88                Some(state.finish_at(cp, Root.into()))
89            }
90            LeftParen => {
91                let cp = state.checkpoint();
92                state.push_child(left);
93                state.bump();
94                while state.not_at_end() && !state.at(RightParen) {
95                    PrattParser::parse(state, 0, self);
96                    if !state.eat(Comma) {
97                        break;
98                    }
99                }
100                state.expect(RightParen).ok();
101                Some(state.finish_at(cp, Root.into()))
102            }
103            LeftBracket => {
104                let cp = state.checkpoint();
105                state.push_child(left);
106                state.bump();
107                PrattParser::parse(state, 0, self);
108                state.expect(RightBracket).ok();
109                Some(state.finish_at(cp, Root.into()))
110            }
111            _ => Some(binary(state, left, kind, prec, assoc, Root.into(), |s, p| PrattParser::parse(s, p, self))),
112        }
113    }
114}
115
116impl<'config> Parser<ZigLanguage> for ZigParser<'config> {
117    fn parse<'a, S: Source + ?Sized>(&self, source: &'a S, edits: &[TextEdit], cache: &'a mut impl ParseCache<ZigLanguage>) -> ParseOutput<'a, ZigLanguage> {
118        let lexer = ZigLexer::new(&self.config);
119        parse_with_lexer(&lexer, source, edits, cache, |state| self.parse_root_internal(state))
120    }
121}
122
123impl<'p> ZigParser<'p> {
124    pub(crate) fn parse_root_internal<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<&'a GreenNode<'a, ZigLanguage>, OakError> {
125        let checkpoint = state.checkpoint();
126
127        while state.not_at_end() {
128            self.parse_statement(state)?;
129        }
130
131        Ok(state.finish_at(checkpoint, ZigSyntaxKind::Root.into()))
132    }
133
134    fn parse_statement<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), OakError> {
135        use crate::kind::ZigSyntaxKind::*;
136        match state.peek_kind() {
137            Some(Fn) => self.parse_function_declaration(state)?,
138            Some(Const) | Some(Var) => self.parse_variable_declaration(state)?,
139            Some(If) => self.parse_if_statement(state)?,
140            Some(While) => self.parse_while_statement(state)?,
141            Some(For) => self.parse_for_statement(state)?,
142            Some(Return) => self.parse_return_statement(state)?,
143            Some(LeftBrace) => self.parse_block(state)?,
144            _ => {
145                PrattParser::parse(state, 0, self);
146                state.eat(Semicolon);
147            }
148        }
149        Ok(())
150    }
151
152    fn parse_function_declaration<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), OakError> {
153        use crate::kind::ZigSyntaxKind::*;
154        let cp = state.checkpoint();
155        state.expect(Fn).ok();
156        state.expect(Identifier).ok();
157        state.expect(LeftParen).ok();
158        while state.not_at_end() && !state.at(RightParen) {
159            state.advance();
160        }
161        state.expect(RightParen).ok();
162        while state.not_at_end() && !state.at(LeftBrace) {
163            state.bump();
164        }
165        self.parse_block(state)?;
166        state.finish_at(cp, ZigSyntaxKind::FnDeclaration.into());
167        Ok(())
168    }
169
170    fn parse_variable_declaration<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), OakError> {
171        use crate::kind::ZigSyntaxKind::*;
172        let cp = state.checkpoint();
173        state.bump(); // const or var
174        state.expect(Identifier).ok();
175        if state.eat(Colon) {
176            while state.not_at_end() && !state.at(Assign) && !state.at(Semicolon) {
177                state.bump();
178            }
179        }
180        if state.eat(Assign) {
181            PrattParser::parse(state, 0, self);
182        }
183        state.eat(Semicolon);
184        state.finish_at(cp, ZigSyntaxKind::VarDeclaration.into());
185        Ok(())
186    }
187
188    fn parse_if_statement<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), OakError> {
189        use crate::kind::ZigSyntaxKind::*;
190        let cp = state.checkpoint();
191        state.expect(If).ok();
192        state.expect(LeftParen).ok();
193        PrattParser::parse(state, 0, self);
194        state.expect(RightParen).ok();
195        self.parse_statement(state)?;
196        if state.eat(Else) {
197            self.parse_statement(state)?;
198        }
199        state.finish_at(cp, ZigSyntaxKind::IfStatement.into());
200        Ok(())
201    }
202
203    fn parse_while_statement<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), OakError> {
204        use crate::kind::ZigSyntaxKind::*;
205        let cp = state.checkpoint();
206        state.expect(While).ok();
207        state.expect(LeftParen).ok();
208        PrattParser::parse(state, 0, self);
209        state.expect(RightParen).ok();
210        self.parse_statement(state)?;
211        state.finish_at(cp, ZigSyntaxKind::WhileStatement.into());
212        Ok(())
213    }
214
215    fn parse_for_statement<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), OakError> {
216        use crate::kind::ZigSyntaxKind::*;
217        let cp = state.checkpoint();
218        state.expect(For).ok();
219        state.expect(LeftParen).ok();
220        PrattParser::parse(state, 0, self);
221        state.expect(RightParen).ok();
222        self.parse_statement(state)?;
223        state.finish_at(cp, ZigSyntaxKind::ForStatement.into());
224        Ok(())
225    }
226
227    fn parse_return_statement<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), OakError> {
228        use crate::kind::ZigSyntaxKind::*;
229        let cp = state.checkpoint();
230        state.expect(Return).ok();
231        if !state.at(Semicolon) {
232            PrattParser::parse(state, 0, self);
233        }
234        state.eat(Semicolon);
235        state.finish_at(cp, ZigSyntaxKind::ReturnStatement.into());
236        Ok(())
237    }
238
239    fn parse_block<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), OakError> {
240        use crate::kind::ZigSyntaxKind::*;
241        let cp = state.checkpoint();
242        state.expect(LeftBrace).ok();
243        while state.not_at_end() && !state.at(RightBrace) {
244            self.parse_statement(state)?;
245        }
246        state.expect(RightBrace).ok();
247        state.finish_at(cp, ZigSyntaxKind::Block.into());
248        Ok(())
249    }
250}