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#[cfg(any(test, feature = "cpu-parity"))]
15pub fn reference_c11_build_vast_nodes(
16 tok_types: &[u32],
17 tok_starts: &[u32],
18 tok_lens: &[u32],
19) -> Vec<u8> {
20 let n = tok_types.len().min(tok_starts.len()).min(tok_lens.len());
21 let mut parent = vec![SENTINEL; n];
22 let mut first_child = vec![SENTINEL; n];
23 let mut next_sibling = vec![SENTINEL; n];
24 let mut previous_sibling = vec![SENTINEL; n];
25 let mut stack: Vec<u32> = Vec::new();
26 let mut last_child: Vec<Option<u32>> = vec![None; n];
27 let mut root_last: Option<u32> = None;
28
29 for i in 0..n {
30 let parent_idx = stack.last().copied().unwrap_or(SENTINEL);
31 parent[i] = parent_idx;
32
33 if let Some(previous) = if parent_idx == SENTINEL {
34 root_last
35 } else {
36 last_child[parent_idx as usize]
37 } {
38 previous_sibling[i] = previous;
39 next_sibling[previous as usize] = i as u32;
40 } else if parent_idx != SENTINEL {
41 first_child[parent_idx as usize] = i as u32;
42 }
43
44 if parent_idx == SENTINEL {
45 root_last = Some(i as u32);
46 } else {
47 last_child[parent_idx as usize] = Some(i as u32);
48 }
49
50 match tok_types[i] {
51 TOK_LPAREN | TOK_LBRACE | TOK_LBRACKET => stack.push(i as u32),
52 TOK_RPAREN => pop_matching(&mut stack, tok_types, TOK_LPAREN),
53 TOK_RBRACE => pop_matching(&mut stack, tok_types, TOK_LBRACE),
54 TOK_RBRACKET => pop_matching(&mut stack, tok_types, TOK_LBRACKET),
55 _ => {}
56 }
57 }
58
59 let mut rows = Vec::with_capacity(n.saturating_mul(VAST_NODE_STRIDE_U32 as usize));
60 for i in 0..n {
61 rows.extend_from_slice(&[
62 tok_types[i],
63 parent[i],
64 first_child[i],
65 next_sibling[i],
66 previous_sibling[i],
67 tok_starts[i],
68 tok_lens[i],
69 0,
70 0,
71 0,
72 ]);
73 }
74 u32_words_to_bytes(&rows)
75}
76
77#[derive(Debug, Clone, PartialEq, Eq)]
79pub enum CReferenceDecodeError {
80 MisalignedBytes {
82 len: usize,
84 },
85 PartialVastRow {
87 words: usize,
89 stride: usize,
91 },
92 MismatchedVastRows {
95 raw_rows: usize,
97 typed_rows: usize,
99 },
100}
101
102impl std::fmt::Display for CReferenceDecodeError {
103 fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
104 match self {
105 Self::MisalignedBytes { len } => write!(
106 formatter,
107 "C VAST byte input has {len} bytes, which is not 4-byte aligned. Fix: pass complete u32 rows to the C VAST reference oracle."
108 ),
109 Self::PartialVastRow { words, stride } => write!(
110 formatter,
111 "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."
112 ),
113 Self::MismatchedVastRows {
114 raw_rows,
115 typed_rows,
116 } => write!(
117 formatter,
118 "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."
119 ),
120 }
121 }
122}
123
124impl std::error::Error for CReferenceDecodeError {}
125
126fn try_u32_words_from_bytes(bytes: &[u8]) -> Result<Vec<u32>, CReferenceDecodeError> {
127 if bytes.len() % 4 != 0 {
128 return Err(CReferenceDecodeError::MisalignedBytes { len: bytes.len() });
129 }
130 Ok(vyre_primitives::wire::decode_u32_le_bytes_all(bytes))
131}
132
133pub(super) fn try_vast_words_from_bytes(bytes: &[u8]) -> Result<Vec<u32>, CReferenceDecodeError> {
134 let words = try_u32_words_from_bytes(bytes)?;
135 if words.len() % VAST_NODE_STRIDE_U32 as usize != 0 {
136 return Err(CReferenceDecodeError::PartialVastRow {
137 words: words.len(),
138 stride: VAST_NODE_STRIDE_U32 as usize,
139 });
140 }
141 Ok(words)
142}