use std::collections::HashMap;
use std::fmt::{Display, Formatter, Result as FResult};
use brane_ast::SymTable;
use brane_ast::data_type::DataType;
use brane_ast::func_id::FunctionId;
use brane_ast::spec::BuiltinClasses;
use serde::de::Visitor;
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use serde_json::Value as JValue;
pub use crate::errors::ValueError as Error;
#[cfg(test)]
mod tests {
use super::*;
fn assert_eq_unordered(ser: Result<String, serde_json::Error>, name: String, fields: [String; 3]) {
let ser: String = match ser {
Ok(ser) => ser,
Err(err) => {
panic!("Serialization failed with error: {err}");
},
};
if ser == format!("[\"{}\",{{{},{},{}}}]", name, fields[0], fields[1], fields[2]) {
return;
}
if ser == format!("[\"{}\",{{{},{},{}}}]", name, fields[0], fields[2], fields[1]) {
return;
}
if ser == format!("[\"{}\",{{{},{},{}}}]", name, fields[1], fields[0], fields[2]) {
return;
}
if ser == format!("[\"{}\",{{{},{},{}}}]", name, fields[1], fields[2], fields[0]) {
return;
}
if ser == format!("[\"{}\",{{{},{},{}}}]", name, fields[2], fields[0], fields[1]) {
return;
}
if ser == format!("[\"{}\",{{{},{},{}}}]", name, fields[2], fields[1], fields[0]) {
return;
}
panic!("Map serialization was not as expected:\nleft : `{}`\nright : `[\"{}\",{{{},{},{}}}]`\n", ser, name, fields[0], fields[1], fields[2]);
}
#[test]
fn test_fullvalue_serialize() {
assert_eq!(serde_json::to_string(&FullValue::Boolean(true)).ok(), Some("true".into()));
assert_eq!(serde_json::to_string(&FullValue::Boolean(false)).ok(), Some("false".into()));
assert_eq!(serde_json::to_string(&FullValue::Integer(0)).ok(), Some("0".into()));
assert_eq!(serde_json::to_string(&FullValue::Integer(42)).ok(), Some("42".into()));
assert_eq!(serde_json::to_string(&FullValue::Integer(-42)).ok(), Some("-42".into()));
assert_eq!(serde_json::to_string(&FullValue::Integer(i64::MAX)).ok(), Some(format!("{}", i64::MAX)));
assert_eq!(serde_json::to_string(&FullValue::Integer(i64::MIN)).ok(), Some(format!("{}", i64::MIN)));
assert_eq!(serde_json::to_string(&FullValue::Real(0.0)).ok(), Some("0.0".into()));
assert_eq!(serde_json::to_string(&FullValue::Real(0.42)).ok(), Some("0.42".into()));
assert_eq!(serde_json::to_string(&FullValue::Real(-0.42)).ok(), Some("-0.42".into()));
assert_eq!(serde_json::to_string(&FullValue::Real(12345.6789)).ok(), Some("12345.6789".into()));
assert_eq!(serde_json::to_string(&FullValue::Real(-12345.6789)).ok(), Some("-12345.6789".into()));
assert_eq!(serde_json::to_string(&FullValue::Real(f64::MAX)).ok(), Some("1.7976931348623157e308".into()));
assert_eq!(serde_json::to_string(&FullValue::Real(f64::MIN)).ok(), Some("-1.7976931348623157e308".into()));
assert_eq!(serde_json::to_string(&FullValue::String("Hello, world!".into())).ok(), Some("\"Hello, world!\"".into()));
assert_eq!(
serde_json::to_string(&FullValue::String("Epic \" nested \" quotes".into())).ok(),
Some("\"Epic \\\" nested \\\" quotes\"".into())
);
assert_eq!(serde_json::to_string(&FullValue::String("true".into())).ok(), Some("\"true\"".into()));
assert_eq!(serde_json::to_string(&FullValue::String("42".into())).ok(), Some("\"42\"".into()));
assert_eq!(serde_json::to_string(&FullValue::String("42.0".into())).ok(), Some("\"42.0\"".into()));
assert_eq!(serde_json::to_string(&FullValue::Array(vec![])).ok(), Some("[]".into()));
assert_eq!(serde_json::to_string(&FullValue::Array(vec![FullValue::Integer(42)])).ok(), Some("[42]".into()));
assert_eq!(
serde_json::to_string(&FullValue::Array(vec![FullValue::Integer(42), FullValue::Integer(-42), FullValue::Integer(i64::MAX)])).ok(),
Some(format!("[42,-42,{}]", i64::MAX))
);
assert_eq!(
serde_json::to_string(&FullValue::Array(vec![FullValue::String("42".into()), FullValue::Integer(-42), FullValue::Real(-12345.6789)]))
.ok(),
Some("[\"42\",-42,-12345.6789]".into())
);
assert_eq!(
serde_json::to_string(&FullValue::Array(vec![
FullValue::Array(vec![FullValue::Integer(1), FullValue::Integer(2), FullValue::Integer(3)]),
FullValue::Array(vec![FullValue::Integer(4), FullValue::Integer(5), FullValue::Integer(6)]),
FullValue::Array(vec![FullValue::Integer(7), FullValue::Integer(8), FullValue::Integer(9)]),
]))
.ok(),
Some("[[1,2,3],[4,5,6],[7,8,9]]".into())
);
assert_eq!(serde_json::to_string(&FullValue::Instance("Test".into(), HashMap::from([]))).ok(), Some("[\"Test\",{}]".into()));
assert_eq!(
serde_json::to_string(&FullValue::Instance("Test".into(), HashMap::from([("one".into(), FullValue::Integer(42))]))).ok(),
Some("[\"Test\",{\"one\":42}]".into())
);
assert_eq_unordered(
serde_json::to_string(&FullValue::Instance(
"Test".into(),
HashMap::from([
("one".into(), FullValue::Integer(42)),
("two".into(), FullValue::Integer(-42)),
("three".into(), FullValue::Integer(i64::MAX)),
]),
)),
"Test".into(),
["\"one\":42".into(), "\"two\":-42".into(), format!("\"three\":{}", i64::MAX)],
);
assert_eq_unordered(
serde_json::to_string(&FullValue::Instance(
"Test".into(),
HashMap::from([
("one".into(), FullValue::String("42".into())),
("two".into(), FullValue::Integer(-42)),
("three".into(), FullValue::Real(-12345.6789)),
]),
)),
"Test".into(),
["\"one\":\"42\"".into(), "\"two\":-42".into(), "\"three\":-12345.6789".into()],
);
assert_eq_unordered(
serde_json::to_string(&FullValue::Instance(
"Test".into(),
HashMap::from([
("one".into(), FullValue::Array(vec![FullValue::Integer(1), FullValue::Integer(2), FullValue::Integer(3)])),
("two".into(), FullValue::Instance("TestNested".into(), HashMap::from([("one".into(), FullValue::Integer(42))]))),
(
"three".into(),
FullValue::Array(vec![
FullValue::Instance("TestNested1".into(), HashMap::from([("one".into(), FullValue::Integer(1))])),
FullValue::Instance("TestNested2".into(), HashMap::from([("two".into(), FullValue::Integer(2))])),
FullValue::Instance("TestNested3".into(), HashMap::from([("three".into(), FullValue::Integer(3))])),
]),
),
]),
)),
"Test".into(),
[
"\"one\":[1,2,3]".into(),
"\"two\":[\"TestNested\",{\"one\":42}]".into(),
"\"three\":[[\"TestNested1\",{\"one\":1}],[\"TestNested2\",{\"two\":2}],[\"TestNested3\",{\"three\":3}]]".into(),
],
);
assert_eq!(serde_json::to_string(&FullValue::Data("testset".into())).ok(), Some("\"Data<testset>\"".into()));
assert_eq!(serde_json::to_string(&FullValue::Void).ok(), Some("null".into()));
}
#[test]
fn test_fullvalue_deserialize() {
assert_eq!(serde_json::from_str::<FullValue>("true").unwrap_or_else(|err| panic!("{}", err)), FullValue::Boolean(true));
assert_eq!(serde_json::from_str::<FullValue>("false").unwrap_or_else(|err| panic!("{}", err)), FullValue::Boolean(false));
assert_eq!(serde_json::from_str::<FullValue>("0").unwrap_or_else(|err| panic!("{}", err)), FullValue::Integer(0));
assert_eq!(serde_json::from_str::<FullValue>("42").unwrap_or_else(|err| panic!("{}", err)), FullValue::Integer(42));
assert_eq!(serde_json::from_str::<FullValue>("-42").unwrap_or_else(|err| panic!("{}", err)), FullValue::Integer(-42));
assert_eq!(serde_json::from_str::<FullValue>(&format!("{}", i64::MAX)).unwrap_or_else(|err| panic!("{}", err)), FullValue::Integer(i64::MAX));
assert_eq!(serde_json::from_str::<FullValue>(&format!("{}", i64::MIN)).unwrap_or_else(|err| panic!("{}", err)), FullValue::Integer(i64::MIN));
assert_eq!(serde_json::from_str::<FullValue>("0.0").unwrap_or_else(|err| panic!("{}", err)), FullValue::Real(0.0));
assert_eq!(serde_json::from_str::<FullValue>("42.0").unwrap_or_else(|err| panic!("{}", err)), FullValue::Real(42.0));
assert_eq!(serde_json::from_str::<FullValue>("-42.0").unwrap_or_else(|err| panic!("{}", err)), FullValue::Real(-42.0));
assert_eq!(serde_json::from_str::<FullValue>("0.42").unwrap_or_else(|err| panic!("{}", err)), FullValue::Real(0.42));
assert_eq!(serde_json::from_str::<FullValue>("-0.42").unwrap_or_else(|err| panic!("{}", err)), FullValue::Real(-0.42));
assert_eq!(serde_json::from_str::<FullValue>("1.7976931348623157e308").unwrap_or_else(|err| panic!("{}", err)), FullValue::Real(f64::MAX));
assert_eq!(serde_json::from_str::<FullValue>("-1.7976931348623157e308").unwrap_or_else(|err| panic!("{}", err)), FullValue::Real(f64::MIN));
assert_eq!(
serde_json::from_str::<FullValue>("\"Hello, world!\"").unwrap_or_else(|err| panic!("{}", err)),
FullValue::String("Hello, world!".into())
);
assert_eq!(
serde_json::from_str::<FullValue>("\"Epic \\\" nested \\\" quotes\"").unwrap_or_else(|err| panic!("{}", err)),
FullValue::String("Epic \" nested \" quotes".into())
);
assert_eq!(serde_json::from_str::<FullValue>("\"true\"").unwrap_or_else(|err| panic!("{}", err)), FullValue::String("true".into()));
assert_eq!(serde_json::from_str::<FullValue>("\"42\"").unwrap_or_else(|err| panic!("{}", err)), FullValue::String("42".into()));
assert_eq!(serde_json::from_str::<FullValue>("\"42.0\"").unwrap_or_else(|err| panic!("{}", err)), FullValue::String("42.0".into()));
assert_eq!(serde_json::from_str::<FullValue>("[]").unwrap_or_else(|err| panic!("{}", err)), FullValue::Array(vec![]));
assert_eq!(serde_json::from_str::<FullValue>("[42]").unwrap_or_else(|err| panic!("{}", err)), FullValue::Array(vec![FullValue::Integer(42)]));
assert_eq!(
serde_json::from_str::<FullValue>(&format!("[42, -42, {}]", i64::MAX)).unwrap_or_else(|err| panic!("{}", err)),
FullValue::Array(vec![FullValue::Integer(42), FullValue::Integer(-42), FullValue::Integer(i64::MAX)])
);
assert_eq!(
serde_json::from_str::<FullValue>("[\"42\",-42,-12345.6789]").unwrap_or_else(|err| panic!("{}", err)),
FullValue::Array(vec![FullValue::String("42".into()), FullValue::Integer(-42), FullValue::Real(-12345.6789)])
);
assert_eq!(
serde_json::from_str::<FullValue>("[[1,2,3],[4,5,6],[7,8,9]]").unwrap_or_else(|err| panic!("{}", err)),
FullValue::Array(vec![
FullValue::Array(vec![FullValue::Integer(1), FullValue::Integer(2), FullValue::Integer(3)]),
FullValue::Array(vec![FullValue::Integer(4), FullValue::Integer(5), FullValue::Integer(6)]),
FullValue::Array(vec![FullValue::Integer(7), FullValue::Integer(8), FullValue::Integer(9)]),
])
);
assert_eq!(
serde_json::from_str::<FullValue>("[\"Test\",{}]").unwrap_or_else(|err| panic!("{}", err)),
FullValue::Instance("Test".into(), HashMap::from([]))
);
assert_eq!(
serde_json::from_str::<FullValue>("[\"Test\",{\"one\":42}]").unwrap_or_else(|err| panic!("{}", err)),
FullValue::Instance("Test".into(), HashMap::from([("one".into(), FullValue::Integer(42))]))
);
assert_eq!(
serde_json::from_str::<FullValue>(&format!("[\"Test\",{{\"one\":42,\"two\":-42,\"three\":{}}}]", i64::MAX))
.unwrap_or_else(|err| panic!("{}", err)),
FullValue::Instance(
"Test".into(),
HashMap::from([
("one".into(), FullValue::Integer(42)),
("two".into(), FullValue::Integer(-42)),
("three".into(), FullValue::Integer(i64::MAX))
])
)
);
assert_eq!(
serde_json::from_str::<FullValue>("[\"Test\",{\"one\":\"42\",\"two\":-42,\"three\":-12345.6789}]")
.unwrap_or_else(|err| panic!("{}", err)),
FullValue::Instance(
"Test".into(),
HashMap::from([
("one".into(), FullValue::String("42".into())),
("two".into(), FullValue::Integer(-42)),
("three".into(), FullValue::Real(-12345.6789))
])
)
);
assert_eq!(
serde_json::from_str::<FullValue>(
"[\"Test\",{\"one\":[1,2,3],\"two\":[\"TestNested\",{\"one\":42}],\"three\":[[\"TestNested1\",{\"one\":1}],[\"TestNested2\",{\"two\"\
:2}],[\"TestNested3\",{\"three\":3}]]}]"
)
.unwrap_or_else(|err| panic!("{}", err)),
FullValue::Instance(
"Test".into(),
HashMap::from([
("one".into(), FullValue::Array(vec![FullValue::Integer(1), FullValue::Integer(2), FullValue::Integer(3)])),
("two".into(), FullValue::Instance("TestNested".into(), HashMap::from([("one".into(), FullValue::Integer(42))]))),
(
"three".into(),
FullValue::Array(vec![
FullValue::Instance("TestNested1".into(), HashMap::from([("one".into(), FullValue::Integer(1))])),
FullValue::Instance("TestNested2".into(), HashMap::from([("two".into(), FullValue::Integer(2))])),
FullValue::Instance("TestNested3".into(), HashMap::from([("three".into(), FullValue::Integer(3))])),
])
),
])
)
);
assert_eq!(serde_json::from_str::<FullValue>("\"Data<testset>\"").unwrap_or_else(|err| panic!("{}", err)), FullValue::Data("testset".into()));
assert_eq!(serde_json::from_str::<FullValue>("null").unwrap_or_else(|err| panic!("{}", err)), FullValue::Void);
}
}
struct DataIdVisitor;
impl<'de> Visitor<'de> for DataIdVisitor {
type Value = DataId;
fn expecting(&self, f: &mut Formatter<'_>) -> FResult { write!(f, "Data identifier") }
fn visit_str<E: serde::de::Error>(self, value: &str) -> Result<Self::Value, E> {
if value.len() < 5 || &value[..5] != "Data<" || &value[value.len() - 1..] != ">" {
return Err(E::custom("given string does not start with 'Data<'"));
}
Ok(DataId(value[5..value.len() - 1].into()))
}
}
struct ResultIdVisitor;
impl<'de> Visitor<'de> for ResultIdVisitor {
type Value = ResultId;
fn expecting(&self, f: &mut Formatter<'_>) -> FResult { write!(f, "Result identifier") }
fn visit_str<E: serde::de::Error>(self, value: &str) -> Result<Self::Value, E> {
if value.len() < 19 || &value[..19] != "IntermediateResult<" || &value[value.len() - 1..] != ">" {
return Err(E::custom("given string does not start with 'IntermediateResult<'"));
}
Ok(ResultId(value[19..value.len() - 1].into()))
}
}
#[derive(Debug)]
pub struct ValueDisplay<'a, 'b> {
value: &'a Value,
table: &'b SymTable,
}
impl<'a, 'b> Display for ValueDisplay<'a, 'b> {
#[inline]
fn fmt(&self, f: &mut Formatter<'_>) -> FResult {
use Value::*;
match self.value {
Boolean { value } => write!(f, "{value}"),
Integer { value } => write!(f, "{value}"),
Real { value } => write!(f, "{value}"),
String { value } => write!(f, "{value}"),
Array { values } => {
write!(f, "[{}]", values.iter().map(|v| format!("{}", v.display(self.table))).collect::<Vec<std::string::String>>().join(", "))
},
Function { def } => write!(
f,
"{}({}) -> {}",
self.table.func(FunctionId::Func(*def)).name,
self.table.func(FunctionId::Func(*def)).args.iter().map(|a| format!("{a}")).collect::<Vec<std::string::String>>().join(","),
self.table.func(FunctionId::Func(*def)).ret
),
Instance { values, def } => write!(
f,
"{} {{{}{}{}}}",
self.table.class(*def).name,
if values.is_empty() { "" } else { " " },
values.iter().map(|(n, v)| format!("{} := {}", n, v.display(self.table))).collect::<Vec<std::string::String>>().join(", "),
if values.is_empty() { "" } else { " " },
),
Method { cdef, fdef, .. } => write!(
f,
"{}::{}({}) -> {}",
self.table.class(*cdef).name,
self.table.func(FunctionId::Func(*fdef)).name,
self.table.func(FunctionId::Func(*fdef)).args.iter().map(|a| format!("{a}")).collect::<Vec<std::string::String>>().join(","),
self.table.func(FunctionId::Func(*fdef)).ret
),
Data { name } => write!(f, "Data<{name}>"),
IntermediateResult { name } => write!(f, "IntermediateResult<{name}>"),
Void => write!(f, "()"),
}
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct DataId(String);
impl Display for DataId {
#[inline]
fn fmt(&self, f: &mut Formatter<'_>) -> FResult { write!(f, "{}", self.0) }
}
impl Serialize for DataId {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> { serializer.serialize_str(&format!("Data<{}>", self.0)) }
}
impl<'de> Deserialize<'de> for DataId {
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> { deserializer.deserialize_str(DataIdVisitor) }
}
impl AsRef<str> for DataId {
fn as_ref(&self) -> &str { self.0.as_str() }
}
impl From<String> for DataId {
#[inline]
fn from(value: String) -> Self { Self(value) }
}
impl From<&String> for DataId {
#[inline]
fn from(value: &String) -> Self { Self::from(value.clone()) }
}
impl From<&mut String> for DataId {
fn from(value: &mut String) -> Self { Self::from(value.as_str()) }
}
impl From<&str> for DataId {
#[inline]
fn from(value: &str) -> Self { Self::from(value.to_string()) }
}
impl From<DataId> for String {
#[inline]
fn from(value: DataId) -> Self { value.0 }
}
impl From<&DataId> for String {
#[inline]
fn from(value: &DataId) -> Self { value.0.clone() }
}
impl From<&mut DataId> for String {
#[inline]
fn from(value: &mut DataId) -> Self { value.0.clone() }
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct ResultId(String);
impl Display for ResultId {
#[inline]
fn fmt(&self, f: &mut Formatter<'_>) -> FResult { write!(f, "{}", self.0) }
}
impl Serialize for ResultId {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
serializer.serialize_str(&format!("IntermediateResult<{}>", self.0))
}
}
impl<'de> Deserialize<'de> for ResultId {
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> { deserializer.deserialize_str(ResultIdVisitor) }
}
impl AsRef<str> for ResultId {
fn as_ref(&self) -> &str { self.0.as_str() }
}
impl From<String> for ResultId {
#[inline]
fn from(value: String) -> Self { Self(value) }
}
impl From<&String> for ResultId {
#[inline]
fn from(value: &String) -> Self { Self::from(value.clone()) }
}
impl From<&mut String> for ResultId {
fn from(value: &mut String) -> Self { Self::from(value.as_str()) }
}
impl From<&str> for ResultId {
#[inline]
fn from(value: &str) -> Self { Self::from(value.to_string()) }
}
impl From<ResultId> for String {
#[inline]
fn from(value: ResultId) -> Self { value.0 }
}
impl From<&ResultId> for String {
#[inline]
fn from(value: &ResultId) -> Self { value.0.clone() }
}
impl From<&mut ResultId> for String {
#[inline]
fn from(value: &mut ResultId) -> Self { value.0.clone() }
}
#[derive(Clone, Debug, PartialEq)]
pub enum Value {
Boolean { value: bool },
Integer { value: i64 },
Real { value: f64 },
String { value: String },
Array { values: Vec<Self> },
Function { def: usize },
Instance { values: HashMap<String, Self>, def: usize },
Method { values: HashMap<String, Self>, cdef: usize, fdef: usize },
Data { name: String },
IntermediateResult { name: String },
Void,
}
impl Value {
#[inline]
pub fn try_as_bool(self) -> Option<bool> {
use Value::*;
match self {
Boolean { value } => Some(value),
_ => None,
}
}
#[inline]
pub fn try_as_int(self) -> Option<i64> {
use Value::*;
match self {
Integer { value } => Some(value),
_ => None,
}
}
#[inline]
pub fn try_as_string(self) -> Option<String> {
use Value::*;
match self {
String { value } => Some(value),
_ => None,
}
}
#[inline]
pub fn try_as_array(self) -> Option<Vec<Self>> {
use Value::*;
match self {
Array { values } => Some(values),
_ => None,
}
}
#[inline]
pub fn try_as_func(self) -> Option<usize> {
use Value::*;
match self {
Function { def } => Some(def),
_ => None,
}
}
#[inline]
pub fn try_as_instance(self) -> Option<(HashMap<String, Self>, usize)> {
use Value::*;
match self {
Instance { values, def } => Some((values, def)),
_ => None,
}
}
#[inline]
pub fn try_as_method(self) -> Option<(HashMap<String, Self>, usize, usize)> {
use Value::*;
match self {
Method { values, cdef, fdef } => Some((values, cdef, fdef)),
_ => None,
}
}
#[inline]
pub fn try_as_intermediate_result(self) -> Option<String> {
use Value::*;
match self {
IntermediateResult { name } => Some(name),
_ => None,
}
}
pub fn cast(self, target: &DataType, table: &SymTable) -> Result<Self, Error> {
use Value::*;
match (self, target) {
(Boolean { value }, DataType::Any) => Ok(Self::Boolean { value }),
(Boolean { value }, DataType::Boolean) => Ok(Self::Boolean { value }),
(Boolean { value }, DataType::Integer) => Ok(Self::Integer { value: i64::from(value) }),
(Boolean { value }, DataType::String) => Ok(Self::String { value: format!("{}", Self::Boolean { value }.display(table)) }),
(Integer { value }, DataType::Any) => Ok(Self::Integer { value }),
(Integer { value }, DataType::Boolean) => Ok(Self::Boolean { value: value != 0 }),
(Integer { value }, DataType::Integer) => Ok(Self::Integer { value }),
(Integer { value }, DataType::Real) => Ok(Self::Real { value: value as f64 }),
(Integer { value }, DataType::String) => Ok(Self::String { value: format!("{}", Self::Integer { value }.display(table)) }),
(Real { value }, DataType::Any) => Ok(Self::Real { value }),
(Real { value }, DataType::Integer) => Ok(Self::Integer { value: value as i64 }),
(Real { value }, DataType::Real) => Ok(Self::Real { value }),
(Real { value }, DataType::String) => Ok(Self::String { value: format!("{}", Self::Real { value }.display(table)) }),
(String { value }, DataType::Any) => Ok(Self::String { value }),
(String { value }, DataType::String) => Ok(Self::String { value }),
(Array { values }, DataType::Any) => Ok(Self::Array { values }),
(Array { values }, DataType::String) => Ok(Self::String { value: format!("{}", Self::Array { values }.display(table)) }),
(Array { values }, DataType::Array { elem_type }) => {
let mut casted_values: Vec<Self> = Vec::with_capacity(values.len());
for v in values {
casted_values.push(v.cast(elem_type, table)?);
}
Ok(Self::Array { values: casted_values })
},
(Function { def }, DataType::Any) => Ok(Self::Function { def }),
(Function { def }, DataType::Function { args, ret }) => {
Ok(if &table.func(FunctionId::Func(def)).args == args && table.func(FunctionId::Func(def)).ret == **ret {
Self::Function { def }
} else {
return Err(Error::CastError {
got: DataType::Function {
args: table.func(FunctionId::Func(def)).args.clone(),
ret: Box::new(table.func(FunctionId::Func(def)).ret.clone()),
},
target: target.clone(),
});
})
},
(Function { def }, DataType::String) => Ok(Self::String { value: format!("{}", Self::Function { def }.display(table)) }),
(Instance { values, def }, DataType::Any) => Ok(Self::Instance { values, def }),
(Instance { values, def }, DataType::Class { name }) => Ok(if &table.class(def).name == name {
Self::Instance { values, def }
} else {
return Err(Error::CastError { got: DataType::Class { name: table.class(def).name.clone() }, target: target.clone() });
}),
(Instance { values, def }, DataType::String) => Ok(Self::String { value: format!("{}", Self::Instance { values, def }.display(table)) }),
(Method { values, cdef, fdef }, DataType::Any) => Ok(Self::Method { values, cdef, fdef }),
(Method { values, cdef, fdef }, DataType::Class { name }) => Ok(if &table.class(cdef).name == name {
Self::Method { values, cdef, fdef }
} else {
return Err(Error::CastError { got: DataType::Class { name: table.class(cdef).name.clone() }, target: target.clone() });
}),
(Method { values, cdef, fdef }, DataType::String) => {
Ok(Self::String { value: format!("{}", Self::Method { values, cdef, fdef }.display(table)) })
},
(Data { name }, DataType::Any) => Ok(Self::Data { name }),
(Data { name }, DataType::Data) => Ok(Self::Data { name }),
(Data { name }, DataType::String) => Ok(Self::String { value: format!("{}", Self::Data { name }.display(table)) }),
(Data { name }, DataType::IntermediateResult) => Ok(Self::Data { name }),
(IntermediateResult { name }, DataType::Any) => Ok(Self::IntermediateResult { name }),
(IntermediateResult { name }, DataType::IntermediateResult) => Ok(Self::IntermediateResult { name }),
(IntermediateResult { name }, DataType::String) => {
Ok(Self::String { value: format!("{}", Self::IntermediateResult { name }.display(table)) })
},
(got, target) => Err(Error::CastError { got: got.data_type(table), target: target.clone() }),
}
}
#[inline]
pub fn data_type(&self, table: &SymTable) -> DataType {
use Value::*;
match self {
Boolean { .. } => DataType::Boolean,
Integer { .. } => DataType::Integer,
Real { .. } => DataType::Real,
String { .. } => DataType::String,
Array { values } => DataType::Array { elem_type: Box::new(values.iter().next().map(|v| v.data_type(table)).unwrap_or(DataType::Any)) },
Function { def } => DataType::Function {
args: table.func(FunctionId::Func(*def)).args.clone(),
ret: Box::new(table.func(FunctionId::Func(*def)).ret.clone()),
},
Instance { def, .. } => {
if table.class(*def).name == BuiltinClasses::Data.name() {
DataType::Data
} else {
DataType::Class { name: table.class(*def).name.clone() }
}
},
Method { fdef, .. } => DataType::Function {
args: table.func(FunctionId::Func(*fdef)).args.clone(),
ret: Box::new(table.func(FunctionId::Func(*fdef)).ret.clone()),
},
Data { .. } => DataType::Data,
IntermediateResult { .. } => DataType::IntermediateResult,
Void => DataType::Void,
}
}
#[inline]
pub fn display<'a, 'b>(&'a self, table: &'b SymTable) -> ValueDisplay<'a, 'b> { ValueDisplay { value: self, table } }
#[inline]
pub fn to_full(&self, table: &SymTable) -> FullValue {
use Value::*;
match self {
Boolean { value } => FullValue::Boolean(*value),
Integer { value } => FullValue::Integer(*value),
Real { value } => FullValue::Real(*value),
String { value } => FullValue::String(value.clone()),
Array { values } => FullValue::Array(values.iter().map(|v| v.to_full(table)).collect()),
Function { .. } => {
panic!("Value::Function has no business being converted into a FullValue");
},
Instance { values, def } => {
FullValue::Instance(table.class(*def).name.clone(), values.iter().map(|(n, v)| (n.clone(), v.to_full(table))).collect())
},
Method { .. } => {
panic!("Value::Method has no business being converted into a FullValue");
},
Data { name } => FullValue::Data(DataId(name.clone())),
IntermediateResult { name } => FullValue::IntermediateResult(ResultId(name.clone())),
Void => FullValue::Void,
}
}
#[inline]
pub fn into_full(self, table: &SymTable) -> FullValue {
use Value::*;
match self {
Boolean { value } => FullValue::Boolean(value),
Integer { value } => FullValue::Integer(value),
Real { value } => FullValue::Real(value),
String { value } => FullValue::String(value),
Array { values } => FullValue::Array(values.into_iter().map(|v| v.into_full(table)).collect()),
Function { .. } => {
panic!("Value::Function has no business being converted into a FullValue");
},
Instance { values, def } => {
FullValue::Instance(table.class(def).name.clone(), values.into_iter().map(|(n, v)| (n, v.into_full(table))).collect())
},
Method { .. } => {
panic!("Value::Method has no business being converted into a FullValue");
},
Data { name } => FullValue::Data(DataId(name)),
IntermediateResult { name } => FullValue::IntermediateResult(ResultId(name)),
Void => FullValue::Void,
}
}
}
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
#[serde(untagged)]
pub enum FullValue {
Array(Vec<Self>),
Instance(String, HashMap<String, Self>),
Data(DataId),
IntermediateResult(ResultId),
Boolean(bool),
Integer(i64),
Real(f64),
String(String),
Void,
}
impl FullValue {
#[inline]
pub fn bool(self) -> bool {
if let Self::Boolean(value) = self {
value
} else {
panic!("Cannot unwrap a non-FullValue::Boolean as FullValue::Boolean");
}
}
#[inline]
pub fn int(self) -> i64 {
if let Self::Integer(value) = self {
value
} else {
panic!("Cannot unwrap a non-FullValue::Integer as FullValue::Integer");
}
}
#[inline]
pub fn real(self) -> f64 {
if let Self::Real(value) = self {
value
} else {
panic!("Cannot unwrap a non-FullValue::Real as FullValue::Real");
}
}
#[inline]
pub fn string(self) -> String {
if let Self::String(value) = self {
value
} else {
panic!("Cannot unwrap a non-FullValue::String as FullValue::String");
}
}
#[inline]
pub fn data(self) -> String {
if let Self::Data(value) = self {
value.0
} else {
panic!("Cannot unwrap a non-FullValue::Data as FullValue::Data");
}
}
#[inline]
pub fn result(self) -> String {
if let Self::IntermediateResult(value) = self {
value.0
} else {
panic!("Cannot unwrap a non-FullValue::IntermediateResult as FullValue::IntermediateResult");
}
}
#[inline]
pub fn data_type(&self) -> DataType {
use FullValue::*;
match self {
Boolean(_) => DataType::Boolean,
Integer(_) => DataType::Integer,
Real(_) => DataType::Real,
String(_) => DataType::String,
Array(values) => DataType::Array { elem_type: Box::new(values.iter().next().map(|v| v.data_type()).unwrap_or(DataType::Any)) },
Instance(name, _) => {
if name == BuiltinClasses::Data.name() {
DataType::Data
} else {
DataType::Class { name: name.clone() }
}
},
Data(_) => DataType::Data,
IntermediateResult(_) => DataType::IntermediateResult,
Void => DataType::Void,
}
}
#[inline]
pub fn to_value(&self, table: &SymTable) -> Value {
use FullValue::*;
match self {
Boolean(value) => Value::Boolean { value: *value },
Integer(value) => Value::Integer { value: *value },
Real(value) => Value::Real { value: *value },
String(value) => Value::String { value: value.clone() },
Array(values) => Value::Array { values: values.iter().map(|v| v.to_value(table)).collect() },
Instance(name, values) => Value::Instance {
values: values.iter().map(|(n, v)| (n.clone(), v.to_value(table))).collect(),
def: table.classes.iter().enumerate().find_map(|(i, c)| if &c.name == name { Some(i) } else { None }).unwrap(),
},
Data(name) => Value::Data { name: name.0.clone() },
IntermediateResult(name) => Value::IntermediateResult { name: name.0.clone() },
Void => Value::Void,
}
}
#[inline]
pub fn into_value(self, table: &SymTable) -> Value {
use FullValue::*;
match self {
Boolean(value) => Value::Boolean { value },
Integer(value) => Value::Integer { value },
Real(value) => Value::Real { value },
String(value) => Value::String { value },
Array(values) => Value::Array { values: values.into_iter().map(|v| v.into_value(table)).collect() },
Instance(name, values) => Value::Instance {
values: values.into_iter().map(|(n, v)| (n, v.into_value(table))).collect(),
def: table.classes.iter().enumerate().find_map(|(i, c)| if c.name == name { Some(i) } else { None }).unwrap(),
},
Data(name) => Value::Data { name: name.0 },
IntermediateResult(name) => Value::IntermediateResult { name: name.0 },
Void => Value::Void,
}
}
}
impl Display for FullValue {
#[inline]
fn fmt(&self, f: &mut Formatter<'_>) -> FResult {
use FullValue::*;
match self {
Boolean(value) => write!(f, "{value}"),
Integer(value) => write!(f, "{value}"),
Real(value) => write!(f, "{value}"),
String(value) => write!(f, "{value}"),
Array(values) => write!(f, "[{}]", values.iter().map(|v| format!("{v}")).collect::<Vec<std::string::String>>().join(", ")),
Instance(name, values) => write!(
f,
"{} {{{}{}{}}}",
name,
if values.is_empty() { "" } else { " " },
values.iter().map(|(n, v)| format!("{n} := {v}")).collect::<Vec<std::string::String>>().join(", "),
if values.is_empty() { "" } else { " " },
),
Data(name) => write!(f, "{name}"),
IntermediateResult(name) => write!(f, "{name}"),
Void => write!(f, "()"),
}
}
}
impl TryFrom<JValue> for FullValue {
type Error = Error;
#[inline]
fn try_from(value: JValue) -> Result<Self, Self::Error> {
match serde_json::from_value(value) {
Ok(res) => Ok(res),
Err(err) => Err(Error::JsonError { err }),
}
}
}