1 /*
2 * Copyright (c) 2003-2019, John Wiegley. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
6 * met:
7 *
8 * - Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 *
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * - Neither the name of New Artisans LLC nor the names of its
16 * contributors may be used to endorse or promote products derived from
17 * this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 */
31
32 #include <system.hh>
33
34 #include "value.h"
35 #include "commodity.h"
36 #include "annotate.h"
37 #include "pool.h"
38 #include "unistring.h" // for justify()
39 #include "op.h"
40
41 namespace ledger {
42
43 intrusive_ptr<value_t::storage_t> value_t::true_value;
44 intrusive_ptr<value_t::storage_t> value_t::false_value;
45
operator =(const value_t::storage_t & rhs)46 value_t::storage_t& value_t::storage_t::operator=(const value_t::storage_t& rhs)
47 {
48 type = rhs.type;
49
50 switch (type) {
51 case BALANCE:
52 data = new balance_t(*boost::get<balance_t *>(rhs.data));
53 break;
54 case SEQUENCE:
55 data = new sequence_t(*boost::get<sequence_t *>(rhs.data));
56 break;
57
58 default:
59 data = rhs.data;
60 break;
61 }
62
63 return *this;
64 }
65
initialize()66 void value_t::initialize()
67 {
68 true_value = new storage_t;
69 true_value->type = BOOLEAN;
70 true_value->data = true;
71
72 false_value = new storage_t;
73 false_value->type = BOOLEAN;
74 false_value->data = false;
75 }
76
shutdown()77 void value_t::shutdown()
78 {
79 true_value = intrusive_ptr<storage_t>();
80 false_value = intrusive_ptr<storage_t>();
81 }
82
operator bool() const83 value_t::operator bool() const
84 {
85 switch (type()) {
86 case VOID:
87 return false;
88 case BOOLEAN:
89 return as_boolean();
90 case DATETIME:
91 return is_valid(as_datetime());
92 case DATE:
93 return is_valid(as_date());
94 case INTEGER:
95 return as_long();
96 case AMOUNT:
97 return as_amount();
98 case BALANCE:
99 return as_balance();
100 case STRING:
101 return ! as_string().empty();
102 case MASK: {
103 std::ostringstream out;
104 out << *this;
105 throw_(value_error,
106 _f("Cannot determine truth of %1% (did you mean 'account =~ %2%'?)")
107 % label() % out.str());
108 }
109 case SEQUENCE:
110 if (! as_sequence().empty()) {
111 foreach (const value_t& value, as_sequence()) {
112 if (value)
113 return true;
114 }
115 }
116 return false;
117 case SCOPE:
118 return as_scope() != NULL;
119 case ANY:
120 return ! as_any().empty();
121 }
122
123 add_error_context(_f("While taking boolean value of %1%:") % *this);
124 throw_(value_error, _f("Cannot determine truth of %1%") % label());
125
126 return false;
127 }
128
set_type(type_t new_type)129 void value_t::set_type(type_t new_type)
130 {
131 if (new_type == VOID) {
132 storage.reset();
133 } else {
134 if (! storage || storage->refc > 1)
135 storage = new storage_t;
136 else
137 storage->destroy();
138 storage->type = new_type;
139 }
140 }
141
to_boolean() const142 bool value_t::to_boolean() const
143 {
144 if (is_boolean()) {
145 return as_boolean();
146 } else {
147 value_t temp(*this);
148 temp.in_place_cast(BOOLEAN);
149 return temp.as_boolean();
150 }
151 }
152
to_datetime() const153 datetime_t value_t::to_datetime() const
154 {
155 if (is_datetime()) {
156 return as_datetime();
157 } else {
158 value_t temp(*this);
159 temp.in_place_cast(DATETIME);
160 return temp.as_datetime();
161 }
162 }
163
to_date() const164 date_t value_t::to_date() const
165 {
166 if (is_date()) {
167 return as_date();
168 } else {
169 value_t temp(*this);
170 temp.in_place_cast(DATE);
171 return temp.as_date();
172 }
173 }
174
to_int() const175 int value_t::to_int() const
176 {
177 if (is_long()) {
178 return static_cast<int>(as_long());
179 } else {
180 value_t temp(*this);
181 temp.in_place_cast(INTEGER);
182 return static_cast<int>(temp.as_long());
183 }
184 }
185
to_long() const186 long value_t::to_long() const
187 {
188 if (is_long()) {
189 return as_long();
190 } else {
191 value_t temp(*this);
192 temp.in_place_cast(INTEGER);
193 return temp.as_long();
194 }
195 }
196
to_amount() const197 amount_t value_t::to_amount() const
198 {
199 if (is_amount()) {
200 return as_amount();
201 } else {
202 value_t temp(*this);
203 temp.in_place_cast(AMOUNT);
204 return temp.as_amount();
205 }
206 }
207
to_balance() const208 balance_t value_t::to_balance() const
209 {
210 if (is_balance()) {
211 return as_balance();
212 } else {
213 value_t temp(*this);
214 temp.in_place_cast(BALANCE);
215 return temp.as_balance();
216 }
217 }
218
to_string() const219 string value_t::to_string() const
220 {
221 if (is_string()) {
222 return as_string();
223 } else {
224 value_t temp(*this);
225 temp.in_place_cast(STRING);
226 return temp.as_string();
227 }
228 }
229
to_mask() const230 mask_t value_t::to_mask() const
231 {
232 if (is_mask()) {
233 return as_mask();
234 } else {
235 value_t temp(*this);
236 temp.in_place_cast(MASK);
237 return temp.as_mask();
238 }
239 }
240
to_sequence() const241 value_t::sequence_t value_t::to_sequence() const
242 {
243 if (is_sequence()) {
244 return as_sequence();
245 } else {
246 value_t temp(*this);
247 temp.in_place_cast(SEQUENCE);
248 return temp.as_sequence();
249 }
250 }
251
252
in_place_simplify()253 void value_t::in_place_simplify()
254 {
255 #if DEBUG_ON
256 LOGGER("value.simplify");
257 #endif
258
259 if (is_realzero()) {
260 DEBUG_("Zeroing type " << static_cast<int>(type()));
261 set_long(0L);
262 return;
263 }
264
265 if (is_balance() && as_balance().single_amount()) {
266 DEBUG_("Reducing balance to amount");
267 DEBUG_("as a balance it looks like: " << *this);
268 in_place_cast(AMOUNT);
269 DEBUG_("as an amount it looks like: " << *this);
270 }
271
272 #if REDUCE_TO_INTEGER // this is off by default
273 if (is_amount() && ! as_amount().has_commodity() &&
274 as_amount().fits_in_long()) {
275 DEBUG_("Reducing amount to integer");
276 in_place_cast(INTEGER);
277 }
278 #endif
279 }
280
number() const281 value_t value_t::number() const
282 {
283 switch (type()) {
284 case VOID:
285 return 0L;
286 case BOOLEAN:
287 return as_boolean() ? 1L : 0L;
288 case INTEGER:
289 return as_long();
290 case AMOUNT:
291 return as_amount().number();
292 case BALANCE:
293 return as_balance().number();
294 case SEQUENCE:
295 if (! as_sequence().empty()) {
296 value_t temp;
297 foreach (const value_t& value, as_sequence())
298 temp += value.number();
299 return temp;
300 }
301 break;
302 default:
303 break;
304 }
305
306 add_error_context(_f("While calling number() on %1%:") % *this);
307 throw_(value_error, _f("Cannot determine numeric value of %1%") % label());
308
309 return false;
310 }
311
operator +=(const value_t & val)312 value_t& value_t::operator+=(const value_t& val)
313 {
314 if (is_string()) {
315 if (val.is_string())
316 as_string_lval() += val.as_string();
317 else
318 as_string_lval() += val.to_string();
319 return *this;
320 }
321 else if (is_sequence()) {
322 if (val.is_sequence()) {
323 if (size() == val.size()) {
324 sequence_t::iterator i = begin();
325 sequence_t::const_iterator j = val.begin();
326
327 for (; i != end(); i++, j++)
328 *i += *j;
329 } else {
330 add_error_context(_f("While adding %1% to %2%:") % val % *this);
331 throw_(value_error, _("Cannot add sequences of different lengths"));
332 }
333 } else {
334 as_sequence_lval().push_back(new value_t(val));
335 }
336 return *this;
337 }
338
339 switch (type()) {
340 case VOID:
341 *this = value_t(val);
342 return *this;
343
344 case DATETIME:
345 switch (val.type()) {
346 case INTEGER:
347 as_datetime_lval() +=
348 time_duration_t(0, 0, static_cast<time_duration_t::sec_type>(val.as_long()));
349 return *this;
350 case AMOUNT:
351 as_datetime_lval() +=
352 time_duration_t(0, 0, static_cast<time_duration_t::sec_type>
353 (val.as_amount().to_long()));
354 return *this;
355 default:
356 break;
357 }
358 break;
359
360 case DATE:
361 switch (val.type()) {
362 case INTEGER:
363 as_date_lval() += gregorian::date_duration(val.as_long());
364 return *this;
365 case AMOUNT:
366 as_date_lval() += gregorian::date_duration(val.as_amount().to_long());
367 return *this;
368 default:
369 break;
370 }
371 break;
372
373 case INTEGER:
374 switch (val.type()) {
375 case INTEGER:
376 as_long_lval() += val.as_long();
377 return *this;
378 case AMOUNT:
379 if (val.as_amount().has_commodity()) {
380 in_place_cast(BALANCE);
381 return *this += val;
382 }
383 in_place_cast(AMOUNT);
384 as_amount_lval() += val.as_amount();
385 return *this;
386 case BALANCE:
387 in_place_cast(BALANCE);
388 as_balance_lval() += val.as_balance();
389 return *this;
390 default:
391 break;
392 }
393 break;
394
395 case AMOUNT:
396 switch (val.type()) {
397 case INTEGER:
398 if (as_amount().has_commodity()) {
399 in_place_cast(BALANCE);
400 return *this += val;
401 } else {
402 as_amount_lval() += val.as_long();
403 return *this;
404 }
405
406 case AMOUNT:
407 if (as_amount().commodity() != val.as_amount().commodity()) {
408 in_place_cast(BALANCE);
409 return *this += val;
410 } else {
411 as_amount_lval() += val.as_amount();
412 return *this;
413 }
414
415 case BALANCE:
416 in_place_cast(BALANCE);
417 as_balance_lval() += val.as_balance();
418 return *this;
419
420 default:
421 break;
422 }
423 break;
424
425 case BALANCE:
426 switch (val.type()) {
427 case INTEGER:
428 as_balance_lval() += val.to_amount();
429 return *this;
430 case AMOUNT:
431 as_balance_lval() += val.as_amount();
432 return *this;
433 case BALANCE:
434 as_balance_lval() += val.as_balance();
435 return *this;
436 default:
437 break;
438 }
439 break;
440
441 default:
442 break;
443 }
444
445 add_error_context(_f("While adding %1% to %2%:") % val % *this);
446 throw_(value_error, _f("Cannot add %1% to %2%") % val.label() % label());
447
448 return *this;
449 }
450
operator -=(const value_t & val)451 value_t& value_t::operator-=(const value_t& val)
452 {
453 if (is_sequence()) {
454 sequence_t& seq(as_sequence_lval());
455
456 if (val.is_sequence()) {
457 if (size() == val.size()) {
458 sequence_t::iterator i = begin();
459 sequence_t::const_iterator j = val.begin();
460
461 for (; i != end(); i++, j++)
462 *i -= *j;
463 } else {
464 add_error_context(_f("While subtracting %1% from %2%:") % val % *this);
465 throw_(value_error, _("Cannot subtract sequences of different lengths"));
466 }
467 } else {
468 sequence_t::iterator i = std::find(seq.begin(), seq.end(), val);
469 if (i != seq.end())
470 seq.erase(i);
471 }
472 return *this;
473 }
474
475 switch (type()) {
476 case DATETIME:
477 switch (val.type()) {
478 case INTEGER:
479 as_datetime_lval() -=
480 time_duration_t(0, 0, static_cast<time_duration_t::sec_type>(val.as_long()));
481 return *this;
482 case AMOUNT:
483 as_datetime_lval() -=
484 time_duration_t(0, 0, static_cast<time_duration_t::sec_type>
485 (val.as_amount().to_long()));
486 return *this;
487 default:
488 break;
489 }
490 break;
491
492 case DATE:
493 switch (val.type()) {
494 case INTEGER:
495 as_date_lval() -= gregorian::date_duration(val.as_long());
496 return *this;
497 case AMOUNT:
498 as_date_lval() -= gregorian::date_duration(val.as_amount().to_long());
499 return *this;
500 default:
501 break;
502 }
503 break;
504
505 case INTEGER:
506 switch (val.type()) {
507 case INTEGER:
508 as_long_lval() -= val.as_long();
509 return *this;
510 case AMOUNT:
511 in_place_cast(AMOUNT);
512 as_amount_lval() -= val.as_amount();
513 in_place_simplify();
514 return *this;
515 case BALANCE:
516 in_place_cast(BALANCE);
517 as_balance_lval() -= val.as_balance();
518 in_place_simplify();
519 return *this;
520 default:
521 break;
522 }
523 break;
524
525 case AMOUNT:
526 switch (val.type()) {
527 case INTEGER:
528 if (as_amount().has_commodity()) {
529 in_place_cast(BALANCE);
530 *this -= val;
531 in_place_simplify();
532 return *this;
533 } else {
534 as_amount_lval() -= val.as_long();
535 in_place_simplify();
536 return *this;
537 }
538
539 case AMOUNT:
540 if (as_amount().commodity() != val.as_amount().commodity()) {
541 in_place_cast(BALANCE);
542 *this -= val;
543 in_place_simplify();
544 return *this;
545 } else {
546 as_amount_lval() -= val.as_amount();
547 in_place_simplify();
548 return *this;
549 }
550
551 case BALANCE:
552 in_place_cast(BALANCE);
553 as_balance_lval() -= val.as_balance();
554 in_place_simplify();
555 return *this;
556
557 default:
558 break;
559 }
560 break;
561
562 case BALANCE:
563 switch (val.type()) {
564 case INTEGER:
565 as_balance_lval() -= val.to_amount();
566 in_place_simplify();
567 return *this;
568 case AMOUNT:
569 as_balance_lval() -= val.as_amount();
570 in_place_simplify();
571 return *this;
572 case BALANCE:
573 as_balance_lval() -= val.as_balance();
574 in_place_simplify();
575 return *this;
576 default:
577 break;
578 }
579 break;
580
581 default:
582 break;
583 }
584
585 add_error_context(_f("While subtracting %1% from %2%:") % val % *this);
586 throw_(value_error, _f("Cannot subtract %1% from %2%") % val.label() % label());
587
588 return *this;
589 }
590
operator *=(const value_t & val)591 value_t& value_t::operator*=(const value_t& val)
592 {
593 if (is_string()) {
594 string temp;
595 long count = val.to_long();
596 for (long i = 0; i < count; i++)
597 temp += as_string();
598 set_string(temp);
599 return *this;
600 }
601 else if (is_sequence()) {
602 value_t temp;
603 long count = val.to_long();
604 for (long i = 0; i < count; i++)
605 temp += as_sequence();
606 return *this = temp;
607 }
608
609 switch (type()) {
610 case INTEGER:
611 switch (val.type()) {
612 case INTEGER:
613 as_long_lval() *= val.as_long();
614 return *this;
615 case AMOUNT:
616 set_amount(val.as_amount() * as_long());
617 return *this;
618 default:
619 break;
620 }
621 break;
622
623 case AMOUNT:
624 switch (val.type()) {
625 case INTEGER:
626 as_amount_lval() *= val.as_long();
627 return *this;
628 case AMOUNT:
629 as_amount_lval() *= val.as_amount();
630 return *this;
631 case BALANCE:
632 if (val.as_balance().single_amount()) {
633 as_amount_lval() *= val.simplified().as_amount();
634 return *this;
635 }
636 break;
637 default:
638 break;
639 }
640 break;
641
642 case BALANCE:
643 switch (val.type()) {
644 case INTEGER:
645 as_balance_lval() *= val.as_long();
646 return *this;
647 case AMOUNT:
648 if (as_balance().single_amount()) {
649 in_place_simplify();
650 as_amount_lval() *= val.as_amount();
651 return *this;
652 }
653 else if (! val.as_amount().has_commodity()) {
654 as_balance_lval() *= val.as_amount();
655 return *this;
656 }
657 break;
658 default:
659 break;
660 }
661 break;
662
663 default:
664 break;
665 }
666
667 add_error_context(_f("While multiplying %1% with %2%:") % val % *this);
668 throw_(value_error, _f("Cannot multiply %1% with %2%") % label() % val.label());
669
670 return *this;
671 }
672
operator /=(const value_t & val)673 value_t& value_t::operator/=(const value_t& val)
674 {
675 switch (type()) {
676 case INTEGER:
677 switch (val.type()) {
678 case INTEGER:
679 as_long_lval() /= val.as_long();
680 return *this;
681 case AMOUNT:
682 set_amount(val.as_amount() / as_long());
683 return *this;
684 default:
685 break;
686 }
687 break;
688
689 case AMOUNT:
690 switch (val.type()) {
691 case INTEGER:
692 as_amount_lval() /= val.as_long();
693 return *this;
694
695 case AMOUNT:
696 as_amount_lval() /= val.as_amount();
697 return *this;
698 case BALANCE:
699 if (val.as_balance().single_amount()) {
700 value_t simpler(val.simplified());
701 switch (simpler.type()) {
702 case INTEGER:
703 as_amount_lval() /= simpler.as_long();
704 break;
705 case AMOUNT:
706 as_amount_lval() /= simpler.as_amount();
707 break;
708 default:
709 assert(false);
710 break;
711 }
712 return *this;
713 }
714 break;
715 default:
716 break;
717 }
718 break;
719
720 case BALANCE:
721 switch (val.type()) {
722 case INTEGER:
723 as_balance_lval() /= val.as_long();
724 return *this;
725 case AMOUNT:
726 if (as_balance().single_amount()) {
727 in_place_cast(AMOUNT);
728 as_amount_lval() /= val.as_amount();
729 return *this;
730 }
731 else if (! val.as_amount().has_commodity()) {
732 as_balance_lval() /= val.as_amount();
733 return *this;
734 }
735 break;
736 default:
737 break;
738 }
739 break;
740
741 default:
742 break;
743 }
744
745 add_error_context(_f("While dividing %1% by %2%:") % *this % val);
746 throw_(value_error, _f("Cannot divide %1% by %2%") % label() % val.label());
747
748 return *this;
749 }
750
751
is_equal_to(const value_t & val) const752 bool value_t::is_equal_to(const value_t& val) const
753 {
754 switch (type()) {
755 case VOID:
756 return val.type() == VOID;
757
758 case BOOLEAN:
759 if (val.is_boolean())
760 return as_boolean() == val.as_boolean();
761 break;
762
763 case DATETIME:
764 if (val.is_datetime())
765 return as_datetime() == val.as_datetime();
766 break;
767
768 case DATE:
769 if (val.is_date())
770 return as_date() == val.as_date();
771 break;
772
773 case INTEGER:
774 switch (val.type()) {
775 case INTEGER:
776 return as_long() == val.as_long();
777 case AMOUNT:
778 return val.as_amount() == to_amount();
779 case BALANCE:
780 return val.as_balance() == to_amount();
781 default:
782 break;
783 }
784 break;
785
786 case AMOUNT:
787 switch (val.type()) {
788 case INTEGER:
789 return as_amount() == val.as_long();
790 case AMOUNT:
791 return as_amount() == val.as_amount();
792 case BALANCE:
793 return val.as_balance() == as_amount();
794 default:
795 break;
796 }
797 break;
798
799 case BALANCE:
800 switch (val.type()) {
801 case INTEGER:
802 return as_balance() == val.to_amount();
803 case AMOUNT:
804 return as_balance() == val.as_amount();
805 case BALANCE:
806 return as_balance() == val.as_balance();
807 default:
808 break;
809 }
810 break;
811
812 case STRING:
813 if (val.is_string())
814 return as_string() == val.as_string();
815 break;
816
817 case MASK:
818 if (val.is_mask())
819 return as_mask() == val.as_mask();
820 break;
821
822 case SEQUENCE:
823 if (val.is_sequence())
824 return as_sequence() == val.as_sequence();
825 break;
826
827 default:
828 break;
829 }
830
831 add_error_context(_f("While comparing equality of %1% and %2%:") % *this % val);
832 throw_(value_error, _f("Cannot compare %1% to %2%") % label() % val.label());
833
834 return *this;
835 }
836
is_less_than(const value_t & val) const837 bool value_t::is_less_than(const value_t& val) const
838 {
839 switch (type()) {
840 case BOOLEAN:
841 if (val.is_boolean()) {
842 if (as_boolean()) {
843 if (! val.as_boolean())
844 return false;
845 else
846 return false;
847 }
848 else if (! as_boolean()) {
849 if (! val.as_boolean())
850 return false;
851 else
852 return true;
853 }
854 }
855 break;
856
857 case DATETIME:
858 if (val.is_datetime())
859 return as_datetime() < val.as_datetime();
860 break;
861
862 case DATE:
863 if (val.is_date())
864 return as_date() < val.as_date();
865 break;
866
867 case INTEGER:
868 switch (val.type()) {
869 case INTEGER:
870 return as_long() < val.as_long();
871 case AMOUNT:
872 return val.as_amount() > as_long();
873 case BALANCE:
874 return val.to_amount() > as_long();
875 default:
876 break;
877 }
878 break;
879
880 case AMOUNT:
881 switch (val.type()) {
882 case INTEGER:
883 return as_amount() < val.as_long();
884 case AMOUNT:
885 if (as_amount().commodity() == val.as_amount().commodity() ||
886 ! as_amount().has_commodity() ||
887 ! val.as_amount().has_commodity())
888 return as_amount() < val.as_amount();
889 else
890 return commodity_t::compare_by_commodity()(&as_amount(), &val.as_amount()) < 0;
891 case BALANCE:
892 return val.to_amount() > as_amount();
893 default:
894 break;
895 }
896 break;
897
898 case BALANCE:
899 switch (val.type()) {
900 case INTEGER:
901 case AMOUNT: {
902 bool no_amounts = true;
903 foreach (const balance_t::amounts_map::value_type& pair,
904 as_balance().amounts) {
905 if (pair.second >= val)
906 return false;
907 no_amounts = false;
908 }
909 return ! no_amounts;
910 }
911 case BALANCE:
912 return val.to_amount() > to_amount();
913 default:
914 break;
915 }
916 break;
917
918 case STRING:
919 if (val.is_string())
920 return as_string() < val.as_string();
921 break;
922
923 case SEQUENCE:
924 switch (val.type()) {
925 case INTEGER:
926 case AMOUNT: {
927 bool no_amounts = true;
928 foreach (const value_t& value, as_sequence()) {
929 if (value >= val)
930 return false;
931 no_amounts = false;
932 }
933 return ! no_amounts;
934 }
935 case SEQUENCE: {
936 sequence_t::const_iterator i = as_sequence().begin();
937 sequence_t::const_iterator j = val.as_sequence().begin();
938 for (; (i != as_sequence().end() &&
939 j != val.as_sequence().end()); i++, j++) {
940 if (! ((*i) < (*j)))
941 return false;
942 }
943 if (i == as_sequence().end())
944 return true;
945 else
946 return false;
947 }
948 default:
949 break;
950 }
951 break;
952
953 default:
954 break;
955 }
956
957 add_error_context(_f("While comparing if %1% is less than %2%:") % *this % val);
958 throw_(value_error, _f("Cannot compare %1% to %2%") % label() % val.label());
959
960 return *this;
961 }
962
is_greater_than(const value_t & val) const963 bool value_t::is_greater_than(const value_t& val) const
964 {
965 switch (type()) {
966 case BOOLEAN:
967 if (val.is_boolean()) {
968 if (as_boolean()) {
969 if (! val.as_boolean())
970 return true;
971 else
972 return false;
973 }
974 else if (! as_boolean()) {
975 if (! val.as_boolean())
976 return false;
977 else
978 return false;
979 }
980 }
981 break;
982
983 case DATETIME:
984 if (val.is_datetime())
985 return as_datetime() > val.as_datetime();
986 break;
987
988 case DATE:
989 if (val.is_date())
990 return as_date() > val.as_date();
991 break;
992
993 case INTEGER:
994 switch (val.type()) {
995 case INTEGER:
996 return as_long() > val.as_long();
997 case AMOUNT:
998 return val.as_amount() < as_long();
999 case BALANCE:
1000 return val.to_amount() < as_long();
1001 default:
1002 break;
1003 }
1004 break;
1005
1006 case AMOUNT:
1007 switch (val.type()) {
1008 case INTEGER:
1009 return as_amount() > val.as_long();
1010 case AMOUNT:
1011 return as_amount() > val.as_amount();
1012 case BALANCE:
1013 return val.to_amount() < as_amount();
1014 default:
1015 break;
1016 }
1017 break;
1018
1019 case BALANCE:
1020 switch (val.type()) {
1021 case INTEGER:
1022 case AMOUNT: {
1023 bool no_amounts = true;
1024 foreach (const balance_t::amounts_map::value_type& pair,
1025 as_balance().amounts) {
1026 if (pair.second <= val)
1027 return false;
1028 no_amounts = false;
1029 }
1030 return ! no_amounts;
1031 }
1032 case BALANCE:
1033 return val.to_amount() < to_amount();
1034 default:
1035 break;
1036 }
1037 break;
1038
1039 case STRING:
1040 if (val.is_string())
1041 return as_string() > val.as_string();
1042 break;
1043
1044 case SEQUENCE:
1045 switch (val.type()) {
1046 case INTEGER:
1047 case AMOUNT: {
1048 bool no_amounts = true;
1049 foreach (const value_t& value, as_sequence()) {
1050 if (value <= val)
1051 return false;
1052 no_amounts = false;
1053 }
1054 return ! no_amounts;
1055 }
1056 case SEQUENCE: {
1057 sequence_t::const_iterator i = as_sequence().begin();
1058 sequence_t::const_iterator j = val.as_sequence().begin();
1059 for (; (i != as_sequence().end() &&
1060 j != val.as_sequence().end()); i++, j++) {
1061 if (! ((*i) > (*j)))
1062 return false;
1063 }
1064 if (i == as_sequence().end())
1065 return false;
1066 else
1067 return true;
1068 }
1069 default:
1070 break;
1071 }
1072 break;
1073
1074 default:
1075 break;
1076 }
1077
1078 add_error_context(_f("While comparing if %1% is greater than %2%:") % *this % val);
1079 throw_(value_error, _f("Cannot compare %1% to %2%") % label() % val.label());
1080
1081 return *this;
1082 }
1083
in_place_cast(type_t cast_type)1084 void value_t::in_place_cast(type_t cast_type)
1085 {
1086 if (type() == cast_type)
1087 return;
1088
1089 _dup();
1090
1091 if (cast_type == BOOLEAN) {
1092 set_boolean(bool(*this));
1093 return;
1094 }
1095 else if (cast_type == SEQUENCE) {
1096 sequence_t temp;
1097 if (! is_null())
1098 temp.push_back(new value_t(*this));
1099 set_sequence(temp);
1100 return;
1101 }
1102
1103 switch (type()) {
1104 case VOID:
1105 switch (cast_type) {
1106 case INTEGER:
1107 set_long(0L);
1108 return;
1109 case AMOUNT:
1110 set_amount(0L);
1111 return;
1112 case STRING:
1113 set_string("");
1114 return;
1115 default:
1116 break;
1117 }
1118 break;
1119
1120 case BOOLEAN:
1121 switch (cast_type) {
1122 case INTEGER:
1123 set_long(as_boolean() ? 1L : 0L);
1124 return;
1125 case AMOUNT:
1126 set_amount(as_boolean() ? 1L : 0L);
1127 return;
1128 case STRING:
1129 set_string(as_boolean() ? "true" : "false");
1130 return;
1131 default:
1132 break;
1133 }
1134 break;
1135
1136 case DATE:
1137 switch (cast_type) {
1138 case DATETIME:
1139 set_datetime(datetime_t(as_date(), time_duration(0, 0, 0, 0)));
1140 return;
1141 case STRING:
1142 set_string(format_date(as_date(), FMT_WRITTEN));
1143 return;
1144 default:
1145 break;
1146 }
1147 break;
1148 case DATETIME:
1149 switch (cast_type) {
1150 case DATE:
1151 set_date(as_datetime().date());
1152 return;
1153 case STRING:
1154 set_string(format_datetime(as_datetime(), FMT_WRITTEN));
1155 return;
1156 default:
1157 break;
1158 }
1159 break;
1160
1161 case INTEGER:
1162 switch (cast_type) {
1163 case AMOUNT:
1164 set_amount(as_long());
1165 return;
1166 case BALANCE:
1167 set_balance(to_amount());
1168 return;
1169 case STRING:
1170 set_string(lexical_cast<string>(as_long()));
1171 return;
1172 default:
1173 break;
1174 }
1175 break;
1176
1177 case AMOUNT: {
1178 const amount_t& amt(as_amount());
1179 switch (cast_type) {
1180 case INTEGER:
1181 if (amt.is_null())
1182 set_long(0L);
1183 else
1184 set_long(as_amount().to_long());
1185 return;
1186 case BALANCE:
1187 if (amt.is_null())
1188 set_balance(balance_t());
1189 else
1190 set_balance(as_amount());
1191 return;
1192 case STRING:
1193 if (amt.is_null())
1194 set_string("");
1195 else
1196 set_string(as_amount().to_string());
1197 return;
1198 default:
1199 break;
1200 }
1201 break;
1202 }
1203
1204 case BALANCE: {
1205 const balance_t& bal(as_balance());
1206 switch (cast_type) {
1207 case AMOUNT: {
1208 if (bal.amounts.size() == 1) {
1209 // Because we are changing the current balance value to an amount
1210 // value, and because set_amount takes a reference (and that memory is
1211 // about to be repurposed), we must pass in a copy.
1212 set_amount(amount_t((*bal.amounts.begin()).second));
1213 return;
1214 }
1215 else if (bal.amounts.size() == 0) {
1216 set_amount(0L);
1217 return;
1218 }
1219 else {
1220 add_error_context(_f("While converting %1% to an amount:") % *this);
1221 throw_(value_error, _f("Cannot convert %1% with multiple commodities to %2%")
1222 % label() % label(cast_type));
1223 }
1224 break;
1225 }
1226 case STRING:
1227 if (bal.is_empty())
1228 set_string("");
1229 else
1230 set_string(as_balance().to_string());
1231 return;
1232 default:
1233 break;
1234 }
1235 break;
1236 }
1237
1238 case STRING:
1239 switch (cast_type) {
1240 case INTEGER: {
1241 if (all(as_string(), is_any_of("-0123456789"))) {
1242 set_long(lexical_cast<long>(as_string()));
1243 return;
1244 }
1245 break;
1246 }
1247 case AMOUNT:
1248 set_amount(amount_t(as_string()));
1249 return;
1250 case DATE:
1251 set_date(parse_date(as_string()));
1252 return;
1253 case DATETIME:
1254 set_datetime(parse_datetime(as_string()));
1255 return;
1256 case MASK:
1257 set_mask(as_string());
1258 return;
1259 default:
1260 break;
1261 }
1262 break;
1263
1264 case MASK:
1265 switch (cast_type) {
1266 case STRING:
1267 set_string(as_mask().str());
1268 return;
1269 default:
1270 break;
1271 }
1272 break;
1273
1274 default:
1275 break;
1276 }
1277
1278 add_error_context(_f("While converting %1%:") % *this);
1279 throw_(value_error,
1280 _f("Cannot convert %1% to %2%") % label() % label(cast_type));
1281 }
1282
in_place_negate()1283 void value_t::in_place_negate()
1284 {
1285 switch (type()) {
1286 case BOOLEAN:
1287 set_boolean(! as_boolean());
1288 return;
1289 case INTEGER:
1290 case DATETIME:
1291 set_long(- as_long());
1292 return;
1293 case DATE:
1294 set_long(- as_long());
1295 return;
1296 case AMOUNT:
1297 as_amount_lval().in_place_negate();
1298 return;
1299 case BALANCE:
1300 as_balance_lval().in_place_negate();
1301 return;
1302 case SEQUENCE:
1303 foreach (value_t& value, as_sequence_lval())
1304 value.in_place_negate();
1305 return;
1306 default:
1307 break;
1308 }
1309
1310 add_error_context(_f("While negating %1%:") % *this);
1311 throw_(value_error, _f("Cannot negate %1%") % label());
1312 }
1313
in_place_not()1314 void value_t::in_place_not()
1315 {
1316 switch (type()) {
1317 case BOOLEAN:
1318 set_boolean(! as_boolean());
1319 return;
1320 case INTEGER:
1321 case DATETIME:
1322 set_boolean(! as_long());
1323 return;
1324 case DATE:
1325 set_boolean(! as_long());
1326 return;
1327 case AMOUNT:
1328 set_boolean(! as_amount());
1329 return;
1330 case BALANCE:
1331 set_boolean(! as_balance());
1332 return;
1333 case STRING:
1334 set_boolean(as_string().empty());
1335 return;
1336 case SEQUENCE:
1337 foreach (value_t& value, as_sequence_lval())
1338 value.in_place_not();
1339 return;
1340 default:
1341 break;
1342 }
1343
1344 add_error_context(_f("While applying not to %1%:") % *this);
1345 throw_(value_error, _f("Cannot 'not' %1%") % label());
1346 }
1347
is_realzero() const1348 bool value_t::is_realzero() const
1349 {
1350 switch (type()) {
1351 case BOOLEAN:
1352 return ! as_boolean();
1353 case INTEGER:
1354 return as_long() == 0;
1355 case DATETIME:
1356 return ! is_valid(as_datetime());
1357 case DATE:
1358 return ! is_valid(as_date());
1359 case AMOUNT:
1360 return as_amount().is_realzero();
1361 case BALANCE:
1362 return as_balance().is_realzero();
1363 case STRING:
1364 return as_string().empty();
1365 case SEQUENCE:
1366 return as_sequence().empty();
1367
1368 case SCOPE:
1369 return as_scope() == NULL;
1370 case ANY:
1371 return as_any().empty();
1372
1373 default:
1374 add_error_context(_f("While applying is_realzero to %1%:") % *this);
1375 throw_(value_error, _f("Cannot determine if %1% is really zero") % label());
1376 }
1377 return false;
1378 }
1379
is_zero() const1380 bool value_t::is_zero() const
1381 {
1382 switch (type()) {
1383 case BOOLEAN:
1384 return ! as_boolean();
1385 case INTEGER:
1386 return as_long() == 0;
1387 case DATETIME:
1388 return ! is_valid(as_datetime());
1389 case DATE:
1390 return ! is_valid(as_date());
1391 case AMOUNT:
1392 return as_amount().is_zero();
1393 case BALANCE:
1394 return as_balance().is_zero();
1395 case STRING:
1396 return as_string().empty();
1397 case SEQUENCE:
1398 return as_sequence().empty();
1399
1400 case SCOPE:
1401 return as_scope() == NULL;
1402 case ANY:
1403 return as_any().empty();
1404
1405 default:
1406 add_error_context(_f("While applying is_zero to %1%:") % *this);
1407 throw_(value_error, _f("Cannot determine if %1% is zero") % label());
1408 }
1409 return false;
1410 }
1411
value(const datetime_t & moment,const commodity_t * in_terms_of) const1412 value_t value_t::value(const datetime_t& moment,
1413 const commodity_t * in_terms_of) const
1414 {
1415 switch (type()) {
1416 case INTEGER:
1417 return NULL_VALUE;
1418
1419 case AMOUNT:
1420 if (optional<amount_t> val = as_amount().value(moment, in_terms_of))
1421 return *val;
1422 return NULL_VALUE;
1423
1424 case BALANCE:
1425 if (optional<balance_t> bal = as_balance().value(moment, in_terms_of))
1426 return *bal;
1427 return NULL_VALUE;
1428
1429 case SEQUENCE: {
1430 value_t temp;
1431 foreach (const value_t& value, as_sequence())
1432 temp.push_back(value.value(moment, in_terms_of));
1433 return temp;
1434 }
1435
1436 default:
1437 break;
1438 }
1439
1440 add_error_context(_f("While finding valuation of %1%:") % *this);
1441 throw_(value_error, _f("Cannot find the value of %1%") % label());
1442 return NULL_VALUE;
1443 }
1444
exchange_commodities(const std::string & commodities,const bool add_prices,const datetime_t & moment)1445 value_t value_t::exchange_commodities(const std::string& commodities,
1446 const bool add_prices,
1447 const datetime_t& moment)
1448 {
1449 if (type() == SEQUENCE) {
1450 value_t temp;
1451 foreach (value_t& value, as_sequence_lval())
1452 temp.push_back(value.exchange_commodities(commodities, add_prices, moment));
1453 return temp;
1454 }
1455
1456 // If we are repricing to just a single commodity, with no price
1457 // expression, skip the expensive logic below.
1458 if (commodities.find(',') == string::npos &&
1459 commodities.find('=') == string::npos)
1460 return value(moment, commodity_pool_t::current_pool->find_or_create(commodities));
1461
1462 std::vector<commodity_t *> comms;
1463 std::vector<bool> force;
1464
1465 typedef tokenizer<char_separator<char> > tokenizer;
1466 tokenizer tokens(commodities, char_separator<char>(","));
1467
1468 foreach (const string& name, tokens) {
1469 string::size_type name_len = name.length();
1470
1471 if (commodity_t * commodity = commodity_pool_t::current_pool
1472 ->parse_price_expression(name[name_len - 1] == '!' ?
1473 string(name, 0, name_len - 1) :
1474 name, add_prices, moment)) {
1475 DEBUG("commodity.exchange", "Pricing for commodity: " << commodity->symbol());
1476 comms.push_back(&commodity->referent());
1477 force.push_back(name[name_len - 1] == '!');
1478 }
1479 }
1480
1481 std::size_t index = 0;
1482 foreach (commodity_t * comm, comms) {
1483 switch (type()) {
1484 case AMOUNT:
1485 DEBUG("commodity.exchange", "We have an amount: " << as_amount_lval());
1486 if (! force[index] &&
1487 std::find(comms.begin(), comms.end(),
1488 &as_amount_lval().commodity().referent()) != comms.end())
1489 break;
1490
1491 DEBUG("commodity.exchange", "Referent doesn't match, pricing...");
1492 if (optional<amount_t> val = as_amount_lval().value(moment, comm)) {
1493 DEBUG("commodity.exchange", "Re-priced amount is: " << *val);
1494 return *val;
1495 }
1496 DEBUG("commodity.exchange", "Was unable to find a price");
1497 break;
1498
1499 case BALANCE: {
1500 balance_t temp;
1501 bool repriced = false;
1502
1503 DEBUG("commodity.exchange", "We have a balance: " << as_balance_lval());
1504 foreach (const balance_t::amounts_map::value_type& pair,
1505 as_balance_lval().amounts) {
1506 DEBUG("commodity.exchange", "We have a balance amount of commodity: "
1507 << pair.first->symbol() << " == "
1508 << pair.second.commodity().symbol());
1509 if (! force[index] &&
1510 std::find(comms.begin(), comms.end(),
1511 &pair.first->referent()) != comms.end()) {
1512 temp += pair.second;
1513 } else {
1514 DEBUG("commodity.exchange", "Referent doesn't match, pricing...");
1515 if (optional<amount_t> val = pair.second.value(moment, comm)) {
1516 DEBUG("commodity.exchange", "Re-priced member amount is: " << *val);
1517 temp += *val;
1518 repriced = true;
1519 } else {
1520 DEBUG("commodity.exchange", "Was unable to find price");
1521 temp += pair.second;
1522 }
1523 }
1524 }
1525
1526 if (repriced) {
1527 DEBUG("commodity.exchange", "Re-priced balance is: " << temp);
1528 return temp;
1529 }
1530 }
1531
1532 default:
1533 break;
1534 }
1535
1536 ++index;
1537 }
1538
1539 return *this;
1540 }
1541
in_place_reduce()1542 void value_t::in_place_reduce()
1543 {
1544 switch (type()) {
1545 case AMOUNT:
1546 as_amount_lval().in_place_reduce();
1547 return;
1548 case BALANCE:
1549 as_balance_lval().in_place_reduce();
1550 return;
1551 case SEQUENCE:
1552 foreach (value_t& value, as_sequence_lval())
1553 value.in_place_reduce();
1554 return;
1555 default:
1556 return;
1557 }
1558
1559 //throw_(value_error, _f("Cannot reduce %1%") % label());
1560 }
1561
in_place_unreduce()1562 void value_t::in_place_unreduce()
1563 {
1564 switch (type()) {
1565 case AMOUNT:
1566 as_amount_lval().in_place_unreduce();
1567 return;
1568 case BALANCE:
1569 as_balance_lval().in_place_unreduce();
1570 return;
1571 case SEQUENCE:
1572 foreach (value_t& value, as_sequence_lval())
1573 value.in_place_unreduce();
1574 return;
1575 default:
1576 return;
1577 }
1578
1579 //throw_(value_error, _f("Cannot reduce %1%") % label());
1580 }
1581
abs() const1582 value_t value_t::abs() const
1583 {
1584 switch (type()) {
1585 case INTEGER: {
1586 long val = as_long();
1587 if (val < 0)
1588 return - val;
1589 return val;
1590 }
1591 case AMOUNT:
1592 return as_amount().abs();
1593 case BALANCE:
1594 return as_balance().abs();
1595 default:
1596 break;
1597 }
1598
1599 add_error_context(_f("While taking abs of %1%:") % *this);
1600 throw_(value_error, _f("Cannot abs %1%") % label());
1601 return NULL_VALUE;
1602 }
1603
in_place_round()1604 void value_t::in_place_round()
1605 {
1606 switch (type()) {
1607 case INTEGER:
1608 return;
1609 case AMOUNT:
1610 as_amount_lval().in_place_round();
1611 return;
1612 case BALANCE:
1613 as_balance_lval().in_place_round();
1614 return;
1615 case SEQUENCE:
1616 foreach (value_t& value, as_sequence_lval())
1617 value.in_place_round();
1618 return;
1619 default:
1620 break;
1621 }
1622
1623 add_error_context(_f("While rounding %1%:") % *this);
1624 throw_(value_error, _f("Cannot set rounding for %1%") % label());
1625 }
1626
in_place_roundto(int places)1627 void value_t::in_place_roundto(int places)
1628 {
1629 DEBUG("amount.roundto", "=====> roundto places " << places);
1630 switch (type()) {
1631 case INTEGER:
1632 return;
1633 case AMOUNT:
1634 as_amount_lval().in_place_roundto(places);
1635 return;
1636 case BALANCE:
1637 as_balance_lval().in_place_roundto(places);
1638 return;
1639 case SEQUENCE:
1640 foreach (value_t& value, as_sequence_lval())
1641 value.in_place_roundto(places);
1642 return;
1643 default:
1644 break;
1645 }
1646 }
1647
in_place_truncate()1648 void value_t::in_place_truncate()
1649 {
1650 switch (type()) {
1651 case INTEGER:
1652 return;
1653 case AMOUNT:
1654 as_amount_lval().in_place_truncate();
1655 return;
1656 case BALANCE:
1657 as_balance_lval().in_place_truncate();
1658 return;
1659 case SEQUENCE:
1660 foreach (value_t& value, as_sequence_lval())
1661 value.in_place_truncate();
1662 return;
1663 default:
1664 break;
1665 }
1666
1667 add_error_context(_f("While truncating %1%:") % *this);
1668 throw_(value_error, _f("Cannot truncate %1%") % label());
1669 }
1670
in_place_floor()1671 void value_t::in_place_floor()
1672 {
1673 switch (type()) {
1674 case INTEGER:
1675 return;
1676 case AMOUNT:
1677 as_amount_lval().in_place_floor();
1678 return;
1679 case BALANCE:
1680 as_balance_lval().in_place_floor();
1681 return;
1682 case SEQUENCE:
1683 foreach (value_t& value, as_sequence_lval())
1684 value.in_place_floor();
1685 return;
1686 default:
1687 break;
1688 }
1689
1690 add_error_context(_f("While flooring %1%:") % *this);
1691 throw_(value_error, _f("Cannot floor %1%") % label());
1692 }
1693
in_place_ceiling()1694 void value_t::in_place_ceiling()
1695 {
1696 switch (type()) {
1697 case INTEGER:
1698 return;
1699 case AMOUNT:
1700 as_amount_lval().in_place_ceiling();
1701 return;
1702 case BALANCE:
1703 as_balance_lval().in_place_ceiling();
1704 return;
1705 case SEQUENCE:
1706 foreach (value_t& value, as_sequence_lval())
1707 value.in_place_ceiling();
1708 return;
1709 default:
1710 break;
1711 }
1712
1713 add_error_context(_f("While ceiling %1%:") % *this);
1714 throw_(value_error, _f("Cannot ceiling %1%") % label());
1715 }
1716
in_place_unround()1717 void value_t::in_place_unround()
1718 {
1719 switch (type()) {
1720 case INTEGER:
1721 return;
1722 case AMOUNT:
1723 as_amount_lval().in_place_unround();
1724 return;
1725 case BALANCE:
1726 as_balance_lval().in_place_unround();
1727 return;
1728 case SEQUENCE:
1729 foreach (value_t& value, as_sequence_lval())
1730 value.in_place_unround();
1731 return;
1732 default:
1733 break;
1734 }
1735
1736 add_error_context(_f("While unrounding %1%:") % *this);
1737 throw_(value_error, _f("Cannot unround %1%") % label());
1738 }
1739
annotate(const annotation_t & details)1740 void value_t::annotate(const annotation_t& details)
1741 {
1742 if (is_amount()) {
1743 as_amount_lval().annotate(details);
1744 } else {
1745 add_error_context(_f("While attempting to annotate %1%:") % *this);
1746 throw_(value_error, _f("Cannot annotate %1%") % label());
1747 }
1748 }
1749
has_annotation() const1750 bool value_t::has_annotation() const
1751 {
1752 if (is_amount()) {
1753 return as_amount().has_annotation();
1754 } else {
1755 add_error_context(_f("While checking if %1% has annotations:") % *this);
1756 throw_(value_error,
1757 _f("Cannot determine whether %1% is annotated") % label());
1758 }
1759 return false;
1760 }
1761
annotation()1762 annotation_t& value_t::annotation()
1763 {
1764 if (is_amount()) {
1765 return as_amount_lval().annotation();
1766 } else {
1767 add_error_context(_f("While requesting the annotations of %1%:") % *this);
1768 throw_(value_error, _f("Cannot request annotation of %1%") % label());
1769 return as_amount_lval().annotation(); // quiet g++ warning
1770 }
1771 }
1772
strip_annotations(const keep_details_t & what_to_keep) const1773 value_t value_t::strip_annotations(const keep_details_t& what_to_keep) const
1774 {
1775 if (what_to_keep.keep_all())
1776 return *this;
1777
1778 switch (type()) {
1779 case VOID:
1780 case BOOLEAN:
1781 case INTEGER:
1782 case DATETIME:
1783 case DATE:
1784 case STRING:
1785 case MASK:
1786 case SCOPE:
1787 case ANY:
1788 return *this;
1789
1790 case SEQUENCE: {
1791 sequence_t temp;
1792 foreach (const value_t& value, as_sequence())
1793 temp.push_back(new value_t(value.strip_annotations(what_to_keep)));
1794 return temp;
1795 }
1796
1797 case AMOUNT:
1798 return as_amount().strip_annotations(what_to_keep);
1799 case BALANCE:
1800 return as_balance().strip_annotations(what_to_keep);
1801 }
1802
1803 assert(false);
1804 return NULL_VALUE;
1805 }
1806
label(optional<type_t> the_type) const1807 string value_t::label(optional<type_t> the_type) const
1808 {
1809 switch (the_type ? *the_type : type()) {
1810 case VOID:
1811 return _("an uninitialized value");
1812 case BOOLEAN:
1813 return _("a boolean");
1814 case DATETIME:
1815 return _("a date/time");
1816 case DATE:
1817 return _("a date");
1818 case INTEGER:
1819 return _("an integer");
1820 case AMOUNT:
1821 return _("an amount");
1822 case BALANCE:
1823 return _("a balance");
1824 case STRING:
1825 return _("a string");
1826 case MASK:
1827 return _("a regexp");
1828 case SEQUENCE:
1829 return _("a sequence");
1830 case SCOPE:
1831 return _("a scope");
1832 case ANY:
1833 if (as_any().type() == typeid(expr_t::ptr_op_t))
1834 return _("an expr");
1835 else
1836 return _("an object");
1837 }
1838 assert(false);
1839 return _("<invalid>");
1840 }
1841
print(std::ostream & _out,const int first_width,const int latter_width,const uint_least8_t flags) const1842 void value_t::print(std::ostream& _out,
1843 const int first_width,
1844 const int latter_width,
1845 const uint_least8_t flags) const
1846 {
1847 std::ostringstream out;
1848
1849 if (first_width > 0 &&
1850 (! is_amount() || as_amount().is_zero()) &&
1851 ! is_balance() && ! is_string()) {
1852 out.width(first_width);
1853
1854 if (flags & AMOUNT_PRINT_RIGHT_JUSTIFY)
1855 out << std::right;
1856 else
1857 out << std::left;
1858 }
1859
1860 switch (type()) {
1861 case VOID:
1862 out << "";
1863 break;
1864
1865 case BOOLEAN:
1866 out << (as_boolean() ? "1" : "0");
1867 break;
1868
1869 case DATETIME:
1870 out << format_datetime(as_datetime(), FMT_WRITTEN);
1871 break;
1872
1873 case DATE:
1874 out << format_date(as_date(), FMT_WRITTEN);
1875 break;
1876
1877 case INTEGER:
1878 if (flags & AMOUNT_PRINT_COLORIZE && as_long() < 0)
1879 justify(out, to_string(), first_width,
1880 flags & AMOUNT_PRINT_RIGHT_JUSTIFY, true);
1881 else
1882 out << as_long();
1883 break;
1884
1885 case AMOUNT: {
1886 if (as_amount().is_zero()) {
1887 out << 0;
1888 } else {
1889 std::ostringstream buf;
1890 as_amount().print(buf, flags);
1891 justify(out, buf.str(), first_width, flags & AMOUNT_PRINT_RIGHT_JUSTIFY,
1892 flags & AMOUNT_PRINT_COLORIZE && as_amount().sign() < 0);
1893 }
1894 break;
1895 }
1896
1897 case BALANCE:
1898 as_balance().print(out, first_width, latter_width, flags);
1899 break;
1900
1901 case STRING:
1902 if (first_width > 0)
1903 justify(out, as_string(), first_width, flags & AMOUNT_PRINT_RIGHT_JUSTIFY);
1904 else
1905 out << as_string();
1906 break;
1907
1908 case MASK:
1909 out << '/' << as_mask() << '/';
1910 break;
1911
1912 case SEQUENCE: {
1913 out << '(';
1914 bool first = true;
1915 foreach (const value_t& value, as_sequence()) {
1916 if (first)
1917 first = false;
1918 else
1919 out << ", ";
1920
1921 value.print(out, first_width, latter_width, flags);
1922 }
1923 out << ')';
1924 break;
1925 }
1926
1927 case SCOPE:
1928 out << "<#SCOPE>";
1929 break;
1930 case ANY:
1931 if (as_any().type() == typeid(expr_t::ptr_op_t)) {
1932 out << "<#EXPR ";
1933 as_any<expr_t::ptr_op_t>()->print(out);
1934 out << ">";
1935 } else {
1936 out << "<#OBJECT>";
1937 }
1938 break;
1939 }
1940
1941 _out << out.str();
1942 }
1943
dump(std::ostream & out,const bool relaxed) const1944 void value_t::dump(std::ostream& out, const bool relaxed) const
1945 {
1946 switch (type()) {
1947 case VOID:
1948 out << "null";
1949 break;
1950
1951 case BOOLEAN:
1952 if (as_boolean())
1953 out << "true";
1954 else
1955 out << "false";
1956 break;
1957
1958 case DATETIME:
1959 out << '[' << format_datetime(as_datetime(), FMT_WRITTEN) << ']';
1960 break;
1961 case DATE:
1962 out << '[' << format_date(as_date(), FMT_WRITTEN) << ']';
1963 break;
1964
1965 case INTEGER:
1966 out << as_long();
1967 break;
1968
1969 case AMOUNT:
1970 if (! relaxed)
1971 out << '{';
1972 out << as_amount();
1973 if (! relaxed)
1974 out << '}';
1975 break;
1976
1977 case BALANCE:
1978 out << as_balance();
1979 break;
1980
1981 case STRING:
1982 out << '"';
1983 foreach (const char& ch, as_string()) {
1984 switch (ch) {
1985 case '"':
1986 out << "\\\"";
1987 break;
1988 case '\\':
1989 out << "\\\\";
1990 break;
1991 default:
1992 out << ch;
1993 break;
1994 }
1995 }
1996 out << '"';
1997 break;
1998
1999 case MASK:
2000 out << '/' << as_mask() << '/';
2001 break;
2002
2003 case SCOPE:
2004 out << as_scope();
2005 break;
2006 case ANY:
2007 if (as_any().type() == typeid(expr_t::ptr_op_t))
2008 as_any<expr_t::ptr_op_t>()->dump(out);
2009 else
2010 out << boost::unsafe_any_cast<const void *>(&as_any());
2011 break;
2012
2013 case SEQUENCE: {
2014 out << '(';
2015 bool first = true;
2016 foreach (const value_t& value, as_sequence()) {
2017 if (first)
2018 first = false;
2019 else
2020 out << ", ";
2021
2022 value.dump(out, relaxed);
2023 }
2024 out << ')';
2025 break;
2026 }
2027 }
2028 }
2029
valid() const2030 bool value_t::valid() const
2031 {
2032 switch (type()) {
2033 case AMOUNT:
2034 return as_amount().valid();
2035 case BALANCE:
2036 return as_balance().valid();
2037 default:
2038 break;
2039 }
2040 return true;
2041 }
2042
sort_value_is_less_than(const std::list<sort_value_t> & left_values,const std::list<sort_value_t> & right_values)2043 bool sort_value_is_less_than(const std::list<sort_value_t>& left_values,
2044 const std::list<sort_value_t>& right_values)
2045 {
2046 std::list<sort_value_t>::const_iterator left_iter = left_values.begin();
2047 std::list<sort_value_t>::const_iterator right_iter = right_values.begin();
2048
2049 while (left_iter != left_values.end() && right_iter != right_values.end()) {
2050 // Don't even try to sort balance values
2051 if (! (*left_iter).value.is_balance() &&
2052 ! (*right_iter).value.is_balance()) {
2053 DEBUG("value.sort",
2054 " Comparing " << (*left_iter).value << " < " << (*right_iter).value);
2055 if ((*left_iter).value < (*right_iter).value) {
2056 DEBUG("value.sort", " is less");
2057 return ! (*left_iter).inverted;
2058 }
2059 else if ((*left_iter).value > (*right_iter).value) {
2060 DEBUG("value.sort", " is greater");
2061 return (*left_iter).inverted;
2062 }
2063 }
2064 left_iter++; right_iter++;
2065 }
2066
2067 assert(left_iter == left_values.end());
2068 assert(right_iter == right_values.end());
2069
2070 return false;
2071 }
2072
put_value(property_tree::ptree & pt,const value_t & value)2073 void put_value(property_tree::ptree& pt, const value_t& value)
2074 {
2075 switch (value.type()) {
2076 case value_t::VOID:
2077 pt.add("void", "");
2078 break;
2079 case value_t::BOOLEAN:
2080 pt.add("bool", value.as_boolean() ? "true" : "false");
2081 break;
2082 case value_t::INTEGER:
2083 pt.add("int", value.to_string());
2084 break;
2085 case value_t::AMOUNT:
2086 put_amount(pt.add("amount", ""), value.as_amount());
2087 break;
2088 case value_t::BALANCE:
2089 put_balance(pt.add("balance", ""), value.as_balance());
2090 break;
2091 case value_t::DATETIME:
2092 put_datetime(pt.add("datetime", ""), value.as_datetime());
2093 break;
2094 case value_t::DATE:
2095 put_date(pt.add("date", ""), value.as_date());
2096 break;
2097 case value_t::STRING:
2098 pt.add("string", value.as_string());
2099 break;
2100 case value_t::MASK:
2101 put_mask(pt.add("mask", ""), value.as_mask());
2102 break;
2103
2104 case value_t::SEQUENCE: {
2105 property_tree::ptree& st(pt.add("sequence", ""));
2106 foreach (const value_t& member, value.as_sequence())
2107 put_value(st, member);
2108 break;
2109 }
2110
2111 case value_t::SCOPE:
2112 case value_t::ANY:
2113 assert(false);
2114 break;
2115 }
2116 }
2117
2118 } // namespace ledger
2119