1use std::{fmt::Display, rc::Rc};
4
5use crate::{
6 compiler::{
7 BuiltinFn, Env, ExprByteCode,
8 lookup::{BUILTIN, PROMPT, SECRET, VAR},
9 opcode,
10 },
11 errors::ExprResult,
12 prelude::lookup::USER_BUILTIN,
13};
14
15#[derive(Debug, Clone, PartialEq)]
16pub enum Value {
17 String(String),
18 Fn(Rc<BuiltinFn>),
19 Bool(bool),
20}
21
22impl Value {
23 pub fn get_string(&self) -> &str {
24 match self {
25 Value::String(s) => s.as_str(),
26 _ => panic!("Value is not a string"),
27 }
28 }
29
30 pub fn get_func(&self) -> Rc<BuiltinFn> {
31 match self {
32 Value::Fn(f) => f.clone(),
33 _ => panic!("Value is not a function"),
34 }
35 }
36
37 pub fn get_bool(&self) -> bool {
38 match self {
39 Value::Bool(s) => s.clone(),
40 _ => panic!("Value is not a string"),
41 }
42 }
43}
44
45impl From<&str> for Value {
46 fn from(s: &str) -> Self {
47 Value::String(s.to_string())
48 }
49}
50
51impl Display for Value {
52 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
53 match self {
54 Value::String(string) => write!(f, "`{}`", string),
55 Value::Fn(builtin) => write!(f, "{builtin:?}"),
56 Value::Bool(value) => write!(f, "{}", value),
57 }
58 }
59}
60
61#[derive(Debug, Clone, Default)]
62pub struct RuntimeEnv {
63 pub vars: Vec<String>,
64 pub prompts: Vec<String>,
65 pub secrets: Vec<String>,
66}
67
68#[derive(Debug)]
69pub struct Vm {
70 bytecode: Option<Box<ExprByteCode>>,
71 ip: usize,
72 stack: Vec<Value>,
73}
74
75impl Vm {
76 pub fn new() -> Self {
77 Self {
78 bytecode: None,
79 ip: 0,
80 stack: vec![],
81 }
82 }
83
84 pub fn interpret(
85 &mut self,
86 bytecode: Box<ExprByteCode>,
87 env: &Env,
88 runtime_env: &RuntimeEnv,
89 ) -> ExprResult<Value> {
90 self.bytecode = Some(bytecode.into());
91 self.ip = 0;
92
93 while let Some(op_code) = self
94 .bytecode
95 .as_ref()
96 .and_then(|bc| bc.codes().get(self.ip))
97 {
98 self.interpret_op(env, runtime_env, *op_code);
99 }
100
101 assert_eq!(1, self.stack.len());
102
103 let value = self.stack_pop();
104
105 Ok(value)
106 }
107
108 fn interpret_op(&mut self, env: &Env, runtime_env: &RuntimeEnv, op_code: u8) {
109 match op_code {
110 opcode::CALL => self.op_call(),
111 opcode::CONSTANT => self.op_constant(),
112 opcode::GET => self.op_get(env, &runtime_env),
113 opcode::TRUE => self.op_true(),
114 opcode::FALSE => self.op_false(),
115 _ => panic!("Invalid OP code: {op_code}"),
116 }
117 }
118
119 fn op_call(&mut self) {
120 assert_eq!(opcode::CALL, self.read_u8(), "Expected CALL opcode");
122
123 let arg_count = self.read_u8() as usize;
124
125 let mut args: Vec<Value> = vec![];
126
127 for _ in 0..arg_count {
128 args.push(self.stack_pop());
129 }
130
131 args.reverse();
132
133 let value = self.stack_pop();
134
135 let builtin = value.get_func().func.clone();
136
137 let result = builtin(args);
138
139 self.stack_push(result);
140 }
141
142 fn op_get(&mut self, env: &Env, runtime_env: &RuntimeEnv) {
143 assert_eq!(opcode::GET, self.read_u8(), "Expected GET opcode");
144 let get_lookup = self.read_u8();
145 let get_idx = self.read_u8() as usize;
146
147 match get_lookup {
148 BUILTIN => {
149 let value = env
150 .get_builtin(get_idx)
151 .expect(&format! {"undefined builtin: {get_idx}"});
152 self.stack_push(Value::Fn(value.clone()));
153 }
154 USER_BUILTIN => {
155 let value = env
156 .get_user_builtin(get_idx)
157 .expect(&format! {"undefined user builtin: {get_idx}"});
158 self.stack_push(Value::Fn(value.clone()));
159 }
160 VAR => {
161 let value = env
162 .get_var(get_idx)
163 .and_then(|_| runtime_env.vars.get(get_idx))
164 .expect(&format! {"undefined variable: {get_idx}"});
165
166 self.stack_push(Value::String(value.clone()));
167 }
168 PROMPT => {
169 let value = env
170 .get_prompt(get_idx)
171 .and_then(|_| runtime_env.prompts.get(get_idx))
172 .expect(&format! {"undefined prompt: {get_idx}"});
173
174 self.stack_push(Value::String(value.clone()));
175 }
176 SECRET => {
177 let value = env
178 .get_secret(get_idx)
179 .and_then(|_| runtime_env.secrets.get(get_idx))
180 .expect(&format! {"undefined secret: {get_idx}"});
181
182 self.stack_push(Value::String(value.clone()));
183 }
184 _ => panic!("invalid get lookup code: {}", get_lookup),
185 };
186 }
187
188 fn op_constant(&mut self) {
189 assert_eq!(opcode::CONSTANT, self.read_u8(), "Expected CONSTANT opcode");
190
191 let get_idx = self.read_u8() as usize;
192
193 let s = self
194 .bytecode
195 .as_ref()
196 .expect("should have bytecode")
197 .strings()
198 .get(get_idx)
199 .expect(&format!("undefined string: {}", get_idx));
200
201 self.stack_push(Value::String(s.clone()));
202 }
203
204 fn op_true(&mut self) {
205 assert_eq!(opcode::TRUE, self.read_u8(), "Expected TRUE opcode");
206
207 self.stack_push(Value::Bool(true));
208 }
209
210 fn op_false(&mut self) {
211 assert_eq!(opcode::FALSE, self.read_u8(), "Expected FALSE opcode");
212
213 self.stack_push(Value::Bool(false));
214 }
215
216 fn stack_push(&mut self, value: Value) {
217 self.stack.push(value);
218 }
219
220 fn stack_pop(&mut self) -> Value {
221 let value = self
222 .stack
223 .pop()
224 .expect("should have a value to pop from the stack");
225
226 value
227 }
228
229 fn read_u8(&mut self) -> u8 {
230 let current_ip = (self.ip as u8).clone();
231
232 self.ip += 1;
233
234 self.bytecode
235 .as_ref()
236 .expect("should have bytecode")
237 .codes()
238 .get(current_ip as usize)
239 .expect("should have op in bytecode at {}")
240 .clone()
241 }
242}