#[macro_use]
use crate::stdlib::*;
use self::assign::*;
use crate::*;
#[derive(Debug)]
pub struct TupleAssign<T> {
pub sink: Ref<T>, pub source: Ref<T> }
impl<T> MechFunctionImpl for TupleAssign<T>
where
T: Debug + Clone + Sync + Send + PartialEq + 'static,
Ref<T>: ToValue,
{
fn solve(&self) {
let source_ptr = self.source.as_ptr();
let sink_ptr = self.sink.as_mut_ptr();
unsafe {
*sink_ptr = (*source_ptr).clone();
}
}
fn out(&self) -> Value {
self.sink.to_value()
}
fn to_string(&self) -> String {
format!("{:#?}", self)
}
}
#[cfg(feature = "compiler")]
impl<T> MechFunctionCompiler for TupleAssign<T>
where
T: CompileConst + ConstElem + AsValueKind,
{
fn compile(&self, ctx: &mut CompileCtx) -> MResult<Register> {
let name = format!("TupleAssign<{}>", T::as_value_kind());
compile_unop!(
name,
self.sink,
self.source,
ctx,
FeatureFlag::Builtin(FeatureKind::Assign)
);
}
}
fn impl_tuple_assign_fxn(
tuple: Value,
source: Value,
index: usize, ) -> MResult<Box<dyn MechFunction>> {
match &tuple {
Value::Tuple(tuple_ref) => {
let tuple = tuple_ref.borrow();
if index >= tuple.size() {
return Err(MechError::new(
TupleIndexOutOfBoundsError {
ix: index + 1,
len: tuple.size(),
},
None,
).with_compiler_loc());
}
let sink = tuple.elements[index].clone();
match (&*sink, &source) {
#[cfg(feature = "bool")]
(Value::Bool(sink), Value::Bool(source)) => {
Ok(Box::new(TupleAssign {
sink: sink.clone(),
source: source.clone(),
}))
}
#[cfg(feature = "i64")]
(Value::I64(sink), Value::I64(source)) => {
Ok(Box::new(TupleAssign {
sink: sink.clone(),
source: source.clone(),
}))
}
#[cfg(feature = "f64")]
(Value::F64(sink), Value::F64(source)) => {
Ok(Box::new(TupleAssign {
sink: sink.clone(),
source: source.clone(),
}))
}
#[cfg(feature = "string")]
(Value::String(sink), Value::String(source)) => {
Ok(Box::new(TupleAssign {
sink: sink.clone(),
source: source.clone(),
}))
}
_ => Err(MechError::new(
TupleElementKindMismatchError {
expected: sink.kind(),
actual: source.kind(),
},
None,
).with_compiler_loc()),
}
}
_ => Err(MechError::new(
DestructureExpectedTupleError {
value: tuple.kind(),
},
None,
).with_compiler_loc()),
}
}
pub struct TupleAssignScalar {}
impl NativeFunctionCompiler for TupleAssignScalar {
fn compile(&self, arguments: &Vec<Value>) -> MResult<Box<dyn MechFunction>> {
if arguments.len() != 3 {
return Err(MechError::new(
IncorrectNumberOfArguments {
expected: 3,
found: arguments.len(),
},
None,
).with_compiler_loc());
}
let tuple = arguments[0].clone();
let source = arguments[1].clone();
let index_val = arguments[2].clone();
let index = match &index_val {
Value::Index(ix) => {
let ix = *ix.borrow() as isize;
if ix <= 0 {
return Err(MechError::new(
TupleIndexOutOfBoundsError {
ix: ix as usize,
len: 0,
},
None,
).with_compiler_loc());
}
(ix - 1) as usize
}
_ => {
return Err(MechError::new(
UnhandledFunctionArgumentKind3 {
arg: (tuple.kind(), source.kind(), index_val.kind()),
fxn_name: "tuple/assign".to_string(),
},
None,
).with_compiler_loc());
}
};
match impl_tuple_assign_fxn(tuple.clone(), source.clone(), index) {
Ok(fxn) => Ok(fxn),
Err(_) => match &tuple {
Value::MutableReference(tuple_ref) => {
impl_tuple_assign_fxn(tuple_ref.borrow().clone(), source, index)
}
_ => Err(MechError::new(
UnhandledFunctionArgumentKind3 {
arg: (arguments[0].kind(), arguments[1].kind(), arguments[2].kind()),
fxn_name: "tuple/assign".to_string(),
},
None,
).with_compiler_loc()),
},
}
}
}
#[derive(Debug, Clone)]
pub struct TupleElementKindMismatchError {
pub expected: ValueKind,
pub actual: ValueKind,
}
impl MechErrorKind for TupleElementKindMismatchError {
fn name(&self) -> &str {
"TupleElementKindMismatch"
}
fn message(&self) -> String {
format!(
"Tuple element kind mismatch: expected {:?}, found {:?}",
self.expected, self.actual
)
}
}