1use core::f64;
2
3use tan::{
4 context::Context,
5 error::Error,
6 expr::Expr,
7 util::{
8 args::{unpack_bool_arg, unpack_float_arg, unpack_stringable_arg},
9 module_util::require_module,
10 },
11};
12
13pub fn float_from_int(args: &[Expr]) -> Result<Expr, Error> {
20 let [value] = args else {
21 return Err(Error::invalid_arguments("requires `value` argument", None));
22 };
23
24 let Some(value) = value.as_int() else {
26 return Err(Error::invalid_arguments(
27 &format!("value=`{value}` is not Int"),
28 value.range(),
29 ));
30 };
31
32 Ok(Expr::Float(value as f64))
33}
34
35pub fn float_from_bool(args: &[Expr]) -> Result<Expr, Error> {
37 let value = unpack_bool_arg(args, 0, "value")?;
38
39 Ok(Expr::Float(if value { 1.0 } else { 0.0 }))
40}
41
42pub fn float_from_string(args: &[Expr]) -> Result<Expr, Error> {
44 let string = unpack_stringable_arg(args, 0, "string")?;
45 let Ok(value) = string.parse::<f64>() else {
46 return Err(Error::invalid_arguments(
47 &format!("string=`{string}` is not a valid Float number"),
48 args[0].range(),
49 ));
50 };
51 Ok(Expr::Float(value))
52}
53
54pub fn float_min(args: &[Expr]) -> Result<Expr, Error> {
59 let mut min = f64::MAX;
60
61 for arg in args {
62 let Some(n) = arg.as_float() else {
63 return Err(Error::invalid_arguments(
64 &format!("{arg} is not a Float"),
65 arg.range(),
66 ));
67 };
68 if n < min {
69 min = n;
70 }
71 }
72
73 Ok(Expr::Float(min))
74}
75
76pub fn float_max(args: &[Expr]) -> Result<Expr, Error> {
77 let mut max = f64::MIN;
78
79 for arg in args {
80 let Some(n) = arg.as_float() else {
81 return Err(Error::invalid_arguments(
82 &format!("{arg} is not a Float"),
83 arg.range(),
84 ));
85 };
86 if n > max {
87 max = n;
88 }
89 }
90
91 Ok(Expr::Float(max))
92}
93
94pub fn float_abs(args: &[Expr]) -> Result<Expr, Error> {
96 let n = unpack_float_arg(args, 0, "n")?;
97 Ok(Expr::Float(n.abs()))
98}
99
100pub fn float_floor(args: &[Expr]) -> Result<Expr, Error> {
104 let n = unpack_float_arg(args, 0, "n")?;
105 Ok(Expr::Float(n.floor()))
106}
107
108pub fn float_ceil(args: &[Expr]) -> Result<Expr, Error> {
109 let n = unpack_float_arg(args, 0, "n")?;
110 Ok(Expr::Float(n.ceil()))
111}
112
113pub fn float_round(args: &[Expr]) -> Result<Expr, Error> {
116 let n = unpack_float_arg(args, 0, "n")?;
117 Ok(Expr::Float(n.round()))
119}
120
121pub fn float_sqrt(args: &[Expr]) -> Result<Expr, Error> {
122 let n = unpack_float_arg(args, 0, "n")?;
123 Ok(Expr::Float(n.sqrt()))
124}
125
126pub fn float_sin(args: &[Expr]) -> Result<Expr, Error> {
127 let Some(n) = args.first() else {
128 return Err(Error::invalid_arguments("missing argument", None));
129 };
130
131 let Some(n) = n.as_float() else {
132 return Err(Error::invalid_arguments(
133 "expected Float argument",
134 n.range(),
135 ));
136 };
137
138 Ok(Expr::Float(n.sin()))
139}
140
141pub fn float_cos(args: &[Expr]) -> Result<Expr, Error> {
142 let Some(n) = args.first() else {
143 return Err(Error::invalid_arguments("missing argument", None));
144 };
145
146 let Some(n) = n.as_float() else {
147 return Err(Error::invalid_arguments(
148 "expected Float argument",
149 n.range(),
150 ));
151 };
152
153 Ok(Expr::Float(n.cos()))
154}
155
156pub fn float_tan(args: &[Expr]) -> Result<Expr, Error> {
158 let n = unpack_float_arg(args, 0, "n")?;
159 Ok(Expr::Float(n.tan()))
160}
161
162pub fn float_powi(args: &[Expr]) -> Result<Expr, Error> {
164 let [n, e] = args else {
165 return Err(Error::invalid_arguments(
166 "- requires at least two arguments",
167 None,
168 ));
169 };
170
171 let Some(n) = n.as_float() else {
173 return Err(Error::invalid_arguments(
174 &format!("{n} is not a Float"),
175 n.range(),
176 ));
177 };
178
179 let Some(e) = e.as_int() else {
180 return Err(Error::invalid_arguments(
181 &format!("{e} is not an Int"),
182 e.range(),
183 ));
184 };
185
186 Ok(Expr::Float(n.powi(e as i32)))
187}
188
189pub fn setup_lib_float(context: &mut Context) {
193 let module = require_module("prelude", context);
195
196 module.insert_invocable("Float", Expr::foreign_func(&float_from_int));
202 module.insert_invocable("Float$$Int", Expr::foreign_func(&float_from_int));
203 module.insert_invocable("Float$$Bool", Expr::foreign_func(&float_from_bool));
204 module.insert_invocable("Float$$String", Expr::foreign_func(&float_from_string));
205 module.insert_invocable("min", Expr::foreign_func(&float_min));
206 module.insert_invocable(
207 "min$$Float$$Float",
208 Expr::foreign_func(&float_min),
210 );
211 module.insert_invocable("max", Expr::foreign_func(&float_max));
212 module.insert_invocable(
213 "max$$Float$$Float",
214 Expr::foreign_func(&float_max),
216 );
217
218 module.insert_invocable("abs", Expr::foreign_func(&float_abs));
219 module.insert_invocable("abs$$Float", Expr::foreign_func(&float_abs));
220
221 module.insert_invocable("floor$$Float", Expr::foreign_func(&float_floor));
224 module.insert_invocable("ceil$$Float", Expr::foreign_func(&float_ceil));
225 module.insert_invocable("round$$Float", Expr::foreign_func(&float_round));
226
227 module.insert_invocable("sqrt", Expr::foreign_func(&float_sqrt));
230 module.insert_invocable("sqrt$$Float", Expr::foreign_func(&float_sqrt));
231
232 module.insert_invocable("sin", Expr::foreign_func(&float_sin));
233 module.insert_invocable("cos", Expr::foreign_func(&float_cos));
234 module.insert_invocable("tan", Expr::foreign_func(&float_tan));
235 module.insert_invocable("**", Expr::foreign_func(&float_powi));
236 module.insert_invocable("**$$Float$$Int", Expr::foreign_func(&float_powi));
237
238 module.insert_invocable("float/max", Expr::Float(f64::MAX));
246 module.insert_invocable("float/infinity", Expr::Float(f64::INFINITY));
247}