Skip to main content

oak_perl/parser/
mod.rs

1/// Element type definitions for Perl.
2pub mod element_type;
3
4use crate::language::PerlLanguage;
5use oak_core::{
6    OakError,
7    parser::{ParseCache, ParseOutput, Parser, ParserState, parse_with_lexer},
8    source::{Source, TextEdit},
9};
10
11pub(crate) type State<'a, S> = ParserState<'a, PerlLanguage, S>;
12
13/// Parser for the Perl language.
14///
15/// This parser converts a stream of [`crate::lexer::PerlTokenType`] tokens into a green tree.
16pub struct PerlParser<'config> {
17    /// The Perl language configuration.
18    pub(crate) config: &'config PerlLanguage,
19}
20
21impl<'config> PerlParser<'config> {
22    /// Creates a new `PerlParser` with the given language configuration.
23    pub fn new(config: &'config PerlLanguage) -> Self {
24        Self { config }
25    }
26
27    /// Parses a single statement.
28    pub(crate) fn parse_statement<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), OakError> {
29        use crate::lexer::token_type::PerlTokenType::*;
30        self.skip_trivia(state);
31
32        if !state.not_at_end() {
33            return Ok(());
34        }
35
36        match state.peek_kind() {
37            Some(Sub) => self.parse_sub_declaration(state),
38            Some(Package) => self.parse_package_declaration(state),
39            Some(Use) => self.parse_use_statement(state),
40            Some(If) => self.parse_if_statement(state),
41            Some(Unless) => self.parse_unless_statement(state),
42            Some(While) => self.parse_while_statement(state),
43            Some(Until) => self.parse_until_statement(state),
44            Some(For) | Some(Foreach) => self.parse_for_statement(state),
45            Some(Do) => self.parse_do_statement(state),
46            Some(My) | Some(Our) | Some(Local) => self.parse_variable_declaration(state),
47            _ => self.parse_expression_statement(state),
48        }
49    }
50
51    fn skip_trivia<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) {
52        use crate::lexer::token_type::PerlTokenType::*;
53        while state.at(Whitespace) || state.at(Newline) || state.at(Comment) {
54            state.bump();
55        }
56    }
57
58    fn parse_sub_declaration<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), OakError> {
59        use crate::lexer::token_type::PerlTokenType::*;
60        let cp = state.checkpoint();
61        state.expect(Sub)?;
62        self.skip_trivia(state);
63        state.expect(Identifier).ok();
64        self.skip_trivia(state);
65        if state.at(LeftBrace) {
66            self.parse_block(state)?;
67        }
68        else {
69            state.expect(Semicolon).ok();
70        }
71        state.finish_at(cp, element_type::PerlElementType::SubroutineDeclaration);
72        Ok(())
73    }
74
75    fn parse_package_declaration<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), OakError> {
76        use crate::lexer::token_type::PerlTokenType::*;
77        let cp = state.checkpoint();
78        state.expect(Package)?;
79        self.skip_trivia(state);
80        state.expect(Identifier)?;
81        self.skip_trivia(state);
82        state.expect(Semicolon)?;
83        state.finish_at(cp, element_type::PerlElementType::PackageDeclaration);
84        Ok(())
85    }
86
87    fn parse_use_statement<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), OakError> {
88        use crate::lexer::token_type::PerlTokenType::*;
89        let cp = state.checkpoint();
90        state.expect(Use)?;
91        self.skip_trivia(state);
92        state.expect(Identifier)?;
93        self.skip_trivia(state);
94        while state.not_at_end() && !state.at(Semicolon) {
95            state.bump();
96        }
97        state.expect(Semicolon).ok();
98        state.finish_at(cp, element_type::PerlElementType::UseStatement);
99        Ok(())
100    }
101
102    fn parse_if_statement<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), OakError> {
103        use crate::lexer::token_type::PerlTokenType::*;
104        let cp = state.checkpoint();
105        state.expect(If)?;
106        self.skip_trivia(state);
107        state.expect(LeftParen)?;
108        while state.not_at_end() && !state.at(RightParen) {
109            state.bump();
110        }
111        state.expect(RightParen).ok();
112        self.skip_trivia(state);
113        self.parse_block(state)?;
114
115        self.skip_trivia(state);
116        while state.at(Elsif) {
117            state.bump();
118            self.skip_trivia(state);
119            state.expect(LeftParen)?;
120            while state.not_at_end() && !state.at(RightParen) {
121                state.bump();
122            }
123            state.expect(RightParen).ok();
124            self.skip_trivia(state);
125            self.parse_block(state)?;
126            self.skip_trivia(state);
127        }
128
129        if state.at(Else) {
130            state.bump();
131            self.skip_trivia(state);
132            self.parse_block(state)?;
133        }
134
135        state.finish_at(cp, element_type::PerlElementType::IfStatement);
136        Ok(())
137    }
138
139    fn parse_unless_statement<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), OakError> {
140        use crate::lexer::token_type::PerlTokenType::*;
141        let cp = state.checkpoint();
142        state.expect(Unless)?;
143        self.skip_trivia(state);
144        state.expect(LeftParen)?;
145        while state.not_at_end() && !state.at(RightParen) {
146            state.bump();
147        }
148        state.expect(RightParen).ok();
149        self.skip_trivia(state);
150        self.parse_block(state)?;
151        state.finish_at(cp, element_type::PerlElementType::UnlessStatement);
152        Ok(())
153    }
154
155    fn parse_while_statement<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), OakError> {
156        use crate::lexer::token_type::PerlTokenType::*;
157        let cp = state.checkpoint();
158        state.expect(While)?;
159        self.skip_trivia(state);
160        state.expect(LeftParen)?;
161        while state.not_at_end() && !state.at(RightParen) {
162            state.bump();
163        }
164        state.expect(RightParen).ok();
165        self.skip_trivia(state);
166        self.parse_block(state)?;
167        state.finish_at(cp, element_type::PerlElementType::WhileStatement);
168        Ok(())
169    }
170
171    fn parse_until_statement<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), OakError> {
172        use crate::lexer::token_type::PerlTokenType::*;
173        let cp = state.checkpoint();
174        state.expect(Until)?;
175        self.skip_trivia(state);
176        state.expect(LeftParen)?;
177        while state.not_at_end() && !state.at(RightParen) {
178            state.bump();
179        }
180        state.expect(RightParen).ok();
181        self.skip_trivia(state);
182        self.parse_block(state)?;
183        state.finish_at(cp, element_type::PerlElementType::UntilStatement);
184        Ok(())
185    }
186
187    fn parse_for_statement<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), OakError> {
188        use crate::lexer::token_type::PerlTokenType::*;
189        let cp = state.checkpoint();
190        if state.at(For) {
191            state.bump();
192        }
193        else {
194            state.expect(Foreach)?;
195        }
196        self.skip_trivia(state);
197        if state.at(LeftParen) {
198            state.bump();
199            while state.not_at_end() && !state.at(RightParen) {
200                state.bump();
201            }
202            state.expect(RightParen).ok();
203        }
204        self.skip_trivia(state);
205        self.parse_block(state)?;
206        state.finish_at(cp, element_type::PerlElementType::ForStatement);
207        Ok(())
208    }
209
210    fn parse_do_statement<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), OakError> {
211        use crate::lexer::token_type::PerlTokenType::*;
212        let cp = state.checkpoint();
213        state.expect(Do)?;
214        self.skip_trivia(state);
215        if state.at(LeftBrace) {
216            self.parse_block(state)?;
217        }
218        else {
219            // do sub() or do "file"
220            while state.not_at_end() && !state.at(Semicolon) {
221                state.bump();
222            }
223        }
224        state.expect(Semicolon).ok();
225        state.finish_at(cp, element_type::PerlElementType::DoStatement);
226        Ok(())
227    }
228
229    fn parse_variable_declaration<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), OakError> {
230        use crate::lexer::token_type::PerlTokenType::*;
231        let cp = state.checkpoint();
232        state.bump(); // my, our, local
233        self.skip_trivia(state);
234        while state.not_at_end() && !state.at(Semicolon) {
235            state.bump();
236        }
237        state.expect(Semicolon).ok();
238        state.finish_at(cp, element_type::PerlElementType::VariableDeclaration);
239        Ok(())
240    }
241
242    fn parse_expression_statement<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), OakError> {
243        use crate::lexer::token_type::PerlTokenType::*;
244        let cp = state.checkpoint();
245        while state.not_at_end() && !state.at(Semicolon) {
246            state.bump();
247        }
248        state.expect(Semicolon).ok();
249        state.finish_at(cp, element_type::PerlElementType::Statement);
250        Ok(())
251    }
252
253    fn parse_block<'a, S: Source + ?Sized>(&self, state: &mut State<'a, S>) -> Result<(), OakError> {
254        use crate::lexer::token_type::PerlTokenType::*;
255        let cp = state.checkpoint();
256        state.expect(LeftBrace)?;
257        while state.not_at_end() && !state.at(RightBrace) {
258            self.parse_statement(state)?;
259        }
260        state.expect(RightBrace).ok();
261        state.finish_at(cp, element_type::PerlElementType::Block);
262        Ok(())
263    }
264}
265
266impl<'config> Parser<PerlLanguage> for PerlParser<'config> {
267    fn parse<'a, S: Source + ?Sized>(&self, text: &'a S, edits: &[TextEdit], cache: &'a mut impl ParseCache<PerlLanguage>) -> ParseOutput<'a, PerlLanguage> {
268        let lexer = crate::lexer::PerlLexer::new(&self.config);
269        parse_with_lexer(&lexer, text, edits, cache, |state| {
270            let checkpoint = state.checkpoint();
271            while state.not_at_end() {
272                if self.parse_statement(state).is_err() {
273                    break;
274                }
275            }
276            Ok(state.finish_at(checkpoint, element_type::PerlElementType::Root))
277        })
278    }
279}