Skip to main content

oak_ocaml/parser/
mod.rs

1pub mod element_type;
2
3use crate::{
4    language::OCamlLanguage,
5    lexer::{OCamlLexer, token_type::OCamlTokenType},
6    parser::element_type::OCamlElementType,
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
14/// OCaml parser state.
15pub(crate) type State<'a, S> = ParserState<'a, OCamlLanguage, S>;
16
17/// A parser for the OCaml language.
18pub struct OCamlParser<'config> {
19    /// The language configuration.
20    pub language: &'config OCamlLanguage,
21}
22
23impl<'config> OCamlParser<'config> {
24    /// Creates a new OCaml parser.
25    pub fn new(language: &'config OCamlLanguage) -> Self {
26        Self { language }
27    }
28
29    /// Parses a top-level item.
30    fn parse_item<'s, S: Source + ?Sized>(&self, state: &mut State<'s, S>) -> Result<(), OakError> {
31        let kind = state.peek_kind();
32        match kind {
33            Some(OCamlTokenType::Let) => self.parse_let_binding(state),
34            Some(OCamlTokenType::Module) => self.parse_module_def(state),
35            Some(OCamlTokenType::Type) => self.parse_type_definition(state),
36            Some(OCamlTokenType::Open) => {
37                let cp = state.checkpoint();
38                state.bump();
39                while state.not_at_end() && !state.at(OCamlTokenType::Semicolon) {
40                    state.bump();
41                }
42                state.finish_at(cp, OCamlElementType::Expression);
43                Ok(())
44            }
45            _ => self.parse_expression_item(state),
46        }
47    }
48
49    fn parse_expression_item<'s, S: Source + ?Sized>(&self, state: &mut State<'s, S>) -> Result<(), OakError> {
50        let cp = state.checkpoint();
51        PrattParser::parse(state, 0, self);
52        if state.at(OCamlTokenType::Semicolon) {
53            state.bump();
54            if state.at(OCamlTokenType::Semicolon) {
55                state.bump();
56            }
57        }
58        state.finish_at(cp, OCamlElementType::Expression);
59        Ok(())
60    }
61
62    /// Parses a let binding.
63    fn parse_let_binding<'s, S: Source + ?Sized>(&self, state: &mut State<'s, S>) -> Result<(), OakError> {
64        let checkpoint = state.checkpoint();
65        state.bump(); // Let
66        if state.at(OCamlTokenType::Rec) {
67            state.bump(); // Rec
68        }
69        // Simplified: consume identifier and until = or ;;
70        while state.not_at_end() && !state.at(OCamlTokenType::Equal) && !state.at(OCamlTokenType::Semicolon) {
71            state.bump();
72        }
73        if state.at(OCamlTokenType::Equal) {
74            state.bump(); // Equal
75            PrattParser::parse(state, 0, self);
76        }
77        state.finish_at(checkpoint, OCamlElementType::LetBinding);
78        Ok(())
79    }
80
81    /// Parses a module definition.
82    fn parse_module_def<'s, S: Source + ?Sized>(&self, state: &mut State<'s, S>) -> Result<(), OakError> {
83        let checkpoint = state.checkpoint();
84        state.bump(); // Module
85        while state.not_at_end() && !state.at(OCamlTokenType::Equal) && !state.at(OCamlTokenType::Semicolon) {
86            state.bump();
87        }
88        if state.at(OCamlTokenType::Equal) {
89            state.bump(); // Equal
90            while state.not_at_end() && !state.at(OCamlTokenType::Semicolon) {
91                state.bump();
92            }
93        }
94        state.finish_at(checkpoint, OCamlElementType::ModuleDef);
95        Ok(())
96    }
97
98    /// Parses a type definition.
99    fn parse_type_definition<'s, S: Source + ?Sized>(&self, state: &mut State<'s, S>) -> Result<(), OakError> {
100        let checkpoint = state.checkpoint();
101        state.bump(); // Type
102        while state.not_at_end() && !state.at(OCamlTokenType::Semicolon) {
103            state.bump();
104        }
105        state.finish_at(checkpoint, OCamlElementType::TypeDefinition);
106        Ok(())
107    }
108}
109
110impl<'config> Parser<OCamlLanguage> for OCamlParser<'config> {
111    fn parse<'a, S: Source + ?Sized>(&self, text: &'a S, edits: &[TextEdit], cache: &'a mut impl ParseCache<OCamlLanguage>) -> ParseOutput<'a, OCamlLanguage> {
112        let lexer = OCamlLexer::new(self.language);
113        parse_with_lexer(&lexer, text, edits, cache, |state| {
114            let checkpoint = state.checkpoint();
115
116            while state.not_at_end() {
117                self.parse_item(state)?;
118            }
119
120            Ok(state.finish_at(checkpoint, OCamlElementType::Root))
121        })
122    }
123}
124
125impl<'config> Pratt<OCamlLanguage> for OCamlParser<'config> {
126    fn primary<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> &'a GreenNode<'a, OCamlLanguage> {
127        let cp = state.checkpoint();
128        match state.peek_kind() {
129            Some(OCamlTokenType::Identifier) => {
130                state.bump();
131                state.finish_at(cp, OCamlElementType::IdentifierExpr)
132            }
133            Some(OCamlTokenType::IntegerLiteral) | Some(OCamlTokenType::FloatLiteral) | Some(OCamlTokenType::StringLiteral) | Some(OCamlTokenType::CharLiteral) | Some(OCamlTokenType::True) | Some(OCamlTokenType::False) => {
134                state.bump();
135                state.finish_at(cp, OCamlElementType::LiteralExpr)
136            }
137            Some(OCamlTokenType::LeftParen) => {
138                state.bump();
139                PrattParser::parse(state, 0, self);
140                state.expect(OCamlTokenType::RightParen).ok();
141                state.finish_at(cp, OCamlElementType::Expression)
142            }
143            _ => {
144                state.bump();
145                state.finish_at(cp, OCamlElementType::Error)
146            }
147        }
148    }
149
150    fn prefix<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> &'a GreenNode<'a, OCamlLanguage> {
151        let kind = match state.peek_kind() {
152            Some(k) => k,
153            None => return self.primary(state),
154        };
155
156        match kind {
157            OCamlTokenType::Minus | OCamlTokenType::MinusDot | OCamlTokenType::Tilde => unary(state, kind, 12, OCamlElementType::UnaryExpr.into(), |s, p| PrattParser::parse(s, p, self)),
158            _ => self.primary(state),
159        }
160    }
161
162    fn infix<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>, left: &'a GreenNode<'a, OCamlLanguage>, min_precedence: u8) -> Option<&'a GreenNode<'a, OCamlLanguage>> {
163        let kind = state.peek_kind()?;
164
165        let (prec, assoc) = match kind {
166            OCamlTokenType::Dot => (13, Associativity::Left),
167            OCamlTokenType::Star | OCamlTokenType::Slash | OCamlTokenType::Percent => (11, Associativity::Left),
168            OCamlTokenType::Plus | OCamlTokenType::Minus => (10, Associativity::Left),
169            OCamlTokenType::At => (9, Associativity::Right),
170            OCamlTokenType::Equal | OCamlTokenType::NotEqual | OCamlTokenType::Less | OCamlTokenType::Greater | OCamlTokenType::LessEqual | OCamlTokenType::GreaterEqual => (8, Associativity::Left),
171            OCamlTokenType::And => (7, Associativity::Right),
172            OCamlTokenType::Or => (6, Associativity::Right),
173            OCamlTokenType::Semicolon => (5, Associativity::Right),
174            _ => return None,
175        };
176
177        if prec < min_precedence {
178            return None;
179        }
180
181        Some(binary(state, left, kind, prec, assoc, OCamlElementType::BinaryExpr.into(), |s, p| PrattParser::parse(s, p, self)))
182    }
183}