etk_dasm/
sym.rs

1//! Expressions, symbols, and variables for symbolic execution.
2use std::convert::TryInto;
3use std::fmt;
4use std::num::NonZeroU16;
5
6/// A variable.
7#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
8pub struct Var(NonZeroU16);
9
10impl Var {
11    pub(crate) fn with_id<T>(id: T) -> Self
12    where
13        T: TryInto<NonZeroU16>,
14        T::Error: std::fmt::Debug,
15    {
16        Var(id.try_into().unwrap())
17    }
18}
19
20impl fmt::Display for Var {
21    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
22        write!(f, "var{}", self.0)
23    }
24}
25
26/// Representation of an expression tree (ex. `add(2, sub(9, 4))`)
27#[derive(Debug, Clone, Eq, PartialEq, Hash)]
28pub struct Expr {
29    ops: Vec<Sym>,
30}
31
32impl fmt::Display for Expr {
33    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
34        self.walk(&mut DisplayVisit(f))
35    }
36}
37
38impl From<Var> for Expr {
39    fn from(v: Var) -> Expr {
40        Self {
41            ops: vec![Sym::Var(v)],
42        }
43    }
44}
45
46impl Expr {
47    fn concat(op: Sym, args: &[&Self]) -> Self {
48        assert_eq!(op.children() as usize, args.len());
49
50        let capacity = 1 + args.iter().map(|x| x.ops.len()).sum::<usize>();
51        let mut ops = Vec::with_capacity(capacity);
52        ops.push(op);
53        for arg in args {
54            ops.extend_from_slice(&arg.ops);
55        }
56
57        Self { ops }
58    }
59
60    /// Create an [`Expr`] representing `address` (`0x30`).
61    pub fn address() -> Self {
62        Self {
63            ops: vec![Sym::Address],
64        }
65    }
66
67    /// Create an [`Expr`] representing `origin` (`0x32`).
68    pub fn origin() -> Self {
69        Self {
70            ops: vec![Sym::Origin],
71        }
72    }
73
74    /// Create an [`Expr`] representing `caller` (`0x33`).
75    pub fn caller() -> Self {
76        Self {
77            ops: vec![Sym::Caller],
78        }
79    }
80
81    /// Create an [`Expr`] representing `callvalue` (`0x34`).
82    pub fn call_value() -> Self {
83        Self {
84            ops: vec![Sym::CallValue],
85        }
86    }
87
88    /// Create an [`Expr`] representing `calldatasize` (`0x36`).
89    pub fn call_data_size() -> Self {
90        Self {
91            ops: vec![Sym::CallDataSize],
92        }
93    }
94
95    /// Create an [`Expr`] representing `codesize` (`0x38`).
96    pub fn code_size() -> Self {
97        Self {
98            ops: vec![Sym::CodeSize],
99        }
100    }
101
102    /// Create an [`Expr`] representing `gasprice` (`0x3a`).
103    pub fn gas_price() -> Self {
104        Self {
105            ops: vec![Sym::GasPrice],
106        }
107    }
108
109    /// Create an [`Expr`] representing `returndatasize` (`0x3d`).
110    pub fn return_data_size() -> Self {
111        Self {
112            ops: vec![Sym::ReturnDataSize],
113        }
114    }
115
116    /// Create an [`Expr`] representing `coinbase` (`0x41`).
117    pub fn coinbase() -> Self {
118        Self {
119            ops: vec![Sym::Coinbase],
120        }
121    }
122
123    /// Create an [`Expr`] representing `timestamp` (`0x42`).
124    pub fn timestamp() -> Self {
125        Self {
126            ops: vec![Sym::Timestamp],
127        }
128    }
129
130    /// Create an [`Expr`] representing `number` (`0x43`).
131    pub fn number() -> Self {
132        Self {
133            ops: vec![Sym::Number],
134        }
135    }
136
137    /// Create an [`Expr`] representing `difficulty` (`0x44`).
138    pub fn difficulty() -> Self {
139        Self {
140            ops: vec![Sym::Difficulty],
141        }
142    }
143
144    /// Create an [`Expr`] representing `gaslimit` (`0x45`).
145    pub fn gas_limit() -> Self {
146        Self {
147            ops: vec![Sym::GasLimit],
148        }
149    }
150
151    /// Create an [`Expr`] representing `chainid` (`0x46`).
152    pub fn chain_id() -> Self {
153        Self {
154            ops: vec![Sym::ChainId],
155        }
156    }
157
158    /// Create an [`Expr`] representing `selfbalance` (`0x47`).
159    pub fn self_balance() -> Self {
160        Self {
161            ops: vec![Sym::SelfBalance],
162        }
163    }
164
165    /// Create an [`Expr`] representing `basefee` (`0x48`).
166    pub fn base_fee() -> Self {
167        Self {
168            ops: vec![Sym::BaseFee],
169        }
170    }
171
172    /// Create an [`Expr`] representing `pc` (`0x58`).
173    pub fn pc(offset: u16) -> Self {
174        Self {
175            ops: vec![Sym::GetPc(offset)],
176        }
177    }
178
179    /// Create an [`Expr`] representing `msize` (`0x59`).
180    pub fn m_size() -> Self {
181        Self {
182            ops: vec![Sym::MSize],
183        }
184    }
185
186    /// Create an [`Expr`] representing `gas` (`0x5a`).
187    pub fn gas() -> Self {
188        Self {
189            ops: vec![Sym::Gas],
190        }
191    }
192
193    /// Create an [`Expr`] representing `create` (`0xf0`).
194    pub fn create(value: &Self, offset: &Self, length: &Self) -> Self {
195        Self::concat(Sym::Create, &[value, offset, length])
196    }
197
198    /// Create an [`Expr`] representing `create2` (`0xf5`).
199    pub fn create2(value: &Self, offset: &Self, length: &Self, salt: &Self) -> Self {
200        Self::concat(Sym::Create2, &[value, offset, length, salt])
201    }
202
203    /// Create an [`Expr`] representing `callcode` (`0xf2`).
204    pub fn call_code(
205        gas: &Self,
206        addr: &Self,
207        value: &Self,
208        args_offset: &Self,
209        args_len: &Self,
210        ret_offset: &Self,
211        ret_len: &Self,
212    ) -> Self {
213        Self::concat(
214            Sym::CallCode,
215            &[gas, addr, value, args_offset, args_len, ret_offset, ret_len],
216        )
217    }
218
219    /// Create an [`Expr`] representing `call` (`0xf1`).
220    pub fn call(
221        gas: &Self,
222        addr: &Self,
223        value: &Self,
224        args_offset: &Self,
225        args_len: &Self,
226        ret_offset: &Self,
227        ret_len: &Self,
228    ) -> Self {
229        Self::concat(
230            Sym::Call,
231            &[gas, addr, value, args_offset, args_len, ret_offset, ret_len],
232        )
233    }
234
235    /// Create an [`Expr`] representing `staticcall` (`0xfa`).
236    pub fn static_call(
237        gas: &Self,
238        addr: &Self,
239        args_offset: &Self,
240        args_len: &Self,
241        ret_offset: &Self,
242        ret_len: &Self,
243    ) -> Self {
244        Self::concat(
245            Sym::StaticCall,
246            &[gas, addr, args_offset, args_len, ret_offset, ret_len],
247        )
248    }
249
250    /// Create an [`Expr`] representing `delegatecall` (`0xf4`).
251    pub fn delegate_call(
252        gas: &Self,
253        addr: &Self,
254        args_offset: &Self,
255        args_len: &Self,
256        ret_offset: &Self,
257        ret_len: &Self,
258    ) -> Self {
259        Self::concat(
260            Sym::DelegateCall,
261            &[gas, addr, args_offset, args_len, ret_offset, ret_len],
262        )
263    }
264
265    /// Create an [`Expr`] representing `add` (`0x01`).
266    pub fn add(&self, rhs: &Self) -> Self {
267        Self::concat(Sym::Add, &[self, rhs])
268    }
269
270    /// Create an [`Expr`] representing `sub` (`0x03`).
271    pub fn sub(&self, rhs: &Self) -> Self {
272        Self::concat(Sym::Sub, &[self, rhs])
273    }
274
275    /// Create an [`Expr`] representing `mul` (`0x02`).
276    pub fn mul(&self, rhs: &Self) -> Self {
277        Self::concat(Sym::Mul, &[self, rhs])
278    }
279
280    /// Create an [`Expr`] representing `div` (`0x04`).
281    pub fn div(&self, rhs: &Self) -> Self {
282        Self::concat(Sym::Div, &[self, rhs])
283    }
284
285    /// Create an [`Expr`] representing `sdiv` (`0x05`).
286    pub fn s_div(&self, rhs: &Self) -> Self {
287        Self::concat(Sym::SDiv, &[self, rhs])
288    }
289
290    /// Create an [`Expr`] representing `mod` (`0x06`).
291    pub fn modulo(&self, rhs: &Self) -> Self {
292        Self::concat(Sym::Mod, &[self, rhs])
293    }
294
295    /// Create an [`Expr`] representing `smod` (`0x07`).
296    pub fn s_modulo(&self, rhs: &Self) -> Self {
297        Self::concat(Sym::SMod, &[self, rhs])
298    }
299
300    /// Create an [`Expr`] representing `addmod` (`0x08`).
301    pub fn add_mod(&self, add: &Self, modulo: &Self) -> Self {
302        Self::concat(Sym::AddMod, &[self, add, modulo])
303    }
304
305    /// Create an [`Expr`] representing `mulmod` (`0x09`).
306    pub fn mul_mod(&self, mul: &Self, modulo: &Self) -> Self {
307        Self::concat(Sym::MulMod, &[self, mul, modulo])
308    }
309
310    /// Create an [`Expr`] representing `exp` (`0x0a`).
311    pub fn exp(&self, rhs: &Self) -> Self {
312        Self::concat(Sym::Exp, &[self, rhs])
313    }
314
315    /// Create an [`Expr`] representing `lt` (`0x10`).
316    pub fn lt(&self, rhs: &Self) -> Self {
317        Self::concat(Sym::Lt, &[self, rhs])
318    }
319
320    /// Create an [`Expr`] representing `gt` (`0x11`).
321    pub fn gt(&self, rhs: &Self) -> Self {
322        Self::concat(Sym::Gt, &[self, rhs])
323    }
324
325    /// Create an [`Expr`] representing `slt` (`0x12`).
326    pub fn s_lt(&self, rhs: &Self) -> Self {
327        Self::concat(Sym::SLt, &[self, rhs])
328    }
329
330    /// Create an [`Expr`] representing `sgt` (`0x13`).
331    pub fn s_gt(&self, rhs: &Self) -> Self {
332        Self::concat(Sym::SGt, &[self, rhs])
333    }
334
335    /// Create an [`Expr`] representing `eq` (`0x14`).
336    pub fn is_eq(&self, rhs: &Self) -> Self {
337        Self::concat(Sym::Eq, &[self, rhs])
338    }
339
340    /// Create an [`Expr`] representing `and` (`0x16`).
341    pub fn and(&self, rhs: &Self) -> Self {
342        Self::concat(Sym::And, &[self, rhs])
343    }
344
345    /// Create an [`Expr`] representing `or` (`0x17`).
346    pub fn or(&self, rhs: &Self) -> Self {
347        Self::concat(Sym::Or, &[self, rhs])
348    }
349
350    /// Create an [`Expr`] representing `xor` (`0x18`).
351    pub fn xor(&self, rhs: &Self) -> Self {
352        Self::concat(Sym::Xor, &[self, rhs])
353    }
354
355    /// Create an [`Expr`] representing `byte` (`0x1a`).
356    pub fn byte(&self, value: &Self) -> Self {
357        Self::concat(Sym::Byte, &[self, value])
358    }
359
360    /// Create an [`Expr`] representing `shl` (`0x1b`).
361    pub fn shl(&self, rhs: &Self) -> Self {
362        Self::concat(Sym::Shl, &[self, rhs])
363    }
364
365    /// Create an [`Expr`] representing `shr` (`0x1c`).
366    pub fn shr(&self, value: &Self) -> Self {
367        Self::concat(Sym::Shr, &[self, value])
368    }
369
370    /// Create an [`Expr`] representing `sar` (`0x1d`).
371    pub fn sar(&self, rhs: &Self) -> Self {
372        Self::concat(Sym::Sar, &[self, rhs])
373    }
374
375    /// Create an [`Expr`] representing `keccak256` (`0x20`).
376    pub fn keccak256(offset: &Self, len: &Self) -> Self {
377        Self::concat(Sym::Keccak256, &[offset, len])
378    }
379
380    /// Create an [`Expr`] representing `signextend` (`0x0b`).
381    pub fn sign_extend(&self, b: &Self) -> Self {
382        Self::concat(Sym::SignExtend, &[self, b])
383    }
384
385    /// Create an [`Expr`] representing `iszero` (`0x15`).
386    pub fn is_zero(&self) -> Self {
387        Self::concat(Sym::IsZero, &[self])
388    }
389
390    /// Create an [`Expr`] representing `not` (`0x19`).
391    pub fn not(&self) -> Self {
392        Self::concat(Sym::Not, &[self])
393    }
394
395    /// Create an [`Expr`] representing `blockhash` (`0x40`).
396    pub fn block_hash(&self) -> Self {
397        Self::concat(Sym::BlockHash, &[self])
398    }
399
400    /// Create an [`Expr`] representing `balance` (`0x31`).
401    pub fn balance(&self) -> Self {
402        Self::concat(Sym::Balance, &[self])
403    }
404
405    /// Create an [`Expr`] representing `calldataload` (`0x35`).
406    pub fn call_data_load(&self) -> Self {
407        Self::concat(Sym::CallDataLoad, &[self])
408    }
409
410    /// Create an [`Expr`] representing `extcodesize` (`0x3b`).
411    pub fn ext_code_size(&self) -> Self {
412        Self::concat(Sym::ExtCodeSize, &[self])
413    }
414
415    /// Create an [`Expr`] representing `extcodehash` (`0x3f`).
416    pub fn ext_code_hash(&self) -> Self {
417        Self::concat(Sym::ExtCodeHash, &[self])
418    }
419
420    /// Create an [`Expr`] representing `mload` (`0x51`).
421    pub fn m_load(&self) -> Self {
422        Self::concat(Sym::MLoad, &[self])
423    }
424
425    /// Create an [`Expr`] representing `sload` (`0x54`).
426    pub fn s_load(&self) -> Self {
427        Self::concat(Sym::SLoad, &[self])
428    }
429
430    /// If this expression represents a single [`Var`] instance, return it.
431    /// Otherwise return `None`.
432    pub fn as_var(&self) -> Option<Var> {
433        match self.ops.as_slice() {
434            [Sym::Var(v)] => Some(*v),
435            _ => None,
436        }
437    }
438
439    /// Create an [`Expr`] representing a constant value.
440    pub fn constant<A>(arr: A) -> Self
441    where
442        A: AsRef<[u8]>,
443    {
444        let arr = arr.as_ref();
445        let mut buf = [0u8; 32];
446        let start = buf.len() - arr.len();
447        buf[start..].copy_from_slice(arr);
448        Self {
449            ops: vec![Sym::Const(buf.into())],
450        }
451    }
452
453    #[cfg(test)]
454    pub(crate) fn constant_offset<T: Into<u128>>(offset: T) -> Self {
455        let offset: u128 = offset.into();
456        let mut buf = [0u8; 32];
457        buf[16..].copy_from_slice(&offset.to_be_bytes());
458
459        Self {
460            ops: vec![Sym::Const(buf.into())],
461        }
462    }
463}
464
465// TODO: Implement UpperHex and LowerHex for Expr
466
467struct DisplayVisit<'a, 'b>(&'a mut fmt::Formatter<'b>);
468
469impl<'a, 'b> Visit for DisplayVisit<'a, 'b> {
470    type Error = fmt::Error;
471
472    fn empty(&mut self) -> fmt::Result {
473        write!(self.0, "{{}}")
474    }
475
476    fn exit(&mut self, op: &Sym) -> fmt::Result {
477        match op {
478            Sym::Const(_) => Ok(()),
479            Sym::Var(_) => Ok(()),
480            Sym::IsZero => write!(self.0, " = 0)"),
481            _ => write!(self.0, ")"),
482        }
483    }
484
485    fn between(&mut self, op: &Sym, idx: u8) -> fmt::Result {
486        let txt = match op {
487            Sym::Add => " + ",
488            Sym::Mul => " × ",
489            Sym::Sub => " - ",
490            Sym::Div => " ÷ ",
491            Sym::SDiv => " ÷⃡ ",
492            Sym::Mod => " ﹪ ",
493            Sym::SMod => " ﹪⃡ ",
494            Sym::AddMod => match idx {
495                0 => " + ",
496                1 => ") ﹪ ",
497                _ => unreachable!(),
498            },
499            Sym::MulMod => match idx {
500                0 => " × ",
501                1 => ") ﹪ ",
502                _ => unreachable!(),
503            },
504            Sym::Exp => " ** ",
505            Sym::Lt => " < ",
506            Sym::Gt => " > ",
507            Sym::SLt => " <⃡ ",
508            Sym::SGt => " >⃡ ",
509            Sym::Eq => " = ",
510            Sym::And => " & ",
511            Sym::Or => " | ",
512            Sym::Xor => " ^ ",
513            q if q.children() < 2 => unreachable!(),
514            _ => ", ",
515        };
516
517        write!(self.0, "{}", txt)
518    }
519
520    fn enter(&mut self, op: &Sym) -> fmt::Result {
521        match op {
522            Sym::Const(v) => {
523                // TODO: Technically this should be in decimal, not hex.
524                write!(self.0, "0x{}", hex::encode(**v))
525            }
526            Sym::Var(v) => write!(self.0, "{}", v),
527            Sym::AddMod => write!(self.0, "(("),
528            Sym::MulMod => write!(self.0, "(("),
529            Sym::Keccak256 => write!(self.0, "keccak256("),
530            Sym::Byte => write!(self.0, "byte("),
531            Sym::SignExtend => write!(self.0, "signextend("),
532            Sym::Not => write!(self.0, "~("),
533            Sym::CallDataLoad => write!(self.0, "calldata("),
534            Sym::ExtCodeSize => write!(self.0, "extcodesize("),
535            Sym::ExtCodeHash => write!(self.0, "extcodehash("),
536            Sym::MLoad => write!(self.0, "mload("),
537            Sym::SLoad => write!(self.0, "sload("),
538            Sym::Address => write!(self.0, "address("),
539            Sym::Balance => write!(self.0, "balance("),
540            Sym::Origin => write!(self.0, "origin("),
541            Sym::Caller => write!(self.0, "caller("),
542            Sym::CallValue => write!(self.0, "callvalue("),
543            Sym::CallDataSize => write!(self.0, "calldatasize("),
544            Sym::CodeSize => write!(self.0, "codesize("),
545            Sym::GasPrice => write!(self.0, "gasprice("),
546            Sym::ReturnDataSize => write!(self.0, "returndatasize("),
547            Sym::BlockHash => write!(self.0, "blockhash("),
548            Sym::Coinbase => write!(self.0, "coinbase("),
549            Sym::Timestamp => write!(self.0, "timestamp("),
550            Sym::Number => write!(self.0, "number("),
551            Sym::Difficulty => write!(self.0, "difficulty("),
552            Sym::GasLimit => write!(self.0, "gaslimit("),
553            Sym::ChainId => write!(self.0, "chainid("),
554            Sym::SelfBalance => write!(self.0, "selfbalance("),
555            Sym::BaseFee => write!(self.0, "basefee("),
556            Sym::GetPc(pc) => write!(self.0, "pc({}", pc),
557            Sym::MSize => write!(self.0, "msize("),
558            Sym::Gas => write!(self.0, "gas("),
559            Sym::Create => write!(self.0, "create("),
560            Sym::CallCode => write!(self.0, "callcode("),
561            Sym::Call => write!(self.0, "call("),
562            Sym::StaticCall => write!(self.0, "staticcall("),
563            Sym::DelegateCall => write!(self.0, "delegatecall("),
564            Sym::Shl => write!(self.0, "shl("),
565            Sym::Shr => write!(self.0, "shr("),
566            Sym::Sar => write!(self.0, "sar("),
567            _ => write!(self.0, "("),
568        }
569    }
570}
571
572impl Expr {
573    /// Traverse the expression's tree, calling the appropriate functions on
574    /// `visitor`.
575    pub fn walk<V>(&self, visitor: &mut V) -> Result<(), V::Error>
576    where
577        V: Visit,
578    {
579        if self.ops.is_empty() {
580            visitor.empty()
581        } else {
582            Self::inner_walk(&self.ops, visitor)?;
583            // TODO: Figure out if it's okay that there's sometimes Syms left
584            //       over after walking.
585            Ok(())
586        }
587    }
588
589    fn inner_walk<'a, V>(mut ops: &'a [Sym], visitor: &mut V) -> Result<&'a [Sym], V::Error>
590    where
591        V: Visit,
592    {
593        if ops.is_empty() {
594            unreachable!();
595        }
596
597        let op = &ops[0];
598
599        visitor.enter(op)?;
600
601        for idx in 0..op.children() {
602            ops = Self::inner_walk(&ops[1..], visitor)?;
603
604            if (idx + 1) < op.children() {
605                visitor.between(op, idx)?;
606            }
607        }
608
609        visitor.exit(op)?;
610
611        Ok(ops)
612    }
613}
614
615/// An interface for visiting the operations in an [`Expr`].
616pub trait Visit {
617    /// An error type.
618    type Error;
619
620    /// Called if the [`Expr`] is empty.
621    fn empty(&mut self) -> Result<(), Self::Error> {
622        Ok(())
623    }
624
625    /// Called when visiting a [`Sym`] for the first time.
626    fn enter(&mut self, _: &Sym) -> Result<(), Self::Error> {
627        Ok(())
628    }
629
630    /// Called between each child of a [`Sym`].
631    fn between(&mut self, _: &Sym, _: u8) -> Result<(), Self::Error> {
632        Ok(())
633    }
634
635    /// Called when leaving a [`Sym`] for the last time.
636    fn exit(&mut self, _: &Sym) -> Result<(), Self::Error> {
637        Ok(())
638    }
639}
640
641/// A node in the tree representation of an [`Expr`].
642///
643/// For example, the expression `2 + 3` would be represented as something like
644/// `[Sym::Add, Sym::Const(2), Sym::Const(3)]`.
645// TODO: std::mem::size_of::<Sym>() is like 16 bytes. That's HUGE.
646#[derive(Debug, Clone, Eq, PartialEq, Hash)]
647pub enum Sym {
648    /// A constant value.
649    Const(Box<[u8; 32]>),
650
651    /// A variable value.
652    Var(Var),
653
654    /// An `add` (`0x01`) operation.
655    Add,
656
657    /// A `mul` (`0x02`) operation.
658    Mul,
659
660    /// A `sub` (`0x03`) operation.
661    Sub,
662
663    /// A `div` (`0x04`) operation.
664    Div,
665
666    /// A `sdiv` (`0x05`) operation.
667    SDiv,
668
669    /// A `mod` (`0x06`) operation.
670    Mod,
671
672    /// A `smod` (`0x07`) operation.
673    SMod,
674
675    /// A `addmod` (`0x08`) operation.
676    AddMod,
677
678    /// A `mulmod` (`0x09`) operation.
679    MulMod,
680
681    /// An `exp` (`0x0a`) operation.
682    Exp,
683
684    /// An `lt` (`0x10`) operation.
685    Lt,
686
687    /// A `gt` (`0x11`) operation.
688    Gt,
689
690    /// An `slt` (`0x12`) operation.
691    SLt,
692
693    /// An `sgt` (`0x13`) operation.
694    SGt,
695
696    /// An `eq` (`0x14`) operation.
697    Eq,
698
699    /// An `and` (`0x16`) operation.
700    And,
701
702    /// An `or` (`0x17`) operation.
703    Or,
704
705    /// A `xor` (`0x18`) operation.
706    Xor,
707
708    /// A `byte` (`0x1a`) operation.
709    Byte,
710
711    /// A `shl` (`0x1b`) operation.
712    Shl,
713
714    /// A `shr` (`0x1c`) operation.
715    Shr,
716
717    /// A `sar` (`0x1d`) operation.
718    Sar,
719
720    /// A `keccak256` (`0x20`) operation.
721    Keccak256,
722
723    /// A `signextend` (`0x0b`) operation.
724    SignExtend,
725
726    /// An `iszero` (`0x15`) operation.
727    IsZero,
728
729    /// A `not` (`0x18`) operation.
730    Not,
731
732    /// A `calldataload` (`0x35`) operation.
733    CallDataLoad,
734
735    /// An `extcodesize` (`0x3b`) operation.
736    ExtCodeSize,
737
738    /// An `extcodehash` (`0x3f`) operation.
739    ExtCodeHash,
740
741    /// An `mload` (`0x51`) operation.
742    MLoad,
743
744    /// An `sload` (`0x54`) operation.
745    SLoad,
746
747    /// A `balance` (`0x31`) operation.
748    Balance,
749
750    /// A `blockhash` (`0x40`) operation.
751    BlockHash,
752
753    /// An `address` (`0x30`) operation.
754    Address,
755
756    /// An `origin` (`0x32`) operation.
757    Origin,
758
759    /// A `caller` (`0x33`) operation.
760    Caller,
761
762    /// A `callvalue` (`0x34`) operation.
763    CallValue,
764
765    /// A `calldatasize` (`0x36`) operation.
766    CallDataSize,
767
768    /// A `codesize` (`0x38`) operation.
769    CodeSize,
770
771    /// A `gasprice` (`0x3a`) operation.
772    GasPrice,
773
774    /// A `returndatasize` (`0x3d`) operation.
775    ReturnDataSize,
776
777    /// A `coinbase` (`0x41`) operation.
778    Coinbase,
779
780    /// A `timestamp` (`0x42`) operation.
781    Timestamp,
782
783    /// A `number` (`0x43`) operation.
784    Number,
785
786    /// A `difficulty` (`0x44`) operation.
787    Difficulty,
788
789    /// A `gaslimit` (`0x45`) operation.
790    GasLimit,
791
792    /// A `chainid` (`0x46`) operation.
793    ChainId,
794
795    /// A `selfbalance` (`0x47`) operation.
796    SelfBalance,
797
798    /// A `basefee` (`0x48`) operation.
799    BaseFee,
800
801    /// A `pc` (`0x58`) operation.
802    GetPc(u16),
803
804    /// An `msize` (`0x59`) operation.
805    MSize,
806
807    /// A `gas` (`0x5a`) operation.
808    Gas,
809
810    /// A `create` (`0xf0`) operation.
811    Create,
812
813    /// A `create2` (`0xf5`) operation.
814    Create2,
815
816    /// A `callcode` (`0xf2`) operation.
817    CallCode,
818
819    /// A `call` (`0xf1`) operation.
820    Call,
821
822    /// A `staticcall` (`0xfa`) operation.
823    StaticCall,
824
825    /// A `delegatecall` (`0xf4`) operation.
826    DelegateCall,
827}
828
829impl Sym {
830    fn children(&self) -> u8 {
831        match self {
832            Sym::Add
833            | Sym::Mul
834            | Sym::Sub
835            | Sym::Div
836            | Sym::SDiv
837            | Sym::Mod
838            | Sym::SMod
839            | Sym::Exp
840            | Sym::Lt
841            | Sym::Gt
842            | Sym::SLt
843            | Sym::SGt
844            | Sym::Eq
845            | Sym::And
846            | Sym::Or
847            | Sym::Xor
848            | Sym::Byte
849            | Sym::Shl
850            | Sym::Shr
851            | Sym::Sar
852            | Sym::SignExtend
853            | Sym::Keccak256 => 2,
854
855            Sym::IsZero
856            | Sym::Not
857            | Sym::CallDataLoad
858            | Sym::ExtCodeSize
859            | Sym::ExtCodeHash
860            | Sym::BlockHash
861            | Sym::Balance
862            | Sym::MLoad
863            | Sym::SLoad => 1,
864
865            Sym::Address
866            | Sym::Origin
867            | Sym::Caller
868            | Sym::CallValue
869            | Sym::CallDataSize
870            | Sym::CodeSize
871            | Sym::GasPrice
872            | Sym::ReturnDataSize
873            | Sym::Coinbase
874            | Sym::Timestamp
875            | Sym::Number
876            | Sym::Difficulty
877            | Sym::GasLimit
878            | Sym::ChainId
879            | Sym::SelfBalance
880            | Sym::BaseFee
881            | Sym::GetPc(_)
882            | Sym::MSize
883            | Sym::Gas
884            | Sym::Const(_)
885            | Sym::Var(_) => 0,
886
887            Sym::AddMod | Sym::MulMod | Sym::Create => 3,
888
889            Sym::Create2 => 4,
890
891            Sym::Call | Sym::CallCode => 7,
892
893            Sym::DelegateCall | Sym::StaticCall => 6,
894        }
895    }
896}
897
898#[cfg(test)]
899mod tests {
900    use super::*;
901
902    #[test]
903    fn expr_display_add_mod() {
904        let expected = "((caller() + origin()) ﹪ var1)";
905        let var = Var::with_id(NonZeroU16::new(1).unwrap());
906        let input = Expr {
907            ops: vec![Sym::AddMod, Sym::Caller, Sym::Origin, Sym::Var(var)],
908        };
909
910        let actual = input.to_string();
911        assert_eq!(expected, actual);
912    }
913
914    #[test]
915    fn expr_display_call() {
916        let expected = "call(gas(), caller(), callvalue(), sload(pc(3)), mload(origin()), number(), timestamp())";
917        let input = Expr {
918            ops: vec![
919                Sym::Call,
920                Sym::Gas,
921                Sym::Caller,
922                Sym::CallValue,
923                Sym::SLoad,
924                Sym::GetPc(3),
925                Sym::MLoad,
926                Sym::Origin,
927                Sym::Number,
928                Sym::Timestamp,
929            ],
930        };
931
932        let actual = input.to_string();
933        assert_eq!(expected, actual);
934    }
935
936    #[test]
937    fn expr_display_add() {
938        let expected = "(0x0000000000000000000000000000000000000000000000000000000000000000 + 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff)";
939        let input = Expr {
940            ops: vec![
941                Sym::Add,
942                Sym::Const(Box::new([0x00; 32])),
943                Sym::Const(Box::new([0xff; 32])),
944            ],
945        };
946
947        let actual = input.to_string();
948        assert_eq!(expected, actual);
949    }
950}