Skip to main content

oak_c/parser/
mod.rs

1pub mod element_type;
2pub use element_type::CElementType;
3
4use crate::{language::CLanguage, lexer::CTokenType};
5use oak_core::{
6    GreenNode, OakError, Source,
7    parser::{Associativity, ParseCache, ParseOutput, Parser, ParserState, Pratt, PrattParser, binary, parse_with_lexer},
8    source::TextEdit,
9};
10
11pub(crate) type State<'a, S> = ParserState<'a, CLanguage, S>;
12
13pub struct CParser<'config> {
14    pub(crate) config: &'config CLanguage,
15}
16
17impl<'config> CParser<'config> {
18    pub fn new(config: &'config CLanguage) -> Self {
19        Self { config }
20    }
21
22    pub(crate) fn parse_statement<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), OakError> {
23        use crate::lexer::CTokenType::*;
24        self.skip_trivia(state);
25        match state.peek_kind() {
26            Some(If) => self.parse_if_statement(state)?,
27            Some(While) => self.parse_while_statement(state)?,
28            Some(For) => self.parse_for_statement(state)?,
29            Some(Return) => self.parse_return_statement(state)?,
30            Some(LeftBrace) => self.parse_compound_statement(state)?,
31            Some(Struct) | Some(Union) | Some(Enum) | Some(Typedef) | Some(Extern) | Some(Static) | Some(Int) | Some(Char) | Some(Void) | Some(Float) | Some(Double) => self.parse_declaration(state)?,
32            _ => {
33                let expr = PrattParser::parse(state, 0, self);
34                state.push_child(expr);
35                self.skip_trivia(state);
36                state.eat(Semicolon);
37            }
38        }
39        Ok(())
40    }
41
42    fn skip_trivia<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) {
43        while let Some(kind) = state.peek_kind() {
44            if matches!(kind, CTokenType::Whitespace | CTokenType::Comment) {
45                state.bump();
46            }
47            else {
48                break;
49            }
50        }
51    }
52
53    fn parse_declaration<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), OakError> {
54        use crate::lexer::CTokenType::*;
55        let cp = state.checkpoint();
56
57        self.skip_trivia(state);
58        while state.not_at_end() && !state.at(Semicolon) && !state.at(LeftBrace) && !state.at(Assign) && !state.at(LeftParen) {
59            state.bump();
60            self.skip_trivia(state);
61        }
62
63        if state.at(LeftParen) {
64            let pcp = state.checkpoint();
65            state.bump(); // (
66            self.skip_trivia(state);
67            while state.not_at_end() && !state.at(RightParen) {
68                if state.at(Identifier) || state.at(Int) || state.at(Char) || state.at(Float) || state.at(Double) || state.at(Void) {
69                    state.bump();
70                }
71                else if state.at(Comma) {
72                    state.bump();
73                }
74                else {
75                    state.bump();
76                }
77                self.skip_trivia(state);
78            }
79            state.expect(RightParen).ok();
80            state.finish_at(pcp, CElementType::ParameterList);
81        }
82
83        self.skip_trivia(state);
84
85        if state.at(Assign) {
86            state.bump(); // =
87            self.skip_trivia(state);
88            let expr = PrattParser::parse(state, 0, self);
89            state.push_child(expr);
90        }
91
92        self.skip_trivia(state);
93
94        if state.at(LeftBrace) {
95            state.bump(); // {
96            self.skip_trivia(state);
97            while state.not_at_end() && !state.at(RightBrace) {
98                self.parse_statement(state)?;
99                self.skip_trivia(state);
100            }
101            state.expect(RightBrace).ok();
102            state.finish_at(cp, CElementType::FunctionDefinition);
103        }
104        else {
105            state.eat(Semicolon);
106            state.finish_at(cp, CElementType::DeclarationStatement);
107        }
108        Ok(())
109    }
110
111    fn parse_if_statement<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), OakError> {
112        let cp = state.checkpoint();
113        state.bump(); // if
114        state.expect(CTokenType::LeftParen).ok();
115        let expr = PrattParser::parse(state, 0, self);
116        state.push_child(expr);
117        state.expect(CTokenType::RightParen).ok();
118        self.parse_statement(state)?;
119        if state.eat(CTokenType::Else) {
120            self.parse_statement(state)?;
121        }
122        state.finish_at(cp, CElementType::IfStatement);
123        Ok(())
124    }
125
126    fn parse_while_statement<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), OakError> {
127        let cp = state.checkpoint();
128        state.bump(); // while
129        state.expect(CTokenType::LeftParen).ok();
130        let expr = PrattParser::parse(state, 0, self);
131        state.push_child(expr);
132        state.expect(CTokenType::RightParen).ok();
133        self.parse_statement(state)?;
134        state.finish_at(cp, CElementType::WhileStatement);
135        Ok(())
136    }
137
138    fn parse_for_statement<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), OakError> {
139        let cp = state.checkpoint();
140        state.bump(); // for
141        state.expect(CTokenType::LeftParen).ok();
142
143        // Init
144        if !state.at(CTokenType::Semicolon) {
145            let expr = PrattParser::parse(state, 0, self);
146            state.push_child(expr);
147        }
148        state.expect(CTokenType::Semicolon).ok();
149
150        // Condition
151        if !state.at(CTokenType::Semicolon) {
152            let expr = PrattParser::parse(state, 0, self);
153            state.push_child(expr);
154        }
155        state.expect(CTokenType::Semicolon).ok();
156
157        // Increment
158        if !state.at(CTokenType::RightParen) {
159            let expr = PrattParser::parse(state, 0, self);
160            state.push_child(expr);
161        }
162        state.expect(CTokenType::RightParen).ok();
163
164        self.parse_statement(state)?;
165        state.finish_at(cp, CElementType::ForStatement);
166        Ok(())
167    }
168
169    fn parse_return_statement<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), OakError> {
170        let cp = state.checkpoint();
171        state.bump(); // return
172        if !state.at(CTokenType::Semicolon) {
173            let expr = PrattParser::parse(state, 0, self);
174            state.push_child(expr);
175        }
176        state.eat(CTokenType::Semicolon);
177        state.finish_at(cp, CElementType::ReturnStatement);
178        Ok(())
179    }
180
181    fn parse_compound_statement<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), OakError> {
182        let cp = state.checkpoint();
183        state.expect(CTokenType::LeftBrace).ok();
184        while state.not_at_end() && !state.at(CTokenType::RightBrace) {
185            self.parse_statement(state)?;
186        }
187        state.expect(CTokenType::RightBrace).ok();
188        state.finish_at(cp, CElementType::CompoundStatement);
189        Ok(())
190    }
191}
192
193impl<'config> Pratt<CLanguage> for CParser<'config> {
194    fn primary<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> &'a GreenNode<'a, CLanguage> {
195        use crate::lexer::CTokenType::*;
196        self.skip_trivia(state);
197        let cp = state.checkpoint();
198        match state.peek_kind() {
199            Some(Identifier) => {
200                state.bump();
201                state.finish_at(cp, CElementType::Token(Identifier))
202            }
203            Some(IntegerLiteral) | Some(FloatLiteral) | Some(CharLiteral) | Some(StringLiteral) => {
204                let _kind = state.peek_kind().unwrap();
205                state.bump();
206                state.finish_at(cp, CElementType::ExpressionStatement) // įŽ€åŒ–å¤„į†
207            }
208            Some(LeftParen) => {
209                state.bump();
210                let expr = PrattParser::parse(state, 0, self);
211                state.push_child(expr);
212                self.skip_trivia(state);
213                state.expect(RightParen).ok();
214                state.finish_at(cp, CElementType::ExpressionStatement)
215            }
216            _ => {
217                state.bump();
218                state.finish_at(cp, CElementType::Error)
219            }
220        }
221    }
222
223    fn infix<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>, left: &'a GreenNode<'a, CLanguage>, min_precedence: u8) -> Option<&'a GreenNode<'a, CLanguage>> {
224        use crate::lexer::CTokenType::*;
225        self.skip_trivia(state);
226        let kind = state.peek_kind()?;
227
228        let (prec, assoc) = match kind {
229            Assign | PlusAssign | MinusAssign | StarAssign | SlashAssign | PercentAssign | AndAssign | OrAssign | XorAssign | LeftShiftAssign | RightShiftAssign => (1, Associativity::Right),
230            LogicalOr => (2, Associativity::Left),
231            LogicalAnd => (3, Associativity::Left),
232            Equal | NotEqual | Less | Greater | LessEqual | GreaterEqual => (4, Associativity::Left),
233            Plus | Minus => (10, Associativity::Left),
234            Star | Slash | Percent => (11, Associativity::Left),
235            LeftParen | LeftBracket | Dot | Arrow => (15, Associativity::Left),
236            _ => return None,
237        };
238
239        if prec < min_precedence {
240            return None;
241        }
242
243        match kind {
244            LeftParen => {
245                let cp = state.checkpoint();
246                state.push_child(left);
247                state.expect(LeftParen).ok();
248                while state.not_at_end() && !state.at(RightParen) {
249                    let expr = PrattParser::parse(state, 0, self);
250                    state.push_child(expr);
251                    self.skip_trivia(state);
252                    if !state.eat(Comma) {
253                        break;
254                    }
255                }
256                state.expect(RightParen).ok();
257                Some(state.finish_at(cp, CElementType::ExpressionStatement))
258            }
259            LeftBracket => {
260                let cp = state.checkpoint();
261                state.push_child(left);
262                state.expect(LeftBracket).ok();
263                let expr = PrattParser::parse(state, 0, self);
264                state.push_child(expr);
265                state.expect(RightBracket).ok();
266                Some(state.finish_at(cp, CElementType::ExpressionStatement))
267            }
268            Dot | Arrow => {
269                let cp = state.checkpoint();
270                state.push_child(left);
271                state.expect(kind).ok();
272                state.expect(Identifier).ok();
273                Some(state.finish_at(cp, CElementType::ExpressionStatement))
274            }
275            _ => Some(binary(state, left, kind, prec, assoc, CElementType::ExpressionStatement, |s, p| PrattParser::parse(s, p, self))),
276        }
277    }
278}
279
280impl<'config> Parser<CLanguage> for CParser<'config> {
281    fn parse<'a, S: Source + ?Sized>(&self, text: &'a S, edits: &[TextEdit], cache: &'a mut impl ParseCache<CLanguage>) -> ParseOutput<'a, CLanguage> {
282        let lexer = crate::lexer::CLexer::new(self.config);
283        parse_with_lexer(&lexer, text, edits, cache, |state| {
284            let cp = state.checkpoint();
285            while state.not_at_end() {
286                self.parse_statement(state).ok();
287            }
288            Ok(state.finish_at(cp, CElementType::Root))
289        })
290    }
291}