use std::sync::Arc;
use sim_citizen::{CitizenField, arity_error, decode_version};
use sim_kernel::{Cx, Expr, Result, Shape, Symbol, Value};
use crate::{
AcceptOnNoDiagnosticsHook, AndShape, AnyShape, ClassShape, DiscardOnDiagnosticPrefixHook,
ExactExprShape, ExprKind, ExprKindShape, HookedShape, ListShape, NotShape, OrShape, OrStrategy,
RepeatShape, ScoreFloorHook, TableExtraPolicy, TableFieldSpec, TableShape, TraceMarkHook,
VennShapeSet, hook_value,
};
use super::{
and_shape_class_symbol, any_shape_class_symbol, build_shape_value, class_shape_class_symbol,
decode_expr_kind, decode_extra, decode_hooks, decode_shape_list, decode_shape_value,
decode_symbol, decode_table_fields, decode_venn_members, exact_expr_shape_class_symbol,
expr_kind_shape_class_symbol, expr_kind_symbol, hooked_shape_class_symbol,
list_shape_class_symbol, not_shape_class_symbol, or_shape_class_symbol, or_strategy_symbol,
repeat_shape_class_symbol, table_shape_class_symbol, venn_shape_set_class_symbol,
};
fn fields<'a>(
cx: &mut Cx,
class: Symbol,
args: &'a [Value],
arity_without_version: usize,
) -> Result<&'a [Value]> {
let expected = arity_without_version + 1;
if args.len() != expected {
return Err(arity_error(class, expected, args.len()));
}
decode_version(cx, args[0].clone(), 1, class)?;
Ok(&args[1..])
}
pub(super) fn any_shape_value() -> Value {
build_shape_value(any_shape_class_symbol(), Arc::new(AnyShape), Vec::new())
}
pub(super) fn construct_any_shape(cx: &mut Cx, args: Vec<Value>) -> Result<Value> {
fields(cx, any_shape_class_symbol(), &args, 0)?;
Ok(any_shape_value())
}
pub(super) fn exact_expr_shape_value(expected: Expr) -> Value {
build_shape_value(
exact_expr_shape_class_symbol(),
Arc::new(ExactExprShape::new(expected.clone())),
vec![expected],
)
}
pub(super) fn construct_exact_expr_shape(cx: &mut Cx, args: Vec<Value>) -> Result<Value> {
let fields = fields(cx, exact_expr_shape_class_symbol(), &args, 1)?;
Ok(exact_expr_shape_value(fields[0].object().as_expr(cx)?))
}
pub(super) fn expr_kind_shape_value(kind: ExprKind) -> Value {
build_shape_value(
expr_kind_shape_class_symbol(),
Arc::new(ExprKindShape::new(kind.clone())),
vec![Expr::Symbol(expr_kind_symbol(&kind))],
)
}
pub(super) fn construct_expr_kind_shape(cx: &mut Cx, args: Vec<Value>) -> Result<Value> {
let fields = fields(cx, expr_kind_shape_class_symbol(), &args, 1)?;
Ok(expr_kind_shape_value(decode_expr_kind(
cx,
fields[0].clone(),
)?))
}
pub(super) fn class_shape_value(symbol: Symbol) -> Value {
build_shape_value(
class_shape_class_symbol(),
Arc::new(ClassShape::new(symbol.clone())),
vec![Expr::Symbol(symbol)],
)
}
pub(super) fn construct_class_shape(cx: &mut Cx, args: Vec<Value>) -> Result<Value> {
let fields = fields(cx, class_shape_class_symbol(), &args, 1)?;
Ok(class_shape_value(decode_symbol(
cx,
fields[0].clone(),
"class",
)?))
}
pub(super) fn list_shape_value(
items: Vec<Arc<dyn Shape>>,
rest: Option<Arc<dyn Shape>>,
) -> Result<Value> {
let shape: Arc<dyn Shape> = match rest.clone() {
Some(rest) => Arc::new(ListShape::with_rest(items.clone(), rest)),
None => Arc::new(ListShape::new(items.clone())),
};
Ok(build_shape_value(
list_shape_class_symbol(),
shape,
vec![
super::encode_shape_list(&items)?,
rest.as_ref()
.map(|shape| super::encode_shape_expr(shape.as_ref()))
.transpose()?
.unwrap_or(Expr::Nil),
],
))
}
pub(super) fn construct_list_shape(cx: &mut Cx, args: Vec<Value>) -> Result<Value> {
let fields = fields(cx, list_shape_class_symbol(), &args, 2)?;
let items = decode_shape_list(cx, fields[0].clone(), "items")?;
let rest = match fields[1].object().as_expr(cx)? {
Expr::Nil => None,
_ => Some(decode_shape_value(cx, fields[1].clone(), "rest")?),
};
list_shape_value(items, rest)
}
pub(super) fn table_shape_value(
fields: Vec<TableFieldSpec>,
extra: TableExtraPolicy,
) -> Result<Value> {
Ok(build_shape_value(
table_shape_class_symbol(),
Arc::new(TableShape::new(fields.clone(), extra.clone())),
vec![
super::encode_table_fields(&fields)?,
super::encode_extra(&extra)?,
],
))
}
pub(super) fn construct_table_shape(cx: &mut Cx, args: Vec<Value>) -> Result<Value> {
let fields = fields(cx, table_shape_class_symbol(), &args, 2)?;
table_shape_value(
decode_table_fields(cx, fields[0].clone())?,
decode_extra(cx, fields[1].clone())?,
)
}
pub(super) fn or_shape_value(choices: Vec<Arc<dyn Shape>>, strategy: OrStrategy) -> Result<Value> {
Ok(build_shape_value(
or_shape_class_symbol(),
Arc::new(OrShape::with_strategy(choices.clone(), strategy)),
vec![
super::encode_shape_list(&choices)?,
Expr::Symbol(or_strategy_symbol(strategy)),
],
))
}
pub(super) fn construct_or_shape(cx: &mut Cx, args: Vec<Value>) -> Result<Value> {
let fields = fields(cx, or_shape_class_symbol(), &args, 2)?;
or_shape_value(
decode_shape_list(cx, fields[0].clone(), "choices")?,
super::codec::decode_or_strategy(cx, fields[1].clone())?,
)
}
pub(super) fn and_shape_value(parts: Vec<Arc<dyn Shape>>) -> Result<Value> {
Ok(build_shape_value(
and_shape_class_symbol(),
Arc::new(AndShape::new(parts.clone())),
vec![super::encode_shape_list(&parts)?],
))
}
pub(super) fn construct_and_shape(cx: &mut Cx, args: Vec<Value>) -> Result<Value> {
let fields = fields(cx, and_shape_class_symbol(), &args, 1)?;
and_shape_value(decode_shape_list(cx, fields[0].clone(), "parts")?)
}
pub(super) fn not_shape_value(inner: Arc<dyn Shape>) -> Result<Value> {
Ok(build_shape_value(
not_shape_class_symbol(),
Arc::new(NotShape::new(inner.clone())),
vec![super::encode_shape_expr(inner.as_ref())?],
))
}
pub(super) fn construct_not_shape(cx: &mut Cx, args: Vec<Value>) -> Result<Value> {
let fields = fields(cx, not_shape_class_symbol(), &args, 1)?;
not_shape_value(decode_shape_value(cx, fields[0].clone(), "inner")?)
}
pub(super) fn repeat_shape_value(
body: Arc<dyn Shape>,
min: usize,
max: Option<usize>,
) -> Result<Value> {
Ok(build_shape_value(
repeat_shape_class_symbol(),
Arc::new(RepeatShape::with_bounds(body.clone(), min, max)),
vec![
super::encode_shape_expr(body.as_ref())?,
min.encode_field(),
max.encode_field(),
],
))
}
pub(super) fn construct_repeat_shape(cx: &mut Cx, args: Vec<Value>) -> Result<Value> {
let fields = fields(cx, repeat_shape_class_symbol(), &args, 3)?;
repeat_shape_value(
decode_shape_value(cx, fields[0].clone(), "body")?,
usize::decode_field_value(cx, fields[1].clone(), "min")?,
Option::<usize>::decode_field_value(cx, fields[2].clone(), "max")?,
)
}
pub(super) fn hooked_shape_value(
inner: Arc<dyn Shape>,
hooks: Vec<Arc<dyn crate::MatchHook>>,
) -> Result<Value> {
Ok(build_shape_value(
hooked_shape_class_symbol(),
Arc::new(HookedShape::new(inner.clone(), hooks.clone())),
vec![
super::encode_shape_expr(inner.as_ref())?,
super::encode_hooks(&hooks)?,
],
))
}
pub(super) fn construct_hooked_shape(cx: &mut Cx, args: Vec<Value>) -> Result<Value> {
let fields = fields(cx, hooked_shape_class_symbol(), &args, 2)?;
hooked_shape_value(
decode_shape_value(cx, fields[0].clone(), "inner")?,
decode_hooks(cx, fields[1].clone())?,
)
}
pub(super) fn construct_trace_mark_hook(cx: &mut Cx, args: Vec<Value>) -> Result<Value> {
fields(cx, crate::trace_mark_hook_class_symbol(), &args, 0)?;
Ok(hook_value(Arc::new(TraceMarkHook)))
}
pub(super) fn construct_score_floor_hook(cx: &mut Cx, args: Vec<Value>) -> Result<Value> {
let fields = fields(cx, crate::score_floor_hook_class_symbol(), &args, 1)?;
Ok(hook_value(Arc::new(ScoreFloorHook::new(
i32::decode_field_value(cx, fields[0].clone(), "floor")?,
))))
}
pub(super) fn construct_accept_on_no_diagnostics_hook(
cx: &mut Cx,
args: Vec<Value>,
) -> Result<Value> {
fields(
cx,
crate::accept_on_no_diagnostics_hook_class_symbol(),
&args,
0,
)?;
Ok(hook_value(Arc::new(AcceptOnNoDiagnosticsHook)))
}
pub(super) fn construct_discard_on_diagnostic_prefix_hook(
cx: &mut Cx,
args: Vec<Value>,
) -> Result<Value> {
let fields = fields(
cx,
crate::discard_on_diagnostic_prefix_hook_class_symbol(),
&args,
1,
)?;
Ok(hook_value(Arc::new(DiscardOnDiagnosticPrefixHook::new(
String::decode_field_value(cx, fields[0].clone(), "prefix")?,
))))
}
pub(super) fn construct_venn_shape_set(cx: &mut Cx, args: Vec<Value>) -> Result<Value> {
let fields = fields(cx, venn_shape_set_class_symbol(), &args, 1)?;
let members = decode_venn_members(cx, fields[0].clone())?;
cx.factory().opaque(Arc::new(VennShapeSet::new(members)))
}