~starkingdoms/starkingdoms

ref: cd7053cdc98554b3e38dba6927a0e00d411b49ad starkingdoms/kabel/src/vm.rs -rw-r--r-- 3.5 KiB
cd7053cd — ghostly_zsh codegen and also functioning strings 1 year, 4 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
use crate::{mismatched_types, runtime_error::KabelRuntimeError, wrong_type};

pub struct VM {
    ip: usize,
    pub chunk: Vec<u8>,
    pub stack: Vec<Value>,
    pub pool: Vec<Value>,
    pub lines: Vec<(usize, usize)>, // line #, repeats number of instructions
    text: Vec<String>
}

impl VM {
    pub fn new(bytecode: Vec<u8>, lines: Vec<(usize, usize)>, pool: Vec<Value>, text: String) -> Self {
        Self {
            ip: 0,
            chunk: bytecode,
            stack: Vec::new(),
            pool,
            lines,
            text: text.lines().map(|s| s.to_string()).collect(),
        }
    }
    pub fn run(&mut self) -> Result<(), KabelRuntimeError> {
        use Value::*;
        while self.ip < self.chunk.len() {
            match self.read() {
                0x00 => { // CONSTANT
                    let byte = self.read() as usize;
                    self.stack.push(self.pool[byte].clone());
                }
                0x01 => { // ADD
                    match (self.stack.pop().unwrap(), self.stack.pop().unwrap()) {
                        (Num(v1), Num(v2)) => self.stack.push(Num(v1 + v2)),
                        (Str(v1), Str(v2)) => {
                            self.stack.push(Str(v1 + &v2));
                        },
                        (Bool(_v1), Bool(_v2)) => {
                            return Err(wrong_type!(self, "Cannot add booleans"))
                        }
                        (v1, v2) => {
                            return Err(mismatched_types!(self, "Mismatched types: {} and {}", v1.type_str(), v2.type_str()))
                        }
                    }
                }
                0x02 => { // SUB
                    match (self.stack.pop().unwrap(), self.stack.pop().unwrap()) {
                        (Num(v1), Num(v2)) => self.stack.push(Num(v1 - v2)),
                        (Str(_v1), Str(_v2)) => {
                            return Err(wrong_type!(self, "Cannot subtract strings"))
                        },
                        (Bool(_v1), Bool(_v2)) => {
                            return Err(wrong_type!(self, "Cannot subtract booleans"))
                        }
                        (v1, v2) => {
                            return Err(mismatched_types!(self, "Mismatched types: {} and {}", v1.type_str(), v2.type_str()))
                        }
                    }
                }

                0xFE => { // PRINT
                    let value = self.stack.pop().unwrap();
                    match value {
                        Num(v) => println!("{}", v),
                        Str(v) => println!("{}", v.to_string()),
                        Bool(v) => println!("{}", v),
                    }
                }
                _ => {}
            }
        }
        Ok(())
    }
    pub fn read(&mut self) -> u8 {
        let byte = self.chunk[self.ip];
        self.ip += 1;
        byte
    }
    pub fn find_line(&mut self) -> usize { // returns line # at ip
        let mut line_ip = 0;
        for (line, rep) in self.lines.clone() {
            if line_ip + rep > self.ip {
                return line;
            }
            line_ip += rep;
        }
        panic!("Something went wrong in finding line for error")
    }
}

#[derive(Debug, Clone)]
pub enum Value {
    Num(f32), Str(String), Bool(bool),
}

impl Value {
    pub fn type_str(&self) -> String {
        match self {
            Value::Num(_) => "number".to_string(),
            Value::Str(_) => "string".to_string(),
            Value::Bool(_) => "bool".to_string(),
        }
    }
}