fugue_ir/disassembly/
walker.rs

1use crate::address::AddressValue;
2use crate::disassembly::context::ContextDatabase;
3use crate::disassembly::pattern::PatternExpression;
4use crate::disassembly::symbol::{Constructor, FixedHandle, Operands, Symbol, SymbolTable, Tokens};
5use crate::disassembly::{Error, IRBuilderArena};
6use crate::space_manager::SpaceManager;
7
8use std::cell::RefCell;
9use std::fmt;
10use std::mem::size_of;
11use std::ops::Range;
12
13pub use bumpalo::collections::String as BString;
14pub use bumpalo::collections::Vec as BVec;
15
16use bumpalo::vec as bvec;
17
18use unsafe_unwrap::UnsafeUnwrap;
19
20const MAX_PARSE_DEPTH: usize = 64 + 1;
21
22pub struct InstructionFormatter<'b, 'c, 'z> {
23    walker: RefCell<ParserWalker<'b, 'c, 'z>>,
24    symbols: &'b SymbolTable,
25    ctor: &'b Constructor,
26}
27
28pub struct MnemonicFormatter<'a, 'b, 'c, 'z> {
29    inner: &'a InstructionFormatter<'b, 'c, 'z>,
30}
31
32pub struct OperandFormatter<'a, 'b, 'c, 'z> {
33    inner: &'a InstructionFormatter<'b, 'c, 'z>,
34}
35
36impl<'b, 'c, 'z> InstructionFormatter<'b, 'c, 'z> {
37    pub fn new(
38        walker: ParserWalker<'b, 'c, 'z>,
39        symbols: &'b SymbolTable,
40        ctor: &'b Constructor,
41    ) -> Self {
42        Self {
43            walker: RefCell::new(walker),
44            symbols,
45            ctor,
46        }
47    }
48
49    pub fn mnemonic<'a>(&'a self) -> MnemonicFormatter<'a, 'b, 'c, 'z> {
50        MnemonicFormatter { inner: self }
51    }
52
53    pub fn mnemonic_str<'az>(&self, irb: &'az IRBuilderArena) -> BString<'az> {
54        bumpalo::format!(in irb.inner(), "{}", self.mnemonic())
55    }
56
57    pub fn operands<'a>(&'a self) -> OperandFormatter<'a, 'b, 'c, 'z> {
58        OperandFormatter { inner: self }
59    }
60
61    pub fn operands_str<'az>(&self, irb: &'az IRBuilderArena) -> BString<'az> {
62        bumpalo::format!(in irb.inner(), "{}", self.operands())
63    }
64
65    pub fn operand_data<'az>(&self, irb: &'az IRBuilderArena) -> Operands<'b, 'az> {
66        self.ctor
67            .operands(irb, &mut self.walker.borrow_mut(), self.symbols)
68    }
69
70    pub fn tokens<'az>(&self, irb: &'az IRBuilderArena) -> (Tokens<'b, 'az>, Tokens<'b, 'az>) {
71        let mut mnemonic_tokens = Tokens::new(irb);
72        self.ctor.mnemonic_tokens(
73            &mut mnemonic_tokens,
74            &mut self.walker.borrow_mut(),
75            self.symbols,
76        );
77
78        let mut body_tokens = Tokens::new(irb);
79        self.ctor.body_tokens(
80            &mut body_tokens,
81            &mut self.walker.borrow_mut(),
82            self.symbols,
83        );
84
85        (mnemonic_tokens, body_tokens)
86    }
87}
88
89impl<'b, 'c, 'z> fmt::Display for InstructionFormatter<'b, 'c, 'z> {
90    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
91        self.ctor
92            .format_mnemonic(f, &mut self.walker.borrow_mut(), self.symbols)?;
93        write!(f, " ")?;
94        self.ctor
95            .format_body(f, &mut self.walker.borrow_mut(), self.symbols)?;
96        Ok(())
97    }
98}
99
100impl<'a, 'b, 'c, 'z> fmt::Display for MnemonicFormatter<'a, 'b, 'c, 'z> {
101    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
102        self.inner.ctor.format_mnemonic(
103            f,
104            &mut self.inner.walker.borrow_mut(),
105            self.inner.symbols,
106        )?;
107        Ok(())
108    }
109}
110
111impl<'a, 'b, 'c, 'z> fmt::Display for OperandFormatter<'a, 'b, 'c, 'z> {
112    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
113        self.inner
114            .ctor
115            .format_body(f, &mut self.inner.walker.borrow_mut(), self.inner.symbols)?;
116        Ok(())
117    }
118}
119
120#[derive(Clone)]
121pub struct ConstructState<'b> {
122    parent: Option<usize>,
123    constructor: Option<&'b Constructor>,
124    handle: Option<FixedHandle<'b>>,
125    resolve: [Option<usize>; 64],
126    length: usize,
127    offset: usize,
128}
129
130impl<'b> ConstructState<'b> {
131    pub fn set_parent(&mut self, parent: usize) {
132        self.parent = Some(parent);
133    }
134}
135
136impl<'b> Default for ConstructState<'b> {
137    fn default() -> Self {
138        Self {
139            parent: None,
140            constructor: None,
141            handle: None,
142            resolve: [None; 64],
143            length: 0,
144            offset: 0,
145        }
146    }
147}
148
149#[derive(Clone)]
150pub struct ContextSet<'b> {
151    triple: &'b Symbol,
152    number: usize,
153    mask: u32,
154    value: u32,
155    point: usize,
156    flow: bool,
157}
158
159#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
160pub enum ParserState {
161    Uninitialised,
162    Disassembly,
163    PCode,
164}
165
166#[derive(Clone)]
167pub struct ParserContext<'b, 'z> {
168    parse_state: ParserState,
169    context: BVec<'z, u32>,
170    context_commit: BVec<'z, ContextSet<'b>>,
171
172    backing: [u8; 16],
173
174    address: AddressValue,
175    next_address: Option<AddressValue>,
176    // next2_address: Option<AddressValue>,
177    delay_slot: usize,
178
179    alloc: usize,
180    state: BVec<'z, ConstructState<'b>>,
181}
182
183impl<'b, 'z> ParserContext<'b, 'z> {
184    pub fn empty(arena: &'z IRBuilderArena, space_manager: &'b SpaceManager) -> Self {
185        Self {
186            parse_state: ParserState::Uninitialised,
187            context: BVec::with_capacity_in(2, arena.inner()),
188            context_commit: BVec::with_capacity_in(2, arena.inner()),
189            backing: [0; 16],
190            address: AddressValue::new(space_manager.default_space(), 0),
191            next_address: None,
192            // next2_address: None,
193            delay_slot: 0,
194            alloc: 1,
195            state: bvec![in arena.inner(); ConstructState::default(); 75],
196        }
197    }
198
199    pub fn new(
200        arena: &'z IRBuilderArena,
201        context_db: &ContextDatabase,
202        address: AddressValue,
203        buffer: &[u8],
204    ) -> Self {
205        let mut backing = [0u8; 16];
206        let length = buffer.len().min(backing.len());
207
208        backing[..length].copy_from_slice(&buffer[..length]);
209
210        let context = context_db.get_context(&address);
211
212        Self {
213            parse_state: ParserState::Uninitialised,
214            context: BVec::from_iter_in(context.iter().map(|v| *v), arena.inner()),
215            backing,
216            context_commit: BVec::with_capacity_in(2, arena.inner()),
217            address,
218            next_address: None,
219            // next2_address: None,
220            delay_slot: 0,
221            alloc: 1,
222            state: bvec![in arena.inner(); ConstructState::default(); 75], // state * param
223        }
224    }
225
226    pub fn reinitialise(
227        &mut self,
228        _arena: &'z IRBuilderArena,
229        context_db: &ContextDatabase,
230        address: AddressValue,
231        buffer: &[u8],
232    ) {
233        let mut backing = [0u8; 16];
234        let length = buffer.len().min(backing.len());
235
236        backing[..length].copy_from_slice(&buffer[..length]);
237
238        self.parse_state = ParserState::Uninitialised;
239        self.backing = backing;
240        self.context.clear();
241        self.context
242            .extend_from_slice(&context_db.get_context(&address));
243        self.context_commit.clear();
244        self.address = address;
245        self.next_address = None;
246        self.delay_slot = 0;
247        self.alloc = 1;
248
249        //self.state.truncate(1);
250        self.state[0] = Default::default();
251    }
252
253    pub fn allocate_operand(&mut self, parent: Option<usize>) -> usize {
254        let id = self.alloc;
255
256        if self.state.len() <= id {
257            self.state
258                .resize((1 + self.state.len()) * 2, Default::default());
259        }
260
261        let op = unsafe { self.state.get_unchecked_mut(id) };
262
263        op.parent = parent;
264        op.constructor = None;
265        op.handle = None;
266        *unsafe { op.resolve.get_unchecked_mut(0) } = None;
267        op.offset = 0;
268        op.length = 0;
269
270        self.alloc += 1;
271
272        id
273    }
274
275    pub(crate) fn set_constructor(&mut self, point: usize, constructor: &'b Constructor) {
276        unsafe { self.state.get_unchecked_mut(point) }.constructor = Some(constructor);
277    }
278
279    pub(crate) fn set_offset(&mut self, point: usize, offset: usize) {
280        unsafe { self.state.get_unchecked_mut(point) }.offset = offset;
281    }
282
283    pub(crate) fn point(&self, point: usize) -> &ConstructState<'b> {
284        unsafe { self.state.get_unchecked(point) }
285    }
286
287    pub(crate) fn point_mut(&mut self, point: usize) -> &mut ConstructState<'b> {
288        unsafe { self.state.get_unchecked_mut(point) }
289    }
290
291    pub(crate) fn set_handle(&mut self, point: usize, handle: FixedHandle<'b>) {
292        unsafe { self.state.get_unchecked_mut(point) }.handle = Some(handle);
293    }
294
295    pub fn handle(&self, point: usize) -> Option<&FixedHandle<'b>> {
296        self.state[point].handle.as_ref()
297    }
298
299    pub unsafe fn unchecked_handle(&self, point: usize) -> &FixedHandle<'b> {
300        if let Some(ref handle) = self.state.get_unchecked(point).handle {
301            handle
302        } else {
303            unreachable!()
304        }
305    }
306
307    pub fn handle_mut(&mut self, point: usize) -> Option<&mut FixedHandle<'b>> {
308        self.state[point].handle.as_mut()
309    }
310
311    pub fn base_state(&self) -> &ConstructState {
312        &self.state[0]
313    }
314
315    pub fn base_state_mut(&mut self) -> &mut ConstructState<'b> {
316        &mut self.state[0]
317    }
318
319    pub fn instruction_bytes(
320        &self,
321        start: usize,
322        size: usize,
323        offset: usize,
324    ) -> Result<u32, Error> {
325        let offset = offset + start;
326
327        if offset >= self.backing.len() {
328            return Err(Error::InstructionResolution);
329        }
330
331        //debug_assert!(offset < self.backing.len());
332        //debug_assert!(offset + size <= self.backing.len());
333
334        let size = (self.backing.len() - offset).min(size);
335        let buf = &self.backing[offset..];
336
337        let mut result = 0u32;
338
339        for b in buf.iter().take(size) {
340            result = result << 8;
341            result |= *b as u32;
342        }
343
344        Ok(result)
345    }
346
347    pub fn instruction_bits(&self, start: usize, size: usize, offset: usize) -> Result<u32, Error> {
348        let offset = offset + (start / 8);
349        let start = start % 8;
350        let bytes_size = (start + size - 1) / 8 + 1;
351
352        //debug_assert!(offset < self.backing.len());
353        //debug_assert!(offset + bytes_size <= self.backing.len());
354
355        if offset >= self.backing.len() {
356            return Err(Error::InstructionResolution);
357        }
358
359        let bytes_size = (self.backing.len() - offset).min(bytes_size);
360
361        let buf = &self.backing[offset..];
362        let mut result = 0u32;
363
364        for b in buf.iter().take(bytes_size) {
365            result = result << 8;
366            result |= *b as u32;
367        }
368
369        result = result
370            .checked_shl(8 * (size_of::<u32>() - bytes_size) as u32 + start as u32)
371            .unwrap_or(0);
372        result = result
373            .checked_shr(8 * size_of::<u32>() as u32 - size as u32)
374            .unwrap_or(0);
375
376        Ok(result)
377    }
378
379    pub fn context_bytes(&self, start: usize, size: usize) -> u32 {
380        let start_off = start / size_of::<u32>();
381        let bytes_off = start % size_of::<u32>();
382
383        let unused = size_of::<u32>() - size;
384        let mut result = self.context[start_off];
385
386        result = result << (bytes_off as u32 * 8); //.checked_shl(bytes_off as u32 * 8).unwrap_or(0);
387        result = result >> (unused as u32 * 8); //.checked_shr(unused as u32 * 8).unwrap_or(0);
388
389        let remaining = (bytes_off + size).checked_sub(size_of::<u32>());
390
391        if remaining.is_some() && remaining.unwrap() > 0 && start_off + 1 < self.context.len() {
392            let mut nresult = self.context[start_off + 1];
393            let unused = size_of::<u32>() - remaining.unwrap();
394            nresult = nresult >> (unused as u32 * 8); //.checked_shr(unused as u32 * 8).unwrap_or(0);
395            result |= nresult;
396        }
397
398        result
399    }
400
401    pub fn context_bits(&self, start: usize, size: usize) -> u32 {
402        let start_off = start / (8 * size_of::<u32>());
403        let bits_off = start % (8 * size_of::<u32>());
404
405        let unused = 8 * size_of::<u32>() - size;
406        let mut result = self.context[start_off];
407
408        result = result.checked_shl(bits_off as u32).unwrap_or(0);
409        result = result.checked_shr(unused as u32).unwrap_or(0);
410
411        let remaining = (bits_off + size).checked_sub(8 * size_of::<u32>());
412
413        if remaining.is_some() && remaining.unwrap() > 0 && start_off + 1 < self.context.len() {
414            let mut nresult = self.context[start_off + 1];
415            let unused = 8 * size_of::<u32>() - remaining.unwrap();
416            nresult = nresult.checked_shr(unused as u32).unwrap_or(0);
417            result |= nresult;
418        }
419
420        result
421    }
422
423    pub fn set_context_word(&mut self, num: usize, value: u32, mask: u32) {
424        self.context[num] = (self.context[num] & !mask) | (mask & value);
425    }
426
427    pub fn add_commit(
428        &mut self,
429        symbol: &'b Symbol,
430        num: usize,
431        mask: u32,
432        point: usize,
433        flow: bool,
434    ) {
435        let set = ContextSet {
436            triple: symbol,
437            number: num,
438            mask,
439            value: self.context[num] & mask,
440            point,
441            flow,
442        };
443        self.context_commit.push(set);
444    }
445
446    pub fn apply_commits<'a, 'c>(
447        &'c mut self,
448        db: &mut ContextDatabase,
449        manager: &'b SpaceManager,
450        symbols: &'b SymbolTable,
451    ) -> Result<(), Error> {
452        if self.context_commit.is_empty() {
453            return Ok(());
454        }
455
456        let curr_address = self.address.clone();
457        let commits = self.context_commit.clone();
458        let mut nwalker = ParserWalker::<'b, 'c, 'z>::new(self);
459
460        for commit in commits {
461            let symbol = commit.triple;
462            let mut address = if let Symbol::Operand { handle_index, .. } = symbol {
463                let handle =
464                    unsafe { nwalker.unchecked_handle_ref_via(commit.point, *handle_index) };
465                AddressValue::new(handle.space, handle.offset_offset)
466            } else {
467                let handle = symbol.fixed_handle(&mut nwalker, manager, symbols)?;
468                AddressValue::new(handle.space, handle.offset_offset)
469            };
470
471            if address.is_constant() {
472                let space = unsafe { manager.unchecked_space_by_id(curr_address.space()) };
473                let noffset = address.offset() * space.word_size() as u64;
474                address = AddressValue::new(space, noffset);
475            }
476
477            if commit.flow {
478                db.set_context_change_point(
479                    address,
480                    commit.number,
481                    commit.mask,
482                    commit.value,
483                );
484            } else {
485                let naddress = address.clone() + 1usize;
486                if naddress.offset() < address.offset() {
487                    db.set_context_change_point(
488                        address,
489                        commit.number,
490                        commit.mask,
491                        commit.value,
492                    );
493                } else {
494                    db.set_context_region(
495                        address,
496                        Some(naddress),
497                        commit.number,
498                        commit.mask,
499                        commit.value,
500                    );
501                }
502            }
503        }
504
505        Ok(())
506    }
507
508    pub fn constructor(&self, point: usize) -> Option<&'b Constructor> {
509        self.state[point].constructor
510    }
511
512    pub unsafe fn unchecked_constructor(&self, point: usize) -> &'b Constructor {
513        self.state.get_unchecked(point).constructor.unsafe_unwrap()
514    }
515
516    pub fn set_next_address(&mut self, address: AddressValue) {
517        self.next_address = Some(address);
518    }
519
520    pub fn set_state(&mut self, state: ParserState) {
521        self.parse_state = state;
522    }
523}
524
525pub struct ParserWalker<'b, 'c, 'z> {
526    ctx: &'c mut ParserContext<'b, 'z>,
527
528    point: Option<usize>,
529    depth: isize,
530    breadcrumb: [usize; MAX_PARSE_DEPTH],
531}
532
533impl<'b, 'c, 'z> ParserWalker<'b, 'c, 'z> {
534    pub fn new(ctx: &'c mut ParserContext<'b, 'z>) -> Self {
535        Self {
536            ctx,
537            point: Some(0),
538            depth: 0,
539            breadcrumb: [0; MAX_PARSE_DEPTH],
540        }
541    }
542
543    pub fn context_mut(&mut self) -> &mut ParserContext<'b, 'z> {
544        self.ctx
545    }
546
547    pub fn base_state(&mut self) {
548        self.point = Some(0);
549        self.depth = 0;
550        self.breadcrumb[0] = 0;
551    }
552
553    pub fn is_state(&self) -> bool {
554        self.point.is_some()
555    }
556
557    pub fn address(&self) -> AddressValue {
558        self.ctx.address.clone()
559    }
560
561    pub unsafe fn unchecked_next_address(&self) -> &AddressValue {
562        if let Some(ref address) = self.ctx.next_address {
563            address
564        } else {
565            unreachable!()
566        }
567    }
568
569    pub fn next_address(&self) -> Option<AddressValue> {
570        self.ctx.next_address.clone()
571    }
572
573    pub unsafe fn unchecked_next2_address(&self) -> &AddressValue {
574        unimplemented!("inst_next2")
575    }
576
577    pub fn next2_address(&self) -> Option<AddressValue> {
578        None
579    }
580
581    pub fn length(&self) -> usize {
582        self.ctx.point(0).length
583    }
584
585    pub fn set_parent_handle(&mut self, handle: FixedHandle<'b>) {
586        self.ctx
587            .set_handle(unsafe { self.point.unsafe_unwrap() }, handle);
588    }
589
590    pub fn parent_handle_mut(&mut self) -> Option<&mut FixedHandle<'b>> {
591        self.ctx.handle_mut(unsafe { self.point.unsafe_unwrap() })
592    }
593
594    pub fn handle(&self, index: usize) -> Result<Option<FixedHandle<'b>>, Error> {
595        let ph = self
596            .point()
597            .ok_or_else(|| Error::InconsistentState)?
598            .resolve[index]
599            .ok_or_else(|| Error::InconsistentState)?;
600        Ok(self.ctx.handle(ph).map(|v| v.clone()))
601    }
602
603    pub fn handle_ref(&self, index: usize) -> Option<&FixedHandle<'b>> {
604        self.point()
605            .and_then(|ctor| ctor.resolve.get(index))
606            .and_then(|v| *v)
607            .and_then(|hidx| self.ctx.handle(hidx))
608    }
609
610    pub fn handle_ref_via(&self, point: usize, index: usize) -> Option<&FixedHandle<'b>> {
611        self.ctx
612            .point(point)
613            .resolve
614            .get(index)
615            .and_then(|v| *v)
616            .and_then(|hidx| self.ctx.handle(hidx))
617    }
618
619    pub unsafe fn unchecked_handle(&self, index: usize) -> FixedHandle<'b> {
620        self.unchecked_handle_ref(index).clone()
621    }
622
623    pub unsafe fn unchecked_handle_ref(&self, index: usize) -> &FixedHandle<'b> {
624        let ph = self
625            .unchecked_point()
626            .resolve
627            .get_unchecked(index)
628            .unsafe_unwrap();
629        self.ctx.unchecked_handle(ph)
630    }
631
632    pub unsafe fn unchecked_handle_ref_via(&self, point: usize, index: usize) -> &FixedHandle<'b> {
633        let ph = self
634            .ctx
635            .point(point)
636            .resolve
637            .get_unchecked(index)
638            .unsafe_unwrap();
639        self.ctx.unchecked_handle(ph)
640    }
641
642    pub fn set_next_address(&mut self, address: AddressValue) {
643        self.ctx.set_next_address(address);
644    }
645
646    pub fn set_state(&mut self, state: ParserState) {
647        self.ctx.set_state(state);
648    }
649
650    pub fn set_current_length(&mut self, length: usize) {
651        self.ctx
652            .point_mut(unsafe { self.point.unsafe_unwrap() })
653            .length = length;
654    }
655
656    pub fn set_delay_slot(&mut self, delay: usize) {
657        self.ctx.delay_slot = delay;
658    }
659
660    pub fn delay_slot(&self) -> usize {
661        self.ctx.delay_slot
662    }
663
664    /*
665    pub fn calculate_length(&mut self, length: usize, nops: usize) -> Result<(), Error> {
666        if let Some(index) = self.point {
667            let poff = self.ctx.point(index).offset;
668            let length = length + poff;
669            let length = (0..nops).try_fold(length, |length, id| {
670                let subpt = self.ctx.point(
671                    self.ctx.point(index).resolve[id]
672                        .ok_or_else(|| Error::InconsistentState)?
673                );
674                let sub_length = subpt.length + subpt.offset;
675                Ok(length.max(sub_length))
676            })?;
677            self.ctx.point_mut(index).length = length - poff;
678        }
679        Ok(())
680    }
681    */
682
683    pub fn calculate_length(&mut self, length: usize, nops: usize) {
684        let index = unsafe { self.point.unsafe_unwrap() };
685        let poff = self.ctx.point(index).offset;
686
687        let length = length + poff;
688        let length = (0..nops).fold(length, |length, id| {
689            let subpt = self.ctx.point(unsafe {
690                self.ctx
691                    .state
692                    .get_unchecked(index)
693                    .resolve
694                    .get_unchecked(id)
695                    .unsafe_unwrap()
696            });
697            let sub_length = subpt.length + subpt.offset;
698            length.max(sub_length)
699        });
700
701        self.ctx.point_mut(index).length = length - poff;
702    }
703
704    pub fn operand(&self) -> usize {
705        *unsafe { self.breadcrumb.get_unchecked(self.depth as usize) }
706    }
707
708    pub fn allocate_operand(&mut self, id: usize) -> Result<(), Error> {
709        let op = self.ctx.allocate_operand(self.point);
710
711        self.ctx
712            .point_mut(self.point.ok_or_else(|| Error::InconsistentState)?)
713            .resolve[id] = Some(op);
714
715        self.breadcrumb[self.depth as usize] += 1;
716        self.depth += 1;
717
718        self.point = Some(op);
719        self.breadcrumb[self.depth as usize] = 0;
720
721        Ok(())
722    }
723
724    pub(crate) fn unchecked_allocate_operand(&mut self, id: usize) {
725        let op = self.ctx.allocate_operand(self.point);
726
727        *unsafe {
728            self.ctx
729                .point_mut(self.point.unsafe_unwrap())
730                .resolve
731                .get_unchecked_mut(id)
732        } = Some(op);
733
734        *unsafe { self.breadcrumb.get_unchecked_mut(self.depth as usize) } += 1;
735        self.depth += 1;
736
737        self.point = Some(op);
738        *unsafe { self.breadcrumb.get_unchecked_mut(self.depth as usize) } = 0;
739    }
740
741    pub fn push_operand(&mut self, id: usize) -> Result<(), Error> {
742        self.breadcrumb[self.depth as usize] = id + 1;
743        self.depth += 1;
744        self.point = self
745            .ctx
746            .point(self.point.ok_or_else(|| Error::InconsistentState)?)
747            .resolve[id];
748        self.breadcrumb[self.depth as usize] = 0;
749        Ok(())
750    }
751
752    pub(crate) fn unchecked_push_operand(&mut self, id: usize) {
753        *unsafe { self.breadcrumb.get_unchecked_mut(self.depth as usize) } = id + 1;
754        self.depth += 1;
755        self.point = unsafe {
756            *self
757                .ctx
758                .point(self.point.unsafe_unwrap())
759                .resolve
760                .get_unchecked(id)
761        };
762        *unsafe { self.breadcrumb.get_unchecked_mut(self.depth as usize) } = 0;
763    }
764
765    pub fn pop_operand(&mut self) -> Result<(), Error> {
766        self.point = self
767            .ctx
768            .point(self.point.ok_or_else(|| Error::InconsistentState)?)
769            .parent;
770        self.depth -= 1;
771        Ok(())
772    }
773
774    pub(crate) fn unchecked_pop_operand(&mut self) {
775        self.point = unsafe { self.ctx.point(self.point.unsafe_unwrap()) }.parent;
776        self.depth -= 1;
777    }
778
779    pub unsafe fn offset(&self, offset: Option<usize>) -> usize {
780        match offset {
781            None => self.unchecked_point().offset,
782            Some(index) => {
783                let op_index = unsafe {
784                    self.unchecked_point()
785                        .resolve
786                        .get_unchecked(index)
787                        .unsafe_unwrap()
788                };
789                let op = self.ctx.point(op_index);
790                op.offset + op.length
791            }
792        }
793    }
794
795    #[inline]
796    pub unsafe fn resolve_with_aux<'d, T, F>(
797        &'d mut self,
798        pat: &'b PatternExpression,
799        ctor: &'b Constructor,
800        index: usize,
801        symbols: &'b SymbolTable,
802        mut f: F,
803    ) -> Result<T, Error>
804    where
805        F: FnMut(
806            &'b PatternExpression,
807            &mut ParserWalker<'b, 'd, 'z>,
808            &'b SymbolTable,
809        ) -> Result<T, Error>,
810    {
811        let mut cur_depth = self.depth;
812        let mut point = self.unchecked_point();
813
814        while point.constructor.map(|ct| ct != ctor).unwrap_or(false) {
815            if cur_depth == 0 {
816                let mut nwalker = ParserWalker::<'b, 'd, 'z>::new(self.context_mut());
817                let mut state = ConstructState::default();
818
819                state.constructor = Some(ctor);
820                nwalker.point = Some(nwalker.ctx.state.len());
821                nwalker.ctx.state.push(state);
822
823                let value = f(pat, &mut nwalker, symbols)?;
824
825                nwalker.ctx.state.pop(); // remove temp. state
826
827                return Ok(value);
828            }
829            cur_depth -= 1;
830            point = self.ctx.point(unsafe { point.parent.unsafe_unwrap() });
831        }
832
833        let sym = unsafe { symbols.unchecked_symbol(ctor.operand(index)) };
834        let offset = if sym.offset_base().is_none() {
835            // relative
836            point.offset + sym.relative_offset()
837        } else {
838            self.ctx
839                .point(unsafe { point.resolve.get_unchecked(index).unsafe_unwrap() })
840                .offset //[index].ok_or_else(|| Error::InconsistentState)?).offset
841        };
842
843        let mut state = ConstructState::default();
844        state.offset = offset;
845        state.constructor = Some(ctor);
846        state.length = point.length;
847
848        let mut nwalker = ParserWalker::<'b, 'd, 'z>::new(self.context_mut());
849
850        nwalker.point = Some(nwalker.ctx.state.len());
851        nwalker.ctx.state.push(state);
852
853        let value = f(pat, &mut nwalker, symbols)?;
854
855        nwalker.ctx.state.pop(); // remove temp. state
856
857        Ok(value)
858    }
859
860    pub unsafe fn resolve_with<'d>(
861        &'d mut self,
862        pat: &'b PatternExpression,
863        ctor: &'b Constructor,
864        index: usize,
865        symbols: &'b SymbolTable,
866    ) -> Result<i64, Error> {
867        self.resolve_with_aux(pat, ctor, index, symbols, |p, w, s| p.value(w, s))
868    }
869
870    pub unsafe fn resolve_with_bits<'d>(
871        &'d mut self,
872        pat: &'b PatternExpression,
873        ctor: &'b Constructor,
874        index: usize,
875        symbols: &'b SymbolTable,
876    ) -> Result<(i64, Option<Range<u32>>), Error> {
877        self.resolve_with_aux(pat, ctor, index, symbols, |p, w, s| p.value_with(w, s))
878    }
879
880    pub fn add_commit(&mut self, symbol: &'b Symbol, num: usize, mask: u32, flow: bool) {
881        let point = unsafe { self.point.unsafe_unwrap() };
882        self.ctx.add_commit(symbol, num, mask, point, flow)
883    }
884
885    pub fn apply_commits(
886        &mut self,
887        db: &mut ContextDatabase,
888        manager: &'b SpaceManager,
889        symbols: &'b SymbolTable,
890    ) -> Result<(), Error> {
891        self.ctx.apply_commits(db, manager, symbols)
892    }
893
894    pub fn set_context_word(&mut self, num: usize, value: u32, mask: u32) {
895        self.ctx.set_context_word(num, value, mask)
896    }
897
898    pub fn set_constructor(&mut self, constructor: &'b Constructor) {
899        self.ctx
900            .set_constructor(unsafe { self.point.unsafe_unwrap() }, constructor)
901    }
902
903    pub fn constructor(&self) -> Result<Option<&'b Constructor>, Error> {
904        if self.point.is_none() {
905            Ok(None)
906        } else {
907            Ok(self
908                .ctx
909                .constructor(self.point.ok_or_else(|| Error::InconsistentState)?))
910        }
911    }
912
913    pub unsafe fn unchecked_constructor(&self) -> &'b Constructor {
914        self.ctx.unchecked_constructor(self.point.unsafe_unwrap())
915    }
916
917    pub fn point(&self) -> Option<&ConstructState<'b>> {
918        self.point.map(|index| self.ctx.point(index))
919    }
920
921    pub unsafe fn unchecked_point(&self) -> &ConstructState<'b> {
922        self.ctx.point(self.point.unsafe_unwrap())
923    }
924
925    pub fn set_offset(&mut self, offset: usize) -> Result<(), Error> {
926        self.ctx
927            .set_offset(self.point.ok_or_else(|| Error::InconsistentState)?, offset);
928        Ok(())
929    }
930
931    pub fn context_bytes(&self, offset: usize, size: usize) -> u32 {
932        self.ctx.context_bytes(offset, size)
933    }
934
935    pub fn context_bits(&self, offset: usize, size: usize) -> u32 {
936        self.ctx.context_bits(offset, size)
937    }
938
939    pub fn instruction_bytes(&self, offset: usize, size: usize) -> Result<u32, Error> {
940        let point = self
941            .ctx
942            .point(self.point.ok_or_else(|| Error::InconsistentState)?);
943        Ok(self.ctx.instruction_bytes(offset, size, point.offset)?)
944    }
945
946    pub unsafe fn unchecked_instruction_bytes(&self, offset: usize, size: usize) -> u32 {
947        let point = self.ctx.point(self.point.unsafe_unwrap());
948        self.ctx
949            .instruction_bytes(offset, size, point.offset)
950            .unwrap()
951    }
952
953    pub fn instruction_bits(&self, offset: usize, size: usize) -> Result<u32, Error> {
954        let point = self
955            .ctx
956            .point(self.point.ok_or_else(|| Error::InconsistentState)?);
957        Ok(self.ctx.instruction_bits(offset, size, point.offset)?)
958    }
959
960    pub unsafe fn unchecked_instruction_bits(&self, offset: usize, size: usize) -> u32 {
961        let point = self.ctx.point(self.point.unsafe_unwrap());
962        self.ctx
963            .instruction_bits(offset, size, point.offset)
964            .unwrap()
965    }
966}