diff --git a/src/protocol/eval_old.rs b/src/protocol/eval_old.rs new file mode 100644 index 0000000000000000000000000000000000000000..5d5ffb3faa1ec7f0e1685dda67a376e1a7f0ce28 --- /dev/null +++ b/src/protocol/eval_old.rs @@ -0,0 +1,1807 @@ +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::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)); + +// TODO: All goes one day anyway, so dirty typechecking hack +trait ValueImpl { + fn exact_type(&self) -> Type; + fn is_type_compatible(&self, h: &Heap, t: &[ParserTypeElement]) -> bool { + Self::is_type_compatible_hack(h, t) + } + fn is_type_compatible_hack(h: &Heap, t: &[ParserTypeElement]) -> bool; +} + +#[derive(Debug, Clone)] +pub enum Value { + Unassigned, + 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: &Payload) -> 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(Payload::new(length as usize)))) + } + } + _ => unimplemented!(), + } + } + fn from_constant(constant: &Literal) -> Value { + match constant { + Literal::Null => Value::Message(MessageValue(None)), + Literal::True => Value::Boolean(BooleanValue(true)), + Literal::False => Value::Boolean(BooleanValue(false)), + Literal::Integer(val) => { + // Convert raw ASCII data to UTF-8 string + let mut integer_value = val.unsigned_value as i64; // TODO: @Int + if val.negated { integer_value = -integer_value; }; + + if integer_value >= BYTE_MIN && integer_value <= BYTE_MAX { + Value::Byte(ByteValue(integer_value as i8)) + } else if integer_value >= SHORT_MIN && integer_value <= SHORT_MAX { + Value::Short(ShortValue(integer_value as i16)) + } else if integer_value >= INT_MIN && integer_value <= INT_MAX { + Value::Int(IntValue(integer_value as i32)) + } else { + Value::Long(LongValue(integer_value)) + } + } + Literal::Character(_data) => unimplemented!(), + Literal::String(_data) => unimplemented!(), + Literal::Struct(_data) => unimplemented!(), + Literal::Enum(_data) => unimplemented!(), + Literal::Union(_data) => unimplemented!(), + Literal::Array(_expressions) => unimplemented!(), + } + } + fn set(&mut self, index: &Value, value: &Value) -> Option { + // The index must be of integer type, and non-negative + let the_index: usize; + match index { + Value::Byte(_) | Value::Short(_) | Value::Int(_) | Value::Long(_) => { + let index = i64::from(index); + if index < 0 || index >= MESSAGE_MAX_LENGTH { + // It is inconsistent to update out of bounds + return None; + } + the_index = index.try_into().unwrap(); + } + _ => unreachable!(), + } + // The subject must be either a message or an array + // And the value and the subject must be compatible + match (self, value) { + (Value::Message(MessageValue(None)), _) => { + // It is inconsistent to update the null message + None + } + (Value::Message(MessageValue(Some(payload))), Value::Byte(ByteValue(b))) => { + if *b < 0 { + // It is inconsistent to update with a negative value + return None; + } + if let Some(slot) = payload.as_mut_vec().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(payload))), 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) = payload.as_mut_vec().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 { + // 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(payload))) => { + if let Some(slot) = payload.as_slice().get(the_index) { + Some(Value::Short(ShortValue((*slot).try_into().unwrap()))) + } else { + // It is inconsistent to update out of bounds + None + } + } + _ => panic!("Can only get from port value"), + } + } + fn length(&self) -> Option { + // 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 { + match (self, other) { + (Value::Byte(ByteValue(s)), Value::Byte(ByteValue(o))) => { + Value::Byte(ByteValue(*s + *o)) + } + (Value::Byte(ByteValue(s)), Value::Short(ShortValue(o))) => { + Value::Short(ShortValue(*s as i16 + *o)) + } + (Value::Byte(ByteValue(s)), Value::Int(IntValue(o))) => { + Value::Int(IntValue(*s as i32 + *o)) + } + (Value::Byte(ByteValue(s)), Value::Long(LongValue(o))) => { + Value::Long(LongValue(*s as i64 + *o)) + } + (Value::Short(ShortValue(s)), Value::Byte(ByteValue(o))) => { + Value::Short(ShortValue(*s + *o as i16)) + } + (Value::Short(ShortValue(s)), Value::Short(ShortValue(o))) => { + Value::Short(ShortValue(*s + *o)) + } + (Value::Short(ShortValue(s)), Value::Int(IntValue(o))) => { + Value::Int(IntValue(*s as i32 + *o)) + } + (Value::Short(ShortValue(s)), Value::Long(LongValue(o))) => { + Value::Long(LongValue(*s as i64 + *o)) + } + (Value::Int(IntValue(s)), Value::Byte(ByteValue(o))) => { + Value::Int(IntValue(*s + *o as i32)) + } + (Value::Int(IntValue(s)), Value::Short(ShortValue(o))) => { + Value::Int(IntValue(*s + *o as i32)) + } + (Value::Int(IntValue(s)), Value::Int(IntValue(o))) => Value::Int(IntValue(*s + *o)), + (Value::Int(IntValue(s)), Value::Long(LongValue(o))) => { + Value::Long(LongValue(*s as i64 + *o)) + } + (Value::Long(LongValue(s)), Value::Byte(ByteValue(o))) => { + Value::Long(LongValue(*s + *o as i64)) + } + (Value::Long(LongValue(s)), Value::Short(ShortValue(o))) => { + Value::Long(LongValue(*s + *o as i64)) + } + (Value::Long(LongValue(s)), Value::Int(IntValue(o))) => { + Value::Long(LongValue(*s + *o as i64)) + } + (Value::Long(LongValue(s)), Value::Long(LongValue(o))) => { + Value::Long(LongValue(*s + *o)) + } + + (Value::Message(MessageValue(s)), Value::Message(MessageValue(o))) => { + let payload = if let [Some(s), Some(o)] = [s, o] { + let mut payload = s.clone(); + payload.concatenate_with(o); + Some(payload) + } else { + None + }; + Value::Message(MessageValue(payload)) + } + _ => unimplemented!(), + } + } + fn minus(&self, other: &Value) -> Value { + match (self, other) { + (Value::Byte(ByteValue(s)), Value::Byte(ByteValue(o))) => { + Value::Byte(ByteValue(*s - *o)) + } + (Value::Byte(ByteValue(s)), Value::Short(ShortValue(o))) => { + Value::Short(ShortValue(*s as i16 - *o)) + } + (Value::Byte(ByteValue(s)), Value::Int(IntValue(o))) => { + Value::Int(IntValue(*s as i32 - *o)) + } + (Value::Byte(ByteValue(s)), Value::Long(LongValue(o))) => { + Value::Long(LongValue(*s as i64 - *o)) + } + (Value::Short(ShortValue(s)), Value::Byte(ByteValue(o))) => { + Value::Short(ShortValue(*s - *o as i16)) + } + (Value::Short(ShortValue(s)), Value::Short(ShortValue(o))) => { + Value::Short(ShortValue(*s - *o)) + } + (Value::Short(ShortValue(s)), Value::Int(IntValue(o))) => { + Value::Int(IntValue(*s as i32 - *o)) + } + (Value::Short(ShortValue(s)), Value::Long(LongValue(o))) => { + Value::Long(LongValue(*s as i64 - *o)) + } + (Value::Int(IntValue(s)), Value::Byte(ByteValue(o))) => { + Value::Int(IntValue(*s - *o as i32)) + } + (Value::Int(IntValue(s)), Value::Short(ShortValue(o))) => { + Value::Int(IntValue(*s - *o as i32)) + } + (Value::Int(IntValue(s)), Value::Int(IntValue(o))) => Value::Int(IntValue(*s - *o)), + (Value::Int(IntValue(s)), Value::Long(LongValue(o))) => { + Value::Long(LongValue(*s as i64 - *o)) + } + (Value::Long(LongValue(s)), Value::Byte(ByteValue(o))) => { + Value::Long(LongValue(*s - *o as i64)) + } + (Value::Long(LongValue(s)), Value::Short(ShortValue(o))) => { + Value::Long(LongValue(*s - *o as i64)) + } + (Value::Long(LongValue(s)), Value::Int(IntValue(o))) => { + Value::Long(LongValue(*s - *o as i64)) + } + (Value::Long(LongValue(s)), Value::Long(LongValue(o))) => { + Value::Long(LongValue(*s - *o)) + } + _ => unimplemented!(), + } + } + fn modulus(&self, other: &Value) -> Value { + match (self, other) { + (Value::Byte(ByteValue(s)), Value::Byte(ByteValue(o))) => { + Value::Byte(ByteValue(*s % *o)) + } + (Value::Byte(ByteValue(s)), Value::Short(ShortValue(o))) => { + Value::Short(ShortValue(*s as i16 % *o)) + } + (Value::Byte(ByteValue(s)), Value::Int(IntValue(o))) => { + Value::Int(IntValue(*s as i32 % *o)) + } + (Value::Byte(ByteValue(s)), Value::Long(LongValue(o))) => { + Value::Long(LongValue(*s as i64 % *o)) + } + (Value::Short(ShortValue(s)), Value::Byte(ByteValue(o))) => { + Value::Short(ShortValue(*s % *o as i16)) + } + (Value::Short(ShortValue(s)), Value::Short(ShortValue(o))) => { + Value::Short(ShortValue(*s % *o)) + } + (Value::Short(ShortValue(s)), Value::Int(IntValue(o))) => { + Value::Int(IntValue(*s as i32 % *o)) + } + (Value::Short(ShortValue(s)), Value::Long(LongValue(o))) => { + Value::Long(LongValue(*s as i64 % *o)) + } + (Value::Int(IntValue(s)), Value::Byte(ByteValue(o))) => { + Value::Int(IntValue(*s % *o as i32)) + } + (Value::Int(IntValue(s)), Value::Short(ShortValue(o))) => { + Value::Int(IntValue(*s % *o as i32)) + } + (Value::Int(IntValue(s)), Value::Int(IntValue(o))) => Value::Int(IntValue(*s % *o)), + (Value::Int(IntValue(s)), Value::Long(LongValue(o))) => { + Value::Long(LongValue(*s as i64 % *o)) + } + (Value::Long(LongValue(s)), Value::Byte(ByteValue(o))) => { + Value::Long(LongValue(*s % *o as i64)) + } + (Value::Long(LongValue(s)), Value::Short(ShortValue(o))) => { + Value::Long(LongValue(*s % *o as i64)) + } + (Value::Long(LongValue(s)), Value::Int(IntValue(o))) => { + Value::Long(LongValue(*s % *o as i64)) + } + (Value::Long(LongValue(s)), Value::Long(LongValue(o))) => { + Value::Long(LongValue(*s % *o)) + } + _ => unimplemented!(), + } + } + fn eq(&self, other: &Value) -> Value { + match (self, other) { + (Value::Byte(ByteValue(s)), Value::Byte(ByteValue(o))) => { + Value::Boolean(BooleanValue(*s == *o)) + } + (Value::Byte(ByteValue(s)), Value::Short(ShortValue(o))) => { + Value::Boolean(BooleanValue(*s as i16 == *o)) + } + (Value::Byte(ByteValue(s)), Value::Int(IntValue(o))) => { + Value::Boolean(BooleanValue(*s as i32 == *o)) + } + (Value::Byte(ByteValue(s)), Value::Long(LongValue(o))) => { + Value::Boolean(BooleanValue(*s as i64 == *o)) + } + (Value::Short(ShortValue(s)), Value::Byte(ByteValue(o))) => { + Value::Boolean(BooleanValue(*s == *o as i16)) + } + (Value::Short(ShortValue(s)), Value::Short(ShortValue(o))) => { + Value::Boolean(BooleanValue(*s == *o)) + } + (Value::Short(ShortValue(s)), Value::Int(IntValue(o))) => { + Value::Boolean(BooleanValue(*s as i32 == *o)) + } + (Value::Short(ShortValue(s)), Value::Long(LongValue(o))) => { + Value::Boolean(BooleanValue(*s as i64 == *o)) + } + (Value::Int(IntValue(s)), Value::Byte(ByteValue(o))) => { + Value::Boolean(BooleanValue(*s == *o as i32)) + } + (Value::Int(IntValue(s)), Value::Short(ShortValue(o))) => { + Value::Boolean(BooleanValue(*s == *o as i32)) + } + (Value::Int(IntValue(s)), Value::Int(IntValue(o))) => { + Value::Boolean(BooleanValue(*s == *o)) + } + (Value::Int(IntValue(s)), Value::Long(LongValue(o))) => { + Value::Boolean(BooleanValue(*s as i64 == *o)) + } + (Value::Long(LongValue(s)), Value::Byte(ByteValue(o))) => { + Value::Boolean(BooleanValue(*s == *o as i64)) + } + (Value::Long(LongValue(s)), Value::Short(ShortValue(o))) => { + Value::Boolean(BooleanValue(*s == *o as i64)) + } + (Value::Long(LongValue(s)), Value::Int(IntValue(o))) => { + Value::Boolean(BooleanValue(*s == *o as i64)) + } + (Value::Long(LongValue(s)), Value::Long(LongValue(o))) => { + Value::Boolean(BooleanValue(*s == *o)) + } + (Value::Message(MessageValue(s)), Value::Message(MessageValue(o))) => { + Value::Boolean(BooleanValue(*s == *o)) + } + _ => unimplemented!(), + } + } + fn neq(&self, other: &Value) -> Value { + match (self, other) { + (Value::Byte(ByteValue(s)), Value::Byte(ByteValue(o))) => { + Value::Boolean(BooleanValue(*s != *o)) + } + (Value::Byte(ByteValue(s)), Value::Short(ShortValue(o))) => { + Value::Boolean(BooleanValue(*s as i16 != *o)) + } + (Value::Byte(ByteValue(s)), Value::Int(IntValue(o))) => { + Value::Boolean(BooleanValue(*s as i32 != *o)) + } + (Value::Byte(ByteValue(s)), Value::Long(LongValue(o))) => { + Value::Boolean(BooleanValue(*s as i64 != *o)) + } + (Value::Short(ShortValue(s)), Value::Byte(ByteValue(o))) => { + Value::Boolean(BooleanValue(*s != *o as i16)) + } + (Value::Short(ShortValue(s)), Value::Short(ShortValue(o))) => { + Value::Boolean(BooleanValue(*s != *o)) + } + (Value::Short(ShortValue(s)), Value::Int(IntValue(o))) => { + Value::Boolean(BooleanValue(*s as i32 != *o)) + } + (Value::Short(ShortValue(s)), Value::Long(LongValue(o))) => { + Value::Boolean(BooleanValue(*s as i64 != *o)) + } + (Value::Int(IntValue(s)), Value::Byte(ByteValue(o))) => { + Value::Boolean(BooleanValue(*s != *o as i32)) + } + (Value::Int(IntValue(s)), Value::Short(ShortValue(o))) => { + Value::Boolean(BooleanValue(*s != *o as i32)) + } + (Value::Int(IntValue(s)), Value::Int(IntValue(o))) => { + Value::Boolean(BooleanValue(*s != *o)) + } + (Value::Int(IntValue(s)), Value::Long(LongValue(o))) => { + Value::Boolean(BooleanValue(*s as i64 != *o)) + } + (Value::Long(LongValue(s)), Value::Byte(ByteValue(o))) => { + Value::Boolean(BooleanValue(*s != *o as i64)) + } + (Value::Long(LongValue(s)), Value::Short(ShortValue(o))) => { + Value::Boolean(BooleanValue(*s != *o as i64)) + } + (Value::Long(LongValue(s)), Value::Int(IntValue(o))) => { + Value::Boolean(BooleanValue(*s != *o as i64)) + } + (Value::Long(LongValue(s)), Value::Long(LongValue(o))) => { + Value::Boolean(BooleanValue(*s != *o)) + } + (Value::Message(MessageValue(s)), Value::Message(MessageValue(o))) => { + Value::Boolean(BooleanValue(*s != *o)) + } + _ => unimplemented!(), + } + } + fn lt(&self, other: &Value) -> Value { + // TODO: match value directly (as done above) + assert!(!self.exact_type().array); + assert!(!other.exact_type().array); + match (self.exact_type().primitive, other.exact_type().primitive) { + (PrimitiveType::Byte, PrimitiveType::Byte) => { + Value::Boolean(BooleanValue(i8::from(self) < i8::from(other))) + } + (PrimitiveType::Byte, PrimitiveType::Short) => { + Value::Boolean(BooleanValue(i16::from(self) < i16::from(other))) + } + (PrimitiveType::Byte, PrimitiveType::Int) => { + Value::Boolean(BooleanValue(i32::from(self) < i32::from(other))) + } + (PrimitiveType::Byte, PrimitiveType::Long) => { + Value::Boolean(BooleanValue(i64::from(self) < i64::from(other))) + } + (PrimitiveType::Short, PrimitiveType::Byte) => { + Value::Boolean(BooleanValue(i16::from(self) < i16::from(other))) + } + (PrimitiveType::Short, PrimitiveType::Short) => { + Value::Boolean(BooleanValue(i16::from(self) < i16::from(other))) + } + (PrimitiveType::Short, PrimitiveType::Int) => { + Value::Boolean(BooleanValue(i32::from(self) < i32::from(other))) + } + (PrimitiveType::Short, PrimitiveType::Long) => { + Value::Boolean(BooleanValue(i64::from(self) < i64::from(other))) + } + (PrimitiveType::Int, PrimitiveType::Byte) => { + Value::Boolean(BooleanValue(i32::from(self) < i32::from(other))) + } + (PrimitiveType::Int, PrimitiveType::Short) => { + Value::Boolean(BooleanValue(i32::from(self) < i32::from(other))) + } + (PrimitiveType::Int, PrimitiveType::Int) => { + Value::Boolean(BooleanValue(i32::from(self) < i32::from(other))) + } + (PrimitiveType::Int, PrimitiveType::Long) => { + Value::Boolean(BooleanValue(i64::from(self) < i64::from(other))) + } + (PrimitiveType::Long, PrimitiveType::Byte) => { + Value::Boolean(BooleanValue(i64::from(self) < i64::from(other))) + } + (PrimitiveType::Long, PrimitiveType::Short) => { + Value::Boolean(BooleanValue(i64::from(self) < i64::from(other))) + } + (PrimitiveType::Long, PrimitiveType::Int) => { + Value::Boolean(BooleanValue(i64::from(self) < i64::from(other))) + } + (PrimitiveType::Long, PrimitiveType::Long) => { + Value::Boolean(BooleanValue(i64::from(self) < i64::from(other))) + } + _ => unimplemented!(), + } + } + fn lte(&self, other: &Value) -> Value { + assert!(!self.exact_type().array); + assert!(!other.exact_type().array); + match (self.exact_type().primitive, other.exact_type().primitive) { + (PrimitiveType::Byte, PrimitiveType::Byte) => { + Value::Boolean(BooleanValue(i8::from(self) <= i8::from(other))) + } + (PrimitiveType::Byte, PrimitiveType::Short) => { + Value::Boolean(BooleanValue(i16::from(self) <= i16::from(other))) + } + (PrimitiveType::Byte, PrimitiveType::Int) => { + Value::Boolean(BooleanValue(i32::from(self) <= i32::from(other))) + } + (PrimitiveType::Byte, PrimitiveType::Long) => { + Value::Boolean(BooleanValue(i64::from(self) <= i64::from(other))) + } + (PrimitiveType::Short, PrimitiveType::Byte) => { + Value::Boolean(BooleanValue(i16::from(self) <= i16::from(other))) + } + (PrimitiveType::Short, PrimitiveType::Short) => { + Value::Boolean(BooleanValue(i16::from(self) <= i16::from(other))) + } + (PrimitiveType::Short, PrimitiveType::Int) => { + Value::Boolean(BooleanValue(i32::from(self) <= i32::from(other))) + } + (PrimitiveType::Short, PrimitiveType::Long) => { + Value::Boolean(BooleanValue(i64::from(self) <= i64::from(other))) + } + (PrimitiveType::Int, PrimitiveType::Byte) => { + Value::Boolean(BooleanValue(i32::from(self) <= i32::from(other))) + } + (PrimitiveType::Int, PrimitiveType::Short) => { + Value::Boolean(BooleanValue(i32::from(self) <= i32::from(other))) + } + (PrimitiveType::Int, PrimitiveType::Int) => { + Value::Boolean(BooleanValue(i32::from(self) <= i32::from(other))) + } + (PrimitiveType::Int, PrimitiveType::Long) => { + Value::Boolean(BooleanValue(i64::from(self) <= i64::from(other))) + } + (PrimitiveType::Long, PrimitiveType::Byte) => { + Value::Boolean(BooleanValue(i64::from(self) <= i64::from(other))) + } + (PrimitiveType::Long, PrimitiveType::Short) => { + Value::Boolean(BooleanValue(i64::from(self) <= i64::from(other))) + } + (PrimitiveType::Long, PrimitiveType::Int) => { + Value::Boolean(BooleanValue(i64::from(self) <= i64::from(other))) + } + (PrimitiveType::Long, PrimitiveType::Long) => { + Value::Boolean(BooleanValue(i64::from(self) <= i64::from(other))) + } + _ => unimplemented!(), + } + } + fn gt(&self, other: &Value) -> Value { + assert!(!self.exact_type().array); + assert!(!other.exact_type().array); + match (self.exact_type().primitive, other.exact_type().primitive) { + (PrimitiveType::Byte, PrimitiveType::Byte) => { + Value::Boolean(BooleanValue(i8::from(self) > i8::from(other))) + } + (PrimitiveType::Byte, PrimitiveType::Short) => { + Value::Boolean(BooleanValue(i16::from(self) > i16::from(other))) + } + (PrimitiveType::Byte, PrimitiveType::Int) => { + Value::Boolean(BooleanValue(i32::from(self) > i32::from(other))) + } + (PrimitiveType::Byte, PrimitiveType::Long) => { + Value::Boolean(BooleanValue(i64::from(self) > i64::from(other))) + } + (PrimitiveType::Short, PrimitiveType::Byte) => { + Value::Boolean(BooleanValue(i16::from(self) > i16::from(other))) + } + (PrimitiveType::Short, PrimitiveType::Short) => { + Value::Boolean(BooleanValue(i16::from(self) > i16::from(other))) + } + (PrimitiveType::Short, PrimitiveType::Int) => { + Value::Boolean(BooleanValue(i32::from(self) > i32::from(other))) + } + (PrimitiveType::Short, PrimitiveType::Long) => { + Value::Boolean(BooleanValue(i64::from(self) > i64::from(other))) + } + (PrimitiveType::Int, PrimitiveType::Byte) => { + Value::Boolean(BooleanValue(i32::from(self) > i32::from(other))) + } + (PrimitiveType::Int, PrimitiveType::Short) => { + Value::Boolean(BooleanValue(i32::from(self) > i32::from(other))) + } + (PrimitiveType::Int, PrimitiveType::Int) => { + Value::Boolean(BooleanValue(i32::from(self) > i32::from(other))) + } + (PrimitiveType::Int, PrimitiveType::Long) => { + Value::Boolean(BooleanValue(i64::from(self) > i64::from(other))) + } + (PrimitiveType::Long, PrimitiveType::Byte) => { + Value::Boolean(BooleanValue(i64::from(self) > i64::from(other))) + } + (PrimitiveType::Long, PrimitiveType::Short) => { + Value::Boolean(BooleanValue(i64::from(self) > i64::from(other))) + } + (PrimitiveType::Long, PrimitiveType::Int) => { + Value::Boolean(BooleanValue(i64::from(self) > i64::from(other))) + } + (PrimitiveType::Long, PrimitiveType::Long) => { + Value::Boolean(BooleanValue(i64::from(self) > i64::from(other))) + } + _ => unimplemented!(), + } + } + fn gte(&self, other: &Value) -> Value { + assert!(!self.exact_type().array); + assert!(!other.exact_type().array); + match (self.exact_type().primitive, other.exact_type().primitive) { + (PrimitiveType::Byte, PrimitiveType::Byte) => { + Value::Boolean(BooleanValue(i8::from(self) >= i8::from(other))) + } + (PrimitiveType::Byte, PrimitiveType::Short) => { + Value::Boolean(BooleanValue(i16::from(self) >= i16::from(other))) + } + (PrimitiveType::Byte, PrimitiveType::Int) => { + Value::Boolean(BooleanValue(i32::from(self) >= i32::from(other))) + } + (PrimitiveType::Byte, PrimitiveType::Long) => { + Value::Boolean(BooleanValue(i64::from(self) >= i64::from(other))) + } + (PrimitiveType::Short, PrimitiveType::Byte) => { + Value::Boolean(BooleanValue(i16::from(self) >= i16::from(other))) + } + (PrimitiveType::Short, PrimitiveType::Short) => { + Value::Boolean(BooleanValue(i16::from(self) >= i16::from(other))) + } + (PrimitiveType::Short, PrimitiveType::Int) => { + Value::Boolean(BooleanValue(i32::from(self) >= i32::from(other))) + } + (PrimitiveType::Short, PrimitiveType::Long) => { + Value::Boolean(BooleanValue(i64::from(self) >= i64::from(other))) + } + (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 for Value { + fn from(b: bool) -> Self { + Value::Boolean(BooleanValue(b)) + } +} +impl From 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 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 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 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 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::Unassigned => Type::UNASSIGNED, + 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, h: &Heap, t: &[ParserTypeElement]) -> bool { + match self { + Value::Unassigned => true, + Value::Input(_) => InputValue::is_type_compatible_hack(h, t), + Value::Output(_) => OutputValue::is_type_compatible_hack(h, t), + Value::Message(_) => MessageValue::is_type_compatible_hack(h, t), + Value::Boolean(_) => BooleanValue::is_type_compatible_hack(h, t), + Value::Byte(_) => ByteValue::is_type_compatible_hack(h, t), + Value::Short(_) => ShortValue::is_type_compatible_hack(h, t), + Value::Int(_) => IntValue::is_type_compatible_hack(h, t), + Value::Long(_) => LongValue::is_type_compatible_hack(h, t), + Value::InputArray(_) => InputArrayValue::is_type_compatible_hack(h, t), + Value::OutputArray(_) => OutputArrayValue::is_type_compatible_hack(h, t), + Value::MessageArray(_) => MessageArrayValue::is_type_compatible_hack(h, t), + Value::BooleanArray(_) => BooleanArrayValue::is_type_compatible_hack(h, t), + Value::ByteArray(_) => ByteArrayValue::is_type_compatible_hack(h, t), + Value::ShortArray(_) => ShortArrayValue::is_type_compatible_hack(h, t), + Value::IntArray(_) => InputArrayValue::is_type_compatible_hack(h, t), + Value::LongArray(_) => LongArrayValue::is_type_compatible_hack(h, t), + } + } + fn is_type_compatible_hack(_h: &Heap, _t: &[ParserTypeElement]) -> bool { false } +} + +impl Display for Value { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + let disp: &dyn Display; + match self { + Value::Unassigned => disp = &Type::UNASSIGNED, + 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 PortId); + +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_hack(_h: &Heap, t: &[ParserTypeElement]) -> bool { + use ParserTypeVariant::*; + match &t[0].variant { + Input | Inferred | Definition(_, _) => true, + _ => false, + } + } +} + +#[derive(Debug, Clone)] +pub struct OutputValue(pub PortId); + +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_hack(_h: &Heap, t: &[ParserTypeElement]) -> bool { + use ParserTypeVariant::*; + match &t[0].variant { + Output | Inferred | Definition(_, _) => true, + _ => false, + } + } +} + +#[derive(Debug, Clone)] +pub struct MessageValue(pub Option); + +impl Display for MessageValue { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + match &self.0 { + None => write!(f, "null"), + Some(payload) => { + // format print up to 10 bytes + let mut slice = payload.as_slice(); + if slice.len() > 10 { + slice = &slice[..10]; + } + f.debug_list().entries(slice.iter().copied()).finish() + } + } + } +} + +impl ValueImpl for MessageValue { + fn exact_type(&self) -> Type { + Type::MESSAGE + } + fn is_type_compatible_hack(_h: &Heap, t: &[ParserTypeElement]) -> bool { + use ParserTypeVariant::*; + match &t[0].variant { + Message | Inferred | Definition(_, _) => 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_hack(_h: &Heap, t: &[ParserTypeElement]) -> bool { + use ParserTypeVariant::*; + match &t[0].variant { + Definition(_, _) | Inferred | Bool | + UInt8 | UInt16 | UInt32 | UInt64 | + SInt8 | SInt16 | SInt32 | SInt64 => 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_hack(_h: &Heap, t: &[ParserTypeElement]) -> bool { + use ParserTypeVariant::*; + match &t[0].variant { + Definition(_, _) | Inferred | + UInt8 | UInt16 | UInt32 | UInt64 | + SInt8 | SInt16 | SInt32 | SInt64 => 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_hack(_h: &Heap, t: &[ParserTypeElement]) -> bool { + use ParserTypeVariant::*; + match &t[0].variant { + Definition(_, _) | Inferred | + UInt16 | UInt32 | UInt64 | + SInt16 | SInt32 | SInt64=> 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_hack(_h: &Heap, t: &[ParserTypeElement]) -> bool { + use ParserTypeVariant::*; + match t[0].variant { + Definition(_, _) | Inferred | + UInt32 | UInt64 | + SInt32 | SInt64 => 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_hack(_h: &Heap, t: &[ParserTypeElement]) -> bool { + use ParserTypeVariant::*; + match &t[0].variant { + UInt64 | SInt64 | Inferred | Definition(_, _) => true, + _ => false, + } + } +} + +fn get_array_inner(t: &[ParserTypeElement]) -> Option<&[ParserTypeElement]> { + if t[0].variant == ParserTypeVariant::Array { + return Some(&t[1..]) + } else { + return None; + } +} + +#[derive(Debug, Clone)] +pub struct InputArrayValue(Vec); + +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_hack(h: &Heap, t: &[ParserTypeElement]) -> bool { + get_array_inner(t) + .map(|v| InputValue::is_type_compatible_hack(h, v)) + .unwrap_or(false) + } +} + +#[derive(Debug, Clone)] +pub struct OutputArrayValue(Vec); + +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_hack(h: &Heap, t: &[ParserTypeElement]) -> bool { + get_array_inner(t) + .map(|v| OutputValue::is_type_compatible_hack(h, v)) + .unwrap_or(false) + } +} + +#[derive(Debug, Clone)] +pub struct MessageArrayValue(Vec); + +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_hack(h: &Heap, t: &[ParserTypeElement]) -> bool { + get_array_inner(t) + .map(|v| MessageValue::is_type_compatible_hack(h, v)) + .unwrap_or(false) + } +} + +#[derive(Debug, Clone)] +pub struct BooleanArrayValue(Vec); + +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_hack(h: &Heap, t: &[ParserTypeElement]) -> bool { + get_array_inner(t) + .map(|v| BooleanValue::is_type_compatible_hack(h, v)) + .unwrap_or(false) + } +} + +#[derive(Debug, Clone)] +pub struct ByteArrayValue(Vec); + +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_hack(h: &Heap, t: &[ParserTypeElement]) -> bool { + get_array_inner(t) + .map(|v| ByteValue::is_type_compatible_hack(h, v)) + .unwrap_or(false) + } +} + +#[derive(Debug, Clone)] +pub struct ShortArrayValue(Vec); + +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_hack(h: &Heap, t: &[ParserTypeElement]) -> bool { + get_array_inner(t) + .map(|v| ShortValue::is_type_compatible_hack(h, v)) + .unwrap_or(false) + } +} + +#[derive(Debug, Clone)] +pub struct IntArrayValue(Vec); + +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_hack(h: &Heap, t: &[ParserTypeElement]) -> bool { + get_array_inner(t) + .map(|v| IntValue::is_type_compatible_hack(h, v)) + .unwrap_or(false) + } +} + +#[derive(Debug, Clone)] +pub struct LongArrayValue(Vec); + +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_hack(h: &Heap, t: &[ParserTypeElement]) -> bool { + get_array_inner(t) + .map(|v| LongValue::is_type_compatible_hack(h, v)) + .unwrap_or(false) + } +} + +#[derive(Debug, Clone)] +struct Store { + map: HashMap, +} +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 parser_type = match &h[var] { + Variable::Local(v) => &v.parser_type, + Variable::Parameter(v) => &v.parser_type, + }; + assert!(value.is_type_compatible(h, &parser_type.elements)); + // 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 parser_type = match &h[var] { + Variable::Local(v) => &v.parser_type, + Variable::Parameter(v) => &v.parser_type + }; + assert!(value.is_type_compatible(h, &parser_type.elements)); + // Overwrite mapping + self.map.insert(var, value.clone()); + Ok(value) + } + Expression::Indexing(indexing) => { + // Evaluate index expression, which must be some integral type + let index = self.eval(h, ctx, indexing.index)?; + // Mutable reference to the subject + let subject; + match &h[indexing.subject] { + Expression::Variable(var) => { + let var = var.declaration.unwrap(); + subject = self.map.get_mut(&var).unwrap(); + } + _ => unreachable!(), + } + match subject.set(&index, &value) { + Some(value) => Ok(value), + None => Err(EvalContinuation::Inconsistent), + } + } + _ => unimplemented!("{:?}", h[lexpr]), + } + } + fn get(&mut self, h: &Heap, ctx: &mut EvalContext, rexpr: ExpressionId) -> EvalResult { + match &h[rexpr] { + Expression::Variable(var) => { + let var_id = var.declaration.unwrap(); + let value = self + .map + .get(&var_id) + .expect(&format!("Uninitialized variable {:?}", var.identifier.value.as_str())); + 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(); + } + q => unreachable!("Reached {:?}", q), + } + 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(); + } + q => unreachable!("Reached {:?}", q), + } + match subject.length() { + Some(value) => Ok(value), + None => Err(EvalContinuation::Inconsistent), + } + } + _ => unimplemented!("{:?}", h[rexpr]), + } + } + fn eval(&mut self, h: &Heap, ctx: &mut EvalContext, expr: ExpressionId) -> EvalResult { + match &h[expr] { + Expression::Assignment(expr) => { + let value = self.eval(h, ctx, expr.right)?; + match expr.operation { + AssignmentOperator::Set => { + self.update(h, ctx, expr.left, value.clone())?; + } + AssignmentOperator::Added => { + let old = self.get(h, ctx, expr.left)?; + self.update(h, ctx, expr.left, old.plus(&value))?; + } + AssignmentOperator::Subtracted => { + let old = self.get(h, ctx, expr.left)?; + self.update(h, ctx, expr.left, old.minus(&value))?; + } + _ => unimplemented!("{:?}", expr), + } + Ok(value) + } + Expression::Binding(_expr) => { + unimplemented!("eval binding expression"); + } + 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; + match expr.operation { + BinaryOperator::LogicalAnd => { + if left.as_boolean().0 == false { + return Ok(left); + } + right = self.eval(h, ctx, expr.right)?; + right.as_boolean(); // panics if not a boolean + return Ok(right); + } + BinaryOperator::LogicalOr => { + if left.as_boolean().0 == true { + return Ok(left); + } + right = self.eval(h, ctx, expr.right)?; + right.as_boolean(); // panics if not a boolean + return Ok(right); + } + _ => {} + } + right = self.eval(h, ctx, expr.right)?; + match expr.operation { + BinaryOperator::Equality => Ok(left.eq(&right)), + BinaryOperator::Inequality => Ok(left.neq(&right)), + BinaryOperator::LessThan => Ok(left.lt(&right)), + BinaryOperator::LessThanEqual => Ok(left.lte(&right)), + BinaryOperator::GreaterThan => Ok(left.gt(&right)), + BinaryOperator::GreaterThanEqual => Ok(left.gte(&right)), + BinaryOperator::Remainder => Ok(left.modulus(&right)), + BinaryOperator::Add => Ok(left.plus(&right)), + _ => unimplemented!("{:?}", expr.operation), + } + } + Expression::Unary(expr) => { + let mut value = self.eval(h, ctx, expr.expression)?; + match expr.operation { + UnaryOperator::PostIncrement => { + self.update(h, ctx, expr.expression, value.plus(&ONE))?; + } + UnaryOperator::PreIncrement => { + value = value.plus(&ONE); + self.update(h, ctx, expr.expression, value.clone())?; + } + UnaryOperator::PostDecrement => { + self.update(h, ctx, expr.expression, value.minus(&ONE))?; + } + UnaryOperator::PreDecrement => { + value = value.minus(&ONE); + self.update(h, ctx, expr.expression, value.clone())?; + } + _ => unimplemented!(), + } + Ok(value) + } + Expression::Indexing(expr) => self.get(h, ctx, expr.this.upcast()), + Expression::Slicing(_expr) => unimplemented!(), + Expression::Select(expr) => self.get(h, ctx, expr.this.upcast()), + Expression::Literal(expr) => Ok(Value::from_constant(&expr.value)), + Expression::Call(expr) => match &expr.method { + 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::Put => { + assert_eq!(2, expr.arguments.len()); + let port_value = self.eval(h, ctx, expr.arguments[0])?; + let msg_value = self.eval(h, ctx, expr.arguments[1])?; + if ctx.did_put(port_value.clone()) { + // Return bogus, replacing this at some point anyway + Ok(Value::Message(MessageValue(None))) + } else { + Err(EvalContinuation::Put(port_value, msg_value)) + } + } + 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::Create => { + assert_eq!(1, expr.arguments.len()); + let length = self.eval(h, ctx, expr.arguments[0])?; + Ok(Value::create_message(length)) + }, + Method::Length => { + todo!("implement") + }, + Method::Assert => { + let value = self.eval(h, ctx, expr.arguments[0])?; + if value.as_boolean().0 { + // Return bogus + Ok(Value::Unassigned) + } else { + // Failed assertion + Err(EvalContinuation::Inconsistent) + } + }, + Method::UserFunction => unimplemented!(), + Method::UserComponent => unreachable!(), + }, + Expression::Variable(expr) => self.get(h, ctx, expr.this.upcast()), + } + } +} + +type EvalResult = Result; +pub enum EvalContinuation { + Stepping, + Inconsistent, + Terminal, + SyncBlockStart, + SyncBlockEnd, + NewComponent(DefinitionId, Vec), + BlockFires(Value), + BlockGet(Value), + Put(Value, Value), +} + +#[derive(Debug, Clone)] +pub(crate) struct Prompt { + definition: DefinitionId, + store: Store, + position: Option, +} + +impl Prompt { + pub fn new(h: &Heap, def: DefinitionId, args: &Vec) -> Self { + let mut prompt = + Prompt { definition: def, store: Store::new(), position: Some((&h[def]).body().upcast()) }; + prompt.set_arguments(h, args); + prompt + } + fn set_arguments(&mut self, h: &Heap, args: &Vec) { + 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]; + assert!(value.is_type_compatible(h, &hparam.parser_type.elements)); + 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) => { + // Update store + self.store.initialize(h, stmt.variable.upcast(), Value::Unassigned); + } + 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::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.upcast()); + } else if let Some(false_body) = stmt.false_body { + self.position = Some(false_body.upcast()); + } else { + // No false body + self.position = Some(stmt.end_if.unwrap().upcast()); + } + 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.upcast()); + } else { + self.position = stmt.end_while.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.upcast()); + 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::Return(stmt) => { + // Evaluate expression + debug_assert_eq!(stmt.expressions.len(), 1); + let value = self.store.eval(h, ctx, stmt.expressions[0])?; + // 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; + match &expr.method { + Method::UserComponent => { + Err(EvalContinuation::NewComponent(expr.definition, args)) + }, + _ => unreachable!("not a symbolic call expression") + } + } + 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) -> Option { + // 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 = 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); +// } +// }