dark_vm/
code.rs

1//! The Code struct maintains the values and the current position of the values vector.
2//! In the future, it should maintain labels, constants, and other information about the code.
3//! This Code struct is called internally and should not be called from the outside.
4
5use crate::{
6    errors::{error::Error, error_kind::ErrorKind},
7    tokens::{token::Token, token_kind::TokenKind},
8    values::value::Value,
9};
10use std::{
11    collections::{HashMap, VecDeque},
12    rc::Rc,
13};
14
15#[derive(Debug)]
16pub struct Code {
17    value_pointer: usize,
18    values: VecDeque<Rc<Value>>,
19    labels: HashMap<String, (usize, usize)>,
20}
21
22impl Code {
23    /// This constructs a new Code struct with the specified tokens.
24    /// Internally, the tokens are converted to reference counted values.
25    ///
26    /// # Arguments
27    /// `tokens` - The tokens from the lexer.
28    pub fn new(tokens: VecDeque<Token>) -> Result<Code, Error> {
29        let mut labels = HashMap::new();
30        let mut values = VecDeque::new();
31        let iter = tokens.into_iter().enumerate();
32        let mut label_stack = vec![];
33        for (pos, token) in iter {
34            match &token.kind {
35                TokenKind::Label(name) => {
36                    label_stack.push((pos, token.pos, name.to_owned()));
37                    values.push_back(Rc::new(token.into()));
38                },
39                TokenKind::End => {
40                    match label_stack.pop() {
41                        Some((last_start, last_pos, last_name)) => {
42                            if labels.insert(last_name, (last_start, pos)).is_some() {
43                                return Err(Error::new(ErrorKind::DuplicateLabel, last_pos));
44                            } else {
45                                values.push_back(Rc::new(token.into()));
46                            }
47                        },
48                        None => return Err(Error::new(ErrorKind::EndWithoutLabel, token.pos)),
49                    }
50                },
51                _ => values.push_back(Rc::new(token.into())),
52            };
53        }
54
55        if let Some((_, last_pos, _)) = label_stack.pop() {
56            Err(Error::new(ErrorKind::NoEndOfLabel, last_pos))
57        } else if let Some(&(value_pointer, _)) = labels.get(&"main".to_owned()) {
58            Ok(Code {
59                value_pointer: value_pointer + 1,
60                values,
61                labels,
62            })
63        } else {
64            Err(Error::message_only(ErrorKind::NoMainLabel))
65        }
66    }
67
68    /// This constructs a new Code struct with the specified tokens.
69    /// Internally, the tokens are converted to reference counted values.
70    /// Additionally, the Code struct does not check for a main label and instead starts at the first token.
71    ///
72    /// # Arguments
73    /// `tokens` - The tokens from the lexer.
74    pub fn repl(tokens: VecDeque<Token>) -> Result<Code, Error> {
75        let mut labels = HashMap::new();
76        let mut values = VecDeque::new();
77        let iter = tokens.into_iter().enumerate();
78        let mut label_stack = vec![];
79        for (pos, token) in iter {
80            match &token.kind {
81                TokenKind::Label(name) => {
82                    label_stack.push((pos, token.pos, name.to_owned()));
83                    values.push_back(Rc::new(token.into()));
84                },
85                TokenKind::End => {
86                    match label_stack.pop() {
87                        Some((last_start, last_pos, last_name)) => {
88                            if labels.insert(last_name, (last_start, pos)).is_some() {
89                                return Err(Error::new(ErrorKind::DuplicateLabel, last_pos));
90                            } else {
91                                values.push_back(Rc::new(token.into()));
92                            }
93                        },
94                        None => return Err(Error::new(ErrorKind::EndWithoutLabel, token.pos)),
95                    }
96                },
97                _ => values.push_back(Rc::new(token.into())),
98            };
99        }
100
101        Ok(
102            Code {
103                value_pointer: 0,
104                values,
105                labels,
106            }
107        )
108    }
109
110    /// This function updates the value_pointer to have the value of jump_location
111    /// if and only if jump_location is a valid index. Note that counting is 0-based.
112    ///
113    /// # Arguments
114    /// `jump_location` - The new value of value_pointer.
115    /// `pos` - The position where this was needed.
116    pub fn jump(&mut self, jump_location: i64, pos: usize) -> Option<Error> {
117        let upper_bound = self.values.len() as i64;
118        if jump_location >= 0 && jump_location <= upper_bound {
119            self.value_pointer = jump_location as usize;
120            None
121        } else {
122            Some(Error::new(
123                ErrorKind::OutOfBounds(0, self.values.len() + 1),
124                pos,
125            ))
126        }
127    }
128
129    /// This function updates the value_pointer by the value of jump_location
130    /// if and only if jump_location is a valid index. Note that counting is 0-based.
131    ///
132    /// # Arguments
133    /// `jump_location` - The new value of value_pointer.
134    /// `pos` - The position where this was needed.
135    pub fn relative_jump(&mut self, jump_location: i64, pos: usize) -> Option<Error> {
136        let lower_bound = -(self.value_pointer as i64);
137        let upper_bound = self.values.len() as i64;
138        if jump_location >= lower_bound && jump_location <= upper_bound {
139            self.value_pointer += jump_location as usize;
140            None
141        } else {
142            Some(Error::new(
143                ErrorKind::OutOfBounds(lower_bound as usize, self.values.len()),
144                pos,
145            ))
146        }
147    }
148
149    /// Sets the value pointer to the location of the label passed in. If the label name does not exist, an error is reported.
150    /// Additionally, it returns the position of the label.
151    ///
152    /// # Arguments
153    /// `label_name` - The name of the label.
154    /// `pos` - The position where this was needed.
155    pub fn set_label_location(&mut self, label_name: &String, pos: usize) -> Result<(usize, usize), Error> {
156        if let Some(&(label_pos_start, label_pos_end)) = self.labels.get(label_name) {
157            self.value_pointer = label_pos_start + 1;
158            Ok((label_pos_start, label_pos_end))
159        } else {
160            Err(Error::new(ErrorKind::UndefinedLabel, pos))
161        }
162    }
163
164    /// This function gets the start and end locations of the given label.
165    /// This function returns None if the label does not exist.
166    pub fn get_label_start_end(&self, label_name: &String) -> Option<(usize, usize)> {
167        self.labels.get(label_name).copied()
168    }
169
170    /// This function gets the current value of value pointer.
171    pub fn get_current_pos(&self) -> usize {
172        self.value_pointer
173    }
174
175    /// This function returns true if there are no more values in the Code struct.
176    pub fn is_finished(&self) -> bool {
177        self.value_pointer >= self.values.len()
178    }
179}
180
181impl Iterator for Code {
182    type Item = Rc<Value>;
183
184    fn next(&mut self) -> Option<Self::Item> {
185        self.value_pointer += 1;
186
187        // Cloning the object is cheap because it is reference counted.
188        self.values.get(self.value_pointer - 1).cloned()
189    }
190}