1pub mod element_type;
3
4pub use element_type::ActionScriptElementType;
5
6use crate::{language::ActionScriptLanguage, lexer::ActionScriptLexer};
7use oak_core::{
8 GreenNode, TokenType,
9 parser::{Associativity, ParseCache, ParseOutput, Parser, ParserState, Pratt, PrattParser, binary, parse_with_lexer, unary},
10 source::{Source, TextEdit},
11};
12
13pub(crate) type State<'a, S> = ParserState<'a, ActionScriptLanguage, S>;
14
15pub struct ActionScriptParser<'config> {
17 pub(crate) config: &'config ActionScriptLanguage,
18}
19
20impl<'config> Pratt<ActionScriptLanguage> for ActionScriptParser<'config> {
21 fn primary<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> &'a GreenNode<'a, ActionScriptLanguage> {
22 let cp = state.checkpoint();
23 match state.peek_kind() {
24 Some(crate::lexer::ActionScriptTokenType::Identifier) => {
25 state.bump();
26 state.finish_at(cp, crate::parser::element_type::ActionScriptElementType::IdentifierExpression)
27 }
28 Some(k) if k.is_literal() => {
29 state.bump();
30 state.finish_at(cp, crate::parser::element_type::ActionScriptElementType::LiteralExpression)
31 }
32 Some(crate::lexer::ActionScriptTokenType::LeftParen) => {
33 state.bump();
34 PrattParser::parse(state, 0, self);
35 state.expect(crate::lexer::ActionScriptTokenType::RightParen).ok();
36 state.finish_at(cp, crate::parser::element_type::ActionScriptElementType::ParenthesizedExpression)
37 }
38 _ => {
39 state.bump();
40 state.finish_at(cp, crate::parser::element_type::ActionScriptElementType::Error)
41 }
42 }
43 }
44
45 fn prefix<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> &'a GreenNode<'a, ActionScriptLanguage> {
46 use crate::{lexer::ActionScriptTokenType as TT, parser::element_type::ActionScriptElementType as ET};
47 let kind = match state.peek_kind() {
48 Some(k) => k,
49 None => return self.primary(state),
50 };
51
52 match kind {
53 TT::Minus | TT::LogicalNot | TT::BitwiseNot => unary(state, kind, 13, ET::UnaryExpression.into(), |s, p| PrattParser::parse(s, p, self)),
54 _ => self.primary(state),
55 }
56 }
57
58 fn infix<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>, left: &'a GreenNode<'a, ActionScriptLanguage>, min_precedence: u8) -> Option<&'a GreenNode<'a, ActionScriptLanguage>> {
59 use crate::{lexer::ActionScriptTokenType as TT, parser::element_type::ActionScriptElementType as ET};
60 let kind = state.peek_kind()?;
61
62 let (prec, assoc) = match kind {
63 TT::Equal
64 | TT::PlusAssign
65 | TT::MinusAssign
66 | TT::StarAssign
67 | TT::SlashAssign
68 | TT::PercentAssign
69 | TT::LeftShiftAssign
70 | TT::RightShiftAssign
71 | TT::UnsignedRightShiftAssign
72 | TT::BitwiseAndAssign
73 | TT::BitwiseOrAssign
74 | TT::BitwiseXorAssign => (1, Associativity::Right),
75 TT::LogicalOr => (3, Associativity::Left),
76 TT::LogicalAnd => (4, Associativity::Left),
77 TT::EqualEqual | TT::NotEqual | TT::EqualEqualEqual | TT::NotEqualEqual => (5, Associativity::Left),
78 TT::LessThan | TT::LessEqual | TT::GreaterThan | TT::GreaterEqual | TT::Is | TT::Instanceof => (6, Associativity::Left),
79 TT::BitwiseOr => (7, Associativity::Left),
80 TT::BitwiseXor => (8, Associativity::Left),
81 TT::BitwiseAnd => (9, Associativity::Left),
82 TT::LeftShift | TT::RightShift | TT::UnsignedRightShift => (10, Associativity::Left),
83 TT::Plus | TT::Minus => (11, Associativity::Left),
84 TT::Star | TT::Slash | TT::Percent => (12, Associativity::Left),
85 TT::LeftParen | TT::LeftBracket | TT::Dot => (14, Associativity::Left),
86 _ => return None,
87 };
88
89 if prec < min_precedence {
90 return None;
91 }
92
93 match kind {
94 TT::LeftParen => {
95 let cp = state.checkpoint();
96 state.push_child(left);
97 state.expect(TT::LeftParen).ok();
98 if !state.at(TT::RightParen) {
99 loop {
100 PrattParser::parse(state, 0, self);
101 if !state.eat(TT::Comma) {
102 break;
103 }
104 }
105 }
106 state.expect(TT::RightParen).ok();
107 Some(state.finish_at(cp, ET::CallExpression))
108 }
109 TT::LeftBracket => {
110 let cp = state.checkpoint();
111 state.push_child(left);
112 state.expect(TT::LeftBracket).ok();
113 PrattParser::parse(state, 0, self);
114 state.expect(TT::RightBracket).ok();
115 Some(state.finish_at(cp, ET::IndexExpression))
116 }
117 TT::Dot => {
118 let cp = state.checkpoint();
119 state.push_child(left);
120 state.expect(TT::Dot).ok();
121 state.expect(TT::Identifier).ok();
122 Some(state.finish_at(cp, ET::FieldExpression))
123 }
124 _ => Some(binary(state, left, kind, prec, assoc, ET::BinaryExpression.into(), |s, p| PrattParser::parse(s, p, self))),
125 }
126 }
127}
128
129impl<'config> ActionScriptParser<'config> {
130 pub fn new(config: &'config ActionScriptLanguage) -> Self {
132 Self { config }
133 }
134
135 pub(crate) fn parse_statement<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), oak_core::OakError> {
136 use crate::lexer::ActionScriptTokenType;
137 match state.peek_kind() {
138 Some(ActionScriptTokenType::Function) => self.parse_function(state)?,
139 Some(ActionScriptTokenType::Import) => self.parse_import_statement(state)?,
140 Some(ActionScriptTokenType::Package) => self.parse_package_declaration(state)?,
141 Some(ActionScriptTokenType::Class) => self.parse_class_declaration(state)?,
142 Some(ActionScriptTokenType::Interface) => self.parse_interface_declaration(state)?,
143 Some(ActionScriptTokenType::Var) | Some(ActionScriptTokenType::Const) => self.parse_variable_declaration(state)?,
144 Some(ActionScriptTokenType::If) => self.parse_if_statement(state)?,
145 Some(ActionScriptTokenType::While) => self.parse_while_statement(state)?,
146 Some(ActionScriptTokenType::For) => self.parse_for_statement(state)?,
147 Some(ActionScriptTokenType::Return) => self.parse_return_statement(state)?,
148 Some(ActionScriptTokenType::LeftBrace) => self.parse_block(state)?,
149 _ => {
150 PrattParser::parse(state, 0, self);
151 state.eat(ActionScriptTokenType::Semicolon);
152 }
153 }
154 Ok(())
155 }
156
157 fn parse_function<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), oak_core::OakError> {
158 use crate::lexer::ActionScriptTokenType;
159 let cp = state.checkpoint();
160 state.expect(ActionScriptTokenType::Function).ok();
161 state.expect(ActionScriptTokenType::Identifier).ok();
162 self.parse_param_list(state)?;
163 if state.eat(ActionScriptTokenType::Colon) {
164 state.expect(ActionScriptTokenType::Identifier).ok();
165 }
166 self.parse_block(state)?;
167 state.finish_at(cp, ActionScriptElementType::Function);
168 Ok(())
169 }
170
171 fn parse_param_list<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), oak_core::OakError> {
172 use crate::lexer::ActionScriptTokenType::*;
173 let cp = state.checkpoint();
174 state.expect(LeftParen).ok();
175 while state.not_at_end() && !state.at(RightParen) {
176 state.advance()
177 }
178 state.expect(RightParen).ok();
179 state.finish_at(cp, ActionScriptElementType::ParameterList);
180 Ok(())
181 }
182
183 fn parse_block<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), oak_core::OakError> {
184 use crate::lexer::ActionScriptTokenType::*;
185 let cp = state.checkpoint();
186 state.expect(LeftBrace).ok();
187 while state.not_at_end() && !state.at(RightBrace) {
188 self.parse_statement(state)?
189 }
190 state.expect(RightBrace).ok();
191 state.finish_at(cp, ActionScriptElementType::BlockExpression);
192 Ok(())
193 }
194
195 fn parse_import_statement<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), oak_core::OakError> {
196 let cp = state.checkpoint();
197 state.expect(crate::lexer::ActionScriptTokenType::Import).ok();
198 while !state.at(crate::lexer::ActionScriptTokenType::Semicolon) && state.not_at_end() {
199 state.bump()
200 }
201 state.eat(crate::lexer::ActionScriptTokenType::Semicolon);
202 state.finish_at(cp, ActionScriptElementType::Import);
203 Ok(())
204 }
205
206 fn parse_package_declaration<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), oak_core::OakError> {
207 let cp = state.checkpoint();
208 state.expect(crate::lexer::ActionScriptTokenType::Package).ok();
209 if state.at(crate::lexer::ActionScriptTokenType::Identifier) {
210 state.bump()
211 }
212 self.parse_block(state)?;
213 state.finish_at(cp, ActionScriptElementType::Package);
214 Ok(())
215 }
216
217 fn parse_class_declaration<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), oak_core::OakError> {
218 let cp = state.checkpoint();
219 state.expect(crate::lexer::ActionScriptTokenType::Class).ok();
220 state.expect(crate::lexer::ActionScriptTokenType::Identifier).ok();
221 if state.eat(crate::lexer::ActionScriptTokenType::Extends) {
222 state.expect(crate::lexer::ActionScriptTokenType::Identifier).ok();
223 }
224 self.parse_block(state)?;
225 state.finish_at(cp, ActionScriptElementType::Class);
226 Ok(())
227 }
228
229 fn parse_interface_declaration<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), oak_core::OakError> {
230 let cp = state.checkpoint();
231 state.expect(crate::lexer::ActionScriptTokenType::Interface).ok();
232 state.expect(crate::lexer::ActionScriptTokenType::Identifier).ok();
233 self.parse_block(state)?;
234 state.finish_at(cp, ActionScriptElementType::Interface);
235 Ok(())
236 }
237
238 fn parse_variable_declaration<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), oak_core::OakError> {
239 let cp = state.checkpoint();
240 if state.eat(crate::lexer::ActionScriptTokenType::Var) || state.eat(crate::lexer::ActionScriptTokenType::Const) {
241 state.expect(crate::lexer::ActionScriptTokenType::Identifier).ok();
242 if state.eat(crate::lexer::ActionScriptTokenType::Colon) {
243 state.expect(crate::lexer::ActionScriptTokenType::Identifier).ok();
244 }
245 if state.eat(crate::lexer::ActionScriptTokenType::Equal) {
246 PrattParser::parse(state, 0, self);
247 }
248 state.eat(crate::lexer::ActionScriptTokenType::Semicolon);
249 }
250 state.finish_at(cp, ActionScriptElementType::Variable);
251 Ok(())
252 }
253
254 fn parse_if_statement<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), oak_core::OakError> {
255 let cp = state.checkpoint();
256 state.expect(crate::lexer::ActionScriptTokenType::If).ok();
257 state.expect(crate::lexer::ActionScriptTokenType::LeftParen).ok();
258 PrattParser::parse(state, 0, self);
259 state.expect(crate::lexer::ActionScriptTokenType::RightParen).ok();
260 self.parse_statement(state)?;
261 if state.eat(crate::lexer::ActionScriptTokenType::Else) {
262 self.parse_statement(state)?;
263 }
264 state.finish_at(cp, ActionScriptElementType::IfStatement);
265 Ok(())
266 }
267
268 fn parse_while_statement<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), oak_core::OakError> {
269 let cp = state.checkpoint();
270 state.expect(crate::lexer::ActionScriptTokenType::While).ok();
271 state.expect(crate::lexer::ActionScriptTokenType::LeftParen).ok();
272 PrattParser::parse(state, 0, self);
273 state.expect(crate::lexer::ActionScriptTokenType::RightParen).ok();
274 self.parse_statement(state)?;
275 state.finish_at(cp, ActionScriptElementType::WhileStatement);
276 Ok(())
277 }
278
279 fn parse_for_statement<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), oak_core::OakError> {
280 let cp = state.checkpoint();
281 state.expect(crate::lexer::ActionScriptTokenType::For).ok();
282 state.expect(crate::lexer::ActionScriptTokenType::LeftParen).ok();
283 while state.not_at_end() && !state.at(crate::lexer::ActionScriptTokenType::RightParen) {
284 state.advance();
285 }
286 state.expect(crate::lexer::ActionScriptTokenType::RightParen).ok();
287 self.parse_statement(state)?;
288 state.finish_at(cp, ActionScriptElementType::ForStatement);
289 Ok(())
290 }
291
292 fn parse_return_statement<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), oak_core::OakError> {
293 let cp = state.checkpoint();
294 state.expect(crate::lexer::ActionScriptTokenType::Return).ok();
295 if !state.at(crate::lexer::ActionScriptTokenType::Semicolon) {
296 PrattParser::parse(state, 0, self);
297 }
298 state.eat(crate::lexer::ActionScriptTokenType::Semicolon);
299 state.finish_at(cp, ActionScriptElementType::ReturnStatement);
300 Ok(())
301 }
302}
303
304impl<'config> Parser<ActionScriptLanguage> for ActionScriptParser<'config> {
305 fn parse<'a, S: Source + ?Sized>(&self, text: &'a S, edits: &[TextEdit], cache: &'a mut impl ParseCache<ActionScriptLanguage>) -> ParseOutput<'a, ActionScriptLanguage> {
306 let lexer = ActionScriptLexer::new(&self.config);
307 parse_with_lexer(&lexer, text, edits, cache, |state| {
308 let cp = state.checkpoint();
309 while state.not_at_end() {
310 if state.current().map(|t| t.kind.is_ignored()).unwrap_or(false) {
311 state.advance();
312 continue;
313 }
314 self.parse_statement(state)?
315 }
316 Ok(state.finish_at(cp, ActionScriptElementType::SourceFile))
317 })
318 }
319}