use super::*;
use crate::err::*;
use crate::eval::*;
use crate::value::*;
#[derive(Debug, Clone)]
pub struct MapperExpr {
pub source: Index,
pub key_name: Option<Index>,
pub value_name: Index,
pub output: Output,
}
impl Expr for MapperExpr {
fn resolve(
&self,
index: Index,
evaluation: &mut dyn ExprEvaluator,
) -> Result<ValueOrReference, ErrorKind> {
let mut required = vec![self.value_name, self.source];
if let Some(key_name) = self.key_name {
required.push(key_name);
}
evaluation.ensure_resolved(required)?;
let value_name_value = evaluation.get_value(self.value_name)?;
let value_name = value_name_value
.as_string()
.ok_or(ErrorKind::TypeNotAllowed {
item: index,
expr: self.value_name,
expected: ValueKind::String,
actual: value_name_value.kind(),
})?;
let contexts: Vec<Index> = match evaluation.get_value(self.source)? {
Value::List(items) => items
.into_iter()
.map(|value| {
let value_expr = evaluation.create(Expression::literal(LiteralExpr { value }));
evaluation.create(Expression::map(MapExpr {
items: vec![(MapKey::Literal(value_name.to_string()), value_expr)],
}))
})
.collect(),
Value::Map(items) => items
.into_iter()
.map(|(key, value)| {
let value_expr = evaluation.create(Expression::literal(LiteralExpr { value }));
let mut items = vec![(MapKey::Literal(value_name.to_string()), value_expr)];
if let Some(key_name) = self.key_name {
let key_expr = evaluation
.create(Expression::literal(LiteralExpr { value: key.into() }));
items.push((MapKey::Expression(key_name), key_expr));
}
evaluation.create(Expression::map(MapExpr { items }))
})
.collect(),
other => {
let expected = if self.key_name.is_some() {
ValueKind::Object
} else {
ValueKind::Array
};
return Err(ErrorKind::ForLoopTypeMismatch {
index,
expected,
actual: other.kind(),
})?;
}
};
match self.output {
Output::List { expr } => {
let expressions = contexts
.into_iter()
.map(|ctx| evaluation.clone_with_context(expr, ctx))
.collect();
let referenced =
evaluation.create(Expression::list(ListExpr { items: expressions }));
Ok(ValueOrReference::Reference(referenced))
}
Output::Map {
key_expr,
value_expr,
} => {
let expressions: Vec<(Index, Index)> = contexts
.into_iter()
.map(|ctx| {
(
evaluation.clone_with_context(key_expr, ctx),
evaluation.clone_with_context(value_expr, ctx),
)
})
.collect();
let referenced = evaluation.create(Expression::map(MapExpr::from(expressions)));
Ok(ValueOrReference::Reference(referenced))
}
Output::StringConcat { expr } => {
let expressions = contexts
.into_iter()
.map(|ctx| evaluation.clone_with_context(expr, ctx))
.collect();
let referenced = evaluation.create(Expression::concat_string(ConcatStringExpr {
parts: expressions,
}));
Ok(ValueOrReference::Reference(referenced))
}
}
}
fn traverse(
&self,
_evaluation: &dyn ExprEvaluator,
expression: Index,
_name: &Indexer,
) -> Result<Option<ValueOrReference>, ErrorKind> {
Err(ErrorKind::DependenciesNotSatisfied {
indices: vec![expression],
})
}
}
#[derive(Debug, Clone, Copy)]
pub enum Output {
List { expr: Index },
Map { key_expr: Index, value_expr: Index },
StringConcat { expr: Index },
}