1pub mod element_type;
3
4use crate::{language::PowerShellLanguage, lexer::token_type::PowerShellTokenType, parser::element_type::PowerShellElementType};
5use oak_core::{
6 parser::{ParseCache, ParseOutput, Parser, ParserState, parse_with_lexer},
7 source::{Source, TextEdit},
8};
9
10#[derive(Debug)]
12pub struct PowerShellParser<'a> {
13 pub config: &'a PowerShellLanguage,
15}
16
17impl<'a> PowerShellParser<'a> {
18 pub fn new(config: &'a PowerShellLanguage) -> Self {
20 Self { config }
21 }
22
23 fn parse_program<'b, S: Source + ?Sized>(&self, state: &mut ParserState<'b, PowerShellLanguage, S>) {
24 while state.not_at_end() {
25 let kind = state.peek_kind();
26 match kind {
27 Some(PowerShellTokenType::Function) => self.parse_function(state),
28 Some(PowerShellTokenType::Class) => self.parse_class(state),
29 Some(PowerShellTokenType::If) => self.parse_if(state),
30 Some(PowerShellTokenType::While) => self.parse_while(state),
31 Some(PowerShellTokenType::For) => self.parse_for(state),
32 Some(PowerShellTokenType::ForEach) => self.parse_foreach(state),
33 Some(PowerShellTokenType::Try) => self.parse_try(state),
34 Some(PowerShellTokenType::Newline) | Some(PowerShellTokenType::Semicolon) | Some(PowerShellTokenType::Whitespace) => {
35 state.bump();
36 }
37 _ => self.parse_statement(state),
38 }
39 }
40 }
41
42 fn parse_function<'b, S: Source + ?Sized>(&self, state: &mut ParserState<'b, PowerShellLanguage, S>) {
43 let checkpoint = state.checkpoint();
44 state.expect(PowerShellTokenType::Function).ok();
45 state.expect(PowerShellTokenType::Identifier).ok();
46 self.skip_trivia(state);
47 if state.at(PowerShellTokenType::LeftBrace) {
48 self.parse_block(state);
49 }
50 state.finish_at(checkpoint, PowerShellElementType::FunctionDef);
51 }
52
53 fn parse_class<'b, S: Source + ?Sized>(&self, state: &mut ParserState<'b, PowerShellLanguage, S>) {
54 let checkpoint = state.checkpoint();
55 state.expect(PowerShellTokenType::Class).ok();
56 state.expect(PowerShellTokenType::Identifier).ok();
57 self.skip_trivia(state);
58 if state.at(PowerShellTokenType::LeftBrace) {
59 self.parse_block(state);
60 }
61 state.finish_at(checkpoint, PowerShellElementType::ClassDef);
62 }
63
64 fn parse_if<'b, S: Source + ?Sized>(&self, state: &mut ParserState<'b, PowerShellLanguage, S>) {
65 let checkpoint = state.checkpoint();
66 state.expect(PowerShellTokenType::If).ok();
67 self.skip_trivia(state);
68 state.expect(PowerShellTokenType::LeftParen).ok();
69 while !state.at(PowerShellTokenType::RightParen) && state.not_at_end() {
70 state.bump();
71 }
72 state.expect(PowerShellTokenType::RightParen).ok();
73 self.skip_trivia(state);
74 self.parse_block(state);
75
76 loop {
77 self.skip_trivia(state);
78 if state.at(PowerShellTokenType::ElseIf) {
79 state.bump();
80 self.skip_trivia(state);
81 state.expect(PowerShellTokenType::LeftParen).ok();
82 while !state.at(PowerShellTokenType::RightParen) && state.not_at_end() {
83 state.bump();
84 }
85 state.expect(PowerShellTokenType::RightParen).ok();
86 self.skip_trivia(state);
87 self.parse_block(state);
88 }
89 else {
90 break;
91 }
92 }
93
94 self.skip_trivia(state);
95 if state.at(PowerShellTokenType::Else) {
96 state.bump();
97 self.skip_trivia(state);
98 self.parse_block(state);
99 }
100
101 state.finish_at(checkpoint, PowerShellElementType::IfStatement);
102 }
103
104 fn parse_while<'b, S: Source + ?Sized>(&self, state: &mut ParserState<'b, PowerShellLanguage, S>) {
105 let checkpoint = state.checkpoint();
106 state.expect(PowerShellTokenType::While).ok();
107 self.skip_trivia(state);
108 state.expect(PowerShellTokenType::LeftParen).ok();
109 while !state.at(PowerShellTokenType::RightParen) && state.not_at_end() {
110 state.bump();
111 }
112 state.expect(PowerShellTokenType::RightParen).ok();
113 self.skip_trivia(state);
114 self.parse_block(state);
115 state.finish_at(checkpoint, PowerShellElementType::WhileStatement);
116 }
117
118 fn parse_for<'b, S: Source + ?Sized>(&self, state: &mut ParserState<'b, PowerShellLanguage, S>) {
119 let checkpoint = state.checkpoint();
120 state.expect(PowerShellTokenType::For).ok();
121 self.skip_trivia(state);
122 state.expect(PowerShellTokenType::LeftParen).ok();
123 while !state.at(PowerShellTokenType::RightParen) && state.not_at_end() {
124 state.bump();
125 }
126 state.expect(PowerShellTokenType::RightParen).ok();
127 self.skip_trivia(state);
128 self.parse_block(state);
129 state.finish_at(checkpoint, PowerShellElementType::ForStatement);
130 }
131
132 fn parse_foreach<'b, S: Source + ?Sized>(&self, state: &mut ParserState<'b, PowerShellLanguage, S>) {
133 let checkpoint = state.checkpoint();
134 state.expect(PowerShellTokenType::ForEach).ok();
135 self.skip_trivia(state);
136 state.expect(PowerShellTokenType::LeftParen).ok();
137 while !state.at(PowerShellTokenType::RightParen) && state.not_at_end() {
138 state.bump();
139 }
140 state.expect(PowerShellTokenType::RightParen).ok();
141 self.skip_trivia(state);
142 self.parse_block(state);
143 state.finish_at(checkpoint, PowerShellElementType::ForEachStatement);
144 }
145
146 fn parse_try<'b, S: Source + ?Sized>(&self, state: &mut ParserState<'b, PowerShellLanguage, S>) {
147 let checkpoint = state.checkpoint();
148 state.expect(PowerShellTokenType::Try).ok();
149 self.skip_trivia(state);
150 self.parse_block(state);
151
152 while state.at(PowerShellTokenType::Catch) {
153 let catch_cp = state.checkpoint();
154 state.bump();
155 self.skip_trivia(state);
156 if state.at(PowerShellTokenType::LeftBracket) {
157 while !state.at(PowerShellTokenType::RightBracket) && state.not_at_end() {
159 state.bump();
160 }
161 state.expect(PowerShellTokenType::RightBracket).ok();
162 self.skip_trivia(state);
163 }
164 self.parse_block(state);
165 state.finish_at(catch_cp, PowerShellElementType::CatchBlock);
166 self.skip_trivia(state);
167 }
168
169 if state.at(PowerShellTokenType::Finally) {
170 let finally_cp = state.checkpoint();
171 state.bump();
172 self.skip_trivia(state);
173 self.parse_block(state);
174 state.finish_at(finally_cp, PowerShellElementType::FinallyBlock);
175 }
176
177 state.finish_at(checkpoint, PowerShellElementType::TryStatement);
178 }
179
180 fn parse_block<'b, S: Source + ?Sized>(&self, state: &mut ParserState<'b, PowerShellLanguage, S>) {
181 state.expect(PowerShellTokenType::LeftBrace).ok();
182 while !state.at(PowerShellTokenType::RightBrace) && state.not_at_end() {
183 let kind = state.peek_kind();
184 match kind {
185 Some(PowerShellTokenType::Newline) | Some(PowerShellTokenType::Semicolon) | Some(PowerShellTokenType::Whitespace) => {
186 state.bump();
187 }
188 _ => self.parse_statement(state),
189 }
190 }
191 state.expect(PowerShellTokenType::RightBrace).ok();
192 }
193
194 fn parse_statement<'b, S: Source + ?Sized>(&self, state: &mut ParserState<'b, PowerShellLanguage, S>) {
195 let checkpoint = state.checkpoint();
196
197 self.parse_pipeline(state);
198
199 if state.at(PowerShellTokenType::Semicolon) || state.at(PowerShellTokenType::Newline) {
200 state.bump();
201 }
202 state.finish_at(checkpoint, PowerShellElementType::ExpressionStatement);
203 }
204
205 fn parse_pipeline<'b, S: Source + ?Sized>(&self, state: &mut ParserState<'b, PowerShellLanguage, S>) {
206 let checkpoint = state.checkpoint();
207 self.parse_command(state);
208
209 while state.at(PowerShellTokenType::Pipe) {
210 state.bump();
211 self.skip_trivia(state);
212 self.parse_command(state);
213 }
214
215 if state.at(PowerShellTokenType::Pipe) {
216 state.finish_at(checkpoint, PowerShellElementType::Pipeline);
217 }
218 }
219
220 fn parse_command<'b, S: Source + ?Sized>(&self, state: &mut ParserState<'b, PowerShellLanguage, S>) {
221 let checkpoint = state.checkpoint();
222
223 if state.not_at_end() && !matches!(state.peek_kind(), Some(PowerShellTokenType::Newline | PowerShellTokenType::Semicolon | PowerShellTokenType::Pipe | PowerShellTokenType::RightBrace)) {
225 state.bump();
226 }
227
228 while state.not_at_end() {
230 self.skip_trivia(state);
231 let kind = state.peek_kind();
232 if matches!(kind, Some(PowerShellTokenType::Newline | PowerShellTokenType::Semicolon | PowerShellTokenType::Pipe | PowerShellTokenType::RightBrace)) {
233 break;
234 }
235 state.bump();
236 }
237
238 state.finish_at(checkpoint, PowerShellElementType::Command);
239 }
240
241 fn skip_trivia<'b, S: Source + ?Sized>(&self, state: &mut ParserState<'b, PowerShellLanguage, S>) {
242 while state.at(PowerShellTokenType::Whitespace) || state.at(PowerShellTokenType::Comment) {
243 state.bump();
244 }
245 }
246}
247
248impl<'a> Parser<PowerShellLanguage> for PowerShellParser<'a> {
249 fn parse<'b, S: Source + ?Sized>(&self, text: &'b S, edits: &[TextEdit], cache: &'b mut impl ParseCache<PowerShellLanguage>) -> ParseOutput<'b, PowerShellLanguage> {
250 let lexer = crate::lexer::PowerShellLexer::new(self.config);
251 parse_with_lexer(&lexer, text, edits, cache, |state| {
252 let checkpoint = state.checkpoint();
253 self.parse_program(state);
254 Ok(state.finish_at(checkpoint, PowerShellElementType::Root))
255 })
256 }
257}