1pub mod element_type;
3
4use crate::{
5 language::ElmLanguage,
6 lexer::{ElmLexer, token_type::ElmTokenType},
7 parser::element_type::ElmElementType,
8};
9use oak_core::{
10 GreenNode, OakError,
11 parser::{Associativity, ParseCache, ParseOutput, Parser, ParserState, Pratt, PrattParser, binary, parse_with_lexer, unary},
12 source::{Source, TextEdit},
13};
14
15pub(crate) type State<'a, S> = ParserState<'a, ElmLanguage, S>;
16
17pub struct ElmParser<'config> {
19 pub(crate) config: &'config ElmLanguage,
20}
21
22impl<'config> ElmParser<'config> {
23 pub fn new(config: &'config ElmLanguage) -> Self {
25 Self { config }
26 }
27
28 fn parse_item<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), OakError> {
29 match state.peek_kind() {
30 Some(ElmTokenType::Module) => self.parse_module(state),
31 Some(ElmTokenType::Import) => self.parse_import(state),
32 Some(ElmTokenType::Type) => {
33 if state.peek_at(1).map(|t| t.kind) == Some(ElmTokenType::Alias) {
34 self.parse_type_alias(state)
35 }
36 else {
37 self.parse_type_declaration(state)
38 }
39 }
40 Some(ElmTokenType::Port) => self.parse_port(state),
41 Some(ElmTokenType::Identifier) => self.parse_value_declaration(state),
42 Some(_) => {
43 state.bump();
44 Ok(())
45 }
46 None => Ok(()),
47 }
48 }
49
50 fn parse_module<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), OakError> {
51 let cp = state.checkpoint();
52 state.expect(ElmTokenType::Module).ok();
53 state.expect(ElmTokenType::Identifier).ok();
54 if state.eat(ElmTokenType::Exposing) {
55 state.expect(ElmTokenType::LeftParen).ok();
56 while state.not_at_end() && !state.at(ElmTokenType::RightParen) {
57 state.bump();
58 }
59 state.expect(ElmTokenType::RightParen).ok();
60 }
61 state.expect(ElmTokenType::Where).ok();
62 state.finish_at(cp, ElmElementType::Module);
63 Ok(())
64 }
65
66 fn parse_import<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), OakError> {
67 let cp = state.checkpoint();
68 state.expect(ElmTokenType::Import).ok();
69 state.expect(ElmTokenType::Identifier).ok();
70 if state.eat(ElmTokenType::As) {
71 state.expect(ElmTokenType::Identifier).ok();
72 }
73 if state.eat(ElmTokenType::Exposing) {
74 state.expect(ElmTokenType::LeftParen).ok();
75 while state.not_at_end() && !state.at(ElmTokenType::RightParen) {
76 state.bump();
77 }
78 state.expect(ElmTokenType::RightParen).ok();
79 }
80 state.finish_at(cp, ElmElementType::Import);
81 Ok(())
82 }
83
84 fn parse_type_declaration<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), OakError> {
85 let cp = state.checkpoint();
86 state.expect(ElmTokenType::Type).ok();
87 state.expect(ElmTokenType::Identifier).ok();
88 while state.not_at_end() && !state.at(ElmTokenType::Equal) {
89 state.bump();
90 }
91 if state.eat(ElmTokenType::Equal) {
92 while state.not_at_end() && !state.at(ElmTokenType::Newline) {
93 state.bump();
94 }
95 }
96 state.finish_at(cp, ElmElementType::TypeDeclaration);
97 Ok(())
98 }
99
100 fn parse_type_alias<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), OakError> {
101 let cp = state.checkpoint();
102 state.expect(ElmTokenType::Type).ok();
103 state.expect(ElmTokenType::Alias).ok();
104 state.expect(ElmTokenType::Identifier).ok();
105 while state.not_at_end() && !state.at(ElmTokenType::Equal) {
106 state.bump();
107 }
108 if state.eat(ElmTokenType::Equal) {
109 while state.not_at_end() && !state.at(ElmTokenType::Newline) {
110 state.bump();
111 }
112 }
113 state.finish_at(cp, ElmElementType::TypeAlias);
114 Ok(())
115 }
116
117 fn parse_port<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), OakError> {
118 let cp = state.checkpoint();
119 state.expect(ElmTokenType::Port).ok();
120 state.expect(ElmTokenType::Identifier).ok();
121 state.expect(ElmTokenType::Colon).ok();
122 while state.not_at_end() && !state.at(ElmTokenType::Newline) {
123 state.bump();
124 }
125 state.finish_at(cp, ElmElementType::FunctionDeclaration);
126 Ok(())
127 }
128
129 fn parse_value_declaration<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), OakError> {
130 let cp = state.checkpoint();
131 if state.at(ElmTokenType::Identifier) {
132 let next = state.peek_at(1);
133 if matches!(next, Some(t) if t.kind == ElmTokenType::Colon) {
134 state.bump(); state.bump(); while state.not_at_end() && !state.at(ElmTokenType::Newline) {
137 state.bump();
138 }
139 state.finish_at(cp, ElmElementType::TypeSignature);
140 return Ok(());
141 }
142 }
143
144 while state.not_at_end() && !state.at(ElmTokenType::Equal) {
145 self.parse_pattern(state)?;
146 }
147 if state.eat(ElmTokenType::Equal) {
148 PrattParser::parse(state, 0, self);
149 }
150 state.finish_at(cp, ElmElementType::ValueDeclaration);
151 Ok(())
152 }
153
154 fn parse_pattern<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), OakError> {
155 let cp = state.checkpoint();
156 match state.peek_kind() {
157 Some(ElmTokenType::Identifier) | Some(ElmTokenType::Number) | Some(ElmTokenType::String) | Some(ElmTokenType::Char) => {
158 state.bump();
159 }
160 Some(ElmTokenType::LeftParen) => {
161 state.bump();
162 while state.not_at_end() && !state.at(ElmTokenType::RightParen) {
163 self.parse_pattern(state)?;
164 }
165 state.expect(ElmTokenType::RightParen).ok();
166 }
167 Some(ElmTokenType::LeftBracket) => {
168 state.bump();
169 while state.not_at_end() && !state.at(ElmTokenType::RightBracket) {
170 self.parse_pattern(state)?;
171 state.eat(ElmTokenType::Comma);
172 }
173 state.expect(ElmTokenType::RightBracket).ok();
174 }
175 _ => {
176 state.bump();
177 }
178 }
179 state.finish_at(cp, ElmElementType::Pattern);
180 Ok(())
181 }
182}
183
184impl<'config> Parser<ElmLanguage> for ElmParser<'config> {
185 fn parse<'a, S: Source + ?Sized>(&self, text: &'a S, edits: &[TextEdit], cache: &'a mut impl ParseCache<ElmLanguage>) -> ParseOutput<'a, ElmLanguage> {
186 let lexer = ElmLexer::new(self.config);
187 parse_with_lexer(&lexer, text, edits, cache, |state| {
188 let checkpoint = state.checkpoint();
189
190 while state.not_at_end() {
191 self.parse_item(state)?;
192 }
193
194 Ok(state.finish_at(checkpoint, ElmElementType::Root))
195 })
196 }
197}
198
199impl<'config> Pratt<ElmLanguage> for ElmParser<'config> {
200 fn primary<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> &'a GreenNode<'a, ElmLanguage> {
201 let cp = state.checkpoint();
202 match state.peek_kind() {
203 Some(ElmTokenType::Identifier) => {
204 state.bump();
205 state.finish_at(cp, ElmElementType::Identifier)
206 }
207 Some(ElmTokenType::Number) | Some(ElmTokenType::Float) | Some(ElmTokenType::String) | Some(ElmTokenType::Char) => {
208 state.bump();
209 state.finish_at(cp, ElmElementType::Literal)
210 }
211 Some(ElmTokenType::LeftParen) => {
212 state.bump();
213 PrattParser::parse(state, 0, self);
214 state.expect(ElmTokenType::RightParen).ok();
215 state.finish_at(cp, ElmElementType::Expression)
216 }
217 Some(ElmTokenType::LeftBracket) => {
218 state.bump();
219 while state.not_at_end() && !state.at(ElmTokenType::RightBracket) {
220 PrattParser::parse(state, 0, self);
221 state.eat(ElmTokenType::Comma);
222 }
223 state.expect(ElmTokenType::RightBracket).ok();
224 state.finish_at(cp, ElmElementType::ListExpression)
225 }
226 _ => {
227 state.bump();
228 state.finish_at(cp, ElmElementType::Error)
229 }
230 }
231 }
232
233 fn prefix<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> &'a GreenNode<'a, ElmLanguage> {
234 let kind = match state.peek_kind() {
235 Some(k) => k,
236 None => return self.primary(state),
237 };
238
239 match kind {
240 ElmTokenType::Minus => unary(state, kind, 12, ElmElementType::UnaryExpression.into(), |s, p| PrattParser::parse(s, p, self)),
241 _ => self.primary(state),
242 }
243 }
244
245 fn infix<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>, left: &'a GreenNode<'a, ElmLanguage>, min_precedence: u8) -> Option<&'a GreenNode<'a, ElmLanguage>> {
246 let kind = state.peek_kind()?;
247
248 let (prec, assoc) = match kind {
249 ElmTokenType::Dot => (13, Associativity::Left),
250 ElmTokenType::Star | ElmTokenType::Slash | ElmTokenType::DoubleSlash | ElmTokenType::Percent => (11, Associativity::Left),
251 ElmTokenType::Plus | ElmTokenType::Minus => (10, Associativity::Left),
252 ElmTokenType::DoublePlus => (9, Associativity::Right),
253 ElmTokenType::EqualEqual | ElmTokenType::NotEqual | ElmTokenType::Less | ElmTokenType::Greater | ElmTokenType::LessEqual | ElmTokenType::GreaterEqual => (8, Associativity::Left),
254 ElmTokenType::DoubleAmpersand => (7, Associativity::Right),
255 ElmTokenType::DoublePipe => (6, Associativity::Right),
256 ElmTokenType::DoubleLess | ElmTokenType::DoubleGreater => (5, Associativity::Left),
257 _ => return None,
258 };
259
260 if prec < min_precedence {
261 return None;
262 }
263
264 Some(binary(state, left, kind, prec, assoc, ElmElementType::BinaryExpression.into(), |s, p| PrattParser::parse(s, p, self)))
265 }
266}