use crate::{
errors::{error::Error, error_kind::ErrorKind},
tokens::{token::Token, token_kind::TokenKind},
values::value::Value,
};
use std::{
collections::{HashMap, VecDeque},
rc::Rc,
};
#[derive(Debug)]
pub struct Code {
value_pointer: usize,
values: VecDeque<Rc<Value>>,
labels: HashMap<String, (usize, usize)>,
}
impl Code {
pub fn new(tokens: VecDeque<Token>) -> Result<Code, Error> {
let mut labels = HashMap::new();
let mut values = VecDeque::new();
let iter = tokens.into_iter().enumerate();
let mut label_stack = vec![];
for (pos, token) in iter {
match &token.kind {
TokenKind::Label(name) => {
label_stack.push((pos, token.pos, name.to_owned()));
values.push_back(Rc::new(token.into()));
},
TokenKind::End => {
match label_stack.pop() {
Some((last_start, last_pos, last_name)) => {
if labels.insert(last_name, (last_start, pos)).is_some() {
return Err(Error::new(ErrorKind::DuplicateLabel, last_pos));
} else {
values.push_back(Rc::new(token.into()));
}
},
None => return Err(Error::new(ErrorKind::EndWithoutLabel, token.pos)),
}
},
_ => values.push_back(Rc::new(token.into())),
};
}
if let Some((_, last_pos, _)) = label_stack.pop() {
Err(Error::new(ErrorKind::NoEndOfLabel, last_pos))
} else if let Some(&(value_pointer, _)) = labels.get(&"main".to_owned()) {
Ok(Code {
value_pointer: value_pointer + 1,
values,
labels,
})
} else {
Err(Error::message_only(ErrorKind::NoMainLabel))
}
}
pub fn repl(tokens: VecDeque<Token>) -> Result<Code, Error> {
let mut labels = HashMap::new();
let mut values = VecDeque::new();
let iter = tokens.into_iter().enumerate();
let mut label_stack = vec![];
for (pos, token) in iter {
match &token.kind {
TokenKind::Label(name) => {
label_stack.push((pos, token.pos, name.to_owned()));
values.push_back(Rc::new(token.into()));
},
TokenKind::End => {
match label_stack.pop() {
Some((last_start, last_pos, last_name)) => {
if labels.insert(last_name, (last_start, pos)).is_some() {
return Err(Error::new(ErrorKind::DuplicateLabel, last_pos));
} else {
values.push_back(Rc::new(token.into()));
}
},
None => return Err(Error::new(ErrorKind::EndWithoutLabel, token.pos)),
}
},
_ => values.push_back(Rc::new(token.into())),
};
}
Ok(
Code {
value_pointer: 0,
values,
labels,
}
)
}
pub fn jump(&mut self, jump_location: i64, pos: usize) -> Option<Error> {
let upper_bound = self.values.len() as i64;
if jump_location >= 0 && jump_location <= upper_bound {
self.value_pointer = jump_location as usize;
None
} else {
Some(Error::new(
ErrorKind::OutOfBounds(0, self.values.len() + 1),
pos,
))
}
}
pub fn relative_jump(&mut self, jump_location: i64, pos: usize) -> Option<Error> {
let lower_bound = -(self.value_pointer as i64);
let upper_bound = self.values.len() as i64;
if jump_location >= lower_bound && jump_location <= upper_bound {
self.value_pointer += jump_location as usize;
None
} else {
Some(Error::new(
ErrorKind::OutOfBounds(lower_bound as usize, self.values.len()),
pos,
))
}
}
pub fn set_label_location(&mut self, label_name: &String, pos: usize) -> Result<(usize, usize), Error> {
if let Some(&(label_pos_start, label_pos_end)) = self.labels.get(label_name) {
self.value_pointer = label_pos_start + 1;
Ok((label_pos_start, label_pos_end))
} else {
Err(Error::new(ErrorKind::UndefinedLabel, pos))
}
}
pub fn get_label_start_end(&self, label_name: &String) -> Option<(usize, usize)> {
self.labels.get(label_name).copied()
}
pub fn get_current_pos(&self) -> usize {
self.value_pointer
}
pub fn is_finished(&self) -> bool {
self.value_pointer >= self.values.len()
}
}
impl Iterator for Code {
type Item = Rc<Value>;
fn next(&mut self) -> Option<Self::Item> {
self.value_pointer += 1;
self.values.get(self.value_pointer - 1).cloned()
}
}