1use bitstream_io::write::BitWriter;
2use bitstream_io::{BigEndian, Numeric, SignedNumeric};
3use pest::iterators::Pair;
4use std::io::Result as IOResult;
5use std::io::Write;
6use std::num::ParseIntError;
7
8pub fn parse_number_literal(s: &str) -> Result<i64, ParseIntError> {
9 s.parse().or_else(|_| match s.chars().nth(0) {
10 Some('#') => s[1..].parse(),
11 Some('x') | Some('X') => i64::from_str_radix(&s[1..], 16),
12 _ => panic!("Invalid decimal literal {} received", s),
13 })
14}
15
16pub fn parse_register_literal(s: &str) -> Result<i64, ParseIntError> {
17 match s.to_ascii_lowercase().chars().nth(0) {
18 Some('r') => i64::from_str_radix(&s[1..], 16),
19 _ => panic!("Invalid register literal {} received", s),
20 }
21}
22
23pub enum PCOffsetTarget {
24 Symbol(String),
25 ExplicitOffset(i64),
26}
27
28pub fn parse_pc_pair(target_pair: &Pair<super::Rule>) -> PCOffsetTarget {
29 let pair_str = target_pair.as_str();
30
31 match pair_str.parse() {
32 Ok(offset) => PCOffsetTarget::ExplicitOffset(offset), Err(_) => match pair_str.chars().nth(0) {
34 Some('#') => PCOffsetTarget::ExplicitOffset(pair_str[1..].parse().unwrap()),
35 _ => PCOffsetTarget::Symbol(pair_str.to_owned()),
36 },
37 }
38}
39
40pub struct BitVecWriter<W>
43where
44 W: Write,
45{
46 wr: BitWriter<W, BigEndian>,
47 bits_pushed: u32,
48}
49
50impl<W> BitVecWriter<W>
51where
52 W: Write,
53{
54 pub fn new(wr: W) -> Self {
55 BitVecWriter {
56 wr: BitWriter::new(wr),
57 bits_pushed: 0,
58 }
59 }
60
61 pub fn write<U>(&mut self, bits: u32, value: U) -> IOResult<()>
63 where
64 U: Numeric,
65 {
66 self.wr.write(bits, value).map(|_| {
67 self.bits_pushed += bits;
68 })
69 }
70
71 pub fn write_signed<S>(&mut self, bits: u32, value: S) -> IOResult<()>
73 where
74 S: SignedNumeric,
75 {
76 self.wr.write_signed(bits, value).map(|_| {
77 self.bits_pushed += bits;
78 })
79 }
80
81 pub fn write_bit(&mut self, bit: bool) -> IOResult<()> {
83 self.wr.write_bit(bit).map(|_| {
84 self.bits_pushed += 1;
85 })
86 }
87
88 pub fn count_written(&self) -> (u32, u8) {
90 (self.bits_pushed / 8, (self.bits_pushed % 8) as u8)
91 }
92
93 pub fn into_inner(self) -> BitWriter<W, BigEndian> {
94 self.wr
95 }
96}
97
98#[macro_export]
99macro_rules! collect_inner {
100 ($pair:expr) => {
101 &$pair.into_inner().collect::<Vec<_>>()[..]
102 };
103}
104
105#[macro_export]
106macro_rules! pair_error_message {
107 ($pair:expr, $($arg:tt)*) => {
108 PestError::new_from_span(
109 PestErrorVariant::<Rule>::CustomError {
110 message: format!($($arg)*)
111 },
112 $pair.as_span()
113 )
114 };
115}
116
117#[macro_export]
118macro_rules! write_fields {
119 ($wr:expr) => {};
120
121 ($wr:expr $(,[$($more:tt)+])*,) => {
122 write_fields!($wr $(,[$($more)+])*);
123 };
124
125 ($wr:expr, [const; $bits:expr, $value:expr] $(,[$($more:tt)+])*) => {
126 $wr.write($bits, $value)?;
127 write_fields!($wr $(,[$($more)+])*);
128 };
129
130 ($wr:expr, [bool; $value:expr] $(,[$($more:tt)+])*) => {
131 $wr.write_bit($value)?;
132 write_fields!($wr $(,[$($more)+])*);
133 };
134
135 ($wr:expr, [number $name:ident; $bits:expr, $pair:expr] $(,[$($more:tt)+])*) => {
136 let $name = util::parse_number_literal($pair.as_str())?;
137 write_fields!($wr,
138 [$name; $bits, $pair, $name]
139 $(,[$($more)+])*,
140 );
141 };
142
143 ($wr:expr, [number_signed $name:ident; $bits:expr, $pair:expr] $(,[$($more:tt)+])*) => {
144 let $name = util::parse_number_literal($pair.as_str())?;
145 write_fields!($wr,
146 [signed $name; $bits, $pair, $name]
147 $(,[$($more)+])*,
148 );
149 };
150
151 ($wr:expr, [register $name:ident; $pair:expr] $(,[$($more:tt)+])*) => {
152 let $name = util::parse_register_literal($pair.as_str())?;
153 write_fields!($wr,
154 [$name; 3, $pair, $name]
155 $(,[$($more)+])*,
156 );
157 };
158
159 ($wr:expr, [pcoffset; $bits:expr, $pair:expr, $table:expr] $(,[$($more:tt)+])*) => {
160 let _current_offset = ($wr.count_written().0-2) / 2;
161 match util::parse_pc_pair($pair) {
162 util::PCOffsetTarget::Symbol(_sym) => {
163 if let Some((_offset, _)) = $table.get(&_sym) {
164 write_fields!(
165 $wr,
166 [signed pc_offset; $bits, $pair, *_offset as i32 - _current_offset as i32 - 1],
167 );
168 } else {
169 return Err(pair_error_message!(
170 $pair,
171 "Cannot find symbol {}, available symbols: {}",
172 _sym,
173 $table.keys().map(String::to_owned).collect::<Vec<_>>().join(", "),
174 ).into())
175 }
176 },
177 util::PCOffsetTarget::ExplicitOffset(_offset) => {
178 write_fields!($wr, [signed pc_offset; $bits, $pair, _offset]);
179 }
180 }
181 write_fields!($wr $(,[$($more)+])*);
182 };
183
184 ($wr:expr, [$name:ident; $bits:expr, $pair:expr, $value:expr] $(,[$($more:tt)+])*) => {
185 write_fields!($wr, [$name; $bits, $pair, $value, write] $(,[$($more)+])*);
186 };
187
188 ($wr:expr, [signed $name:ident; $bits:expr, $pair:expr, $value:expr] $(,[$($more:tt)+])*) => {
189 write_fields!($wr, [$name; $bits, $pair, $value, write_signed] $(,[$($more)+])*);
190 };
191
192 ($wr:expr,
193 [$name:ident; $bits:expr, $pair:expr, $value:expr, $func:ident]
194 $(,[$($more:tt)+])*) => {
195 $wr.$func($bits, $value).map_err(|e| -> Error {
196 if e.kind() == IOErrorKind::InvalidInput {
197 pair_error_message!(
198 $pair,
199 "Value {} overflows for given field {}",
200 $value,
201 stringify!($name)
202 )
203 .into()
204 } else {
205 e.into()
206 }
207 })?;
208 write_fields!($wr $(,[$($more)+])*);
209 };
210}
211
212#[cfg(test)]
213mod tests {
214 use super::*;
215
216 #[test]
217 fn test_bitvecwriter() {
218 let mut buf = Vec::new();
219 let mut bvw = BitVecWriter::new(&mut buf);
220 bvw.write(8, 3).unwrap();
221 assert_eq!(bvw.count_written(), (1, 0));
222 bvw.write(3, 5).unwrap();
223 assert_eq!(bvw.count_written(), (1, 3));
224 bvw.write_bit(true).unwrap();
225 bvw.write(4, 5).unwrap();
226 assert_eq!(bvw.count_written(), (2, 0));
227 assert_eq!(bvw.into_inner().into_writer(), &[3, 0b1011_0101]);
228 }
229
230 #[test]
231 fn test_bvw_overflow() {
232 let mut buf = Vec::new();
233 let mut bvw = BitVecWriter::new(&mut buf);
234 bvw.write(4, 16).unwrap_err();
235 }
236}