1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
use crate::{
parser::Type,
ty,
unroll::{AnyExpr, Convert},
};
use super::{prelude::*, Overload};
struct MidPoint;
impl Overload for MidPoint {
fn get_returned_type(&self, params: &[AnyExpr]) -> Option<Type> {
params
.iter()
.all(|p| p.can_convert_to(Type::Point))
.then_some(Type::Point)
}
fn unroll(
&self,
params: Vec<AnyExpr>,
context: &mut CompileContext,
props: Properties,
) -> AnyExpr {
context
.average_p_display(
params.into_iter().map(|x| x.convert(context)).collect(),
props,
)
.into()
}
}
struct MidNumber;
impl Overload for MidNumber {
fn get_returned_type(&self, params: &[AnyExpr]) -> Option<Type> {
// This overload is only valid if all params are scalars of the same unit.
// To check this, we convert the first param to a scalar of any unit,
// get its type and check if every next param can also be converted.
let mut unit = None;
for param in params {
if let Some(u) = param.can_convert_to_scalar(unit) {
unit = u;
} else {
return None;
}
}
Some(Type::Number(unit))
}
fn unroll(
&self,
params: Vec<AnyExpr>,
context: &mut CompileContext,
props: Properties,
) -> AnyExpr {
let ty = self.get_returned_type(¶ms).unwrap();
context
.average_s_display(
params
.into_iter()
.map(|x| x.convert_to(ty, context).to_scalar().unwrap())
.collect(),
props,
)
.into()
}
}
// Registers the `mid` function.
//
// # Note:
// Moved `...DISTANCE` rule to the end
// to avoid ambiguity with two-point rule (2-P).
// mid(AB) should be interpreted as mid(A, B), and
// not as average of one number, the length of AB.
// This is somewhat temporary, eventually we should
// have a way of specifying that there should be
// at least two `DISTANCE arguments in the last rule.
pub fn register(library: &mut Library) {
library
.add(
Function::new("mid")
.overload(|mut col: Pc<0>, context: &CompileContext, props| {
context.average_p_display(
(0..col.0.data.length)
.map(|i| index!(node col, i))
.collect(),
props,
)
})
.overload(MidNumber)
.overload(MidPoint),
)
.add(
Function::new("[pc]::mid")
.alias_method(ty::collection(0), "mid")
.overload(|mut col: Pc<0>, context: &CompileContext, props| {
context.average_p_display(
(0..col.0.data.length)
.map(|i| index!(node col, i))
.collect(),
props,
)
}),
);
}