vyre_libs/parsing/c/parse/vast/
ref_decode_err.rs1#![allow(missing_docs)] use crate::parsing::c::lex::tokens::*;
9
10use super::expr_shape::*;
11use super::ref_expr_shape::*;
12use super::*;
13
14#[deprecated(
15 note = "CPU oracle only; production VAST construction must dispatch c11_build_vast_nodes"
16)]
17#[cfg(any(test, feature = "cpu-parity"))]
18pub fn reference_c11_build_vast_nodes(
19 tok_types: &[u32],
20 tok_starts: &[u32],
21 tok_lens: &[u32],
22) -> Vec<u8> {
23 let n = tok_types.len().min(tok_starts.len()).min(tok_lens.len());
24 let mut parent = vec![SENTINEL; n];
25 let mut first_child = vec![SENTINEL; n];
26 let mut next_sibling = vec![SENTINEL; n];
27 let mut previous_sibling = vec![SENTINEL; n];
28 let mut stack: Vec<u32> = Vec::new();
29 let mut last_child: Vec<Option<u32>> = vec![None; n];
30 let mut root_last: Option<u32> = None;
31
32 for i in 0..n {
33 let parent_idx = stack.last().copied().unwrap_or(SENTINEL);
34 parent[i] = parent_idx;
35
36 if let Some(previous) = if parent_idx == SENTINEL {
37 root_last
38 } else {
39 last_child[parent_idx as usize]
40 } {
41 previous_sibling[i] = previous;
42 next_sibling[previous as usize] = i as u32;
43 } else if parent_idx != SENTINEL {
44 first_child[parent_idx as usize] = i as u32;
45 }
46
47 if parent_idx == SENTINEL {
48 root_last = Some(i as u32);
49 } else {
50 last_child[parent_idx as usize] = Some(i as u32);
51 }
52
53 match tok_types[i] {
54 TOK_LPAREN | TOK_LBRACE | TOK_LBRACKET => stack.push(i as u32),
55 TOK_RPAREN => pop_matching(&mut stack, tok_types, TOK_LPAREN),
56 TOK_RBRACE => pop_matching(&mut stack, tok_types, TOK_LBRACE),
57 TOK_RBRACKET => pop_matching(&mut stack, tok_types, TOK_LBRACKET),
58 _ => {}
59 }
60 }
61
62 let mut rows = Vec::with_capacity(n.saturating_mul(VAST_NODE_STRIDE_U32 as usize));
63 for i in 0..n {
64 rows.extend_from_slice(&[
65 tok_types[i],
66 parent[i],
67 first_child[i],
68 next_sibling[i],
69 previous_sibling[i],
70 tok_starts[i],
71 tok_lens[i],
72 0,
73 0,
74 0,
75 ]);
76 }
77 u32_words_to_bytes(&rows)
78}
79
80#[derive(Debug, Clone, PartialEq, Eq)]
82pub enum CReferenceDecodeError {
83 MisalignedBytes {
85 len: usize,
87 },
88 PartialVastRow {
90 words: usize,
92 stride: usize,
94 },
95 MismatchedVastRows {
98 raw_rows: usize,
100 typed_rows: usize,
102 },
103}
104
105impl std::fmt::Display for CReferenceDecodeError {
106 fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
107 match self {
108 Self::MisalignedBytes { len } => write!(
109 formatter,
110 "C VAST byte input has {len} bytes, which is not 4-byte aligned. Fix: pass complete u32 rows to the C VAST reference oracle."
111 ),
112 Self::PartialVastRow { words, stride } => write!(
113 formatter,
114 "C VAST word input has {words} words, which is not a multiple of row stride {stride}. Fix: pass complete C VAST rows to the reference oracle."
115 ),
116 Self::MismatchedVastRows {
117 raw_rows,
118 typed_rows,
119 } => write!(
120 formatter,
121 "C VAST reference oracle received {raw_rows} raw rows but {typed_rows} typed rows. Fix: pass matching raw and typed VAST streams from the same translation unit."
122 ),
123 }
124 }
125}
126
127impl std::error::Error for CReferenceDecodeError {}
128
129fn try_u32_words_from_bytes(bytes: &[u8]) -> Result<Vec<u32>, CReferenceDecodeError> {
130 if bytes.len() % 4 != 0 {
131 return Err(CReferenceDecodeError::MisalignedBytes { len: bytes.len() });
132 }
133 Ok(vyre_primitives::wire::decode_u32_le_bytes_all(bytes))
134}
135
136pub(super) fn try_vast_words_from_bytes(bytes: &[u8]) -> Result<Vec<u32>, CReferenceDecodeError> {
137 let words = try_u32_words_from_bytes(bytes)?;
138 if words.len() % VAST_NODE_STRIDE_U32 as usize != 0 {
139 return Err(CReferenceDecodeError::PartialVastRow {
140 words: words.len(),
141 stride: VAST_NODE_STRIDE_U32 as usize,
142 });
143 }
144 Ok(words)
145}