rune/
bytecode.rs

1//! The main bytecode interpeter.
2use crate::core::cons::Cons;
3use crate::core::env::{CallFrame, Env, sym};
4use crate::core::gc::{Context, IntoRoot, Rt, Rto, Slot};
5use crate::core::object::{
6    ByteFn, ByteString, FnArgs, Function, FunctionType, Gc, LispVec, NIL, Object, ObjectType,
7    Symbol, WithLifetime,
8};
9use crate::data::LispError;
10use crate::eval::{ErrorType, EvalError, EvalResult};
11use anyhow::{Result, bail};
12use rune_core::macros::{bail_err, rebind, root};
13use rune_macros::{Trace, defun};
14
15mod opcode;
16
17/// An program counter. This is implemented as a bound checked range pointer.
18// TODO: If the GC moves the bytecode, this will be invalid. We need to fix this
19#[derive(Clone, Debug)]
20struct ProgramCounter {
21    /// Valid range for this instruction pointer.
22    range: std::ops::Range<*const u8>,
23    /// Points to the next instruction.
24    pc: *const u8,
25}
26
27impl ProgramCounter {
28    fn new(vec: &[u8]) -> Self {
29        ProgramCounter { range: vec.as_ptr_range(), pc: vec.as_ptr() }
30    }
31
32    fn with_offset(vec: &[u8], offset: usize) -> Self {
33        ProgramCounter { range: vec.as_ptr_range(), pc: vec.as_ptr().map_addr(|a| a + offset) }
34    }
35
36    fn as_offset(&self) -> usize {
37        self.pc.addr() - self.range.start.addr()
38    }
39
40    fn goto(&mut self, offset: u16) {
41        unsafe {
42            self.pc = self.range.start.add(offset as usize);
43            debug_assert!(self.range.contains(&self.pc));
44        }
45    }
46
47    /// Take the next byte in the stream
48    fn next(&mut self) -> u8 {
49        unsafe {
50            debug_assert!(self.range.contains(&self.pc));
51            let value = *self.pc;
52            self.pc = self.pc.add(1);
53            value
54        }
55    }
56
57    fn arg1(&mut self) -> u16 {
58        unsafe {
59            debug_assert!(self.range.contains(&self.pc));
60            let value = *self.pc;
61            self.pc = self.pc.add(1);
62            if cfg!(feature = "debug_bytecode") && crate::debug::debug_enabled() {
63                println!("  arg: {value}");
64            }
65            value.into()
66        }
67    }
68
69    fn arg2(&mut self) -> u16 {
70        unsafe {
71            debug_assert!(self.range.contains(&self.pc.add(1)));
72            let value = u16::from_le(self.pc.cast::<u16>().read_unaligned());
73            self.pc = self.pc.add(2);
74            if cfg!(feature = "debug_bytecode") && crate::debug::debug_enabled() {
75                println!("  arg: {value}");
76            }
77            value
78        }
79    }
80}
81
82#[derive(Debug, Trace)]
83/// A handler for a condition-case. These are stored in a vector in the VM and
84/// added/removed via bytecodes.
85struct Handler<'ob> {
86    #[no_trace]
87    jump_code: u16,
88    #[no_trace]
89    stack_size: usize,
90    #[no_trace]
91    stack_frame: usize,
92    condition: Slot<Object<'ob>>,
93}
94
95impl<'new> IntoRoot<Handler<'new>> for Handler<'_> {
96    unsafe fn into_root(self) -> Handler<'new> {
97        self.with_lifetime()
98    }
99}
100
101impl<'old, 'new> WithLifetime<'new> for Handler<'old> {
102    type Out = Handler<'new>;
103
104    unsafe fn with_lifetime(self) -> Self::Out {
105        std::mem::transmute::<Handler<'old>, Handler<'new>>(self)
106    }
107}
108
109/// The bytecode VM. This hold all the current call frames and handlers. The
110/// execution stack is part of the Environment.
111#[derive(Trace)]
112struct VM<'brw, 'env, 'rt> {
113    #[no_trace]
114    /// Current program counter
115    pc: ProgramCounter,
116    /// The current function being executed. Saved to ensure it is preserved by
117    /// the garbage collector.
118    func: Slot<&'rt ByteFn>,
119    /// All currently active condition-case handlers
120    handlers: Vec<Handler<'rt>>,
121    /// The runtime environment
122    #[no_trace]
123    env: &'brw mut Rt<Env<'env>>,
124}
125
126impl<'brw, 'env> IntoRoot<VM<'brw, 'env, 'static>> for VM<'brw, 'env, '_> {
127    unsafe fn into_root(self) -> VM<'brw, 'env, 'static> {
128        std::mem::transmute(self)
129    }
130}
131
132impl<'ob> RootedVM<'_, '_, '_> {
133    fn varref(&mut self, idx: u16, cx: &'ob Context) -> Result<()> {
134        let symbol = self.get_const(idx as usize, cx);
135        if let ObjectType::Symbol(sym) = symbol.untag() {
136            let Some(var) = self.env.vars.get(sym) else { bail!("Void Variable: {sym}") };
137            let var = var.bind(cx);
138            self.env.stack.push(var);
139            Ok(())
140        } else {
141            unreachable!("Varref was not a symbol: {:?}", symbol);
142        }
143    }
144
145    fn varset(&mut self, idx: usize, cx: &Context) -> Result<()> {
146        let obj = self.get_const(idx, cx);
147        let symbol: Symbol = obj.try_into()?;
148        let value = self.env.stack.pop(cx);
149        crate::data::set(symbol, value, self.env)?;
150        Ok(())
151    }
152
153    fn varbind(&mut self, idx: u16, cx: &'ob Context) {
154        let value = self.env.stack.pop(cx);
155        let symbol = self.get_const(idx as usize, cx);
156        let ObjectType::Symbol(sym) = symbol.untag() else {
157            unreachable!("Varbind was not a symbol: {:?}", symbol)
158        };
159        self.env.varbind(sym, value, cx);
160    }
161
162    fn unbind(&mut self, idx: u16, cx: &'ob Context) {
163        self.env.unbind(idx, cx);
164    }
165
166    fn get_const(&self, i: usize, cx: &'ob Context) -> Object<'ob> {
167        *self.func.bind(cx).consts().get(i).expect("constant had invalid index")
168    }
169
170    fn set_current_frame(&mut self, f: &ByteFn, offset: usize) {
171        self.func.set(f);
172        self.pc = ProgramCounter::with_offset(f.codes(), offset);
173    }
174
175    fn unwind(&mut self, idx: usize, cx: &'ob Context) {
176        if idx == self.env.stack.current_frame() {
177            return;
178        }
179        assert!(idx < self.env.stack.current_frame());
180        if let Some((f, offset)) = self.env.stack.get_bytecode_frame(idx) {
181            self.set_current_frame(f.bind(cx), offset);
182            self.env.stack.unwind_frames(idx);
183        } else {
184            unreachable!("Unwind frame not found")
185        }
186    }
187
188    #[inline(always)]
189    fn debug_enabled() -> bool {
190        cfg!(test) || (cfg!(feature = "debug_bytecode") && crate::debug::debug_enabled())
191    }
192
193    /// Prepare the arguments for lisp function call. This means filling all
194    /// needed stack slots with `nil` and moving all the `&rest` arguments into
195    /// a list.
196    fn prepare_lisp_args(
197        &mut self,
198        func: &ByteFn,
199        arg_cnt: usize,
200        name: &str,
201        cx: &'ob Context,
202    ) -> Result<()> {
203        let arg_cnt = arg_cnt as u16;
204        let fill_args = num_of_fill_args(func.args, arg_cnt, name, cx)?;
205        self.env.stack.fill_extra_args(fill_args);
206        let total_args = arg_cnt + fill_args;
207        let rest_size = total_args - (func.args.required + func.args.optional);
208        if rest_size > 0 {
209            let slice = &self.env.stack[..rest_size as usize];
210            let list = crate::fns::slice_into_list(Rt::bind_slice(slice, cx), None, cx);
211            self.env.stack.remove_top(rest_size as usize - 1);
212            self.env.stack[0].set(list);
213            self.env.stack.set_arg_count(total_args - rest_size + 1, true);
214        } else if func.args.rest {
215            self.env.stack.push(NIL);
216            self.env.stack.set_arg_count(total_args + 1, true)
217        } else {
218            self.env.stack.set_arg_count(total_args, false)
219        };
220        Ok(())
221    }
222
223    fn call(&mut self, arg_cnt: u16, cx: &'ob mut Context) -> Result<(), EvalError> {
224        let arg_cnt = usize::from(arg_cnt);
225        let func: Function = self.env.stack[arg_cnt].bind(cx).try_into()?;
226        let name = match func.untag() {
227            FunctionType::Symbol(x) => x.name().to_owned(),
228            _ => String::from("lambda"),
229        };
230        if let FunctionType::ByteFn(next_fn) = func.untag() {
231            // If bytecode, add another frame and resume execution.
232            // OpCode::Return will remove the call frame.
233            let len = self.env.stack.len();
234            let pc_offset = self.pc.as_offset();
235            let prev_fn = self.func.bind(cx);
236            self.set_current_frame(next_fn, 0);
237            let frame_start = len - (arg_cnt + 1);
238            self.env
239                .stack
240                .push_bytecode_frame(frame_start, next_fn.depth, prev_fn, pc_offset);
241            self.prepare_lisp_args(next_fn, arg_cnt, &name, cx)?;
242        } else {
243            // Otherwise, call the function directly.
244            let mut frame = CallFrame::new_with_args(self.env, arg_cnt);
245            root!(func, cx);
246            let result = func.call(&mut frame, Some(&name), cx)?;
247            drop(frame); // removes the arguments from the stack
248            self.env.stack.top().set(result);
249            cx.garbage_collect(false);
250        }
251        Ok(())
252    }
253
254    fn run(&mut self, cx: &'ob mut Context) -> EvalResult<'ob> {
255        'main: loop {
256            let err = match self.execute_bytecode(cx) {
257                Ok(x) => return Ok(rebind!(x, cx)),
258                Err(e) => e,
259            };
260
261            // we will fix this once we can handle different error types
262            #[expect(clippy::never_loop)]
263            while let Some(handler) = self.handlers.bind_mut(cx).pop() {
264                match handler.condition.untag() {
265                    ObjectType::Symbol(sym::ERROR) => {}
266                    ObjectType::Cons(conditions) => {
267                        for condition in conditions {
268                            let condition = condition?;
269                            // TODO: Handle different error symbols
270                            if condition != sym::DEBUG && condition != sym::ERROR {
271                                bail_err!("non-error conditions {condition} not yet supported")
272                            }
273                        }
274                    }
275                    x => bail_err!("Invalid condition handler: {x}"),
276                }
277
278                let error = if let EvalError { error: ErrorType::Signal(id), .. } = err {
279                    let Some((sym, data)) = self.env.get_exception(id) else {
280                        unreachable!("Exception not found")
281                    };
282                    Cons::new(sym, data, cx)
283                } else {
284                    // TODO: Need to remove the anyhow branch once
285                    // full errors are implemented
286                    Cons::new(sym::ERROR, format!("{err}"), cx)
287                };
288                self.unwind(handler.stack_frame, cx);
289                self.env.stack.truncate(handler.stack_size);
290                self.env.stack.push(Object::from(error));
291                self.pc.goto(handler.jump_code);
292                continue 'main;
293            }
294            return Err(err);
295        }
296    }
297
298    #[expect(clippy::too_many_lines)]
299    /// The main bytecode execution loop.
300    fn execute_bytecode(&mut self, cx: &'ob mut Context) -> EvalResult<'ob> {
301        use crate::{alloc, arith, data, fns};
302        use opcode::OpCode as op;
303        loop {
304            let op = match self.pc.next().try_into() {
305                Ok(x) => x,
306                Err(e) => panic!("Invalid Bytecode: {e}"),
307            };
308
309            if Self::debug_enabled() {
310                println!("[");
311                for (idx, x) in self.env.stack.frames().iter().rev().enumerate() {
312                    println!("    {idx}: {x},");
313                }
314                println!("]");
315                let byte_offset = self.pc.pc as i64 - self.pc.range.start as i64 - 1;
316                println!("op :{byte_offset}: {op:?}");
317            }
318            match op {
319                op::StackRef0 => self.env.stack.push_ref(0, cx),
320                op::StackRef1 => self.env.stack.push_ref(1, cx),
321                op::StackRef2 => self.env.stack.push_ref(2, cx),
322                op::StackRef3 => self.env.stack.push_ref(3, cx),
323                op::StackRef4 => self.env.stack.push_ref(4, cx),
324                op::StackRef5 => self.env.stack.push_ref(5, cx),
325                op::StackRefN => {
326                    let idx = self.pc.arg1();
327                    self.env.stack.push_ref(idx, cx);
328                }
329                op::StackRefN2 => {
330                    let idx = self.pc.arg2();
331                    self.env.stack.push_ref(idx, cx);
332                }
333                op::StackSetN => {
334                    let idx = self.pc.arg1();
335                    self.env.stack.set_ref(idx);
336                }
337                op::StackSetN2 => {
338                    let idx = self.pc.arg2();
339                    self.env.stack.set_ref(idx);
340                }
341                op::VarRef0 => self.varref(0, cx)?,
342                op::VarRef1 => self.varref(1, cx)?,
343                op::VarRef2 => self.varref(2, cx)?,
344                op::VarRef3 => self.varref(3, cx)?,
345                op::VarRef4 => self.varref(4, cx)?,
346                op::VarRef5 => self.varref(5, cx)?,
347                op::VarRefN => {
348                    let idx = self.pc.arg1();
349                    self.varref(idx, cx)?;
350                }
351                op::VarRefN2 => {
352                    let idx = self.pc.arg2();
353                    self.varref(idx, cx)?;
354                }
355                op::VarSet0 => self.varset(0, cx)?,
356                op::VarSet1 => self.varset(1, cx)?,
357                op::VarSet2 => self.varset(2, cx)?,
358                op::VarSet3 => self.varset(3, cx)?,
359                op::VarSet4 => self.varset(4, cx)?,
360                op::VarSet5 => self.varset(5, cx)?,
361                op::VarSetN => {
362                    let idx = self.pc.arg1();
363                    self.varset(idx.into(), cx)?;
364                }
365                op::VarSetN2 => {
366                    let idx = self.pc.arg2();
367                    self.varset(idx.into(), cx)?;
368                }
369                op::VarBind0 => self.varbind(0, cx),
370                op::VarBind1 => self.varbind(1, cx),
371                op::VarBind2 => self.varbind(2, cx),
372                op::VarBind3 => self.varbind(3, cx),
373                op::VarBind4 => self.varbind(4, cx),
374                op::VarBind5 => self.varbind(5, cx),
375                op::VarBindN => {
376                    let idx = self.pc.arg1();
377                    self.varbind(idx, cx);
378                }
379                op::VarBindN2 => {
380                    let idx = self.pc.arg2();
381                    self.varbind(idx, cx);
382                }
383                op::Call0 => self.call(0, cx)?,
384                op::Call1 => self.call(1, cx)?,
385                op::Call2 => self.call(2, cx)?,
386                op::Call3 => self.call(3, cx)?,
387                op::Call4 => self.call(4, cx)?,
388                op::Call5 => self.call(5, cx)?,
389                op::CallN => {
390                    let idx = self.pc.arg1();
391                    self.call(idx, cx)?;
392                }
393                op::CallN2 => {
394                    let idx = self.pc.arg2();
395                    self.call(idx, cx)?;
396                }
397                op::Unbind0 => self.unbind(0, cx),
398                op::Unbind1 => self.unbind(1, cx),
399                op::Unbind2 => self.unbind(2, cx),
400                op::Unbind3 => self.unbind(3, cx),
401                op::Unbind4 => self.unbind(4, cx),
402                op::Unbind5 => self.unbind(5, cx),
403                op::UnbindN => {
404                    let idx = self.pc.arg1();
405                    self.unbind(idx, cx);
406                }
407                op::UnbindN2 => {
408                    let idx = self.pc.arg2();
409                    self.unbind(idx, cx);
410                }
411                op::PopHandler => {
412                    self.handlers.pop();
413                }
414                op::PushCondtionCase => {
415                    // pop before getting stack size
416                    let condition = self.env.stack.pop(cx);
417                    let handler = Handler {
418                        jump_code: self.pc.arg2(),
419                        stack_size: self.env.stack.len(),
420                        stack_frame: self.env.stack.current_frame(),
421                        condition: Slot::new(condition),
422                    };
423                    self.handlers.push(handler);
424                }
425                op::PushCatch => todo!("PushCatch bytecode"),
426                op::Nth => {
427                    let list = self.env.stack.pop(cx);
428                    let top = self.env.stack.top();
429                    top.set(fns::nth(top.bind_as(cx)?, list.try_into()?)?);
430                }
431                op::Symbolp => {
432                    let top = self.env.stack.top();
433                    top.set(data::symbolp(top.bind(cx)));
434                }
435                op::Consp => {
436                    let top = self.env.stack.top();
437                    top.set(data::consp(top.bind(cx)));
438                }
439                op::Stringp => {
440                    let top = self.env.stack.top();
441                    top.set(data::stringp(top.bind(cx)));
442                }
443                op::Listp => {
444                    let top = self.env.stack.top();
445                    top.set(data::listp(top.bind(cx)));
446                }
447                op::Eq => {
448                    let v1 = self.env.stack.pop(cx);
449                    let top = self.env.stack.top();
450                    top.set(fns::eq(top.bind(cx), v1));
451                }
452                op::Memq => {
453                    let list = self.env.stack.pop(cx);
454                    let elt = self.env.stack.top();
455                    elt.set(fns::memq(elt.bind(cx), list.try_into()?)?);
456                }
457                op::Not => {
458                    let top = self.env.stack.top();
459                    top.set(data::null(top.bind(cx)));
460                }
461                op::Car => {
462                    let top = self.env.stack.top();
463                    top.set(data::car(top.bind_as(cx)?));
464                }
465                op::Cdr => {
466                    let top = self.env.stack.top();
467                    top.set(data::cdr(top.bind_as(cx)?));
468                }
469                op::Cons => {
470                    let cdr = self.env.stack.pop(cx);
471                    let car = self.env.stack.top();
472                    car.set(data::cons(car.bind(cx), cdr, cx));
473                }
474                op::List1 => {
475                    let top = self.env.stack.top();
476                    top.set(alloc::list(&[top.bind(cx)], cx));
477                }
478                op::List2 => {
479                    let a2 = self.env.stack.pop(cx);
480                    let top = self.env.stack.top();
481                    top.set(alloc::list(&[top.bind(cx), a2], cx));
482                }
483                op::List3 => {
484                    let a3 = self.env.stack.pop(cx);
485                    let a2 = self.env.stack.pop(cx);
486                    let top = self.env.stack.top();
487                    top.set(alloc::list(&[top.bind(cx), a2, a3], cx));
488                }
489                op::List4 => {
490                    let a4 = self.env.stack.pop(cx);
491                    let a3 = self.env.stack.pop(cx);
492                    let a2 = self.env.stack.pop(cx);
493                    let top = self.env.stack.top();
494                    top.set(alloc::list(&[top.bind(cx), a2, a3, a4], cx));
495                }
496                op::Length => {
497                    let top = self.env.stack.top();
498                    top.set(fns::length(top.bind(cx))? as i64);
499                }
500                op::Aref => {
501                    let idx = self.env.stack.pop(cx);
502                    let top = self.env.stack.top();
503                    top.set(data::aref(top.bind(cx), idx.try_into()?, cx)?);
504                }
505                op::Aset => {
506                    let newlet = self.env.stack.pop(cx);
507                    let idx = self.env.stack.pop(cx);
508                    let top = self.env.stack.top();
509                    top.set(data::aset(top.bind(cx), idx.try_into()?, newlet)?);
510                }
511                op::SymbolValue => {
512                    let top = self.env.stack.top().bind_as(cx)?;
513                    let value = data::symbol_value(top, self.env, cx).unwrap_or_default();
514                    self.env.stack.top().set(value);
515                }
516                op::SymbolFunction => {
517                    let top = self.env.stack.top();
518                    top.set(data::symbol_function(top.bind_as(cx)?, cx));
519                }
520                op::Set => {
521                    let newlet = self.env.stack.pop(cx);
522                    let top = self.env.stack.top().bind_as(cx)?;
523                    let value = data::set(top, newlet, self.env)?;
524                    self.env.stack.top().set(value);
525                }
526                op::Fset => {
527                    let def = self.env.stack.pop(cx);
528                    let top = self.env.stack.top();
529                    top.set::<Object>(data::fset(top.bind_as(cx)?, def)?.into());
530                }
531                op::Get => {
532                    let prop = self.env.stack.pop(cx).try_into()?;
533                    let top = self.env.stack.top().bind_as(cx)?;
534                    let value = data::get(top, prop, self.env, cx);
535                    self.env.stack.top().set(value);
536                }
537                op::Substring => todo!("Substring bytecode"),
538                op::Concat2 => todo!("Concat2 bytecode"),
539                op::Concat3 => todo!("Concat3 bytecode"),
540                op::Concat4 => todo!("Concat4 bytecode"),
541                op::Sub1 => {
542                    let top = self.env.stack.top();
543                    top.set(cx.add(arith::sub_one(top.bind_as(cx)?)));
544                }
545                op::Add1 => {
546                    let top = self.env.stack.top();
547                    top.set(cx.add(arith::add_one(top.bind_as(cx)?)));
548                }
549                op::EqlSign => {
550                    let rhs = self.env.stack.pop(cx);
551                    let top = self.env.stack.top();
552                    top.set::<Object>(arith::num_eq(top.bind_as(cx)?, &[rhs.try_into()?]).into());
553                }
554                op::GreaterThan => {
555                    let v1 = self.env.stack.pop(cx);
556                    let top = self.env.stack.top();
557                    top.set(arith::greater_than(top.bind_as(cx)?, &[v1.try_into()?]));
558                }
559                op::LessThan => {
560                    let v1 = self.env.stack.pop(cx);
561                    let top = self.env.stack.top();
562                    top.set(arith::less_than(top.bind_as(cx)?, &[v1.try_into()?]));
563                }
564                op::LessThanOrEqual => {
565                    let v1 = self.env.stack.pop(cx);
566                    let top = self.env.stack.top();
567                    top.set(arith::less_than_or_eq(top.bind_as(cx)?, &[v1.try_into()?]));
568                }
569                op::GreaterThanOrEqual => {
570                    let v1 = &[self.env.stack.pop(cx).try_into()?];
571                    let top = self.env.stack.top();
572                    top.set(arith::greater_than_or_eq(top.bind_as(cx)?, v1));
573                }
574                op::Diff => todo!("Diff bytecode"),
575                op::Negate => {
576                    let top = self.env.stack.top();
577                    top.set(cx.add(arith::sub(top.bind_as(cx)?, &[])));
578                }
579                op::Plus => {
580                    let arg1 = self.env.stack.pop(cx);
581                    let top = self.env.stack.top();
582                    let args = &[top.bind_as(cx)?, arg1.try_into()?];
583                    top.set(cx.add(arith::add(args)));
584                }
585                op::Max => {
586                    let arg1 = self.env.stack.pop(cx);
587                    let top = self.env.stack.top();
588                    let args = &[arg1.try_into()?];
589                    top.set(cx.add(arith::max(top.bind_as(cx)?, args)));
590                }
591                op::Min => {
592                    let arg1 = self.env.stack.pop(cx);
593                    let top = self.env.stack.top();
594                    let args = &[arg1.try_into()?];
595                    top.set(cx.add(arith::min(top.bind_as(cx)?, args)));
596                }
597                op::Multiply => {
598                    let arg1 = self.env.stack.pop(cx);
599                    let top = self.env.stack.top();
600                    let args = &[top.bind_as(cx)?, arg1.try_into()?];
601                    top.set(cx.add(arith::mul(args)));
602                }
603                op::Point => todo!("Point bytecode"),
604                op::GotoChar => todo!("GotoChar bytecode"),
605                op::Insert => todo!("Insert bytecode"),
606                op::PointMax => todo!("PointMax bytecode"),
607                op::PointMin => todo!("PointMin bytecode"),
608                op::CharAfter => todo!("CharAfter bytecode"),
609                op::FollowingChar => todo!("FollowingChar bytecode"),
610                op::PrecedingChar => todo!("PrecedingChar bytecode"),
611                op::CurrentColumn => todo!("CurrentColumn bytecode"),
612                op::IndentTo => todo!("IndentTo bytecode"),
613                op::EndOfLineP => todo!("EndOfLineP bytecode"),
614                op::EndOfBufferP => todo!("EndOfBufferP bytecode"),
615                op::BeginningOfLineP => todo!("BeginningOfLineP bytecode"),
616                op::BeginningOfBufferP => todo!("BeginningOfBufferP bytecode"),
617                op::CurrentBuffer => todo!("CurrentBuffer bytecode"),
618                op::SetBuffer => todo!("SetBuffer bytecode"),
619                op::SaveCurrentBuffer1 => todo!("SaveCurrentBuffer1 bytecode"),
620                op::ForwardChar => todo!("ForwardChar bytecode"),
621                op::ForwardWord => todo!("ForwardWord bytecode"),
622                op::SkipCharsForward => todo!("SkipCharsForward bytecode"),
623                op::SkipCharsBackward => todo!("SkipCharsBackward bytecode"),
624                op::ForwardLine => todo!("ForwardLine bytecode"),
625                op::CharSyntax => todo!("CharSyntax bytecode"),
626                op::BufferSubstring => todo!("BufferSubstring bytecode"),
627                op::DeleteRegion => todo!("DeleteRegion bytecode"),
628                op::NarrowToRegion => todo!("NarrowToRegion bytecode"),
629                op::Widen => todo!("Widen bytecode"),
630                op::EndOfLine => todo!("EndOfLine bytecode"),
631                op::ConstantN2 => {
632                    let idx = self.pc.arg2();
633                    let cnst = self.get_const(idx.into(), cx);
634                    self.env.stack.push(cnst);
635                }
636                op::Goto => {
637                    let offset = self.pc.arg2();
638                    self.pc.goto(offset);
639                }
640                op::GotoIfNil => {
641                    let cond = self.env.stack.pop(cx);
642                    let offset = self.pc.arg2();
643                    if cond.is_nil() {
644                        self.pc.goto(offset);
645                    }
646                }
647                op::GotoIfNonNil => {
648                    let cond = self.env.stack.pop(cx);
649                    let offset = self.pc.arg2();
650                    if !cond.is_nil() {
651                        self.pc.goto(offset);
652                    }
653                }
654                op::GotoIfNilElsePop => {
655                    let offset = self.pc.arg2();
656                    if self.env.stack[0].bind(cx).is_nil() {
657                        self.pc.goto(offset);
658                    } else {
659                        self.env.stack.pop(cx);
660                    }
661                }
662                op::GotoIfNonNilElsePop => {
663                    let offset = self.pc.arg2();
664                    if self.env.stack[0].bind(cx).is_nil() {
665                        self.env.stack.pop(cx);
666                    } else {
667                        self.pc.goto(offset);
668                    }
669                }
670                op::Return => {
671                    if let Some((f, offset)) = self.env.stack.prev_bytecode_frame() {
672                        self.set_current_frame(f.bind(cx), offset);
673                        let top = self.env.stack.top().bind(cx);
674                        self.env.stack.pop_frame();
675                        self.env.stack.push(top);
676                    } else {
677                        let top = self.env.stack.pop(cx);
678                        return Ok(top);
679                    }
680                }
681                op::Discard => {
682                    self.env.stack.pop(cx);
683                }
684                op::DiscardN => {
685                    let arg = self.pc.arg1();
686                    let cur_len = self.env.stack.len();
687                    let keep_tos = (arg & 0x80) != 0;
688                    let count = (arg & 0x7F) as usize;
689                    if keep_tos {
690                        let top = self.env.stack.top().bind(cx);
691                        self.env.stack.truncate(cur_len - count);
692                        self.env.stack.top().set(top);
693                    } else {
694                        self.env.stack.truncate(cur_len - count);
695                    }
696                }
697                op::Duplicate => {
698                    let top = self.env.stack[0].bind(cx);
699                    self.env.stack.push(top);
700                }
701                op::SaveExcursion => todo!("SaveExcursion bytecode"),
702                op::SaveRestriction => todo!("SaveRestriction bytecode"),
703                op::UnwindProtect => todo!("UnwindProtect bytecode"),
704                op::SetMarker => todo!("SetMarker bytecode"),
705                op::MatchBeginning => todo!("MatchBeginning bytecode"),
706                op::MatchEnd => todo!("MatchEnd bytecode"),
707                op::Upcase => todo!("Upcase bytecode"),
708                op::Downcase => todo!("Downcase bytecode"),
709                op::StringEqlSign => todo!("StringEqlSign bytecode"),
710                op::StringLessThan => todo!("StringLessThan bytecode"),
711                op::Equal => {
712                    let rhs = self.env.stack.pop(cx);
713                    let top = self.env.stack.top();
714                    top.set(fns::equal(top.bind(cx), rhs));
715                }
716                op::Nthcdr => {
717                    let list = self.env.stack.pop(cx);
718                    let top = self.env.stack.top();
719                    top.set(fns::nthcdr(top.bind_as(cx)?, list.try_into()?)?.as_obj_copy());
720                }
721                op::Elt => {
722                    let n = self.env.stack.pop(cx);
723                    let top = self.env.stack.top();
724                    top.set(fns::elt(top.bind(cx), n.try_into()?, cx)?);
725                }
726                op::Member => {
727                    let list = self.env.stack.pop(cx);
728                    let top = self.env.stack.top();
729                    top.set(fns::member(top.bind(cx), list.try_into()?)?);
730                }
731                op::Assq => {
732                    let alist = self.env.stack.pop(cx);
733                    let top = self.env.stack.top();
734                    top.set(fns::assq(top.bind(cx), alist.try_into()?)?);
735                }
736                op::Nreverse => {
737                    let elt = self.env.stack.top();
738                    elt.set(fns::nreverse(elt.bind_as(cx)?)?);
739                }
740                op::Setcar => {
741                    let newcar = self.env.stack.pop(cx);
742                    let top = self.env.stack.top();
743                    top.set(data::setcar(top.bind_as(cx)?, newcar)?);
744                }
745                op::Setcdr => {
746                    let newcdr = self.env.stack.pop(cx);
747                    let top = self.env.stack.top();
748                    top.set(data::setcdr(top.bind_as(cx)?, newcdr)?);
749                }
750                op::CarSafe => {
751                    let top = self.env.stack.top();
752                    top.set(data::car_safe(top.bind(cx)));
753                }
754                op::CdrSafe => {
755                    let top = self.env.stack.top();
756                    top.set(data::cdr_safe(top.bind(cx)));
757                }
758                op::Nconc => {
759                    let list2 = self.env.stack.pop(cx);
760                    let top = self.env.stack.top();
761                    top.set(fns::nconc(&[top.bind_as(cx)?, list2.try_into()?])?);
762                }
763                op::Quo => todo!("Quo bytecode"),
764                op::Rem => todo!("Rem bytecode"),
765                op::Numberp => {
766                    let top = self.env.stack.top();
767                    top.set(data::numberp(top.bind(cx)));
768                }
769                op::Integerp => {
770                    let top = self.env.stack.top();
771                    top.set(data::integerp(top.bind(cx)));
772                }
773                op::ListN => {
774                    let size = self.pc.arg1() as usize;
775                    let slice = Rt::bind_slice(&self.env.stack[..size], cx);
776                    let list = alloc::list(slice, cx);
777                    let len = self.env.stack.len();
778                    self.env.stack.truncate(len - (size - 1));
779                    self.env.stack.top().set(list);
780                }
781                op::ConcatN => todo!("ConcatN bytecode"),
782                op::InsertN => todo!("InsertN bytecode"),
783                op::Switch => {
784                    let ObjectType::HashTable(table) = self.env.stack.pop(cx).untag() else {
785                        unreachable!("switch table was not a hash table")
786                    };
787                    let cond = self.env.stack.pop(cx);
788                    if let Some(offset) = table.get(cond) {
789                        let ObjectType::Int(offset) = offset.untag() else {
790                            unreachable!("switch value was not a int")
791                        };
792                        self.pc.goto(offset as u16);
793                    }
794                }
795                op::Constant0
796                | op::Constant1
797                | op::Constant2
798                | op::Constant3
799                | op::Constant4
800                | op::Constant5
801                | op::Constant6
802                | op::Constant7
803                | op::Constant8
804                | op::Constant9
805                | op::Constant10
806                | op::Constant11
807                | op::Constant12
808                | op::Constant13
809                | op::Constant14
810                | op::Constant15
811                | op::Constant16
812                | op::Constant17
813                | op::Constant18
814                | op::Constant19
815                | op::Constant20
816                | op::Constant21
817                | op::Constant22
818                | op::Constant23
819                | op::Constant24
820                | op::Constant25
821                | op::Constant26
822                | op::Constant27
823                | op::Constant28
824                | op::Constant29
825                | op::Constant30
826                | op::Constant31
827                | op::Constant32
828                | op::Constant33
829                | op::Constant34
830                | op::Constant35
831                | op::Constant36
832                | op::Constant37
833                | op::Constant38
834                | op::Constant39
835                | op::Constant40
836                | op::Constant41
837                | op::Constant42
838                | op::Constant43
839                | op::Constant44
840                | op::Constant45
841                | op::Constant46
842                | op::Constant47
843                | op::Constant48
844                | op::Constant49
845                | op::Constant50
846                | op::Constant51
847                | op::Constant52
848                | op::Constant53
849                | op::Constant54
850                | op::Constant55
851                | op::Constant56
852                | op::Constant57
853                | op::Constant58
854                | op::Constant59
855                | op::Constant60
856                | op::Constant61
857                | op::Constant62
858                | op::Constant63 => {
859                    let idx = (op as u8) - (op::Constant0 as u8);
860                    let cnst = self.get_const(idx as usize, cx);
861                    self.env.stack.push(cnst);
862                }
863            }
864        }
865    }
866}
867
868#[defun]
869fn byte_code<'ob>(
870    bytestr: &Rto<Gc<&ByteString>>,
871    vector: &Rto<Gc<&LispVec>>,
872    maxdepth: usize,
873    env: &mut Rt<Env>,
874    cx: &'ob mut Context,
875) -> Result<Object<'ob>> {
876    let fun = crate::alloc::make_byte_code(
877        0,
878        bytestr.untag(cx),
879        vector.untag(cx),
880        maxdepth,
881        None,
882        None,
883        &[],
884        cx,
885    )?;
886    root!(fun, cx);
887    Ok(call(fun, 0, "unnamed", &mut CallFrame::new(env), cx)?)
888}
889
890/// Number of arguments needed to fill out the remaining slots on the stack.
891/// If a function has 3 required args and 2 optional, and it is called with
892/// 4 arguments, then 1 will be returned. Indicating that 1 additional `nil`
893/// argument should be added to the stack.
894fn num_of_fill_args(spec: FnArgs, args: u16, name: &str, cx: &Context) -> Result<u16> {
895    if args < spec.required {
896        bail!(LispError::arg_cnt(name, spec.required, args, cx));
897    }
898    let total = spec.required + spec.optional;
899    if !spec.rest && (args > total) {
900        bail!(LispError::arg_cnt(name, total, args, cx));
901    }
902    Ok(total.saturating_sub(args))
903}
904
905#[defun]
906fn fetch_bytecode(_object: Object) {
907    // TODO: Implement
908}
909
910pub(crate) fn call<'ob>(
911    func: &Rto<&ByteFn>,
912    arg_cnt: usize,
913    name: &str,
914    frame: &mut CallFrame,
915    cx: &'ob mut Context,
916) -> EvalResult<'ob> {
917    frame.stack.set_depth(func.bind(cx).depth);
918    let func = func.bind(cx);
919    let vm = VM {
920        pc: ProgramCounter::new(func.codes()),
921        func: Slot::new(func),
922        env: frame,
923        handlers: Vec::new(),
924    };
925    root!(vm, cx);
926    vm.prepare_lisp_args(func, arg_cnt, name, cx)?;
927    vm.run(cx).map_err(|e| e.add_trace(name, vm.env.stack.current_args()))
928}
929
930#[cfg(test)]
931mod test {
932    use crate::core::{
933        gc::RootSet,
934        object::{HashTable, IntoObject},
935    };
936    use rune_core::macros::{list, rebind, root};
937
938    use super::{opcode::OpCode, *};
939
940    macro_rules! make_bytecode { (
941        $name:ident,
942        $arglist:expr,
943        [$($opcodes:expr),* $(,)?],
944        [$($constants:expr),* $(,)?],
945        $cx:expr $(,)?
946    ) => (
947        // https://github.com/rust-lang/rust-analyzer/issues/11681
948        let cx1: &Context = $cx;
949        let constants: &LispVec = {
950            let vec: Vec<Object> = vec![$(cx1.add($constants)),*];
951            vec.into_obj(cx1).untag()
952        };
953        let opcodes = {
954            #[allow(trivial_numeric_casts)]
955            let opcodes = vec![$($opcodes as u8),*];
956            println!("Test seq: {opcodes:?}");
957            opcodes.into_obj(cx1).untag()
958        };
959        // TODO: we should probably caculate the actual depth
960        let depth = 10;
961        let bytecode = crate::alloc::make_byte_code(
962            $arglist,
963            &opcodes,
964            constants,
965            depth,
966            None,
967            None,
968            &[],
969            cx1
970        ).unwrap();
971        root!(bytecode, cx1);
972        let $name = bytecode;
973        )
974    }
975
976    macro_rules! check_bytecode { (
977        $bytecode:expr,
978        [$($args:expr),* $(,)?],
979        $expect:expr,
980        $cx:expr $(,)?
981    ) => ({
982            let bytecode: &Rto<&ByteFn> = $bytecode;
983            let cx: &mut Context = $cx;
984
985            let args: Vec<Object> = { vec![$(cx.add($args)),*] };
986            let expect = cx.add($expect);
987
988            root!(args, cx);
989            root!(expect, cx);
990
991            check_bytecode_internal(
992                args,
993                bytecode,
994                expect,
995                cx
996            );
997        })
998    }
999
1000    fn check_bytecode_internal(
1001        args: &mut Rt<Vec<Slot<Object>>>,
1002        bytecode: &Rto<&ByteFn>,
1003        expect: &Rto<Object>,
1004        cx: &mut Context,
1005    ) {
1006        root!(env, new(Env), cx);
1007        let frame = &mut CallFrame::new(env);
1008        frame.push_arg_slice(Rt::bind_slice(args, cx));
1009        frame.finalize_arguments();
1010        let val = rebind!(call(bytecode, frame.arg_count(), "test", frame, cx).unwrap());
1011        let expect = expect.bind(cx);
1012        assert_eq!(val, expect);
1013    }
1014
1015    #[test]
1016    fn test_basic() {
1017        use OpCode::*;
1018        let roots = &RootSet::default();
1019        let cx = &mut Context::new(roots);
1020        // (lambda () 5)
1021        make_bytecode!(bytecode, 0, [Constant0, Return], [5], cx);
1022        check_bytecode!(bytecode, [], 5, cx);
1023        // (lambda (x) (+ x 5))
1024        make_bytecode!(bytecode, 257, [Duplicate, Constant0, Plus, Return], [5], cx);
1025        check_bytecode!(bytecode, [7], 12, cx);
1026        // (lambda (x &optional y) (+ x y))
1027        make_bytecode!(bytecode, 513, [StackRef1, StackRef1, Plus, Return], [], cx);
1028        check_bytecode!(bytecode, [3, 4], 7, cx);
1029        // (lambda (x) (if x 2 3))
1030        make_bytecode!(
1031            bytecode,
1032            257,
1033            [Duplicate, GotoIfNil, 0x06, 0x00, Constant0, Return, Constant1, Return],
1034            [2, 3],
1035            cx
1036        );
1037        check_bytecode!(bytecode, [false], 3, cx);
1038        check_bytecode!(bytecode, [true], 2, cx);
1039
1040        // (lambda (x) (let ((y 0))
1041        //          (while (< 0 x)
1042        //            (setq x (1- x))
1043        //            (setq y (1+ y)))
1044        //          y))
1045        make_bytecode!(
1046            bytecode,
1047            257,
1048            [
1049                Constant0, Constant0, StackRef2, LessThan, GotoIfNil, VarSet2, 0x00, StackRef1,
1050                Sub1, StackSetN, 0x02, Duplicate, Add1, StackSetN, 0x01, Goto, 0x01, 0x00, Return
1051            ],
1052            [0],
1053            cx
1054        );
1055        check_bytecode!(bytecode, [5], 5, cx);
1056        check_bytecode!(bytecode, [0], 0, cx);
1057    }
1058
1059    #[test]
1060    fn test_bytecode_call() {
1061        use OpCode::*;
1062        let roots = &RootSet::default();
1063        let cx = &mut Context::new(roots);
1064        sym::init_symbols();
1065        // (lambda (x) (symbol-name x))
1066        make_bytecode!(
1067            bytecode,
1068            257,
1069            [Constant0, StackRef1, Call1, Return],
1070            [sym::SYMBOL_NAME],
1071            cx
1072        );
1073        check_bytecode!(bytecode, [sym::SYMBOL_NAME], "symbol-name", cx);
1074        check_bytecode!(bytecode, [sym::AREF], "aref", cx);
1075        check_bytecode!(bytecode, [sym::ADD], "+", cx);
1076
1077        // (lambda (x y z) (+ x y z))
1078        make_bytecode!(
1079            bytecode,
1080            771,
1081            [Constant0, StackRef3, StackRef3, StackRef3, Call3, Return],
1082            [sym::ADD],
1083            cx
1084        );
1085        check_bytecode!(bytecode, [1, 2, 3], 6, cx);
1086
1087        // (lambda (&rest x) (apply '+ x))
1088        make_bytecode!(
1089            bytecode,
1090            128,
1091            [Constant0, Constant1, StackRef2, Call2, Return],
1092            [sym::APPLY, sym::ADD],
1093            cx
1094        );
1095        check_bytecode!(bytecode, [1, 2, 3], 6, cx);
1096
1097        // (lambda (x &optional y) (+ x y))
1098        make_bytecode!(bytecode, 513, [StackRef1, StackRef1, Plus, Return], [], cx);
1099        check_bytecode!(bytecode, [1, 2], 3, cx);
1100    }
1101
1102    #[test]
1103    fn test_bytecode_variables() {
1104        use OpCode::*;
1105        let roots = &RootSet::default();
1106        let cx = &mut Context::new(roots);
1107        sym::init_symbols();
1108
1109        // (lambda () (let ((load-path 5)) load-path))
1110        make_bytecode!(
1111            bytecode,
1112            0,
1113            [Constant1, VarBind0, VarRef0, Unbind1, Return],
1114            [sym::LOAD_PATH, 5],
1115            cx
1116        );
1117        check_bytecode!(bytecode, [], 5, cx);
1118    }
1119
1120    #[test]
1121    fn test_bytecode_advanced() {
1122        use OpCode::*;
1123        let roots = &RootSet::default();
1124        let cx = &mut Context::new(roots);
1125
1126        let mut table = HashTable::default();
1127        table.insert(1.into(), 6.into());
1128        table.insert(2.into(), 8.into());
1129        table.insert(3.into(), 10.into());
1130
1131        // (lambda (n)
1132        //   (cond ((equal n 1) 1)
1133        //         ((equal n 2) 2)
1134        //         ((equal n 3) 3)))
1135        make_bytecode!(
1136            bytecode,
1137            257,
1138            [
1139                Duplicate, Constant0, Switch, Goto, 0x0C, 0x00, Constant1, Return, Constant2,
1140                Return, Constant3, Return, Constant4, Return
1141            ],
1142            [table, 4, 5, 6, false],
1143            cx
1144        );
1145        check_bytecode!(bytecode, [1], 4, cx);
1146        check_bytecode!(bytecode, [2], 5, cx);
1147        check_bytecode!(bytecode, [3], 6, cx);
1148        check_bytecode!(bytecode, [4], false, cx);
1149
1150        // (1+ (let ((a 1) (_b) (_c)) a))
1151        make_bytecode!(
1152            bytecode,
1153            0,
1154            [Constant0, Constant1, Duplicate, StackRef2, DiscardN, 0x83, Add1, Return],
1155            [1, false],
1156            cx
1157        );
1158        check_bytecode!(bytecode, [], 2, cx);
1159
1160        // (lambda () (list 1 2 3 4 5 6))
1161        make_bytecode!(
1162            bytecode,
1163            0,
1164            [
1165                Constant0, Constant1, Constant2, Constant3, Constant4, Constant5, ListN, 6, Return
1166            ],
1167            [1, 2, 3, 4, 5, 6],
1168            cx
1169        );
1170        let list = list![1, 2, 3, 4, 5, 6; cx];
1171        root!(list, cx);
1172        check_bytecode!(bytecode, [], list, cx);
1173
1174        // hand rolled bytecode
1175        // (lambda () (list 1 2 3 4 5 6) 7)
1176        make_bytecode!(
1177            bytecode,
1178            0,
1179            [
1180                Constant6, Constant0, Constant1, Constant2, Constant3, Constant4, Constant5, ListN,
1181                6, DiscardN, 1, Return
1182            ],
1183            [1, 2, 3, 4, 5, 6, 7],
1184            cx
1185        );
1186        check_bytecode!(bytecode, [], 7, cx);
1187    }
1188
1189    #[test]
1190    fn test_handlers() {
1191        use OpCode as O;
1192
1193        let roots = &RootSet::default();
1194        let cx = &mut Context::new(roots);
1195        sym::init_symbols();
1196        let err = Cons::new1(sym::ERROR, cx);
1197
1198        // (lambda (y) (condition-case nil
1199        //            (floor)
1200        //              (error (+ y 4))))
1201        make_bytecode!(
1202            bytecode,
1203            257,
1204            [
1205                O::Constant0,
1206                O::PushCondtionCase,
1207                0x09,
1208                0x0,
1209                O::Constant1,
1210                O::StackRef1,
1211                O::Call1,
1212                O::PopHandler,
1213                O::Return,
1214                O::Discard,
1215                O::Duplicate,
1216                O::Constant2,
1217                O::Plus,
1218                O::Return
1219            ],
1220            [err, sym::SYMBOL_NAME, 4],
1221            cx
1222        );
1223        check_bytecode!(bytecode, [3], 7, cx);
1224        check_bytecode!(bytecode, [sym::FLOOR], "floor", cx);
1225    }
1226
1227    #[test]
1228    fn test_recursive_handlers() {
1229        use OpCode as O;
1230
1231        let roots = &RootSet::default();
1232        let cx = &mut Context::new(roots);
1233        sym::init_symbols();
1234        let err = Cons::new1(sym::ERROR, cx);
1235
1236        // (lambda () (floor))
1237        // ;; This will error out
1238        make_bytecode!(inner, 0, [O::Constant0, O::Call0, O::Return], [sym::FLOOR], cx);
1239
1240        // (lambda (x)
1241        //    (condition-case nil
1242        //        (funcall x)
1243        //      (error 7)))
1244        make_bytecode!(
1245            outer,
1246            257,
1247            [
1248                O::Constant0,
1249                O::PushCondtionCase,
1250                0x08,
1251                0x0,
1252                O::Duplicate,
1253                O::Call0,
1254                O::PopHandler,
1255                O::Return,
1256                O::Discard,
1257                O::Constant1,
1258                O::Return
1259            ],
1260            [err, 7],
1261            cx
1262        );
1263        let inner = cx.add(inner.bind(cx));
1264        root!(inner, cx);
1265        check_bytecode!(outer, [inner], 7, cx);
1266    }
1267}