use crate::parser::ast::stmt::*;
use crate::parser::core::error::{ParseError, ParseErrorKind};
use crate::parser::parsing::clause_parser::ClauseParser;
use crate::parser::parsing::parse_context::ParseContext;
use crate::parser::TokenKind;
pub(super) fn parse_in_query_call_statement(ctx: &mut ParseContext) -> Result<Stmt, ParseError> {
let start_span = ctx.current_span();
ctx.consume_keyword("CALL")?;
let func_name = ctx.expect_identifier()?;
ctx.expect_token(TokenKind::LParen)?;
let mut args = Vec::new();
if !ctx.check_token(TokenKind::RParen) {
loop {
let arg = super::misc::parse_expression(ctx)?;
args.push(arg);
if !ctx.match_token(TokenKind::Comma) {
break;
}
}
}
ctx.expect_token(TokenKind::RParen)?;
let yield_clause = if ctx.match_token(TokenKind::Yield) {
Some(ClauseParser::new().parse_yield_clause(ctx)?)
} else {
None
};
let span = ctx.span_since(start_span.start);
Ok(Stmt::InQueryCall(InQueryCallStmt {
span,
func_name,
args,
yield_clause,
}))
}
pub(super) fn parse_export_database_statement(ctx: &mut ParseContext) -> Result<Stmt, ParseError> {
let start_span = ctx.current_span();
ctx.consume_keyword("EXPORT")?;
ctx.consume_keyword("DATABASE")?;
let path = ctx.expect_string_literal()?;
let options = if ctx.check_keyword("WITH") {
ctx.consume_keyword("WITH")?;
ctx.consume_keyword("OPTIONS")?;
ctx.expect_token(TokenKind::LParen)?;
let mut opts = Vec::new();
loop {
let key = ctx.expect_identifier()?;
ctx.expect_token(TokenKind::Assign)?;
let value = ctx.expect_string_literal()?;
opts.push(ExportOption { key, value });
if !ctx.match_token(TokenKind::Comma) {
break;
}
}
ctx.expect_token(TokenKind::RParen)?;
opts
} else {
vec![]
};
let span = ctx.span_since(start_span.start);
Ok(Stmt::ExportDatabase(ExportDatabaseStmt {
span,
path,
options,
}))
}
pub(super) fn parse_import_database_statement(ctx: &mut ParseContext) -> Result<Stmt, ParseError> {
let start_span = ctx.current_span();
ctx.consume_keyword("IMPORT")?;
ctx.consume_keyword("DATABASE")?;
let path = ctx.expect_string_literal()?;
let span = ctx.span_since(start_span.start);
Ok(Stmt::ImportDatabase(ImportDatabaseStmt { span, path }))
}
pub(super) fn parse_attach_database_statement(ctx: &mut ParseContext) -> Result<Stmt, ParseError> {
let start_span = ctx.current_span();
ctx.consume_keyword("ATTACH")?;
let path = ctx.expect_string_literal()?;
ctx.consume_keyword("AS")?;
let alias = ctx.expect_identifier()?;
let mut db_type = None;
let mut options = Vec::new();
if ctx.match_token(TokenKind::LParen) {
if !ctx.check_token(TokenKind::RParen) {
loop {
if ctx.check_keyword("DBTYPE") || ctx.check_keyword("DATABASE_TYPE") {
ctx.next_token();
let value = parse_option_value(ctx)?;
db_type = Some(value);
} else {
let key = ctx.expect_identifier()?;
if ctx.match_token(TokenKind::Assign) || ctx.match_token(TokenKind::Eq) {
let value = parse_option_value(ctx)?;
options.push((key, value));
} else {
let value = parse_option_value(ctx)?;
options.push((key, value));
}
}
if !ctx.match_token(TokenKind::Comma) {
break;
}
}
}
ctx.expect_token(TokenKind::RParen)?;
}
let span = ctx.span_since(start_span.start);
Ok(Stmt::AttachDatabase(AttachDatabaseStmt {
span,
path,
alias,
db_type,
options,
}))
}
pub(super) fn parse_detach_database_statement(ctx: &mut ParseContext) -> Result<Stmt, ParseError> {
let start_span = ctx.current_span();
ctx.consume_keyword("DETACH")?;
let alias = ctx.expect_identifier()?;
let span = ctx.span_since(start_span.start);
Ok(Stmt::DetachDatabase(DetachDatabaseStmt { span, alias }))
}
fn parse_option_value(ctx: &mut ParseContext) -> Result<String, ParseError> {
let token = ctx.current_token().clone();
let value = match token.kind {
TokenKind::StringLiteral(s) => s,
TokenKind::Identifier(name) => name,
TokenKind::IntegerLiteral(n) => n.to_string(),
TokenKind::FloatLiteral(f) => f.to_string(),
_ => {
return Err(ParseError::new(
ParseErrorKind::UnexpectedToken,
format!("Expected option value, got {:?}", token.kind),
ctx.current_position(),
));
}
};
ctx.next_token();
Ok(value)
}