1use crate::{
4 compiler::{
5 CompileTimeEnv, ExprByteCode,
6 lookup::{BUILTIN, PROMPT, SECRET, TYPE, VAR},
7 opcode,
8 },
9 errors::{ExprErrorS, ExprResult, RuntimeError},
10 prelude::lookup::{CLIENT_CTX, USER_BUILTIN},
11 types::Type,
12 value::Value,
13};
14
15#[derive(Debug, Clone, Default)]
16pub struct RuntimeEnv {
17 pub vars: Vec<String>,
18 pub prompts: Vec<String>,
19 pub secrets: Vec<String>,
20 pub client_context: Vec<Value>,
21}
22
23impl RuntimeEnv {
24 pub fn add_to_client_context(&mut self, index: usize, value: Value) {
25 if index < self.client_context.len() {
26 self.client_context[index] = value;
27 } else {
28 self.client_context.push(value);
29 }
30 }
31}
32
33#[derive(Debug)]
34pub struct Vm {
35 bytecode: Option<Box<ExprByteCode>>,
36 ip: usize,
37 stack: Vec<Value>,
38}
39
40impl Default for Vm {
41 fn default() -> Self {
42 Self::new()
43 }
44}
45
46impl Vm {
47 pub fn new() -> Self {
48 Self {
49 bytecode: None,
50 ip: 0,
51 stack: vec![],
52 }
53 }
54
55 pub fn interpret(
56 &mut self,
57 bytecode: Box<ExprByteCode>,
58 env: &CompileTimeEnv,
59 runtime_env: &RuntimeEnv,
60 ) -> ExprResult<Value> {
61 self.bytecode = Some(bytecode);
62 self.ip = 0;
63
64 let mut errs: Vec<ExprErrorS> = vec![];
65
66 while let Some(op_code) = self
67 .bytecode
68 .as_ref()
69 .and_then(|bc| bc.codes().get(self.ip))
70 {
71 if let Err(e) = self.interpret_op(env, runtime_env, *op_code) {
72 errs.extend(e);
73 }
74 }
75
76 if !errs.is_empty() {
77 return Err(errs);
78 }
79
80 self.stack_pop()
81 }
82
83 fn interpret_op(
84 &mut self,
85 env: &CompileTimeEnv,
86 runtime_env: &RuntimeEnv,
87 op_code: u8,
88 ) -> ExprResult<()> {
89 match op_code {
90 opcode::CALL => self.op_call(),
91 opcode::CONSTANT => self.op_constant(),
92 opcode::GET => self.op_get(env, runtime_env),
93 opcode::TRUE => self.op_true(),
94 opcode::FALSE => self.op_false(),
95 _ => panic!("Invalid OP code: {op_code}"),
96 }
97 }
98
99 fn op_call(&mut self) -> ExprResult<()> {
100 self.read_u8();
102
103 let arg_count = self.read_u8() as usize;
104
105 let mut args: Vec<Value> = vec![];
106
107 for _ in 0..arg_count {
108 args.push(self.stack_pop()?);
109 }
110
111 args.reverse();
112
113 let value = self.stack_pop()?;
114
115 let builtin = value.get_func()?.func;
116
117 let result = builtin(args);
118
119 self.stack_push(result?);
120
121 Ok(())
122 }
123
124 fn op_get(&mut self, env: &CompileTimeEnv, runtime_env: &RuntimeEnv) -> ExprResult<()> {
125 self.read_u8();
127
128 let get_lookup = self.read_u8();
129 let get_idx = self.read_u8() as usize;
130
131 match get_lookup {
132 BUILTIN => {
133 let value = env
134 .get_builtin(get_idx)
135 .unwrap_or_else(|| panic!("undefined builtin: {get_idx}"));
136 self.stack_push(Value::Fn(value.clone().into()));
137 }
138 USER_BUILTIN => {
139 let value = env
140 .get_user_builtin(get_idx)
141 .unwrap_or_else(|| panic!("undefined user builtin: {get_idx}"));
142 self.stack_push(Value::Fn(value.clone().into()));
143 }
144 VAR => {
145 let value = env
146 .get_var(get_idx)
147 .and_then(|_| runtime_env.vars.get(get_idx))
148 .unwrap_or_else(|| panic!("undefined variable: {get_idx}"));
149
150 self.stack_push(Value::String(value.clone()));
151 }
152 PROMPT => {
153 let value = env
154 .get_prompt(get_idx)
155 .and_then(|_| runtime_env.prompts.get(get_idx))
156 .unwrap_or_else(|| panic!("undefined prompt: {get_idx}"));
157
158 self.stack_push(Value::String(value.clone()));
159 }
160 SECRET => {
161 let value = env
162 .get_secret(get_idx)
163 .and_then(|_| runtime_env.secrets.get(get_idx))
164 .unwrap_or_else(|| panic!("undefined secret: {get_idx}"));
165
166 self.stack_push(Value::String(value.clone()));
167 }
168 CLIENT_CTX => {
169 let value = env
170 .get_client_context(get_idx)
171 .and_then(|_| runtime_env.client_context.get(get_idx))
172 .unwrap_or_else(|| panic!("undefined client context: {get_idx}"));
173
174 self.stack_push(value.clone());
175 }
176 TYPE => {
177 let ty = self
178 .bytecode
179 .as_ref()
180 .unwrap()
181 .types()
182 .get(get_idx)
183 .unwrap_or_else(|| panic!("undefined type: {get_idx}"));
184
185 if ty.is_type() {
186 self.stack_push(Value::Type(ty.clone().into()));
187 } else {
188 self.stack_push(Value::Type(Type::Type(ty.clone().into()).into()));
189 }
190 }
191 _ => panic!("Invalid get lookup code: {get_lookup}"),
192 };
193
194 Ok(())
195 }
196
197 fn op_constant(&mut self) -> ExprResult<()> {
198 self.read_u8();
200
201 let get_idx = self.read_u8() as usize;
202
203 let s = self
204 .bytecode
205 .as_ref()
206 .expect("should have bytecode")
207 .constants()
208 .get(get_idx)
209 .unwrap_or_else(|| panic!("undefined constant: {get_idx}"));
210
211 self.stack_push(s.clone());
212
213 Ok(())
214 }
215
216 fn op_true(&mut self) -> ExprResult<()> {
217 self.read_u8();
219
220 self.stack_push(Value::Bool(true));
221
222 Ok(())
223 }
224
225 fn op_false(&mut self) -> ExprResult<()> {
226 self.read_u8();
228
229 self.stack_push(Value::Bool(false));
230
231 Ok(())
232 }
233
234 fn stack_push(&mut self, value: Value) {
235 self.stack.push(value);
236 }
237
238 fn stack_pop(&mut self) -> ExprResult<Value> {
239 if let Some(value) = self.stack.pop() {
240 return Ok(value);
241 };
242
243 Err(vec![(RuntimeError::EmptyStack.into(), 0..0)])
244 }
245
246 fn read_u8(&mut self) -> u8 {
247 let current_ip = self.ip as u8;
248
249 self.ip += 1;
250
251 *self
252 .bytecode
253 .as_ref()
254 .expect("should have bytecode")
255 .codes()
256 .get(current_ip as usize)
257 .expect("should have op in bytecode at {}")
258 }
259}
260
261#[cfg(test)]
262mod tests {
263 use crate::{compiler::get_version_bytes, errors::ExprError, prelude::lookup};
264
265 use super::*;
266
267 #[test]
268 fn test_popping_from_empty_stack() {
269 let mut vm = Vm::new();
270
271 let mut codes = get_version_bytes().to_vec();
272
273 codes.push(opcode::GET);
275 codes.push(lookup::BUILTIN);
276 codes.push(0);
277
278 codes.push(opcode::CALL);
281 codes.push(1);
282
283 let bytecode = Box::new(ExprByteCode::new(codes, vec![], vec![]));
284 let env = CompileTimeEnv::default();
285 let runtime_env = RuntimeEnv::default();
286
287 assert_eq!(
288 Err(vec![(
289 ExprError::RuntimeError(RuntimeError::EmptyStack),
290 0..0
291 )]),
292 vm.interpret(bytecode, &env, &runtime_env)
293 );
294 }
295
296 #[test]
297 #[should_panic(expected = "Invalid OP code: 99")]
298 fn test_invalid_opcode_99() {
299 let mut vm = Vm::new();
300
301 let mut codes = get_version_bytes().to_vec();
302 codes.push(99);
303
304 let bytecode = Box::new(ExprByteCode::new(codes, vec![], vec![]));
305 let env = CompileTimeEnv::default();
306 let runtime_env = RuntimeEnv::default();
307
308 let _ = vm.interpret(bytecode, &env, &runtime_env);
310 }
311
312 #[test]
313 #[should_panic(expected = "Invalid get lookup code: 99")]
314 fn test_invalid_look_99() {
315 let mut vm = Vm::new();
316
317 let mut codes = get_version_bytes().to_vec();
318 codes.push(opcode::GET);
319 codes.push(99);
320 codes.push(0);
321
322 let bytecode = Box::new(ExprByteCode::new(codes, vec![], vec![]));
323 let env = CompileTimeEnv::default();
324 let runtime_env = RuntimeEnv::default();
325
326 let _ = vm.interpret(bytecode, &env, &runtime_env);
328 }
329
330 #[test]
331 #[should_panic(expected = "undefined variable: 99")]
332 fn undefined_variable() {
333 let mut vm = Vm::new();
334
335 let mut codes = get_version_bytes().to_vec();
336 codes.push(opcode::GET);
337 codes.push(lookup::VAR);
338 codes.push(99);
339
340 let bytecode = Box::new(ExprByteCode::new(codes, vec![], vec![]));
341 let env = CompileTimeEnv::default();
342 let runtime_env = RuntimeEnv::default();
343
344 let _ = vm.interpret(bytecode, &env, &runtime_env);
345 }
346
347 #[test]
348 #[should_panic(expected = "undefined prompt: 99")]
349 fn undefined_prompt() {
350 let mut vm = Vm::new();
351
352 let mut codes = get_version_bytes().to_vec();
353 codes.push(opcode::GET);
354 codes.push(lookup::PROMPT);
355 codes.push(99);
356
357 let bytecode = Box::new(ExprByteCode::new(codes, vec![], vec![]));
358 let env = CompileTimeEnv::default();
359 let runtime_env = RuntimeEnv::default();
360
361 let _ = vm.interpret(bytecode, &env, &runtime_env);
362 }
363
364 #[test]
365 #[should_panic(expected = "undefined secret: 99")]
366 fn undefined_secret() {
367 let mut vm = Vm::new();
368
369 let mut codes = get_version_bytes().to_vec();
370 codes.push(opcode::GET);
371 codes.push(lookup::SECRET);
372 codes.push(99);
373
374 let bytecode = Box::new(ExprByteCode::new(codes, vec![], vec![]));
375 let env = CompileTimeEnv::default();
376 let runtime_env = RuntimeEnv::default();
377
378 let _ = vm.interpret(bytecode, &env, &runtime_env);
379 }
380
381 #[test]
382 #[should_panic(expected = "undefined builtin: 255")]
383 fn undefined_builtin() {
384 let mut vm = Vm::new();
385
386 let mut codes = get_version_bytes().to_vec();
387 codes.push(opcode::GET);
388 codes.push(lookup::BUILTIN);
389 codes.push(255);
390
391 let bytecode = Box::new(ExprByteCode::new(codes, vec![], vec![]));
392 let env = CompileTimeEnv::default();
393 let runtime_env = RuntimeEnv::default();
394
395 let _ = vm.interpret(bytecode, &env, &runtime_env);
396 }
397
398 #[test]
399 #[should_panic(expected = "undefined user builtin: 255")]
400 fn undefined_user_builtin() {
401 let mut vm = Vm::new();
402
403 let mut codes = get_version_bytes().to_vec();
404 codes.push(opcode::GET);
405 codes.push(lookup::USER_BUILTIN);
406 codes.push(255);
407
408 let bytecode = Box::new(ExprByteCode::new(codes, vec![], vec![]));
409 let env = CompileTimeEnv::default();
410 let runtime_env = RuntimeEnv::default();
411
412 let _ = vm.interpret(bytecode, &env, &runtime_env);
413 }
414
415 #[test]
416 #[should_panic(expected = "undefined client context: 255")]
417 fn undefined_client_context() {
418 let mut vm = Vm::new();
419
420 let mut codes = get_version_bytes().to_vec();
421 codes.push(opcode::GET);
422 codes.push(lookup::CLIENT_CTX);
423 codes.push(255);
424
425 let bytecode = Box::new(ExprByteCode::new(codes, vec![], vec![]));
426 let env = CompileTimeEnv::default();
427 let runtime_env = RuntimeEnv::default();
428
429 let _ = vm.interpret(bytecode, &env, &runtime_env);
430 }
431
432 #[test]
433 #[should_panic(expected = "undefined type: 255")]
434 fn undefined_type() {
435 let mut vm = Vm::new();
436
437 let mut codes = get_version_bytes().to_vec();
438 codes.push(opcode::GET);
439 codes.push(lookup::TYPE);
440 codes.push(255);
441
442 let bytecode = Box::new(ExprByteCode::new(codes, vec![], vec![]));
443 let env = CompileTimeEnv::default();
444 let runtime_env = RuntimeEnv::default();
445
446 let _ = vm.interpret(bytecode, &env, &runtime_env);
447 }
448
449 #[test]
450 #[should_panic(expected = "undefined constant: 255")]
451 fn undefined_constant() {
452 let mut vm = Vm::new();
453
454 let mut codes = get_version_bytes().to_vec();
455 codes.push(opcode::CONSTANT);
456 codes.push(255);
457
458 let bytecode = Box::new(ExprByteCode::new(codes, vec![], vec![]));
459 let env = CompileTimeEnv::default();
460 let runtime_env = RuntimeEnv::default();
461
462 let _ = vm.interpret(bytecode, &env, &runtime_env);
463 }
464}