#[derive(Debug)]
pub enum Commands {
AddByte,
RemoveByte,
LoopBegin,
LoopEnd,
GoNext,
GoLast,
ReadByte,
WriteByte,
}
#[derive(Debug)]
pub struct Token {
pub value: Commands,
pub line: i32,
pub column: i32,
pub repeats: i32
}
fn generate_optimization(index: usize, input: &str, ignore_list: &mut Vec<usize>, handle_char: char, give_val: Commands) -> Token {
let input_slice = &input[index..input.len()];
let mut total_found = 0;
for (i, char) in input_slice.chars().enumerate() {
if char == handle_char {
total_found += 1;
ignore_list.push(i+index);
} else {
break;
}
}
return Token{
value: give_val,
repeats: total_found,
line: 0,
column: 0
}
}
pub fn execute(input: &str) -> Vec<Token> {
let mut tokenized: Vec<Token> = Vec::new();
let mut line = 0;
let mut column = 0;
let mut ignore_list: Vec<usize> = Vec::new();
for (i, char) in input.chars().enumerate() {
if ignore_list.contains(&i) {
continue
}
match char {
'\n' => {
line += 1;
column = 0;
},
'+' => {
let mut optimized_token = generate_optimization(i, input, &mut ignore_list, '+', Commands::AddByte);
optimized_token.line = line;
optimized_token.column = column;
tokenized.push(optimized_token)
},
'-' => {
let mut optimized_token = generate_optimization(i, input, &mut ignore_list, '-', Commands::RemoveByte);
optimized_token.line = line;
optimized_token.column = column;
tokenized.push(optimized_token)
},
'[' => tokenized.push(Token{
value: Commands::LoopBegin,
line: line,
column: column,
repeats: 0
}),
']' => tokenized.push(Token{
value: Commands::LoopEnd,
line: line,
column: column,
repeats: 0
}),
'>' => {
let mut optimized_token = generate_optimization(i, input, &mut ignore_list, '>', Commands::GoNext);
optimized_token.line = line;
optimized_token.column = column;
tokenized.push(optimized_token)
},
'<' => {
let mut optimized_token = generate_optimization(i, input, &mut ignore_list, '<', Commands::GoLast);
optimized_token.line = line;
optimized_token.column = column;
tokenized.push(optimized_token)
},
'.' => tokenized.push(Token{
value: Commands::WriteByte,
line: line,
column: column,
repeats: 0
}),
',' => tokenized.push(Token{
value: Commands::ReadByte,
line: line,
column: column,
repeats: 0
}),
_ => {
column += 1;
continue;
}
};
column += 1;
};
tokenized
}
pub fn check_brackets(tokens: &Vec<Token>) -> Result<(), String> {
let mut loop_reference_count = 0;
let (mut open_brackets_line, mut open_brackets_column) = (0, 0);
let (mut close_brackets_line, mut close_brackets_column) = (0, 0);
for token in tokens {
match token.value {
Commands::LoopBegin => {
loop_reference_count += 1;
open_brackets_line = token.line;
open_brackets_column = token.column;
},
Commands::LoopEnd => {
loop_reference_count -= 1;
close_brackets_line = token.line;
close_brackets_column = token.column;
},
_ => continue
};
};
if loop_reference_count > 0 {
return Err(format!("un-closed loop at line {}, column {}.", open_brackets_line, open_brackets_column))
}
if loop_reference_count < 0 {
return Err(format!("closing the undefined loop at line {}, column {}.", close_brackets_line, close_brackets_column))
}
Ok(())
}