1use oak_core::TokenType;
2pub mod element_type;
3
4use crate::{
5 language::RubyLanguage,
6 lexer::{RubyLexer, token_type::RubyTokenType},
7};
8use oak_core::{
9 GreenNode, OakError, TextEdit,
10 parser::{
11 ParseCache, ParseOutput, Parser, ParserState, parse_with_lexer,
12 pratt::{Associativity, Pratt, PrattParser, binary, unary},
13 },
14 source::Source,
15};
16
17pub(crate) type State<'a, S> = ParserState<'a, RubyLanguage, S>;
18
19pub struct RubyParser<'config> {
20 pub(crate) config: &'config RubyLanguage,
21}
22
23impl<'config> RubyParser<'config> {
24 pub fn new(config: &'config RubyLanguage) -> Self {
25 Self { config }
26 }
27
28 pub(crate) fn parse_root_internal<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<&'a GreenNode<'a, RubyLanguage>, OakError> {
29 let cp = state.checkpoint();
30 while state.not_at_end() {
31 if state.peek_kind().map(|k| k.is_ignored()).unwrap_or(false) {
32 state.bump();
33 continue;
34 }
35 let _ = self.parse_statement(state);
36 }
37 Ok(state.finish_at(cp, crate::parser::element_type::RubyElementType::Root))
38 }
39
40 fn parse_statement<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), OakError> {
41 use crate::lexer::token_type::RubyTokenType::*;
42 match state.peek_kind() {
43 Some(Def) => self.parse_method_def(state)?,
44 Some(Class) => self.parse_class_def(state)?,
45 Some(Module) => self.parse_module_def(state)?,
46 Some(If) => self.parse_if_stmt(state)?,
47 Some(While) => self.parse_while_stmt(state)?,
48 Some(Return) => self.parse_return_stmt(state)?,
49 _ => {
50 PrattParser::parse(state, 0, self);
51 state.eat(Semicolon);
52 state.eat(Newline);
53 }
54 }
55 Ok(())
56 }
57
58 fn parse_method_def<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), OakError> {
59 use crate::lexer::token_type::RubyTokenType::*;
60 let cp = state.checkpoint();
61 state.bump(); state.expect(Identifier).ok();
63 if state.eat(LeftParen) {
64 while state.not_at_end() && !state.at(RightParen) {
65 state.advance()
66 }
67 let _ = state.expect(RightParen);
68 }
69 self.parse_body(state)?;
70 state.finish_at(cp, crate::parser::element_type::RubyElementType::MethodDefinition);
71 Ok(())
72 }
73
74 fn parse_body<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), OakError> {
75 use crate::lexer::token_type::RubyTokenType::*;
76 while state.not_at_end() && !state.at(End) && !state.at(Else) && !state.at(Elsif) && !state.at(Rescue) && !state.at(Ensure) {
77 self.parse_statement(state)?
78 }
79 state.eat(End);
80 Ok(())
81 }
82
83 fn parse_class_def<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), OakError> {
84 use crate::lexer::token_type::RubyTokenType::*;
85 let cp = state.checkpoint();
86 state.bump(); state.expect(Constant).ok();
88 self.parse_body(state)?;
89 state.finish_at(cp, crate::parser::element_type::RubyElementType::ClassDefinition);
90 Ok(())
91 }
92
93 fn parse_module_def<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), OakError> {
94 use crate::lexer::token_type::RubyTokenType::*;
95 let cp = state.checkpoint();
96 state.bump(); state.expect(Constant).ok();
98 self.parse_body(state)?;
99 state.finish_at(cp, crate::parser::element_type::RubyElementType::ModuleDefinition);
100 Ok(())
101 }
102
103 fn parse_if_stmt<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), OakError> {
104 use crate::lexer::token_type::RubyTokenType::*;
105 let cp = state.checkpoint();
106 state.bump(); PrattParser::parse(state, 0, self);
108 self.parse_body(state)?;
109 state.finish_at(cp, crate::parser::element_type::RubyElementType::IfStatement);
110 Ok(())
111 }
112
113 fn parse_while_stmt<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), OakError> {
114 use crate::lexer::token_type::RubyTokenType::*;
115 let cp = state.checkpoint();
116 state.bump(); PrattParser::parse(state, 0, self);
118 self.parse_body(state)?;
119 state.finish_at(cp, crate::parser::element_type::RubyElementType::WhileStatement);
120 Ok(())
121 }
122
123 fn parse_return_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(); PrattParser::parse(state, 0, self);
128 state.finish_at(cp, crate::parser::element_type::RubyElementType::ReturnStatement);
129 Ok(())
130 }
131}
132
133impl<'config> Pratt<RubyLanguage> for RubyParser<'config> {
134 fn primary<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> &'a GreenNode<'a, RubyLanguage> {
135 use crate::lexer::token_type::RubyTokenType::*;
136 let cp = state.checkpoint();
137 match state.peek_kind() {
138 Some(Identifier) | Some(Constant) | Some(GlobalVariable) | Some(InstanceVariable) | Some(ClassVariable) => {
139 state.bump();
140 state.finish_at(cp, crate::parser::element_type::RubyElementType::Identifier)
141 }
142 Some(IntegerLiteral) | Some(FloatLiteral) | Some(StringLiteral) | Some(True) | Some(False) | Some(Nil) | Some(Self_) => {
143 state.bump();
144 state.finish_at(cp, crate::parser::element_type::RubyElementType::LiteralExpression) }
146 Some(LeftParen) => {
147 state.bump();
148 PrattParser::parse(state, 0, self);
149 state.expect(RightParen).ok();
150 state.finish_at(cp, crate::parser::element_type::RubyElementType::ParenExpression) }
152 _ => {
153 state.bump();
154 state.finish_at(cp, crate::parser::element_type::RubyElementType::Error)
155 }
156 }
157 }
158
159 fn prefix<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> &'a GreenNode<'a, RubyLanguage> {
160 use crate::lexer::token_type::RubyTokenType::*;
161 match state.peek_kind() {
162 Some(kind @ (Plus | Minus | Not | Tilde)) => {
163 state.bump();
164 unary(state, kind, 13, crate::parser::element_type::RubyElementType::UnaryExpression, |st, p| PrattParser::parse(st, p, self))
165 }
166 _ => self.primary(state),
167 }
168 }
169
170 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>> {
171 use crate::lexer::token_type::RubyTokenType::*;
172 let kind = state.peek_kind()?;
173
174 let (prec, assoc) = match kind {
175 Power => (30, Associativity::Right),
176 Multiply | Divide | Modulo => (20, Associativity::Left),
177 Plus | Minus => (10, Associativity::Left),
178 EqualEqual | NotEqual | Less | Greater | LessEqual | GreaterEqual => (5, Associativity::Left),
179 AndAnd => (2, Associativity::Left),
180 OrOr => (1, Associativity::Left),
181 _ => return None,
182 };
183
184 if prec < min_precedence {
185 return None;
186 }
187
188 Some(binary(state, left, kind, prec, assoc, crate::parser::element_type::RubyElementType::BinaryExpression, |s, p| PrattParser::parse(s, p, self)))
189 }
190}
191
192impl<'config> Parser<RubyLanguage> for RubyParser<'config> {
193 fn parse<'a, S: Source + ?Sized>(&self, text: &'a S, edits: &[TextEdit], cache: &'a mut impl ParseCache<RubyLanguage>) -> ParseOutput<'a, RubyLanguage> {
194 let lexer = RubyLexer::new(&self.config);
195 parse_with_lexer(&lexer, text, edits, cache, |state| self.parse_root_internal(state))
196 }
197}