vibesql_parser/parser/advanced_objects/
routines.rs1use crate::keywords::Keyword;
30use crate::parser::{ParseError, Parser};
31use crate::token::Token;
32use vibesql_ast::{
33 CallStmt, CreateFunctionStmt, CreateProcedureStmt, DropFunctionStmt, DropProcedureStmt,
34 FunctionParameter, ParameterMode, ProcedureBody, ProcedureParameter, ProceduralStatement,
35 SqlSecurity,
36};
37
38impl Parser {
39 pub fn parse_create_procedure(&mut self) -> Result<CreateProcedureStmt, ParseError> {
43 let procedure_name = self.parse_identifier()?;
45
46 self.expect_token(Token::LParen)?;
47 let parameters = self.parse_procedure_parameters()?;
48 self.expect_token(Token::RParen)?;
49
50 let (sql_security, comment, language) = self.parse_procedure_characteristics()?;
52
53 let body = self.parse_procedure_body()?;
54
55 Ok(CreateProcedureStmt {
56 procedure_name,
57 parameters,
58 body,
59 sql_security,
60 comment,
61 language,
62 })
63 }
64
65 pub fn parse_create_function(&mut self) -> Result<CreateFunctionStmt, ParseError> {
69 let function_name = self.parse_identifier()?;
71
72 self.expect_token(Token::LParen)?;
73 let parameters = self.parse_function_parameters()?;
74 self.expect_token(Token::RParen)?;
75
76 self.expect_keyword(Keyword::Returns)?;
77 let return_type = self.parse_data_type()?;
78
79 let (deterministic, sql_security, comment, language) = self.parse_function_characteristics()?;
81
82 let body = self.parse_procedure_body()?;
83
84 Ok(CreateFunctionStmt {
85 function_name,
86 parameters,
87 return_type,
88 body,
89 deterministic,
90 sql_security,
91 comment,
92 language,
93 })
94 }
95
96 pub fn parse_drop_procedure(&mut self) -> Result<DropProcedureStmt, ParseError> {
100 let if_exists = self.try_consume_keyword(Keyword::If);
102 if if_exists {
103 self.expect_keyword(Keyword::Exists)?;
104 }
105
106 let procedure_name = self.parse_identifier()?;
107
108 Ok(DropProcedureStmt {
109 procedure_name,
110 if_exists,
111 })
112 }
113
114 pub fn parse_drop_function(&mut self) -> Result<DropFunctionStmt, ParseError> {
118 let if_exists = self.try_consume_keyword(Keyword::If);
120 if if_exists {
121 self.expect_keyword(Keyword::Exists)?;
122 }
123
124 let function_name = self.parse_identifier()?;
125
126 Ok(DropFunctionStmt {
127 function_name,
128 if_exists,
129 })
130 }
131
132 pub fn parse_call(&mut self) -> Result<CallStmt, ParseError> {
136 let procedure_name = self.parse_identifier()?;
138
139 self.expect_token(Token::LParen)?;
140 let arguments = self.parse_expression_list()?;
141 self.expect_token(Token::RParen)?;
142
143 Ok(CallStmt {
144 procedure_name,
145 arguments,
146 })
147 }
148
149 fn parse_procedure_parameters(&mut self) -> Result<Vec<ProcedureParameter>, ParseError> {
153 let mut parameters = Vec::new();
154
155 if self.peek() == &Token::RParen {
157 return Ok(parameters);
158 }
159
160 loop {
161 let mode = if self.try_consume_keyword(Keyword::In) {
163 ParameterMode::In
164 } else if self.try_consume_keyword(Keyword::Out) {
165 ParameterMode::Out
166 } else if self.try_consume_keyword(Keyword::InOut) {
167 ParameterMode::InOut
168 } else {
169 ParameterMode::In
171 };
172
173 let name = self.parse_identifier()?;
174 let data_type = self.parse_data_type()?;
175
176 parameters.push(ProcedureParameter {
177 mode,
178 name,
179 data_type,
180 });
181
182 if !self.try_consume(&Token::Comma) {
183 break;
184 }
185 }
186
187 Ok(parameters)
188 }
189
190 fn parse_function_parameters(&mut self) -> Result<Vec<FunctionParameter>, ParseError> {
195 let mut parameters = Vec::new();
196
197 if self.peek() == &Token::RParen {
199 return Ok(parameters);
200 }
201
202 loop {
203 let name = self.parse_identifier()?;
204 let data_type = self.parse_data_type()?;
205
206 parameters.push(FunctionParameter { name, data_type });
207
208 if !self.try_consume(&Token::Comma) {
209 break;
210 }
211 }
212
213 Ok(parameters)
214 }
215
216 fn parse_procedure_body(&mut self) -> Result<ProcedureBody, ParseError> {
222 if self.try_consume_keyword(Keyword::Begin) {
223 let statements = self.parse_procedural_statements()?;
225 self.expect_keyword(Keyword::End)?;
226 Ok(ProcedureBody::BeginEnd(statements))
227 } else {
228 Err(ParseError {
230 message: "Expected BEGIN keyword for procedure body".to_string(),
231 })
232 }
233 }
234
235 fn parse_procedural_statements(&mut self) -> Result<Vec<ProceduralStatement>, ParseError> {
248 let mut statements = Vec::new();
249
250 while !self.peek_keyword(Keyword::End) && self.peek() != &Token::Eof {
251 let stmt = if self.try_consume_keyword(Keyword::Declare) {
252 self.parse_declare_statement()?
253 } else if self.try_consume_keyword(Keyword::Set) {
254 self.parse_set_statement()?
255 } else if self.try_consume_keyword(Keyword::If) {
256 self.parse_if_statement()?
257 } else if self.try_consume_keyword(Keyword::While) {
258 self.parse_while_statement()?
259 } else if self.try_consume_keyword(Keyword::Loop) {
260 self.parse_loop_statement()?
261 } else if self.try_consume_keyword(Keyword::Repeat) {
262 self.parse_repeat_statement()?
263 } else if self.try_consume_keyword(Keyword::Return) {
264 let expr = self.parse_expression()?;
265 self.expect_token(Token::Semicolon)?;
266 ProceduralStatement::Return(Box::new(expr))
267 } else if self.try_consume_keyword(Keyword::Leave) {
268 let label = self.parse_identifier()?;
269 self.expect_token(Token::Semicolon)?;
270 ProceduralStatement::Leave(label)
271 } else if self.try_consume_keyword(Keyword::Iterate) {
272 let label = self.parse_identifier()?;
273 self.expect_token(Token::Semicolon)?;
274 ProceduralStatement::Iterate(label)
275 } else {
276 let sql_stmt = self.parse_statement()?;
278 ProceduralStatement::Sql(Box::new(sql_stmt))
279 };
280
281 statements.push(stmt);
282 }
283
284 Ok(statements)
285 }
286
287 fn parse_declare_statement(&mut self) -> Result<ProceduralStatement, ParseError> {
291 let name = self.parse_identifier()?;
292 let data_type = self.parse_data_type()?;
293
294 let default_value = if self.try_consume_keyword(Keyword::Default) {
295 Some(Box::new(self.parse_expression()?))
296 } else {
297 None
298 };
299
300 self.expect_token(Token::Semicolon)?;
301
302 Ok(ProceduralStatement::Declare {
303 name,
304 data_type,
305 default_value,
306 })
307 }
308
309 fn parse_set_statement(&mut self) -> Result<ProceduralStatement, ParseError> {
313 let name = self.parse_identifier()?;
314 self.expect_token(Token::Symbol('='))?;
315 let value = self.parse_expression()?;
316 self.expect_token(Token::Semicolon)?;
317
318 Ok(ProceduralStatement::Set {
319 name,
320 value: Box::new(value),
321 })
322 }
323
324 fn parse_if_statement(&mut self) -> Result<ProceduralStatement, ParseError> {
328 let condition = self.parse_expression()?;
329 self.expect_keyword(Keyword::Then)?;
330
331 let then_statements = self.parse_procedural_statements_until(&[Keyword::Else, Keyword::End])?;
332
333 let else_statements = if self.try_consume_keyword(Keyword::Else) {
334 Some(self.parse_procedural_statements_until(&[Keyword::End])?)
335 } else {
336 None
337 };
338
339 self.expect_keyword(Keyword::End)?;
340 self.expect_keyword(Keyword::If)?;
341 self.expect_token(Token::Semicolon)?;
342
343 Ok(ProceduralStatement::If {
344 condition: Box::new(condition),
345 then_statements,
346 else_statements,
347 })
348 }
349
350 fn parse_while_statement(&mut self) -> Result<ProceduralStatement, ParseError> {
354 let condition = self.parse_expression()?;
355 self.expect_keyword(Keyword::Do)?;
356
357 let statements = self.parse_procedural_statements_until(&[Keyword::End])?;
358
359 self.expect_keyword(Keyword::End)?;
360 self.expect_keyword(Keyword::While)?;
361 self.expect_token(Token::Semicolon)?;
362
363 Ok(ProceduralStatement::While {
364 condition: Box::new(condition),
365 statements,
366 })
367 }
368
369 fn parse_loop_statement(&mut self) -> Result<ProceduralStatement, ParseError> {
373 let statements = self.parse_procedural_statements_until(&[Keyword::End])?;
374
375 self.expect_keyword(Keyword::Loop)?;
376 self.expect_token(Token::Semicolon)?;
377
378 Ok(ProceduralStatement::Loop { statements })
379 }
380
381 fn parse_repeat_statement(&mut self) -> Result<ProceduralStatement, ParseError> {
385 let statements = self.parse_procedural_statements_until(&[Keyword::Until])?;
386
387 self.expect_keyword(Keyword::Until)?;
388 let condition = self.parse_expression()?;
389 self.expect_keyword(Keyword::End)?;
390 self.expect_keyword(Keyword::Repeat)?;
391 self.expect_token(Token::Semicolon)?;
392
393 Ok(ProceduralStatement::Repeat {
394 statements,
395 condition: Box::new(condition),
396 })
397 }
398
399 fn parse_procedural_statements_until(
404 &mut self,
405 stop_keywords: &[Keyword],
406 ) -> Result<Vec<ProceduralStatement>, ParseError> {
407 let mut statements = Vec::new();
408
409 while self.peek() != &Token::Eof {
410 if stop_keywords.iter().any(|kw| self.peek_keyword(*kw)) {
412 break;
413 }
414
415 let stmt = if self.try_consume_keyword(Keyword::Declare) {
416 self.parse_declare_statement()?
417 } else if self.try_consume_keyword(Keyword::Set) {
418 self.parse_set_statement()?
419 } else if self.try_consume_keyword(Keyword::If) {
420 self.parse_if_statement()?
421 } else if self.try_consume_keyword(Keyword::While) {
422 self.parse_while_statement()?
423 } else if self.try_consume_keyword(Keyword::Loop) {
424 self.parse_loop_statement()?
425 } else if self.try_consume_keyword(Keyword::Repeat) {
426 self.parse_repeat_statement()?
427 } else if self.try_consume_keyword(Keyword::Return) {
428 let expr = self.parse_expression()?;
429 self.expect_token(Token::Semicolon)?;
430 ProceduralStatement::Return(Box::new(expr))
431 } else if self.try_consume_keyword(Keyword::Leave) {
432 let label = self.parse_identifier()?;
433 self.expect_token(Token::Semicolon)?;
434 ProceduralStatement::Leave(label)
435 } else if self.try_consume_keyword(Keyword::Iterate) {
436 let label = self.parse_identifier()?;
437 self.expect_token(Token::Semicolon)?;
438 ProceduralStatement::Iterate(label)
439 } else {
440 let sql_stmt = self.parse_statement()?;
442 ProceduralStatement::Sql(Box::new(sql_stmt))
443 };
444
445 statements.push(stmt);
446 }
447
448 Ok(statements)
449 }
450
451 #[allow(clippy::type_complexity)]
455 fn parse_procedure_characteristics(&mut self) -> Result<(Option<SqlSecurity>, Option<String>, Option<String>), ParseError> {
456 let mut sql_security = None;
457 let mut comment = None;
458 let mut language = None;
459
460 loop {
462 if self.try_consume_keyword(Keyword::Sql) {
463 self.expect_keyword(Keyword::Security)?;
464 if self.try_consume_keyword(Keyword::Definer) {
465 sql_security = Some(SqlSecurity::Definer);
466 } else if self.try_consume_keyword(Keyword::Invoker) {
467 sql_security = Some(SqlSecurity::Invoker);
468 } else {
469 return Err(ParseError {
470 message: "Expected DEFINER or INVOKER after SQL SECURITY".to_string(),
471 });
472 }
473 } else if self.try_consume_keyword(Keyword::Comment) {
474 if let Token::String(s) = self.peek().clone() {
475 self.advance();
476 comment = Some(s);
477 } else {
478 return Err(ParseError {
479 message: "Expected string literal after COMMENT".to_string(),
480 });
481 }
482 } else if self.try_consume_keyword(Keyword::Language) {
483 self.expect_keyword(Keyword::Sql)?;
484 language = Some("SQL".to_string());
485 } else {
486 break;
488 }
489 }
490
491 Ok((sql_security, comment, language))
492 }
493
494 #[allow(clippy::type_complexity)]
498 fn parse_function_characteristics(&mut self) -> Result<(Option<bool>, Option<SqlSecurity>, Option<String>, Option<String>), ParseError> {
499 let mut deterministic = None;
500 let mut sql_security = None;
501 let mut comment = None;
502 let mut language = None;
503
504 loop {
506 if self.try_consume_keyword(Keyword::Deterministic) {
507 deterministic = Some(true);
508 } else if self.try_consume_keyword(Keyword::Not) {
509 self.expect_keyword(Keyword::Deterministic)?;
510 deterministic = Some(false);
511 } else if self.try_consume_keyword(Keyword::Sql) {
512 self.expect_keyword(Keyword::Security)?;
513 if self.try_consume_keyword(Keyword::Definer) {
514 sql_security = Some(SqlSecurity::Definer);
515 } else if self.try_consume_keyword(Keyword::Invoker) {
516 sql_security = Some(SqlSecurity::Invoker);
517 } else {
518 return Err(ParseError {
519 message: "Expected DEFINER or INVOKER after SQL SECURITY".to_string(),
520 });
521 }
522 } else if self.try_consume_keyword(Keyword::Comment) {
523 if let Token::String(s) = self.peek().clone() {
524 self.advance();
525 comment = Some(s);
526 } else {
527 return Err(ParseError {
528 message: "Expected string literal after COMMENT".to_string(),
529 });
530 }
531 } else if self.try_consume_keyword(Keyword::Language) {
532 self.expect_keyword(Keyword::Sql)?;
533 language = Some("SQL".to_string());
534 } else {
535 break;
537 }
538 }
539
540 Ok((deterministic, sql_security, comment, language))
541 }
542}