summaryrefslogtreecommitdiff
path: root/src/annotate.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/annotate.cc')
-rw-r--r--src/annotate.cc158
1 files changed, 145 insertions, 13 deletions
diff --git a/src/annotate.cc b/src/annotate.cc
index cd1733ca..2b118e76 100644
--- a/src/annotate.cc
+++ b/src/annotate.cc
@@ -33,11 +33,47 @@
#include "amount.h"
#include "commodity.h"
+#include "expr.h"
#include "annotate.h"
#include "pool.h"
namespace ledger {
+bool annotation_t::operator<(const annotation_t& rhs) const
+{
+ if (! price && rhs.price) return true;
+ if (price && ! rhs.price) return false;
+ if (! date && rhs.date) return true;
+ if (date && ! rhs.date) return false;
+ if (! tag && rhs.tag) return true;
+ if (tag && ! rhs.tag) return false;
+
+ if (! value_expr && rhs.value_expr) return true;
+ if (value_expr && ! rhs.value_expr) return false;
+
+ if (price) {
+ if (price->commodity().symbol() < rhs.price->commodity().symbol())
+ return true;
+ if (price->commodity().symbol() > rhs.price->commodity().symbol())
+ return false;
+ if (*price < *rhs.price) return true;
+ if (*price > *rhs.price) return false;
+ }
+ if (date) {
+ if (*date < *rhs.date) return true;
+ if (*date > *rhs.date) return false;
+ }
+ if (tag) {
+ if (*tag < *rhs.tag) return true;
+ if (*tag > *rhs.tag) return false;
+ }
+ if (value_expr) {
+ if (value_expr->text() < rhs.value_expr->text()) return true;
+ if (value_expr->text() > rhs.value_expr->text()) return false;
+ }
+ return false;
+}
+
void annotation_t::parse(std::istream& in)
{
do {
@@ -52,6 +88,12 @@ void annotation_t::parse(std::istream& in)
throw_(amount_error, _("Commodity specifies more than one price"));
in.get(c);
+ c = static_cast<char>(in.peek());
+ if (c == '{') {
+ in.get(c);
+ add_flags(ANNOTATION_PRICE_NOT_PER_UNIT);
+ }
+
c = peek_next_nonws(in);
if (c == '=') {
in.get(c);
@@ -59,10 +101,18 @@ void annotation_t::parse(std::istream& in)
}
READ_INTO(in, buf, 255, c, c != '}');
- if (c == '}')
+ if (c == '}') {
in.get(c);
- else
- throw_(amount_error, _("Commodity price lacks closing brace"));
+ if (has_flags(ANNOTATION_PRICE_NOT_PER_UNIT)) {
+ c = static_cast<char>(in.peek());
+ if (c != '}')
+ throw_(amount_error, _("Commodity lot price lacks double closing brace"));
+ else
+ in.get(c);
+ }
+ } else {
+ throw_(amount_error, _("Commodity lot price lacks closing brace"));
+ }
amount_t temp;
temp.parse(buf, PARSE_NO_MIGRATE);
@@ -84,17 +134,46 @@ void annotation_t::parse(std::istream& in)
date = parse_date(buf);
}
else if (c == '(') {
- if (tag)
- throw_(amount_error, _("Commodity specifies more than one tag"));
-
in.get(c);
- READ_INTO(in, buf, 255, c, c != ')');
- if (c == ')')
- in.get(c);
- else
- throw_(amount_error, _("Commodity tag lacks closing parenthesis"));
+ c = static_cast<char>(in.peek());
+ if (c == '@') {
+ in.clear();
+ in.seekg(pos, std::ios::beg);
+ break;
+ }
+ else if (c == '(') {
+ if (value_expr)
+ throw_(amount_error,
+ _("Commodity specifies more than one valuation expresion"));
- tag = buf;
+ in.get(c);
+ READ_INTO(in, buf, 255, c, c != ')');
+ if (c == ')') {
+ in.get(c);
+ c = static_cast<char>(in.peek());
+ if (c == ')')
+ in.get(c);
+ else
+ throw_(amount_error,
+ _("Commodity valuation expression lacks closing parentheses"));
+ } else {
+ throw_(amount_error,
+ _("Commodity valuation expression lacks closing parentheses"));
+ }
+
+ value_expr = expr_t(buf);
+ } else {
+ if (tag)
+ throw_(amount_error, _("Commodity specifies more than one tag"));
+
+ READ_INTO(in, buf, 255, c, c != ')');
+ if (c == ')')
+ in.get(c);
+ else
+ throw_(amount_error, _("Commodity tag lacks closing parenthesis"));
+
+ tag = buf;
+ }
}
else {
in.clear();
@@ -128,6 +207,10 @@ void annotation_t::print(std::ostream& out, bool keep_base,
if (tag &&
(! no_computed_annotations || ! has_flags(ANNOTATION_TAG_CALCULATED)))
out << " (" << *tag << ')';
+
+ if (value_expr && (! no_computed_annotations ||
+ ! has_flags(ANNOTATION_VALUE_EXPR_CALCULATED)))
+ out << " ((" << *value_expr << "))";
}
bool keep_details_t::keep_all(const commodity_t& comm) const
@@ -157,6 +240,54 @@ bool annotated_commodity_t::operator==(const commodity_t& comm) const
return true;
}
+optional<price_point_t>
+annotated_commodity_t::find_price(const commodity_t * commodity,
+ const datetime_t& moment,
+ const datetime_t& oldest) const
+{
+ DEBUG("commodity.price.find",
+ "annotated_commodity_t::find_price(" << symbol() << ")");
+
+ datetime_t when;
+ if (! moment.is_not_a_date_time())
+ when = moment;
+ else if (epoch)
+ when = *epoch;
+ else
+ when = CURRENT_TIME();
+
+ DEBUG("commodity.price.find", "reference time: " << when);
+
+ const commodity_t * target = NULL;
+ if (commodity)
+ target = commodity;
+
+ if (details.price) {
+ DEBUG("commodity.price.find", "price annotation: " << *details.price);
+
+ if (details.has_flags(ANNOTATION_PRICE_FIXATED)) {
+ DEBUG("commodity.price.find",
+ "amount_t::value: fixated price = " << *details.price);
+ return price_point_t(when, *details.price);
+ }
+ else if (! target) {
+ DEBUG("commodity.price.find", "setting target commodity from price");
+ target = details.price->commodity_ptr();
+ }
+ }
+
+#if defined(DEBUG_ON)
+ if (target)
+ DEBUG("commodity.price.find", "target commodity: " << target->symbol());
+#endif
+
+ if (details.value_expr)
+ return find_price_from_expr(const_cast<expr_t&>(*details.value_expr),
+ commodity, when);
+
+ return commodity_t::find_price(target, moment, oldest);
+}
+
commodity_t&
annotated_commodity_t::strip_annotations(const keep_details_t& what_to_keep)
{
@@ -192,7 +323,8 @@ annotated_commodity_t::strip_annotations(const keep_details_t& what_to_keep)
if ((keep_price && details.price) ||
(keep_date && details.date) ||
- (keep_tag && details.tag))
+ (keep_tag && details.tag) ||
+ details.value_expr)
{
new_comm = pool().find_or_create
(referent(), annotation_t(keep_price ? details.price : none,