Skip to main content

oak_purescript/parser/
mod.rs

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
16/// PureScript parser implementation.
17pub struct PurescriptParser<'config> {
18    pub(crate) config: &'config PurescriptLanguage,
19}
20
21impl<'config> PurescriptParser<'config> {
22    /// Creates a new `PurescriptParser`.
23    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(); // ident
173                state.bump(); // ::
174                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}