Skip to main content

oak_zig/parser/
mod.rs

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