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;
13pub use self::element_type::ElixirElementType;
14
15pub(crate) type State<'a, S> = ParserState<'a, ElixirLanguage, S>;
16
17pub struct ElixirParser<'config> {
19 pub(crate) config: &'config ElixirLanguage,
20}
21
22impl<'config> Parser<ElixirLanguage> for ElixirParser<'config> {
23 fn parse<'a, S: Source + ?Sized>(&self, text: &'a S, edits: &[TextEdit], cache: &'a mut impl ParseCache<ElixirLanguage>) -> ParseOutput<'a, ElixirLanguage> {
24 let lexer = ElixirLexer::new(self.config);
25 parse_with_lexer(&lexer, text, edits, cache, |state| {
26 let checkpoint = state.checkpoint();
27
28 while state.not_at_end() {
29 match state.peek_kind() {
30 Some(ElixirTokenType::Defmodule) => {
31 self.parse_module(state);
32 }
33 Some(ElixirTokenType::Def) | Some(ElixirTokenType::Defp) => {
34 self.parse_function(state);
35 }
36 Some(_) => {
37 PrattParser::parse(state, 0, self);
38 }
39 None => break,
40 }
41 state.eat(ElixirTokenType::Semicolon);
42 state.eat(ElixirTokenType::Newline);
43 }
44
45 Ok(state.finish_at(checkpoint, ElixirElementType::Root))
46 })
47 }
48}
49
50impl<'config> ElixirParser<'config> {
51 pub fn new(config: &'config ElixirLanguage) -> Self {
53 Self { config }
54 }
55
56 fn parse_module<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> &'a GreenNode<'a, ElixirLanguage> {
57 let cp = state.checkpoint();
58 state.expect(ElixirTokenType::Defmodule).ok();
59 PrattParser::parse(state, 0, self); state.expect(ElixirTokenType::Do).ok();
61 while state.not_at_end() && !state.at(ElixirTokenType::End) {
62 match state.peek_kind() {
63 Some(ElixirTokenType::Def) | Some(ElixirTokenType::Defp) => {
64 self.parse_function(state);
65 }
66 Some(_) => {
67 PrattParser::parse(state, 0, self);
68 }
69 None => break,
70 }
71 state.eat(ElixirTokenType::Semicolon);
72 state.eat(ElixirTokenType::Newline);
73 }
74 state.expect(ElixirTokenType::End).ok();
75 state.finish_at(cp, ElixirElementType::ModuleDefinition)
76 }
77
78 fn parse_function<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> &'a GreenNode<'a, ElixirLanguage> {
79 let cp = state.checkpoint();
80 state.bump(); PrattParser::parse(state, 0, self); if state.eat(ElixirTokenType::Do) {
83 while state.not_at_end() && !state.at(ElixirTokenType::End) {
84 PrattParser::parse(state, 0, self);
85 state.eat(ElixirTokenType::Semicolon);
86 state.eat(ElixirTokenType::Newline);
87 }
88 state.expect(ElixirTokenType::End).ok();
89 }
90 state.finish_at(cp, ElixirElementType::FunctionDefinition)
91 }
92}
93
94impl<'config> Pratt<ElixirLanguage> for ElixirParser<'config> {
95 fn primary<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> &'a GreenNode<'a, ElixirLanguage> {
96 let cp = state.checkpoint();
97 match state.peek_kind() {
98 Some(ElixirTokenType::Identifier) => {
99 state.bump();
100 state.finish_at(cp, ElixirElementType::IdentifierExpression)
101 }
102 Some(ElixirTokenType::Atom) => {
103 state.bump();
104 state.finish_at(cp, ElixirElementType::LiteralExpression)
105 }
106 Some(ElixirTokenType::Number) | Some(ElixirTokenType::Float) => {
107 state.bump();
108 state.finish_at(cp, ElixirElementType::LiteralExpression)
109 }
110 Some(ElixirTokenType::String) | Some(ElixirTokenType::Character) => {
111 state.bump();
112 state.finish_at(cp, ElixirElementType::LiteralExpression)
113 }
114 Some(ElixirTokenType::LeftParen) => {
115 state.bump();
116 PrattParser::parse(state, 0, self);
117 state.expect(ElixirTokenType::RightParen).ok();
118 state.finish_at(cp, ElixirElementType::BlockExpression)
119 }
120 Some(ElixirTokenType::LeftBracket) => {
121 state.bump();
122 if !state.at(ElixirTokenType::RightBracket) {
123 loop {
124 PrattParser::parse(state, 0, self);
125 if !state.eat(ElixirTokenType::Comma) {
126 break;
127 }
128 }
129 }
130 state.expect(ElixirTokenType::RightBracket).ok();
131 state.finish_at(cp, ElixirElementType::ListLiteral)
132 }
133 Some(ElixirTokenType::LeftBrace) => {
134 state.bump();
135 if !state.at(ElixirTokenType::RightBrace) {
136 loop {
137 PrattParser::parse(state, 0, self);
138 if !state.eat(ElixirTokenType::Comma) {
139 break;
140 }
141 }
142 }
143 state.expect(ElixirTokenType::RightBrace).ok();
144 state.finish_at(cp, ElixirElementType::TupleLiteral)
145 }
146 Some(ElixirTokenType::Percent) => {
147 state.bump();
148 if state.eat(ElixirTokenType::LeftBrace) {
149 if !state.at(ElixirTokenType::RightBrace) {
150 loop {
151 PrattParser::parse(state, 0, self);
152 if !state.eat(ElixirTokenType::Comma) {
153 break;
154 }
155 }
156 }
157 state.expect(ElixirTokenType::RightBrace).ok();
158 state.finish_at(cp, ElixirElementType::MapLiteral)
159 }
160 else {
161 state.finish_at(cp, ElixirElementType::Error)
162 }
163 }
164 _ => {
165 state.bump();
166 state.finish_at(cp, ElixirElementType::Error)
167 }
168 }
169 }
170
171 fn prefix<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> &'a GreenNode<'a, ElixirLanguage> {
172 let kind = match state.peek_kind() {
173 Some(k) => k,
174 None => return self.primary(state),
175 };
176
177 match kind {
178 ElixirTokenType::Plus | ElixirTokenType::Minus | ElixirTokenType::Bang | ElixirTokenType::At => unary(state, kind, 13, ElixirElementType::UnaryExpression.into(), |s, p| PrattParser::parse(s, p, self)),
179 _ => self.primary(state),
180 }
181 }
182
183 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>> {
184 use ElixirTokenType::*;
185 let kind = state.peek_kind()?;
186
187 let (prec, assoc) = match kind {
188 Eq => (1, Associativity::Right),
189 OrOr => (2, Associativity::Left),
190 AndAnd => (3, Associativity::Left),
191 EqEq | Ne => (4, Associativity::Left),
192 Lt | Le | Gt | Ge => (5, Associativity::Left),
193 Pipeline => (6, Associativity::Left),
194 Concat | PlusPlus | MinusMinus => (7, Associativity::Left),
195 Plus | Minus => (8, Associativity::Left),
196 Mul | Div => (9, Associativity::Left),
197 Dot => (11, Associativity::Left),
198 LeftParen => (12, Associativity::Left),
199 _ => return None,
200 };
201
202 if prec < min_precedence {
203 return None;
204 }
205
206 match kind {
207 LeftParen => {
208 let cp = state.checkpoint();
209 state.push_child(left);
210 state.bump();
211 if !state.at(RightParen) {
212 loop {
213 PrattParser::parse(state, 0, self);
214 if !state.eat(Comma) {
215 break;
216 }
217 }
218 }
219 state.expect(RightParen).ok();
220 Some(state.finish_at(cp, ElixirElementType::CallExpression))
221 }
222 Dot => {
223 let cp = state.checkpoint();
224 state.push_child(left);
225 state.bump();
226 PrattParser::parse(state, prec + 1, self);
227 Some(state.finish_at(cp, ElixirElementType::AccessExpression))
228 }
229 Eq => Some(binary(state, left, kind, prec, assoc, ElixirElementType::MatchExpression.into(), |s, p| PrattParser::parse(s, p, self))),
230 _ => Some(binary(state, left, kind, prec, assoc, ElixirElementType::BinaryExpression.into(), |s, p| PrattParser::parse(s, p, self))),
231 }
232 }
233}