Skip to main content

oak_haskell/parser/
mod.rs

1pub mod element_type;
2
3use crate::{
4    language::HaskellLanguage,
5    lexer::{HaskellLexer, token_type::HaskellTokenType},
6    parser::element_type::HaskellElementType,
7};
8use oak_core::{
9    GreenNode, OakError, TokenType,
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, HaskellLanguage, S>;
15
16/// A parser for the Haskell language.
17pub struct HaskellParser<'config> {
18    /// Language configuration.
19    pub(crate) config: &'config HaskellLanguage,
20}
21
22impl<'config> HaskellParser<'config> {
23    /// Creates a new Haskell parser with the given configuration.
24    pub fn new(config: &'config HaskellLanguage) -> Self {
25        Self { config }
26    }
27
28    /// Parses a top-level item in a Haskell source file.
29    fn parse_item<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), OakError> {
30        match state.peek_kind() {
31            Some(HaskellTokenType::Module) => {
32                self.parse_module(state);
33            }
34            Some(HaskellTokenType::Import) => {
35                self.parse_import(state);
36            }
37            Some(HaskellTokenType::Data) => {
38                self.parse_data(state);
39            }
40            Some(HaskellTokenType::Type) => {
41                self.parse_type_alias(state);
42            }
43            Some(HaskellTokenType::Identifier) => {
44                self.parse_function(state);
45            }
46            _ => {
47                state.bump();
48            }
49        }
50        Ok(())
51    }
52
53    fn parse_module<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> &'a GreenNode<'a, HaskellLanguage> {
54        let cp = state.checkpoint();
55        state.expect(HaskellTokenType::Module).ok();
56        state.expect(HaskellTokenType::Constructor).ok(); // Module name
57        if state.eat(HaskellTokenType::Where) {
58            // Module body handled by parse loop
59        }
60        state.finish_at(cp, HaskellElementType::ModuleDeclaration)
61    }
62
63    fn parse_import<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> &'a GreenNode<'a, HaskellLanguage> {
64        let cp = state.checkpoint();
65        state.expect(HaskellTokenType::Import).ok();
66        state.eat(HaskellTokenType::Qualified);
67        state.expect(HaskellTokenType::Constructor).ok(); // Module name
68        if state.eat(HaskellTokenType::As) {
69            state.expect(HaskellTokenType::Constructor).ok();
70        }
71        state.finish_at(cp, HaskellElementType::ImportDeclaration)
72    }
73
74    fn parse_data<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> &'a GreenNode<'a, HaskellLanguage> {
75        let cp = state.checkpoint();
76        state.expect(HaskellTokenType::Data).ok();
77        state.expect(HaskellTokenType::Constructor).ok(); // Type name
78        while state.at(HaskellTokenType::Identifier) {
79            state.bump(); // Type params
80        }
81        if state.eat(HaskellTokenType::Assign) {
82            loop {
83                state.expect(HaskellTokenType::Constructor).ok();
84                while state.at(HaskellTokenType::Constructor) || state.at(HaskellTokenType::Identifier) || state.at(HaskellTokenType::LeftParen) {
85                    if state.at(HaskellTokenType::LeftParen) {
86                        state.bump();
87                        while !state.at(HaskellTokenType::RightParen) && state.not_at_end() {
88                            state.bump();
89                        }
90                        state.eat(HaskellTokenType::RightParen);
91                    }
92                    else {
93                        state.bump();
94                    }
95                }
96                if !state.eat(HaskellTokenType::Pipe) {
97                    break;
98                }
99            }
100        }
101        state.finish_at(cp, HaskellElementType::DataDeclaration)
102    }
103
104    fn parse_type_alias<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> &'a GreenNode<'a, HaskellLanguage> {
105        let cp = state.checkpoint();
106        state.expect(HaskellTokenType::Type).ok();
107        state.expect(HaskellTokenType::Constructor).ok();
108        while state.at(HaskellTokenType::Identifier) {
109            state.bump();
110        }
111        state.expect(HaskellTokenType::Assign).ok();
112        // Simplified type parsing
113        while !state.at(HaskellTokenType::Newline) && state.not_at_end() {
114            state.bump();
115        }
116        state.finish_at(cp, HaskellElementType::TypeAliasDeclaration)
117    }
118
119    fn parse_function<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> &'a GreenNode<'a, HaskellLanguage> {
120        let cp = state.checkpoint();
121        state.expect(HaskellTokenType::Identifier).ok();
122        if state.eat(HaskellTokenType::DoubleColon) {
123            // Type signature
124            while !state.at(HaskellTokenType::Newline) && state.not_at_end() {
125                state.bump();
126            }
127            state.finish_at(cp, HaskellElementType::TypeSignature)
128        }
129        else {
130            // Equation
131            while !state.at(HaskellTokenType::Assign) && state.not_at_end() {
132                state.bump(); // Patterns
133            }
134            state.expect(HaskellTokenType::Assign).ok();
135            PrattParser::parse(state, 0, self); // Body
136            state.finish_at(cp, HaskellElementType::Function)
137        }
138    }
139}
140
141impl<'config> Parser<HaskellLanguage> for HaskellParser<'config> {
142    fn parse<'a, S: Source + ?Sized>(&self, text: &'a S, edits: &[TextEdit], cache: &'a mut impl ParseCache<HaskellLanguage>) -> ParseOutput<'a, HaskellLanguage> {
143        let lexer = HaskellLexer::new(&self.config);
144        parse_with_lexer(&lexer, text, edits, cache, |state| {
145            let checkpoint = state.checkpoint();
146
147            while state.not_at_end() {
148                self.parse_item(state)?
149            }
150
151            Ok(state.finish_at(checkpoint, HaskellElementType::Root))
152        })
153    }
154}
155
156impl<'config> Pratt<HaskellLanguage> for HaskellParser<'config> {
157    fn primary<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> &'a GreenNode<'a, HaskellLanguage> {
158        let cp = state.checkpoint();
159        match state.peek_kind() {
160            Some(HaskellTokenType::Identifier) => {
161                state.bump();
162                state.finish_at(cp, HaskellElementType::IdentifierExpression)
163            }
164            Some(HaskellTokenType::Constructor) => {
165                state.bump();
166                state.finish_at(cp, HaskellElementType::IdentifierExpression)
167            }
168            Some(HaskellTokenType::Integer) | Some(HaskellTokenType::Float) => {
169                state.bump();
170                state.finish_at(cp, HaskellElementType::LiteralExpression)
171            }
172            Some(HaskellTokenType::StringLiteral) | Some(HaskellTokenType::CharLiteral) => {
173                state.bump();
174                state.finish_at(cp, HaskellElementType::LiteralExpression)
175            }
176            Some(HaskellTokenType::LeftParen) => {
177                state.bump();
178                PrattParser::parse(state, 0, self);
179                state.expect(HaskellTokenType::RightParen).ok();
180                state.finish_at(cp, HaskellElementType::InfixExpression) // Simplified
181            }
182            _ => {
183                state.bump();
184                state.finish_at(cp, HaskellElementType::Error)
185            }
186        }
187    }
188
189    fn prefix<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> &'a GreenNode<'a, HaskellLanguage> {
190        let kind = match state.peek_kind() {
191            Some(k) => k,
192            None => return self.primary(state),
193        };
194
195        match kind {
196            HaskellTokenType::Minus => unary(state, kind, 9, HaskellElementType::PrefixExpression.into(), |s, p| PrattParser::parse(s, p, self)),
197            _ => self.primary(state),
198        }
199    }
200
201    fn infix<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>, left: &'a GreenNode<'a, HaskellLanguage>, min_precedence: u8) -> Option<&'a GreenNode<'a, HaskellLanguage>> {
202        let kind = state.peek_kind()?;
203
204        let (prec, assoc) = match kind {
205            HaskellTokenType::Dot => (9, Associativity::Right),
206            HaskellTokenType::Star | HaskellTokenType::Slash | HaskellTokenType::Percent => (7, Associativity::Left),
207            HaskellTokenType::Plus | HaskellTokenType::Minus => (6, Associativity::Left),
208            HaskellTokenType::Append => (5, Associativity::Right),
209            HaskellTokenType::Equal | HaskellTokenType::NotEqual | HaskellTokenType::Less | HaskellTokenType::LessEqual | HaskellTokenType::Greater | HaskellTokenType::GreaterEqual => (4, Associativity::None),
210            HaskellTokenType::And => (3, Associativity::Right),
211            HaskellTokenType::Or => (2, Associativity::Right),
212            HaskellTokenType::Dollar => (0, Associativity::Right),
213            _ => return None,
214        };
215
216        if prec < min_precedence {
217            return None;
218        }
219
220        Some(binary(state, left, kind, prec, assoc, HaskellElementType::InfixExpression.into(), |s, p| PrattParser::parse(s, p, self)))
221    }
222}