1pub mod element_type;
2
3pub use element_type::ActionScriptElementType;
4
5use crate::{language::ActionScriptLanguage, lexer::ActionScriptLexer};
6use oak_core::{
7 GreenNode,
8 parser::{Associativity, ParseCache, ParseOutput, Parser, ParserState, Pratt, PrattParser, binary, parse_with_lexer, unary},
9 source::{Source, TextEdit},
10};
11
12mod parse_top_level;
13
14pub(crate) type State<'a, S> = ParserState<'a, ActionScriptLanguage, S>;
15
16pub 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 {
131 Self { config }
132 }
133}
134
135impl<'config> Parser<ActionScriptLanguage> for ActionScriptParser<'config> {
136 fn parse<'a, S: Source + ?Sized>(&self, text: &'a S, edits: &[TextEdit], cache: &'a mut impl ParseCache<ActionScriptLanguage>) -> ParseOutput<'a, ActionScriptLanguage> {
137 let lexer = ActionScriptLexer::new(&self.config);
138 parse_with_lexer(&lexer, text, edits, cache, |state| self.parse_source_file(state))
139 }
140}