2023-03-29 21:15:41 +02:00
|
|
|
use std::convert::From;
|
2023-03-29 20:03:16 +02:00
|
|
|
use std::fmt;
|
|
|
|
|
|
2023-03-29 20:07:31 +02:00
|
|
|
#[repr(u8)]
|
2023-03-29 21:15:41 +02:00
|
|
|
#[derive(Copy, Clone, Debug)]
|
2023-03-29 20:07:31 +02:00
|
|
|
pub enum Op {
|
2023-03-29 21:15:41 +02:00
|
|
|
Return,
|
|
|
|
|
Constant { offset: usize },
|
|
|
|
|
}
|
|
|
|
|
|
2023-03-30 11:49:38 +02:00
|
|
|
#[derive(Copy, Clone)]
|
2023-03-29 21:15:41 +02:00
|
|
|
pub struct Value {
|
|
|
|
|
val: f64,
|
|
|
|
|
}
|
|
|
|
|
|
2023-03-30 11:49:38 +02:00
|
|
|
impl fmt::Debug for Value {
|
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
|
|
|
|
|
write!(f, "{}", self.val)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-03-29 21:15:41 +02:00
|
|
|
impl From<f64> for Value {
|
|
|
|
|
fn from(value: f64) -> Self {
|
|
|
|
|
Value { val: value }
|
|
|
|
|
}
|
2023-03-29 20:07:31 +02:00
|
|
|
}
|
|
|
|
|
|
2023-03-29 20:03:16 +02:00
|
|
|
pub struct Chunk {
|
|
|
|
|
code: Vec<Op>,
|
2023-03-29 21:15:41 +02:00
|
|
|
name: String,
|
|
|
|
|
debug_info: Vec<usize>,
|
|
|
|
|
constants: Vec<Value>,
|
2023-03-29 20:03:16 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Chunk {
|
2023-03-29 21:15:41 +02:00
|
|
|
pub fn new(name: String) -> Self {
|
2023-03-29 20:03:16 +02:00
|
|
|
Chunk {
|
|
|
|
|
code: Vec::new(),
|
2023-03-29 21:15:41 +02:00
|
|
|
name: name,
|
|
|
|
|
debug_info: Vec::new(),
|
|
|
|
|
constants: Vec::new(),
|
2023-03-29 20:03:16 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-03-29 21:15:41 +02:00
|
|
|
pub fn add_op(&mut self, op: Op, line: usize) {
|
|
|
|
|
self.code.push(op);
|
|
|
|
|
self.debug_info.push(line);
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn add_constant(&mut self, value: Value) {
|
|
|
|
|
self.constants.push(value);
|
2023-03-29 20:03:16 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl fmt::Debug for Chunk {
|
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
|
|
|
|
|
writeln!(f, "-*-*- {} -*-*-", self.name)?;
|
2023-03-29 21:15:41 +02:00
|
|
|
for (idx, op) in self.code.iter().copied().enumerate() {
|
|
|
|
|
write!(f, "{:04} ", idx)?;
|
|
|
|
|
|
|
|
|
|
let line = self.debug_info[idx];
|
|
|
|
|
|
|
|
|
|
if idx > 0 && self.debug_info[idx-1] == line {
|
2023-03-30 11:49:38 +02:00
|
|
|
write!(f, " | ")
|
2023-03-29 21:15:41 +02:00
|
|
|
} else {
|
2023-03-30 11:49:38 +02:00
|
|
|
write!(f, "{:4} ", line)
|
|
|
|
|
}?;
|
2023-03-29 21:15:41 +02:00
|
|
|
|
|
|
|
|
match op {
|
|
|
|
|
Op::Return => writeln!(f, "{:?}", op),
|
|
|
|
|
Op::Constant { offset } =>
|
|
|
|
|
f.debug_struct("Constant")
|
|
|
|
|
.field("val", &self.constants[offset].val)
|
|
|
|
|
.finish(),
|
|
|
|
|
}?;
|
2023-03-29 20:03:16 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return Ok(());
|
|
|
|
|
}
|
|
|
|
|
}
|
2023-03-30 11:49:38 +02:00
|
|
|
|
|
|
|
|
const VM_STACK_SIZE: usize = 256;
|
|
|
|
|
|
|
|
|
|
struct VM {
|
|
|
|
|
trace: bool,
|
|
|
|
|
stack: Vec<Value>,
|
|
|
|
|
code: Chunk
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
enum VMError {
|
|
|
|
|
Compile,
|
|
|
|
|
Runtime
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl VM {
|
|
|
|
|
fn push(&mut self, value: Value) {
|
|
|
|
|
self.stack.push(value);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn pop(&mut self) -> Value {
|
|
|
|
|
self.stack.pop().unwrap()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn interpret(&mut self, chunk: &Chunk) -> Result<(), VMError> {
|
|
|
|
|
for instr in chunk.code.iter().copied() {
|
|
|
|
|
if self.trace {
|
|
|
|
|
print!(" [");
|
|
|
|
|
for value in self.stack.iter() {
|
|
|
|
|
println!("{:?} | ", value);
|
|
|
|
|
}
|
|
|
|
|
println!("_ ]");
|
|
|
|
|
|
|
|
|
|
println!("{:?}", instr);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
match instr {
|
|
|
|
|
Op::Return => {
|
|
|
|
|
print!("{:?}", self.pop());
|
|
|
|
|
return Ok(())
|
|
|
|
|
},
|
|
|
|
|
Op::Constant { offset } => {
|
|
|
|
|
self.push(self.code.constants[offset])
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return Ok(())
|
|
|
|
|
}
|
|
|
|
|
}
|