Changeset - 05c5f19eb371
[Not reviewed]
0 2 4
Hans-Dieter Hiep - 5 years ago 2020-02-10 17:54:35
hdh@cwi.nl
Implements logical and/or and message equality
6 files changed with 213 insertions and 179 deletions:
0 comments (0 inline, 0 general)
src/protocol/eval.rs
Show inline comments
 
@@ -33,660 +33,656 @@ pub enum Value {
 
    Input(InputValue),
 
    Output(OutputValue),
 
    Message(MessageValue),
 
    Boolean(BooleanValue),
 
    Byte(ByteValue),
 
    Short(ShortValue),
 
    Int(IntValue),
 
    Long(LongValue),
 
    InputArray(InputArrayValue),
 
    OutputArray(OutputArrayValue),
 
    MessageArray(MessageArrayValue),
 
    BooleanArray(BooleanArrayValue),
 
    ByteArray(ByteArrayValue),
 
    ShortArray(ShortArrayValue),
 
    IntArray(IntArrayValue),
 
    LongArray(LongArrayValue),
 
}
 
impl Value {
 
    pub fn receive_message(buffer: &Vec<u8>) -> Value {
 
        Value::Message(MessageValue(Some(buffer.clone())))
 
    }
 
    fn create_message(length: Value) -> Value {
 
        match length {
 
            Value::Byte(_) | Value::Short(_) | Value::Int(_) | Value::Long(_) => {
 
                let length: i64 = i64::from(length);
 
                if length < 0 || length > MESSAGE_MAX_LENGTH {
 
                    // Only messages within the expected length are allowed
 
                    Value::Message(MessageValue(None))
 
                } else {
 
                    Value::Message(MessageValue(Some(vec![0; length.try_into().unwrap()])))
 
                }
 
            }
 
            _ => unimplemented!(),
 
        }
 
    }
 
    fn from_constant(constant: &Constant) -> Value {
 
        match constant {
 
            Constant::Null => Value::Message(MessageValue(None)),
 
            Constant::True => Value::Boolean(BooleanValue(true)),
 
            Constant::False => Value::Boolean(BooleanValue(false)),
 
            Constant::Integer(data) => {
 
                // Convert raw ASCII data to UTF-8 string
 
                let raw = String::from_utf8_lossy(data);
 
                let val = raw.parse::<i64>().unwrap();
 
                if val >= BYTE_MIN && val <= BYTE_MAX {
 
                    Value::Byte(ByteValue(val as i8))
 
                } else if val >= SHORT_MIN && val <= SHORT_MAX {
 
                    Value::Short(ShortValue(val as i16))
 
                } else if val >= INT_MIN && val <= INT_MAX {
 
                    Value::Int(IntValue(val as i32))
 
                } else {
 
                    Value::Long(LongValue(val))
 
                }
 
            }
 
            Constant::Character(data) => unimplemented!(),
 
        }
 
    }
 
    fn set(&mut self, index: &Value, value: &Value) -> Option<Value> {
 
        // The index must be of integer type, and non-negative
 
        let the_index: usize;
 
        match index {
 
            Value::Byte(_) | Value::Short(_) | Value::Int(_) | Value::Long(_) => {
 
                let index = i64::from(index);
 
                if index < 0 || index >= MESSAGE_MAX_LENGTH {
 
                    // It is inconsistent to update out of bounds
 
                    return None;
 
                }
 
                the_index = index.try_into().unwrap();
 
            }
 
            _ => unreachable!(),
 
        }
 
        // The subject must be either a message or an array
 
        // And the value and the subject must be compatible
 
        match (self, value) {
 
            (Value::Message(MessageValue(None)), _) => {
 
                // It is inconsistent to update the null message
 
                None
 
            }
 
            (Value::Message(MessageValue(Some(buffer))), Value::Byte(ByteValue(b))) => {
 
                if *b < 0 {
 
                    // It is inconsistent to update with a negative value
 
                    return None;
 
                }
 
                if let Some(slot) = buffer.get_mut(the_index) {
 
                    *slot = (*b).try_into().unwrap();
 
                    Some(value.clone())
 
                } else {
 
                    // It is inconsistent to update out of bounds
 
                    None
 
                }
 
            }
 
            (Value::Message(MessageValue(Some(buffer))), Value::Short(ShortValue(b))) => {
 
                if *b < 0 || *b > BYTE_MAX as i16 {
 
                    // It is inconsistent to update with a negative value or a too large value
 
                    return None;
 
                }
 
                if let Some(slot) = buffer.get_mut(the_index) {
 
                    *slot = (*b).try_into().unwrap();
 
                    Some(value.clone())
 
                } else {
 
                    // It is inconsistent to update out of bounds
 
                    None
 
                }
 
            }
 
            (Value::InputArray(_), Value::Input(_)) => todo!(),
 
            (Value::OutputArray(_), Value::Output(_)) => todo!(),
 
            (Value::MessageArray(_), Value::Message(_)) => todo!(),
 
            (Value::BooleanArray(_), Value::Boolean(_)) => todo!(),
 
            (Value::ByteArray(_), Value::Byte(_)) => todo!(),
 
            (Value::ShortArray(_), Value::Short(_)) => todo!(),
 
            (Value::IntArray(_), Value::Int(_)) => todo!(),
 
            (Value::LongArray(_), Value::Long(_)) => todo!(),
 
            _ => unreachable!(),
 
        }
 
    }
 
    fn get(&self, index: &Value) -> Option<Value> {
 
        // The index must be of integer type, and non-negative
 
        let the_index: usize;
 
        match index {
 
            Value::Byte(_) | Value::Short(_) | Value::Int(_) | Value::Long(_) => {
 
                let index = i64::from(index);
 
                if index < 0 || index >= MESSAGE_MAX_LENGTH {
 
                    // It is inconsistent to update out of bounds
 
                    return None;
 
                }
 
                the_index = index.try_into().unwrap();
 
            }
 
            _ => unreachable!(),
 
        }
 
        // The subject must be either a message or an array
 
        match self {
 
            Value::Message(MessageValue(None)) => {
 
                // It is inconsistent to read from the null message
 
                None
 
            }
 
            Value::Message(MessageValue(Some(buffer))) => {
 
                if let Some(slot) = buffer.get(the_index) {
 
                    Some(Value::Short(ShortValue((*slot).try_into().unwrap())))
 
                } else {
 
                    // It is inconsistent to update out of bounds
 
                    None
 
                }
 
            }
 
            Value::InputArray(_) => todo!(),
 
            Value::OutputArray(_) => todo!(),
 
            Value::MessageArray(_) => todo!(),
 
            Value::BooleanArray(_) => todo!(),
 
            Value::ByteArray(_) => todo!(),
 
            Value::ShortArray(_) => todo!(),
 
            Value::IntArray(_) => todo!(),
 
            Value::LongArray(_) => todo!(),
 
            _ => unreachable!(),
 
        }
 
    }
 
    fn length(&self) -> Option<Value> {
 
        // The subject must be either a message or an array
 
        match self {
 
            Value::Message(MessageValue(None)) => {
 
                // It is inconsistent to get length from the null message
 
                None
 
            }
 
            Value::Message(MessageValue(Some(buffer))) => {
 
                Some(Value::Int(IntValue((buffer.len()).try_into().unwrap())))
 
            }
 
            Value::InputArray(InputArrayValue(vec)) => {
 
                Some(Value::Int(IntValue((vec.len()).try_into().unwrap())))
 
            }
 
            Value::OutputArray(OutputArrayValue(vec)) => {
 
                Some(Value::Int(IntValue((vec.len()).try_into().unwrap())))
 
            }
 
            Value::MessageArray(MessageArrayValue(vec)) => {
 
                Some(Value::Int(IntValue((vec.len()).try_into().unwrap())))
 
            }
 
            Value::BooleanArray(BooleanArrayValue(vec)) => {
 
                Some(Value::Int(IntValue((vec.len()).try_into().unwrap())))
 
            }
 
            Value::ByteArray(ByteArrayValue(vec)) => {
 
                Some(Value::Int(IntValue((vec.len()).try_into().unwrap())))
 
            }
 
            Value::ShortArray(ShortArrayValue(vec)) => {
 
                Some(Value::Int(IntValue((vec.len()).try_into().unwrap())))
 
            }
 
            Value::IntArray(IntArrayValue(vec)) => {
 
                Some(Value::Int(IntValue((vec.len()).try_into().unwrap())))
 
            }
 
            Value::LongArray(LongArrayValue(vec)) => {
 
                Some(Value::Int(IntValue((vec.len()).try_into().unwrap())))
 
            }
 
            _ => unreachable!(),
 
        }
 
    }
 
    fn plus(&self, other: &Value) -> Value {
 
        // TODO: do a match on the value directly
 
        assert!(!self.exact_type().array);
 
        assert!(!other.exact_type().array);
 
        match (self.exact_type().primitive, other.exact_type().primitive) {
 
            (PrimitiveType::Byte, PrimitiveType::Byte) => {
 
                Value::Byte(ByteValue(i8::from(self) + i8::from(other)))
 
        match (self, other) {
 
            (Value::Byte(ByteValue(s)), Value::Byte(ByteValue(o))) => {
 
                Value::Byte(ByteValue(*s + *o))
 
            }
 
            (PrimitiveType::Byte, PrimitiveType::Short) => {
 
                Value::Short(ShortValue(i16::from(self) + i16::from(other)))
 
            (Value::Byte(ByteValue(s)), Value::Short(ShortValue(o))) => {
 
                Value::Short(ShortValue(*s as i16 + *o))
 
            }
 
            (PrimitiveType::Byte, PrimitiveType::Int) => {
 
                Value::Int(IntValue(i32::from(self) + i32::from(other)))
 
            (Value::Byte(ByteValue(s)), Value::Int(IntValue(o))) => {
 
                Value::Int(IntValue(*s as i32 + *o))
 
            }
 
            (PrimitiveType::Byte, PrimitiveType::Long) => {
 
                Value::Long(LongValue(i64::from(self) + i64::from(other)))
 
            (Value::Byte(ByteValue(s)), Value::Long(LongValue(o))) => {
 
                Value::Long(LongValue(*s as i64 + *o))
 
            }
 
            (PrimitiveType::Short, PrimitiveType::Byte) => {
 
                Value::Short(ShortValue(i16::from(self) + i16::from(other)))
 
            (Value::Short(ShortValue(s)), Value::Byte(ByteValue(o))) => {
 
                Value::Short(ShortValue(*s + *o as i16))
 
            }
 
            (PrimitiveType::Short, PrimitiveType::Short) => {
 
                Value::Short(ShortValue(i16::from(self) + i16::from(other)))
 
            (Value::Short(ShortValue(s)), Value::Short(ShortValue(o))) => {
 
                Value::Short(ShortValue(*s + *o))
 
            }
 
            (PrimitiveType::Short, PrimitiveType::Int) => {
 
                Value::Int(IntValue(i32::from(self) + i32::from(other)))
 
            (Value::Short(ShortValue(s)), Value::Int(IntValue(o))) => {
 
                Value::Int(IntValue(*s as i32 + *o))
 
            }
 
            (PrimitiveType::Short, PrimitiveType::Long) => {
 
                Value::Long(LongValue(i64::from(self) + i64::from(other)))
 
            (Value::Short(ShortValue(s)), Value::Long(LongValue(o))) => {
 
                Value::Long(LongValue(*s as i64 + *o))
 
            }
 
            (PrimitiveType::Int, PrimitiveType::Byte) => {
 
                Value::Int(IntValue(i32::from(self) + i32::from(other)))
 
            (Value::Int(IntValue(s)), Value::Byte(ByteValue(o))) => {
 
                Value::Int(IntValue(*s + *o as i32))
 
            }
 
            (PrimitiveType::Int, PrimitiveType::Short) => {
 
                Value::Int(IntValue(i32::from(self) + i32::from(other)))
 
            (Value::Int(IntValue(s)), Value::Short(ShortValue(o))) => {
 
                Value::Int(IntValue(*s + *o as i32))
 
            }
 
            (PrimitiveType::Int, PrimitiveType::Int) => {
 
                Value::Int(IntValue(i32::from(self) + i32::from(other)))
 
            (Value::Int(IntValue(s)), Value::Int(IntValue(o))) => {
 
                Value::Int(IntValue(*s + *o))
 
            }
 
            (PrimitiveType::Int, PrimitiveType::Long) => {
 
                Value::Long(LongValue(i64::from(self) + i64::from(other)))
 
            (Value::Int(IntValue(s)), Value::Long(LongValue(o))) => {
 
                Value::Long(LongValue(*s as i64 + *o))
 
            }
 
            (PrimitiveType::Long, PrimitiveType::Byte) => {
 
                Value::Long(LongValue(i64::from(self) + i64::from(other)))
 
            (Value::Long(LongValue(s)), Value::Byte(ByteValue(o))) => {
 
                Value::Long(LongValue(*s + *o as i64))
 
            }
 
            (PrimitiveType::Long, PrimitiveType::Short) => {
 
                Value::Long(LongValue(i64::from(self) + i64::from(other)))
 
            (Value::Long(LongValue(s)), Value::Short(ShortValue(o))) => {
 
                Value::Long(LongValue(*s + *o as i64))
 
            }
 
            (PrimitiveType::Long, PrimitiveType::Int) => {
 
                Value::Long(LongValue(i64::from(self) + i64::from(other)))
 
            (Value::Long(LongValue(s)), Value::Int(IntValue(o))) => {
 
                Value::Long(LongValue(*s + *o as i64))
 
            }
 
            (PrimitiveType::Long, PrimitiveType::Long) => {
 
                Value::Long(LongValue(i64::from(self) + i64::from(other)))
 
            (Value::Long(LongValue(s)), Value::Long(LongValue(o))) => {
 
                Value::Long(LongValue(*s + *o))
 
            }
 
            _ => unimplemented!(),
 
        }
 
    }
 
    fn minus(&self, other: &Value) -> Value {
 
        assert!(!self.exact_type().array);
 
        assert!(!other.exact_type().array);
 
        match (self.exact_type().primitive, other.exact_type().primitive) {
 
            (PrimitiveType::Byte, PrimitiveType::Byte) => {
 
                Value::Byte(ByteValue(i8::from(self) - i8::from(other)))
 
        match (self, other) {
 
            (Value::Byte(ByteValue(s)), Value::Byte(ByteValue(o))) => {
 
                Value::Byte(ByteValue(*s - *o))
 
            }
 
            (PrimitiveType::Byte, PrimitiveType::Short) => {
 
                Value::Short(ShortValue(i16::from(self) - i16::from(other)))
 
            (Value::Byte(ByteValue(s)), Value::Short(ShortValue(o))) => {
 
                Value::Short(ShortValue(*s as i16 - *o))
 
            }
 
            (PrimitiveType::Byte, PrimitiveType::Int) => {
 
                Value::Int(IntValue(i32::from(self) - i32::from(other)))
 
            (Value::Byte(ByteValue(s)), Value::Int(IntValue(o))) => {
 
                Value::Int(IntValue(*s as i32 - *o))
 
            }
 
            (PrimitiveType::Byte, PrimitiveType::Long) => {
 
                Value::Long(LongValue(i64::from(self) - i64::from(other)))
 
            (Value::Byte(ByteValue(s)), Value::Long(LongValue(o))) => {
 
                Value::Long(LongValue(*s as i64 - *o))
 
            }
 
            (PrimitiveType::Short, PrimitiveType::Byte) => {
 
                Value::Short(ShortValue(i16::from(self) - i16::from(other)))
 
            (Value::Short(ShortValue(s)), Value::Byte(ByteValue(o))) => {
 
                Value::Short(ShortValue(*s - *o as i16))
 
            }
 
            (PrimitiveType::Short, PrimitiveType::Short) => {
 
                Value::Short(ShortValue(i16::from(self) - i16::from(other)))
 
            (Value::Short(ShortValue(s)), Value::Short(ShortValue(o))) => {
 
                Value::Short(ShortValue(*s - *o))
 
            }
 
            (PrimitiveType::Short, PrimitiveType::Int) => {
 
                Value::Int(IntValue(i32::from(self) - i32::from(other)))
 
            (Value::Short(ShortValue(s)), Value::Int(IntValue(o))) => {
 
                Value::Int(IntValue(*s as i32 - *o))
 
            }
 
            (PrimitiveType::Short, PrimitiveType::Long) => {
 
                Value::Long(LongValue(i64::from(self) - i64::from(other)))
 
            (Value::Short(ShortValue(s)), Value::Long(LongValue(o))) => {
 
                Value::Long(LongValue(*s as i64 - *o))
 
            }
 
            (PrimitiveType::Int, PrimitiveType::Byte) => {
 
                Value::Int(IntValue(i32::from(self) - i32::from(other)))
 
            (Value::Int(IntValue(s)), Value::Byte(ByteValue(o))) => {
 
                Value::Int(IntValue(*s - *o as i32))
 
            }
 
            (PrimitiveType::Int, PrimitiveType::Short) => {
 
                Value::Int(IntValue(i32::from(self) - i32::from(other)))
 
            (Value::Int(IntValue(s)), Value::Short(ShortValue(o))) => {
 
                Value::Int(IntValue(*s - *o as i32))
 
            }
 
            (PrimitiveType::Int, PrimitiveType::Int) => {
 
                Value::Int(IntValue(i32::from(self) - i32::from(other)))
 
            (Value::Int(IntValue(s)), Value::Int(IntValue(o))) => {
 
                Value::Int(IntValue(*s - *o))
 
            }
 
            (PrimitiveType::Int, PrimitiveType::Long) => {
 
                Value::Long(LongValue(i64::from(self) - i64::from(other)))
 
            (Value::Int(IntValue(s)), Value::Long(LongValue(o))) => {
 
                Value::Long(LongValue(*s as i64 - *o))
 
            }
 
            (PrimitiveType::Long, PrimitiveType::Byte) => {
 
                Value::Long(LongValue(i64::from(self) - i64::from(other)))
 
            (Value::Long(LongValue(s)), Value::Byte(ByteValue(o))) => {
 
                Value::Long(LongValue(*s - *o as i64))
 
            }
 
            (PrimitiveType::Long, PrimitiveType::Short) => {
 
                Value::Long(LongValue(i64::from(self) - i64::from(other)))
 
            (Value::Long(LongValue(s)), Value::Short(ShortValue(o))) => {
 
                Value::Long(LongValue(*s - *o as i64))
 
            }
 
            (PrimitiveType::Long, PrimitiveType::Int) => {
 
                Value::Long(LongValue(i64::from(self) - i64::from(other)))
 
            (Value::Long(LongValue(s)), Value::Int(IntValue(o))) => {
 
                Value::Long(LongValue(*s - *o as i64))
 
            }
 
            (PrimitiveType::Long, PrimitiveType::Long) => {
 
                Value::Long(LongValue(i64::from(self) - i64::from(other)))
 
            (Value::Long(LongValue(s)), Value::Long(LongValue(o))) => {
 
                Value::Long(LongValue(*s - *o))
 
            }
 
            _ => unimplemented!(),
 
        }
 
    }
 
    fn modulus(&self, other: &Value) -> Value {
 
        assert!(!self.exact_type().array);
 
        assert!(!other.exact_type().array);
 
        match (self.exact_type().primitive, other.exact_type().primitive) {
 
            (PrimitiveType::Byte, PrimitiveType::Byte) => {
 
                Value::Byte(ByteValue(i8::from(self) % i8::from(other)))
 
        match (self, other) {
 
            (Value::Byte(ByteValue(s)), Value::Byte(ByteValue(o))) => {
 
                Value::Byte(ByteValue(*s % *o))
 
            }
 
            (PrimitiveType::Byte, PrimitiveType::Short) => {
 
                Value::Short(ShortValue(i16::from(self) % i16::from(other)))
 
            (Value::Byte(ByteValue(s)), Value::Short(ShortValue(o))) => {
 
                Value::Short(ShortValue(*s as i16 % *o))
 
            }
 
            (PrimitiveType::Byte, PrimitiveType::Int) => {
 
                Value::Int(IntValue(i32::from(self) % i32::from(other)))
 
            (Value::Byte(ByteValue(s)), Value::Int(IntValue(o))) => {
 
                Value::Int(IntValue(*s as i32 % *o))
 
            }
 
            (PrimitiveType::Byte, PrimitiveType::Long) => {
 
                Value::Long(LongValue(i64::from(self) % i64::from(other)))
 
            (Value::Byte(ByteValue(s)), Value::Long(LongValue(o))) => {
 
                Value::Long(LongValue(*s as i64 % *o))
 
            }
 
            (PrimitiveType::Short, PrimitiveType::Byte) => {
 
                Value::Short(ShortValue(i16::from(self) % i16::from(other)))
 
            (Value::Short(ShortValue(s)), Value::Byte(ByteValue(o))) => {
 
                Value::Short(ShortValue(*s % *o as i16))
 
            }
 
            (PrimitiveType::Short, PrimitiveType::Short) => {
 
                Value::Short(ShortValue(i16::from(self) % i16::from(other)))
 
            (Value::Short(ShortValue(s)), Value::Short(ShortValue(o))) => {
 
                Value::Short(ShortValue(*s % *o))
 
            }
 
            (PrimitiveType::Short, PrimitiveType::Int) => {
 
                Value::Int(IntValue(i32::from(self) % i32::from(other)))
 
            (Value::Short(ShortValue(s)), Value::Int(IntValue(o))) => {
 
                Value::Int(IntValue(*s as i32 % *o))
 
            }
 
            (PrimitiveType::Short, PrimitiveType::Long) => {
 
                Value::Long(LongValue(i64::from(self) % i64::from(other)))
 
            (Value::Short(ShortValue(s)), Value::Long(LongValue(o))) => {
 
                Value::Long(LongValue(*s as i64 % *o))
 
            }
 
            (PrimitiveType::Int, PrimitiveType::Byte) => {
 
                Value::Int(IntValue(i32::from(self) % i32::from(other)))
 
            (Value::Int(IntValue(s)), Value::Byte(ByteValue(o))) => {
 
                Value::Int(IntValue(*s % *o as i32))
 
            }
 
            (PrimitiveType::Int, PrimitiveType::Short) => {
 
                Value::Int(IntValue(i32::from(self) % i32::from(other)))
 
            (Value::Int(IntValue(s)), Value::Short(ShortValue(o))) => {
 
                Value::Int(IntValue(*s % *o as i32))
 
            }
 
            (PrimitiveType::Int, PrimitiveType::Int) => {
 
                Value::Int(IntValue(i32::from(self) % i32::from(other)))
 
            (Value::Int(IntValue(s)), Value::Int(IntValue(o))) => {
 
                Value::Int(IntValue(*s % *o))
 
            }
 
            (PrimitiveType::Int, PrimitiveType::Long) => {
 
                Value::Long(LongValue(i64::from(self) % i64::from(other)))
 
            (Value::Int(IntValue(s)), Value::Long(LongValue(o))) => {
 
                Value::Long(LongValue(*s as i64 % *o))
 
            }
 
            (PrimitiveType::Long, PrimitiveType::Byte) => {
 
                Value::Long(LongValue(i64::from(self) % i64::from(other)))
 
            (Value::Long(LongValue(s)), Value::Byte(ByteValue(o))) => {
 
                Value::Long(LongValue(*s % *o as i64))
 
            }
 
            (PrimitiveType::Long, PrimitiveType::Short) => {
 
                Value::Long(LongValue(i64::from(self) % i64::from(other)))
 
            (Value::Long(LongValue(s)), Value::Short(ShortValue(o))) => {
 
                Value::Long(LongValue(*s % *o as i64))
 
            }
 
            (PrimitiveType::Long, PrimitiveType::Int) => {
 
                Value::Long(LongValue(i64::from(self) % i64::from(other)))
 
            (Value::Long(LongValue(s)), Value::Int(IntValue(o))) => {
 
                Value::Long(LongValue(*s % *o as i64))
 
            }
 
            (PrimitiveType::Long, PrimitiveType::Long) => {
 
                Value::Long(LongValue(i64::from(self) % i64::from(other)))
 
            (Value::Long(LongValue(s)), Value::Long(LongValue(o))) => {
 
                Value::Long(LongValue(*s % *o))
 
            }
 
            _ => unimplemented!(),
 
        }
 
    }
 
    fn eq(&self, other: &Value) -> Value {
 
        assert!(!self.exact_type().array);
 
        assert!(!other.exact_type().array);
 
        match (self.exact_type().primitive, other.exact_type().primitive) {
 
            (PrimitiveType::Byte, PrimitiveType::Byte) => {
 
                Value::Boolean(BooleanValue(i8::from(self) == i8::from(other)))
 
        match (self, other) {
 
            (Value::Byte(ByteValue(s)), Value::Byte(ByteValue(o))) => {
 
                Value::Boolean(BooleanValue(*s == *o))
 
            }
 
            (PrimitiveType::Byte, PrimitiveType::Short) => {
 
                Value::Boolean(BooleanValue(i16::from(self) == i16::from(other)))
 
            (Value::Byte(ByteValue(s)), Value::Short(ShortValue(o))) => {
 
                Value::Boolean(BooleanValue(*s as i16 == *o))
 
            }
 
            (PrimitiveType::Byte, PrimitiveType::Int) => {
 
                Value::Boolean(BooleanValue(i32::from(self) == i32::from(other)))
 
            (Value::Byte(ByteValue(s)), Value::Int(IntValue(o))) => {
 
                Value::Boolean(BooleanValue(*s as i32 == *o))
 
            }
 
            (PrimitiveType::Byte, PrimitiveType::Long) => {
 
                Value::Boolean(BooleanValue(i64::from(self) == i64::from(other)))
 
            (Value::Byte(ByteValue(s)), Value::Long(LongValue(o))) => {
 
                Value::Boolean(BooleanValue(*s as i64 == *o))
 
            }
 
            (PrimitiveType::Short, PrimitiveType::Byte) => {
 
                Value::Boolean(BooleanValue(i16::from(self) == i16::from(other)))
 
            (Value::Short(ShortValue(s)), Value::Byte(ByteValue(o))) => {
 
                Value::Boolean(BooleanValue(*s == *o as i16))
 
            }
 
            (PrimitiveType::Short, PrimitiveType::Short) => {
 
                Value::Boolean(BooleanValue(i16::from(self) == i16::from(other)))
 
            (Value::Short(ShortValue(s)), Value::Short(ShortValue(o))) => {
 
                Value::Boolean(BooleanValue(*s == *o))
 
            }
 
            (PrimitiveType::Short, PrimitiveType::Int) => {
 
                Value::Boolean(BooleanValue(i32::from(self) == i32::from(other)))
 
            (Value::Short(ShortValue(s)), Value::Int(IntValue(o))) => {
 
                Value::Boolean(BooleanValue(*s as i32 == *o))
 
            }
 
            (PrimitiveType::Short, PrimitiveType::Long) => {
 
                Value::Boolean(BooleanValue(i64::from(self) == i64::from(other)))
 
            (Value::Short(ShortValue(s)), Value::Long(LongValue(o))) => {
 
                Value::Boolean(BooleanValue(*s as i64 == *o))
 
            }
 
            (PrimitiveType::Int, PrimitiveType::Byte) => {
 
                Value::Boolean(BooleanValue(i32::from(self) == i32::from(other)))
 
            (Value::Int(IntValue(s)), Value::Byte(ByteValue(o))) => {
 
                Value::Boolean(BooleanValue(*s == *o as i32))
 
            }
 
            (PrimitiveType::Int, PrimitiveType::Short) => {
 
                Value::Boolean(BooleanValue(i32::from(self) == i32::from(other)))
 
            (Value::Int(IntValue(s)), Value::Short(ShortValue(o))) => {
 
                Value::Boolean(BooleanValue(*s == *o as i32))
 
            }
 
            (PrimitiveType::Int, PrimitiveType::Int) => {
 
                Value::Boolean(BooleanValue(i32::from(self) == i32::from(other)))
 
            (Value::Int(IntValue(s)), Value::Int(IntValue(o))) => {
 
                Value::Boolean(BooleanValue(*s == *o))
 
            }
 
            (PrimitiveType::Int, PrimitiveType::Long) => {
 
                Value::Boolean(BooleanValue(i64::from(self) == i64::from(other)))
 
            (Value::Int(IntValue(s)), Value::Long(LongValue(o))) => {
 
                Value::Boolean(BooleanValue(*s as i64 == *o))
 
            }
 
            (PrimitiveType::Long, PrimitiveType::Byte) => {
 
                Value::Boolean(BooleanValue(i64::from(self) == i64::from(other)))
 
            (Value::Long(LongValue(s)), Value::Byte(ByteValue(o))) => {
 
                Value::Boolean(BooleanValue(*s == *o as i64))
 
            }
 
            (PrimitiveType::Long, PrimitiveType::Short) => {
 
                Value::Boolean(BooleanValue(i64::from(self) == i64::from(other)))
 
            (Value::Long(LongValue(s)), Value::Short(ShortValue(o))) => {
 
                Value::Boolean(BooleanValue(*s == *o as i64))
 
            }
 
            (PrimitiveType::Long, PrimitiveType::Int) => {
 
                Value::Boolean(BooleanValue(i64::from(self) == i64::from(other)))
 
            (Value::Long(LongValue(s)), Value::Int(IntValue(o))) => {
 
                Value::Boolean(BooleanValue(*s == *o as i64))
 
            }
 
            (PrimitiveType::Long, PrimitiveType::Long) => {
 
                Value::Boolean(BooleanValue(i64::from(self) == i64::from(other)))
 
            (Value::Long(LongValue(s)), Value::Long(LongValue(o))) => {
 
                Value::Boolean(BooleanValue(*s == *o))
 
            }
 
            (Value::Message(MessageValue(s)), Value::Message(MessageValue(o))) => {
 
                Value::Boolean(BooleanValue(*s == *o))
 
            }
 
            _ => unimplemented!(),
 
        }
 
    }
 
    fn neq(&self, other: &Value) -> Value {
 
        assert!(!self.exact_type().array);
 
        assert!(!other.exact_type().array);
 
        match (self.exact_type().primitive, other.exact_type().primitive) {
 
            (PrimitiveType::Byte, PrimitiveType::Byte) => {
 
                Value::Boolean(BooleanValue(i8::from(self) != i8::from(other)))
 
        match (self, other) {
 
            (Value::Byte(ByteValue(s)), Value::Byte(ByteValue(o))) => {
 
                Value::Boolean(BooleanValue(*s != *o))
 
            }
 
            (PrimitiveType::Byte, PrimitiveType::Short) => {
 
                Value::Boolean(BooleanValue(i16::from(self) != i16::from(other)))
 
            (Value::Byte(ByteValue(s)), Value::Short(ShortValue(o))) => {
 
                Value::Boolean(BooleanValue(*s as i16 != *o))
 
            }
 
            (PrimitiveType::Byte, PrimitiveType::Int) => {
 
                Value::Boolean(BooleanValue(i32::from(self) != i32::from(other)))
 
            (Value::Byte(ByteValue(s)), Value::Int(IntValue(o))) => {
 
                Value::Boolean(BooleanValue(*s as i32 != *o))
 
            }
 
            (PrimitiveType::Byte, PrimitiveType::Long) => {
 
                Value::Boolean(BooleanValue(i64::from(self) != i64::from(other)))
 
            (Value::Byte(ByteValue(s)), Value::Long(LongValue(o))) => {
 
                Value::Boolean(BooleanValue(*s as i64 != *o))
 
            }
 
            (PrimitiveType::Short, PrimitiveType::Byte) => {
 
                Value::Boolean(BooleanValue(i16::from(self) != i16::from(other)))
 
            (Value::Short(ShortValue(s)), Value::Byte(ByteValue(o))) => {
 
                Value::Boolean(BooleanValue(*s != *o as i16))
 
            }
 
            (PrimitiveType::Short, PrimitiveType::Short) => {
 
                Value::Boolean(BooleanValue(i16::from(self) != i16::from(other)))
 
            (Value::Short(ShortValue(s)), Value::Short(ShortValue(o))) => {
 
                Value::Boolean(BooleanValue(*s != *o))
 
            }
 
            (PrimitiveType::Short, PrimitiveType::Int) => {
 
                Value::Boolean(BooleanValue(i32::from(self) != i32::from(other)))
 
            (Value::Short(ShortValue(s)), Value::Int(IntValue(o))) => {
 
                Value::Boolean(BooleanValue(*s as i32 != *o))
 
            }
 
            (PrimitiveType::Short, PrimitiveType::Long) => {
 
                Value::Boolean(BooleanValue(i64::from(self) != i64::from(other)))
 
            (Value::Short(ShortValue(s)), Value::Long(LongValue(o))) => {
 
                Value::Boolean(BooleanValue(*s as i64 != *o))
 
            }
 
            (PrimitiveType::Int, PrimitiveType::Byte) => {
 
                Value::Boolean(BooleanValue(i32::from(self) != i32::from(other)))
 
            (Value::Int(IntValue(s)), Value::Byte(ByteValue(o))) => {
 
                Value::Boolean(BooleanValue(*s != *o as i32))
 
            }
 
            (PrimitiveType::Int, PrimitiveType::Short) => {
 
                Value::Boolean(BooleanValue(i32::from(self) != i32::from(other)))
 
            (Value::Int(IntValue(s)), Value::Short(ShortValue(o))) => {
 
                Value::Boolean(BooleanValue(*s != *o as i32))
 
            }
 
            (PrimitiveType::Int, PrimitiveType::Int) => {
 
                Value::Boolean(BooleanValue(i32::from(self) != i32::from(other)))
 
            (Value::Int(IntValue(s)), Value::Int(IntValue(o))) => {
 
                Value::Boolean(BooleanValue(*s != *o))
 
            }
 
            (PrimitiveType::Int, PrimitiveType::Long) => {
 
                Value::Boolean(BooleanValue(i64::from(self) != i64::from(other)))
 
            (Value::Int(IntValue(s)), Value::Long(LongValue(o))) => {
 
                Value::Boolean(BooleanValue(*s as i64 != *o))
 
            }
 
            (PrimitiveType::Long, PrimitiveType::Byte) => {
 
                Value::Boolean(BooleanValue(i64::from(self) != i64::from(other)))
 
            (Value::Long(LongValue(s)), Value::Byte(ByteValue(o))) => {
 
                Value::Boolean(BooleanValue(*s != *o as i64))
 
            }
 
            (PrimitiveType::Long, PrimitiveType::Short) => {
 
                Value::Boolean(BooleanValue(i64::from(self) != i64::from(other)))
 
            (Value::Long(LongValue(s)), Value::Short(ShortValue(o))) => {
 
                Value::Boolean(BooleanValue(*s != *o as i64))
 
            }
 
            (PrimitiveType::Long, PrimitiveType::Int) => {
 
                Value::Boolean(BooleanValue(i64::from(self) != i64::from(other)))
 
            (Value::Long(LongValue(s)), Value::Int(IntValue(o))) => {
 
                Value::Boolean(BooleanValue(*s != *o as i64))
 
            }
 
            (PrimitiveType::Long, PrimitiveType::Long) => {
 
                Value::Boolean(BooleanValue(i64::from(self) != i64::from(other)))
 
            (Value::Long(LongValue(s)), Value::Long(LongValue(o))) => {
 
                Value::Boolean(BooleanValue(*s != *o))
 
            }
 
            (Value::Message(MessageValue(s)), Value::Message(MessageValue(o))) => {
 
                Value::Boolean(BooleanValue(*s != *o))
 
            }
 
            _ => unimplemented!(),
 
        }
 
    }
 
    fn lt(&self, other: &Value) -> Value {
 
        // TODO: match value directly (as done above)
 
        assert!(!self.exact_type().array);
 
        assert!(!other.exact_type().array);
 
        match (self.exact_type().primitive, other.exact_type().primitive) {
 
            (PrimitiveType::Byte, PrimitiveType::Byte) => {
 
                Value::Boolean(BooleanValue(i8::from(self) < i8::from(other)))
 
            }
 
            (PrimitiveType::Byte, PrimitiveType::Short) => {
 
                Value::Boolean(BooleanValue(i16::from(self) < i16::from(other)))
 
            }
 
            (PrimitiveType::Byte, PrimitiveType::Int) => {
 
                Value::Boolean(BooleanValue(i32::from(self) < i32::from(other)))
 
            }
 
            (PrimitiveType::Byte, PrimitiveType::Long) => {
 
                Value::Boolean(BooleanValue(i64::from(self) < i64::from(other)))
 
            }
 
            (PrimitiveType::Short, PrimitiveType::Byte) => {
 
                Value::Boolean(BooleanValue(i16::from(self) < i16::from(other)))
 
            }
 
            (PrimitiveType::Short, PrimitiveType::Short) => {
 
                Value::Boolean(BooleanValue(i16::from(self) < i16::from(other)))
 
            }
 
            (PrimitiveType::Short, PrimitiveType::Int) => {
 
                Value::Boolean(BooleanValue(i32::from(self) < i32::from(other)))
 
            }
 
            (PrimitiveType::Short, PrimitiveType::Long) => {
 
                Value::Boolean(BooleanValue(i64::from(self) < i64::from(other)))
 
            }
 
            (PrimitiveType::Int, PrimitiveType::Byte) => {
 
                Value::Boolean(BooleanValue(i32::from(self) < i32::from(other)))
 
            }
 
            (PrimitiveType::Int, PrimitiveType::Short) => {
 
                Value::Boolean(BooleanValue(i32::from(self) < i32::from(other)))
 
            }
 
            (PrimitiveType::Int, PrimitiveType::Int) => {
 
                Value::Boolean(BooleanValue(i32::from(self) < i32::from(other)))
 
            }
 
            (PrimitiveType::Int, PrimitiveType::Long) => {
 
                Value::Boolean(BooleanValue(i64::from(self) < i64::from(other)))
 
            }
 
            (PrimitiveType::Long, PrimitiveType::Byte) => {
 
                Value::Boolean(BooleanValue(i64::from(self) < i64::from(other)))
 
            }
 
            (PrimitiveType::Long, PrimitiveType::Short) => {
 
                Value::Boolean(BooleanValue(i64::from(self) < i64::from(other)))
 
            }
 
            (PrimitiveType::Long, PrimitiveType::Int) => {
 
                Value::Boolean(BooleanValue(i64::from(self) < i64::from(other)))
 
            }
 
            (PrimitiveType::Long, PrimitiveType::Long) => {
 
                Value::Boolean(BooleanValue(i64::from(self) < i64::from(other)))
 
            }
 
            _ => unimplemented!(),
 
        }
 
    }
 
    fn lte(&self, other: &Value) -> Value {
 
        assert!(!self.exact_type().array);
 
        assert!(!other.exact_type().array);
 
        match (self.exact_type().primitive, other.exact_type().primitive) {
 
            (PrimitiveType::Byte, PrimitiveType::Byte) => {
 
                Value::Boolean(BooleanValue(i8::from(self) <= i8::from(other)))
 
            }
 
            (PrimitiveType::Byte, PrimitiveType::Short) => {
 
                Value::Boolean(BooleanValue(i16::from(self) <= i16::from(other)))
 
            }
 
            (PrimitiveType::Byte, PrimitiveType::Int) => {
 
                Value::Boolean(BooleanValue(i32::from(self) <= i32::from(other)))
 
            }
 
            (PrimitiveType::Byte, PrimitiveType::Long) => {
 
                Value::Boolean(BooleanValue(i64::from(self) <= i64::from(other)))
 
            }
 
            (PrimitiveType::Short, PrimitiveType::Byte) => {
 
                Value::Boolean(BooleanValue(i16::from(self) <= i16::from(other)))
 
            }
 
            (PrimitiveType::Short, PrimitiveType::Short) => {
 
                Value::Boolean(BooleanValue(i16::from(self) <= i16::from(other)))
 
            }
 
            (PrimitiveType::Short, PrimitiveType::Int) => {
 
                Value::Boolean(BooleanValue(i32::from(self) <= i32::from(other)))
 
            }
 
            (PrimitiveType::Short, PrimitiveType::Long) => {
 
                Value::Boolean(BooleanValue(i64::from(self) <= i64::from(other)))
 
            }
 
            (PrimitiveType::Int, PrimitiveType::Byte) => {
 
                Value::Boolean(BooleanValue(i32::from(self) <= i32::from(other)))
 
            }
 
            (PrimitiveType::Int, PrimitiveType::Short) => {
 
                Value::Boolean(BooleanValue(i32::from(self) <= i32::from(other)))
 
            }
 
            (PrimitiveType::Int, PrimitiveType::Int) => {
 
                Value::Boolean(BooleanValue(i32::from(self) <= i32::from(other)))
 
            }
 
            (PrimitiveType::Int, PrimitiveType::Long) => {
 
                Value::Boolean(BooleanValue(i64::from(self) <= i64::from(other)))
 
            }
 
            (PrimitiveType::Long, PrimitiveType::Byte) => {
 
                Value::Boolean(BooleanValue(i64::from(self) <= i64::from(other)))
 
            }
 
            (PrimitiveType::Long, PrimitiveType::Short) => {
 
                Value::Boolean(BooleanValue(i64::from(self) <= i64::from(other)))
 
            }
 
            (PrimitiveType::Long, PrimitiveType::Int) => {
 
                Value::Boolean(BooleanValue(i64::from(self) <= i64::from(other)))
 
            }
 
            (PrimitiveType::Long, PrimitiveType::Long) => {
 
                Value::Boolean(BooleanValue(i64::from(self) <= i64::from(other)))
 
            }
 
            _ => unimplemented!(),
 
        }
 
    }
 
    fn gt(&self, other: &Value) -> Value {
 
        assert!(!self.exact_type().array);
 
        assert!(!other.exact_type().array);
 
        match (self.exact_type().primitive, other.exact_type().primitive) {
 
            (PrimitiveType::Byte, PrimitiveType::Byte) => {
 
                Value::Boolean(BooleanValue(i8::from(self) > i8::from(other)))
 
            }
 
            (PrimitiveType::Byte, PrimitiveType::Short) => {
 
                Value::Boolean(BooleanValue(i16::from(self) > i16::from(other)))
 
            }
 
            (PrimitiveType::Byte, PrimitiveType::Int) => {
 
                Value::Boolean(BooleanValue(i32::from(self) > i32::from(other)))
 
            }
 
            (PrimitiveType::Byte, PrimitiveType::Long) => {
 
                Value::Boolean(BooleanValue(i64::from(self) > i64::from(other)))
 
            }
 
            (PrimitiveType::Short, PrimitiveType::Byte) => {
 
                Value::Boolean(BooleanValue(i16::from(self) > i16::from(other)))
 
            }
 
            (PrimitiveType::Short, PrimitiveType::Short) => {
 
                Value::Boolean(BooleanValue(i16::from(self) > i16::from(other)))
 
            }
 
            (PrimitiveType::Short, PrimitiveType::Int) => {
 
                Value::Boolean(BooleanValue(i32::from(self) > i32::from(other)))
 
            }
 
            (PrimitiveType::Short, PrimitiveType::Long) => {
 
                Value::Boolean(BooleanValue(i64::from(self) > i64::from(other)))
 
            }
 
            (PrimitiveType::Int, PrimitiveType::Byte) => {
 
                Value::Boolean(BooleanValue(i32::from(self) > i32::from(other)))
 
            }
 
            (PrimitiveType::Int, PrimitiveType::Short) => {
 
                Value::Boolean(BooleanValue(i32::from(self) > i32::from(other)))
 
            }
 
            (PrimitiveType::Int, PrimitiveType::Int) => {
 
                Value::Boolean(BooleanValue(i32::from(self) > i32::from(other)))
 
            }
 
            (PrimitiveType::Int, PrimitiveType::Long) => {
 
                Value::Boolean(BooleanValue(i64::from(self) > i64::from(other)))
 
            }
 
            (PrimitiveType::Long, PrimitiveType::Byte) => {
 
                Value::Boolean(BooleanValue(i64::from(self) > i64::from(other)))
 
            }
 
            (PrimitiveType::Long, PrimitiveType::Short) => {
 
                Value::Boolean(BooleanValue(i64::from(self) > i64::from(other)))
 
            }
 
            (PrimitiveType::Long, PrimitiveType::Int) => {
 
                Value::Boolean(BooleanValue(i64::from(self) > i64::from(other)))
 
            }
 
            (PrimitiveType::Long, PrimitiveType::Long) => {
 
                Value::Boolean(BooleanValue(i64::from(self) > i64::from(other)))
 
            }
 
            _ => unimplemented!(),
 
        }
 
    }
 
    fn gte(&self, other: &Value) -> Value {
 
        assert!(!self.exact_type().array);
 
        assert!(!other.exact_type().array);
 
        match (self.exact_type().primitive, other.exact_type().primitive) {
 
            (PrimitiveType::Byte, PrimitiveType::Byte) => {
 
                Value::Boolean(BooleanValue(i8::from(self) >= i8::from(other)))
 
            }
 
            (PrimitiveType::Byte, PrimitiveType::Short) => {
 
                Value::Boolean(BooleanValue(i16::from(self) >= i16::from(other)))
 
            }
 
            (PrimitiveType::Byte, PrimitiveType::Int) => {
 
                Value::Boolean(BooleanValue(i32::from(self) >= i32::from(other)))
 
            }
 
            (PrimitiveType::Byte, PrimitiveType::Long) => {
 
                Value::Boolean(BooleanValue(i64::from(self) >= i64::from(other)))
 
            }
 
            (PrimitiveType::Short, PrimitiveType::Byte) => {
 
                Value::Boolean(BooleanValue(i16::from(self) >= i16::from(other)))
 
            }
 
            (PrimitiveType::Short, PrimitiveType::Short) => {
 
                Value::Boolean(BooleanValue(i16::from(self) >= i16::from(other)))
 
            }
 
            (PrimitiveType::Short, PrimitiveType::Int) => {
 
                Value::Boolean(BooleanValue(i32::from(self) >= i32::from(other)))
 
            }
 
            (PrimitiveType::Short, PrimitiveType::Long) => {
 
                Value::Boolean(BooleanValue(i64::from(self) >= i64::from(other)))
 
            }
 
@@ -1330,394 +1326,414 @@ impl ValueImpl for ShortArrayValue {
 
#[derive(Debug, Clone)]
 
pub struct IntArrayValue(Vec<IntValue>);
 

	
 
impl Display for IntArrayValue {
 
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
 
        write!(f, "{{")?;
 
        let mut first = true;
 
        for v in self.0.iter() {
 
            if !first {
 
                write!(f, ",")?;
 
            }
 
            write!(f, "{}", v)?;
 
            first = false;
 
        }
 
        write!(f, "}}")
 
    }
 
}
 

	
 
impl ValueImpl for IntArrayValue {
 
    fn exact_type(&self) -> Type {
 
        Type::INT_ARRAY
 
    }
 
    fn is_type_compatible(&self, t: &Type) -> bool {
 
        let Type { primitive, array } = t;
 
        if !*array {
 
            return false;
 
        }
 
        match primitive {
 
            PrimitiveType::Int => true,
 
            _ => false,
 
        }
 
    }
 
}
 

	
 
#[derive(Debug, Clone)]
 
pub struct LongArrayValue(Vec<LongValue>);
 

	
 
impl Display for LongArrayValue {
 
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
 
        write!(f, "{{")?;
 
        let mut first = true;
 
        for v in self.0.iter() {
 
            if !first {
 
                write!(f, ",")?;
 
            }
 
            write!(f, "{}", v)?;
 
            first = false;
 
        }
 
        write!(f, "}}")
 
    }
 
}
 

	
 
impl ValueImpl for LongArrayValue {
 
    fn exact_type(&self) -> Type {
 
        Type::LONG_ARRAY
 
    }
 
    fn is_type_compatible(&self, t: &Type) -> bool {
 
        let Type { primitive, array } = t;
 
        if !*array {
 
            return false;
 
        }
 
        match primitive {
 
            PrimitiveType::Long => true,
 
            _ => false,
 
        }
 
    }
 
}
 

	
 
#[derive(Debug, Clone)]
 
struct Store {
 
    map: HashMap<VariableId, Value>,
 
}
 
impl Store {
 
    fn new() -> Self {
 
        Store { map: HashMap::new() }
 
    }
 
    fn initialize(&mut self, h: &Heap, var: VariableId, value: Value) {
 
        // Ensure value is compatible with type of variable
 
        let the_type = h[var].the_type(h);
 
        assert!(value.is_type_compatible(the_type));
 
        // Overwrite mapping
 
        self.map.insert(var, value.clone());
 
    }
 
    fn update(
 
        &mut self,
 
        h: &Heap,
 
        ctx: &mut EvalContext,
 
        lexpr: ExpressionId,
 
        value: Value,
 
    ) -> EvalResult {
 
        match &h[lexpr] {
 
            Expression::Variable(var) => {
 
                let var = var.declaration.unwrap();
 
                // Ensure value is compatible with type of variable
 
                let the_type = h[var].the_type(h);
 
                assert!(value.is_type_compatible(the_type));
 
                // Overwrite mapping
 
                self.map.insert(var, value.clone());
 
                Ok(value)
 
            }
 
            Expression::Indexing(indexing) => {
 
                // Evaluate index expression, which must be some integral type
 
                let index = self.eval(h, ctx, indexing.index)?;
 
                // Mutable reference to the subject
 
                let subject;
 
                match &h[indexing.subject] {
 
                    Expression::Variable(var) => {
 
                        let var = var.declaration.unwrap();
 
                        subject = self.map.get_mut(&var).unwrap();
 
                    }
 
                    _ => unreachable!(),
 
                }
 
                match subject.set(&index, &value) {
 
                    Some(value) => Ok(value),
 
                    None => Err(EvalContinuation::Inconsistent),
 
                }
 
            }
 
            _ => unimplemented!("{:?}", h[lexpr]),
 
        }
 
    }
 
    fn get(&mut self, h: &Heap, ctx: &mut EvalContext, rexpr: ExpressionId) -> EvalResult {
 
        match &h[rexpr] {
 
            Expression::Variable(var) => {
 
                let var = var.declaration.unwrap();
 
                let value = self.map.get(&var).expect(&format!("Uninitialized variable {:?}", h[h[var].identifier()]));
 
                Ok(value.clone())
 
            }
 
            Expression::Indexing(indexing) => {
 
                // Evaluate index expression, which must be some integral type
 
                let index = self.eval(h, ctx, indexing.index)?;
 
                // Reference to subject
 
                let subject;
 
                match &h[indexing.subject] {
 
                    Expression::Variable(var) => {
 
                        let var = var.declaration.unwrap();
 
                        subject = self.map.get(&var).unwrap();
 
                    }
 
                    _ => unreachable!(),
 
                }
 
                match subject.get(&index) {
 
                    Some(value) => Ok(value),
 
                    None => Err(EvalContinuation::Inconsistent),
 
                }
 
            }
 
            Expression::Select(selecting) => {
 
                // Reference to subject
 
                let subject;
 
                match &h[selecting.subject] {
 
                    Expression::Variable(var) => {
 
                        let var = var.declaration.unwrap();
 
                        subject = self.map.get(&var).unwrap();
 
                    }
 
                    _ => unreachable!(),
 
                }
 
                match subject.length() {
 
                    Some(value) => Ok(value),
 
                    None => Err(EvalContinuation::Inconsistent),
 
                }
 
            }
 
            _ => unimplemented!("{:?}", h[rexpr]),
 
        }
 
    }
 
    fn eval(&mut self, h: &Heap, ctx: &mut EvalContext, expr: ExpressionId) -> EvalResult {
 
        match &h[expr] {
 
            Expression::Assignment(expr) => {
 
                let value = self.eval(h, ctx, expr.right)?;
 
                match expr.operation {
 
                    AssignmentOperator::Set => {
 
                        self.update(h, ctx, expr.left, value.clone())?;
 
                    }
 
                    AssignmentOperator::Added => {
 
                        let old = self.get(h, ctx, expr.left)?;
 
                        self.update(h, ctx, expr.left, old.plus(&value))?;
 
                    }
 
                    AssignmentOperator::Subtracted => {
 
                        let old = self.get(h, ctx, expr.left)?;
 
                        self.update(h, ctx, expr.left, old.minus(&value))?;
 
                    }
 
                    _ => unimplemented!("{:?}", expr),
 
                }
 
                Ok(value)
 
            }
 
            Expression::Conditional(expr) => {
 
                let test = self.eval(h, ctx, expr.test)?;
 
                if test.as_boolean().0 {
 
                    self.eval(h, ctx, expr.true_expression)
 
                } else {
 
                    self.eval(h, ctx, expr.false_expression)
 
                }
 
            }
 
            Expression::Binary(expr) => {
 
                let left = self.eval(h, ctx, expr.left)?;
 
                let right = self.eval(h, ctx, expr.right)?;
 
                let right;
 
                match expr.operation {
 
                    BinaryOperator::LogicalAnd => {
 
                        if left.as_boolean().0 == false {
 
                            return Ok(left)
 
                        }
 
                        right = self.eval(h, ctx, expr.right)?;
 
                        right.as_boolean(); // panics if not a boolean
 
                        return Ok(right);
 
                    }
 
                    BinaryOperator::LogicalOr => {
 
                        if left.as_boolean().0 == true {
 
                            return Ok(left)
 
                        }
 
                        right = self.eval(h, ctx, expr.right)?;
 
                        right.as_boolean(); // panics if not a boolean
 
                        return Ok(right);
 
                    }
 
                    _ => {}
 
                }
 
                right = self.eval(h, ctx, expr.right)?;
 
                match expr.operation {
 
                    BinaryOperator::Equality => Ok(left.eq(&right)),
 
                    BinaryOperator::Inequality => Ok(left.neq(&right)),
 
                    BinaryOperator::LessThan => Ok(left.lt(&right)),
 
                    BinaryOperator::LessThanEqual => Ok(left.lte(&right)),
 
                    BinaryOperator::GreaterThan => Ok(left.gt(&right)),
 
                    BinaryOperator::GreaterThanEqual => Ok(left.gte(&right)),
 
                    BinaryOperator::Remainder => Ok(left.modulus(&right)),
 
                    _ => unimplemented!(),
 
                    _ => unimplemented!("{:?}", expr.operation),
 
                }
 
            }
 
            Expression::Unary(expr) => {
 
                let mut value = self.eval(h, ctx, expr.expression)?;
 
                match expr.operation {
 
                    UnaryOperation::PostIncrement => {
 
                        self.update(h, ctx, expr.expression, value.plus(&ONE))?;
 
                    }
 
                    UnaryOperation::PreIncrement => {
 
                        value = value.plus(&ONE);
 
                        self.update(h, ctx, expr.expression, value.clone())?;
 
                    }
 
                    UnaryOperation::PostDecrement => {
 
                        self.update(h, ctx, expr.expression, value.minus(&ONE))?;
 
                    }
 
                    UnaryOperation::PreDecrement => {
 
                        value = value.minus(&ONE);
 
                        self.update(h, ctx, expr.expression, value.clone())?;
 
                    }
 
                    _ => unimplemented!(),
 
                }
 
                Ok(value)
 
            }
 
            Expression::Indexing(expr) => self.get(h, ctx, expr.this.upcast()),
 
            Expression::Slicing(expr) => unimplemented!(),
 
            Expression::Select(expr) => self.get(h, ctx, expr.this.upcast()),
 
            Expression::Array(expr) => {
 
                let mut elements = Vec::new();
 
                for &elem in expr.elements.iter() {
 
                    elements.push(self.eval(h, ctx, elem)?);
 
                }
 
                todo!()
 
            },
 
            Expression::Constant(expr) => Ok(Value::from_constant(&expr.value)),
 
            Expression::Call(expr) => match expr.method {
 
                Method::Create => {
 
                    assert_eq!(1, expr.arguments.len());
 
                    let length = self.eval(h, ctx, expr.arguments[0])?;
 
                    Ok(Value::create_message(length))
 
                }
 
                Method::Fires => {
 
                    assert_eq!(1, expr.arguments.len());
 
                    let value = self.eval(h, ctx, expr.arguments[0])?;
 
                    match ctx.fires(value.clone()) {
 
                        None => Err(EvalContinuation::BlockFires(value)),
 
                        Some(result) => Ok(result),
 
                    }
 
                }
 
                Method::Get => {
 
                    assert_eq!(1, expr.arguments.len());
 
                    let value = self.eval(h, ctx, expr.arguments[0])?;
 
                    match ctx.get(value.clone()) {
 
                        None => Err(EvalContinuation::BlockGet(value)),
 
                        Some(result) => Ok(result),
 
                    }
 
                }
 
                Method::Symbolic(symbol) => unimplemented!(),
 
            },
 
            Expression::Variable(expr) => self.get(h, ctx, expr.this.upcast()),
 
        }
 
    }
 
}
 

	
 
type EvalResult = Result<Value, EvalContinuation>;
 
pub enum EvalContinuation {
 
    Stepping,
 
    Inconsistent,
 
    Terminal,
 
    SyncBlockStart,
 
    SyncBlockEnd,
 
    NewComponent(DeclarationId, Vec<Value>),
 
    BlockFires(Value),
 
    BlockGet(Value),
 
    Put(Value, Value),
 
}
 

	
 
#[derive(Debug, Clone)]
 
pub struct Prompt {
 
    definition: DefinitionId,
 
    store: Store,
 
    position: Option<StatementId>,
 
}
 

	
 
impl Prompt {
 
    pub fn new(h: &Heap, def: DefinitionId, args: &Vec<Value>) -> Self {
 
        let mut prompt =
 
            Prompt { definition: def, store: Store::new(), position: Some((&h[def]).body()) };
 
        prompt.set_arguments(h, args);
 
        prompt
 
    }
 
    fn set_arguments(&mut self, h: &Heap, args: &Vec<Value>) {
 
        let def = &h[self.definition];
 
        let params = def.parameters();
 
        assert_eq!(params.len(), args.len());
 
        for (param, value) in params.iter().zip(args.iter()) {
 
            let hparam = &h[*param];
 
            let type_annot = &h[hparam.type_annotation];
 
            assert!(value.is_type_compatible(&type_annot.the_type));
 
            self.store.initialize(h, param.upcast(), value.clone());
 
        }
 
    }
 
    pub fn step(&mut self, h: &Heap, ctx: &mut EvalContext) -> EvalResult {
 
        if self.position.is_none() {
 
            return Err(EvalContinuation::Terminal);
 
        }
 
        let stmt = &h[self.position.unwrap()];
 
        match stmt {
 
            Statement::Block(stmt) => {
 
                // Continue to first statement
 
                self.position = Some(stmt.first());
 
                Err(EvalContinuation::Stepping)
 
            }
 
            Statement::Local(stmt) => {
 
                match stmt {
 
                    LocalStatement::Memory(stmt) => {
 
                        // Evaluate initial expression
 
                        let value = self.store.eval(h, ctx, stmt.initial)?;
 
                        // Update store
 
                        self.store.initialize(h, stmt.variable.upcast(), value);
 
                    }
 
                    LocalStatement::Channel(stmt) => {
 
                        let [from, to] = ctx.new_channel();
 
                        // Store the values in the declared variables
 
                        self.store.initialize(h, stmt.from.upcast(), from);
 
                        self.store.initialize(h, stmt.to.upcast(), to);
 
                    },
 
                }
 
                // Continue to next statement
 
                self.position = stmt.next();
 
                Err(EvalContinuation::Stepping)
 
            }
 
            Statement::Skip(stmt) => {
 
                // Continue to next statement
 
                self.position = stmt.next;
 
                Err(EvalContinuation::Stepping)
 
            }
 
            Statement::Labeled(stmt) => {
 
                // Continue to next statement
 
                self.position = Some(stmt.body);
 
                Err(EvalContinuation::Stepping)
 
            }
 
            Statement::If(stmt) => {
 
                // Evaluate test
 
                let value = self.store.eval(h, ctx, stmt.test)?;
 
                // Continue with either branch
 
                if value.as_boolean().0 {
 
                    self.position = Some(stmt.true_body);
 
                } else {
 
                    self.position = Some(stmt.false_body);
 
                }
 
                Err(EvalContinuation::Stepping)
 
            }
 
            Statement::EndIf(stmt) => {
 
                // Continue to next statement
 
                self.position = stmt.next;
 
                Err(EvalContinuation::Stepping)
 
            }
 
            Statement::While(stmt) => {
 
                // Evaluate test
 
                let value = self.store.eval(h, ctx, stmt.test)?;
 
                // Either continue with body, or go to next
 
                if value.as_boolean().0 {
 
                    self.position = Some(stmt.body);
 
                } else {
 
                    self.position = stmt.next.map(|x| x.upcast());
 
                }
 
                Err(EvalContinuation::Stepping)
 
            }
 
            Statement::EndWhile(stmt) => {
 
                // Continue to next statement
 
                self.position = stmt.next;
 
                Err(EvalContinuation::Stepping)
 
            }
 
            Statement::Synchronous(stmt) => {
 
                // Continue to next statement, and signal upward
 
                self.position = Some(stmt.body);
 
                Err(EvalContinuation::SyncBlockStart)
 
            }
 
            Statement::EndSynchronous(stmt) => {
 
                // Continue to next statement, and signal upward
 
                self.position = stmt.next;
 
                Err(EvalContinuation::SyncBlockEnd)
 
            }
 
            Statement::Break(stmt) => {
 
                // Continue to end of while
 
                self.position = stmt.target.map(EndWhileStatementId::upcast);
 
                Err(EvalContinuation::Stepping)
 
            }
 
            Statement::Continue(stmt) => {
 
                // Continue to beginning of while
 
                self.position = stmt.target.map(WhileStatementId::upcast);
 
                Err(EvalContinuation::Stepping)
src/test/connector.rs
Show inline comments
 
@@ -483,197 +483,197 @@ fn composite_chain_a() {
 
            for _ in 0..N {
 
                x.put(0, MSG.to_vec()).unwrap();
 
                assert_eq!(0, x.sync(timeout).unwrap());
 
            }
 
        },
 
        &|x| {
 
            // Bob
 
            x.configure(PDL, b"forward").unwrap();
 
            x.bind_port(0, Passive(addrs[0])).unwrap();
 
            x.bind_port(1, Native).unwrap();
 
            x.connect(timeout).unwrap();
 
            for _ in 0..N {
 
                // get msg round
 
                x.get(0).unwrap();
 
                assert_eq!(Ok(0), x.sync(timeout));
 
                assert_eq!(Ok(MSG), x.read_gotten(0));
 
            }
 
        },
 
    ]));
 
}
 

	
 
#[test]
 
fn composite_chain_b() {
 
    // Check if composition works. Forward messages through long chains
 
    /*
 
    Alice -->sync-->sync-->A|P-->sync-->sync--> Bob
 
    */
 
    let timeout = Duration::from_millis(1_500);
 
    let addrs = [next_addr(), next_addr()];
 
    const N: usize = 1;
 
    static MSG: &[u8] = b"SSS";
 
    assert!(run_connector_set(&[
 
        //
 
        &|x| {
 
            // Alice
 
            x.configure(PDL, b"sync_2").unwrap();
 
            x.bind_port(0, Native).unwrap();
 
            x.bind_port(1, Active(addrs[0])).unwrap();
 
            x.connect(timeout).unwrap();
 
            for _ in 0..N {
 
                x.put(0, MSG.to_vec()).unwrap();
 
                assert_eq!(0, x.sync(timeout).unwrap());
 
            }
 
        },
 
        &|x| {
 
            // Bob
 
            x.configure(PDL, b"sync_2").unwrap();
 
            x.bind_port(0, Passive(addrs[0])).unwrap();
 
            x.bind_port(1, Native).unwrap();
 
            x.connect(timeout).unwrap();
 
            for _ in 0..N {
 
                // get msg round
 
                x.get(0).unwrap();
 
                assert_eq!(Ok(0), x.sync(timeout));
 
                assert_eq!(Ok(MSG), x.read_gotten(0));
 
            }
 
        },
 
    ]));
 
}
 

	
 
#[test]
 
fn exchange() {
 
    /*
 
        /-->\      /-->P|A-->\      /-->\
 
    Alice   exchange         exchange   Bob
 
        \<--/      \<--P|A<--/      \<--/
 
    */
 
    let timeout = Duration::from_millis(1_500);
 
    let addrs = [next_addr(), next_addr()];
 
    const N: usize = 1;
 
    assert!(run_connector_set(&[
 
        //
 
        &|x| {
 
            // Alice
 
            x.configure(PDL, b"exchange").unwrap();
 
            x.bind_port(0, Native).unwrap(); // native in
 
            x.bind_port(1, Native).unwrap(); // native out
 
            x.bind_port(2, Passive(addrs[0])).unwrap(); // peer out
 
            x.bind_port(3, Passive(addrs[1])).unwrap(); // peer in
 
            x.connect(timeout).unwrap();
 
            for _ in 0..N {
 
                assert_eq!(Ok(()), x.put(0, b"A->B".to_vec()));
 
                assert_eq!(Ok(()), x.get(1));
 
                assert_eq!(Ok(0), x.sync(timeout));
 
                assert_eq!(Ok(b"B->A" as &[u8]), x.read_gotten(1));
 
            }
 
        },
 
        &|x| {
 
            // Bob
 
            x.configure(PDL, b"exchange").unwrap();
 
            x.bind_port(0, Native).unwrap(); // native in
 
            x.bind_port(1, Native).unwrap(); // native out
 
            x.bind_port(2, Active(addrs[1])).unwrap(); // peer out
 
            x.bind_port(3, Active(addrs[0])).unwrap(); // peer in
 
            x.connect(timeout).unwrap();
 
            for _ in 0..N {
 
                assert_eq!(Ok(()), x.put(0, b"B->A".to_vec()));
 
                assert_eq!(Ok(()), x.get(1));
 
                assert_eq!(Ok(0), x.sync(timeout));
 
                assert_eq!(Ok(b"A->B" as &[u8]), x.read_gotten(1));
 
            }
 
        },
 
    ]));
 
}
 

	
 
#[test]
 
fn routing_filter() {
 
    // Make a protocol whose behavior is a function of the contents of
 
    // a message. Here, the putter determines what is sent, and the proto
 
    // determines how it is routed
 
    /*
 
    Sender -->filter-->P|A-->sync--> Receiver
 
    */
 
    let timeout = Duration::from_millis(1_500);
 
    let addrs = [next_addr()];
 
    const N: usize = 10;
 
    assert!(run_connector_set(&[
 
        //
 
        &|x| {
 
            // Sender
 
            x.configure(PDL, b"filter").unwrap();
 
            x.bind_port(0, Native).unwrap();
 
            x.bind_port(1, Passive(addrs[0])).unwrap();
 
            x.bind_port(2, Native).unwrap(); // err channel
 
            x.connect(timeout).unwrap();
 

	
 
            for i in (0..3).cycle().take(N) {
 
                // messages cycle [], [4], [4,4], ...
 
                let msg: Payload = std::iter::repeat(4).take(i).collect();
 

	
 
                // batch 0: passes through filter!
 
                x.put(0, msg.clone()).unwrap();
 
                x.next_batch().unwrap();
 

	
 
                // batch 1: gets returned!
 
                x.put(0, msg.clone()).unwrap();
 
                x.get(1).unwrap();
 
                match x.sync(timeout).unwrap() {
 
                    0 => assert_ne!(msg.len(), 0), // ok
 
                    1 => assert_eq!(msg.len(), 0), // err
 
                    _ => unreachable!(),
 
                }
 
            }
 
        },
 
        &|x| {
 
            // Receiver
 
            x.configure(PDL, b"sync").unwrap();
 
            x.bind_port(0, Active(addrs[0])).unwrap();
 
            x.bind_port(1, Native).unwrap();
 
            x.connect(timeout).unwrap();
 
            for _ in 0..N {
 
                // empty batch
 
                x.next_batch().unwrap();
 

	
 
                // got a message
 
                x.get(0).unwrap();
 
                match x.sync(timeout).unwrap() {
 
                    0 => assert_eq!(Err(ReadGottenErr::DidNotGet), x.read_gotten(0)),
 
                    1 => assert_ne!(Ok(&[] as &[u8]), x.read_gotten(0)),
 
                    _ => unreachable!(),
 
                }
 
            }
 
        },
 
    ]));
 
}
 

	
 
#[test]
 
fn fifo_1_e() {
 
    /*
 
        /-->\
 
    Alice   fifo_1
 
        \<--/
 
    */
 
    let timeout = Duration::from_millis(1_500);
 
    const N: usize = 10;
 
    assert!(run_connector_set(&[
 
        //
 
        &|x| {
 
            // Alice
 
            x.configure(PDL, b"fifo_1_e").unwrap();
 
            x.bind_port(0, Native).unwrap();
 
            x.bind_port(1, Native).unwrap();
 
            x.connect(timeout).unwrap();
 

	
 
            for _ in 0..N {
 
                // put
 
                assert_eq!(Ok(()), x.put(0, b"message~".to_vec()));
 
                assert_eq!(Ok(0), x.sync(timeout));
 

	
 
                // get
 
                assert_eq!(Ok(()), x.get(1));
 
                assert_eq!(Ok(0), x.sync(timeout));
 
                assert_eq!(Ok(&[] as &[u8]), x.read_gotten(1));
 
                assert_eq!(Ok(b"message~" as &[u8]), x.read_gotten(1));
 
            }
 
        },
 
    ]));
 
}
testdata/eval/positive/10.pdl
Show inline comments
 
new file 100644
 
#version 100
 

	
 
composite main() {}
 

	
 
int test() {
 
	msg x = create(0);
 
	return x == null;
 
}
 
\ No newline at end of file
testdata/eval/positive/10.txt
Show inline comments
 
new file 100644
 
false
 
\ No newline at end of file
testdata/eval/positive/11.pdl
Show inline comments
 
new file 100644
 
#version 100
 

	
 
composite main() {}
 

	
 
int test() {
 
	msg x = create(0);
 
	return x.length == 0 && (x != null || (x[0] = 1) == 1);
 
}
 
\ No newline at end of file
testdata/eval/positive/11.txt
Show inline comments
 
new file 100644
 
true
 
\ No newline at end of file
0 comments (0 inline, 0 general)