1mod error {
4 use super::expression;
5 use etk_ops::london::Op;
6 use num_bigint::BigInt;
7 use snafu::{Backtrace, Snafu};
8
9 #[derive(Snafu, Debug)]
10 #[snafu(context(suffix(false)), visibility(pub(crate)))]
11 pub enum Error {
12 ContextIncomplete {
13 #[snafu(backtrace)]
14 source: expression::Error,
15 },
16 ExpressionTooLarge {
17 source: std::array::TryFromSliceError,
18 value: BigInt,
19 spec: Op<()>,
20 backtrace: Backtrace,
21 },
22 ExpressionNegative {
23 value: BigInt,
24 backtrace: Backtrace,
25 },
26 }
27
28 #[derive(Debug, Snafu)]
30 #[snafu(display("unknown specifier: {}", text))]
31 #[snafu(context(suffix(Context)), visibility(pub(super)))]
32 #[non_exhaustive]
33 pub struct UnknownSpecifierError {
34 text: String,
35 backtrace: Backtrace,
36 }
37}
38
39pub(crate) mod expression;
40pub(crate) mod imm;
41mod macros;
42mod types;
43
44pub(crate) use self::error::Error;
45
46use etk_ops::london::{Op, Operation, Push32};
47
48pub use self::error::UnknownSpecifierError;
49pub use self::expression::{Context, Expression, Terminal};
50pub use self::imm::{Imm, TryFromSliceError};
51
52pub use self::macros::{
53 ExpressionMacroDefinition, ExpressionMacroInvocation, InstructionMacroDefinition,
54 InstructionMacroInvocation, MacroDefinition,
55};
56pub use self::types::Abstract;
57
58use std::cmp::{Eq, PartialEq};
59use std::convert::{TryFrom, TryInto};
60use std::fmt;
61
62use snafu::{ensure, ResultExt};
63
64pub(crate) trait Assemble {
65 fn assemble(&self, buf: &mut Vec<u8>);
66}
67
68impl<T> Assemble for T
69where
70 T: Operation,
71 T::ImmediateRef: AsRef<[u8]>,
72{
73 fn assemble(&self, buf: &mut Vec<u8>) {
74 buf.push(self.code_byte());
75 if let Some(immediate) = self.immediate().map(AsRef::as_ref) {
76 buf.extend_from_slice(immediate);
77 }
78 }
79}
80
81pub trait Concretize {
83 type Concrete;
85
86 fn concretize(&self, ctx: Context) -> Result<Self::Concrete, error::Error>;
88}
89
90impl Concretize for Op<Abstract> {
91 type Concrete = Op<[u8]>;
92
93 fn concretize(&self, ctx: Context) -> Result<Self::Concrete, error::Error> {
94 let expr = match self.immediate() {
95 Some(i) => &i.tree,
96 None => return Ok(Op::new(self.code()).unwrap()),
97 };
98
99 let value = expr
100 .eval_with_context(ctx)
101 .context(error::ContextIncomplete)?;
102
103 let (sign, mut bytes) = value.to_bytes_be();
104
105 ensure!(
106 sign != num_bigint::Sign::Minus,
107 error::ExpressionNegative { value }
108 );
109
110 if bytes.len() < self.extra_len() {
111 let mut new = vec![0u8; self.extra_len() - bytes.len()];
112 new.append(&mut bytes);
113 bytes = new;
114 }
115
116 let result = self
117 .code()
118 .with(bytes.as_slice())
119 .context(error::ExpressionTooLarge {
120 value,
121 spec: self.code(),
122 })?;
123
124 Ok(result)
125 }
126}
127
128trait Expr {
129 fn expr(&self) -> Option<&Expression>;
130 fn expr_mut(&mut self) -> Option<&mut Expression>;
131}
132
133impl<T> Expr for T
134where
135 T: Operation<ImmediateRef = Imm>,
136{
137 fn expr(&self) -> Option<&Expression> {
138 self.immediate().map(|i| &i.tree)
139 }
140
141 fn expr_mut(&mut self) -> Option<&mut Expression> {
142 self.immediate_mut().map(|i| &mut i.tree)
143 }
144}
145
146#[derive(Debug, Clone, Copy, Eq, PartialEq)]
148pub enum Access {
149 Read,
151
152 Write,
154
155 ReadWrite,
157}
158
159impl Access {
160 pub fn reads(self) -> bool {
162 matches!(self, Self::Read | Self::ReadWrite)
163 }
164
165 pub fn writes(self) -> bool {
167 matches!(self, Self::Write | Self::ReadWrite)
168 }
169}
170
171#[derive(Debug, Clone, Eq, PartialEq)]
176pub enum AbstractOp {
177 Op(Op<Abstract>),
179
180 Label(String),
182
183 Push(Imm),
185
186 MacroDefinition(MacroDefinition),
188
189 Macro(InstructionMacroInvocation),
191}
192
193impl AbstractOp {
194 pub fn new<O>(op: O) -> Self
196 where
197 O: Into<Op<Abstract>>,
198 {
199 Self::Op(op.into())
200 }
201
202 pub fn concretize(self, ctx: Context) -> Result<Op<[u8]>, error::Error> {
204 match self {
205 Self::Op(op) => op.concretize(ctx),
206 Self::Push(imm) => {
207 let value = imm
208 .tree
209 .eval_with_context(ctx)
210 .context(error::ContextIncomplete)?;
211
212 let (sign, bytes) = value.to_bytes_be();
213
214 ensure!(
215 sign != num_bigint::Sign::Minus,
216 error::ExpressionNegative { value }
217 );
218
219 if bytes.len() > 32 {
220 let err = <[u8; 32]>::try_from(bytes.as_slice())
222 .context(error::ExpressionTooLarge {
223 value,
224 spec: Push32(()),
225 })
226 .unwrap_err();
227 return Err(err);
228 }
229
230 let size = std::cmp::max(1, (value.bits() + 8 - 1) / 8);
231 let spec = Op::<()>::push(size.try_into().unwrap()).unwrap();
232
233 let start = bytes.len() + 1 - spec.size();
234 AbstractOp::new(spec.with(&bytes[start..]).unwrap()).concretize(ctx)
235 }
236 Self::Label(_) => panic!("labels cannot be concretized"),
237 Self::Macro(_) => panic!("macros cannot be concretized"),
238 Self::MacroDefinition(_) => panic!("macro definitions cannot be concretized"),
239 }
240 }
241
242 pub(crate) fn expr(&self) -> Option<&Expression> {
244 match self {
245 Self::Op(op) => op.expr(),
246 Self::Push(Imm { tree, .. }) => Some(tree),
247 _ => None,
248 }
249 }
250
251 pub(crate) fn expr_mut(&mut self) -> Option<&mut Expression> {
253 match self {
254 Self::Op(op) => op.expr_mut(),
255 Self::Push(Imm { tree, .. }) => Some(tree),
256 _ => None,
257 }
258 }
259
260 pub fn size(&self) -> Option<usize> {
266 match self {
267 Self::Op(op) => Some(op.size()),
268 Self::Label(_) => Some(0),
269 Self::Push(_) => None,
270 Self::Macro(_) => None,
271 Self::MacroDefinition(_) => None,
272 }
273 }
274
275 pub fn specifier(&self) -> Option<Op<()>> {
277 match self {
278 Self::Op(op) => Some(op.code()),
279 _ => None,
280 }
281 }
282}
283
284impl From<Op<[u8]>> for AbstractOp {
285 fn from(cop: Op<[u8]>) -> Self {
286 let code = cop.code();
287 let cop = match cop.into_immediate() {
288 Some(i) => code.with(i).unwrap(),
289 None => Op::new(code).unwrap(),
290 };
291 Self::Op(cop)
292 }
293}
294
295impl From<InstructionMacroDefinition> for AbstractOp {
296 fn from(item: InstructionMacroDefinition) -> Self {
297 AbstractOp::MacroDefinition(item.into())
298 }
299}
300
301impl From<ExpressionMacroDefinition> for AbstractOp {
302 fn from(item: ExpressionMacroDefinition) -> Self {
303 AbstractOp::MacroDefinition(item.into())
304 }
305}
306
307impl fmt::Display for AbstractOp {
308 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
309 match self {
310 Self::Op(op) => {
311 write!(f, "{}", op.code())?;
312 if let Some(imm) = op.immediate() {
313 write!(f, " {}", imm)?;
314 }
315 Ok(())
316 }
317 Self::Push(txt) => write!(f, r#"%push({})"#, txt),
318 Self::Label(lbl) => write!(f, r#"{}:"#, lbl),
319 Self::Macro(m) => write!(f, "{}", m),
320 Self::MacroDefinition(defn) => write!(f, "{}", defn),
321 }
322 }
323}
324
325#[cfg(test)]
326mod tests {
327 use std::convert::TryInto;
328
329 use super::*;
330
331 #[test]
332 fn u8_into_imm1() {
333 let x: u8 = 0xdc;
334 let imm: Imm = x.into();
335 let res: Imm = Terminal::Number(x.into()).into();
336 assert_eq!(imm, res);
337 }
338
339 #[test]
340 fn u16_try_into_imm1() {
341 let x: u16 = 0xFF;
342 let imm: Imm = x.try_into().unwrap();
343 let res: Imm = Terminal::Number(x.into()).into();
344 assert_eq!(imm, res);
345 }
346
347 #[test]
348 fn u8_into_imm2() {
349 let x: u8 = 0xdc;
350 let imm: Imm = x.into();
351 let res: Imm = Terminal::Number(x.into()).into();
352 assert_eq!(imm, res);
353 }
354
355 #[test]
356 fn u16_into_imm2() {
357 let x: u16 = 0xfedc;
358 let imm: Imm = x.into();
359 let res: Imm = Terminal::Number(x.into()).into();
360 assert_eq!(imm, res);
361 }
362
363 #[test]
364 fn u128_into_imm32() {
365 let x: u128 = 0x1023456789abcdef0123456789abcdef;
366 let imm: Imm = x.into();
367 let res: Imm = Terminal::Number(x.into()).into();
368 assert_eq!(imm, res);
369 }
370}