Changeset - ac7f49602455
[Not reviewed]
0 3 6
Hans-Dieter Hiep - 5 years ago 2020-02-10 15:14:34
hdh@cwi.nl
Implements array access in evaluator
9 files changed with 175 insertions and 26 deletions:
0 comments (0 inline, 0 general)
src/protocol/eval.rs
Show inline comments
 
use std::collections::HashMap;
 
use std::fmt;
 
use std::fmt::{Debug, Display, Formatter};
 
use std::{i16, i32, i64, i8};
 

	
 
use crate::common::*;
 

	
 
use crate::protocol::ast::*;
 
use crate::protocol::inputsource::*;
 
use crate::protocol::parser::*;
 
use crate::protocol::EvalContext;
 

	
 
const MAX_RECURSION: usize = 1024;
 

	
 
const BYTE_MIN: i64 = i8::MIN as i64;
 
const BYTE_MAX: i64 = i8::MAX as i64;
 
const SHORT_MIN: i64 = i16::MIN as i64;
 
const SHORT_MAX: i64 = i16::MAX as i64;
 
const INT_MIN: i64 = i32::MIN as i64;
 
const INT_MAX: i64 = i32::MAX as i64;
 

	
 
const MESSAGE_MAX_LENGTH: i64 = SHORT_MAX;
 

	
 
const ONE: Value = Value::Byte(ByteValue(1));
 

	
 
trait ValueImpl {
 
    fn exact_type(&self) -> Type;
 
    fn is_type_compatible(&self, t: &Type) -> bool;
 
}
 

	
 
#[derive(Debug, Clone)]
 
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 {
 
                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)))
 
            }
 
            (PrimitiveType::Byte, PrimitiveType::Short) => {
 
                Value::Short(ShortValue(i16::from(self) + i16::from(other)))
 
            }
 
            (PrimitiveType::Byte, PrimitiveType::Int) => {
 
                Value::Int(IntValue(i32::from(self) + i32::from(other)))
 
            }
 
            (PrimitiveType::Byte, PrimitiveType::Long) => {
 
                Value::Long(LongValue(i64::from(self) + i64::from(other)))
 
            }
 
            (PrimitiveType::Short, PrimitiveType::Byte) => {
 
                Value::Short(ShortValue(i16::from(self) + i16::from(other)))
 
            }
 
            (PrimitiveType::Short, PrimitiveType::Short) => {
 
                Value::Short(ShortValue(i16::from(self) + i16::from(other)))
 
            }
 
            (PrimitiveType::Short, PrimitiveType::Int) => {
 
                Value::Int(IntValue(i32::from(self) + i32::from(other)))
 
            }
 
            (PrimitiveType::Short, PrimitiveType::Long) => {
 
                Value::Long(LongValue(i64::from(self) + i64::from(other)))
 
            }
 
            (PrimitiveType::Int, PrimitiveType::Byte) => {
 
                Value::Int(IntValue(i32::from(self) + i32::from(other)))
 
            }
 
            (PrimitiveType::Int, PrimitiveType::Short) => {
 
                Value::Int(IntValue(i32::from(self) + i32::from(other)))
 
            }
 
            (PrimitiveType::Int, PrimitiveType::Int) => {
 
                Value::Int(IntValue(i32::from(self) + i32::from(other)))
 
            }
 
            (PrimitiveType::Int, PrimitiveType::Long) => {
 
                Value::Long(LongValue(i64::from(self) + i64::from(other)))
 
            }
 
            (PrimitiveType::Long, PrimitiveType::Byte) => {
 
                Value::Long(LongValue(i64::from(self) + i64::from(other)))
 
            }
 
            (PrimitiveType::Long, PrimitiveType::Short) => {
 
                Value::Long(LongValue(i64::from(self) + i64::from(other)))
 
            }
 
            (PrimitiveType::Long, PrimitiveType::Int) => {
 
                Value::Long(LongValue(i64::from(self) + i64::from(other)))
 
            }
 
            (PrimitiveType::Long, PrimitiveType::Long) => {
 
                Value::Long(LongValue(i64::from(self) + i64::from(other)))
 
            }
 
            _ => 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)))
 
            }
 
            (PrimitiveType::Byte, PrimitiveType::Short) => {
 
                Value::Short(ShortValue(i16::from(self) - i16::from(other)))
 
            }
 
            (PrimitiveType::Byte, PrimitiveType::Int) => {
 
                Value::Int(IntValue(i32::from(self) - i32::from(other)))
 
            }
 
            (PrimitiveType::Byte, PrimitiveType::Long) => {
 
                Value::Long(LongValue(i64::from(self) - i64::from(other)))
 
            }
 
            (PrimitiveType::Short, PrimitiveType::Byte) => {
 
                Value::Short(ShortValue(i16::from(self) - i16::from(other)))
 
            }
 
            (PrimitiveType::Short, PrimitiveType::Short) => {
 
                Value::Short(ShortValue(i16::from(self) - i16::from(other)))
 
            }
 
            (PrimitiveType::Short, PrimitiveType::Int) => {
 
                Value::Int(IntValue(i32::from(self) - i32::from(other)))
 
            }
 
            (PrimitiveType::Short, PrimitiveType::Long) => {
 
                Value::Long(LongValue(i64::from(self) - i64::from(other)))
 
            }
 
            (PrimitiveType::Int, PrimitiveType::Byte) => {
 
                Value::Int(IntValue(i32::from(self) - i32::from(other)))
 
            }
 
            (PrimitiveType::Int, PrimitiveType::Short) => {
 
                Value::Int(IntValue(i32::from(self) - i32::from(other)))
 
            }
 
            (PrimitiveType::Int, PrimitiveType::Int) => {
 
                Value::Int(IntValue(i32::from(self) - i32::from(other)))
 
            }
 
            (PrimitiveType::Int, PrimitiveType::Long) => {
 
                Value::Long(LongValue(i64::from(self) - i64::from(other)))
 
            }
 
            (PrimitiveType::Long, PrimitiveType::Byte) => {
 
                Value::Long(LongValue(i64::from(self) - i64::from(other)))
 
            }
 
            (PrimitiveType::Long, PrimitiveType::Short) => {
 
                Value::Long(LongValue(i64::from(self) - i64::from(other)))
 
            }
 
            (PrimitiveType::Long, PrimitiveType::Int) => {
 
                Value::Long(LongValue(i64::from(self) - i64::from(other)))
 
            }
 
            (PrimitiveType::Long, PrimitiveType::Long) => {
 
                Value::Long(LongValue(i64::from(self) - i64::from(other)))
 
            }
 
            _ => 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)))
 
            }
 
            (PrimitiveType::Byte, PrimitiveType::Short) => {
 
                Value::Short(ShortValue(i16::from(self) % i16::from(other)))
 
            }
 
            (PrimitiveType::Byte, PrimitiveType::Int) => {
 
                Value::Int(IntValue(i32::from(self) % i32::from(other)))
 
            }
 
            (PrimitiveType::Byte, PrimitiveType::Long) => {
 
                Value::Long(LongValue(i64::from(self) % i64::from(other)))
 
            }
 
            (PrimitiveType::Short, PrimitiveType::Byte) => {
 
                Value::Short(ShortValue(i16::from(self) % i16::from(other)))
 
            }
 
            (PrimitiveType::Short, PrimitiveType::Short) => {
 
                Value::Short(ShortValue(i16::from(self) % i16::from(other)))
 
            }
 
            (PrimitiveType::Short, PrimitiveType::Int) => {
 
                Value::Int(IntValue(i32::from(self) % i32::from(other)))
 
            }
 
            (PrimitiveType::Short, PrimitiveType::Long) => {
 
                Value::Long(LongValue(i64::from(self) % i64::from(other)))
 
            }
 
            (PrimitiveType::Int, PrimitiveType::Byte) => {
 
                Value::Int(IntValue(i32::from(self) % i32::from(other)))
 
            }
 
            (PrimitiveType::Int, PrimitiveType::Short) => {
 
                Value::Int(IntValue(i32::from(self) % i32::from(other)))
 
            }
 
            (PrimitiveType::Int, PrimitiveType::Int) => {
 
                Value::Int(IntValue(i32::from(self) % i32::from(other)))
 
            }
 
            (PrimitiveType::Int, PrimitiveType::Long) => {
 
                Value::Long(LongValue(i64::from(self) % i64::from(other)))
 
            }
 
            (PrimitiveType::Long, PrimitiveType::Byte) => {
 
                Value::Long(LongValue(i64::from(self) % i64::from(other)))
 
            }
 
            (PrimitiveType::Long, PrimitiveType::Short) => {
 
                Value::Long(LongValue(i64::from(self) % i64::from(other)))
 
            }
 
            (PrimitiveType::Long, PrimitiveType::Int) => {
 
                Value::Long(LongValue(i64::from(self) % i64::from(other)))
 
            }
 
            (PrimitiveType::Long, PrimitiveType::Long) => {
 
                Value::Long(LongValue(i64::from(self) % i64::from(other)))
 
            }
 
            _ => 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)))
 
            }
 
            (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 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)))
 
            }
 
            (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 lt(&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 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)))
 
            }
 
            (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 as_boolean(&self) -> &BooleanValue {
 
        match self {
 
            Value::Boolean(result) => result,
 
            _ => panic!("Unable to cast `Value` to `BooleanValue`"),
 
        }
 
    }
 
}
 

	
 
impl From<bool> for Value {
 
    fn from(b: bool) -> Self {
 
        Value::Boolean(BooleanValue(b))
 
    }
 
}
 
impl From<Value> for bool {
 
    fn from(val: Value) -> Self {
 
        match val {
 
            Value::Boolean(BooleanValue(b)) => b,
 
            _ => unimplemented!(),
 
        }
 
    }
 
}
 
impl From<&Value> for bool {
 
    fn from(val: &Value) -> Self {
 
        match val {
 
            Value::Boolean(BooleanValue(b)) => *b,
 
            _ => unimplemented!(),
 
        }
 
    }
 
}
 

	
 
impl From<Value> for i8 {
 
    fn from(val: Value) -> Self {
 
        match val {
 
            Value::Byte(ByteValue(b)) => b,
 
            _ => unimplemented!(),
 
        }
 
    }
 
}
 
impl From<&Value> for i8 {
 
    fn from(val: &Value) -> Self {
 
        match val {
 
            Value::Byte(ByteValue(b)) => *b,
 
            _ => unimplemented!(),
 
        }
 
    }
 
}
 

	
 
impl From<Value> for i16 {
 
    fn from(val: Value) -> Self {
 
        match val {
 
            Value::Byte(ByteValue(b)) => i16::from(b),
 
            Value::Short(ShortValue(s)) => s,
 
            _ => unimplemented!(),
 
        }
 
    }
 
}
 
impl From<&Value> for i16 {
 
    fn from(val: &Value) -> Self {
 
        match val {
 
            Value::Byte(ByteValue(b)) => i16::from(*b),
 
            Value::Short(ShortValue(s)) => *s,
 
            _ => unimplemented!(),
 
        }
 
    }
 
}
 

	
 
impl From<Value> for i32 {
 
    fn from(val: Value) -> Self {
 
        match val {
 
            Value::Byte(ByteValue(b)) => i32::from(b),
 
            Value::Short(ShortValue(s)) => i32::from(s),
 
            Value::Int(IntValue(i)) => i,
 
            _ => unimplemented!(),
 
        }
 
    }
 
}
 
impl From<&Value> for i32 {
 
    fn from(val: &Value) -> Self {
 
        match val {
 
            Value::Byte(ByteValue(b)) => i32::from(*b),
 
            Value::Short(ShortValue(s)) => i32::from(*s),
 
            Value::Int(IntValue(i)) => *i,
 
            _ => unimplemented!(),
 
        }
 
    }
 
}
 

	
 
impl From<Value> for i64 {
 
    fn from(val: Value) -> Self {
 
        match val {
 
            Value::Byte(ByteValue(b)) => i64::from(b),
 
            Value::Short(ShortValue(s)) => i64::from(s),
 
            Value::Int(IntValue(i)) => i64::from(i),
 
            Value::Long(LongValue(l)) => l,
 
            _ => unimplemented!(),
 
        }
 
    }
 
}
 
impl From<&Value> for i64 {
 
    fn from(val: &Value) -> Self {
 
        match val {
 
            Value::Byte(ByteValue(b)) => i64::from(*b),
 
            Value::Short(ShortValue(s)) => i64::from(*s),
 
            Value::Int(IntValue(i)) => i64::from(*i),
 
            Value::Long(LongValue(l)) => *l,
 
            _ => unimplemented!(),
 
        }
 
    }
 
}
 

	
 
impl ValueImpl for Value {
 
    fn exact_type(&self) -> Type {
 
        match self {
 
            Value::Input(val) => val.exact_type(),
 
            Value::Output(val) => val.exact_type(),
 
            Value::Message(val) => val.exact_type(),
 
            Value::Boolean(val) => val.exact_type(),
 
            Value::Byte(val) => val.exact_type(),
 
            Value::Short(val) => val.exact_type(),
 
            Value::Int(val) => val.exact_type(),
 
            Value::Long(val) => val.exact_type(),
 
            Value::InputArray(val) => val.exact_type(),
 
            Value::OutputArray(val) => val.exact_type(),
 
            Value::MessageArray(val) => val.exact_type(),
 
            Value::BooleanArray(val) => val.exact_type(),
 
            Value::ByteArray(val) => val.exact_type(),
 
            Value::ShortArray(val) => val.exact_type(),
 
            Value::IntArray(val) => val.exact_type(),
 
            Value::LongArray(val) => val.exact_type(),
 
        }
 
    }
 
    fn is_type_compatible(&self, t: &Type) -> bool {
 
        match self {
 
            Value::Input(val) => val.is_type_compatible(t),
 
            Value::Output(val) => val.is_type_compatible(t),
 
            Value::Message(val) => val.is_type_compatible(t),
 
            Value::Boolean(val) => val.is_type_compatible(t),
 
            Value::Byte(val) => val.is_type_compatible(t),
 
            Value::Short(val) => val.is_type_compatible(t),
 
            Value::Int(val) => val.is_type_compatible(t),
 
            Value::Long(val) => val.is_type_compatible(t),
 
            Value::InputArray(val) => val.is_type_compatible(t),
 
            Value::OutputArray(val) => val.is_type_compatible(t),
 
            Value::MessageArray(val) => val.is_type_compatible(t),
 
            Value::BooleanArray(val) => val.is_type_compatible(t),
 
            Value::ByteArray(val) => val.is_type_compatible(t),
 
            Value::ShortArray(val) => val.is_type_compatible(t),
 
            Value::IntArray(val) => val.is_type_compatible(t),
 
            Value::LongArray(val) => val.is_type_compatible(t),
 
        }
 
    }
 
}
 

	
 
impl Display for Value {
 
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
 
        let disp: &dyn Display;
 
        match self {
 
            Value::Input(val) => disp = val,
 
            Value::Output(val) => disp = val,
 
            Value::Message(val) => disp = val,
 
            Value::Boolean(val) => disp = val,
 
            Value::Byte(val) => disp = val,
 
            Value::Short(val) => disp = val,
 
            Value::Int(val) => disp = val,
 
            Value::Long(val) => disp = val,
 
            Value::InputArray(val) => disp = val,
 
            Value::OutputArray(val) => disp = val,
 
            Value::MessageArray(val) => disp = val,
 
            Value::BooleanArray(val) => disp = val,
 
            Value::ByteArray(val) => disp = val,
 
            Value::ShortArray(val) => disp = val,
 
            Value::IntArray(val) => disp = val,
 
            Value::LongArray(val) => disp = val,
 
        }
 
        disp.fmt(f)
 
    }
 
}
 

	
 
#[derive(Debug, Clone)]
 
pub struct InputValue(pub Key);
 

	
 
impl Display for InputValue {
 
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
 
        write!(f, "#in")
 
    }
 
}
 

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

	
 
#[derive(Debug, Clone)]
 
pub struct OutputValue(pub Key);
 

	
 
impl Display for OutputValue {
 
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
 
        write!(f, "#out")
 
    }
 
}
 

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

	
 
#[derive(Debug, Clone)]
 
pub struct MessageValue(pub Option<Vec<u8>>);
 

	
 
impl Display for MessageValue {
 
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
 
        match &self.0 {
 
            None => write!(f, "null"),
 
            Some(vec) => {
 
                write!(f, "#msg({};", vec.len())?;
 
                let mut i = 0;
 
                for v in vec.iter() {
 
                    if i > 0 {
 
                        write!(f, ",")?;
 
                    }
 
                    write!(f, "{}", v)?;
 
                    i += 1;
 
                    if i >= 10 {
 
                        write!(f, ",...")?;
 
                        break;
 
                    }
 
                }
 
                write!(f, ")")
 
            }
 
        }
 
    }
 
}
 

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

	
 
#[derive(Debug, Clone)]
 
pub struct BooleanValue(bool);
 

	
 
impl Display for BooleanValue {
 
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
 
        write!(f, "{}", self.0)
 
    }
 
}
 

	
 
impl ValueImpl for BooleanValue {
 
    fn exact_type(&self) -> Type {
 
        Type::BOOLEAN
 
    }
 
    fn is_type_compatible(&self, t: &Type) -> bool {
 
        let Type { primitive, array } = t;
 
        if *array {
 
            return false;
 
        }
 
        match primitive {
 
            PrimitiveType::Boolean => true,
 
            PrimitiveType::Byte => true,
 
            PrimitiveType::Short => true,
 
            PrimitiveType::Int => true,
 
            PrimitiveType::Long => true,
 
            _ => false,
 
        }
 
    }
 
}
 

	
 
#[derive(Debug, Clone)]
 
pub struct ByteValue(i8);
 

	
 
impl Display for ByteValue {
 
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
 
        write!(f, "{}", self.0)
 
    }
 
}
 

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

	
 
#[derive(Debug, Clone)]
 
pub struct ShortValue(i16);
 

	
 
impl Display for ShortValue {
 
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
 
        write!(f, "{}", self.0)
 
    }
 
}
 

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

	
 
#[derive(Debug, Clone)]
 
pub struct IntValue(i32);
 

	
 
impl Display for IntValue {
 
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
 
        write!(f, "{}", self.0)
 
    }
 
}
 

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

	
 
#[derive(Debug, Clone)]
 
pub struct LongValue(i64);
 

	
 
impl Display for LongValue {
 
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
 
        write!(f, "{}", self.0)
 
    }
 
}
 

	
 
impl ValueImpl for LongValue {
 
    fn exact_type(&self) -> Type {
 
        Type::LONG
 
    }
 
    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)]
 
pub struct InputArrayValue(Vec<InputValue>);
 

	
 
impl Display for InputArrayValue {
 
    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 InputArrayValue {
 
    fn exact_type(&self) -> Type {
 
        Type::INPUT_ARRAY
 
    }
 
    fn is_type_compatible(&self, t: &Type) -> bool {
 
        let Type { primitive, array } = t;
 
        if !*array {
 
            return false;
 
        }
 
        match primitive {
 
            PrimitiveType::Input => true,
 
            _ => false,
 
        }
 
    }
 
}
 

	
 
#[derive(Debug, Clone)]
 
pub struct OutputArrayValue(Vec<OutputValue>);
 

	
 
impl Display for OutputArrayValue {
 
    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 OutputArrayValue {
 
    fn exact_type(&self) -> Type {
 
        Type::OUTPUT_ARRAY
 
    }
 
    fn is_type_compatible(&self, t: &Type) -> bool {
 
        let Type { primitive, array } = t;
 
        if !*array {
 
            return false;
 
        }
 
        match primitive {
 
            PrimitiveType::Output => true,
 
            _ => false,
 
        }
 
    }
 
}
 

	
 
#[derive(Debug, Clone)]
 
pub struct MessageArrayValue(Vec<MessageValue>);
 

	
 
impl Display for MessageArrayValue {
 
    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 MessageArrayValue {
 
    fn exact_type(&self) -> Type {
 
        Type::MESSAGE_ARRAY
 
    }
 
    fn is_type_compatible(&self, t: &Type) -> bool {
 
        let Type { primitive, array } = t;
 
        if !*array {
 
            return false;
 
        }
 
        match primitive {
 
            PrimitiveType::Message => true,
 
            _ => false,
 
        }
 
    }
 
}
 

	
 
#[derive(Debug, Clone)]
 
pub struct BooleanArrayValue(Vec<BooleanValue>);
 

	
 
impl Display for BooleanArrayValue {
 
    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 BooleanArrayValue {
 
    fn exact_type(&self) -> Type {
 
        Type::BOOLEAN_ARRAY
 
    }
 
    fn is_type_compatible(&self, t: &Type) -> bool {
 
        let Type { primitive, array } = t;
 
        if !*array {
 
            return false;
 
        }
 
        match primitive {
 
            PrimitiveType::Boolean => true,
 
            _ => false,
 
        }
 
    }
 
}
 

	
 
#[derive(Debug, Clone)]
 
pub struct ByteArrayValue(Vec<ByteValue>);
 

	
 
impl Display for ByteArrayValue {
 
    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 ByteArrayValue {
 
    fn exact_type(&self) -> Type {
 
        Type::BYTE_ARRAY
 
    }
 
    fn is_type_compatible(&self, t: &Type) -> bool {
 
        let Type { primitive, array } = t;
 
        if !*array {
 
            return false;
 
        }
 
        match primitive {
 
            PrimitiveType::Byte => true,
 
            _ => false,
 
        }
 
    }
 
}
 

	
 
#[derive(Debug, Clone)]
 
pub struct ShortArrayValue(Vec<ShortValue>);
 

	
 
impl Display for ShortArrayValue {
 
    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 ShortArrayValue {
 
    fn exact_type(&self) -> Type {
 
        Type::SHORT_ARRAY
 
    }
 
    fn is_type_compatible(&self, t: &Type) -> bool {
 
        let Type { primitive, array } = t;
 
        if !*array {
 
            return false;
 
        }
 
        match primitive {
 
            PrimitiveType::Short => true,
 
            _ => false,
 
        }
 
    }
 
}
 

	
 
#[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, rexpr: ExpressionId) -> EvalResult {
 
    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());
 
                        self.update(h, ctx, expr.left, value.clone())?;
 
                    }
 
                    AssignmentOperator::Added => {
 
                        let old = self.get(h, expr.left)?;
 
                        self.update(h, ctx, expr.left, old.plus(&value));
 
                        let old = self.get(h, ctx, expr.left)?;
 
                        self.update(h, ctx, expr.left, old.plus(&value))?;
 
                    }
 
                    AssignmentOperator::Subtracted => {
 
                        let old = self.get(h, expr.left)?;
 
                        self.update(h, ctx, expr.left, old.minus(&value));
 
                        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)?;
 
                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!(),
 
                }
 
            }
 
            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));
 
                        self.update(h, ctx, expr.expression, value.plus(&ONE))?;
 
                    }
 
                    UnaryOperation::PreIncrement => {
 
                        value = value.plus(&ONE);
 
                        self.update(h, ctx, expr.expression, value.clone());
 
                        self.update(h, ctx, expr.expression, value.clone())?;
 
                    }
 
                    UnaryOperation::PostDecrement => {
 
                        self.update(h, ctx, expr.expression, value.minus(&ONE));
 
                        self.update(h, ctx, expr.expression, value.minus(&ONE))?;
 
                    }
 
                    UnaryOperation::PreDecrement => {
 
                        value = value.minus(&ONE);
 
                        self.update(h, ctx, expr.expression, value.clone());
 
                        self.update(h, ctx, expr.expression, value.clone())?;
 
                    }
 
                    _ => unimplemented!(),
 
                }
 
                Ok(value)
 
            }
 
            Expression::Indexing(expr) => self.get(h, expr.this.upcast()),
 
            Expression::Indexing(expr) => self.get(h, ctx, expr.this.upcast()),
 
            Expression::Slicing(expr) => unimplemented!(),
 
            Expression::Select(expr) => self.get(h, expr.this.upcast()),
 
            Expression::Array(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, expr.this.upcast()),
 
            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)
 
            }
 
            Statement::Assert(stmt) => {
 
                // Evaluate expression
 
                let value = self.store.eval(h, ctx, stmt.expression)?;
 
                if value.as_boolean().0 {
 
                    // Continue to next statement
 
                    self.position = stmt.next;
 
                    Err(EvalContinuation::Stepping)
 
                } else {
 
                    // Assertion failed: inconsistent
 
                    Err(EvalContinuation::Inconsistent)
 
                }
 
            }
 
            Statement::Return(stmt) => {
 
                // Evaluate expression
 
                let value = self.store.eval(h, ctx, stmt.expression)?;
 
                // Done with evaluation
 
                Ok(value)
 
            }
 
            Statement::Goto(stmt) => {
 
                // Continue to target
 
                self.position = stmt.target.map(|x| x.upcast());
 
                Err(EvalContinuation::Stepping)
 
            }
 
            Statement::New(stmt) => {
 
                let expr = &h[stmt.expression];
 
                let mut args = Vec::new();
 
                for &arg in expr.arguments.iter() {
 
                    let value = self.store.eval(h, ctx, arg)?;
 
                    args.push(value);
 
                }
 
                self.position = stmt.next;
 
                Err(EvalContinuation::NewComponent(expr.declaration.unwrap(), args))
 
            }
 
            Statement::Put(stmt) => {
 
                // Evaluate port and message
 
                let port = self.store.eval(h, ctx, stmt.port)?;
 
                let message = self.store.eval(h, ctx, stmt.message)?;
 
                // Continue to next statement
 
                self.position = stmt.next;
 
                // Signal the put upwards
 
                Err(EvalContinuation::Put(port, message))
 
            }
 
            Statement::Expression(stmt) => {
 
                // Evaluate expression
 
                let value = self.store.eval(h, ctx, stmt.expression)?;
 
                // Continue to next statement
 
                self.position = stmt.next;
 
                Err(EvalContinuation::Stepping)
 
            }
 
        }
 
    }
 
    fn compute_function(h: &Heap, fun: FunctionId, args: &Vec<Value>) -> Option<Value> {
 
        let mut prompt = Self::new(h, fun.upcast(), args);
 
        let mut context = EvalContext::None;
 
        loop {
 
            let result = prompt.step(h, &mut context);
 
            match result {
 
                Ok(val) => return Some(val),
 
                Err(cont) => match cont {
 
                    EvalContinuation::Stepping => continue,
 
                    EvalContinuation::Inconsistent => return None,
 
                    // Functions never terminate without returning
 
                    EvalContinuation::Terminal => unreachable!(),
 
                    // Functions never encounter any blocking behavior
 
                    EvalContinuation::SyncBlockStart => unreachable!(),
 
                    EvalContinuation::SyncBlockEnd => unreachable!(),
 
                    EvalContinuation::NewComponent(_, _) => unreachable!(),
 
                    EvalContinuation::BlockFires(val) => unreachable!(),
 
                    EvalContinuation::BlockGet(val) => unreachable!(),
 
                    EvalContinuation::Put(port, msg) => unreachable!(),
 
                },
 
            }
 
        }
 
    }
 
}
 

	
 
#[cfg(test)]
 
mod tests {
 
    extern crate test_generator;
 

	
 
    use std::fs::File;
 
    use std::io::Read;
 
    use std::path::Path;
 
    use test_generator::test_resources;
 

	
 
    use super::*;
 

	
 
    #[test_resources("testdata/eval/positive/*.pdl")]
 
    fn batch1(resource: &str) {
 
        let path = Path::new(resource);
 
        let expect = path.with_extension("txt");
 
        let mut heap = Heap::new();
 
        let mut source = InputSource::from_file(&path).unwrap();
 
        let mut parser = Parser::new(&mut source);
 
        let pd = parser.parse(&mut heap).unwrap();
 
        let def = heap[pd].get_definition_ident(&heap, b"test").unwrap();
 
        let fun = heap[def].as_function().this;
 
        let args = Vec::new();
 
        let result = Prompt::compute_function(&heap, fun, &args).unwrap();
 
        let valstr: String = format!("{}", result);
 
        println!("{}", valstr);
 

	
 
        let mut cev: Vec<u8> = Vec::new();
 
        let mut f = File::open(expect).unwrap();
 
        f.read_to_end(&mut cev).unwrap();
 
        let lavstr = String::from_utf8_lossy(&cev);
 
        println!("{}", lavstr);
 

	
 
        assert_eq!(valstr, lavstr);
 
    }
 
}
src/protocol/mod.rs
Show inline comments
 
mod ast;
 
mod eval;
 
pub mod inputsource;
 
mod lexer;
 
mod library;
 
mod parser;
 

	
 
use crate::common::*;
 
use crate::protocol::ast::*;
 
use crate::protocol::eval::*;
 
use crate::protocol::inputsource::*;
 
use crate::protocol::parser::*;
 
use std::hint::unreachable_unchecked;
 

	
 
pub struct ProtocolDescriptionImpl {
 
    heap: Heap,
 
    source: InputSource,
 
    root: RootId,
 
}
 

	
 
impl std::fmt::Debug for ProtocolDescriptionImpl {
 
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
 
        write!(f, "Protocol")
 
    }
 
}
 

	
 
impl ProtocolDescription for ProtocolDescriptionImpl {
 
    type S = ComponentStateImpl;
 

	
 
    fn parse(buffer: &[u8]) -> Result<Self, String> {
 
        let mut heap = Heap::new();
 
        let mut source = InputSource::from_buffer(buffer).unwrap();
 
        let mut parser = Parser::new(&mut source);
 
        match parser.parse(&mut heap) {
 
            Ok(root) => {
 
                return Ok(ProtocolDescriptionImpl { heap, source, root });
 
            }
 
            Err(err) => {
 
                let mut vec: Vec<u8> = Vec::new();
 
                err.write(&source, &mut vec).unwrap();
 
                Err(String::from_utf8_lossy(&vec).to_string())
 
            }
 
        }
 
    }
 
    fn component_polarities(&self, identifier: &[u8]) -> Result<Vec<Polarity>, MainComponentErr> {
 
        let h = &self.heap;
 
        let root = &h[self.root];
 
        let def = root.get_definition_ident(h, identifier);
 
        if def.is_none() {
 
            return Err(MainComponentErr::NoSuchComponent);
 
        }
 
        let def = &h[def.unwrap()];
 
        if !def.is_component() {
 
            return Err(MainComponentErr::NoSuchComponent);
 
        }
 
        for &param in def.parameters().iter() {
 
            let param = &h[param];
 
            let type_annot = &h[param.type_annotation];
 
            if type_annot.the_type.array {
 
                return Err(MainComponentErr::NonPortTypeParameters);
 
            }
 
            match type_annot.the_type.primitive {
 
                PrimitiveType::Input | PrimitiveType::Output => continue,
 
                _ => {
 
                    return Err(MainComponentErr::NonPortTypeParameters);
 
                }
 
            }
 
        }
 
        let mut result = Vec::new();
 
        for &param in def.parameters().iter() {
 
            let param = &h[param];
 
            let type_annot = &h[param.type_annotation];
 
            let ptype = &type_annot.the_type.primitive;
 
            if ptype == &PrimitiveType::Input {
 
                result.push(Polarity::Getter)
 
            } else if ptype == &PrimitiveType::Output {
 
                result.push(Polarity::Putter)
 
            } else {
 
                unreachable!()
 
            }
 
        }
 
        Ok(result)
 
    }
 
    fn new_main_component(&self, identifier: &[u8], ports: &[Key]) -> ComponentStateImpl {
 
        let mut args = Vec::new();
 
        for (&x, y) in ports.iter().zip(self.component_polarities(identifier).unwrap()) {
 
            match y {
 
                Polarity::Getter => args.push(Value::Input(InputValue(x))),
 
                Polarity::Putter => args.push(Value::Output(OutputValue(x))),
 
            }
 
        }
 
        let h = &self.heap;
 
        let root = &h[self.root];
 
        let def = root.get_definition_ident(h, identifier).unwrap();
 
        ComponentStateImpl { prompt: Prompt::new(h, def, &args) }
 
    }
 
}
 

	
 
#[derive(Debug, Clone)]
 
pub struct ComponentStateImpl {
 
    prompt: Prompt,
 
}
 
impl ComponentState for ComponentStateImpl {
 
    type D = ProtocolDescriptionImpl;
 

	
 
    fn pre_sync_run<C: MonoContext<D = ProtocolDescriptionImpl, S = Self>>(
 
        &mut self,
 
        context: &mut C,
 
        pd: &ProtocolDescriptionImpl,
 
    ) -> MonoBlocker {
 
        let mut context = EvalContext::Mono(context);
 
        loop {
 
            let result = self.prompt.step(&pd.heap, &mut context);
 
            match result {
 
                // In component definitions, there are no return statements
 
                Ok(_) => unreachable!(),
 
                Err(cont) => match cont {
 
                    EvalContinuation::Stepping => continue,
 
                    EvalContinuation::Inconsistent => return MonoBlocker::Inconsistent,
 
                    EvalContinuation::Terminal => return MonoBlocker::ComponentExit,
 
                    EvalContinuation::SyncBlockStart => return MonoBlocker::SyncBlockStart,
 
                    // Not possible to end sync block if never entered one
 
                    EvalContinuation::SyncBlockEnd => unreachable!(),
 
                    EvalContinuation::NewComponent(decl, args) => {
 
                        // Look up definition (TODO for now, assume it is a definition)
 
                        let h = &pd.heap;
 
                        let def = h[decl].as_defined().definition;
 
                        println!("Create component: {}",  String::from_utf8_lossy(h[h[def].identifier()].ident()));
 
                        let init_state = ComponentStateImpl { prompt: Prompt::new(h, def, &args) };
 
                        context.new_component(&args, init_state);
 
                        // Continue stepping
 
                        continue;
 
                    }
 
                    // Outside synchronous blocks, no fires/get/put happens
 
                    EvalContinuation::BlockFires(val) => unreachable!(),
 
                    EvalContinuation::BlockGet(val) => unreachable!(),
 
                    EvalContinuation::Put(port, msg) => unreachable!(),
 
                    EvalContinuation::BlockFires(_) => unreachable!(),
 
                    EvalContinuation::BlockGet(_) => unreachable!(),
 
                    EvalContinuation::Put(_, _) => unreachable!(),
 
                },
 
            }
 
        }
 
    }
 

	
 
    fn sync_run<C: PolyContext<D = ProtocolDescriptionImpl>>(
 
        &mut self,
 
        context: &mut C,
 
        pd: &ProtocolDescriptionImpl,
 
    ) -> PolyBlocker {
 
        let mut context = EvalContext::Poly(context);
 
        loop {
 
            let result = self.prompt.step(&pd.heap, &mut context);
 
            match result {
 
                // Inside synchronous blocks, there are no return statements
 
                Ok(_) => unreachable!(),
 
                Err(cont) => match cont {
 
                    EvalContinuation::Stepping => continue,
 
                    EvalContinuation::Inconsistent => return PolyBlocker::Inconsistent,
 
                    // First need to exit synchronous block before definition may end
 
                    EvalContinuation::Terminal => unreachable!(),
 
                    // No nested synchronous blocks
 
                    EvalContinuation::SyncBlockStart => unreachable!(),
 
                    EvalContinuation::SyncBlockEnd => return PolyBlocker::SyncBlockEnd,
 
                    // Not possible to create component in sync block
 
                    EvalContinuation::NewComponent(_, _) => unreachable!(),
 
                    EvalContinuation::BlockFires(port) => match port {
 
                        Value::Output(OutputValue(key)) => {
 
                            return PolyBlocker::CouldntCheckFiring(key);
 
                        }
 
                        Value::Input(InputValue(key)) => {
 
                            return PolyBlocker::CouldntCheckFiring(key);
 
                        }
 
                        _ => unreachable!(),
 
                    },
 
                    EvalContinuation::BlockGet(port) => match port {
 
                        Value::Output(OutputValue(key)) => {
 
                            return PolyBlocker::CouldntReadMsg(key);
 
                        }
 
                        Value::Input(InputValue(key)) => {
 
                            return PolyBlocker::CouldntReadMsg(key);
 
                        }
 
                        _ => unreachable!(),
 
                    },
 
                    EvalContinuation::Put(port, message) => {
 
                        let key;
 
                        match port {
 
                            Value::Output(OutputValue(the_key)) => {
 
                                key = the_key;
 
                            }
 
                            Value::Input(InputValue(the_key)) => {
 
                                key = the_key;
 
                            }
 
                            _ => unreachable!(),
 
                        }
 
                        let payload;
 
                        match message {
 
                            Value::Message(MessageValue(None)) => {
 
                                // Putting a null message is inconsistent
 
                                return PolyBlocker::Inconsistent;
 
                            }
 
                            Value::Message(MessageValue(Some(buffer))) => {
 
                                // Create a copy of the payload
 
                                payload = buffer.clone();
 
                            }
 
                            _ => unreachable!(),
 
                        }
 
                        return PolyBlocker::PutMsg(key, payload);
 
                    }
 
                },
 
            }
 
        }
 
    }
 
}
 

	
 
pub enum EvalContext<'a> {
 
    Mono(&'a mut dyn MonoContext<D = ProtocolDescriptionImpl, S = ComponentStateImpl>),
 
    Poly(&'a mut dyn PolyContext<D = ProtocolDescriptionImpl>),
 
    None,
 
}
 
impl EvalContext<'_> {
 
    fn random(&mut self) -> LongValue {
 
        match self {
 
            EvalContext::None => unreachable!(),
 
            EvalContext::Mono(context) => todo!(),
 
            EvalContext::Poly(_) => unreachable!(),
 
        }
 
    }
 
    fn new_component(&mut self, args: &[Value], init_state: ComponentStateImpl) -> () {
 
        match self {
 
            EvalContext::None => unreachable!(),
 
            EvalContext::Mono(context) => {
 
                let mut moved_keys = HashSet::new();
 
                for arg in args.iter() {
 
                    match arg {
 
                        Value::Output(OutputValue(key)) => { moved_keys.insert(*key); }
 
                        Value::Input(InputValue(key)) => { moved_keys.insert(*key); }
 
                        _ => {}
 
                    }
 
                }
 
                context.new_component(moved_keys, init_state)
 
            }
 
            EvalContext::Poly(_) => unreachable!(),
 
        }
 
    }
 
    fn new_channel(&mut self) -> [Value; 2] {
 
        match self {
 
            EvalContext::None => unreachable!(),
 
            EvalContext::Mono(context) => {
 
                let [from, to] = context.new_channel();
 
                let from = Value::Output(OutputValue(from));
 
                let to = Value::Input(InputValue(to));
 
                return [from, to];
 
            }
 
            EvalContext::Poly(_) => unreachable!()
 
        }
 
    }
 
    fn fires(&mut self, port: Value) -> Option<Value> {
 
        match self {
 
            EvalContext::None => unreachable!(),
 
            EvalContext::Mono(_) => unreachable!(),
 
            EvalContext::Poly(context) => match port {
 
                Value::Output(OutputValue(key)) => context.is_firing(key).map(Value::from),
 
                Value::Input(InputValue(key)) => context.is_firing(key).map(Value::from),
 
                _ => unreachable!(),
 
            },
 
        }
 
    }
 
    fn get(&mut self, port: Value) -> Option<Value> {
 
        match self {
 
            EvalContext::None => unreachable!(),
 
            EvalContext::Mono(_) => unreachable!(),
 
            EvalContext::Poly(context) => match port {
 
                Value::Output(OutputValue(key)) => {
 
                    context.read_msg(key).map(Value::receive_message)
 
                }
 
                Value::Input(InputValue(key)) => context.read_msg(key).map(Value::receive_message),
 
                _ => unreachable!(),
 
            },
 
        }
 
    }
 
}
src/protocol/parser.rs
Show inline comments
 
@@ -861,1026 +861,1023 @@ impl Visitor for LinkCallExpressions {
 
    fn visit_call_expression(&mut self, h: &mut Heap, expr: CallExpressionId) -> VisitorResult {
 
        if let Method::Symbolic(id) = h[expr].method {
 
            let decl = self.get_declaration(h, id)?;
 
            if self.new_statement && h[decl].is_function() {
 
                return Err(ParseError::new(h[id].position, "Illegal call expression"));
 
            }
 
            if !self.new_statement && h[decl].is_component() {
 
                return Err(ParseError::new(h[id].position, "Illegal call expression"));
 
            }
 
            // Set the corresponding declaration of the call
 
            h[expr].declaration = Some(decl);
 
        }
 
        // A new statement's call expression may have as arguments function calls
 
        let old = self.new_statement;
 
        self.new_statement = false;
 
        recursive_call_expression(self, h, expr)?;
 
        self.new_statement = old;
 
        Ok(())
 
    }
 
}
 

	
 
struct BuildScope {
 
    scope: Option<Scope>,
 
}
 

	
 
impl BuildScope {
 
    fn new() -> Self {
 
        BuildScope { scope: None }
 
    }
 
}
 

	
 
impl Visitor for BuildScope {
 
    fn visit_symbol_definition(&mut self, h: &mut Heap, def: DefinitionId) -> VisitorResult {
 
        assert!(self.scope.is_none());
 
        self.scope = Some(Scope::Definition(def));
 
        recursive_symbol_definition(self, h, def)?;
 
        self.scope = None;
 
        Ok(())
 
    }
 
    fn visit_block_statement(&mut self, h: &mut Heap, stmt: BlockStatementId) -> VisitorResult {
 
        assert!(!self.scope.is_none());
 
        let old = self.scope;
 
        // First store the current scope
 
        h[stmt].parent_scope = self.scope;
 
        // Then move scope down to current block
 
        self.scope = Some(Scope::Block(stmt));
 
        recursive_block_statement(self, h, stmt)?;
 
        // Move scope back up
 
        self.scope = old;
 
        Ok(())
 
    }
 
    fn visit_synchronous_statement(
 
        &mut self,
 
        h: &mut Heap,
 
        stmt: SynchronousStatementId,
 
    ) -> VisitorResult {
 
        assert!(!self.scope.is_none());
 
        let old = self.scope;
 
        // First store the current scope
 
        h[stmt].parent_scope = self.scope;
 
        // Then move scope down to current sync
 
        self.scope = Some(Scope::Synchronous(stmt));
 
        recursive_synchronous_statement(self, h, stmt)?;
 
        // Move scope back up
 
        self.scope = old;
 
        Ok(())
 
    }
 
    fn visit_expression(&mut self, h: &mut Heap, expr: ExpressionId) -> VisitorResult {
 
        Ok(())
 
    }
 
}
 

	
 
struct ResolveVariables {
 
    scope: Option<Scope>,
 
}
 

	
 
impl ResolveVariables {
 
    fn new() -> Self {
 
        ResolveVariables { scope: None }
 
    }
 
    fn get_variable(&self, h: &Heap, id: SourceIdentifierId) -> Result<VariableId, ParseError> {
 
        if let Some(var) = self.find_variable(h, id) {
 
            Ok(var)
 
        } else {
 
            Err(ParseError::new(h[id].position, "Unresolved variable"))
 
        }
 
    }
 
    fn find_variable(&self, h: &Heap, id: SourceIdentifierId) -> Option<VariableId> {
 
        ResolveVariables::find_variable_impl(h, self.scope, id)
 
    }
 
    fn find_variable_impl(
 
        h: &Heap,
 
        scope: Option<Scope>,
 
        id: SourceIdentifierId,
 
    ) -> Option<VariableId> {
 
        if let Some(scope) = scope {
 
            // The order in which we check for variables is important:
 
            // otherwise, two variables with the same name are shadowed.
 
            if let Some(var) = ResolveVariables::find_variable_impl(h, scope.parent_scope(h), id) {
 
                Some(var)
 
            } else {
 
                scope.get_variable(h, id)
 
            }
 
        } else {
 
            None
 
        }
 
    }
 
}
 

	
 
impl Visitor for ResolveVariables {
 
    fn visit_symbol_definition(&mut self, h: &mut Heap, def: DefinitionId) -> VisitorResult {
 
        assert!(self.scope.is_none());
 
        self.scope = Some(Scope::Definition(def));
 
        recursive_symbol_definition(self, h, def)?;
 
        self.scope = None;
 
        Ok(())
 
    }
 
    fn visit_variable_declaration(&mut self, h: &mut Heap, decl: VariableId) -> VisitorResult {
 
        // This is only called for parameters of definitions and synchronous statements,
 
        // since the local variables of block statements are still empty
 
        // the moment it is traversed. After resolving variables, this
 
        // function is also called for every local variable declaration.
 

	
 
        // We want to make sure that the resolved variable is the variable declared itself;
 
        // otherwise, there is some variable defined in the parent scope. This check
 
        // imposes that the order in which find_variable looks is significant!
 
        let id = h[decl].identifier();
 
        let check_same = self.find_variable(h, id);
 
        if let Some(check_same) = check_same {
 
            if check_same != decl {
 
                return Err(ParseError::new(h[id].position, "Declared variable clash"));
 
            }
 
        }
 
        recursive_variable_declaration(self, h, decl)
 
    }
 
    fn visit_memory_statement(&mut self, h: &mut Heap, stmt: MemoryStatementId) -> VisitorResult {
 
        assert!(!self.scope.is_none());
 
        let var = h[stmt].variable;
 
        let id = h[var].identifier;
 
        // First check whether variable with same identifier is in scope
 
        let check_duplicate = self.find_variable(h, id);
 
        if !check_duplicate.is_none() {
 
            return Err(ParseError::new(h[id].position, "Declared variable clash"));
 
        }
 
        // Then check the expression's variables (this should not refer to own variable)
 
        recursive_memory_statement(self, h, stmt)?;
 
        // Finally, we may add the variable to the scope, which is guaranteed to be a block
 
        {
 
            let mut block = &mut h[self.scope.unwrap().to_block()];
 
            block.locals.push(var);
 
        }
 
        Ok(())
 
    }
 
    fn visit_channel_statement(&mut self, h: &mut Heap, stmt: ChannelStatementId) -> VisitorResult {
 
        assert!(!self.scope.is_none());
 
        // First handle the from variable
 
        {
 
            let var = h[stmt].from;
 
            let id = h[var].identifier;
 
            let check_duplicate = self.find_variable(h, id);
 
            if !check_duplicate.is_none() {
 
                return Err(ParseError::new(h[id].position, "Declared variable clash"));
 
            }
 
            let mut block = &mut h[self.scope.unwrap().to_block()];
 
            block.locals.push(var);
 
        }
 
        // Then handle the to variable (which may not be the same as the from)
 
        {
 
            let var = h[stmt].to;
 
            let id = h[var].identifier;
 
            let check_duplicate = self.find_variable(h, id);
 
            if !check_duplicate.is_none() {
 
                return Err(ParseError::new(h[id].position, "Declared variable clash"));
 
            }
 
            let mut block = &mut h[self.scope.unwrap().to_block()];
 
            block.locals.push(var);
 
        }
 
        Ok(())
 
    }
 
    fn visit_block_statement(&mut self, h: &mut Heap, stmt: BlockStatementId) -> VisitorResult {
 
        assert!(!self.scope.is_none());
 
        let old = self.scope;
 
        self.scope = Some(Scope::Block(stmt));
 
        recursive_block_statement(self, h, stmt)?;
 
        self.scope = old;
 
        Ok(())
 
    }
 
    fn visit_synchronous_statement(
 
        &mut self,
 
        h: &mut Heap,
 
        stmt: SynchronousStatementId,
 
    ) -> VisitorResult {
 
        assert!(!self.scope.is_none());
 
        let old = self.scope;
 
        self.scope = Some(Scope::Synchronous(stmt));
 
        recursive_synchronous_statement(self, h, stmt)?;
 
        self.scope = old;
 
        Ok(())
 
    }
 
    fn visit_variable_expression(
 
        &mut self,
 
        h: &mut Heap,
 
        expr: VariableExpressionId,
 
    ) -> VisitorResult {
 
        let var = self.get_variable(h, h[expr].identifier)?;
 
        h[expr].declaration = Some(var);
 
        Ok(())
 
    }
 
}
 

	
 
struct UniqueStatementId(StatementId);
 

	
 
struct LinkStatements {
 
    prev: Option<UniqueStatementId>,
 
}
 

	
 
impl LinkStatements {
 
    fn new() -> Self {
 
        LinkStatements { prev: None }
 
    }
 
}
 

	
 
impl Visitor for LinkStatements {
 
    fn visit_symbol_definition(&mut self, h: &mut Heap, def: DefinitionId) -> VisitorResult {
 
        assert!(self.prev.is_none());
 
        recursive_symbol_definition(self, h, def)?;
 
        // Clear out last statement
 
        self.prev = None;
 
        Ok(())
 
    }
 
    fn visit_statement(&mut self, h: &mut Heap, stmt: StatementId) -> VisitorResult {
 
        if let Some(UniqueStatementId(prev)) = self.prev.take() {
 
            h[prev].link_next(stmt);
 
        }
 
        recursive_statement(self, h, stmt)
 
    }
 
    fn visit_local_statement(&mut self, _h: &mut Heap, stmt: LocalStatementId) -> VisitorResult {
 
        self.prev = Some(UniqueStatementId(stmt.upcast()));
 
        Ok(())
 
    }
 
    fn visit_labeled_statement(&mut self, h: &mut Heap, stmt: LabeledStatementId) -> VisitorResult {
 
        recursive_labeled_statement(self, h, stmt)
 
    }
 
    fn visit_skip_statement(&mut self, _h: &mut Heap, stmt: SkipStatementId) -> VisitorResult {
 
        self.prev = Some(UniqueStatementId(stmt.upcast()));
 
        Ok(())
 
    }
 
    fn visit_if_statement(&mut self, h: &mut Heap, stmt: IfStatementId) -> VisitorResult {
 
        // We allocate a pseudo-statement, which combines both branches into one next statement
 
        let position = h[stmt].position;
 
        let pseudo =
 
            h.alloc_end_if_statement(|this| EndIfStatement { this, position, next: None }).upcast();
 
        assert!(self.prev.is_none());
 
        self.visit_statement(h, h[stmt].true_body)?;
 
        if let Some(UniqueStatementId(prev)) = self.prev.take() {
 
            h[prev].link_next(pseudo);
 
        }
 
        assert!(self.prev.is_none());
 
        self.visit_statement(h, h[stmt].false_body)?;
 
        if let Some(UniqueStatementId(prev)) = self.prev.take() {
 
            h[prev].link_next(pseudo);
 
        }
 
        // Use the pseudo-statement as the statement where to update the next pointer
 
        self.prev = Some(UniqueStatementId(pseudo));
 
        Ok(())
 
    }
 
    fn visit_while_statement(&mut self, h: &mut Heap, stmt: WhileStatementId) -> VisitorResult {
 
        // We allocate a pseudo-statement, to which the break statement finds its target
 
        let position = h[stmt].position;
 
        let pseudo =
 
            h.alloc_end_while_statement(|this| EndWhileStatement { this, position, next: None });
 
        // Update the while's next statement to point to the pseudo-statement
 
        h[stmt].next = Some(pseudo);
 
        assert!(self.prev.is_none());
 
        self.visit_statement(h, h[stmt].body)?;
 
        // The body's next statement loops back to the while statement itself
 
        // Note: continue statements also loop back to the while statement itself
 
        if let Some(UniqueStatementId(prev)) = std::mem::replace(&mut self.prev, None) {
 
            h[prev].link_next(stmt.upcast());
 
        }
 
        // Use the while statement as the statement where the next pointer is updated
 
        self.prev = Some(UniqueStatementId(pseudo.upcast()));
 
        Ok(())
 
    }
 
    fn visit_break_statement(&mut self, _h: &mut Heap, _stmt: BreakStatementId) -> VisitorResult {
 
        Ok(())
 
    }
 
    fn visit_continue_statement(
 
        &mut self,
 
        _h: &mut Heap,
 
        _stmt: ContinueStatementId,
 
    ) -> VisitorResult {
 
        Ok(())
 
    }
 
    fn visit_synchronous_statement(
 
        &mut self,
 
        h: &mut Heap,
 
        stmt: SynchronousStatementId,
 
    ) -> VisitorResult {
 
        // Allocate a pseudo-statement, that is added for helping the evaluator to issue a command
 
        // that marks the end of the synchronous block. Every evaluation has to pause at this
 
        // point, only to resume later when the thread is selected as unique thread to continue.
 
        let position = h[stmt].position;
 
        let pseudo = h
 
            .alloc_end_synchronous_statement(|this| EndSynchronousStatement {
 
                this,
 
                position,
 
                next: None,
 
            })
 
            .upcast();
 
        assert!(self.prev.is_none());
 
        self.visit_statement(h, h[stmt].body)?;
 
        // The body's next statement points to the pseudo element
 
        if let Some(UniqueStatementId(prev)) = std::mem::replace(&mut self.prev, None) {
 
            h[prev].link_next(pseudo);
 
        }
 
        // Use the pseudo-statement as the statement where the next pointer is updated
 
        self.prev = Some(UniqueStatementId(pseudo));
 
        Ok(())
 
    }
 
    fn visit_return_statement(&mut self, h: &mut Heap, stmt: ReturnStatementId) -> VisitorResult {
 
        Ok(())
 
    }
 
    fn visit_assert_statement(&mut self, h: &mut Heap, stmt: AssertStatementId) -> VisitorResult {
 
        self.prev = Some(UniqueStatementId(stmt.upcast()));
 
        Ok(())
 
    }
 
    fn visit_goto_statement(&mut self, _h: &mut Heap, _stmt: GotoStatementId) -> VisitorResult {
 
        Ok(())
 
    }
 
    fn visit_new_statement(&mut self, h: &mut Heap, stmt: NewStatementId) -> VisitorResult {
 
        self.prev = Some(UniqueStatementId(stmt.upcast()));
 
        Ok(())
 
    }
 
    fn visit_put_statement(&mut self, h: &mut Heap, stmt: PutStatementId) -> VisitorResult {
 
        self.prev = Some(UniqueStatementId(stmt.upcast()));
 
        Ok(())
 
    }
 
    fn visit_expression_statement(
 
        &mut self,
 
        h: &mut Heap,
 
        stmt: ExpressionStatementId,
 
    ) -> VisitorResult {
 
        self.prev = Some(UniqueStatementId(stmt.upcast()));
 
        Ok(())
 
    }
 
    fn visit_expression(&mut self, h: &mut Heap, expr: ExpressionId) -> VisitorResult {
 
        Ok(())
 
    }
 
}
 

	
 
struct BuildLabels {
 
    block: Option<BlockStatementId>,
 
    sync_enclosure: Option<SynchronousStatementId>,
 
}
 

	
 
impl BuildLabels {
 
    fn new() -> Self {
 
        BuildLabels { block: None, sync_enclosure: None }
 
    }
 
}
 

	
 
impl Visitor for BuildLabels {
 
    fn visit_block_statement(&mut self, h: &mut Heap, stmt: BlockStatementId) -> VisitorResult {
 
        assert_eq!(self.block, h[stmt].parent_block(h));
 
        let old = self.block;
 
        self.block = Some(stmt);
 
        recursive_block_statement(self, h, stmt)?;
 
        self.block = old;
 
        Ok(())
 
    }
 
    fn visit_labeled_statement(&mut self, h: &mut Heap, stmt: LabeledStatementId) -> VisitorResult {
 
        assert!(!self.block.is_none());
 
        // Store label in current block (on the fly)
 
        h[self.block.unwrap()].labels.push(stmt);
 
        // Update synchronous scope of label
 
        h[stmt].in_sync = self.sync_enclosure;
 
        recursive_labeled_statement(self, h, stmt)
 
    }
 
    fn visit_while_statement(&mut self, h: &mut Heap, stmt: WhileStatementId) -> VisitorResult {
 
        h[stmt].in_sync = self.sync_enclosure;
 
        recursive_while_statement(self, h, stmt)
 
    }
 
    fn visit_synchronous_statement(
 
        &mut self,
 
        h: &mut Heap,
 
        stmt: SynchronousStatementId,
 
    ) -> VisitorResult {
 
        assert!(self.sync_enclosure.is_none());
 
        self.sync_enclosure = Some(stmt);
 
        recursive_synchronous_statement(self, h, stmt)?;
 
        self.sync_enclosure = None;
 
        Ok(())
 
    }
 
    fn visit_expression(&mut self, h: &mut Heap, expr: ExpressionId) -> VisitorResult {
 
        Ok(())
 
    }
 
}
 

	
 
struct ResolveLabels {
 
    block: Option<BlockStatementId>,
 
    while_enclosure: Option<WhileStatementId>,
 
    sync_enclosure: Option<SynchronousStatementId>,
 
}
 

	
 
impl ResolveLabels {
 
    fn new() -> Self {
 
        ResolveLabels { block: None, while_enclosure: None, sync_enclosure: None }
 
    }
 
    fn check_duplicate_impl(
 
        h: &Heap,
 
        block: Option<BlockStatementId>,
 
        stmt: LabeledStatementId,
 
    ) -> VisitorResult {
 
        if let Some(block) = block {
 
            // Checking the parent first is important. Otherwise, labels
 
            // overshadow previously defined labels: and this is illegal!
 
            ResolveLabels::check_duplicate_impl(h, h[block].parent_block(h), stmt)?;
 
            // For the current block, check for a duplicate.
 
            for &other_stmt in h[block].labels.iter() {
 
                if other_stmt == stmt {
 
                    continue;
 
                } else {
 
                    if h[h[other_stmt].label] == h[h[stmt].label] {
 
                        return Err(ParseError::new(h[stmt].position, "Duplicate label"));
 
                    }
 
                }
 
            }
 
        }
 
        Ok(())
 
    }
 
    fn check_duplicate(&self, h: &Heap, stmt: LabeledStatementId) -> VisitorResult {
 
        ResolveLabels::check_duplicate_impl(h, self.block, stmt)
 
    }
 
    fn get_target(
 
        &self,
 
        h: &Heap,
 
        id: SourceIdentifierId,
 
    ) -> Result<LabeledStatementId, ParseError> {
 
        if let Some(stmt) = ResolveLabels::find_target(h, self.block, id) {
 
            Ok(stmt)
 
        } else {
 
            Err(ParseError::new(h[id].position, "Unresolved label"))
 
        }
 
    }
 
    fn find_target(
 
        h: &Heap,
 
        block: Option<BlockStatementId>,
 
        id: SourceIdentifierId,
 
    ) -> Option<LabeledStatementId> {
 
        if let Some(block) = block {
 
            // It does not matter in what order we find the labels.
 
            // If there are duplicates: that is checked elsewhere.
 
            for &stmt in h[block].labels.iter() {
 
                if h[h[stmt].label] == h[id] {
 
                    return Some(stmt);
 
                }
 
            }
 
            if let Some(stmt) = ResolveLabels::find_target(h, h[block].parent_block(h), id) {
 
                return Some(stmt);
 
            }
 
        }
 
        None
 
    }
 
}
 

	
 
impl Visitor for ResolveLabels {
 
    fn visit_block_statement(&mut self, h: &mut Heap, stmt: BlockStatementId) -> VisitorResult {
 
        assert_eq!(self.block, h[stmt].parent_block(h));
 
        let old = self.block;
 
        self.block = Some(stmt);
 
        recursive_block_statement(self, h, stmt)?;
 
        self.block = old;
 
        Ok(())
 
    }
 
    fn visit_labeled_statement(&mut self, h: &mut Heap, stmt: LabeledStatementId) -> VisitorResult {
 
        assert!(!self.block.is_none());
 
        self.check_duplicate(h, stmt)?;
 
        recursive_labeled_statement(self, h, stmt)
 
    }
 
    fn visit_while_statement(&mut self, h: &mut Heap, stmt: WhileStatementId) -> VisitorResult {
 
        let old = self.while_enclosure;
 
        self.while_enclosure = Some(stmt);
 
        recursive_while_statement(self, h, stmt)?;
 
        self.while_enclosure = old;
 
        Ok(())
 
    }
 
    fn visit_break_statement(&mut self, h: &mut Heap, stmt: BreakStatementId) -> VisitorResult {
 
        let the_while;
 
        if let Some(label) = h[stmt].label {
 
            let target = self.get_target(h, label)?;
 
            let target = &h[h[target].body];
 
            if !target.is_while() {
 
                return Err(ParseError::new(
 
                    h[stmt].position,
 
                    "Illegal break: target not a while statement",
 
                ));
 
            }
 
            the_while = target.as_while();
 
        // TODO: check if break is nested under while
 
        } else {
 
            if self.while_enclosure.is_none() {
 
                return Err(ParseError::new(
 
                    h[stmt].position,
 
                    "Illegal break: no surrounding while statement",
 
                ));
 
            }
 
            the_while = &h[self.while_enclosure.unwrap()];
 
            // break is always nested under while, by recursive vistor
 
        }
 
        if the_while.in_sync != self.sync_enclosure {
 
            return Err(ParseError::new(
 
                h[stmt].position,
 
                "Illegal break: synchronous statement escape",
 
            ));
 
        }
 
        h[stmt].target = the_while.next;
 
        Ok(())
 
    }
 
    fn visit_continue_statement(
 
        &mut self,
 
        h: &mut Heap,
 
        stmt: ContinueStatementId,
 
    ) -> VisitorResult {
 
        let the_while;
 
        if let Some(label) = h[stmt].label {
 
            let target = self.get_target(h, label)?;
 
            let target = &h[h[target].body];
 
            if !target.is_while() {
 
                return Err(ParseError::new(
 
                    h[stmt].position,
 
                    "Illegal continue: target not a while statement",
 
                ));
 
            }
 
            the_while = target.as_while();
 
        // TODO: check if continue is nested under while
 
        } else {
 
            if self.while_enclosure.is_none() {
 
                return Err(ParseError::new(
 
                    h[stmt].position,
 
                    "Illegal continue: no surrounding while statement",
 
                ));
 
            }
 
            the_while = &h[self.while_enclosure.unwrap()];
 
            // continue is always nested under while, by recursive vistor
 
        }
 
        if the_while.in_sync != self.sync_enclosure {
 
            return Err(ParseError::new(
 
                h[stmt].position,
 
                "Illegal continue: synchronous statement escape",
 
            ));
 
        }
 
        h[stmt].target = Some(the_while.this);
 
        Ok(())
 
    }
 
    fn visit_synchronous_statement(
 
        &mut self,
 
        h: &mut Heap,
 
        stmt: SynchronousStatementId,
 
    ) -> VisitorResult {
 
        assert!(self.sync_enclosure.is_none());
 
        self.sync_enclosure = Some(stmt);
 
        recursive_synchronous_statement(self, h, stmt)?;
 
        self.sync_enclosure = None;
 
        Ok(())
 
    }
 
    fn visit_goto_statement(&mut self, h: &mut Heap, stmt: GotoStatementId) -> VisitorResult {
 
        let target = self.get_target(h, h[stmt].label)?;
 
        if h[target].in_sync != self.sync_enclosure {
 
            return Err(ParseError::new(
 
                h[stmt].position,
 
                "Illegal goto: synchronous statement escape",
 
            ));
 
        }
 
        h[stmt].target = Some(target);
 
        Ok(())
 
    }
 
    fn visit_expression(&mut self, h: &mut Heap, expr: ExpressionId) -> VisitorResult {
 
        Ok(())
 
    }
 
}
 

	
 
struct AssignableExpressions {
 
    assignable: bool,
 
}
 

	
 
impl AssignableExpressions {
 
    fn new() -> Self {
 
        AssignableExpressions { assignable: false }
 
    }
 
    fn error(&self, position: InputPosition) -> VisitorResult {
 
        Err(ParseError::new(position, "Unassignable expression"))
 
    }
 
}
 

	
 
impl Visitor for AssignableExpressions {
 
    fn visit_assignment_expression(
 
        &mut self,
 
        h: &mut Heap,
 
        expr: AssignmentExpressionId,
 
    ) -> VisitorResult {
 
        if self.assignable {
 
            self.error(h[expr].position)
 
        } else {
 
            self.assignable = true;
 
            self.visit_expression(h, h[expr].left)?;
 
            self.assignable = false;
 
            self.visit_expression(h, h[expr].right)
 
        }
 
    }
 
    fn visit_conditional_expression(
 
        &mut self,
 
        h: &mut Heap,
 
        expr: ConditionalExpressionId,
 
    ) -> VisitorResult {
 
        if self.assignable {
 
            self.error(h[expr].position)
 
        } else {
 
            recursive_conditional_expression(self, h, expr)
 
        }
 
    }
 
    fn visit_binary_expression(&mut self, h: &mut Heap, expr: BinaryExpressionId) -> VisitorResult {
 
        if self.assignable {
 
            self.error(h[expr].position)
 
        } else {
 
            recursive_binary_expression(self, h, expr)
 
        }
 
    }
 
    fn visit_unary_expression(&mut self, h: &mut Heap, expr: UnaryExpressionId) -> VisitorResult {
 
        if self.assignable {
 
            self.error(h[expr].position)
 
        } else {
 
            match h[expr].operation {
 
                UnaryOperation::PostDecrement
 
                | UnaryOperation::PreDecrement
 
                | UnaryOperation::PostIncrement
 
                | UnaryOperation::PreIncrement => {
 
                    self.assignable = true;
 
                    recursive_unary_expression(self, h, expr)?;
 
                    self.assignable = false;
 
                    Ok(())
 
                }
 
                _ => recursive_unary_expression(self, h, expr),
 
            }
 
        }
 
    }
 
    fn visit_indexing_expression(
 
        &mut self,
 
        h: &mut Heap,
 
        expr: IndexingExpressionId,
 
    ) -> VisitorResult {
 
        let old = self.assignable;
 
        self.assignable = false;
 
        recursive_indexing_expression(self, h, expr)?;
 
        self.assignable = old;
 
        Ok(())
 
    }
 
    fn visit_slicing_expression(
 
        &mut self,
 
        h: &mut Heap,
 
        expr: SlicingExpressionId,
 
    ) -> VisitorResult {
 
        let old = self.assignable;
 
        self.assignable = false;
 
        recursive_slicing_expression(self, h, expr)?;
 
        self.assignable = old;
 
        Ok(())
 
    }
 
    fn visit_select_expression(&mut self, h: &mut Heap, expr: SelectExpressionId) -> VisitorResult {
 
        if h[expr].field.is_length() && self.assignable {
 
            return self.error(h[expr].position);
 
        }
 
        let old = self.assignable;
 
        self.assignable = false;
 
        recursive_select_expression(self, h, expr)?;
 
        self.assignable = old;
 
        Ok(())
 
    }
 
    fn visit_array_expression(&mut self, h: &mut Heap, expr: ArrayExpressionId) -> VisitorResult {
 
        if self.assignable {
 
            self.error(h[expr].position)
 
        } else {
 
            recursive_array_expression(self, h, expr)
 
        }
 
    }
 
    fn visit_call_expression(&mut self, h: &mut Heap, expr: CallExpressionId) -> VisitorResult {
 
        if self.assignable {
 
            self.error(h[expr].position)
 
        } else {
 
            recursive_call_expression(self, h, expr)
 
        }
 
    }
 
    fn visit_constant_expression(
 
        &mut self,
 
        h: &mut Heap,
 
        expr: ConstantExpressionId,
 
    ) -> VisitorResult {
 
        if self.assignable {
 
            self.error(h[expr].position)
 
        } else {
 
            Ok(())
 
        }
 
    }
 
    fn visit_variable_expression(
 
        &mut self,
 
        h: &mut Heap,
 
        expr: VariableExpressionId,
 
    ) -> VisitorResult {
 
        Ok(())
 
    }
 
}
 

	
 
struct IndexableExpressions {
 
    indexable: bool,
 
}
 

	
 
impl IndexableExpressions {
 
    fn new() -> Self {
 
        IndexableExpressions { indexable: false }
 
    }
 
    fn error(&self, position: InputPosition) -> VisitorResult {
 
        Err(ParseError::new(position, "Unindexable expression"))
 
    }
 
}
 

	
 
impl Visitor for IndexableExpressions {
 
    fn visit_assignment_expression(
 
        &mut self,
 
        h: &mut Heap,
 
        expr: AssignmentExpressionId,
 
    ) -> VisitorResult {
 
        if self.indexable {
 
            self.error(h[expr].position)
 
        } else {
 
            recursive_assignment_expression(self, h, expr)
 
        }
 
    }
 
    fn visit_conditional_expression(
 
        &mut self,
 
        h: &mut Heap,
 
        expr: ConditionalExpressionId,
 
    ) -> VisitorResult {
 
        let old = self.indexable;
 
        self.indexable = false;
 
        self.visit_expression(h, h[expr].test)?;
 
        self.indexable = old;
 
        self.visit_expression(h, h[expr].true_expression)?;
 
        self.visit_expression(h, h[expr].false_expression)
 
    }
 
    fn visit_binary_expression(&mut self, h: &mut Heap, expr: BinaryExpressionId) -> VisitorResult {
 
        if self.indexable && h[expr].operation != BinaryOperator::Concatenate {
 
            self.error(h[expr].position)
 
        } else {
 
            recursive_binary_expression(self, h, expr)
 
        }
 
    }
 
    fn visit_unary_expression(&mut self, h: &mut Heap, expr: UnaryExpressionId) -> VisitorResult {
 
        if self.indexable {
 
            self.error(h[expr].position)
 
        } else {
 
            recursive_unary_expression(self, h, expr)
 
        }
 
    }
 
    fn visit_indexing_expression(
 
        &mut self,
 
        h: &mut Heap,
 
        expr: IndexingExpressionId,
 
    ) -> VisitorResult {
 
        if self.indexable {
 
            self.error(h[expr].position)
 
        } else {
 
            self.indexable = true;
 
            self.visit_expression(h, h[expr].subject)?;
 
        let old = self.indexable;
 
        self.indexable = false;
 
        self.visit_expression(h, h[expr].subject)?;
 
        self.indexable = old;
 
        self.visit_expression(h, h[expr].index)
 
    }
 
    }
 
    fn visit_slicing_expression(
 
        &mut self,
 
        h: &mut Heap,
 
        expr: SlicingExpressionId,
 
    ) -> VisitorResult {
 
        let old = self.indexable;
 
        self.indexable = true;
 
        self.visit_expression(h, h[expr].subject)?;
 
        self.indexable = false;
 
        self.visit_expression(h, h[expr].from_index)?;
 
        self.visit_expression(h, h[expr].to_index)?;
 
        self.indexable = old;
 
        Ok(())
 
    }
 
    fn visit_select_expression(&mut self, h: &mut Heap, expr: SelectExpressionId) -> VisitorResult {
 
        let old = self.indexable;
 
        self.indexable = false;
 
        recursive_select_expression(self, h, expr)?;
 
        self.indexable = old;
 
        Ok(())
 
    }
 
    fn visit_array_expression(&mut self, h: &mut Heap, expr: ArrayExpressionId) -> VisitorResult {
 
        let old = self.indexable;
 
        self.indexable = false;
 
        recursive_array_expression(self, h, expr)?;
 
        self.indexable = old;
 
        Ok(())
 
    }
 
    fn visit_call_expression(&mut self, h: &mut Heap, expr: CallExpressionId) -> VisitorResult {
 
        let old = self.indexable;
 
        self.indexable = false;
 
        recursive_call_expression(self, h, expr)?;
 
        self.indexable = old;
 
        Ok(())
 
    }
 
    fn visit_constant_expression(
 
        &mut self,
 
        h: &mut Heap,
 
        expr: ConstantExpressionId,
 
    ) -> VisitorResult {
 
        if self.indexable {
 
            self.error(h[expr].position)
 
        } else {
 
            Ok(())
 
        }
 
    }
 
}
 

	
 
struct SelectableExpressions {
 
    selectable: bool,
 
}
 

	
 
impl SelectableExpressions {
 
    fn new() -> Self {
 
        SelectableExpressions { selectable: false }
 
    }
 
    fn error(&self, position: InputPosition) -> VisitorResult {
 
        Err(ParseError::new(position, "Unselectable expression"))
 
    }
 
}
 

	
 
impl Visitor for SelectableExpressions {
 
    fn visit_assignment_expression(
 
        &mut self,
 
        h: &mut Heap,
 
        expr: AssignmentExpressionId,
 
    ) -> VisitorResult {
 
        // left-hand side of assignment can be skipped
 
        let old = self.selectable;
 
        self.selectable = false;
 
        self.visit_expression(h, h[expr].right)?;
 
        self.selectable = old;
 
        Ok(())
 
    }
 
    fn visit_conditional_expression(
 
        &mut self,
 
        h: &mut Heap,
 
        expr: ConditionalExpressionId,
 
    ) -> VisitorResult {
 
        let old = self.selectable;
 
        self.selectable = false;
 
        self.visit_expression(h, h[expr].test)?;
 
        self.selectable = old;
 
        self.visit_expression(h, h[expr].true_expression)?;
 
        self.visit_expression(h, h[expr].false_expression)
 
    }
 
    fn visit_binary_expression(&mut self, h: &mut Heap, expr: BinaryExpressionId) -> VisitorResult {
 
        if self.selectable && h[expr].operation != BinaryOperator::Concatenate {
 
            self.error(h[expr].position)
 
        } else {
 
            recursive_binary_expression(self, h, expr)
 
        }
 
    }
 
    fn visit_unary_expression(&mut self, h: &mut Heap, expr: UnaryExpressionId) -> VisitorResult {
 
        if self.selectable {
 
            self.error(h[expr].position)
 
        } else {
 
            recursive_unary_expression(self, h, expr)
 
        }
 
    }
 
    fn visit_indexing_expression(
 
        &mut self,
 
        h: &mut Heap,
 
        expr: IndexingExpressionId,
 
    ) -> VisitorResult {
 
        let old = self.selectable;
 
        self.selectable = false;
 
        recursive_indexing_expression(self, h, expr)?;
 
        self.selectable = old;
 
        Ok(())
 
    }
 
    fn visit_slicing_expression(
 
        &mut self,
 
        h: &mut Heap,
 
        expr: SlicingExpressionId,
 
    ) -> VisitorResult {
 
        let old = self.selectable;
 
        self.selectable = false;
 
        recursive_slicing_expression(self, h, expr)?;
 
        self.selectable = old;
 
        Ok(())
 
    }
 
    fn visit_select_expression(&mut self, h: &mut Heap, expr: SelectExpressionId) -> VisitorResult {
 
        let old = self.selectable;
 
        self.selectable = false;
 
        recursive_select_expression(self, h, expr)?;
 
        self.selectable = old;
 
        Ok(())
 
    }
 
    fn visit_array_expression(&mut self, h: &mut Heap, expr: ArrayExpressionId) -> VisitorResult {
 
        let old = self.selectable;
 
        self.selectable = false;
 
        recursive_array_expression(self, h, expr)?;
 
        self.selectable = old;
 
        Ok(())
 
    }
 
    fn visit_call_expression(&mut self, h: &mut Heap, expr: CallExpressionId) -> VisitorResult {
 
        let old = self.selectable;
 
        self.selectable = false;
 
        recursive_call_expression(self, h, expr)?;
 
        self.selectable = old;
 
        Ok(())
 
    }
 
    fn visit_constant_expression(
 
        &mut self,
 
        h: &mut Heap,
 
        expr: ConstantExpressionId,
 
    ) -> VisitorResult {
 
        if self.selectable {
 
            self.error(h[expr].position)
 
        } else {
 
            Ok(())
 
        }
 
    }
 
}
 

	
 
pub struct Parser<'a> {
 
    source: &'a mut InputSource,
 
}
 

	
 
impl<'a> Parser<'a> {
 
    pub fn new(source: &'a mut InputSource) -> Self {
 
        Parser { source }
 
    }
 
    pub fn parse(&mut self, h: &mut Heap) -> Result<RootId, ParseError> {
 
        let mut lex = Lexer::new(self.source);
 
        let pd = lex.consume_protocol_description(h)?;
 
        NestedSynchronousStatements::new().visit_protocol_description(h, pd)?;
 
        ChannelStatementOccurrences::new().visit_protocol_description(h, pd)?;
 
        FunctionStatementReturns::new().visit_protocol_description(h, pd)?;
 
        ComponentStatementReturnNew::new().visit_protocol_description(h, pd)?;
 
        CheckBuiltinOccurrences::new().visit_protocol_description(h, pd)?;
 
        BuildSymbolDeclarations::new().visit_protocol_description(h, pd)?;
 
        LinkCallExpressions::new().visit_protocol_description(h, pd)?;
 
        BuildScope::new().visit_protocol_description(h, pd)?;
 
        ResolveVariables::new().visit_protocol_description(h, pd)?;
 
        LinkStatements::new().visit_protocol_description(h, pd)?;
 
        BuildLabels::new().visit_protocol_description(h, pd)?;
 
        ResolveLabels::new().visit_protocol_description(h, pd)?;
 
        AssignableExpressions::new().visit_protocol_description(h, pd)?;
 
        IndexableExpressions::new().visit_protocol_description(h, pd)?;
 
        SelectableExpressions::new().visit_protocol_description(h, pd)?;
 
        Ok(pd)
 
    }
 
}
 

	
 
#[cfg(test)]
 
mod tests {
 
    extern crate test_generator;
 

	
 
    use std::fs::File;
 
    use std::io::Read;
 
    use std::path::Path;
 

	
 
    use test_generator::test_resources;
 

	
 
    use super::*;
 

	
 
    #[test_resources("testdata/parser/positive/*.pdl")]
 
    fn batch1(resource: &str) {
 
        let path = Path::new(resource);
 
        let mut heap = Heap::new();
 
        let mut source = InputSource::from_file(&path).unwrap();
 
        let mut parser = Parser::new(&mut source);
 
        match parser.parse(&mut heap) {
 
            Ok(_) => {}
 
            Err(err) => {
 
                println!("{}", err.display(&source));
 
                println!("{:?}", err);
 
                assert!(false);
 
            }
 
        }
 
    }
 

	
 
    #[test_resources("testdata/parser/negative/*.pdl")]
 
    fn batch2(resource: &str) {
 
        let path = Path::new(resource);
 
        let expect = path.with_extension("txt");
 
        let mut heap = Heap::new();
 
        let mut source = InputSource::from_file(&path).unwrap();
 
        let mut parser = Parser::new(&mut source);
 
        match parser.parse(&mut heap) {
 
            Ok(pd) => {
 
                println!("{:?}", heap[pd]);
 
                println!("Expected parse error:");
 

	
 
                let mut cev: Vec<u8> = Vec::new();
 
                let mut f = File::open(expect).unwrap();
 
                f.read_to_end(&mut cev).unwrap();
 
                println!("{}", String::from_utf8_lossy(&cev));
 
                assert!(false);
 
            }
 
            Err(err) => {
 
                println!("{:?}", err);
 

	
 
                let mut vec: Vec<u8> = Vec::new();
 
                err.write(&source, &mut vec).unwrap();
 
                println!("{}", String::from_utf8_lossy(&vec));
 

	
 
                let mut cev: Vec<u8> = Vec::new();
 
                let mut f = File::open(expect).unwrap();
 
                f.read_to_end(&mut cev).unwrap();
 
                println!("{}", String::from_utf8_lossy(&cev));
 

	
 
                assert_eq!(vec, cev);
 
            }
 
        }
 
    }
 
}
testdata/eval/positive/7.pdl
Show inline comments
 
new file 100644
 
#version 100
 

	
 
composite main() {}
 

	
 
int test() {
 
	msg x = create(5);
 
	x[0] = 1;
 
	x[1] = 2;
 
	x[2] = 3;
 
	x[3] = 4;
 
	x[4] = 5;
 
	return x[x[x[x[x[0]]]]];
 
}
 
\ No newline at end of file
testdata/eval/positive/7.txt
Show inline comments
 
new file 100644
 
5
 
\ No newline at end of file
testdata/eval/positive/8.pdl
Show inline comments
 
new file 100644
 
#version 100
 

	
 
composite main() {}
 

	
 
int test() {
 
	msg x = create(4);
 
	x[0] = 1;
 
	x[1] = 2;
 
	x[2] = 3;
 
	x[3] = 4;
 
	return x.length;
 
}
 
\ No newline at end of file
testdata/eval/positive/8.txt
Show inline comments
 
new file 100644
 
4
 
\ No newline at end of file
testdata/eval/positive/9.pdl
Show inline comments
 
new file 100644
 
#version 100
 

	
 
composite main() {}
 

	
 
int test() {
 
	msg[] x = {create(4)};
 
	x[0][0] = 0;
 
	x[x[0][0]][1] = 1;
 
	x[x[0][0]][x[0][1]+x[0][1]] = 2;
 
	x[x[0][0]][3] = 3;
 
	return x.length + x[0].length + x[x[0][0]][x[0][3]];
 
}
 
\ No newline at end of file
testdata/eval/positive/9.txt
Show inline comments
 
new file 100644
 
8
 
\ No newline at end of file
0 comments (0 inline, 0 general)