use std::{collections::BTreeMap, fmt, ops::Deref};
use crate::value::{KeyString, Value};
use crate::{
compiler::{
Context, Expression, TypeDef,
expression::{Expr, Resolved},
state::{TypeInfo, TypeState},
},
value::Kind,
};
#[derive(Debug, Clone, PartialEq)]
pub struct Object {
inner: BTreeMap<KeyString, Expr>,
}
impl Object {
#[must_use]
pub fn new(inner: BTreeMap<KeyString, Expr>) -> Self {
Self { inner }
}
}
impl Deref for Object {
type Target = BTreeMap<KeyString, Expr>;
fn deref(&self) -> &Self::Target {
&self.inner
}
}
impl Expression for Object {
fn resolve(&self, ctx: &mut Context) -> Resolved {
self.inner
.iter()
.map(|(key, expr)| expr.resolve(ctx).map(|v| (key.clone(), v)))
.collect::<Result<BTreeMap<_, _>, _>>()
.map(Value::Object)
}
fn resolve_constant(&self, state: &TypeState) -> Option<Value> {
self.inner
.iter()
.map(|(key, expr)| expr.resolve_constant(state).map(|v| (key.clone(), v)))
.collect::<Option<BTreeMap<_, _>>>()
.map(Value::Object)
}
fn type_info(&self, state: &TypeState) -> TypeInfo {
let mut state = state.clone();
let mut fallible = false;
let mut returns = Kind::never();
let mut type_defs = BTreeMap::new();
for (k, expr) in &self.inner {
let type_def = expr.apply_type_info(&mut state).upgrade_undefined();
returns.merge_keep(type_def.returns().clone(), false);
fallible |= type_def.is_fallible();
if type_def.is_never() {
return TypeInfo::new(
state,
TypeDef::never()
.maybe_fallible(fallible)
.with_returns(returns),
);
}
type_defs.insert(k.clone(), type_def);
}
let collection = type_defs
.into_iter()
.map(|(field, type_def)| (field.into(), type_def.into()))
.collect::<BTreeMap<_, _>>();
let result = TypeDef::object(collection)
.maybe_fallible(fallible)
.with_returns(returns);
TypeInfo::new(state, result)
}
}
impl fmt::Display for Object {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let exprs = self
.inner
.iter()
.map(|(k, v)| format!(r#""{k}": {v}"#))
.collect::<Vec<_>>()
.join(", ");
write!(f, "{{ {exprs} }}")
}
}
impl From<BTreeMap<KeyString, Expr>> for Object {
fn from(inner: BTreeMap<KeyString, Expr>) -> Self {
Self { inner }
}
}