1use crate::{
4 compiler::{
5 CompileTimeEnv, ExprByteCode,
6 lookup::{BUILTIN, PROMPT, SECRET, VAR},
7 opcode,
8 },
9 errors::{ExprErrorS, ExprResult, RuntimeError},
10 prelude::lookup::{CLIENT_CTX, USER_BUILTIN},
11 value::Value,
12};
13
14#[derive(Debug, Clone, Default)]
15pub struct RuntimeEnv {
16 pub vars: Vec<String>,
17 pub prompts: Vec<String>,
18 pub secrets: Vec<String>,
19 pub client_context: Vec<Value>,
20}
21
22impl RuntimeEnv {
23 pub fn add_to_client_context(&mut self, index: usize, value: Value) {
24 if index < self.client_context.len() {
25 self.client_context[index] = value;
26 } else {
27 self.client_context.push(value);
28 }
29 }
30}
31
32#[derive(Debug)]
33pub struct Vm {
34 bytecode: Option<Box<ExprByteCode>>,
35 ip: usize,
36 stack: Vec<Value>,
37}
38
39impl Vm {
40 pub fn new() -> Self {
41 Self {
42 bytecode: None,
43 ip: 0,
44 stack: vec![],
45 }
46 }
47
48 pub fn interpret(
49 &mut self,
50 bytecode: Box<ExprByteCode>,
51 env: &CompileTimeEnv,
52 runtime_env: &RuntimeEnv,
53 ) -> ExprResult<Value> {
54 self.bytecode = Some(bytecode);
55 self.ip = 0;
56
57 let mut errs: Vec<ExprErrorS> = vec![];
58
59 while let Some(op_code) = self
60 .bytecode
61 .as_ref()
62 .and_then(|bc| bc.codes().get(self.ip))
63 {
64 if let Err(e) = self.interpret_op(env, runtime_env, *op_code) {
65 errs.extend(e);
66 }
67 }
68
69 if !errs.is_empty() {
70 return Err(errs.into());
71 }
72
73 self.stack_pop()
74 }
75
76 fn interpret_op(
77 &mut self,
78 env: &CompileTimeEnv,
79 runtime_env: &RuntimeEnv,
80 op_code: u8,
81 ) -> ExprResult<()> {
82 match op_code {
83 opcode::CALL => self.op_call(),
84 opcode::CONSTANT => self.op_constant(),
85 opcode::GET => self.op_get(env, runtime_env),
86 opcode::TRUE => self.op_true(),
87 opcode::FALSE => self.op_false(),
88 opcode::NOT => self.op_not(),
89 opcode::EQ => self.op_eq(),
90 opcode::TYPE => self.op_type(),
91 _ => panic!("Invalid OP code: {op_code}"),
92 }
93 }
94
95 fn op_call(&mut self) -> ExprResult<()> {
96 assert_eq!(opcode::CALL, self.read_u8(), "Expected CALL opcode");
98
99 let arg_count = self.read_u8() as usize;
100
101 let mut args: Vec<Value> = vec![];
102
103 for _ in 0..arg_count {
104 args.push(self.stack_pop()?);
105 }
106
107 args.reverse();
108
109 let value = self.stack_pop()?;
110
111 let builtin = value.get_func().func.clone();
112
113 let result = builtin(args);
114
115 self.stack_push(result);
116
117 Ok(())
118 }
119
120 fn op_get(&mut self, env: &CompileTimeEnv, runtime_env: &RuntimeEnv) -> ExprResult<()> {
121 assert_eq!(opcode::GET, self.read_u8(), "Expected GET opcode");
122 let get_lookup = self.read_u8();
123 let get_idx = self.read_u8() as usize;
124
125 match get_lookup {
126 BUILTIN => {
127 let value = env
128 .get_builtin(get_idx)
129 .unwrap_or_else(|| panic!("undefined builtin: {get_idx}"));
130 self.stack_push(Value::Fn(value.clone()));
131 }
132 USER_BUILTIN => {
133 let value = env
134 .get_user_builtin(get_idx)
135 .unwrap_or_else(|| panic!("undefined user builtin: {get_idx}"));
136 self.stack_push(Value::Fn(value.clone()));
137 }
138 VAR => {
139 let value = env
140 .get_var(get_idx)
141 .and_then(|_| runtime_env.vars.get(get_idx))
142 .unwrap_or_else(|| panic!("undefined variable: {get_idx}"));
143
144 self.stack_push(Value::String(value.clone()));
145 }
146 PROMPT => {
147 let value = env
148 .get_prompt(get_idx)
149 .and_then(|_| runtime_env.prompts.get(get_idx))
150 .unwrap_or_else(|| panic!("undefined prompt: {get_idx}"));
151
152 self.stack_push(Value::String(value.clone()));
153 }
154 SECRET => {
155 let value = env
156 .get_secret(get_idx)
157 .and_then(|_| runtime_env.secrets.get(get_idx))
158 .unwrap_or_else(|| panic!("undefined secret: {get_idx}"));
159
160 self.stack_push(Value::String(value.clone()));
161 }
162 CLIENT_CTX => {
163 let value = env
164 .get_client_context(get_idx)
165 .and_then(|_| runtime_env.client_context.get(get_idx))
166 .unwrap_or_else(|| panic!("undefined client context: {get_idx}"));
167
168 self.stack_push(value.clone());
169 }
170 _ => panic!("Invalid get lookup code: {}", get_lookup),
171 };
172
173 Ok(())
174 }
175
176 fn op_constant(&mut self) -> ExprResult<()> {
177 assert_eq!(opcode::CONSTANT, self.read_u8(), "Expected CONSTANT opcode");
178
179 let get_idx = self.read_u8() as usize;
180
181 let s = self
182 .bytecode
183 .as_ref()
184 .expect("should have bytecode")
185 .strings()
186 .get(get_idx)
187 .unwrap_or_else(|| panic!("undefined string: {}", get_idx));
188
189 self.stack_push(Value::String(s.clone()));
190
191 Ok(())
192 }
193
194 fn op_true(&mut self) -> ExprResult<()> {
195 assert_eq!(opcode::TRUE, self.read_u8(), "Expected TRUE opcode");
196
197 self.stack_push(Value::Bool(true));
198
199 Ok(())
200 }
201
202 fn op_false(&mut self) -> ExprResult<()> {
203 assert_eq!(opcode::FALSE, self.read_u8(), "Expected FALSE opcode");
204
205 self.stack_push(Value::Bool(false));
206
207 Ok(())
208 }
209
210 fn stack_push(&mut self, value: Value) {
211 self.stack.push(value);
212 }
213
214 fn stack_pop(&mut self) -> ExprResult<Value> {
215 if let Some(value) = self.stack.pop() {
216 return Ok(value);
217 };
218
219 Err(vec![(RuntimeError::EmptyStack.into(), 0..0)])
220 }
221
222 fn read_u8(&mut self) -> u8 {
223 let current_ip = self.ip as u8;
224
225 self.ip += 1;
226
227 *self
228 .bytecode
229 .as_ref()
230 .expect("should have bytecode")
231 .codes()
232 .get(current_ip as usize)
233 .expect("should have op in bytecode at {}")
234 }
235
236 fn op_not(&mut self) -> ExprResult<()> {
237 assert_eq!(opcode::NOT, self.read_u8(), "Expected NOT opcode");
238
239 let value = self.stack_pop()?;
240
241 self.stack_push(Value::Bool(!value.get_bool()));
242
243 Ok(())
244 }
245
246 fn op_eq(&mut self) -> ExprResult<()> {
247 assert_eq!(opcode::EQ, self.read_u8(), "Expected EQ opcode");
248
249 let value = self.stack_pop()?;
250 let value2 = self.stack_pop()?;
251
252 self.stack_push(Value::Bool(value == value2));
253
254 Ok(())
255 }
256
257 fn op_type(&mut self) -> ExprResult<()> {
258 assert_eq!(opcode::TYPE, self.read_u8(), "Expected TYPE opcode");
259
260 let value = self.stack_pop()?;
261
262 self.stack_push(Value::Type(value.get_type().into()));
263
264 Ok(())
265 }
266}
267
268#[cfg(test)]
269mod tests {
270 use crate::compiler::get_version_bytes;
271
272 use super::*;
273
274 #[test]
275 #[should_panic(expected = "Invalid OP code: 99")]
276 fn test_invalid_opcode_99() {
277 let mut vm = Vm::new();
278
279 let mut codes = get_version_bytes().to_vec();
280 codes.push(99);
281
282 let bytecode = Box::new(ExprByteCode::new(codes, vec![])); let env = CompileTimeEnv::default();
284 let runtime_env = RuntimeEnv::default();
285
286 let _ = vm.interpret(bytecode, &env, &runtime_env);
288 }
289
290 #[test]
291 #[should_panic(expected = "Invalid get lookup code: 99")]
292 fn test_invalid_look_99() {
293 let mut vm = Vm::new();
294
295 let mut codes = get_version_bytes().to_vec();
296 codes.push(opcode::GET);
297 codes.push(99);
298 codes.push(0);
299
300 let bytecode = Box::new(ExprByteCode::new(codes, vec![])); let env = CompileTimeEnv::default();
302 let runtime_env = RuntimeEnv::default();
303
304 let _ = vm.interpret(bytecode, &env, &runtime_env);
306 }
307}