aimx/expressions/
collection.rs1use crate::{
9 aim::{ContextLike, WriterLike, Writer},
10 expressions::{Expression, ExpressionLike, parse_expression},
11 literals::parse_text,
12 values::Value,
13};
14use anyhow::Result;
15use nom::{
16 IResult, Parser,
17 character::complete::{char, multispace0},
18 multi::{separated_list1}, sequence::{delimited, separated_pair},
19};
20use std::{collections::HashMap, fmt, sync::Arc};
21
22#[derive(Debug, Clone, PartialEq)]
23pub struct Collection {
24 pool: Arc<HashMap<Arc<str>, Arc<Expression>>>,
27}
28
29impl Collection {
30 pub fn new(pool: Arc<HashMap<Arc<str>, Arc<Expression>>>) -> Self {
31 Collection { pool }
32 }
33
34 pub fn to_value(&self) -> Arc<Value> {
35 Arc::new(Value::Collection(self.pool.clone()))
36 }
37
38 pub fn print(&self, writer: &mut Writer) {
39 writer.write_char('{');
40 let mut first = true;
41 for (key, expr) in self.pool.iter() {
42 if !first {
43 writer.write_str("; ");
44 }
45 first = false;
46 writer.write_char('"');
48 writer.write_str(key);
49 writer.write_str("\" = ");
50 expr.print(writer);
51 }
52 writer.write_char('}');
53 }
54}
55
56impl ExpressionLike for Collection {
57 fn evaluate(&self, _context: &mut dyn ContextLike) -> Result<Arc<Value>> {
58 Ok(self.to_value())
60 }
61
62 fn to_formula(&self) -> String {
64 let mut writer = Writer::formulizer();
65 self.print(&mut writer);
66 writer.finish()
67 }
68}
69
70impl WriterLike for Collection {
71 fn write(&self, writer: &mut Writer) {
72 self.print(writer);
73 }
74}
75
76impl fmt::Display for Collection {
77 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
78 write!(f, "{}", self.to_stringized())
79 }
80}
81
82fn parse_tuple(input: &str) -> IResult<&str, (Arc<str>, Expression)> {
83 delimited(
84 multispace0,
85 separated_pair(
86 parse_text,
87 delimited(multispace0, char('='), multispace0),
88 parse_expression,
89 ),
90 multispace0
91 ).parse(input)
92}
93
94pub fn parse_collection(input: &str) -> IResult<&str, Collection> {
95 let (input, tuples) = delimited(
96 char('{'),
97 separated_list1(
99 delimited(multispace0, char(';'), multispace0),
100 parse_tuple,
101 ),
102 char('}'),
103 ).parse(input)?;
104
105 let pool = tuples.into_iter()
107 .map(|(key, expr)| (key, Arc::new(expr)))
108 .collect();
109
110 Ok((input, Collection::new(Arc::new(pool))))
111}