oak_actionscript/parser/
mod.rs

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}