sim_lib_numbers_core/
value_shape.rs1use sim_kernel::{Cx, Expr, NumberValueRef, Result, Symbol, Value};
4use sim_shape::{MatchScore, Shape, ShapeDoc, ShapeMatch};
5
6pub fn value_shape_symbol(domain: &Symbol) -> Symbol {
8 Symbol::qualified(domain.to_string(), "value-shape")
9}
10
11pub struct NumberDomainTableSpec<'a> {
13 domain: Symbol,
14 numeric_family: &'a str,
15 canonical_form: &'a str,
16 parse_priority: i32,
17 literal_class: Value,
18 instance_shape: Value,
19 value_shape: Value,
20}
21
22impl<'a> NumberDomainTableSpec<'a> {
23 pub fn new(
26 domain: Symbol,
27 numeric_family: &'a str,
28 canonical_form: &'a str,
29 parse_priority: i32,
30 literal_class: Value,
31 instance_shape: Value,
32 value_shape: Value,
33 ) -> Self {
34 Self {
35 domain,
36 numeric_family,
37 canonical_form,
38 parse_priority,
39 literal_class,
40 instance_shape,
41 value_shape,
42 }
43 }
44}
45
46pub fn number_domain_table(cx: &mut Cx, spec: NumberDomainTableSpec<'_>) -> Result<Value> {
48 cx.factory().table(vec![
49 (Symbol::new("symbol"), cx.factory().symbol(spec.domain)?),
50 (
51 Symbol::new("kind"),
52 cx.factory().string("number-domain".to_owned())?,
53 ),
54 (
55 Symbol::new("numeric-family"),
56 cx.factory().string(spec.numeric_family.to_owned())?,
57 ),
58 (
59 Symbol::new("canonical-form"),
60 cx.factory().string(spec.canonical_form.to_owned())?,
61 ),
62 (
63 Symbol::new("parse-priority"),
64 cx.factory().string(spec.parse_priority.to_string())?,
65 ),
66 (Symbol::new("literal-class"), spec.literal_class),
67 (Symbol::new("instance-shape"), spec.instance_shape),
68 (Symbol::new("value-shape"), spec.value_shape),
69 ])
70}
71
72pub struct DomainNumberValueShape {
74 domain: Symbol,
75 name: &'static str,
76 details: Vec<&'static str>,
77}
78
79impl DomainNumberValueShape {
80 pub fn new(
82 domain: Symbol,
83 name: &'static str,
84 details: impl IntoIterator<Item = &'static str>,
85 ) -> Self {
86 Self {
87 domain,
88 name,
89 details: details.into_iter().collect(),
90 }
91 }
92
93 fn matches_number(&self, number: &NumberValueRef) -> bool {
94 number.domain == self.domain
95 }
96}
97
98impl Shape for DomainNumberValueShape {
99 fn check_value(&self, cx: &mut Cx, value: Value) -> Result<ShapeMatch> {
100 match cx.number_value_ref(value)? {
101 Some(number) if self.matches_number(&number) => {
102 Ok(ShapeMatch::accept(MatchScore::exact(25)))
103 }
104 _ => Ok(ShapeMatch::reject(format!(
105 "expected number value in {}",
106 self.domain
107 ))),
108 }
109 }
110
111 fn check_expr(&self, _cx: &mut Cx, expr: &Expr) -> Result<ShapeMatch> {
112 match expr {
113 Expr::Number(number) if number.domain == self.domain => {
114 Ok(ShapeMatch::accept(MatchScore::exact(20)))
115 }
116 _ => Ok(ShapeMatch::reject(format!(
117 "expected number value in {}",
118 self.domain
119 ))),
120 }
121 }
122
123 fn describe(&self, _cx: &mut Cx) -> Result<ShapeDoc> {
124 let mut doc = ShapeDoc::new(self.name);
125 for detail in &self.details {
126 doc = doc.with_detail(*detail);
127 }
128 Ok(doc)
129 }
130}
131
132pub fn assert_value_shape_symbol(domain: Symbol, actual: Symbol) {
134 assert_eq!(actual, value_shape_symbol(&domain));
135}