1use crate::number::Number;
2use crate::value::Value;
3use crate::VMError;
4use std::ops::Shl;
5
6impl Shl for &Value {
7 type Output = Value;
8
9 #[inline]
10 fn shl(self, rhs: Self) -> Self::Output {
11 match (self, rhs) {
12 (Value::Error(v), _) | (_, Value::Error(v)) => Value::Error(v.clone()),
13 (Value::Type(t), a) | (a, Value::Type(t)) => Value::Error(
14 VMError::UnsupportedOperation(format!("Invalid Operation (<<): {t} and {a}")),
15 ),
16 (Value::None, _) => Value::None,
17 (lhs, Value::None) => lhs.clone(),
18 (rhs, &Value::Bool(b)) => {
19 if b {
20 rhs << &Value::Number(Number::Int(1))
21 } else {
22 rhs.clone()
23 }
24 }
25 (&Value::Bool(lhs), Value::Number(rhs)) => {
26 if lhs {
27 Value::Number(&Number::Int(1) >> rhs)
28 } else {
29 Value::Number(Number::Int(0))
30 }
31 }
32 (Value::Number(lhs), Value::Number(rhs)) => Value::Number(lhs << rhs),
33 (Value::Number(a), Value::String(b)) => {
34 let s = Value::String(b.clone());
35 match s.to_number() {
36 Err(_) => VMError::UnsupportedOperation(format!("{} << {}", a, b)).to_value(),
37 Ok(r) => Value::Number(a << &r),
38 }
39 }
40 (Value::String(lhs), Value::Number(rhs)) => {
41 let lhs = lhs.as_str();
42 let s = if rhs.is_negative() {
43 lhs[..=rhs.to_int().unsigned_abs() as usize].to_string()
44 } else {
45 lhs[rhs.to_usize().unwrap()..].to_string()
46 };
47 Value::String(s)
48 }
49 (Value::String(lhs), Value::String(rhs)) => {
50 let mut res = lhs.clone();
51 res.push_str(rhs.as_str());
52 Value::String(res)
53 }
54 (Value::Tuple(a), Value::Tuple(b)) => {
55 Value::Tuple(a.iter().zip(b).map(|(a, b)| a << b).collect())
56 }
57 (Value::Tuple(a), b) => Value::Tuple(a.iter().map(|a| a << b).collect()),
58 (b, Value::Tuple(a)) => Value::Tuple(a.iter().map(|a| b << a).collect()),
59 (lhs, rhs) => {
60 VMError::UnsupportedOperation(format!("Not supported: {lhs} << {rhs}")).into()
61 }
62 }
63 }
64}
65
66#[cfg(test)]
67mod tests {
68 use crate::define_value_tests;
69
70 define_value_tests! {
71 << {
72 test_none_shl_none => ((), ()) = ();
73 test_none_bool_false_shl_none => (false, ()) = false;
74 test_bool_true_shl_none => (true, ()) = true;
75 test_none_bool_true_shl_true => ((), true) = ();
76 test_false_bool_true_shl_true => (false, true) = 0;
77 test_false_0_shl_true => (false, 0) = false;
78 test_true_0_shl_true => (true, 0) = 1;
79 push_to_end => ("abc", "123") = "abc123";
80 int_like => (1, 2.0) = (1 << 2);
81 }
82 }
83}