rust_grammar_dpdfa/
rt.rs

1use std::{
2    cmp::Ordering,
3    iter,
4    marker::Copy,
5    mem,
6    ops::{Add, AddAssign, Index, IndexMut, Sub},
7};
8
9use smallvec::SmallVec;
10
11use crate::token::TokenDescription;
12
13const PARSING_FUEL: usize = 256;
14
15#[derive(Clone, Debug, PartialEq)]
16pub(crate) struct Program {
17    pub(crate) functions: &'static [Function],
18}
19
20#[derive(Clone, Debug, PartialEq)]
21pub(crate) struct Function {
22    pub(crate) name: &'static str,
23    pub(crate) code: &'static [Instruction],
24    // Registers #0..#n are used for function arguments.
25    //
26    // Next registers are used for local variables.
27    pub(crate) reg_num: usize,
28}
29
30impl Index<Address> for Function {
31    type Output = Instruction;
32
33    fn index(&self, index: Address) -> &Instruction {
34        &self.code[index.0 as usize]
35    }
36}
37
38#[derive(Clone, Copy, Debug, PartialEq)]
39pub(crate) enum Instruction {
40    LoadConst(Register, Value),
41    #[expect(dead_code)]
42    Copy {
43        src: Register,
44        dst: Register,
45    },
46    Sub {
47        lhs: Register,
48        rhs: Register,
49        out: Register,
50    },
51    #[expect(dead_code)]
52    Add {
53        lhs: Register,
54        rhs: Register,
55        out: Register,
56    },
57    Jump {
58        address: Address,
59    },
60    JumpIfZero {
61        cond: Register,
62        address: Address,
63    },
64    JumpIfNonZero {
65        cond: Register,
66        address: Address,
67    },
68    Invert {
69        src: Register,
70        dst: Register,
71    },
72    #[expect(dead_code)]
73    PushArg(Register),
74    Call {
75        function: FunctionId,
76        result: Register,
77    },
78    Return(Register),
79    Peek {
80        tok: TokenDescription,
81        reg: Register,
82    },
83    PeekAny {
84        reg: Register,
85    },
86    Peek2 {
87        tok: TokenDescription,
88        reg: Register,
89    },
90    #[expect(dead_code)]
91    Peek3 {
92        tok: TokenDescription,
93        reg: Register,
94    },
95    BumpToken {
96        tok: TokenDescription,
97    },
98    Bump,
99    Error,
100}
101
102#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
103pub(crate) struct Register(pub u8);
104
105#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
106pub(crate) struct Address(pub u32);
107
108impl Address {
109    #[expect(dead_code)]
110    fn next(self) -> Address {
111        Address(self.0 + 1)
112    }
113
114    fn prev(self) -> Address {
115        Address(self.0 - 1)
116    }
117}
118
119impl AddAssign<u32> for Address {
120    fn add_assign(&mut self, rhs: u32) {
121        self.0 += rhs;
122    }
123}
124
125#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
126pub(crate) struct FunctionId(pub(crate) u32);
127
128#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
129pub(crate) struct Value(pub(crate) i8);
130
131impl Value {
132    const ONE: Value = Value(1);
133    const ZERO: Value = Value(0);
134
135    fn is_zero(self) -> bool {
136        self.0 == 0
137    }
138}
139
140impl Add for Value {
141    type Output = Value;
142
143    fn add(self, rhs: Value) -> Value {
144        Value(self.0 + rhs.0)
145    }
146}
147
148impl Sub for Value {
149    type Output = Value;
150
151    fn sub(self, rhs: Value) -> Value {
152        Value(self.0 - rhs.0)
153    }
154}
155
156#[derive(Clone, Debug)]
157pub struct Interpreter<'code, Span> {
158    program: &'code Program,
159    // Allows to assign frame ids.
160    frame_counter: usize,
161    // Allows to assign description ids.
162    descr_counter: usize,
163    stack: Vec<StackFrame<'code>>,
164    token_buffer: TokenBuffer<Span>,
165    next_call_args: Vec<Value>,
166}
167
168impl<'code, Span> Interpreter<'code, Span>
169where
170    Span: Copy,
171{
172    pub(crate) fn new(program: &'code Program, main_fn: FunctionId) -> Interpreter<'code, Span> {
173        let mut this = Self {
174            program,
175            frame_counter: 0,
176            descr_counter: 0,
177            stack: Vec::new(),
178            token_buffer: TokenBuffer::EMPTY,
179            next_call_args: Vec::new(),
180        };
181
182        let main_frame = this.create_stack_frame(main_fn);
183        this.stack.push(main_frame);
184
185        this
186    }
187
188    pub fn step(
189        &mut self,
190        token_description: TokenDescription,
191        span: Span,
192    ) -> Result<Transition, (Vec<TokenDescription>, Span)> {
193        let trans = if self.token_buffer.status() == TokenBufferStatus::Full {
194            self.perform_progress()?
195        } else {
196            Transition::empty(self.token_buffer, self.stack.last().unwrap())
197        };
198
199        let reserved_id = self.descr_id();
200        self.token_buffer.push(token_description, span, reserved_id);
201
202        Ok(trans)
203    }
204
205    pub fn finish(&mut self, end_span: Span) -> Result<Transition, (Vec<TokenDescription>, Span)> {
206        // Keep calling `perform_progress` and progressively fill the buffer
207        // with `Eof` tokens, until it contains only `Eof` tokens.
208
209        // Safety measure: make sure the buffer is full before doing anything.
210        self.fill_buffer(end_span);
211
212        let mut trans = Transition::empty(self.token_buffer, self.stack.last().unwrap());
213
214        let mut finish_fuel = PARSING_FUEL;
215        let mut tried = Vec::new();
216        while self.token_buffer.first().unwrap().0 != TokenDescription::Eof {
217            assert!(finish_fuel > 0, "Out of finishing fuel.");
218            finish_fuel -= 1;
219
220            trans += self.perform_progress()?;
221
222            // Safety measure: make sure the buffer is full before doing anything.
223            self.fill_buffer(end_span);
224        }
225
226        // Now that the buffer is full of EOF tokens (which can't be consumed),
227        // we run the interpreter until the stack is empty.
228        let mut finish_fuel = PARSING_FUEL;
229        tried.clear();
230        while !self.stack.is_empty() {
231            if finish_fuel == 0 {
232                return Err((Vec::new(), end_span));
233            }
234            finish_fuel -= 1;
235
236            match self.run_instruction(&mut trans, &mut tried) {
237                Ok(()) => {}
238                Err(span) => return Err((tried, span)),
239            };
240
241            // Safety measure: make sure the buffer is full before doing anything.
242            self.fill_buffer(end_span);
243        }
244
245        Ok(trans)
246    }
247
248    fn fill_buffer(&mut self, end_span: Span) {
249        while self.token_buffer.status() != TokenBufferStatus::Full {
250            let reserved_id = self.descr_id();
251            self.token_buffer
252                .push(TokenDescription::Eof, end_span, reserved_id);
253        }
254    }
255
256    fn perform_progress(&mut self) -> Result<Transition, (Vec<TokenDescription>, Span)> {
257        let mut fuel = PARSING_FUEL;
258        let mut trans = Transition::empty(self.token_buffer, self.stack.last().unwrap());
259        let mut tried = Vec::<TokenDescription>::new();
260
261        while self.token_buffer.status() == TokenBufferStatus::Full {
262            assert!(fuel > 0, "Out of parsing fuel.");
263            fuel -= 1;
264
265            match self.run_instruction(&mut trans, &mut tried) {
266                Ok(()) => {}
267                Err(span) => return Err((tried, span)),
268            }
269        }
270
271        Ok(trans)
272    }
273
274    fn run_instruction(
275        &mut self,
276        transition: &mut Transition,
277        tried: &mut Vec<TokenDescription>,
278    ) -> Result<(), Span> {
279        let current_frame = match self.stack.last_mut() {
280            Some(frame) => frame,
281            None => {
282                return Err(self.token_buffer.first().unwrap().1);
283            }
284        };
285
286        transition.log_frame_usage(current_frame);
287
288        let current_instr = current_frame[current_frame.ip];
289
290        current_frame.ip += 1;
291
292        match current_instr {
293            // Regular VM instructions.
294            Instruction::LoadConst(reg, val) => {
295                current_frame[reg] = val;
296            }
297
298            Instruction::Copy { src, dst } => {
299                current_frame[dst] = current_frame[src];
300            }
301
302            Instruction::Sub { lhs, rhs, out } => {
303                current_frame[out] = current_frame[lhs] - current_frame[rhs];
304            }
305
306            Instruction::Add { lhs, rhs, out } => {
307                current_frame[out] = current_frame[lhs] + current_frame[rhs];
308            }
309
310            Instruction::Jump { address } => {
311                current_frame.ip = address;
312            }
313
314            Instruction::JumpIfZero { cond, address } => {
315                if current_frame[cond].is_zero() {
316                    current_frame.ip = address;
317                }
318            }
319
320            Instruction::JumpIfNonZero { cond, address } => {
321                if !current_frame[cond].is_zero() {
322                    current_frame.ip = address;
323                }
324            }
325
326            Instruction::Invert { src, dst } => {
327                let out_val = if current_frame[src].is_zero() {
328                    Value::ONE
329                } else {
330                    Value::ZERO
331                };
332
333                current_frame[dst] = out_val;
334            }
335
336            Instruction::PushArg(reg) => {
337                self.next_call_args.push(current_frame[reg]);
338            }
339
340            Instruction::Call { function, .. } => {
341                let new_frame = self.create_stack_frame(function);
342
343                transition.log_frame_usage(&new_frame);
344                self.stack.push(new_frame);
345
346                return Ok(());
347            }
348
349            Instruction::Return(reg) => {
350                let return_value = current_frame[reg];
351
352                self.stack.pop();
353
354                if let Some(frame) = self.stack.last_mut() {
355                    transition.log_frame_usage(frame);
356
357                    // Backtrack to get the register in which the return value should be stored.
358                    let call_instr = frame[frame.ip.prev()];
359                    let return_reg = match call_instr {
360                        Instruction::Call { result, .. } => result,
361                        _ => unreachable!(),
362                    };
363
364                    frame[return_reg] = return_value;
365
366                    // Safety measure against bad codegen :)
367                    self.next_call_args.clear();
368                }
369
370                return Ok(());
371            }
372
373            // Parsing-specific instructions.
374            Instruction::Peek { tok, reg } => {
375                tried.push(tok);
376
377                let tok_ = self.token_buffer.first().unwrap().0;
378
379                if tok_ == tok || tok_.try_split_with(tok).is_some() {
380                    current_frame[reg] = Value::ONE;
381                } else {
382                    current_frame[reg] = Value::ZERO;
383                }
384            }
385
386            Instruction::PeekAny { reg } => {
387                let any = matches!(self.token_buffer.first(), Some((tok, _)) if tok != TokenDescription::Eof);
388
389                if any {
390                    current_frame[reg] = Value::ONE;
391                } else {
392                    current_frame[reg] = Value::ZERO;
393                }
394            }
395
396            Instruction::Peek2 { tok, reg } => {
397                let tok_ = self.token_buffer.second().unwrap().0;
398                if tok_ == tok {
399                    current_frame[reg] = Value::ONE;
400                } else {
401                    current_frame[reg] = Value::ZERO;
402                }
403            }
404
405            Instruction::Peek3 { tok, reg } => {
406                let tok_ = self.token_buffer.third().unwrap().0;
407                if tok_ == tok {
408                    current_frame[reg] = Value::ONE;
409                } else {
410                    current_frame[reg] = Value::ZERO;
411                }
412            }
413
414            Instruction::BumpToken { tok } => {
415                tried.push(tok);
416                let (tok_, span) = self.token_buffer.first().unwrap();
417
418                if tok_ == tok {
419                    self.token_buffer.pop_front();
420                } else if let Some(head) = tok_.try_split_with(tok) {
421                    let reserved_id = self.descr_id();
422                    self.token_buffer.set_head(head, reserved_id);
423                } else {
424                    return Err(span);
425                }
426            }
427
428            Instruction::Bump => {
429                self.token_buffer.pop_front();
430            }
431
432            Instruction::Error => {
433                return Err(self.token_buffer.first().unwrap().1);
434            }
435        }
436
437        Ok(())
438    }
439
440    fn create_stack_frame(&mut self, function: FunctionId) -> StackFrame<'code> {
441        let id = self.frame_id();
442
443        let function = &self.program.functions[function.0 as usize];
444        let fn_locals_num = function.reg_num - self.next_call_args.len();
445
446        let registers = iter::once(Value::ZERO) // Return value.
447            .chain(mem::take(&mut self.next_call_args)) // Arguments
448            .chain(iter::repeat(Value::ZERO).take(fn_locals_num)) // Locals
449            .collect::<Vec<_>>();
450
451        StackFrame {
452            id,
453            function,
454            ip: Address(0),
455            registers,
456        }
457    }
458
459    fn frame_id(&mut self) -> StackFrameId {
460        let id = self.frame_counter;
461        self.frame_counter += 1;
462        StackFrameId(id)
463    }
464
465    fn descr_id(&mut self) -> DescrId {
466        let id_ = DescrId(self.descr_counter);
467        self.descr_counter += 1;
468
469        id_
470    }
471
472    pub fn initial_transition(&self) -> Transition {
473        Transition::empty(self.token_buffer, self.stack.last().unwrap())
474    }
475}
476
477impl<Span> PartialEq for Interpreter<'_, Span>
478where
479    Span: Copy,
480{
481    fn eq(&self, other: &Interpreter<'_, Span>) -> bool {
482        // Let's assume we can skip the program part - it will always be the same.
483
484        self.frame_counter.eq(&other.frame_counter)
485            && self.descr_counter.eq(&other.descr_counter)
486            && self.stack.eq(&other.stack)
487            && self.token_buffer.eq(&other.token_buffer)
488            && self.next_call_args.eq(&other.next_call_args)
489    }
490}
491impl<Span> Eq for Interpreter<'_, Span> where Span: Copy {}
492
493impl<Span> PartialOrd for Interpreter<'_, Span>
494where
495    Span: Copy,
496{
497    fn partial_cmp(&self, other: &Interpreter<'_, Span>) -> Option<Ordering> {
498        Some(self.cmp(other))
499    }
500}
501
502impl<Span> Ord for Interpreter<'_, Span>
503where
504    Span: Copy,
505{
506    fn cmp(&self, other: &Interpreter<'_, Span>) -> Ordering {
507        // Skipping the `program` field - it is and will always be - the same.
508        //
509        // Skipping the `*_counter` fields - they don't represent the state of
510        // the interpreter - only the state of the future executions.
511        self.stack
512            .cmp(&other.stack)
513            .then_with(|| self.token_buffer.cmp(&other.token_buffer))
514            .then_with(|| self.next_call_args.cmp(&other.next_call_args))
515    }
516}
517
518#[derive(Clone, Debug)]
519struct StackFrame<'code> {
520    // Each stack frame has its own unique id. This allows us to properly
521    // multiple transitions into one.
522    id: StackFrameId,
523    function: &'code Function,
524    ip: Address,
525    registers: Vec<Value>,
526}
527
528impl PartialOrd for StackFrame<'_> {
529    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
530        Some(self.cmp(other))
531    }
532}
533
534impl Ord for StackFrame<'_> {
535    fn cmp(&self, other: &Self) -> Ordering {
536        // Skipping the `function` field - it will always be the same.
537        //
538        // Skipping the `id` field - it will always be the same.
539        self.ip
540            .cmp(&other.ip)
541            .then_with(|| self.registers.cmp(&other.registers))
542    }
543}
544
545impl PartialEq for StackFrame<'_> {
546    fn eq(&self, other: &Self) -> bool {
547        self.cmp(other) == Ordering::Equal
548    }
549}
550
551impl Eq for StackFrame<'_> {}
552
553impl Index<Register> for StackFrame<'_> {
554    type Output = Value;
555
556    fn index(&self, index: Register) -> &Value {
557        &self.registers[index.0 as usize]
558    }
559}
560
561impl IndexMut<Register> for StackFrame<'_> {
562    fn index_mut(&mut self, index: Register) -> &mut Value {
563        &mut self.registers[index.0 as usize]
564    }
565}
566
567impl Index<Address> for StackFrame<'_> {
568    type Output = Instruction;
569
570    fn index(&self, index: Address) -> &Instruction {
571        &self.function[index]
572    }
573}
574
575#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
576pub(crate) struct StackFrameId(pub(crate) usize);
577
578#[derive(Clone, Copy, Debug)]
579enum TokenBuffer<Span> {
580    Zero([TokenBufferSlot<Span>; 0]),
581    One([TokenBufferSlot<Span>; 1]),
582    Two([TokenBufferSlot<Span>; 2]),
583    Three([TokenBufferSlot<Span>; 3]),
584}
585
586impl<Span> Eq for TokenBuffer<Span> where Span: Copy {}
587
588impl<Span> PartialEq for TokenBuffer<Span>
589where
590    Span: Copy,
591{
592    fn eq(&self, other: &Self) -> bool {
593        self.as_slice().eq(other.as_slice())
594    }
595}
596
597impl<Span> PartialOrd for TokenBuffer<Span>
598where
599    Span: Copy,
600{
601    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
602        Some(self.cmp(other))
603    }
604}
605
606impl<Span> Ord for TokenBuffer<Span>
607where
608    Span: Copy,
609{
610    fn cmp(&self, other: &Self) -> Ordering {
611        self.as_slice().cmp(other.as_slice())
612    }
613}
614
615#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
616struct DescrId(usize);
617
618impl<Span> TokenBuffer<Span>
619where
620    Span: Copy,
621{
622    const EMPTY: TokenBuffer<Span> = TokenBuffer::Zero([]);
623
624    fn as_slice(&self) -> &[TokenBufferSlot<Span>] {
625        match self {
626            TokenBuffer::Zero(inner) => inner,
627            TokenBuffer::One(inner) => inner,
628            TokenBuffer::Two(inner) => inner,
629            TokenBuffer::Three(inner) => inner,
630        }
631    }
632
633    fn status(&self) -> TokenBufferStatus {
634        match self {
635            TokenBuffer::Zero(_) => TokenBufferStatus::Empty,
636            TokenBuffer::One(_) => TokenBufferStatus::One,
637            TokenBuffer::Two(_) => TokenBufferStatus::Two,
638            TokenBuffer::Three(_) => TokenBufferStatus::Full,
639        }
640    }
641
642    fn push(&mut self, descr: TokenDescription, span: Span, id: DescrId) {
643        let slot = TokenBufferSlot { descr, span, id };
644
645        match self {
646            TokenBuffer::Zero([]) => {
647                *self = TokenBuffer::One([slot]);
648            }
649            TokenBuffer::One([a]) => {
650                *self = TokenBuffer::Two([*a, slot]);
651            }
652            TokenBuffer::Two([a, b]) => {
653                *self = TokenBuffer::Three([*a, *b, slot]);
654            }
655            TokenBuffer::Three(_) => {
656                panic!("Token buffer is full");
657            }
658        }
659    }
660
661    fn first(&self) -> Option<(TokenDescription, Span)> {
662        match self.as_slice() {
663            [] => None,
664            [TokenBufferSlot { descr, span, .. }, ..] => Some((*descr, *span)),
665        }
666    }
667
668    pub(crate) fn second(&self) -> Option<(TokenDescription, Span)> {
669        match self.as_slice() {
670            [] | [_] => None,
671            [_, TokenBufferSlot { descr, span, .. }, ..] => Some((*descr, *span)),
672        }
673    }
674
675    pub(crate) fn third(&self) -> Option<(TokenDescription, Span)> {
676        match self.as_slice() {
677            [] | [_] | [_, _] => None,
678            [_, _, TokenBufferSlot { descr, span, .. }, ..] => Some((*descr, *span)),
679        }
680    }
681
682    fn pop_front(&mut self) {
683        match self {
684            TokenBuffer::Zero([]) => unreachable!(),
685
686            TokenBuffer::One([_, remaining @ ..]) => {
687                *self = TokenBuffer::Zero(*remaining);
688            }
689
690            TokenBuffer::Two([_, remaining @ ..]) => {
691                *self = TokenBuffer::One(*remaining);
692            }
693
694            TokenBuffer::Three([_, remaining @ ..]) => {
695                *self = TokenBuffer::Two(*remaining);
696            }
697        }
698    }
699
700    fn set_head(&mut self, descr_: TokenDescription, id_: DescrId) {
701        match self {
702            TokenBuffer::Zero([]) => panic!("`set_head` called en empty buffer"),
703
704            TokenBuffer::One([TokenBufferSlot { descr, id, .. }])
705            | TokenBuffer::Two([TokenBufferSlot { descr, id, .. }, _])
706            | TokenBuffer::Three([TokenBufferSlot { descr, id, .. }, _, _]) => {
707                *descr = descr_;
708                *id = id_;
709            }
710        }
711    }
712
713    fn as_small_vec(&self) -> SmallVec<[(TokenDescription, DescrId); 16]> {
714        self.as_slice()
715            .iter()
716            .copied()
717            .map(TokenBufferSlot::forget_span)
718            .collect()
719    }
720}
721
722#[derive(Clone, Copy, Debug)]
723struct TokenBufferSlot<Span> {
724    descr: TokenDescription,
725    span: Span,
726    id: DescrId,
727}
728
729impl<Span> PartialEq for TokenBufferSlot<Span> {
730    fn eq(&self, other: &TokenBufferSlot<Span>) -> bool {
731        (self.descr, self.id).eq(&(other.descr, other.id))
732    }
733}
734
735impl<Span> Eq for TokenBufferSlot<Span> {}
736
737impl<Span> Ord for TokenBufferSlot<Span> {
738    fn cmp(&self, other: &TokenBufferSlot<Span>) -> Ordering {
739        // Skipping the `span` field. We are generic over this :).
740        //
741        // Skipping the `id` field - it is only used for token deduplication
742        // when two transitions are added.
743        self.descr.cmp(&other.descr)
744    }
745}
746
747impl<Span> PartialOrd for TokenBufferSlot<Span> {
748    fn partial_cmp(&self, other: &TokenBufferSlot<Span>) -> Option<Ordering> {
749        Some(self.cmp(other))
750    }
751}
752
753impl<Span> TokenBufferSlot<Span> {
754    fn forget_span(self) -> (TokenDescription, DescrId) {
755        (self.descr, self.id)
756    }
757}
758
759#[derive(Debug, PartialEq)]
760enum TokenBufferStatus {
761    Empty,
762    One,
763    Two,
764    Full,
765}
766
767#[derive(Clone, Debug, Eq, PartialEq)]
768pub struct Transition {
769    // All the tokens that have been used for the transition, including those
770    // in the token buffer.
771    buffer: SmallVec<[(TokenDescription, DescrId); 16]>,
772    // The top of the stack that is used for the transition. Reversed.
773    stack_top_rev: Vec<FrameDescr>,
774}
775
776impl Transition {
777    fn empty<Span>(buffer: TokenBuffer<Span>, stack_top: &StackFrame) -> Transition
778    where
779        Span: Copy,
780    {
781        let buffer = buffer.as_small_vec();
782        let top = FrameDescr::for_frame(stack_top);
783
784        Transition {
785            buffer,
786            stack_top_rev: vec![top],
787        }
788    }
789
790    /// Must be called before the frame usage.
791    ///
792    /// Do not call this with a frame that has been popped earlier.
793    fn log_frame_usage(&mut self, frame: &StackFrame) {
794        if frame.id < self.stack_top_rev.last().unwrap().id {
795            // The used frame is older (smaller id). It is therefore a parent of
796            // the top frame. We need to log it.
797
798            self.stack_top_rev.push(FrameDescr::for_frame(frame));
799        }
800    }
801}
802
803impl AddAssign for Transition {
804    fn add_assign(&mut self, rhs: Transition) {
805        // We find the first token that is common to both the `self` and `rhs`,
806        // then we push everything that comes after in `rhs` to `self`.
807        let last_known_descr_id = self.buffer.last().map(|(_, id)| id);
808
809        let to_append = match last_known_descr_id {
810            Some(id) => {
811                let idx_to_start_from = rhs
812                    .buffer
813                    .iter()
814                    .enumerate()
815                    .find(|(_, (_, id_))| id_ == id)
816                    .map(|(idx, _)| idx);
817
818                match idx_to_start_from {
819                    Some(idx) if idx + 1 < rhs.buffer.len() => &rhs.buffer[idx + 1..],
820                    Some(_) => &[],
821                    None => &rhs.buffer,
822                }
823            }
824            None => rhs.buffer.as_slice(),
825        };
826
827        self.buffer.extend_from_slice(to_append);
828
829        let mut to_append = rhs
830            .stack_top_rev
831            .into_iter()
832            .filter(|frame| self.stack_top_rev.last().unwrap().id > frame.id)
833            .collect();
834
835        self.stack_top_rev.append(&mut to_append);
836    }
837}
838
839impl Add for Transition {
840    type Output = Transition;
841
842    fn add(mut self, rhs: Transition) -> Transition {
843        self += rhs;
844        self
845    }
846}
847
848impl PartialOrd for Transition {
849    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
850        Some(self.cmp(other))
851    }
852}
853
854impl Ord for Transition {
855    fn cmp(&self, rhs: &Self) -> Ordering {
856        self.buffer
857            .iter()
858            .map(|(descr, _)| descr)
859            .cmp(rhs.buffer.iter().map(|(descr, _)| descr))
860            .then_with(|| {
861                self.buffer
862                    .iter()
863                    .map(|(descr, _)| descr)
864                    .cmp(rhs.buffer.iter().map(|(descr, _)| descr))
865            })
866    }
867}
868
869#[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd)]
870struct FrameDescr {
871    id: StackFrameId,
872    // The IP at the beginning of the transition.
873    ip: Address,
874    // The value of the registers at the beginning of the transition.
875    registers: Vec<Value>,
876}
877
878impl FrameDescr {
879    fn for_frame(frame: &StackFrame) -> FrameDescr {
880        FrameDescr {
881            id: frame.id,
882            ip: frame.ip,
883            registers: frame.registers.clone(),
884        }
885    }
886}