Skip to main content

oak_ruby/parser/
mod.rs

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(); // def
62        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(); // class
87        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(); // module
97        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(); // if
107        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(); // while
117        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(); // return
127        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) // 简化处理
145            }
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) // 简化处理
151            }
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}