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(); 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 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}