~cdv/loxen

ref: 2978e5f44798bf331f27dd7e3353e221af4d319b loxen/rs/src/vm.rs -rw-r--r-- 3.0 KiB
2978e5f4Chris Vittal [relox] Arithmetic expression parsing 1 year, 6 months ago
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
use std::convert::TryFrom;

use byteorder::{ReadBytesExt, LE};

use crate::chunk::*;
use crate::value::Value;
use crate::Error;

use OpCode::*;

pub fn interpret(source: &str) -> Result<(), Error> {
    let chunk = crate::compiler::compile(source)?;
    VM::interpret(chunk)
}

pub struct VM {
    chunk: Box<Chunk>,
    stack: Vec<Value>,
    ip: usize,
}

impl VM {
    fn interpret(chunk: Box<Chunk>) -> Result<(), Error> {
        let mut vm = Self {
            chunk,
            stack: Vec::with_capacity(65536),
            ip: 0,
        };

        vm.run()
    }

    fn run(&mut self) -> Result<(), Error> {
        macro_rules! binary_op {
            ($op:tt) => {
                let b = self.pop();
                let a = self.pop();
                self.push(a $op b);
            }
        }
        #[cfg(debug_assertions)]
        let mut prev_line = u32::MAX;
        loop {
            let op = self.read_op();
            #[cfg(debug_assertions)]
            {
                if !self.stack.is_empty() {
                    print!("          ");
                }
                for v in &self.stack {
                    print!("[ {} ]", v);
                }
                println!();
                op.disassemble(&self.chunk, self.ip - 1, &mut prev_line);
            }
            match op {
                Constant | ConstantLong => {
                    let v = self.read_constant(op);
                    self.push(v);
                }
                Negate => {
                    let v = self.pop();
                    self.push(-v);
                }
                Add => {
                    binary_op!(+);
                }
                Sub => {
                    binary_op!(-);
                }
                Mul => {
                    binary_op!(*);
                }
                Div => {
                    binary_op!(/);
                }
                Return => {
                    println!("{}", self.pop());
                    return Ok(());
                }
            }
        }
    }

    fn read_constant(&mut self, op: OpCode) -> Value {
        match op {
            Constant => {
                let cid = self.read_byte() as usize;
                self.chunk.constants[cid]
            }
            ConstantLong => {
                let nip = self.ip + 3;
                let mut cid_buf = &self.chunk[self.ip..nip];
                self.ip = nip;

                let cid = cid_buf.read_u24::<LE>().expect("cannot fail");
                self.chunk.constants[cid as usize]
            }
            _ => panic!("Invalid argument, {:?}", op),
        }
    }

    fn read_byte(&mut self) -> u8 {
        self.ip += 1;
        self.chunk[self.ip - 1]
    }

    fn read_op(&mut self) -> OpCode {
        OpCode::try_from(self.read_byte()).expect("Invalid Opcode")
    }

    fn push(&mut self, v: Value) {
        self.stack.push(v);
    }

    fn pop(&mut self) -> Value {
        self.stack.pop().expect("Attempted to pop from empty stack")
    }
}