stack_vm/code/
mod.rs

1//! Code
2//!
3//! This module represents a hunk of code ready to be executed by the VM.
4//! Code can be created in one of two ways:
5//!
6//! * From an instance of a `Builder`.
7//! * From dumped bytecode.
8//!
9//! ## Creating code from a Builder:
10//!
11//! ```
12//! # use stack_vm::{Machine, Instruction, InstructionTable, Code, Builder};
13//!
14//! #[derive(Debug, PartialEq)]
15//! struct Operand(i64);
16//!
17//! fn example_noop(_machine: &mut Machine<Operand>, _args: &[usize]) {}
18//!
19//! # fn main() {
20//! let mut instruction_table = InstructionTable::new();
21//! instruction_table.insert(Instruction::new(1, "push", 1, example_noop));
22//!
23//! let mut builder: Builder<Operand> = Builder::new(&instruction_table);
24//! builder.push("push", vec![Operand(13)]);
25//! builder.push("push", vec![Operand(14)]);
26//!
27//! Code::from(builder);
28//! # }
29//! ```
30//!
31//! ## Creating code from bytecode
32//!
33//! Loading bytecode is pretty straight-forward.  Note that you must implement
34//! `FromByteCode` for your Operand type however.
35//!
36//! ```
37//! # extern crate stack_vm;
38//! # extern crate rmp;
39//! # use stack_vm::{Code, FromByteCode};
40//! # use std::io::Read;
41//!
42//! #[derive(Debug)]
43//! struct Operand(i64);
44//!
45//! impl FromByteCode for Operand {
46//!     fn from_byte_code(mut buf: &mut Read) -> Operand {
47//!         let value = rmp::decode::read_int(&mut buf).unwrap();
48//!         Operand(value)
49//!     }
50//! }
51//!
52//! # fn main() {
53//! let bytecode: [u8; 30] = [132, 164, 99, 111, 100, 101, 144, 164, 100, 97, 116, 97, 144, 167, 115, 121, 109, 98, 111, 108, 115, 144, 166, 108, 97, 98, 101, 108, 115, 144];
54//! let _code: Code<Operand> = Code::from_byte_code(&mut &bytecode[..]);
55//! # }
56//! ```
57//!
58//! ## Dumping code to bytecode
59//!
60//! Dumping your code to bytecode is also very straight-forward.  You will need
61//! to implement the `ToByteCode` trait on your Operand type.
62//!
63//! ```
64//! # extern crate rmp;
65//! # extern crate stack_vm;
66//! # use stack_vm::{Code, ToByteCode};
67//! # use std::io::Write;
68//!
69//! #[derive(Debug, PartialEq)]
70//! struct Operand(i64);
71//!
72//! impl ToByteCode for Operand {
73//!     fn to_byte_code(&self, mut buf: &mut Write) {
74//!         rmp::encode::write_sint(&mut buf, self.0).unwrap();
75//!     }
76//! }
77//!
78//! # fn main() {
79//! let code: Code<Operand> = Code::empty();
80//! let mut bytecode: Vec<u8> = vec![];
81//! code.to_byte_code(&mut bytecode);
82//! assert_eq!(&bytecode[..], [132, 164, 99, 111, 100, 101, 144, 164, 100, 97, 116, 97, 144, 167, 115, 121, 109, 98, 111, 108, 115, 144, 166, 108, 97, 98, 101, 108, 115, 144]);
83//! # }
84//! ```
85
86use crate::builder::Builder;
87use crate::table::Table;
88use std::convert::From;
89use std::fmt;
90mod debug;
91mod from_byte_code;
92mod to_byte_code;
93
94/// A structure containing runnable or dumpable code.
95///
96/// See the module-level docs for more details.
97pub struct Code<T> {
98    pub symbols: Vec<(usize, String)>,
99    pub code: Vec<usize>,
100    pub data: Vec<T>,
101    pub labels: Vec<(usize, String)>,
102}
103
104impl<T: fmt::Debug> Code<T> {
105    /// Create an empty code.
106    ///
107    /// Not useful for anything except tests and documentation.
108    pub fn empty() -> Code<T> {
109        Code {
110            symbols: vec![],
111            code: vec![],
112            data: vec![],
113            labels: vec![],
114        }
115    }
116
117    /// Retrieve a list of all symbols in the code.
118    ///
119    /// This is a list of tuples containing op codes and instruction names.
120    pub fn symbols(&self) -> &[(usize, String)] {
121        self.symbols.as_slice()
122    }
123
124    /// Retrieve a list of instructions in the code.
125    ///
126    /// This is the executable source program of the code.  It is a simple
127    /// format based around the following:
128    ///
129    /// ```text
130    /// | Op Code | No of args | Args ...         |
131    /// | 0x01    | 0x03       | 0x01, 0x02, 0x03 |
132    /// ```
133    pub fn code(&self) -> &[usize] {
134        self.code.as_slice()
135    }
136
137    /// Retrieve the constant data compiled into the code.
138    pub fn data(&self) -> &[T] {
139        self.data.as_slice()
140    }
141
142    /// Retrieve a list of labels used in the program.
143    ///
144    /// Returns a list of tuples containing the IP of the label and the name of
145    /// the label.
146    pub fn labels(&self) -> &[(usize, String)] {
147        self.labels.as_slice()
148    }
149
150    /// Returns the IP for a given label.
151    ///
152    /// This function is used within the `Machine` to perform jumps.
153    pub fn get_label_ip(&self, name: &str) -> Option<usize> {
154        for label in self.labels.as_slice() {
155            if label.1 == name {
156                return Some(label.0);
157            }
158        }
159        None
160    }
161}
162
163impl<'a, T: fmt::Debug + PartialEq> From<Builder<'a, T>> for Code<T> {
164    /// Convert a `Builder` into `Code`.
165    ///
166    /// This function consumes the builder and returns a `Code`.
167    fn from(builder: Builder<T>) -> Code<T> {
168        let symbols = builder.instruction_table.symbols();
169        let code = builder.instructions;
170        let data = builder.data;
171        let mut labels = vec![];
172        for key in builder.labels.keys() {
173            let idx = builder.labels.get(&key).unwrap();
174            labels.push((*idx, key.clone()));
175        }
176        labels.sort_by(|lhs, rhs| lhs.0.cmp(&rhs.0));
177
178        Code {
179            symbols,
180            code,
181            data,
182            labels,
183        }
184    }
185}
186
187#[cfg(test)]
188mod test {
189    use super::*;
190    use crate::from_byte_code::FromByteCode;
191    use crate::instruction::Instruction;
192    use crate::instruction_table::InstructionTable;
193    use crate::machine::Machine;
194    use crate::to_byte_code::ToByteCode;
195    use rmp::{decode, encode};
196    use std::io::{Read, Write};
197
198    impl ToByteCode for usize {
199        fn to_byte_code(&self, mut buf: &mut Write) {
200            encode::write_uint(&mut buf, *self as u64).unwrap();
201        }
202    }
203
204    impl FromByteCode for usize {
205        fn from_byte_code(mut buf: &mut Read) -> usize {
206            decode::read_int(&mut buf).unwrap()
207        }
208    }
209
210    fn noop(_machine: &mut Machine<usize>, _args: &[usize]) {}
211
212    fn example_instruction_table() -> InstructionTable<usize> {
213        let mut it = InstructionTable::new();
214        it.insert(Instruction::new(0, "noop", 0, noop));
215        it.insert(Instruction::new(1, "push", 1, noop));
216        it.insert(Instruction::new(2, "pop", 0, noop));
217        it
218    }
219
220    #[test]
221    fn from_builder() {
222        let it = example_instruction_table();
223        let mut builder: Builder<usize> = Builder::new(&it);
224        builder.push("push", vec![13]);
225        builder.push("push", vec![14]);
226        let code: Code<usize> = Code::from(builder);
227
228        assert_eq!(code.symbols().len(), 3);
229        assert_eq!(code.symbols()[0], (0 as usize, "noop".to_string()));
230        assert_eq!(code.symbols()[1], (1 as usize, "push".to_string()));
231        assert_eq!(code.symbols()[2], (2 as usize, "pop".to_string()));
232
233        assert_eq!(code.code(), [1, 1, 0, 1, 1, 1]);
234        assert_eq!(code.data(), [13, 14]);
235        assert_eq!(code.labels().len(), 1);
236        assert_eq!(code.labels()[0], (0 as usize, "main".to_string()));
237    }
238
239    #[test]
240    fn get_label_ip() {
241        let it = example_instruction_table();
242        let builder: Builder<usize> = Builder::new(&it);
243        let code: Code<usize> = Code::from(builder);
244        assert_eq!(code.get_label_ip("main").unwrap(), 0);
245    }
246
247    #[test]
248    fn debug_formatter() {
249        let it = example_instruction_table();
250        let mut builder: Builder<usize> = Builder::new(&it);
251        builder.push("noop", vec![]);
252        builder.push("push", vec![123]);
253        builder.push("push", vec![456]);
254        builder.label("some_function");
255        builder.push("pop", vec![]);
256        let code = Code::from(builder);
257
258        let actual = format!("{:?}", code);
259        let expected = "@0 = 123
260@1 = 456
261
262.main:
263\tnoop
264\tpush @0
265\tpush @1
266
267.some_function:
268\tpop
269";
270        assert_eq!(actual, expected);
271    }
272
273    #[test]
274    fn to_byte_code() {
275        let it = example_instruction_table();
276        let mut builder: Builder<usize> = Builder::new(&it);
277        builder.push("noop", vec![]);
278        builder.push("push", vec![123]);
279        builder.push("push", vec![456]);
280        builder.label("some_function");
281        builder.push("pop", vec![]);
282        let code = Code::from(builder);
283        let mut actual: Vec<u8> = vec![];
284        code.to_byte_code(&mut actual);
285        let expected = [
286            132, 164, 99, 111, 100, 101, 154, 0, 0, 1, 1, 0, 1, 1, 1, 2, 0, 164, 100, 97, 116, 97,
287            146, 123, 205, 1, 200, 167, 115, 121, 109, 98, 111, 108, 115, 150, 0, 164, 110, 111,
288            111, 112, 1, 164, 112, 117, 115, 104, 2, 163, 112, 111, 112, 166, 108, 97, 98, 101,
289            108, 115, 148, 0, 164, 109, 97, 105, 110, 8, 173, 115, 111, 109, 101, 95, 102, 117,
290            110, 99, 116, 105, 111, 110,
291        ];
292        assert_eq!(&actual[..], &expected[..]);
293    }
294
295    #[test]
296    fn from_byte_code() {
297        let bytecode: [u8; 82] = [
298            132, 164, 99, 111, 100, 101, 154, 0, 0, 1, 1, 0, 1, 1, 1, 2, 0, 164, 100, 97, 116, 97,
299            146, 123, 205, 1, 200, 167, 115, 121, 109, 98, 111, 108, 115, 150, 0, 164, 110, 111,
300            111, 112, 1, 164, 112, 117, 115, 104, 2, 163, 112, 111, 112, 166, 108, 97, 98, 101,
301            108, 115, 148, 0, 164, 109, 97, 105, 110, 8, 173, 115, 111, 109, 101, 95, 102, 117,
302            110, 99, 116, 105, 111, 110,
303        ];
304        let code: Code<usize> = Code::from_byte_code(&mut &bytecode[..]);
305        assert_eq!(
306            code.code,
307            [0x0, 0x0, 0x1, 0x1, 0x0, 0x1, 0x1, 0x1, 0x2, 0x0]
308        );
309        assert_eq!(code.data, [123, 456]);
310        assert_eq!(
311            code.symbols,
312            [
313                (0 as usize, "noop".to_string()),
314                (1 as usize, "push".to_string()),
315                (2 as usize, "pop".to_string())
316            ]
317        );
318        assert_eq!(
319            code.labels,
320            [
321                (0 as usize, "main".to_string()),
322                (8 as usize, "some_function".to_string())
323            ]
324        )
325    }
326}