use crate::expressions::token::TokenType;
use crate::expressions::token::{TableReference, TableSpecifier};
use super::Result;
use super::{Lexer, LexerError};
impl<'a> Lexer<'a> {
fn consume_table_specifier(&mut self) -> Result<Option<TableSpecifier>> {
if self.peek_char() == Some('#') {
let rest_of_formula: String = self.chars[self.position..self.len].iter().collect();
let specifier = if rest_of_formula.starts_with("#This Row]") {
self.position += "#This Row]".len();
TableSpecifier::ThisRow
} else if rest_of_formula.starts_with("#All]") {
self.position += "#All]".len();
TableSpecifier::All
} else if rest_of_formula.starts_with("#Data]") {
self.position += "#Data]".len();
TableSpecifier::Data
} else if rest_of_formula.starts_with("#Headers]") {
self.position += "#Headers]".len();
TableSpecifier::Headers
} else if rest_of_formula.starts_with("#Totals]") {
self.position += "#Totals]".len();
TableSpecifier::Totals
} else {
return Err(LexerError {
position: self.position,
message: "Invalid structured reference".to_string(),
});
};
Ok(Some(specifier))
} else {
Ok(None)
}
}
fn consume_column_reference(&mut self) -> Result<String> {
self.consume_whitespace();
let end_char = if self.peek_char() == Some('[') {
self.position += 1;
']'
} else {
')'
};
let mut position = self.position;
while position < self.len {
let next_char = self.chars[position];
if next_char != end_char {
position += 1;
if next_char == '\'' {
if position == self.len {
return Err(LexerError {
position: self.position,
message: "Invalid column name".to_string(),
});
}
position += 1
}
} else {
break;
}
}
let chars: String = self.chars[self.position..position].iter().collect();
if end_char == ']' {
position += 1;
}
self.position = position;
Ok(chars
.replace("'[", "[")
.replace("']", "]")
.replace("'#", "#")
.replace("'@", "@")
.replace("''", "'"))
}
pub(crate) fn consume_structured_reference(&mut self, table_name: &str) -> Result<TokenType> {
self.expect(TokenType::LeftBracket)?;
let peek_char = self.peek_char();
if peek_char == Some(']') {
self.expect(TokenType::RightBracket)?;
return Ok(TokenType::Ident(table_name.to_string()));
}
if peek_char == Some('#') {
if let Some(specifier) = self.consume_table_specifier()? {
return Ok(TokenType::StructuredReference {
table_name: table_name.to_string(),
specifier: Some(specifier),
table_reference: None,
});
} else {
return Err(LexerError {
position: self.position,
message: "Invalid structured reference".to_string(),
});
}
} else if peek_char != Some('[') {
self.position -= 1;
let column_name = self.consume_column_reference()?;
return Ok(TokenType::StructuredReference {
table_name: table_name.to_string(),
specifier: None,
table_reference: Some(TableReference::ColumnReference(column_name)),
});
}
self.expect(TokenType::LeftBracket)?;
let specifier = self.consume_table_specifier()?;
if specifier.is_some() {
let peek_token = self.peek_token();
if peek_token == TokenType::Comma {
self.advance_token();
self.expect(TokenType::LeftBracket)?;
} else if peek_token == TokenType::RightBracket {
return Ok(TokenType::StructuredReference {
table_name: table_name.to_string(),
specifier,
table_reference: None,
});
}
}
self.position -= 1;
let column_reference = self.consume_column_reference()?;
let table_reference = if self.peek_char() == Some(':') {
self.position += 1;
let column_reference_right = self.consume_column_reference()?;
self.expect(TokenType::RightBracket)?;
Some(TableReference::RangeReference((
column_reference,
column_reference_right,
)))
} else {
self.expect(TokenType::RightBracket)?;
Some(TableReference::ColumnReference(column_reference))
};
Ok(TokenType::StructuredReference {
table_name: table_name.to_string(),
specifier,
table_reference,
})
}
}