mech_interpreter/stdlib/assign/
tuple.rs

1#[macro_use]
2use crate::stdlib::*;
3use self::assign::*;
4
5use crate::*;
6
7// Tuple Assign ----------------------------------------------------------------
8
9#[derive(Debug)]
10pub struct TupleAssign<T> {
11  pub sink: Ref<T>,   // tuple element slot
12  pub source: Ref<T> // rhs value
13}
14
15impl<T> MechFunctionImpl for TupleAssign<T>
16where
17  T: Debug + Clone + Sync + Send + PartialEq + 'static,
18  Ref<T>: ToValue,
19{
20  fn solve(&self) {
21    let source_ptr = self.source.as_ptr();
22    let sink_ptr = self.sink.as_mut_ptr();
23    unsafe {
24      *sink_ptr = (*source_ptr).clone();
25    }
26  }
27
28  fn out(&self) -> Value {
29    self.sink.to_value()
30  }
31
32  fn to_string(&self) -> String {
33    format!("{:#?}", self)
34  }
35}
36
37#[cfg(feature = "compiler")]
38impl<T> MechFunctionCompiler for TupleAssign<T>
39where
40  T: CompileConst + ConstElem + AsValueKind,
41{
42  fn compile(&self, ctx: &mut CompileCtx) -> MResult<Register> {
43    let name = format!("TupleAssign<{}>", T::as_value_kind());
44    compile_unop!(
45      name,
46      self.sink,
47      self.source,
48      ctx,
49      FeatureFlag::Builtin(FeatureKind::Assign)
50    );
51  }
52}
53
54// -----------------------------------------------------------------------------
55
56fn impl_tuple_assign_fxn(
57  tuple: Value,
58  source: Value,
59  index: usize, // 0-based internally
60) -> MResult<Box<dyn MechFunction>> {
61
62  match &tuple {
63    Value::Tuple(tuple_ref) => {
64      let tuple = tuple_ref.borrow();
65
66      if index >= tuple.size() {
67        return Err(MechError2::new(
68          TupleIndexOutOfBoundsError {
69            ix: index + 1,
70            len: tuple.size(),
71          },
72          None,
73        ).with_compiler_loc());
74      }
75
76      let sink = tuple.elements[index].clone();
77
78      match (&*sink, &source) {
79
80        #[cfg(feature = "bool")]
81        (Value::Bool(sink), Value::Bool(source)) => {
82          Ok(Box::new(TupleAssign {
83            sink: sink.clone(),
84            source: source.clone(),
85          }))
86        }
87
88        #[cfg(feature = "i64")]
89        (Value::I64(sink), Value::I64(source)) => {
90          Ok(Box::new(TupleAssign {
91            sink: sink.clone(),
92            source: source.clone(),
93          }))
94        }
95
96        #[cfg(feature = "f64")]
97        (Value::F64(sink), Value::F64(source)) => {
98          Ok(Box::new(TupleAssign {
99            sink: sink.clone(),
100            source: source.clone(),
101          }))
102        }
103
104        #[cfg(feature = "string")]
105        (Value::String(sink), Value::String(source)) => {
106          Ok(Box::new(TupleAssign {
107            sink: sink.clone(),
108            source: source.clone(),
109          }))
110        }
111
112        _ => Err(MechError2::new(
113          TupleElementKindMismatchError {
114            expected: sink.kind(),
115            actual: source.kind(),
116          },
117          None,
118        ).with_compiler_loc()),
119      }
120    }
121
122    _ => Err(MechError2::new(
123      DestructureExpectedTupleError {
124        value: tuple.kind(),
125      },
126      None,
127    ).with_compiler_loc()),
128  }
129}
130
131// -----------------------------------------------------------------------------
132
133pub struct TupleAssignScalar {}
134
135impl NativeFunctionCompiler for TupleAssignScalar {
136  fn compile(&self, arguments: &Vec<Value>) -> MResult<Box<dyn MechFunction>> {
137
138    if arguments.len() != 3 {
139      return Err(MechError2::new(
140        IncorrectNumberOfArguments {
141          expected: 3,
142          found: arguments.len(),
143        },
144        None,
145      ).with_compiler_loc());
146    }
147
148    let tuple = arguments[0].clone();
149    let source = arguments[1].clone();
150    let index_val = arguments[2].clone();
151
152    let index = match &index_val {
153      Value::Index(ix) => {
154        let ix = *ix.borrow() as isize;
155        if ix <= 0 {
156          return Err(MechError2::new(
157            TupleIndexOutOfBoundsError {
158              ix: ix as usize,
159              len: 0,
160            },
161            None,
162          ).with_compiler_loc());
163        }
164        (ix - 1) as usize
165      }
166
167      _ => {
168        return Err(MechError2::new(
169          UnhandledFunctionArgumentKind3 {
170            arg: (tuple.kind(), source.kind(), index_val.kind()),
171            fxn_name: "tuple/assign".to_string(),
172          },
173          None,
174        ).with_compiler_loc());
175      }
176    };
177
178    match impl_tuple_assign_fxn(tuple.clone(), source.clone(), index) {
179      Ok(fxn) => Ok(fxn),
180
181      Err(_) => match &tuple {
182        Value::MutableReference(tuple_ref) => {
183          impl_tuple_assign_fxn(tuple_ref.borrow().clone(), source, index)
184        }
185
186        _ => Err(MechError2::new(
187          UnhandledFunctionArgumentKind3 {
188            arg: (arguments[0].kind(), arguments[1].kind(), arguments[2].kind()),
189            fxn_name: "tuple/assign".to_string(),
190          },
191          None,
192        ).with_compiler_loc()),
193      },
194    }
195  }
196}
197
198// -----------------------------------------------------------------------------
199
200#[derive(Debug, Clone)]
201pub struct TupleElementKindMismatchError {
202  pub expected: ValueKind,
203  pub actual: ValueKind,
204}
205
206impl MechErrorKind2 for TupleElementKindMismatchError {
207  fn name(&self) -> &str {
208    "TupleElementKindMismatch"
209  }
210
211  fn message(&self) -> String {
212    format!(
213      "Tuple element kind mismatch: expected {:?}, found {:?}",
214      self.expected, self.actual
215    )
216  }
217}