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