1use crate::ast::*;
3
4#[derive(Debug, Clone)]
5pub enum ScalarError {
6 IncorrectSign,
8 OutOfBounds,
10 UnsupportedPtrSize,
11}
12pub type ScalarResult<T> = std::result::Result<T, ScalarError>;
14
15macro_rules! from_le_bytes {
16 ($m:ident, $b:ident, [$(($i_ty: ty, $i:ident, $s:ident, $n_ty:ty, $t:ty)),*]) => {
17 match $m {
18 $(
19 IntegerTy::$s(<$i_ty>::$i) => {
20 let n = size_of::<$n_ty>();
21 let b: [u8; _] = $b[0..n].try_into().unwrap();
22 ScalarValue::$s(<$i_ty>::$i, <$n_ty>::from_le_bytes(b) as $t)
23 }
24 )*
25 }
26 }
27}
28
29impl Literal {
30 pub fn char_from_le_bytes(bits: u128) -> Self {
31 let b: [u8; 4] = bits.to_le_bytes()[0..4].try_into().unwrap();
32 Literal::Char(std::char::from_u32(u32::from_le_bytes(b)).unwrap())
33 }
34
35 pub fn from_bits(lit_ty: &LiteralTy, bits: u128) -> Option<Self> {
36 match *lit_ty {
37 LiteralTy::Int(int_ty) => Some(Literal::Scalar(ScalarValue::from_bits(
38 IntegerTy::Signed(int_ty),
39 bits,
40 ))),
41 LiteralTy::UInt(uint_ty) => Some(Literal::Scalar(ScalarValue::from_bits(
42 IntegerTy::Unsigned(uint_ty),
43 bits,
44 ))),
45 LiteralTy::Char => Some(Literal::char_from_le_bytes(bits)),
46 _ => None,
47 }
48 }
49}
50
51impl ScalarValue {
52 fn ptr_size_max(ptr_size: ByteCount, signed: bool) -> ScalarResult<u128> {
53 match ptr_size {
54 2 => Ok(if signed {
55 i16::MAX as u128
56 } else {
57 u16::MAX as u128
58 }),
59 4 => Ok(if signed {
60 i32::MAX as u128
61 } else {
62 u32::MAX as u128
63 }),
64 8 => Ok(if signed {
65 i64::MAX as u128
66 } else {
67 u64::MAX as u128
68 }),
69 _ => Err(ScalarError::UnsupportedPtrSize),
70 }
71 }
72
73 fn ptr_size_min(ptr_size: ByteCount, signed: bool) -> ScalarResult<i128> {
74 match ptr_size {
75 2 => Ok(if signed {
76 i16::MIN as i128
77 } else {
78 u16::MIN as i128
79 }),
80 4 => Ok(if signed {
81 i32::MIN as i128
82 } else {
83 u32::MIN as i128
84 }),
85 8 => Ok(if signed {
86 i64::MIN as i128
87 } else {
88 u64::MIN as i128
89 }),
90 _ => Err(ScalarError::UnsupportedPtrSize),
91 }
92 }
93
94 pub fn get_integer_ty(&self) -> IntegerTy {
95 match self {
96 ScalarValue::Signed(ty, _) => IntegerTy::Signed(*ty),
97 ScalarValue::Unsigned(ty, _) => IntegerTy::Unsigned(*ty),
98 }
99 }
100
101 pub fn is_int(&self) -> bool {
102 matches!(self, ScalarValue::Signed(_, _))
103 }
104
105 pub fn is_uint(&self) -> bool {
106 matches!(self, ScalarValue::Unsigned(_, _))
107 }
108
109 pub fn as_uint(&self) -> ScalarResult<u128> {
113 match self {
114 ScalarValue::Unsigned(_, v) => Ok(*v),
115 _ => Err(ScalarError::IncorrectSign),
116 }
117 }
118
119 pub fn uint_is_in_bounds(ptr_size: ByteCount, ty: UIntTy, v: u128) -> bool {
120 match ty {
121 UIntTy::Usize => v <= Self::ptr_size_max(ptr_size, false).unwrap(),
122 UIntTy::U8 => v <= (u8::MAX as u128),
123 UIntTy::U16 => v <= (u16::MAX as u128),
124 UIntTy::U32 => v <= (u32::MAX as u128),
125 UIntTy::U64 => v <= (u64::MAX as u128),
126 UIntTy::U128 => true,
127 }
128 }
129
130 pub fn from_unchecked_uint(ty: UIntTy, v: u128) -> ScalarValue {
131 ScalarValue::Unsigned(ty, v)
132 }
133
134 pub fn from_uint(ptr_size: ByteCount, ty: UIntTy, v: u128) -> ScalarResult<Self> {
135 if !ScalarValue::uint_is_in_bounds(ptr_size, ty, v) {
136 trace!("Not in bounds for {:?}: {}", ty, v);
137 Err(ScalarError::OutOfBounds)
138 } else {
139 Ok(ScalarValue::from_unchecked_uint(ty, v))
140 }
141 }
142
143 pub fn mk_usize(ptr_size: ByteCount, v: u64) -> Self {
144 ScalarValue::from_uint(ptr_size, UIntTy::Usize, v as u128).unwrap()
145 }
146
147 pub fn as_int(&self) -> ScalarResult<i128> {
151 match self {
152 ScalarValue::Signed(_, v) => Ok(*v),
153 _ => Err(ScalarError::IncorrectSign),
154 }
155 }
156
157 pub fn int_is_in_bounds(ptr_size: ByteCount, ty: IntTy, v: i128) -> bool {
158 match ty {
159 IntTy::Isize => {
160 v >= Self::ptr_size_min(ptr_size, true).unwrap()
161 && v <= Self::ptr_size_max(ptr_size, true).unwrap() as i128
162 }
163 IntTy::I8 => v >= (i8::MIN as i128) && v <= (i8::MAX as i128),
164 IntTy::I16 => v >= (i16::MIN as i128) && v <= (i16::MAX as i128),
165 IntTy::I32 => v >= (i32::MIN as i128) && v <= (i32::MAX as i128),
166 IntTy::I64 => v >= (i64::MIN as i128) && v <= (i64::MAX as i128),
167 IntTy::I128 => true,
168 }
169 }
170
171 pub fn from_unchecked_int(ty: IntTy, v: i128) -> ScalarValue {
172 ScalarValue::Signed(ty, v)
173 }
174
175 pub fn to_bits(&self) -> u128 {
177 match *self {
178 ScalarValue::Unsigned(_, v) => v,
179 ScalarValue::Signed(_, v) => u128::from_le_bytes(v.to_le_bytes()),
180 }
181 }
182
183 pub fn from_le_bytes(ty: IntegerTy, bytes: [u8; 16]) -> Self {
188 from_le_bytes!(
189 ty,
190 bytes,
191 [
192 (IntTy, Isize, Signed, isize, i128),
193 (IntTy, I8, Signed, i8, i128),
194 (IntTy, I16, Signed, i16, i128),
195 (IntTy, I32, Signed, i32, i128),
196 (IntTy, I64, Signed, i64, i128),
197 (IntTy, I128, Signed, i128, i128),
198 (UIntTy, Usize, Unsigned, usize, u128),
199 (UIntTy, U8, Unsigned, u8, u128),
200 (UIntTy, U16, Unsigned, u16, u128),
201 (UIntTy, U32, Unsigned, u32, u128),
202 (UIntTy, U64, Unsigned, u64, u128),
203 (UIntTy, U128, Unsigned, u128, u128)
204 ]
205 )
206 }
207
208 pub fn from_bits(ty: IntegerTy, bits: u128) -> Self {
209 let bytes = bits.to_le_bytes();
210 Self::from_le_bytes(ty, bytes)
211 }
212
213 pub fn from_int(ptr_size: ByteCount, ty: IntTy, v: i128) -> ScalarResult<ScalarValue> {
217 if !ScalarValue::int_is_in_bounds(ptr_size, ty, v) {
218 Err(ScalarError::OutOfBounds)
219 } else {
220 Ok(ScalarValue::from_unchecked_int(ty, v))
221 }
222 }
223
224 pub fn to_constant(self) -> ConstantExpr {
225 let literal_ty = match self {
226 ScalarValue::Signed(int_ty, _) => LiteralTy::Int(int_ty),
227 ScalarValue::Unsigned(uint_ty, _) => LiteralTy::UInt(uint_ty),
228 };
229 ConstantExpr {
230 kind: ConstantExprKind::Literal(Literal::Scalar(self)),
231 ty: TyKind::Literal(literal_ty).into_ty(),
232 }
233 }
234}
235
236pub(crate) mod scalar_value_ser_de {
238 use std::{marker::PhantomData, str::FromStr};
239
240 use serde::de::{Deserializer, Error};
241
242 pub fn serialize<S, V>(val: &V, serializer: S) -> Result<S::Ok, S::Error>
243 where
244 S: serde::ser::Serializer,
245 V: ToString,
246 {
247 serializer.serialize_str(&val.to_string())
248 }
249
250 pub fn deserialize<'de, D, V>(deserializer: D) -> Result<V, D::Error>
251 where
252 D: Deserializer<'de>,
253 V: FromStr,
254 {
255 struct Visitor<V> {
256 _val: PhantomData<V>,
257 }
258 impl<'de, V> serde::de::Visitor<'de> for Visitor<V>
259 where
260 V: FromStr,
261 {
262 type Value = V;
263 fn expecting(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
264 write!(f, "ScalarValue value")
265 }
266 fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
267 where
268 E: Error,
269 {
270 v.parse()
271 .map_err(|_| E::custom("Could not parse 128 bit integer!"))
272 }
273 }
274 deserializer.deserialize_str(Visitor { _val: PhantomData })
275 }
276}
277
278#[cfg(test)]
279mod test {
280 use super::*;
281
282 #[test]
283 fn test_big_endian_scalars() -> ScalarResult<()> {
284 let u128 = 0x12345678901234567890123456789012u128;
285 let le_bytes = u128.to_le_bytes();
286
287 let le_scalar = ScalarValue::from_le_bytes(IntegerTy::Unsigned(UIntTy::U128), le_bytes);
288 assert_eq!(le_scalar, ScalarValue::Unsigned(UIntTy::U128, u128));
289
290 let i64 = 0x1234567890123456i64;
291 let le_bytes = (i64 as i128).to_le_bytes();
292 let le_scalar = ScalarValue::from_le_bytes(IntegerTy::Signed(IntTy::I64), le_bytes);
293 assert_eq!(le_scalar, ScalarValue::Signed(IntTy::I64, i64 as i128));
294
295 Ok(())
296 }
297}