1use oak_core::TokenType;
2pub mod element_type;
4
5use crate::{
6 language::RubyLanguage,
7 lexer::{RubyLexer, token_type::RubyTokenType},
8};
9use oak_core::{
10 GreenNode, OakError, TextEdit,
11 parser::{
12 ParseCache, ParseOutput, Parser, ParserState, parse_with_lexer,
13 pratt::{Associativity, Pratt, PrattParser, binary, unary},
14 },
15 source::Source,
16};
17
18pub(crate) type State<'a, S> = ParserState<'a, RubyLanguage, S>;
19
20pub struct RubyParser<'config> {
22 pub(crate) config: &'config RubyLanguage,
23}
24
25impl<'config> RubyParser<'config> {
26 pub fn new(config: &'config RubyLanguage) -> Self {
28 Self { config }
29 }
30
31 fn parse_statement<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), OakError> {
32 use crate::lexer::token_type::RubyTokenType::*;
33 match state.peek_kind() {
34 Some(Def) => self.parse_method_def(state)?,
35 Some(Class) => self.parse_class_def(state)?,
36 Some(Module) => self.parse_module_def(state)?,
37 Some(If) => self.parse_if_stmt(state)?,
38 Some(Unless) => self.parse_unless_stmt(state)?,
39 Some(While) => self.parse_while_stmt(state)?,
40 Some(Until) => self.parse_until_stmt(state)?,
41 Some(For) => self.parse_for_stmt(state)?,
42 Some(Case) => self.parse_case_stmt(state)?,
43 Some(Begin) => self.parse_begin_stmt(state)?,
44 Some(Return) => self.parse_return_stmt(state)?,
45 _ => {
46 PrattParser::parse(state, 0, self);
47 state.eat(Semicolon);
48 state.eat(Newline);
49 }
50 }
51 Ok(())
52 }
53
54 fn parse_unless_stmt<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), OakError> {
55 use crate::lexer::token_type::RubyTokenType::*;
56 let cp = state.checkpoint();
57 state.bump(); PrattParser::parse(state, 0, self);
59 self.parse_body(state)?;
60 state.finish_at(cp, crate::parser::element_type::RubyElementType::UnlessStatement);
61 Ok(())
62 }
63
64 fn parse_until_stmt<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), OakError> {
65 use crate::lexer::token_type::RubyTokenType::*;
66 let cp = state.checkpoint();
67 state.bump(); PrattParser::parse(state, 0, self);
69 self.parse_body(state)?;
70 state.finish_at(cp, crate::parser::element_type::RubyElementType::UntilStatement);
71 Ok(())
72 }
73
74 fn parse_for_stmt<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), OakError> {
75 use crate::lexer::token_type::RubyTokenType::*;
76 let cp = state.checkpoint();
77 state.bump(); state.expect(Identifier).ok();
79 state.expect(In).ok();
80 PrattParser::parse(state, 0, self);
81 self.parse_body(state)?;
82 state.finish_at(cp, crate::parser::element_type::RubyElementType::ForStatement);
83 Ok(())
84 }
85
86 fn parse_case_stmt<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), OakError> {
87 use crate::lexer::token_type::RubyTokenType::*;
88 let cp = state.checkpoint();
89 state.bump(); if !state.at(When) {
91 PrattParser::parse(state, 0, self);
92 }
93
94 while state.at(When) {
95 let when_cp = state.checkpoint();
96 state.bump(); PrattParser::parse(state, 0, self);
98 while state.eat(Comma) {
99 PrattParser::parse(state, 0, self);
100 }
101 state.eat(Then);
102 self.parse_case_body(state)?;
103 state.finish_at(when_cp, crate::parser::element_type::RubyElementType::WhenClause);
104 }
105
106 if state.eat(Else) {
107 self.parse_case_body(state)?;
108 }
109
110 state.expect(End).ok();
111 state.finish_at(cp, crate::parser::element_type::RubyElementType::CaseStatement);
112 Ok(())
113 }
114
115 fn parse_case_body<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), OakError> {
116 use crate::lexer::token_type::RubyTokenType::*;
117 while state.not_at_end() && !state.at(End) && !state.at(When) && !state.at(Else) {
118 self.parse_statement(state)?
119 }
120 Ok(())
121 }
122
123 fn parse_begin_stmt<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), OakError> {
124 use crate::lexer::token_type::RubyTokenType::*;
125 let cp = state.checkpoint();
126 state.bump(); while state.not_at_end() && !state.at(End) && !state.at(Rescue) && !state.at(Ensure) && !state.at(Else) {
129 self.parse_statement(state)?
130 }
131
132 while state.at(Rescue) {
133 let rescue_cp = state.checkpoint();
134 state.bump(); if !state.at(Then) && !state.at(Newline) && !state.at(Semicolon) {
136 PrattParser::parse(state, 0, self); if state.at(EqualGreater) {
138 state.bump();
139 state.expect(Identifier).ok();
140 }
141 }
142 state.eat(Then);
143 while state.not_at_end() && !state.at(End) && !state.at(Rescue) && !state.at(Ensure) && !state.at(Else) {
144 self.parse_statement(state)?
145 }
146 state.finish_at(rescue_cp, crate::parser::element_type::RubyElementType::RescueClause);
147 }
148
149 if state.eat(Else) {
150 while state.not_at_end() && !state.at(End) && !state.at(Ensure) {
151 self.parse_statement(state)?
152 }
153 }
154
155 if state.at(Ensure) {
156 let ensure_cp = state.checkpoint();
157 state.bump(); while state.not_at_end() && !state.at(End) {
159 self.parse_statement(state)?
160 }
161 state.finish_at(ensure_cp, crate::parser::element_type::RubyElementType::EnsureClause);
162 }
163
164 state.expect(End).ok();
165 state.finish_at(cp, crate::parser::element_type::RubyElementType::BeginStatement);
166 Ok(())
167 }
168
169 fn parse_method_def<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), OakError> {
170 use crate::lexer::token_type::RubyTokenType::*;
171 let cp = state.checkpoint();
172 state.bump(); state.expect(Identifier).ok();
174 if state.eat(LeftParen) {
175 while state.not_at_end() && !state.at(RightParen) {
176 state.advance()
177 }
178 let _ = state.expect(RightParen);
179 }
180 self.parse_body(state)?;
181 state.finish_at(cp, crate::parser::element_type::RubyElementType::MethodDefinition);
182 Ok(())
183 }
184
185 fn parse_body<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), OakError> {
186 use crate::lexer::token_type::RubyTokenType::*;
187 while state.not_at_end() && !state.at(End) && !state.at(Else) && !state.at(Elsif) && !state.at(Rescue) && !state.at(Ensure) {
188 self.parse_statement(state)?
189 }
190 state.eat(End);
191 Ok(())
192 }
193
194 fn parse_class_def<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), OakError> {
195 use crate::lexer::token_type::RubyTokenType::*;
196 let cp = state.checkpoint();
197 state.bump(); state.expect(Constant).ok();
199 self.parse_body(state)?;
200 state.finish_at(cp, crate::parser::element_type::RubyElementType::ClassDefinition);
201 Ok(())
202 }
203
204 fn parse_module_def<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), OakError> {
205 use crate::lexer::token_type::RubyTokenType::*;
206 let cp = state.checkpoint();
207 state.bump(); state.expect(Constant).ok();
209 self.parse_body(state)?;
210 state.finish_at(cp, crate::parser::element_type::RubyElementType::ModuleDefinition);
211 Ok(())
212 }
213
214 fn parse_if_stmt<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), OakError> {
215 use crate::lexer::token_type::RubyTokenType::*;
216 let cp = state.checkpoint();
217 state.bump(); PrattParser::parse(state, 0, self);
219 self.parse_body(state)?;
220 state.finish_at(cp, crate::parser::element_type::RubyElementType::IfStatement);
221 Ok(())
222 }
223
224 fn parse_while_stmt<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), OakError> {
225 use crate::lexer::token_type::RubyTokenType::*;
226 let cp = state.checkpoint();
227 state.bump(); PrattParser::parse(state, 0, self);
229 self.parse_body(state)?;
230 state.finish_at(cp, crate::parser::element_type::RubyElementType::WhileStatement);
231 Ok(())
232 }
233
234 fn parse_return_stmt<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), OakError> {
235 use crate::lexer::token_type::RubyTokenType::*;
236 let cp = state.checkpoint();
237 state.bump(); PrattParser::parse(state, 0, self);
239 state.finish_at(cp, crate::parser::element_type::RubyElementType::ReturnStatement);
240 Ok(())
241 }
242}
243
244impl<'config> Pratt<RubyLanguage> for RubyParser<'config> {
245 fn primary<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> &'a GreenNode<'a, RubyLanguage> {
246 use crate::lexer::token_type::RubyTokenType::*;
247 let cp = state.checkpoint();
248 match state.peek_kind() {
249 Some(Identifier) | Some(Constant) | Some(GlobalVariable) | Some(InstanceVariable) | Some(ClassVariable) => {
250 state.bump();
251 state.finish_at(cp, crate::parser::element_type::RubyElementType::Identifier)
252 }
253 Some(IntegerLiteral) | Some(FloatLiteral) | Some(StringLiteral) | Some(True) | Some(False) | Some(Nil) | Some(Self_) => {
254 state.bump();
255 state.finish_at(cp, crate::parser::element_type::RubyElementType::LiteralExpression) }
257 Some(LeftParen) => {
258 state.bump();
259 PrattParser::parse(state, 0, self);
260 state.expect(RightParen).ok();
261 state.finish_at(cp, crate::parser::element_type::RubyElementType::ParenExpression) }
263 _ => {
264 state.bump();
265 state.finish_at(cp, crate::parser::element_type::RubyElementType::Error)
266 }
267 }
268 }
269
270 fn prefix<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> &'a GreenNode<'a, RubyLanguage> {
271 use crate::lexer::token_type::RubyTokenType::*;
272 match state.peek_kind() {
273 Some(kind @ (Plus | Minus | Not | Tilde)) => {
274 state.bump();
275 unary(state, kind, 13, crate::parser::element_type::RubyElementType::UnaryExpression, |st, p| PrattParser::parse(st, p, self))
276 }
277 _ => self.primary(state),
278 }
279 }
280
281 fn infix<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>, left: &'a GreenNode<'a, RubyLanguage>, min_precedence: u8) -> Option<&'a GreenNode<'a, RubyLanguage>> {
282 use crate::lexer::token_type::RubyTokenType::*;
283 let kind = state.peek_kind()?;
284
285 let (prec, assoc) = match kind {
286 Power => (30, Associativity::Right),
287 Multiply | Divide | Modulo => (20, Associativity::Left),
288 Plus | Minus => (10, Associativity::Left),
289 EqualEqual | NotEqual | Less | Greater | LessEqual | GreaterEqual => (5, Associativity::Left),
290 AndAnd => (2, Associativity::Left),
291 OrOr => (1, Associativity::Left),
292 _ => return None,
293 };
294
295 if prec < min_precedence {
296 return None;
297 }
298
299 Some(binary(state, left, kind, prec, assoc, crate::parser::element_type::RubyElementType::BinaryExpression, |s, p| PrattParser::parse(s, p, self)))
300 }
301}
302
303impl<'config> Parser<RubyLanguage> for RubyParser<'config> {
304 fn parse<'a, S: Source + ?Sized>(&self, text: &'a S, edits: &[TextEdit], cache: &'a mut impl ParseCache<RubyLanguage>) -> ParseOutput<'a, RubyLanguage> {
305 let lexer = RubyLexer::new(&self.config);
306 parse_with_lexer(&lexer, text, edits, cache, |state| {
307 let cp = state.checkpoint();
308 while state.not_at_end() {
309 if state.peek_kind().map(|k| k.is_ignored()).unwrap_or(false) {
310 state.bump();
311 continue;
312 }
313 let _ = self.parse_statement(state);
314 }
315 Ok(state.finish_at(cp, crate::parser::element_type::RubyElementType::Root))
316 })
317 }
318}