use std::fmt;
use builder::Builder;
use table::Table;
mod to_byte_code;
mod from_byte_code;
mod debug;
pub struct Code<T> {
pub symbols: Vec<(usize, String)>,
pub code: Vec<usize>,
pub data: Vec<T>,
pub labels: Vec<(usize, String)>
}
impl<T: fmt::Debug> Code<T> {
pub fn from_builder(builder: Builder<T>) -> Code<T> {
let symbols = builder.instruction_table.symbols();
let code = builder.instructions;
let data = builder.data;
let mut labels = vec![];
for key in builder.labels.keys() {
let idx = builder.labels.get(key).unwrap();
labels.push((*idx, key.clone()));
}
labels.sort_by(|lhs, rhs| {
lhs.0.cmp(&rhs.0)
});
Code {
symbols: symbols,
code: code,
data: data,
labels: labels
}
}
pub fn empty() -> Code<T> {
Code {
symbols: vec![],
code: vec![],
data: vec![],
labels: vec![]
}
}
pub fn symbols(&self) -> &[(usize, String)] {
self.symbols.as_slice()
}
pub fn code(&self) -> &[usize] {
self.code.as_slice()
}
pub fn data(&self) -> &[T] {
self.data.as_slice()
}
pub fn labels(&self) -> &[(usize, String)] {
self.labels.as_slice()
}
pub fn get_label_ip(&self, name: &str) -> Option<usize> {
for label in self.labels.as_slice() {
if label.1 == name { return Some(label.0); }
}
None
}
}
#[cfg(test)]
mod test {
use super::*;
use rmp::{encode, decode};
use std::io::{Read, Write};
use instruction::Instruction;
use instruction_table::InstructionTable;
use machine::Machine;
use to_byte_code::ToByteCode;
use from_byte_code::FromByteCode;
impl ToByteCode for usize {
fn to_byte_code(&self, mut buf: &mut Write) {
encode::write_uint(&mut buf, *self as u64).unwrap();
}
}
impl FromByteCode for usize {
fn from_byte_code(mut buf: &mut Read) -> usize {
decode::read_int(&mut buf).unwrap()
}
}
fn noop(_machine: &mut Machine<usize>, _args: &[usize]) {}
fn example_instruction_table() -> InstructionTable<usize> {
let mut it = InstructionTable::new();
it.insert(Instruction::new(0, "noop", 0, noop));
it.insert(Instruction::new(1, "push", 1, noop));
it.insert(Instruction::new(2, "pop", 0, noop));
it
}
#[test]
fn from_builder() {
let it = example_instruction_table();
let mut builder: Builder<usize> = Builder::new(&it);
builder.push("push", vec![13]);
builder.push("push", vec![14]);
let code: Code<usize> = Code::from_builder(builder);
assert_eq!(code.symbols().len(), 3);
assert_eq!(code.symbols()[0], (0 as usize, "noop".to_string()));
assert_eq!(code.symbols()[1], (1 as usize, "push".to_string()));
assert_eq!(code.symbols()[2], (2 as usize, "pop".to_string()));
assert_eq!(code.code(), [1, 1, 0, 1, 1, 1]);
assert_eq!(code.data(), [13, 14]);
assert_eq!(code.labels().len(), 1);
assert_eq!(code.labels()[0], (0 as usize, "main".to_string()));
}
#[test]
fn get_label_ip() {
let it = example_instruction_table();
let builder: Builder<usize> = Builder::new(&it);
let code: Code<usize> = Code::from_builder(builder);
assert_eq!(code.get_label_ip("main").unwrap(), 0);
}
#[test]
fn debug_formatter() {
let it = example_instruction_table();
let mut builder: Builder<usize> = Builder::new(&it);
builder.push("noop", vec![]);
builder.push("push", vec![123]);
builder.push("push", vec![456]);
builder.label("some_function");
builder.push("pop", vec![]);
let code = Code::from_builder(builder);
let actual = format!("{:?}", code);
let expected = "@0 = 123
@1 = 456
.main:
\tnoop
\tpush @0
\tpush @1
.some_function:
\tpop
";
assert_eq!(actual, expected);
}
#[test]
fn to_byte_code() {
let it = example_instruction_table();
let mut builder: Builder<usize> = Builder::new(&it);
builder.push("noop", vec![]);
builder.push("push", vec![123]);
builder.push("push", vec![456]);
builder.label("some_function");
builder.push("pop", vec![]);
let code = Code::from_builder(builder);
let mut actual: Vec<u8> = vec![];
code.to_byte_code(&mut actual);
let expected = [132, 164, 99, 111, 100, 101, 154, 0, 0, 1, 1, 0, 1, 1,
1, 2, 0, 164, 100, 97, 116, 97, 146, 123, 205, 1, 200,
167, 115, 121, 109, 98, 111, 108, 115, 150, 0, 164,
110, 111, 111, 112, 1, 164, 112, 117, 115, 104, 2, 163,
112, 111, 112, 166, 108, 97, 98, 101, 108, 115, 148, 0,
164, 109, 97, 105, 110, 8, 173, 115, 111, 109, 101, 95,
102, 117, 110, 99, 116, 105, 111, 110];
assert_eq!(&actual[..], &expected[..]);
}
#[test]
fn from_byte_code() {
let bytecode: [u8; 82] = [132, 164, 99, 111, 100, 101, 154, 0, 0, 1, 1, 0, 1, 1,
1, 2, 0, 164, 100, 97, 116, 97, 146, 123, 205, 1, 200,
167, 115, 121, 109, 98, 111, 108, 115, 150, 0, 164,
110, 111, 111, 112, 1, 164, 112, 117, 115, 104, 2, 163,
112, 111, 112, 166, 108, 97, 98, 101, 108, 115, 148, 0,
164, 109, 97, 105, 110, 8, 173, 115, 111, 109, 101, 95,
102, 117, 110, 99, 116, 105, 111, 110];
let code: Code<usize> = Code::from_byte_code(&mut &bytecode[..]);
assert_eq!(code.code, [0x0, 0x0, 0x1, 0x1, 0x0, 0x1, 0x1, 0x1, 0x2, 0x0]);
assert_eq!(code.data, [123, 456]);
assert_eq!(code.symbols, [(0 as usize, "noop".to_string()), (1 as usize, "push".to_string()), (2 as usize, "pop".to_string())]);
assert_eq!(code.labels, [(0 as usize, "main".to_string()), (8 as usize, "some_function".to_string())])
}
}