Add support for valuation expressions on commodities
This commit is contained in:
parent
7b12b3041d
commit
8ae2fb8721
6 changed files with 97 additions and 95 deletions
|
|
@ -33,6 +33,7 @@
|
|||
|
||||
#include "amount.h"
|
||||
#include "commodity.h"
|
||||
#include "expr.h"
|
||||
#include "annotate.h"
|
||||
#include "pool.h"
|
||||
|
||||
|
|
@ -47,6 +48,9 @@ bool annotation_t::operator<(const annotation_t& rhs) const
|
|||
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;
|
||||
|
|
@ -63,6 +67,10 @@ bool annotation_t::operator<(const annotation_t& rhs) const
|
|||
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;
|
||||
}
|
||||
|
||||
|
|
@ -112,17 +120,41 @@ 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 == '(') {
|
||||
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();
|
||||
|
|
@ -156,6 +188,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
|
||||
|
|
@ -220,12 +256,14 @@ 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,
|
||||
keep_date ? details.date : none,
|
||||
keep_tag ? details.tag : none));
|
||||
keep_tag ? details.tag : none,
|
||||
details.value_expr));
|
||||
|
||||
// Transfer over any relevant annotation flags, as they still apply.
|
||||
if (new_comm->annotated) {
|
||||
|
|
@ -238,6 +276,8 @@ annotated_commodity_t::strip_annotations(const keep_details_t& what_to_keep)
|
|||
new_details.add_flags(details.flags() & ANNOTATION_DATE_CALCULATED);
|
||||
if (keep_tag)
|
||||
new_details.add_flags(details.flags() & ANNOTATION_TAG_CALCULATED);
|
||||
if (details.value_expr)
|
||||
new_details.add_flags(details.flags() & ANNOTATION_VALUE_EXPR_CALCULATED);
|
||||
}
|
||||
|
||||
return *new_comm;
|
||||
|
|
|
|||
|
|
@ -46,29 +46,38 @@
|
|||
#ifndef _ANNOTATE_H
|
||||
#define _ANNOTATE_H
|
||||
|
||||
#include "expr.h"
|
||||
|
||||
namespace ledger {
|
||||
|
||||
struct annotation_t : public supports_flags<>,
|
||||
public equality_comparable<annotation_t>
|
||||
{
|
||||
#define ANNOTATION_PRICE_CALCULATED 0x01
|
||||
#define ANNOTATION_PRICE_FIXATED 0x02
|
||||
#define ANNOTATION_DATE_CALCULATED 0x04
|
||||
#define ANNOTATION_TAG_CALCULATED 0x08
|
||||
#define ANNOTATION_PRICE_CALCULATED 0x01
|
||||
#define ANNOTATION_PRICE_FIXATED 0x02
|
||||
#define ANNOTATION_DATE_CALCULATED 0x04
|
||||
#define ANNOTATION_TAG_CALCULATED 0x08
|
||||
#define ANNOTATION_VALUE_EXPR_CALCULATED 0x10
|
||||
|
||||
optional<amount_t> price;
|
||||
optional<date_t> date;
|
||||
optional<string> tag;
|
||||
optional<expr_t> value_expr;
|
||||
|
||||
explicit annotation_t(const optional<amount_t>& _price = none,
|
||||
const optional<date_t>& _date = none,
|
||||
const optional<string>& _tag = none)
|
||||
: supports_flags<>(), price(_price), date(_date), tag(_tag) {
|
||||
TRACE_CTOR(annotation_t, "const optional<amount_t>& + date_t + string");
|
||||
explicit annotation_t(const optional<amount_t>& _price = none,
|
||||
const optional<date_t>& _date = none,
|
||||
const optional<string>& _tag = none,
|
||||
const optional<expr_t>& _value_expr = none)
|
||||
: supports_flags<>(), price(_price), date(_date), tag(_tag),
|
||||
value_expr(_value_expr) {
|
||||
TRACE_CTOR(annotation_t,
|
||||
"const optional<amount_t>& + date_t + string + expr_t");
|
||||
}
|
||||
annotation_t(const annotation_t& other)
|
||||
: supports_flags<>(other.flags()),
|
||||
price(other.price), date(other.date), tag(other.tag) {
|
||||
price(other.price), date(other.date), tag(other.tag),
|
||||
value_expr(other.value_expr)
|
||||
{
|
||||
TRACE_CTOR(annotation_t, "copy");
|
||||
}
|
||||
~annotation_t() {
|
||||
|
|
@ -76,14 +85,15 @@ struct annotation_t : public supports_flags<>,
|
|||
}
|
||||
|
||||
operator bool() const {
|
||||
return price || date || tag;
|
||||
return price || date || tag || value_expr;
|
||||
}
|
||||
|
||||
bool operator<(const annotation_t& rhs) const;
|
||||
bool operator==(const annotation_t& rhs) const {
|
||||
return (price == rhs.price &&
|
||||
date == rhs.date &&
|
||||
tag == rhs.tag);
|
||||
return (price == rhs.price &&
|
||||
date == rhs.date &&
|
||||
tag == rhs.tag &&
|
||||
value_expr == rhs.value_expr);
|
||||
}
|
||||
|
||||
void parse(std::istream& in);
|
||||
|
|
@ -133,6 +143,12 @@ inline void to_xml(std::ostream& out, const annotation_t& details)
|
|||
push_xml y(out, "tag");
|
||||
out << y.guard(*details.tag);
|
||||
}
|
||||
|
||||
if (details.value_expr)
|
||||
{
|
||||
push_xml y(out, "value-expr");
|
||||
out << y.guard(details.value_expr->text());
|
||||
}
|
||||
}
|
||||
|
||||
struct keep_details_t
|
||||
|
|
|
|||
|
|
@ -58,6 +58,9 @@ public:
|
|||
typedef intrusive_ptr<op_t> ptr_op_t;
|
||||
typedef intrusive_ptr<const op_t> const_ptr_op_t;
|
||||
|
||||
friend void intrusive_ptr_add_ref(const op_t * op);
|
||||
friend void intrusive_ptr_release(const op_t * op);
|
||||
|
||||
enum check_expr_kind_t {
|
||||
EXPR_GENERAL,
|
||||
EXPR_ASSERTION,
|
||||
|
|
|
|||
|
|
@ -1,40 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2003-2012, John Wiegley. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* - Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* - Neither the name of New Artisans LLC nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <system.hh>
|
||||
|
||||
#include "predicate.h"
|
||||
#include "query.h"
|
||||
#include "op.h"
|
||||
|
||||
namespace ledger {
|
||||
|
||||
} // namespace ledger
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
#define BOOST_TEST_DYN_LINK
|
||||
#define BOOST_TEST_MODULE expr
|
||||
//#define BOOST_TEST_MODULE expr
|
||||
#include <boost/test/unit_test.hpp>
|
||||
|
||||
#include <system.hh>
|
||||
|
|
|
|||
|
|
@ -8,7 +8,6 @@ DISTCLEANFILES = .timestamp
|
|||
lib_LTLIBRARIES = \
|
||||
libledger_report.la \
|
||||
libledger_data.la \
|
||||
libledger_expr.la \
|
||||
libledger_math.la \
|
||||
libledger_util.la
|
||||
|
||||
|
|
@ -28,6 +27,14 @@ libledger_util_la_CPPFLAGS = $(lib_cppflags)
|
|||
libledger_util_la_LDFLAGS = -release $(LIBVERSION)
|
||||
|
||||
libledger_math_la_SOURCES = \
|
||||
src/format.cc \
|
||||
src/query.cc \
|
||||
src/scope.cc \
|
||||
src/expr.cc \
|
||||
src/op.cc \
|
||||
src/parser.cc \
|
||||
src/token.cc \
|
||||
src/value.cc \
|
||||
src/balance.cc \
|
||||
src/quotes.cc \
|
||||
src/history.cc \
|
||||
|
|
@ -39,22 +46,8 @@ libledger_math_la_SOURCES = \
|
|||
libledger_math_la_CPPFLAGS = $(lib_cppflags)
|
||||
libledger_math_la_LDFLAGS = -release $(LIBVERSION)
|
||||
|
||||
libledger_expr_la_SOURCES = \
|
||||
src/option.cc \
|
||||
src/format.cc \
|
||||
src/query.cc \
|
||||
src/predicate.cc \
|
||||
src/scope.cc \
|
||||
src/expr.cc \
|
||||
src/op.cc \
|
||||
src/parser.cc \
|
||||
src/token.cc \
|
||||
src/value.cc
|
||||
|
||||
libledger_expr_la_CPPFLAGS = $(lib_cppflags)
|
||||
libledger_expr_la_LDFLAGS = -release $(LIBVERSION)
|
||||
|
||||
libledger_data_la_SOURCES = \
|
||||
src/option.cc \
|
||||
src/lookup.cc \
|
||||
src/compare.cc \
|
||||
src/iterators.cc \
|
||||
|
|
@ -204,7 +197,6 @@ DISTCLEANFILES += ledger.elc timeclock.elc
|
|||
|
||||
all_sources = $(libledger_util_la_SOURCES) \
|
||||
$(libledger_math_la_SOURCES) \
|
||||
$(libledger_expr_la_SOURCES) \
|
||||
$(libledger_data_la_SOURCES) \
|
||||
$(libledger_report_la_SOURCES) \
|
||||
$(libledger_python_la_SOURCES) \
|
||||
|
|
@ -259,8 +251,7 @@ TESTS = RegressTests BaselineTests ManualTests ConfirmTests \
|
|||
if HAVE_BOOST_TEST
|
||||
TESTS += \
|
||||
UtilTests \
|
||||
MathTests \
|
||||
ExprTests
|
||||
MathTests
|
||||
# DataTests \
|
||||
# ReportTests
|
||||
endif
|
||||
|
|
@ -285,6 +276,7 @@ UtilTests_CPPFLAGS = -I$(srcdir)/test $(lib_cppflags)
|
|||
UtilTests_LDADD = libledger_util.la $(TESTLIBS)
|
||||
|
||||
MathTests_SOURCES = \
|
||||
test/unit/t_expr.cc \
|
||||
test/unit/t_commodity.cc \
|
||||
test/unit/t_amount.cc \
|
||||
test/unit/t_balance.cc
|
||||
|
|
@ -292,16 +284,10 @@ MathTests_SOURCES = \
|
|||
MathTests_CPPFLAGS = -I$(srcdir)/test $(lib_cppflags)
|
||||
MathTests_LDADD = libledger_math.la $(UtilTests_LDADD)
|
||||
|
||||
ExprTests_SOURCES = \
|
||||
test/unit/t_expr.cc
|
||||
|
||||
ExprTests_CPPFLAGS = -I$(srcdir)/test $(lib_cppflags)
|
||||
ExprTests_LDADD = libledger_expr.la $(MathTests_LDADD)
|
||||
|
||||
DataTests_SOURCES =
|
||||
|
||||
DataTests_CPPFLAGS = -I$(srcdir)/test $(lib_cppflags)
|
||||
DataTests_LDADD = libledger_data.la $(ExprTests_LDADD)
|
||||
DataTests_LDADD = libledger_data.la $(MathTests_LDADD)
|
||||
|
||||
ReportTests_SOURCES =
|
||||
|
||||
|
|
@ -311,7 +297,6 @@ ReportTests_LDADD = libledger_report.la $(DataTests_LDADD)
|
|||
all_tests_sources = \
|
||||
$(UtilTests_SOURCES) \
|
||||
$(MathTests_SOURCES) \
|
||||
$(ExprTests_SOURCES) \
|
||||
$(DataTests_SOURCES) \
|
||||
$(ReportTests_SOURCES)
|
||||
|
||||
|
|
@ -421,8 +406,6 @@ unittests: check
|
|||
2>&1 | grep -v '^GuardMalloc:'
|
||||
@sh $(FULLCHECK) $(top_builddir)/MathTests$(EXEEXT) --verify \
|
||||
2>&1 | grep -v '^GuardMalloc:'
|
||||
@sh $(FULLCHECK) $(top_builddir)/ExprTests$(EXEEXT) --verify \
|
||||
2>&1 | grep -v '^GuardMalloc:'
|
||||
# @sh $(FULLCHECK) $(top_builddir)/DataTests$(EXEEXT) --verify \
|
||||
# 2>&1 | grep -v '^GuardMalloc:'
|
||||
# @sh $(FULLCHECK) $(top_builddir)/ReportTests$(EXEEXT) --verify \
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue