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;
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, ActionScriptElementType::IdentifierExpression.into())
27 }
28 Some(k) if k.is_literal() => {
29 state.bump();
30 state.finish_at(cp, ActionScriptElementType::LiteralExpression.into())
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, ActionScriptElementType::ParenthesizedExpression.into())
37 }
38 _ => {
39 state.bump();
40 state.finish_at(cp, ActionScriptElementType::Error.into())
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::*, parser::ActionScriptElementType::*};
47 let kind = match state.peek_kind() {
48 Some(k) => k,
49 None => return self.primary(state),
50 };
51
52 match kind {
53 Minus | LogicalNot | BitwiseNot => unary(state, kind, 13, 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::*, parser::ActionScriptElementType::*};
60 let kind = state.peek_kind()?;
61
62 let (prec, assoc) = match kind {
63 Equal | PlusAssign | MinusAssign | StarAssign | SlashAssign | PercentAssign | LeftShiftAssign | RightShiftAssign | UnsignedRightShiftAssign | BitwiseAndAssign | BitwiseOrAssign | BitwiseXorAssign => (1, Associativity::Right),
64 LogicalOr => (3, Associativity::Left),
65 LogicalAnd => (4, Associativity::Left),
66 EqualEqual | NotEqual | EqualEqualEqual | NotEqualEqual => (5, Associativity::Left),
67 LessThan | LessEqual | GreaterThan | GreaterEqual | Is | Instanceof => (6, Associativity::Left),
68 BitwiseOr => (7, Associativity::Left),
69 BitwiseXor => (8, Associativity::Left),
70 BitwiseAnd => (9, Associativity::Left),
71 LeftShift | RightShift | UnsignedRightShift => (10, Associativity::Left),
72 Plus | Minus => (11, Associativity::Left),
73 Star | Slash | Percent => (12, Associativity::Left),
74 LeftParen | LeftBracket | Dot => (14, Associativity::Left),
75 _ => return None,
76 };
77
78 if prec < min_precedence {
79 return None;
80 }
81
82 match kind {
83 LeftParen => {
84 let cp = state.checkpoint();
85 state.push_child(left);
86 state.expect(LeftParen).ok();
87 if !state.at(RightParen) {
88 loop {
89 PrattParser::parse(state, 0, self);
90 if !state.eat(Comma) {
91 break;
92 }
93 }
94 }
95 state.expect(RightParen).ok();
96 Some(state.finish_at(cp, CallExpression.into()))
97 }
98 LeftBracket => {
99 let cp = state.checkpoint();
100 state.push_child(left);
101 state.expect(LeftBracket).ok();
102 PrattParser::parse(state, 0, self);
103 state.expect(RightBracket).ok();
104 Some(state.finish_at(cp, IndexExpression.into()))
105 }
106 Dot => {
107 let cp = state.checkpoint();
108 state.push_child(left);
109 state.expect(Dot).ok();
110 state.expect(crate::lexer::ActionScriptTokenType::Identifier).ok();
111 Some(state.finish_at(cp, FieldExpression.into()))
112 }
113 _ => Some(binary(state, left, kind, prec, assoc, BinaryExpression.into(), |s, p| PrattParser::parse(s, p, self))),
114 }
115 }
116}
117
118impl<'config> ActionScriptParser<'config> {
119 pub fn new(config: &'config ActionScriptLanguage) -> Self {
120 Self { config }
121 }
122}
123
124impl<'config> Parser<ActionScriptLanguage> for ActionScriptParser<'config> {
125 fn parse<'a, S: Source + ?Sized>(&self, text: &'a S, edits: &[TextEdit], cache: &'a mut impl ParseCache<ActionScriptLanguage>) -> ParseOutput<'a, ActionScriptLanguage> {
126 let lexer = ActionScriptLexer::new(self.config);
127 parse_with_lexer(&lexer, text, edits, cache, |state| self.parse_source_file(state))
128 }
129}