1use rust_decimal_macros::dec;
2
3use tan::{
4 context::Context,
5 error::Error,
6 expr::{annotate_type, Expr},
7 util::{
8 args::{unpack_float_arg, unpack_int_arg},
9 module_util::require_module,
10 },
11};
12
13pub fn add_int(args: &[Expr]) -> Result<Expr, Error> {
31 let mut xs = Vec::new();
32
33 for arg in args {
34 let Some(n) = arg.as_int() else {
35 return Err(Error::invalid_arguments(
38 &format!("{arg} is not an Int"),
39 arg.range(),
40 ));
41 };
42 xs.push(n);
43 }
44
45 let sum = add_int_impl(xs);
46
47 Ok(Expr::Int(sum))
48}
49
50fn add_int_impl(xs: Vec<i64>) -> i64 {
52 xs.iter().sum()
53}
54
55pub fn add_float(args: &[Expr]) -> Result<Expr, Error> {
56 let mut sum = 0.0;
57
58 for arg in args {
59 let Some(n) = arg.as_float() else {
60 return Err(Error::invalid_arguments(
61 &format!("{arg} is not a Float"),
62 arg.range(),
63 ));
64 };
65 sum += n;
66 }
67
68 Ok(Expr::Float(sum))
69}
70
71pub fn add_dec(args: &[Expr]) -> Result<Expr, Error> {
73 let mut sum = dec!(0.0);
74
75 for arg in args {
76 let Some(n) = arg.as_decimal() else {
77 return Err(Error::invalid_arguments(
78 &format!("{arg} is not a Dec"),
79 arg.range(),
80 ));
81 };
82 sum += n;
83 }
84
85 Ok(Expr::Dec(sum))
86}
87
88pub fn sub_int(args: &[Expr]) -> Result<Expr, Error> {
118 let mut diff = unpack_int_arg(args, 0, "n")?;
121
122 for arg in args.iter().skip(1) {
123 let Some(n) = arg.as_int() else {
124 return Err(Error::invalid_arguments(
125 &format!("{arg} is not an Int"),
126 arg.range(),
127 ));
128 };
129 diff -= n;
130 }
131
132 Ok(Expr::Int(diff))
133}
134
135pub fn neg_int(args: &[Expr]) -> Result<Expr, Error> {
136 let n = unpack_int_arg(args, 0, "n")?;
138 Ok(Expr::Int(-n))
139}
140
141pub fn sub_float(args: &[Expr]) -> Result<Expr, Error> {
142 let [a, b] = args else {
144 return Err(Error::invalid_arguments(
145 "- requires at least two arguments",
146 None,
147 ));
148 };
149
150 let Some(a) = a.as_float() else {
151 return Err(Error::invalid_arguments(
152 &format!("{a} is not a Float"),
153 a.range(),
154 ));
155 };
156
157 let Some(b) = b.as_float() else {
158 return Err(Error::invalid_arguments(
159 &format!("{b} is not a Float"),
160 b.range(),
161 ));
162 };
163
164 Ok(Expr::Float(a - b))
165}
166
167pub fn neg_float(args: &[Expr]) -> Result<Expr, Error> {
168 let n = unpack_float_arg(args, 0, "n")?;
169 Ok(Expr::Float(-n))
170}
171
172pub fn mul_int(args: &[Expr]) -> Result<Expr, Error> {
173 let mut product = 1;
175
176 for arg in args {
177 let Some(n) = arg.as_int() else {
178 return Err(Error::invalid_arguments(
179 &format!("{arg} is not an Int"),
180 arg.range(),
181 ));
182 };
183 product *= n;
184 }
185
186 Ok(Expr::Int(product))
187}
188
189pub fn mul_float(args: &[Expr]) -> Result<Expr, Error> {
190 let mut product = 1.0;
192
193 for arg in args {
194 let Some(n) = arg.as_float() else {
195 return Err(Error::invalid_arguments(
196 &format!("{arg} is not a Float"),
197 arg.range(),
198 ));
199 };
200 product *= n;
201 }
202
203 Ok(Expr::Float(product))
204}
205
206pub fn div_int(args: &[Expr]) -> Result<Expr, Error> {
207 let mut quotient = unpack_int_arg(args, 0, "n")?;
209
210 for arg in args.iter().skip(1) {
211 let Some(n) = arg.as_int() else {
212 return Err(Error::invalid_arguments(
213 &format!("{arg} is not an Int"),
214 arg.range(),
215 ));
216 };
217
218 quotient /= n;
219 }
220
221 Ok(Expr::Int(quotient))
222}
223
224pub fn div_float(args: &[Expr]) -> Result<Expr, Error> {
226 let mut quotient = f64::NAN;
228
229 for arg in args {
233 let Some(n) = arg.as_float() else {
234 return Err(Error::invalid_arguments(
235 &format!("{arg} is not a Float"),
236 arg.range(),
237 ));
238 };
239
240 if quotient.is_nan() {
241 quotient = n;
242 } else {
243 quotient /= n;
244 }
245 }
246
247 Ok(Expr::Float(quotient))
248}
249
250pub fn mod_int(args: &[Expr]) -> Result<Expr, Error> {
251 let x = unpack_int_arg(args, 0, "x")?;
253 let y = unpack_int_arg(args, 1, "y")?;
254
255 Ok(Expr::Int(x % y))
256}
257
258pub fn mod_float(args: &[Expr]) -> Result<Expr, Error> {
259 let x = unpack_float_arg(args, 0, "x")?;
261 let y = unpack_float_arg(args, 1, "y")?;
262
263 Ok(Expr::Float(x % y))
264}
265
266pub fn int_compare(args: &[Expr]) -> Result<Expr, Error> {
268 let [a, b] = args else {
270 return Err(Error::invalid_arguments(
271 "requires at least two arguments",
272 None,
273 ));
274 };
275
276 let Some(a) = a.as_int() else {
277 return Err(Error::invalid_arguments(
278 &format!("{a} is not an Int"),
279 a.range(),
280 ));
281 };
282
283 let Some(b) = b.as_int() else {
284 return Err(Error::invalid_arguments(
285 &format!("{b} is not an Int"),
286 b.range(),
287 ));
288 };
289
290 let ordering = match a.cmp(&b) {
292 std::cmp::Ordering::Less => -1,
293 std::cmp::Ordering::Equal => 0,
294 std::cmp::Ordering::Greater => 1,
295 };
296
297 Ok(Expr::Int(ordering))
298}
299
300pub fn setup_lib_arithmetic(context: &mut Context) {
301 let module = require_module("prelude", context);
302
303 module.insert_invocable("+", annotate_type(Expr::foreign_func(&add_int), "Int"));
307 module.insert_invocable(
308 "+$$Int$$Int",
309 annotate_type(Expr::foreign_func(&add_int), "Int"),
310 );
311 module.insert_invocable(
313 "+$$Int$$Int$$Int",
314 annotate_type(Expr::foreign_func(&add_int), "Int"),
315 );
316 module.insert_invocable(
317 "+$$Int$$Int$$Int$$Int",
318 annotate_type(Expr::foreign_func(&add_int), "Int"),
319 );
320 module.insert_invocable(
321 "+$$Float$$Float",
322 annotate_type(Expr::foreign_func(&add_float), "Float"),
325 );
326 module.insert_invocable(
328 "+$$Float$$Float$$Float",
329 annotate_type(Expr::foreign_func(&add_float), "Float"),
332 );
333 module.insert_invocable(
334 "+$$Float$$Float$$Float$$Float",
335 annotate_type(Expr::foreign_func(&add_float), "Float"),
338 );
339 module.insert_invocable(
340 "+$$Dec$$Dec",
341 annotate_type(Expr::foreign_func(&add_dec), "Dec"),
344 );
345 module.insert_invocable("-", Expr::foreign_func(&sub_int));
346 module.insert_invocable("-$$Int", annotate_type(Expr::foreign_func(&neg_int), "Int"));
347 module.insert_invocable(
348 "-$$Int$$Int",
349 annotate_type(Expr::foreign_func(&sub_int), "Int"),
350 );
351 module.insert_invocable(
353 "-$$Int$$Int$$Int",
354 annotate_type(Expr::foreign_func(&sub_int), "Int"),
355 );
356 module.insert_invocable(
357 "-$$Int$$Int$$Int$$Int",
358 annotate_type(Expr::foreign_func(&sub_int), "Int"),
359 );
360 module.insert_invocable(
361 "-$$Float",
362 annotate_type(Expr::foreign_func(&neg_float), "Float"),
363 );
364 module.insert_invocable(
365 "-$$Float$$Float",
366 annotate_type(Expr::foreign_func(&sub_float), "Float"),
367 );
368 module.insert_invocable("*", Expr::foreign_func(&mul_int));
369 module.insert_invocable(
370 "*$$Int$$Int",
371 annotate_type(Expr::foreign_func(&mul_int), "Int"),
372 );
373 module.insert_invocable(
375 "*$$Int$$Int$$Int",
376 annotate_type(Expr::foreign_func(&mul_int), "Int"),
377 );
378 module.insert_invocable(
379 "*$$Float$$Float",
380 annotate_type(Expr::foreign_func(&mul_float), "Float"),
383 );
384 module.insert_invocable(
385 "*$$Float$$Float$$Float",
386 annotate_type(Expr::foreign_func(&mul_float), "Float"),
389 );
390 module.insert_invocable("/", annotate_type(Expr::foreign_func(&div_float), "Float"));
391 module.insert_invocable(
392 "/$$Int$$Int",
393 annotate_type(Expr::foreign_func(&div_int), "Int"),
394 );
395 module.insert_invocable(
397 "/$$Float$$Float",
398 annotate_type(Expr::foreign_func(&div_float), "Float"),
399 );
400 module.insert_invocable(
402 "/$$Float$$Float$$Float",
403 annotate_type(Expr::foreign_func(&div_float), "Float"),
404 );
405 module.insert_invocable("%", annotate_type(Expr::foreign_func(&mod_int), "Int"));
408 module.insert_invocable(
409 "%$$Int$$Int",
410 annotate_type(Expr::foreign_func(&mod_int), "Int"),
411 );
412 module.insert_invocable(
413 "%$$Float$$Float",
414 annotate_type(Expr::foreign_func(&mod_float), "Float"),
415 );
416}