1use crate::data::primitive::tools::check_division_by_zero_f64;
2use crate::data::{
3 ast::Interval,
4 error_info::ErrorInfo,
5 literal,
6 literal::ContentType,
7 message::Message,
8 position::Position,
9 primitive::{
10 Primitive, PrimitiveBoolean, PrimitiveInt, PrimitiveObject, PrimitiveString, PrimitiveType,
11 Right,
12 },
13 Data, Literal, MemoryType, MessageData, MSG,
14};
15use crate::error_format::*;
16use phf::phf_map;
17use serde::{Deserialize, Serialize};
18use std::cmp::Ordering;
19use std::{collections::HashMap, sync::mpsc};
20
21type PrimitiveMethod = fn(
26 float: &mut PrimitiveFloat,
27 args: &HashMap<String, Literal>,
28 additional_info: &Option<HashMap<String, Literal>>,
29 data: &mut Data,
30 interval: Interval,
31) -> Result<Literal, ErrorInfo>;
32
33const FUNCTIONS: phf::Map<&'static str, (PrimitiveMethod, Right)> = phf_map! {
34 "is_number" => (PrimitiveFloat::is_number as PrimitiveMethod, Right::Read),
35 "is_int" => (PrimitiveFloat::is_int as PrimitiveMethod, Right::Read),
36 "is_float" => (PrimitiveFloat::is_float as PrimitiveMethod, Right::Read),
37 "type_of" => (PrimitiveFloat::type_of as PrimitiveMethod, Right::Read),
38 "is_error" => (PrimitiveFloat::is_error as PrimitiveMethod, Right::Read),
39 "get_info" => (PrimitiveFloat::get_info as PrimitiveMethod, Right::Read),
40 "to_string" => (PrimitiveFloat::to_string as PrimitiveMethod, Right::Read),
41
42 "precision" => (PrimitiveFloat::precision as PrimitiveMethod, Right::Read),
43 "abs" => (PrimitiveFloat::abs as PrimitiveMethod, Right::Read),
44 "cos" => (PrimitiveFloat::cos as PrimitiveMethod, Right::Read),
45 "ceil" => (PrimitiveFloat::ceil as PrimitiveMethod, Right::Read),
46 "floor" => (PrimitiveFloat::floor as PrimitiveMethod, Right::Read),
47 "pow" => (PrimitiveFloat::pow as PrimitiveMethod, Right::Read),
48 "round" => (PrimitiveFloat::round as PrimitiveMethod, Right::Read),
49 "sin" => (PrimitiveFloat::sin as PrimitiveMethod, Right::Read),
50 "sqrt" => (PrimitiveFloat::sqrt as PrimitiveMethod, Right::Read),
51 "tan" => (PrimitiveFloat::tan as PrimitiveMethod, Right::Read),
52 "to_int" => (PrimitiveFloat::to_int as PrimitiveMethod, Right::Read),
53 "to_float" => (PrimitiveFloat::to_float as PrimitiveMethod, Right::Read),
54};
55#[derive(PartialEq, Debug, Clone, Serialize, Deserialize)]
56pub struct PrimitiveFloat {
57 pub value: f64,
58}
59
60impl PrimitiveFloat {
65 fn is_number(
66 _float: &mut PrimitiveFloat,
67 args: &HashMap<String, Literal>,
68 _additional_info: &Option<HashMap<String, Literal>>,
69 data: &mut Data,
70 interval: Interval,
71 ) -> Result<Literal, ErrorInfo> {
72 let usage = "is_number() => boolean";
73
74 if !args.is_empty() {
75 return Err(gen_error_info(
76 Position::new(interval, &data.context.flow),
77 format!("usage: {}", usage),
78 ));
79 }
80
81 Ok(PrimitiveBoolean::get_literal(true, interval))
82 }
83
84 fn is_int(
85 _float: &mut PrimitiveFloat,
86 args: &HashMap<String, Literal>,
87 _additional_info: &Option<HashMap<String, Literal>>,
88 data: &mut Data,
89 interval: Interval,
90 ) -> Result<Literal, ErrorInfo> {
91 let usage = "is_int() => boolean";
92
93 if !args.is_empty() {
94 return Err(gen_error_info(
95 Position::new(interval, &data.context.flow),
96 format!("usage: {}", usage),
97 ));
98 }
99
100 Ok(PrimitiveBoolean::get_literal(false, interval))
101 }
102
103 fn is_float(
104 _float: &mut PrimitiveFloat,
105 args: &HashMap<String, Literal>,
106 _additional_info: &Option<HashMap<String, Literal>>,
107 data: &mut Data,
108 interval: Interval,
109 ) -> Result<Literal, ErrorInfo> {
110 let usage = "is_float() => boolean";
111
112 if !args.is_empty() {
113 return Err(gen_error_info(
114 Position::new(interval, &data.context.flow),
115 format!("usage: {}", usage),
116 ));
117 }
118
119 Ok(PrimitiveBoolean::get_literal(true, interval))
120 }
121
122 fn type_of(
123 _float: &mut PrimitiveFloat,
124 args: &HashMap<String, Literal>,
125 _additional_info: &Option<HashMap<String, Literal>>,
126 data: &mut Data,
127 interval: Interval,
128 ) -> Result<Literal, ErrorInfo> {
129 let usage = "type_of() => string";
130
131 if !args.is_empty() {
132 return Err(gen_error_info(
133 Position::new(interval, &data.context.flow),
134 format!("usage: {}", usage),
135 ));
136 }
137
138 Ok(PrimitiveString::get_literal("float", interval))
139 }
140
141 fn get_info(
142 _float: &mut PrimitiveFloat,
143 args: &HashMap<String, Literal>,
144 additional_info: &Option<HashMap<String, Literal>>,
145 data: &mut Data,
146 interval: Interval,
147 ) -> Result<Literal, ErrorInfo> {
148 literal::get_info(args, additional_info, interval, data)
149 }
150
151 fn is_error(
152 _float: &mut PrimitiveFloat,
153 _args: &HashMap<String, Literal>,
154 additional_info: &Option<HashMap<String, Literal>>,
155 _data: &mut Data,
156 interval: Interval,
157 ) -> Result<Literal, ErrorInfo> {
158 match additional_info {
159 Some(map) if map.contains_key("error") => {
160 Ok(PrimitiveBoolean::get_literal(true, interval))
161 }
162 _ => Ok(PrimitiveBoolean::get_literal(false, interval)),
163 }
164 }
165
166 fn to_string(
167 float: &mut PrimitiveFloat,
168 args: &HashMap<String, Literal>,
169 _additional_info: &Option<HashMap<String, Literal>>,
170 data: &mut Data,
171 interval: Interval,
172 ) -> Result<Literal, ErrorInfo> {
173 let usage = "to_string() => string";
174
175 if !args.is_empty() {
176 return Err(gen_error_info(
177 Position::new(interval, &data.context.flow),
178 format!("usage: {}", usage),
179 ));
180 }
181
182 Ok(PrimitiveString::get_literal(&float.to_string(), interval))
183 }
184}
185
186impl PrimitiveFloat {
187 fn abs(
188 float: &mut PrimitiveFloat,
189 args: &HashMap<String, Literal>,
190 _additional_info: &Option<HashMap<String, Literal>>,
191 data: &mut Data,
192 interval: Interval,
193 ) -> Result<Literal, ErrorInfo> {
194 let usage = "abs() => float";
195
196 if !args.is_empty() {
197 return Err(gen_error_info(
198 Position::new(interval, &data.context.flow),
199 format!("usage: {}", usage),
200 ));
201 }
202
203 let result = float.value.abs();
204
205 Ok(PrimitiveFloat::get_literal(result, interval))
206 }
207
208 fn cos(
209 float: &mut PrimitiveFloat,
210 args: &HashMap<String, Literal>,
211 _additional_info: &Option<HashMap<String, Literal>>,
212 data: &mut Data,
213 interval: Interval,
214 ) -> Result<Literal, ErrorInfo> {
215 let usage = "cos() => float";
216
217 if !args.is_empty() {
218 return Err(gen_error_info(
219 Position::new(interval, &data.context.flow),
220 format!("usage: {}", usage),
221 ));
222 }
223
224 let result = float.value.cos();
225
226 Ok(PrimitiveFloat::get_literal(result, interval))
227 }
228
229 fn ceil(
230 float: &mut PrimitiveFloat,
231 args: &HashMap<String, Literal>,
232 _additional_info: &Option<HashMap<String, Literal>>,
233 data: &mut Data,
234 interval: Interval,
235 ) -> Result<Literal, ErrorInfo> {
236 let usage = "ceil() => float";
237
238 if !args.is_empty() {
239 return Err(gen_error_info(
240 Position::new(interval, &data.context.flow),
241 format!("usage: {}", usage),
242 ));
243 }
244
245 let result = float.value.ceil();
246
247 Ok(PrimitiveFloat::get_literal(result, interval))
248 }
249
250 fn precision(
251 float: &mut PrimitiveFloat,
252 args: &HashMap<String, Literal>,
253 _additional_info: &Option<HashMap<String, Literal>>,
254 data: &mut Data,
255 interval: Interval,
256 ) -> Result<Literal, ErrorInfo> {
257 let usage = "precision(value) => float";
258
259 let precision = match args.get("arg0") {
260 Some(int) if int.primitive.get_type() == PrimitiveType::PrimitiveInt => {
261 Literal::get_value::<i64>(
262 &int.primitive,
263 &data.context.flow,
264 int.interval,
265 format!("usage: {}", usage),
266 )?
267 }
268 _ => {
269 return Err(gen_error_info(
270 Position::new(interval, &data.context.flow),
271 format!("usage: {}", usage),
272 ))
273 }
274 };
275
276 let result = format!("{:.*}", *precision as usize, float.value)
277 .parse::<f64>()
278 .unwrap_or(float.value);
279
280 Ok(PrimitiveFloat::get_literal(result, interval))
281 }
282
283 fn floor(
284 float: &mut PrimitiveFloat,
285 args: &HashMap<String, Literal>,
286 _additional_info: &Option<HashMap<String, Literal>>,
287 data: &mut Data,
288 interval: Interval,
289 ) -> Result<Literal, ErrorInfo> {
290 let usage = "floor() => float";
291
292 if !args.is_empty() {
293 return Err(gen_error_info(
294 Position::new(interval, &data.context.flow),
295 format!("usage: {}", usage),
296 ));
297 }
298
299 let result = float.value.floor();
300
301 Ok(PrimitiveFloat::get_literal(result, interval))
302 }
303
304 fn pow(
305 float: &mut PrimitiveFloat,
306 args: &HashMap<String, Literal>,
307 _additional_info: &Option<HashMap<String, Literal>>,
308 data: &mut Data,
309 interval: Interval,
310 ) -> Result<Literal, ErrorInfo> {
311 let usage = "pow(exponent: number) => float";
312
313 if args.len() != 1 {
314 return Err(gen_error_info(
315 Position::new(interval, &data.context.flow),
316 format!("usage: {}", usage),
317 ));
318 }
319
320 let exponent = match args.get("arg0") {
321 Some(exponent) if exponent.primitive.get_type() == PrimitiveType::PrimitiveInt => {
322 *Literal::get_value::<i64>(
323 &exponent.primitive,
324 &data.context.flow,
325 interval,
326 ERROR_NUMBER_POW.to_owned(),
327 )? as f64
328 }
329 Some(exponent) if exponent.primitive.get_type() == PrimitiveType::PrimitiveFloat => {
330 *Literal::get_value::<f64>(
331 &exponent.primitive,
332 &data.context.flow,
333 interval,
334 ERROR_NUMBER_POW.to_owned(),
335 )?
336 }
337 Some(exponent) if exponent.primitive.get_type() == PrimitiveType::PrimitiveString => {
338 let exponent = Literal::get_value::<String>(
339 &exponent.primitive,
340 &data.context.flow,
341 interval,
342 ERROR_NUMBER_POW.to_owned(),
343 )?;
344
345 match exponent.parse::<f64>() {
346 Ok(res) => res,
347 Err(_) => {
348 return Err(gen_error_info(
349 Position::new(interval, &data.context.flow),
350 ERROR_NUMBER_POW.to_owned(),
351 ));
352 }
353 }
354 }
355 _ => {
356 return Err(gen_error_info(
357 Position::new(interval, &data.context.flow),
358 ERROR_NUMBER_POW.to_owned(),
359 ));
360 }
361 };
362
363 let result = float.value.powf(exponent);
364
365 Ok(PrimitiveFloat::get_literal(result, interval))
366 }
367
368 fn round(
369 float: &mut PrimitiveFloat,
370 args: &HashMap<String, Literal>,
371 _additional_info: &Option<HashMap<String, Literal>>,
372 data: &mut Data,
373 interval: Interval,
374 ) -> Result<Literal, ErrorInfo> {
375 let usage = "round() => float";
376
377 if !args.is_empty() {
378 return Err(gen_error_info(
379 Position::new(interval, &data.context.flow),
380 format!("usage: {}", usage),
381 ));
382 }
383
384 let result = float.value.round();
385
386 Ok(PrimitiveFloat::get_literal(result, interval))
387 }
388
389 fn sin(
390 float: &mut PrimitiveFloat,
391 args: &HashMap<String, Literal>,
392 _additional_info: &Option<HashMap<String, Literal>>,
393 data: &mut Data,
394 interval: Interval,
395 ) -> Result<Literal, ErrorInfo> {
396 let usage = "sin() => float";
397
398 if !args.is_empty() {
399 return Err(gen_error_info(
400 Position::new(interval, &data.context.flow),
401 format!("usage: {}", usage),
402 ));
403 }
404
405 let result = float.value.sin();
406
407 Ok(PrimitiveFloat::get_literal(result, interval))
408 }
409
410 fn sqrt(
411 float: &mut PrimitiveFloat,
412 args: &HashMap<String, Literal>,
413 _additional_info: &Option<HashMap<String, Literal>>,
414 data: &mut Data,
415 interval: Interval,
416 ) -> Result<Literal, ErrorInfo> {
417 let usage = "sqrt() => float";
418
419 if !args.is_empty() {
420 return Err(gen_error_info(
421 Position::new(interval, &data.context.flow),
422 format!("usage: {}", usage),
423 ));
424 }
425
426 let result = float.value.sqrt();
427
428 Ok(PrimitiveFloat::get_literal(result, interval))
429 }
430
431 fn tan(
432 float: &mut PrimitiveFloat,
433 args: &HashMap<String, Literal>,
434 _additional_info: &Option<HashMap<String, Literal>>,
435 data: &mut Data,
436 interval: Interval,
437 ) -> Result<Literal, ErrorInfo> {
438 let usage = "tan() => float";
439
440 if !args.is_empty() {
441 return Err(gen_error_info(
442 Position::new(interval, &data.context.flow),
443 format!("usage: {}", usage),
444 ));
445 }
446
447 let result = float.value.tan();
448
449 Ok(PrimitiveFloat::get_literal(result, interval))
450 }
451
452 fn to_int(
453 float: &mut PrimitiveFloat,
454 args: &HashMap<String, Literal>,
455 _additional_info: &Option<HashMap<String, Literal>>,
456 data: &mut Data,
457 interval: Interval,
458 ) -> Result<Literal, ErrorInfo> {
459 let usage = "to_int() => int";
460
461 if !args.is_empty() {
462 return Err(gen_error_info(
463 Position::new(interval, &data.context.flow),
464 format!("usage: {}", usage),
465 ));
466 }
467
468 Ok(PrimitiveInt::get_literal(float.value as i64, interval))
469 }
470
471 fn to_float(
472 float: &mut PrimitiveFloat,
473 args: &HashMap<String, Literal>,
474 _additional_info: &Option<HashMap<String, Literal>>,
475 data: &mut Data,
476 interval: Interval,
477 ) -> Result<Literal, ErrorInfo> {
478 let usage = "to_float() => float";
479
480 if !args.is_empty() {
481 return Err(gen_error_info(
482 Position::new(interval, &data.context.flow),
483 format!("usage: {}", usage),
484 ));
485 }
486
487 Ok(PrimitiveFloat::get_literal(float.value, interval))
488 }
489}
490
491impl PrimitiveFloat {
496 pub fn new(value: f64) -> Self {
497 Self { value }
498 }
499
500 pub fn get_literal(float: f64, interval: Interval) -> Literal {
501 let primitive = Box::new(PrimitiveFloat::new(float));
502
503 Literal {
504 content_type: "float".to_owned(),
505 primitive,
506 additional_info: None,
507 secure_variable: false,
508 interval,
509 }
510 }
511}
512
513#[typetag::serde]
518impl Primitive for PrimitiveFloat {
519 fn is_eq(&self, other: &dyn Primitive) -> bool {
520 if let Some(other) = other.as_any().downcast_ref::<Self>() {
521 return self.value == other.value;
522 }
523
524 false
525 }
526
527 fn is_cmp(&self, other: &dyn Primitive) -> Option<Ordering> {
528 if let Some(other) = other.as_any().downcast_ref::<Self>() {
529 return self.value.partial_cmp(&other.value);
530 }
531
532 None
533 }
534
535 fn do_add(&self, other: &dyn Primitive) -> Result<Box<dyn Primitive>, String> {
536 let mut error_msg = ERROR_ILLEGAL_OPERATION;
537
538 if let Some(other) = other.as_any().downcast_ref::<Self>() {
539 let lhs = self.value as i64;
540 let rhs = other.value as i64;
541
542 if lhs.checked_add(rhs).is_some() {
543 return Ok(Box::new(PrimitiveFloat::new(self.value + other.value)));
544 }
545
546 error_msg = OVERFLOWING_OPERATION;
547 }
548
549 Err(format!(
550 "{} {:?} + {:?}",
551 error_msg,
552 self.get_type(),
553 other.get_type()
554 ))
555 }
556
557 fn do_sub(&self, other: &dyn Primitive) -> Result<Box<dyn Primitive>, String> {
558 let mut error_msg = ERROR_ILLEGAL_OPERATION;
559
560 if let Some(other) = other.as_any().downcast_ref::<Self>() {
561 let lhs = self.value as i64;
562 let rhs = other.value as i64;
563
564 if lhs.checked_sub(rhs).is_some() {
565 return Ok(Box::new(PrimitiveFloat::new(self.value - other.value)));
566 }
567
568 error_msg = OVERFLOWING_OPERATION;
569 }
570
571 Err(format!(
572 "{} {:?} - {:?}",
573 error_msg,
574 self.get_type(),
575 other.get_type()
576 ))
577 }
578
579 fn do_div(&self, other: &dyn Primitive) -> Result<Box<dyn Primitive>, String> {
580 let mut error_msg = ERROR_ILLEGAL_OPERATION;
581
582 if let Some(other) = other.as_any().downcast_ref::<Self>() {
583 check_division_by_zero_f64(self.value, other.value)?;
584
585 let lhs = self.value as i64;
586 let rhs = other.value as i64;
587
588 if lhs.checked_div(rhs).is_some() {
589 return Ok(Box::new(PrimitiveFloat::new(self.value / other.value)));
590 }
591
592 error_msg = OVERFLOWING_OPERATION;
593 }
594
595 Err(format!(
596 "{} {:?} / {:?}",
597 error_msg,
598 self.get_type(),
599 other.get_type()
600 ))
601 }
602
603 fn do_mul(&self, other: &dyn Primitive) -> Result<Box<dyn Primitive>, String> {
604 let mut error_msg = ERROR_ILLEGAL_OPERATION;
605
606 if let Some(other) = other.as_any().downcast_ref::<Self>() {
607 let lhs = self.value as i64;
608 let rhs = other.value as i64;
609
610 if lhs.checked_mul(rhs).is_some() {
611 return Ok(Box::new(PrimitiveFloat::new(self.value * other.value)));
612 }
613
614 error_msg = OVERFLOWING_OPERATION;
615 }
616
617 Err(format!(
618 "{} {:?} * {:?}",
619 error_msg,
620 self.get_type(),
621 other.get_type()
622 ))
623 }
624
625 fn do_rem(&self, other: &dyn Primitive) -> Result<Box<dyn Primitive>, String> {
626 let mut error_msg = ERROR_ILLEGAL_OPERATION;
627
628 if let Some(other) = other.as_any().downcast_ref::<Self>() {
629 let lhs = self.value as i64;
630 let rhs = other.value as i64;
631
632 if lhs.checked_rem(rhs).is_some() {
633 return Ok(Box::new(PrimitiveFloat::new(self.value % other.value)));
634 }
635
636 error_msg = OVERFLOWING_OPERATION;
637 }
638
639 Err(format!(
640 "{} {:?} % {:?}",
641 error_msg,
642 self.get_type(),
643 other.get_type()
644 ))
645 }
646
647 fn as_debug(&self) -> &dyn std::fmt::Debug {
648 self
649 }
650
651 fn as_any(&self) -> &dyn std::any::Any {
652 self
653 }
654
655 fn get_type(&self) -> PrimitiveType {
656 PrimitiveType::PrimitiveFloat
657 }
658
659 fn as_box_clone(&self) -> Box<dyn Primitive> {
660 Box::new((*self).clone())
661 }
662
663 fn to_json(&self) -> serde_json::Value {
664 serde_json::json!(self.value)
665 }
666
667 fn format_mem(&self, _content_type: &str, _first: bool) -> serde_json::Value {
668 serde_json::json!(self.value)
669 }
670
671 fn to_string(&self) -> String {
672 self.value.to_string()
673 }
674
675 fn as_bool(&self) -> bool {
676 self.value.is_normal()
677 }
678
679 fn get_value(&self) -> &dyn std::any::Any {
680 &self.value
681 }
682
683 fn get_mut_value(&mut self) -> &mut dyn std::any::Any {
684 &mut self.value
685 }
686
687 fn to_msg(&self, _content_type: String) -> Message {
688 let mut hashmap: HashMap<String, Literal> = HashMap::new();
689
690 hashmap.insert(
691 "text".to_owned(),
692 Literal {
693 content_type: "float".to_owned(),
694 primitive: Box::new(PrimitiveString::new(&self.to_string())),
695 additional_info: None,
696 secure_variable: false,
697 interval: Interval {
698 start_column: 0,
699 start_line: 0,
700 offset: 0,
701 end_line: None,
702 end_column: None,
703 },
704 },
705 );
706
707 let mut result = PrimitiveObject::get_literal(
708 &hashmap,
709 Interval {
710 start_column: 0,
711 start_line: 0,
712 offset: 0,
713 end_line: None,
714 end_column: None,
715 },
716 );
717 result.set_content_type("text");
718
719 Message {
720 content_type: result.content_type,
721 content: result.primitive.to_json(),
722 }
723 }
724
725 fn do_exec(
726 &mut self,
727 name: &str,
728 args: &HashMap<String, Literal>,
729 mem_type: &MemoryType,
730 additional_info: &Option<HashMap<String, Literal>>,
731 interval: Interval,
732 _content_type: &ContentType,
733 data: &mut Data,
734 _msg_data: &mut MessageData,
735 _sender: &Option<mpsc::Sender<MSG>>,
736 ) -> Result<(Literal, Right), ErrorInfo> {
737 if let Some((f, right)) = FUNCTIONS.get(name) {
738 if *mem_type == MemoryType::Constant && *right == Right::Write {
739 return Err(gen_error_info(
740 Position::new(interval, &data.context.flow),
741 format!("{}" , ERROR_CONSTANT_MUTABLE_FUNCTION),
742 ));
743 } else {
744 let res = f(self, args, additional_info, data, interval)?;
745
746 return Ok((res, *right));
747 }
748 }
749
750 Err(gen_error_info(
751 Position::new(interval, &data.context.flow),
752 format!("[{}] {}", name, ERROR_FLOAT_UNKNOWN_METHOD),
753 ))
754 }
755}