1use crate::*;
2use std::collections::HashMap;
3
4pub fn structure(strct: &Structure, env: Option<&Environment>, p: &Interpreter) -> MResult<Value> {
8 match strct {
9 Structure::Empty => Ok(Value::Empty),
10 #[cfg(feature = "record")]
11 Structure::Record(x) => record(&x, env, p),
12 #[cfg(feature = "matrix")]
13 Structure::Matrix(x) => matrix(&x, env, p),
14 #[cfg(feature = "table")]
15 Structure::Table(x) => table(&x, env, p),
16 #[cfg(feature = "tuple")]
17 Structure::Tuple(x) => tuple(&x, env, p),
18 #[cfg(all(feature = "tuple", feature = "atom"))]
19 Structure::TupleStruct(x) => tuple_struct(&x, env, p),
20 #[cfg(feature = "set")]
21 Structure::Set(x) => set(&x, env, p),
22 #[cfg(feature = "map")]
23 Structure::Map(x) => map(&x, env, p),
24 x => Err(MechError::new(FeatureNotEnabledError, Some(format!("Feature not enabled for `{:?}`", stringify!(x)))).with_compiler_loc()),
25 }
26}
27
28#[cfg(feature = "tuple")]
29pub fn tuple(tpl: &Tuple, env: Option<&Environment>, p: &Interpreter) -> MResult<Value> {
30 let mut elements = vec![];
31 for el in &tpl.elements {
32 let result = expression(el, env, p)?;
33 elements.push(Box::new(result));
34 }
35 let mech_tuple = Ref::new(MechTuple{elements});
36 Ok(Value::Tuple(mech_tuple))
37}
38
39#[cfg(all(feature = "tuple", feature = "atom"))]
40pub fn tuple_struct(tpl: &TupleStruct, env: Option<&Environment>, p: &Interpreter) -> MResult<Value> {
41 let mut elements = vec![];
42 let atom_value = atom(&Atom { name: tpl.name.clone() }, p);
43 elements.push(Box::new(atom_value));
44 let payload = expression(&tpl.value, env, p)?;
45 elements.push(Box::new(payload));
46 Ok(Value::Tuple(Ref::new(MechTuple { elements })))
47}
48
49#[cfg(feature = "map")]
50pub fn map(mp: &Map, env: Option<&Environment>, p: &Interpreter) -> MResult<Value> {
51 let mut m = IndexMap::new();
52 for b in &mp.elements {
53 let key = expression(&b.key, env, p)?;
54 let val = expression(&b.value, env, p)?;
55 m.insert(key,val);
56 }
57
58 let key_kind = m.keys().next().unwrap().kind();
59 for k in m.keys() {
61 if k.kind() != key_kind {
62 return Err(MechError::new(
63 MapKeyKindMismatchError{expected_kind: key_kind.clone(), actual_kind: k.kind().clone()},
64 None
65 ).with_compiler_loc());
66 }
67 }
68
69 let value_kind = m.values().next().unwrap().kind();
70 for v in m.values() {
72 if v.kind() != value_kind {
73 return Err(MechError::new(
74 MapValueKindMismatchError{expected_kind: value_kind.clone(), actual_kind: v.kind().clone()},
75 None
76 ).with_compiler_loc());
77 }
78 }
79 Ok(Value::Map(Ref::new(MechMap{
80 num_elements: m.len(),
81 key_kind,
82 value_kind,
83 map: m
84 })))
85}
86
87#[cfg(feature = "record")]
88pub fn record(rcrd: &Record, env: Option<&Environment>, p: &Interpreter) -> MResult<Value> {
89 let mut data: IndexMap<u64,Value> = IndexMap::new();
90 let cols: usize = rcrd.bindings.len();
91 let mut kinds: Vec<ValueKind> = Vec::new();
92 let mut field_names: HashMap<u64,String> = HashMap::new();
93 for b in &rcrd.bindings {
94 let name_hash = b.name.hash();
95 let name_str = b.name.to_string();
96 let val = expression(&b.value, env, p)?;
97 let knd: ValueKind = match &b.kind {
98 Some(k) => kind_annotation(&k.kind, p)?.to_value_kind(&p.state.borrow().kinds)?,
99 None => val.kind(),
100 };
101 kinds.push(knd.clone());
103 #[cfg(feature = "convert")]
104 if knd != val.kind() {
105 let fxn = ConvertKind{}.compile(&vec![val.clone(), Value::Kind(knd.clone())]);
106 match fxn {
107 Ok(convert_fxn) => {
108 convert_fxn.solve();
109 let converted_result = convert_fxn.out();
110 p.state.borrow_mut().add_plan_step(convert_fxn);
111 data.insert(name_hash, converted_result);
112 },
113 Err(e) => {
114 return Err(MechError::new(
115 TableColumnKindMismatchError {
116 column_id: name_hash,
117 expected_kind: knd.clone(),
118 actual_kind: val.kind().clone(),
119 },
120 None
121 ).with_compiler_loc());
122 }
123 }
124 } else {
125 data.insert(name_hash, val);
126 }
127 #[cfg(not(feature = "convert"))]
128 if knd != val.kind() {
129 return Err(MechError{file: file!().to_string(), tokens: vec![], msg: "".to_string(), id: line!(), kind: MechErrorKind::KindMismatch(val.kind(),knd)});
130 } else {
131 data.insert(name_hash, val);
132 }
133 field_names.insert(name_hash, name_str);
134 }
135 Ok(Value::Record(Ref::new(MechRecord{
136 cols,
137 kinds,
138 data,
139 field_names,
140 })))
141}
142
143#[cfg(feature = "set")]
148#[derive(Debug)]
149pub struct ValueSet {
150 pub out: Ref<MechSet>,
151}
152#[cfg(feature = "set")]
153#[cfg(feature = "functions")]
154impl MechFunctionImpl for ValueSet {
155 fn solve(&self) {}
156 fn out(&self) -> Value { Value::Set(self.out.clone()) }
157 fn to_string(&self) -> String { format!("{:#?}", self) }
158}
159#[cfg(feature = "set")]
160#[cfg(feature = "functions")]
161impl MechFunctionFactory for ValueSet {
162 fn new(args: FunctionArgs) -> MResult<Box<dyn MechFunction>> {
163 match args {
164 FunctionArgs::Nullary(out) => {
165 let out: Ref<MechSet> = unsafe{ out.as_unchecked().clone() };
166 Ok(Box::new(ValueSet {out}))
167 },
168 _ => Err(MechError::new(
169 IncorrectNumberOfArguments { expected: 0, found: args.len() },
170 None
171 ).with_compiler_loc()
172 ),
173 }
174 }
175}
176#[cfg(feature = "set")]
177#[cfg(feature = "compiler")]
178impl MechFunctionCompiler for ValueSet {
179 fn compile(&self, ctx: &mut CompileCtx) -> MResult<Register> {
180 compile_nullop!("set/define", self.out, ctx, FeatureFlag::Builtin(FeatureKind::Set));
181 }
182}
183#[cfg(feature = "set")]
184#[cfg(feature = "functions")]
185register_descriptor!{
186 FunctionDescriptor {
187 name: "set/define",
188 ptr: ValueSet::new,
189 }
190}
191
192#[cfg(feature = "set")]
193pub struct SetDefine {}
194#[cfg(feature = "set")]
195#[cfg(feature = "functions")]
196impl NativeFunctionCompiler for SetDefine {
197 fn compile(&self, arguments: &Vec<Value>) -> MResult<Box<dyn MechFunction>> {
198 Ok(Box::new(ValueSet {
199 out: Ref::new(MechSet::from_vec(arguments.clone())),
200 }))
201 }
202}
203#[cfg(feature = "set")]
204#[cfg(feature = "functions")]
205register_descriptor!{
206 FunctionCompilerDescriptor {
207 name: "set/define",
208 ptr: &SetDefine{},
209 }
210}
211
212#[cfg(feature = "set")]
213pub fn set(m: &Set, env: Option<&Environment>, p: &Interpreter) -> MResult<Value> {
214 let mut elements = Vec::new();
215 for el in &m.elements {
216 let result = expression(el, env, p)?;
217 elements.push(result.clone());
218 }
219 let element_kind = if elements.len() > 0 {
220 elements[0].kind()
221 } else {
222 ValueKind::Empty
223 };
224 for el in &elements {
226 if el.kind() != element_kind {
227 return Err(MechError::new(
228 SetKindMismatchError{expected_kind: element_kind.clone(), actual_kind: el.kind().clone()},
229 None
230 ).with_compiler_loc());
231 }
232 }
233 #[cfg(feature = "functions")]
234 {
235 let new_fxn = SetDefine {}.compile(&elements)?;
236 new_fxn.solve();
237 let out = new_fxn.out();
238 let plan = p.plan();
239 let mut plan_brrw = plan.borrow_mut();
240 plan_brrw.push(new_fxn);
241 Ok(out)
242 }
243 #[cfg(not(feature = "functions"))]
244 {
245 Ok(Value::Set(Ref::new(MechSet::from_vec(elements))))
246 }
247}
248
249macro_rules! handle_value_kind {
253 ($value_kind:ident, $val:expr, $field_label:expr, $data_map:expr, $converter:ident) => {{
254 let mut vals = Vec::new();
255 let id = $field_label; for x in $val.as_vec().iter() {
257 match x.$converter() {
258 Ok(u) => vals.push(u.to_value()),
259 Err(_) => {
260 return Err(MechError::new(
261 TableColumnKindMismatchError {
262 column_id: id,
263 expected_kind: $value_kind.clone(),
264 actual_kind: x.kind()
265 },
266 None
267 ).with_compiler_loc());
268 }
269 }
270 }
271 $data_map.insert(id, ($value_kind.clone(), Value::to_matrixd(vals.clone(), vals.len(), 1)));
272 }};
273}
274
275
276#[cfg(feature = "table")]
277fn handle_column_kind(
278 kind: ValueKind,
279 id: u64,
280 val: Matrix<Value>,
281 data_map: &mut IndexMap<u64,(ValueKind,Matrix<Value>)>
282) -> MResult<()>
283{
284 match kind {
285 #[cfg(feature = "i8")]
286 ValueKind::I8 => handle_value_kind!(kind, val, id, data_map, as_i8),
287 #[cfg(feature = "i16")]
288 ValueKind::I16 => handle_value_kind!(kind, val, id, data_map, as_i16),
289 #[cfg(feature = "i32")]
290 ValueKind::I32 => handle_value_kind!(kind, val, id, data_map, as_i32),
291 #[cfg(feature = "i64")]
292 ValueKind::I64 => handle_value_kind!(kind, val, id, data_map, as_i64),
293 #[cfg(feature = "i128")]
294 ValueKind::I128 => handle_value_kind!(kind, val, id, data_map, as_i128),
295
296 #[cfg(feature = "u8")]
297 ValueKind::U8 => handle_value_kind!(kind, val, id, data_map, as_u8),
298 #[cfg(feature = "u16")]
299 ValueKind::U16 => handle_value_kind!(kind, val, id, data_map, as_u16),
300 #[cfg(feature = "u32")]
301 ValueKind::U32 => handle_value_kind!(kind, val, id, data_map, as_u32),
302 #[cfg(feature = "u64")]
303 ValueKind::U64 => handle_value_kind!(kind, val, id, data_map, as_u64),
304 #[cfg(feature = "u128")]
305 ValueKind::U128 => handle_value_kind!(kind, val, id, data_map, as_u128),
306
307 #[cfg(feature = "f32")]
308 ValueKind::F32 => handle_value_kind!(kind, val, id, data_map, as_f32),
309 #[cfg(feature = "f64")]
310 ValueKind::F64 => handle_value_kind!(kind, val, id, data_map, as_f64),
311
312 #[cfg(feature = "string")]
313 ValueKind::String => handle_value_kind!(kind, val, id, data_map, as_string),
314
315 #[cfg(feature = "complex")]
316 ValueKind::C64 => handle_value_kind!(kind, val, id, data_map, as_c64),
317
318 #[cfg(feature = "rational")]
319 ValueKind::R64 => handle_value_kind!(kind, val, id, data_map, as_r64),
320
321 #[cfg(feature = "bool")]
322 ValueKind::Bool => {
323 let vals: Vec<Value> = val.as_vec()
324 .iter()
325 .map(|x| x.as_bool().unwrap().to_value())
326 .collect();
327 data_map.insert(id, (ValueKind::Bool, Value::to_matrix(vals.clone(), vals.len(), 1)));
328 }
329 ValueKind::Any => {
330 let vals: Vec<Value> = val.as_vec()
331 .iter()
332 .map(|x| x.clone())
333 .collect();
334 data_map.insert(id, (ValueKind::Any, Value::to_matrix(vals.clone(), vals.len(), 1)));
335 }
336
337 x => {
338 println!("Unsupported kind in table column: {:?}", x);
339 todo!()
340 }
341 }
342
343 Ok(())
344}
345
346#[cfg(feature = "table")]
347pub fn table(t: &Table, env: Option<&Environment>, p: &Interpreter) -> MResult<Value> {
348 let mut rows = vec![];
349 let headings = table_header(&t.header, env, p)?;
350 let mut cols = 0;
351
352 for row in &t.rows {
354 let result = table_row(row, env, p)?;
355 cols = result.len();
356 rows.push(result);
357 }
358
359 let mut data = vec![Vec::<Value>::new(); cols];
361
362 for row in rows {
364 for (ix, el) in row.into_iter().enumerate() {
365 data[ix].push(el);
366 }
367 }
368
369 let mut data_map: IndexMap<u64,(ValueKind,Matrix<Value>)> = IndexMap::new();
371
372 for ((id, knd, _name), column) in headings.iter().zip(data.iter()) {
373 let id_u64 = id.as_u64().unwrap().borrow().clone();
374
375 let actual_kind = match knd {
377 ValueKind::None => {
378 match column.first() {
379 Some(v) => v.kind(),
380 None => ValueKind::String, }
382 }
383 _ => knd.clone(),
384 };
385
386 let val = Value::to_matrix(column.clone(), column.len(), 1);
388
389 handle_column_kind(actual_kind, id_u64, val, &mut data_map)?;
391 }
392
393 let names: HashMap<u64, String> = headings.iter()
395 .map(|(id, _, name)| (id.as_u64().unwrap().borrow().clone(), name.to_string()))
396 .collect();
397
398 let tbl = MechTable::new(t.rows.len(), cols, data_map.clone(), names);
399 Ok(Value::Table(Ref::new(tbl)))
400}
401
402#[cfg(feature = "kind_annotation")]
403pub fn table_header(fields: &TableHeader, env: Option<&Environment>, p: &Interpreter) -> MResult<Vec<(Value,ValueKind,Identifier)>> {
404 let mut headings: Vec<(Value,ValueKind,Identifier)> = Vec::new();
405 for f in &fields.0 {
406 let id = f.name.hash();
407 let kind = match &f.kind {
408 Some(k) => kind_annotation(&k.kind, p)?,
409 None => Kind::None,
410 };
411 headings.push((Value::Id(id),kind.to_value_kind(&p.state.borrow().kinds)?,f.name.clone()));
412 }
413 Ok(headings)
414}
415
416pub fn table_row(r: &TableRow, env: Option<&Environment>, p: &Interpreter) -> MResult<Vec<Value>> {
417 let mut row: Vec<Value> = Vec::new();
418 for col in &r.columns {
419 let result = table_column(col, env, p)?;
420 row.push(result);
421 }
422 Ok(row)
423}
424
425pub fn table_column(r: &TableColumn, env: Option<&Environment>, p: &Interpreter) -> MResult<Value> {
426 expression(&r.element, env, p)
427}
428
429#[cfg(feature = "matrix")]
433pub fn matrix(m: &Mat, env: Option<&Environment>, p: &Interpreter) -> MResult<Value> {
434 let plan = p.plan();
435 let mut shape = vec![0, 0];
436 let mut col: Vec<Value> = Vec::new();
437 let mut kind = ValueKind::Empty;
438 #[cfg(feature = "matrix_horzcat")]
439 {
440 for row in &m.rows {
441 let result = matrix_row(row, env, p)?;
442 if shape == vec![0,0] {
443 shape = result.shape();
444 kind = result.kind();
445 col.push(result);
446 } else if shape[1] == result.shape()[1] {
447 col.push(result);
448 } else {
449 return Err(MechError::new(
450 DimensionMismatch { dims: vec![shape[1], result.shape()[1]] },
451 None
452 ).with_compiler_loc()
453 );
454 }
455 }
456 if col.is_empty() {
457 return Ok(Value::MatrixValue(Matrix::from_vec(vec![], 0, 0)));
458 } else if col.len() == 1 {
459 return Ok(col[0].clone());
460 }
461 }
462 #[cfg(feature = "matrix_vertcat")]
463 {
464 let new_fxn = MatrixVertCat{}.compile(&col)?;
465 new_fxn.solve();
466 let out = new_fxn.out();
467 let mut plan_brrw = plan.borrow_mut();
468 plan_brrw.push(new_fxn);
469 return Ok(out);
470 }
471 return Err(MechError::new(
472 FeatureNotEnabledError,
473 Some("matrix/vertcat feature not enabled".to_string())).with_compiler_loc()
474 );
475}
476
477#[cfg(feature = "matrix_horzcat")]
478pub fn matrix_row(r: &MatrixRow, env: Option<&Environment>, p: &Interpreter) -> MResult<Value> {
479 let plan = p.plan();
480 let mut row: Vec<Value> = Vec::new();
481 let mut shape = vec![0, 0];
482 let mut kind = ValueKind::Empty;
483 for col in &r.columns {
484 let result = matrix_column(col, env, p)?;
485 if shape == vec![0,0] {
486 shape = result.shape();
487 kind = result.kind();
488 row.push(result);
489 } else if shape[0] == result.shape()[0] {
490 row.push(result);
491 } else {
492 return Err(MechError::new(
493 DimensionMismatch { dims: vec![shape[0], result.shape()[0]] },
494 None
495 ).with_compiler_loc()
496 );
497 }
498 }
499 let new_fxn = MatrixHorzCat{}.compile(&row)?;
500 new_fxn.solve();
501 let out = new_fxn.out();
502 let mut plan_brrw = plan.borrow_mut();
503 plan_brrw.push(new_fxn);
504 Ok(out)
505}
506
507pub fn matrix_column(r: &MatrixColumn, env: Option<&Environment>, p: &Interpreter) -> MResult<Value> {
508 expression(&r.element, env, p)
509}