oak_javascript/parser/
mod.rs

1use crate::{kind::JavaScriptSyntaxKind, language::JavaScriptLanguage};
2use oak_core::{
3    GreenNode, OakError, ParseCache, TextEdit,
4    parser::{Associativity, Parser, ParserState, Pratt, PrattParser, binary},
5    source::Source,
6};
7
8pub(crate) type State<'a, S> = ParserState<'a, JavaScriptLanguage, S>;
9
10pub struct JavaScriptParser {
11    pub(crate) config: JavaScriptLanguage,
12}
13
14impl JavaScriptParser {
15    pub fn new(config: JavaScriptLanguage) -> Self {
16        Self { config }
17    }
18
19    fn parse_statement<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), OakError> {
20        use crate::kind::JavaScriptSyntaxKind::*;
21        match state.peek_kind() {
22            Some(Function) => self.parse_function_declaration(state)?,
23            Some(Var) | Some(Let) | Some(Const) => self.parse_variable_declaration(state)?,
24            Some(If) => self.parse_if_statement(state)?,
25            Some(While) => self.parse_while_statement(state)?,
26            Some(For) => self.parse_for_statement(state)?,
27            Some(Return) => self.parse_return_statement(state)?,
28            Some(LeftBrace) => self.parse_block_statement(state)?,
29            _ => {
30                PrattParser::parse(state, 0, self);
31                state.eat(Semicolon);
32            }
33        }
34        Ok(())
35    }
36
37    fn parse_function_declaration<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), OakError> {
38        use crate::kind::JavaScriptSyntaxKind::*;
39        let cp = state.checkpoint();
40        state.expect(Function).ok();
41        state.eat(IdentifierName);
42        state.expect(LeftParen).ok();
43        while state.not_at_end() && !state.at(RightParen) {
44            state.advance();
45        }
46        state.expect(RightParen).ok();
47        self.parse_block_statement(state)?;
48        state.finish_at(cp, FunctionDeclaration.into());
49        Ok(())
50    }
51
52    fn parse_variable_declaration<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), OakError> {
53        use crate::kind::JavaScriptSyntaxKind::*;
54        let cp = state.checkpoint();
55        state.bump(); // var/let/const
56        state.expect(IdentifierName).ok();
57        if state.eat(Equal) {
58            PrattParser::parse(state, 0, self);
59        }
60        state.eat(Semicolon);
61        state.finish_at(cp, VariableDeclaration.into());
62        Ok(())
63    }
64
65    fn parse_if_statement<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), OakError> {
66        use crate::kind::JavaScriptSyntaxKind::*;
67        let cp = state.checkpoint();
68        state.expect(If).ok();
69        state.expect(LeftParen).ok();
70        PrattParser::parse(state, 0, self);
71        state.expect(RightParen).ok();
72        self.parse_statement(state)?;
73        if state.eat(Else) {
74            self.parse_statement(state)?;
75        }
76        state.finish_at(cp, IfStatement.into());
77        Ok(())
78    }
79
80    fn parse_while_statement<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), OakError> {
81        use crate::kind::JavaScriptSyntaxKind::*;
82        let cp = state.checkpoint();
83        state.expect(While).ok();
84        state.expect(LeftParen).ok();
85        PrattParser::parse(state, 0, self);
86        state.expect(RightParen).ok();
87        self.parse_statement(state)?;
88        state.finish_at(cp, WhileStatement.into());
89        Ok(())
90    }
91
92    fn parse_for_statement<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), OakError> {
93        use crate::kind::JavaScriptSyntaxKind::*;
94        let cp = state.checkpoint();
95        state.expect(For).ok();
96        state.expect(LeftParen).ok();
97        // įŽ€åŒ–å¤„į†
98        while state.not_at_end() && !state.at(RightParen) {
99            state.advance();
100        }
101        state.expect(RightParen).ok();
102        self.parse_statement(state)?;
103        state.finish_at(cp, ForStatement.into());
104        Ok(())
105    }
106
107    fn parse_return_statement<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), OakError> {
108        use crate::kind::JavaScriptSyntaxKind::*;
109        let cp = state.checkpoint();
110        state.expect(Return).ok();
111        if !state.at(Semicolon) {
112            PrattParser::parse(state, 0, self);
113        }
114        state.eat(Semicolon);
115        state.finish_at(cp, ReturnStatement.into());
116        Ok(())
117    }
118
119    fn parse_block_statement<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), OakError> {
120        use crate::kind::JavaScriptSyntaxKind::*;
121        let cp = state.checkpoint();
122        state.expect(LeftBrace).ok();
123        while state.not_at_end() && !state.at(RightBrace) {
124            self.parse_statement(state)?;
125        }
126        state.expect(RightBrace).ok();
127        state.finish_at(cp, BlockStatement.into());
128        Ok(())
129    }
130}
131
132impl Pratt<JavaScriptLanguage> for JavaScriptParser {
133    fn primary<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> &'a GreenNode<'a, JavaScriptLanguage> {
134        use crate::kind::JavaScriptSyntaxKind::*;
135        let cp = state.checkpoint();
136        match state.peek_kind() {
137            Some(IdentifierName) => {
138                state.bump();
139                state.finish_at(cp, Identifier.into())
140            }
141            Some(NumericLiteral) | Some(StringLiteral) | Some(True) | Some(False) | Some(Null) => {
142                state.bump();
143                state.finish_at(cp, Literal.into())
144            }
145            Some(LeftParen) => {
146                state.bump();
147                PrattParser::parse(state, 0, self);
148                state.expect(RightParen).ok();
149                state.finish_at(cp, Expression.into())
150            }
151            _ => {
152                state.bump();
153                state.finish_at(cp, Error.into())
154            }
155        }
156    }
157
158    fn infix<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>, left: &'a GreenNode<'a, JavaScriptLanguage>, min_precedence: u8) -> Option<&'a GreenNode<'a, JavaScriptLanguage>> {
159        use crate::kind::JavaScriptSyntaxKind::*;
160        let kind = state.peek_kind()?;
161
162        let (prec, assoc) = match kind {
163            Equal
164            | PlusEqual
165            | MinusEqual
166            | StarEqual
167            | SlashEqual
168            | PercentEqual
169            | StarStarEqual
170            | LeftShiftEqual
171            | RightShiftEqual
172            | UnsignedRightShiftEqual
173            | AmpersandEqual
174            | PipeEqual
175            | CaretEqual
176            | AmpersandAmpersandEqual
177            | PipePipeEqual
178            | QuestionQuestionEqual => (1, Associativity::Right),
179            PipePipe => (2, Associativity::Left),
180            AmpersandAmpersand => (3, Associativity::Left),
181            EqualEqual | NotEqual | EqualEqualEqual | NotEqualEqual => (4, Associativity::Left),
182            Plus | Minus => (10, Associativity::Left),
183            Star | Slash | Percent => (11, Associativity::Left),
184            LeftParen | Dot => (15, Associativity::Left),
185            _ => return None,
186        };
187
188        if prec < min_precedence {
189            return None;
190        }
191
192        match kind {
193            LeftParen => {
194                let cp = state.checkpoint();
195                state.push_child(left);
196                state.expect(LeftParen).ok();
197                while state.not_at_end() && !state.at(RightParen) {
198                    state.advance();
199                }
200                state.expect(RightParen).ok();
201                Some(state.finish_at(cp, CallExpression.into()))
202            }
203            Dot => {
204                let cp = state.checkpoint();
205                state.push_child(left);
206                state.expect(Dot).ok();
207                state.expect(IdentifierName).ok();
208                Some(state.finish_at(cp, MemberExpression.into()))
209            }
210            _ => {
211                let result_kind = match kind {
212                    Equal
213                    | PlusEqual
214                    | MinusEqual
215                    | StarEqual
216                    | SlashEqual
217                    | PercentEqual
218                    | StarStarEqual
219                    | LeftShiftEqual
220                    | RightShiftEqual
221                    | UnsignedRightShiftEqual
222                    | AmpersandEqual
223                    | PipeEqual
224                    | CaretEqual
225                    | AmpersandAmpersandEqual
226                    | PipePipeEqual
227                    | QuestionQuestionEqual => AssignmentExpression,
228                    PipePipe | AmpersandAmpersand => LogicalExpression,
229                    _ => BinaryExpression,
230                };
231                Some(binary(state, left, kind, prec, assoc, result_kind.into(), |s, p| PrattParser::parse(s, p, self)))
232            }
233        }
234    }
235}
236
237impl JavaScriptParser {
238    fn parse_root_internal<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<&'a GreenNode<'a, JavaScriptLanguage>, OakError> {
239        let cp = state.checkpoint();
240        while state.not_at_end() {
241            self.parse_statement(state).ok();
242        }
243        Ok(state.finish_at(cp, JavaScriptSyntaxKind::Root.into()))
244    }
245}
246
247impl Parser<JavaScriptLanguage> for JavaScriptParser {
248    fn parse<'a, S: Source + ?Sized>(&self, text: &'a S, edits: &[TextEdit], cache: &'a mut impl ParseCache<JavaScriptLanguage>) -> oak_core::parser::ParseOutput<'a, JavaScriptLanguage> {
249        let lexer = crate::lexer::JavaScriptLexer::new(&self.config);
250        oak_core::parser::parse_with_lexer(&lexer, text, edits, cache, |state| self.parse_root_internal(state))
251    }
252}