Skip to main content

oak_ocaml/parser/
mod.rs

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