use sim_kernel::{Cx, Result, Symbol};
use crate::{
AndShape, AnyShape, ListShape, NotShape, OneOfShape, OrShape, RepeatShape, Shape,
TableExtraPolicy, TableShape,
};
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct ShapeNormalForm {
pub kind: ShapeNormalKind,
pub label: String,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum ShapeNormalKind {
Any,
Atom(Symbol),
And(Vec<ShapeNormalForm>),
Or(Vec<ShapeNormalForm>),
Not(Box<ShapeNormalForm>),
List {
items: Vec<ShapeNormalForm>,
rest: Option<Box<ShapeNormalForm>>,
},
Table {
fields: Vec<(Symbol, ShapeNormalForm)>,
closed: bool,
},
Repeat {
body: Box<ShapeNormalForm>,
min: usize,
max: Option<usize>,
},
Opaque,
}
impl ShapeNormalForm {
fn new(kind: ShapeNormalKind, label: impl Into<String>) -> Self {
Self {
kind,
label: label.into(),
}
}
}
pub fn normalize_shape(cx: &mut Cx, shape: &dyn Shape) -> Result<ShapeNormalForm> {
if shape.as_any().is::<AnyShape>() {
return Ok(ShapeNormalForm::new(ShapeNormalKind::Any, "Any"));
}
if let Some(and) = shape.as_any().downcast_ref::<AndShape>() {
let mut parts = Vec::new();
for part in and.parts() {
let normalized = normalize_shape(cx, part.as_ref())?;
match normalized.kind {
ShapeNormalKind::And(nested) => parts.extend(nested),
_ => parts.push(normalized),
}
}
return Ok(ShapeNormalForm::new(
ShapeNormalKind::And(parts),
label(cx, shape)?,
));
}
if let Some(or) = shape.as_any().downcast_ref::<OrShape>() {
return normalize_or(cx, shape, or.choices());
}
if let Some(one_of) = shape.as_any().downcast_ref::<OneOfShape>() {
return normalize_or(cx, shape, one_of.choices());
}
if let Some(not) = shape.as_any().downcast_ref::<NotShape>() {
let inner = normalize_shape(cx, not.inner().as_ref())?;
return Ok(ShapeNormalForm::new(
ShapeNormalKind::Not(Box::new(inner)),
label(cx, shape)?,
));
}
if let Some(list) = shape.as_any().downcast_ref::<ListShape>() {
let items = list
.items()
.iter()
.map(|item| normalize_shape(cx, item.as_ref()))
.collect::<Result<Vec<_>>>()?;
let rest = list
.rest()
.map(|rest| normalize_shape(cx, rest.as_ref()).map(Box::new))
.transpose()?;
return Ok(ShapeNormalForm::new(
ShapeNormalKind::List { items, rest },
label(cx, shape)?,
));
}
if let Some(table) = shape.as_any().downcast_ref::<TableShape>() {
let fields = table
.fields()
.iter()
.map(|field| {
Ok((
field.key.clone(),
normalize_shape(cx, field.shape.as_ref())?,
))
})
.collect::<Result<Vec<_>>>()?;
return Ok(ShapeNormalForm::new(
ShapeNormalKind::Table {
fields,
closed: matches!(table.extra(), TableExtraPolicy::Reject),
},
label(cx, shape)?,
));
}
if let Some(repeat) = shape.as_any().downcast_ref::<RepeatShape>() {
let body = normalize_shape(cx, repeat.body().as_ref())?;
return Ok(ShapeNormalForm::new(
ShapeNormalKind::Repeat {
body: Box::new(body),
min: repeat.min(),
max: repeat.max(),
},
label(cx, shape)?,
));
}
if let Some(symbol) = shape.symbol() {
return Ok(ShapeNormalForm::new(
ShapeNormalKind::Atom(symbol.clone()),
symbol.to_string(),
));
}
Ok(ShapeNormalForm::new(
ShapeNormalKind::Opaque,
label(cx, shape)?,
))
}
fn normalize_or(
cx: &mut Cx,
shape: &dyn Shape,
choices: &[std::sync::Arc<dyn Shape>],
) -> Result<ShapeNormalForm> {
let mut out = Vec::new();
for choice in choices {
let normalized = normalize_shape(cx, choice.as_ref())?;
match normalized.kind {
ShapeNormalKind::Or(nested) => out.extend(nested),
_ => out.push(normalized),
}
}
Ok(ShapeNormalForm::new(
ShapeNormalKind::Or(out),
label(cx, shape)?,
))
}
fn label(cx: &mut Cx, shape: &dyn Shape) -> Result<String> {
Ok(shape.describe(cx)?.name)
}