motoko 0.0.32

A library for parsing and running Motoko in Rust
Documentation
use crate::ast::{BinOp, PrimType, RelOp, UnOp};
use crate::value::{Value, Value_};
use crate::vm_types::Interruption;
use num_bigint::{BigUint, ToBigInt};

use crate::{nyi, type_mismatch};

pub fn unop(un: UnOp, v: Value_) -> Result<Value, Interruption> {
    match (un, &*v) {
        (UnOp::Neg, Value::Nat(n)) => Ok(Value::Int(-n.to_bigint().unwrap())),
        (UnOp::Neg, _) => crate::nyi!(line!()),
        (UnOp::Pos, _) => crate::nyi!(line!()),
        (UnOp::Not, _) => crate::nyi!(line!()),
        /* _ => crate::nyi!(line!()), */
    }
}

pub fn binop(
    cont_prim_type: &Option<PrimType>,
    binop: BinOp,
    v1: Value_,
    v2: Value_,
) -> Result<Value, Interruption> {
    use BinOp::*;
    use Value::*;
    if let Unit = &*v1 {
        type_mismatch!(file!(), line!());
    };
    if let Unit = &*v2 {
        type_mismatch!(file!(), line!());
    };
    match binop {
        Add => match (&*v1, &*v2) {
            (Nat(n1), Nat(n2)) => Ok(Nat(n1 + n2)),
            (Int(i1), Int(i2)) => Ok(Int(i1 + i2)),
            (Float(f1), Float(f2)) => Ok(Float(*f1 + *f2)),
            // _ => nyi!(line!()),
            (v1, v2) => unimplemented!("{:?} + {:?}", v1, v2),
        },
        Div => match (&*v1, &*v2) {
            (Nat(n1), Nat(n2)) => Ok(Nat(n1 / n2)),
            (Int(i1), Int(i2)) => Ok(Int(i1 / i2)),
            (Float(f1), Float(f2)) => Ok(Float(*f1 / *f2)),
            // _ => nyi!(line!()),
            (v1, v2) => unimplemented!("{:?} + {:?}", v1, v2),
        },
        Sub => match (&*v1, &*v2) {
            (Nat(n1), Nat(n2)) => {
                if n2 > n1 {
                    Ok(Int(n1.to_bigint().unwrap() - n2.to_bigint().unwrap()))
                } else {
                    Ok(Nat(n1 - n2))
                }
            }
            (Int(i1), Int(i2)) => Ok(Int(i1 - i2)),
            (Int(i1), Nat(n2)) => Ok(Int(i1 - n2.to_bigint().unwrap())),
            (Nat(n1), Int(i2)) => Ok(Int(n1.to_bigint().unwrap() - i2)),
            (Float(f1), Float(f2)) => Ok(Float(*f1 - *f2)),
            // _ => nyi!(line!()),
            (v1, v2) => unimplemented!("{:?} - {:?}", v1, v2),
        },
        Mul => match (&*v1, &*v2) {
            (Nat(n1), Nat(n2)) => Ok(Nat(n1 * n2)),
            (Int(i1), Int(i2)) => Ok(Int(i1 * i2)),
            (Float(f1), Float(f2)) => Ok(Float(*f1 * *f2)),
            // _ => nyi!(line!()),
            (v1, v2) => unimplemented!("{:?} * {:?}", v1, v2),
        },
        WAdd => match (cont_prim_type, &*v1, &*v2) {
            (None, _, _) => Err(Interruption::AmbiguousOperation),
            (Some(t), Value::Nat(n1), Value::Nat(n2)) => match t {
                PrimType::Nat => Ok(Value::Nat(n1 + n2)),
                PrimType::Nat8 => Ok(Value::Nat(
                    (n1 + n2) % BigUint::parse_bytes(b"256", 10).unwrap(),
                )),
                _ => nyi!(line!()),
            },
            _ => nyi!(line!()),
        },

        Mod | Pow | And | Or | Xor | ShL | ShR | RotL | RotR | WSub | WMul | WPow | Cat | BitOr
        | BitAnd => nyi!(line!(), "binop({:?}. {:?}, {:?})", binop, v1, v2),
    }
}

pub fn relop(
    _cont_prim_xotype: &Option<PrimType>,
    relop: RelOp,
    v1: Value_,
    v2: Value_,
) -> Result<Value, Interruption> {
    use RelOp::*;
    use Value::*;
    Ok(Bool(match relop {
        Eq => match (&*v1, &*v2) {
            (Unit, Unit) => true,
            (Bool(b1), Bool(b2)) => b1 == b2,
            (Text(t1), Text(t2)) => t1 == t2,
            (Nat(n1), Nat(n2)) => n1 == n2,
            (Int(i1), Int(i2)) => i1 == i2,
            (v1, v2) => v1 == v2, //            _ => nyi!(line!(), "{:?} == {:?}", v1, v2)?,
        },
        Neq => match (&*v1, &*v2) {
            (Unit, Unit) => false,
            (Bool(b1), Bool(b2)) => b1 != b2,
            (Text(t1), Text(t2)) => t1 == t2,
            (Nat(n1), Nat(n2)) => n1 != n2,
            (Int(i1), Int(i2)) => i1 != i2,
            (v1, v2) => v1 != v2, //            _ => nyi!(line!(), "{:?} == {:?}", v1, v2)?,
        },
        Lt => match (&*v1, &*v2) {
            (Unit, Unit) => false,
            (Nat(n1), Nat(n2)) => n1 < n2,
            (Int(i1), Int(i2)) => i1 < i2,
            _ => nyi!(line!(), "{:?} < {:?}", v1, v2)?,
        },
        Le => match (&*v1, &*v2) {
            (Unit, Unit) => false,
            (Nat(n1), Nat(n2)) => n1 <= n2,
            (Int(i1), Int(i2)) => i1 <= i2,
            _ => nyi!(line!(), "{:?} <= {:?}", v1, v2)?,
        },
        Gt => match (&*v1, &*v2) {
            (Unit, Unit) => false,
            (Nat(n1), Nat(n2)) => n1 > n2,
            (Int(i1), Int(i2)) => i1 > i2,
            _ => nyi!(line!(), "{:?} > {:?}", v1, v2)?,
        },
        Ge => match (&*v1, &*v2) {
            (Unit, Unit) => false,
            (Nat(n1), Nat(n2)) => n1 >= n2,
            (Int(i1), Int(i2)) => i1 >= i2,
            _ => nyi!(line!(), "{:?} >= {:?}", v1, v2)?,
        },
        //        _ => nyi!(line!(), "relop({:?}, {:?}, {:?})", relop, v1, v2)?,
    }))
}