1pub mod element_type;
2
3use crate::{
4 language::PurescriptLanguage,
5 lexer::{PurescriptLexer, token_type::PurescriptTokenType},
6 parser::element_type::PurescriptElementType,
7};
8use oak_core::{
9 GreenNode, OakError,
10 parser::{Associativity, ParseCache, ParseOutput, Parser, ParserState, Pratt, PrattParser, binary, parse_with_lexer, unary},
11 source::{Source, TextEdit},
12};
13
14pub(crate) type State<'a, S> = ParserState<'a, PurescriptLanguage, S>;
15
16pub struct PurescriptParser<'config> {
18 pub(crate) config: &'config PurescriptLanguage,
19}
20
21impl<'config> PurescriptParser<'config> {
22 pub fn new(config: &'config PurescriptLanguage) -> Self {
24 Self { config }
25 }
26
27 fn parse_item<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), OakError> {
28 match state.peek_kind() {
29 Some(PurescriptTokenType::Module) => self.parse_module(state),
30 Some(PurescriptTokenType::Import) => self.parse_import(state),
31 Some(PurescriptTokenType::Data) => self.parse_data(state),
32 Some(PurescriptTokenType::Newtype) => self.parse_newtype(state),
33 Some(PurescriptTokenType::Type) => self.parse_type_alias(state),
34 Some(PurescriptTokenType::Class) => self.parse_class(state),
35 Some(PurescriptTokenType::Instance) => self.parse_instance(state),
36 Some(PurescriptTokenType::Foreign) => self.parse_foreign(state),
37 Some(PurescriptTokenType::Identifier) | Some(PurescriptTokenType::Operator) => self.parse_value_declaration(state),
38 Some(_) => {
39 state.bump();
40 Ok(())
41 }
42 None => Ok(()),
43 }
44 }
45
46 fn parse_module<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), OakError> {
47 let cp = state.checkpoint();
48 state.expect(PurescriptTokenType::Module).ok();
49 state.expect(PurescriptTokenType::UpperIdentifier).ok();
50 while state.eat(PurescriptTokenType::Dot) {
51 state.expect(PurescriptTokenType::UpperIdentifier).ok();
52 }
53 if state.eat(PurescriptTokenType::LeftParen) {
54 while state.not_at_end() && !state.at(PurescriptTokenType::RightParen) {
55 state.bump();
56 }
57 state.expect(PurescriptTokenType::RightParen).ok();
58 }
59 state.expect(PurescriptTokenType::Where).ok();
60 state.finish_at(cp, PurescriptElementType::ModuleDeclaration);
61 Ok(())
62 }
63
64 fn parse_import<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), OakError> {
65 let cp = state.checkpoint();
66 state.expect(PurescriptTokenType::Import).ok();
67 state.expect(PurescriptTokenType::UpperIdentifier).ok();
68 while state.eat(PurescriptTokenType::Dot) {
69 state.expect(PurescriptTokenType::UpperIdentifier).ok();
70 }
71 if state.eat(PurescriptTokenType::LeftParen) {
72 while state.not_at_end() && !state.at(PurescriptTokenType::RightParen) {
73 state.bump();
74 }
75 state.expect(PurescriptTokenType::RightParen).ok();
76 }
77 state.finish_at(cp, PurescriptElementType::ImportDeclaration);
78 Ok(())
79 }
80
81 fn parse_data<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), OakError> {
82 let cp = state.checkpoint();
83 state.expect(PurescriptTokenType::Data).ok();
84 state.expect(PurescriptTokenType::UpperIdentifier).ok();
85 while state.not_at_end() && !state.at(PurescriptTokenType::Equal) && !state.at(PurescriptTokenType::Where) {
86 state.bump();
87 }
88 if state.eat(PurescriptTokenType::Equal) {
89 while state.not_at_end() && !state.at(PurescriptTokenType::Pipe) && !state.at(PurescriptTokenType::Newline) {
90 state.bump();
91 }
92 }
93 state.finish_at(cp, PurescriptElementType::DataDeclaration);
94 Ok(())
95 }
96
97 fn parse_newtype<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), OakError> {
98 let cp = state.checkpoint();
99 state.expect(PurescriptTokenType::Newtype).ok();
100 state.expect(PurescriptTokenType::UpperIdentifier).ok();
101 while state.not_at_end() && !state.at(PurescriptTokenType::Equal) {
102 state.bump();
103 }
104 if state.eat(PurescriptTokenType::Equal) {
105 state.expect(PurescriptTokenType::UpperIdentifier).ok();
106 self.parse_type(state)?;
107 }
108 state.finish_at(cp, PurescriptElementType::NewtypeDeclaration);
109 Ok(())
110 }
111
112 fn parse_type_alias<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), OakError> {
113 let cp = state.checkpoint();
114 state.expect(PurescriptTokenType::Type).ok();
115 state.expect(PurescriptTokenType::UpperIdentifier).ok();
116 while state.not_at_end() && !state.at(PurescriptTokenType::Equal) {
117 state.bump();
118 }
119 if state.eat(PurescriptTokenType::Equal) {
120 self.parse_type(state)?;
121 }
122 state.finish_at(cp, PurescriptElementType::TypeAliasDeclaration);
123 Ok(())
124 }
125
126 fn parse_class<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), OakError> {
127 let cp = state.checkpoint();
128 state.expect(PurescriptTokenType::Class).ok();
129 while state.not_at_end() && !state.at(PurescriptTokenType::Where) {
130 state.bump();
131 }
132 if state.eat(PurescriptTokenType::Where) {
133 while state.not_at_end() && !state.at(PurescriptTokenType::Newline) {
134 state.bump();
135 }
136 }
137 state.finish_at(cp, PurescriptElementType::ClassDeclaration);
138 Ok(())
139 }
140
141 fn parse_instance<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), OakError> {
142 let cp = state.checkpoint();
143 state.expect(PurescriptTokenType::Instance).ok();
144 while state.not_at_end() && !state.at(PurescriptTokenType::Where) {
145 state.bump();
146 }
147 if state.eat(PurescriptTokenType::Where) {
148 while state.not_at_end() && !state.at(PurescriptTokenType::Newline) {
149 state.bump();
150 }
151 }
152 state.finish_at(cp, PurescriptElementType::InstanceDeclaration);
153 Ok(())
154 }
155
156 fn parse_foreign<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), OakError> {
157 let cp = state.checkpoint();
158 state.expect(PurescriptTokenType::Foreign).ok();
159 state.expect(PurescriptTokenType::Import).ok();
160 while state.not_at_end() && !state.at(PurescriptTokenType::Newline) {
161 state.bump();
162 }
163 state.finish_at(cp, PurescriptElementType::ForeignImportDeclaration);
164 Ok(())
165 }
166
167 fn parse_value_declaration<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), OakError> {
168 let cp = state.checkpoint();
169 if state.at(PurescriptTokenType::Identifier) {
170 let next = state.peek_at(1);
171 if matches!(next, Some(t) if t.kind == PurescriptTokenType::ColonColon) {
172 state.bump(); state.bump(); self.parse_type(state)?;
175 state.finish_at(cp, PurescriptElementType::TypeSignature);
176 return Ok(());
177 }
178 }
179
180 while state.not_at_end() && !state.at(PurescriptTokenType::Equal) && !state.at(PurescriptTokenType::Pipe) {
181 self.parse_pattern(state)?;
182 }
183 if state.eat(PurescriptTokenType::Equal) {
184 PrattParser::parse(state, 0, self);
185 }
186 else if state.at(PurescriptTokenType::Pipe) {
187 while state.eat(PurescriptTokenType::Pipe) {
188 PrattParser::parse(state, 0, self);
189 state.expect(PurescriptTokenType::Equal).ok();
190 PrattParser::parse(state, 0, self);
191 }
192 }
193 if state.eat(PurescriptTokenType::Where) {
194 while state.not_at_end() && !state.at(PurescriptTokenType::Newline) {
195 state.bump();
196 }
197 }
198 state.finish_at(cp, PurescriptElementType::ValueDeclaration);
199 Ok(())
200 }
201
202 fn parse_pattern<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), OakError> {
203 let cp = state.checkpoint();
204 match state.peek_kind() {
205 Some(PurescriptTokenType::Identifier)
206 | Some(PurescriptTokenType::UpperIdentifier)
207 | Some(PurescriptTokenType::IntLiteral)
208 | Some(PurescriptTokenType::StringLiteral)
209 | Some(PurescriptTokenType::CharLiteral)
210 | Some(PurescriptTokenType::True)
211 | Some(PurescriptTokenType::False)
212 | Some(PurescriptTokenType::Underscore) => {
213 state.bump();
214 }
215 Some(PurescriptTokenType::LeftParen) => {
216 state.bump();
217 while state.not_at_end() && !state.at(PurescriptTokenType::RightParen) {
218 self.parse_pattern(state)?;
219 }
220 state.expect(PurescriptTokenType::RightParen).ok();
221 }
222 Some(PurescriptTokenType::LeftBracket) => {
223 state.bump();
224 while state.not_at_end() && !state.at(PurescriptTokenType::RightBracket) {
225 self.parse_pattern(state)?;
226 state.eat(PurescriptTokenType::Comma);
227 }
228 state.expect(PurescriptTokenType::RightBracket).ok();
229 }
230 _ => {
231 state.bump();
232 }
233 }
234 state.finish_at(cp, PurescriptElementType::Pattern);
235 Ok(())
236 }
237
238 fn parse_type<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), OakError> {
239 let cp = state.checkpoint();
240 while state.not_at_end() && !state.at(PurescriptTokenType::Newline) && !state.at(PurescriptTokenType::Equal) && !state.at(PurescriptTokenType::Pipe) && !state.at(PurescriptTokenType::Where) {
241 state.bump();
242 }
243 state.finish_at(cp, PurescriptElementType::TypeNode);
244 Ok(())
245 }
246}
247
248impl<'config> Parser<PurescriptLanguage> for PurescriptParser<'config> {
249 fn parse<'a, S: Source + ?Sized>(&self, text: &'a S, edits: &[TextEdit], cache: &'a mut impl ParseCache<PurescriptLanguage>) -> ParseOutput<'a, PurescriptLanguage> {
250 let lexer = PurescriptLexer::new(self.config);
251 parse_with_lexer(&lexer, text, edits, cache, |state| {
252 let checkpoint = state.checkpoint();
253
254 while state.not_at_end() {
255 self.parse_item(state)?;
256 }
257
258 Ok(state.finish_at(checkpoint, PurescriptElementType::SourceFile))
259 })
260 }
261}
262
263impl<'config> Pratt<PurescriptLanguage> for PurescriptParser<'config> {
264 fn primary<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> &'a GreenNode<'a, PurescriptLanguage> {
265 let cp = state.checkpoint();
266 match state.peek_kind() {
267 Some(PurescriptTokenType::Identifier) => {
268 state.bump();
269 state.finish_at(cp, PurescriptElementType::IdentifierExpression)
270 }
271 Some(PurescriptTokenType::UpperIdentifier) => {
272 state.bump();
273 state.finish_at(cp, PurescriptElementType::IdentifierExpression)
274 }
275 Some(PurescriptTokenType::IntLiteral) | Some(PurescriptTokenType::NumberLiteral) | Some(PurescriptTokenType::StringLiteral) | Some(PurescriptTokenType::CharLiteral) | Some(PurescriptTokenType::True) | Some(PurescriptTokenType::False) => {
276 state.bump();
277 state.finish_at(cp, PurescriptElementType::LiteralExpression)
278 }
279 Some(PurescriptTokenType::LeftParen) => {
280 state.bump();
281 PrattParser::parse(state, 0, self);
282 state.expect(PurescriptTokenType::RightParen).ok();
283 state.finish_at(cp, PurescriptElementType::Expression)
284 }
285 Some(PurescriptTokenType::LeftBracket) => {
286 state.bump();
287 while state.not_at_end() && !state.at(PurescriptTokenType::RightBracket) {
288 PrattParser::parse(state, 0, self);
289 state.eat(PurescriptTokenType::Comma);
290 }
291 state.expect(PurescriptTokenType::RightBracket).ok();
292 state.finish_at(cp, PurescriptElementType::LiteralExpression)
293 }
294 _ => {
295 state.bump();
296 state.finish_at(cp, PurescriptElementType::Error)
297 }
298 }
299 }
300
301 fn prefix<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> &'a GreenNode<'a, PurescriptLanguage> {
302 let kind = match state.peek_kind() {
303 Some(k) => k,
304 None => return self.primary(state),
305 };
306
307 match kind {
308 PurescriptTokenType::Minus => unary(state, kind, 12, PurescriptElementType::PrefixExpression.into(), |s, p| PrattParser::parse(s, p, self)),
309 _ => self.primary(state),
310 }
311 }
312
313 fn infix<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>, left: &'a GreenNode<'a, PurescriptLanguage>, min_precedence: u8) -> Option<&'a GreenNode<'a, PurescriptLanguage>> {
314 let kind = state.peek_kind()?;
315
316 let (prec, assoc) = match kind {
317 PurescriptTokenType::Dot => (13, Associativity::Left),
318 PurescriptTokenType::Star | PurescriptTokenType::Slash | PurescriptTokenType::Percent => (11, Associativity::Left),
319 PurescriptTokenType::Plus | PurescriptTokenType::Minus => (10, Associativity::Left),
320 PurescriptTokenType::Append => (9, Associativity::Right),
321 PurescriptTokenType::EqualEqual | PurescriptTokenType::NotEqual | PurescriptTokenType::Less | PurescriptTokenType::Greater | PurescriptTokenType::LessEqual | PurescriptTokenType::GreaterEqual => (8, Associativity::Left),
322 PurescriptTokenType::And => (7, Associativity::Right),
323 PurescriptTokenType::Or => (6, Associativity::Right),
324 PurescriptTokenType::Apply => (0, Associativity::Right),
325 _ => return None,
326 };
327
328 if prec < min_precedence {
329 return None;
330 }
331
332 Some(binary(state, left, kind, prec, assoc, PurescriptElementType::InfixExpression.into(), |s, p| PrattParser::parse(s, p, self)))
333 }
334}