mod display;
pub mod tokentype;
use crate::{
context::Context,
function::builtin,
out::{ErrorType, EvalResult},
token::tokentype::TokenType,
};
use self::tokentype::IdentifierType;
use itertools::Itertools;
#[derive(Debug, Clone, PartialEq)]
pub struct Token {
pub r#type: TokenType,
pub length: usize,
pub value: String,
}
pub type TokenStream = Vec<Token>;
impl Token {
fn new(r#type: TokenType, length: usize, value: &str) -> Self {
Self {
r#type,
length,
value: String::from(value),
}
}
fn join_with(&mut self, token: &Token, r#type: TokenType) {
self.r#type = r#type;
self.value.extend(token.value.chars());
self.length += token.length;
}
}
pub fn build_stream(mut source: String, context: &Context) -> EvalResult<TokenStream> {
source = remove_whitespaces(&source);
let mut stream: TokenStream = vec![];
let mut content_iter = source.chars();
while let Some(c) = content_iter.next() {
stream.push(tokenize(&c)?);
}
stream = join_operators(&stream);
stream = join_identifiers(&stream)?;
stream = join_literals(&stream)?;
stream = format_identifiers(&stream, context);
stream = predict_unknown_identifiers(&stream);
stream = add_implicit_brackets(&stream)?;
stream = add_implicit_multiplications(&stream);
Ok(stream)
}
fn join_operators(stream: &TokenStream) -> TokenStream {
fn find_and_join(
stream: &TokenStream,
pattern: Vec<TokenType>,
replacement: TokenType,
) -> TokenStream {
let mut out_v = vec![];
let mut start_index = 0;
let mut end_index = pattern.len();
let mut stream_as_iter = stream.iter();
while end_index <= stream.len() {
let slice = &stream[start_index..end_index]
.iter()
.map(|token| token.r#type)
.collect::<Vec<TokenType>>();
if *slice == pattern {
out_v.push(Token::new(replacement, pattern.len(), ""));
for _ in 0..pattern.len() {
stream_as_iter.next();
}
start_index += pattern.len();
end_index += pattern.len();
} else {
out_v.push(stream[start_index].clone());
stream_as_iter.next();
start_index += 1;
end_index += 1;
}
}
for token in stream_as_iter {
out_v.push(token.clone());
}
out_v
}
use TokenType::*;
let mut new_stream = stream.clone();
new_stream = find_and_join(&new_stream, vec![LessThan, Equal], LessOrEqualTo);
new_stream = find_and_join(&new_stream, vec![GreaterThan, Equal], GreaterOrEqualTo);
new_stream = find_and_join(&new_stream, vec![Equal, Equal], DoubleEqual);
new_stream = find_and_join(&new_stream, vec![Exclamation, Equal], NotEqual);
new_stream = find_and_join(&new_stream, vec![And, And], DoubleAnd);
new_stream = find_and_join(&new_stream, vec![Or, Or], DoubleOr);
new_stream
}
fn predict_unknown_identifiers(stream: &TokenStream) -> TokenStream {
if stream.len() == 0 {
return stream.clone();
}
let mut out_stream = vec![];
let stream_as_iter = stream.iter();
let mut convert = |prev: &Token, next: Option<&Token>| {
let next_is_bracket = match next {
Some(token) => token.r#type == TokenType::OpeningBracket,
None => false,
};
if prev.r#type == TokenType::Identifier(IdentifierType::Unknown) {
if next_is_bracket {
out_stream.push(Token::new(
TokenType::Identifier(IdentifierType::Function),
prev.value.len(),
&prev.value[..],
));
} else {
out_stream.push(Token::new(
TokenType::Identifier(IdentifierType::Var),
prev.value.len(),
&prev.value[..],
));
}
} else {
out_stream.push(prev.clone());
}
};
for (prev, next) in stream_as_iter.tuple_windows() {
convert(prev, Some(next));
}
let last_token = stream.iter().last().unwrap();
convert(last_token, None);
out_stream
}
fn add_implicit_brackets(stream: &TokenStream) -> EvalResult<TokenStream> {
if stream.len() == 0 {
return Ok(stream.clone());
}
let mut out_stream = vec![];
let mut skip_iteration = false;
let stream_as_iter = stream.iter();
for (prev, next) in stream_as_iter.tuple_windows() {
if skip_iteration {
skip_iteration = false;
continue;
}
if prev.r#type == TokenType::Identifier(IdentifierType::Function)
&& next.r#type != TokenType::OpeningBracket
{
if next.r#type == TokenType::Literal
|| next.r#type == TokenType::Identifier(IdentifierType::Var)
{
out_stream.push(prev.clone());
out_stream.push(Token::new(TokenType::OpeningBracket, 1, ""));
out_stream.push(next.clone());
out_stream.push(Token::new(TokenType::ClosingBracket, 1, ""));
skip_iteration = true;
} else {
return Err(ErrorType::MissingFunctionParameters {
func_name: prev.value.clone(),
});
}
} else {
out_stream.push(prev.clone());
}
}
if !skip_iteration {
out_stream.push(stream.iter().last().unwrap().clone());
}
Ok(out_stream)
}
fn format_identifiers(stream: &TokenStream, context: &Context) -> TokenStream {
let mut out_stream = vec![];
let mut stream_as_iter = stream.iter();
while let Some(token) = stream_as_iter.next() {
if token.r#type == TokenType::Identifier(IdentifierType::Unknown) {
let content = token.value.clone();
let splitted = split_into_identifiers(content, context);
for (i, i_type) in splitted {
out_stream.push(Token::new(TokenType::Identifier(i_type), i.len(), &i[..]));
}
} else {
out_stream.push(token.clone());
}
}
out_stream
}
pub fn split_into_identifiers(input: String, context: &Context) -> Vec<(String, IdentifierType)> {
let mut out = vec![];
fn try_to_categorize(
sorted_patterns: &Vec<(IdentifierType, Vec<&str>)>,
candidate: &String,
) -> Option<IdentifierType> {
let mut patterns_as_iter = sorted_patterns.iter();
while let Some((i_type, patterns)) = patterns_as_iter.next() {
for pattern in patterns {
if &&candidate[..] == pattern {
return Some(*i_type);
}
}
}
None
}
let patterns = vec![
(
IdentifierType::Function,
builtin::get_built_in_functions_vec()
.iter()
.map(|x| x.func_identifier)
.collect::<Vec<&str>>(),
),
(
IdentifierType::Var,
builtin::get_built_in_consts_map()
.iter()
.map(|x| x.0)
.collect::<Vec<&str>>(),
),
(
IdentifierType::Function,
context
.functions
.iter()
.map(|x| &x.0[..])
.collect::<Vec<&str>>(),
),
(
IdentifierType::Var,
context
.variables
.iter()
.map(|x| &x.0[..])
.collect::<Vec<&str>>(),
),
];
let mut to_identify = input.to_owned();
let mut current;
while to_identify.len() > 0 {
current = to_identify.clone();
to_identify = "".to_owned();
if current.is_empty() {
break;
}
loop {
let categorized = try_to_categorize(&patterns, ¤t);
match categorized {
Some(identifier) => {
out.push((current, identifier));
break;
}
None => {
if current.len() == 1 {
out.push((current.clone(), IdentifierType::Unknown));
break;
} else {
to_identify.insert(0, current.chars().last().unwrap());
current = current[0..current.len() - 1].to_owned();
}
}
}
}
}
out
}
fn add_implicit_multiplications(stream: &TokenStream) -> TokenStream {
if stream.len() == 0 {
return stream.clone();
}
let mut out_stream: TokenStream = vec![stream[0].clone()];
let mut previous_token_type = stream[0].r#type;
let mut index = 1;
while index < stream.len() {
let current_type = stream[index].r#type;
use IdentifierType::*;
use TokenType::*;
if previous_token_type == Literal && current_type == OpeningBracket
|| previous_token_type == ClosingBracket && current_type == Literal
|| previous_token_type == Literal && current_type == Literal
|| previous_token_type == ClosingBracket && current_type == OpeningBracket
|| previous_token_type == ClosingBracket && matches!(current_type, Identifier(_))
|| previous_token_type == Identifier(Var) && current_type == OpeningBracket
|| previous_token_type == Literal && matches!(current_type, Identifier(_))
|| matches!(previous_token_type, Identifier(_)) && current_type == Literal
|| matches!(previous_token_type, Identifier(_)) && matches!(current_type, Identifier(_))
{
out_stream.push(Token::new(TokenType::Star, 1, ""));
}
out_stream.push(stream[index].clone());
previous_token_type = current_type;
index += 1;
}
out_stream
}
fn remove_whitespaces(string: &String) -> String {
string.replace(" ", "")
}
fn join_identifiers(stream: &TokenStream) -> EvalResult<TokenStream> {
let mut joined_stream: TokenStream = vec![];
let mut is_previous_identifier: bool = false;
for token in stream {
let is_identifier = token.r#type == TokenType::Identifier(IdentifierType::Unknown);
if is_identifier && is_previous_identifier {
let previous_token = joined_stream.last_mut().unwrap();
previous_token.join_with(token, TokenType::Identifier(IdentifierType::Unknown));
} else {
joined_stream.push(token.clone());
}
is_previous_identifier = is_identifier;
}
Ok(joined_stream)
}
fn join_literals(stream: &TokenStream) -> EvalResult<TokenStream> {
let mut joined_stream: TokenStream = vec![];
let mut is_previous_literal: bool = false;
let mut comma_found = false;
for token in stream {
let is_comma = token.r#type == TokenType::Dot;
let is_literal = token.r#type == TokenType::Literal || is_comma;
if is_literal || is_comma {
if is_comma {
if comma_found {
return Err(ErrorType::InvalidTokenPosition {
token: token.r#type,
});
}
comma_found = true;
}
if is_previous_literal {
let previous_token = joined_stream.last_mut().unwrap();
previous_token.join_with(token, TokenType::Literal);
} else {
joined_stream.push(token.clone());
}
} else {
comma_found = false;
joined_stream.push(token.clone());
}
is_previous_literal = is_literal;
}
Ok(joined_stream)
}
fn tokenize(character: &char) -> EvalResult<Token> {
Ok(match character {
'+' => Token::new(TokenType::Plus, 1, ""),
'-' => Token::new(TokenType::Minus, 1, ""),
'*' => Token::new(TokenType::Star, 1, ""),
'/' => Token::new(TokenType::Slash, 1, ""),
',' => Token::new(TokenType::Comma, 1, ""),
'=' => Token::new(TokenType::Equal, 1, ""),
'^' => Token::new(TokenType::Caret, 1, ""),
'%' => Token::new(TokenType::Percentage, 1, ""),
'<' => Token::new(TokenType::LessThan, 1, ""),
'>' => Token::new(TokenType::GreaterThan, 1, ""),
'&' => Token::new(TokenType::And, 1, ""),
'|' => Token::new(TokenType::Or, 1, ""),
'!' => Token::new(TokenType::Exclamation, 1, ""),
'.' => Token::new(TokenType::Dot, 1, "."),
'(' => Token::new(TokenType::OpeningBracket, 1, ""),
')' => Token::new(TokenType::ClosingBracket, 1, ""),
other => {
let as_string = format!("{}", other);
if other.is_numeric() {
Token::new(TokenType::Literal, 1, &as_string)
} else if other.is_alphabetic() {
Token::new(
TokenType::Identifier(IdentifierType::Unknown),
1,
&as_string,
)
} else {
return Err(ErrorType::UnknownToken {
token: String::from(&as_string),
});
}
}
})
}