use crate::token::Token;
use crate::lexer::LexerErrorType;
use crate::utils::{
ParseResult,
accumulate_until,
is_digit,
number::parse_number,
};
pub fn parse_symbols<'a>(
input: &'a str,
characters: (char, Option<char>, Option<char>)
) -> ParseResult<'a> {
match characters {
('.', Some('.'), Some('.')) => {
let (symbol, next_input) = input.split_at(3);
Ok((Token::new_symbol(symbol), next_input))
},
('.', Some('.'), _) => {
let (symbol, next_input) = input.split_at(2);
Ok((Token::new_symbol(symbol), next_input))
},
('.', Some(character), _) if is_digit(character) => parse_number(input),
('-', Some('-'), _) => parse_comment(input),
('[', Some('['), _) => {
input.find("]]").map_or_else(
|| Err(LexerErrorType::UnfinishedString),
|index| {
let (string, next_input) = input.split_at(index + 2);
Ok((Token::new_string(string), next_input))
}
)
},
('[', Some('='), _) => {
match try_parse_balanced_brackets(input) {
Some((content, next_input)) => Ok((Token::new_string(content), next_input)),
None => {
let (symbol, next_input) = input.split_at(1);
Ok((Token::new_symbol(symbol), next_input))
},
}
},
('=', Some('='), _)
| ('~', Some('='), _)
| ('<', Some('='), _)
| ('>', Some('='), _) => {
let (symbol, next_input) = input.split_at(2);
Ok((Token::new_symbol(symbol), next_input))
},
_ => {
let (symbol, next_input) = input.split_at(1);
Ok((Token::new_symbol(symbol), next_input))
},
}
}
fn parse_comment<'a>(input: &'a str) -> ParseResult<'a> {
let (comment, next_input) = input.get(2..)
.and_then(try_parse_balanced_brackets)
.map(|(content, _)| {
input.split_at(content.len() + 2)
}).unwrap_or_else(|| {
accumulate_until(input, |character| character == '\n' || character == '\r')
});
Ok((Token::new_comment(comment), next_input))
}
fn try_parse_balanced_brackets<'a>(input: &'a str) -> Option<(&'a str, &'a str)> {
let mut chars = input.chars();
if chars.next() != Some('[') {
return None
}
let mut closing_pattern = "]".to_owned();
loop {
match chars.next() {
Some('=') => {
closing_pattern.push('=');
},
Some('[') => break,
_ => return None,
}
}
closing_pattern.push(']');
input.find(&closing_pattern)
.map(|index| {
input.split_at(index + closing_pattern.len())
})
}