lc3asm/
util.rs

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), // TODO: Determine whether this is allowed
33        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
40/// Wrapper struct for [BitWriter] which extends some functionality
41/// e.g. counting total bytes written without consuming itself.
42pub 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    /// Wrapping method for [BitWriter::write]
62    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    /// Wrapping method for [BitWriter::write]
72    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    /// Wrapping method for [BitWriter::write_bit]
82    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    /// Returns a pair of `(bytes_written, remaining_bits_count)`
89    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}