1use crate::{
2 language::ElixirLanguage,
3 lexer::{ElixirLexer, token_type::ElixirTokenType},
4};
5use oak_core::{
6 GreenNode, OakError, TokenType,
7 parser::{Associativity, ParseCache, ParseOutput, Parser, ParserState, Pratt, PrattParser, binary, parse_with_lexer, unary},
8 source::{Source, TextEdit},
9};
10
11pub mod element_type;
12mod parse_top_level;
13pub use self::element_type::ElixirElementType;
14
15pub(crate) type State<'a, S> = ParserState<'a, ElixirLanguage, S>;
16
17pub struct ElixirParser<'config> {
18 pub(crate) _config: &'config ElixirLanguage,
19}
20
21impl<'config> Parser<ElixirLanguage> for ElixirParser<'config> {
22 fn parse<'a, S: Source + ?Sized>(&self, text: &'a S, edits: &[TextEdit], cache: &'a mut impl ParseCache<ElixirLanguage>) -> ParseOutput<'a, ElixirLanguage> {
23 let lexer = ElixirLexer::new(self._config);
24 parse_with_lexer(&lexer, text, edits, cache, |state| self.parse_root_internal(state))
25 }
26}
27
28impl<'config> ElixirParser<'config> {
29 pub fn new(config: &'config ElixirLanguage) -> Self {
30 Self { _config: config }
31 }
32}
33
34impl<'config> Pratt<ElixirLanguage> for ElixirParser<'config> {
35 fn primary<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> &'a GreenNode<'a, ElixirLanguage> {
36 let cp = state.checkpoint();
37 match state.peek_kind() {
38 Some(ElixirTokenType::Identifier) => {
39 state.bump();
40 state.finish_at(cp, ElixirElementType::IdentifierExpression)
41 }
42 Some(ElixirTokenType::Atom) => {
43 state.bump();
44 state.finish_at(cp, ElixirElementType::LiteralExpression)
45 }
46 Some(ElixirTokenType::Number) | Some(ElixirTokenType::Float) => {
47 state.bump();
48 state.finish_at(cp, ElixirElementType::LiteralExpression)
49 }
50 Some(ElixirTokenType::String) | Some(ElixirTokenType::Character) => {
51 state.bump();
52 state.finish_at(cp, ElixirElementType::LiteralExpression)
53 }
54 Some(ElixirTokenType::LeftParen) => {
55 state.bump();
56 PrattParser::parse(state, 0, self);
57 state.expect(ElixirTokenType::RightParen).ok();
58 state.finish_at(cp, ElixirElementType::BlockExpression)
59 }
60 Some(ElixirTokenType::LeftBracket) => {
61 state.bump();
62 if !state.at(ElixirTokenType::RightBracket) {
63 loop {
64 PrattParser::parse(state, 0, self);
65 if !state.eat(ElixirTokenType::Comma) {
66 break;
67 }
68 }
69 }
70 state.expect(ElixirTokenType::RightBracket).ok();
71 state.finish_at(cp, ElixirElementType::ListLiteral)
72 }
73 Some(ElixirTokenType::LeftBrace) => {
74 state.bump();
75 if !state.at(ElixirTokenType::RightBrace) {
76 loop {
77 PrattParser::parse(state, 0, self);
78 if !state.eat(ElixirTokenType::Comma) {
79 break;
80 }
81 }
82 }
83 state.expect(ElixirTokenType::RightBrace).ok();
84 state.finish_at(cp, ElixirElementType::TupleLiteral)
85 }
86 Some(ElixirTokenType::Percent) => {
87 state.bump();
88 if state.eat(ElixirTokenType::LeftBrace) {
89 if !state.at(ElixirTokenType::RightBrace) {
90 loop {
91 PrattParser::parse(state, 0, self);
92 if !state.eat(ElixirTokenType::Comma) {
93 break;
94 }
95 }
96 }
97 state.expect(ElixirTokenType::RightBrace).ok();
98 state.finish_at(cp, ElixirElementType::MapLiteral)
99 }
100 else {
101 state.finish_at(cp, ElixirElementType::Error)
102 }
103 }
104 _ => {
105 state.bump();
106 state.finish_at(cp, ElixirElementType::Error)
107 }
108 }
109 }
110
111 fn prefix<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> &'a GreenNode<'a, ElixirLanguage> {
112 let kind = match state.peek_kind() {
113 Some(k) => k,
114 None => return self.primary(state),
115 };
116
117 match kind {
118 ElixirTokenType::Plus | ElixirTokenType::Minus | ElixirTokenType::Bang | ElixirTokenType::At => unary(state, kind, 13, ElixirElementType::UnaryExpression.into(), |s, p| PrattParser::parse(s, p, self)),
119 _ => self.primary(state),
120 }
121 }
122
123 fn infix<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>, left: &'a GreenNode<'a, ElixirLanguage>, min_precedence: u8) -> Option<&'a GreenNode<'a, ElixirLanguage>> {
124 use ElixirTokenType::*;
125 let kind = state.peek_kind()?;
126
127 let (prec, assoc) = match kind {
128 Eq => (1, Associativity::Right),
129 OrOr => (2, Associativity::Left),
130 AndAnd => (3, Associativity::Left),
131 EqEq | Ne => (4, Associativity::Left),
132 Lt | Le | Gt | Ge => (5, Associativity::Left),
133 Pipeline => (6, Associativity::Left),
134 Concat | PlusPlus | MinusMinus => (7, Associativity::Left),
135 Plus | Minus => (8, Associativity::Left),
136 Mul | Div => (9, Associativity::Left),
137 Dot => (11, Associativity::Left),
138 LeftParen => (12, Associativity::Left),
139 _ => return None,
140 };
141
142 if prec < min_precedence {
143 return None;
144 }
145
146 match kind {
147 LeftParen => {
148 let cp = state.checkpoint();
149 state.push_child(left);
150 state.bump();
151 if !state.at(RightParen) {
152 loop {
153 PrattParser::parse(state, 0, self);
154 if !state.eat(Comma) {
155 break;
156 }
157 }
158 }
159 state.expect(RightParen).ok();
160 Some(state.finish_at(cp, ElixirElementType::CallExpression))
161 }
162 Dot => {
163 let cp = state.checkpoint();
164 state.push_child(left);
165 state.bump();
166 PrattParser::parse(state, prec + 1, self);
167 Some(state.finish_at(cp, ElixirElementType::AccessExpression))
168 }
169 Eq => Some(binary(state, left, kind, prec, assoc, ElixirElementType::MatchExpression.into(), |s, p| PrattParser::parse(s, p, self))),
170 _ => Some(binary(state, left, kind, prec, assoc, ElixirElementType::BinaryExpression.into(), |s, p| PrattParser::parse(s, p, self))),
171 }
172 }
173}