More work toward getting the textual parser working again. Since this means
that value expressions must work, there are a lot of details involved.
This commit is contained in:
parent
7409b050be
commit
643f2d33cf
16 changed files with 380 additions and 210 deletions
32
acprep
32
acprep
|
|
@ -35,6 +35,10 @@ LIBDIRS="$LIBDIRS -L/usr/local/lib"
|
||||||
|
|
||||||
PYTHON_HOME="/usr"
|
PYTHON_HOME="/usr"
|
||||||
|
|
||||||
|
if [ -x /usr/bin/g++-4.2 ]; then
|
||||||
|
CXX=g++-4.2
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
SYSTEM=`uname -s`
|
SYSTEM=`uname -s`
|
||||||
|
|
||||||
|
|
@ -85,44 +89,50 @@ while [ -n "$1" ]; do
|
||||||
SWITCHES="$SWITCHES --disable-shared"
|
SWITCHES="$SWITCHES --disable-shared"
|
||||||
CPPFLAGS="$CPPFLAGS -DBOOST_MULTI_INDEX_ENABLE_INVARIANT_CHECKING=1"
|
CPPFLAGS="$CPPFLAGS -DBOOST_MULTI_INDEX_ENABLE_INVARIANT_CHECKING=1"
|
||||||
CPPFLAGS="$CPPFLAGS -DBOOST_MULTI_INDEX_ENABLE_SAFE_MODE=1"
|
CPPFLAGS="$CPPFLAGS -DBOOST_MULTI_INDEX_ENABLE_SAFE_MODE=1"
|
||||||
;;
|
shift 1 ;;
|
||||||
|
|
||||||
--debug)
|
--debug)
|
||||||
SWITCHES="$SWITCHES --enable-debug"
|
SWITCHES="$SWITCHES --enable-debug"
|
||||||
#CPPFLAGS="$CPPFLAGS -D_GLIBCXX_DEBUG=1"
|
#CPPFLAGS="$CPPFLAGS -D_GLIBCXX_DEBUG=1"
|
||||||
CXXFLAGS="$CXXFLAGS -g" ;;
|
CXXFLAGS="$CXXFLAGS -g"
|
||||||
|
shift 1 ;;
|
||||||
|
|
||||||
--boost)
|
--boost)
|
||||||
shift 1
|
shift 1
|
||||||
SWITCHES="$SWITCHES --with-boost-suffix=$1"
|
SWITCHES="$SWITCHES --with-boost-suffix=$1"
|
||||||
;;
|
shift 1 ;;
|
||||||
|
|
||||||
--gcov)
|
--gcov)
|
||||||
CXXFLAGS="$CXXFLAGS -fprofile-arcs -ftest-coverage" ;;
|
CXXFLAGS="$CXXFLAGS -fprofile-arcs -ftest-coverage"
|
||||||
|
shift 1 ;;
|
||||||
|
|
||||||
--gprof)
|
--gprof)
|
||||||
CXXFLAGS="$CXXFLAGS -g -pg" ;;
|
CXXFLAGS="$CXXFLAGS -g -pg"
|
||||||
|
shift 1 ;;
|
||||||
|
|
||||||
--python)
|
--python)
|
||||||
if [ -d "$PYTHON_HOME" ]; then
|
if [ -d "$PYTHON_HOME" ]; then
|
||||||
SWITCHES="$SWITCHES --enable-python"
|
SWITCHES="$SWITCHES --enable-python"
|
||||||
CPPFLAGS="$CPPFLAGS -I$PYTHON_HOME/include/python2.5"
|
CPPFLAGS="$CPPFLAGS -I$PYTHON_HOME/include/python2.5"
|
||||||
LDFLAGS="$LDFLAGS -L$PYTHON_HOME/lib/python2.5/config"
|
LDFLAGS="$LDFLAGS -L$PYTHON_HOME/lib/python2.5/config"
|
||||||
fi ;;
|
fi
|
||||||
|
shift 1;;
|
||||||
|
|
||||||
--pic)
|
--pic)
|
||||||
CXXFLAGS="$CXXFLAGS -fPIC" ;;
|
CXXFLAGS="$CXXFLAGS -fPIC"
|
||||||
|
shift 1 ;;
|
||||||
|
|
||||||
--opt)
|
--opt)
|
||||||
CXXFLAGS="$CXXFLAGS -fomit-frame-pointer -O3" ;;
|
CXXFLAGS="$CXXFLAGS -fomit-frame-pointer -O3"
|
||||||
|
shift 1 ;;
|
||||||
|
|
||||||
--local)
|
--local)
|
||||||
LOCAL=true ;;
|
LOCAL=true
|
||||||
|
shift 1 ;;
|
||||||
|
|
||||||
*)
|
*)
|
||||||
break ;;
|
break ;;
|
||||||
esac
|
esac
|
||||||
shift 1
|
|
||||||
done
|
done
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
52
amount.cc
52
amount.cc
|
|
@ -97,6 +97,25 @@ struct amount_t::bigint_t : public supports_flags<>
|
||||||
assert(ref == 0);
|
assert(ref == 0);
|
||||||
mpz_clear(val);
|
mpz_clear(val);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool valid() const {
|
||||||
|
if (prec > 32) {
|
||||||
|
DEBUG("ledger.validate", "amount_t::bigint_t: prec > 32");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (ref > 128) {
|
||||||
|
DEBUG("ledger.validate", "amount_t::bigint_t: ref > 128");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
#if 0
|
||||||
|
// jww (2008-07-24): How does one check the validity of an mpz_t?
|
||||||
|
if (val[0]._mp_size < 0 || val[0]._mp_size > 100) {
|
||||||
|
DEBUG("ledger.validate", "amount_t::bigint_t: val._mp_size is bad");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return true;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
uint_fast32_t amount_t::sizeof_bigint_t()
|
uint_fast32_t amount_t::sizeof_bigint_t()
|
||||||
|
|
@ -139,6 +158,8 @@ void amount_t::shutdown()
|
||||||
|
|
||||||
void amount_t::_copy(const amount_t& amt)
|
void amount_t::_copy(const amount_t& amt)
|
||||||
{
|
{
|
||||||
|
assert(amt.valid());
|
||||||
|
|
||||||
if (quantity != amt.quantity) {
|
if (quantity != amt.quantity) {
|
||||||
if (quantity)
|
if (quantity)
|
||||||
_release();
|
_release();
|
||||||
|
|
@ -155,15 +176,21 @@ void amount_t::_copy(const amount_t& amt)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
commodity_ = amt.commodity_;
|
commodity_ = amt.commodity_;
|
||||||
|
|
||||||
|
assert(valid());
|
||||||
}
|
}
|
||||||
|
|
||||||
void amount_t::_dup()
|
void amount_t::_dup()
|
||||||
{
|
{
|
||||||
|
assert(valid());
|
||||||
|
|
||||||
if (quantity->ref > 1) {
|
if (quantity->ref > 1) {
|
||||||
bigint_t * q = new bigint_t(*quantity);
|
bigint_t * q = new bigint_t(*quantity);
|
||||||
_release();
|
_release();
|
||||||
quantity = q;
|
quantity = q;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
assert(valid());
|
||||||
}
|
}
|
||||||
|
|
||||||
void amount_t::_resize(precision_t prec)
|
void amount_t::_resize(precision_t prec)
|
||||||
|
|
@ -180,6 +207,8 @@ void amount_t::_resize(precision_t prec)
|
||||||
mpz_mul(MPZ(quantity), MPZ(quantity), divisor);
|
mpz_mul(MPZ(quantity), MPZ(quantity), divisor);
|
||||||
|
|
||||||
quantity->prec = prec;
|
quantity->prec = prec;
|
||||||
|
|
||||||
|
assert(valid());
|
||||||
}
|
}
|
||||||
|
|
||||||
void amount_t::_clear()
|
void amount_t::_clear()
|
||||||
|
|
@ -195,6 +224,8 @@ void amount_t::_clear()
|
||||||
|
|
||||||
void amount_t::_release()
|
void amount_t::_release()
|
||||||
{
|
{
|
||||||
|
assert(valid());
|
||||||
|
|
||||||
DEBUG("amounts.refs", quantity << " ref--, now " << (quantity->ref - 1));
|
DEBUG("amounts.refs", quantity << " ref--, now " << (quantity->ref - 1));
|
||||||
|
|
||||||
if (--quantity->ref == 0) {
|
if (--quantity->ref == 0) {
|
||||||
|
|
@ -202,7 +233,11 @@ void amount_t::_release()
|
||||||
quantity->~bigint_t();
|
quantity->~bigint_t();
|
||||||
else
|
else
|
||||||
checked_delete(quantity);
|
checked_delete(quantity);
|
||||||
|
quantity = NULL;
|
||||||
|
commodity_ = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
assert(valid());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -328,6 +363,8 @@ amount_t& amount_t::operator=(const amount_t& amt)
|
||||||
|
|
||||||
int amount_t::compare(const amount_t& amt) const
|
int amount_t::compare(const amount_t& amt) const
|
||||||
{
|
{
|
||||||
|
assert(amt.valid());
|
||||||
|
|
||||||
if (! quantity || ! amt.quantity) {
|
if (! quantity || ! amt.quantity) {
|
||||||
if (quantity)
|
if (quantity)
|
||||||
throw_(amount_error, "Cannot compare an amount to an uninitialized amount");
|
throw_(amount_error, "Cannot compare an amount to an uninitialized amount");
|
||||||
|
|
@ -361,6 +398,8 @@ int amount_t::compare(const amount_t& amt) const
|
||||||
|
|
||||||
amount_t& amount_t::operator+=(const amount_t& amt)
|
amount_t& amount_t::operator+=(const amount_t& amt)
|
||||||
{
|
{
|
||||||
|
assert(amt.valid());
|
||||||
|
|
||||||
if (! quantity || ! amt.quantity) {
|
if (! quantity || ! amt.quantity) {
|
||||||
if (quantity)
|
if (quantity)
|
||||||
throw_(amount_error, "Cannot add an amount to an uninitialized amount");
|
throw_(amount_error, "Cannot add an amount to an uninitialized amount");
|
||||||
|
|
@ -397,6 +436,8 @@ amount_t& amount_t::operator+=(const amount_t& amt)
|
||||||
|
|
||||||
amount_t& amount_t::operator-=(const amount_t& amt)
|
amount_t& amount_t::operator-=(const amount_t& amt)
|
||||||
{
|
{
|
||||||
|
assert(amt.valid());
|
||||||
|
|
||||||
if (! quantity || ! amt.quantity) {
|
if (! quantity || ! amt.quantity) {
|
||||||
if (quantity)
|
if (quantity)
|
||||||
throw_(amount_error, "Cannot subtract an amount from an uninitialized amount");
|
throw_(amount_error, "Cannot subtract an amount from an uninitialized amount");
|
||||||
|
|
@ -481,6 +522,8 @@ namespace {
|
||||||
|
|
||||||
amount_t& amount_t::operator*=(const amount_t& amt)
|
amount_t& amount_t::operator*=(const amount_t& amt)
|
||||||
{
|
{
|
||||||
|
assert(amt.valid());
|
||||||
|
|
||||||
if (! quantity || ! amt.quantity) {
|
if (! quantity || ! amt.quantity) {
|
||||||
if (quantity)
|
if (quantity)
|
||||||
throw_(amount_error, "Cannot multiply an amount by an uninitialized amount");
|
throw_(amount_error, "Cannot multiply an amount by an uninitialized amount");
|
||||||
|
|
@ -521,6 +564,8 @@ amount_t& amount_t::operator*=(const amount_t& amt)
|
||||||
|
|
||||||
amount_t& amount_t::operator/=(const amount_t& amt)
|
amount_t& amount_t::operator/=(const amount_t& amt)
|
||||||
{
|
{
|
||||||
|
assert(amt.valid());
|
||||||
|
|
||||||
if (! quantity || ! amt.quantity) {
|
if (! quantity || ! amt.quantity) {
|
||||||
if (quantity)
|
if (quantity)
|
||||||
throw_(amount_error, "Cannot divide an amount by an uninitialized amount");
|
throw_(amount_error, "Cannot divide an amount by an uninitialized amount");
|
||||||
|
|
@ -1023,6 +1068,8 @@ void amount_t::parse(std::istream& in, flags_t flags)
|
||||||
in_place_reduce();
|
in_place_reduce();
|
||||||
|
|
||||||
safe_holder.release(); // `this->quantity' owns the pointer
|
safe_holder.release(); // `this->quantity' owns the pointer
|
||||||
|
|
||||||
|
assert(valid());
|
||||||
}
|
}
|
||||||
|
|
||||||
void amount_t::parse_conversion(const string& larger_str,
|
void amount_t::parse_conversion(const string& larger_str,
|
||||||
|
|
@ -1048,6 +1095,8 @@ void amount_t::parse_conversion(const string& larger_str,
|
||||||
void amount_t::print(std::ostream& _out, bool omit_commodity,
|
void amount_t::print(std::ostream& _out, bool omit_commodity,
|
||||||
bool full_precision) const
|
bool full_precision) const
|
||||||
{
|
{
|
||||||
|
assert(valid());
|
||||||
|
|
||||||
if (! quantity)
|
if (! quantity)
|
||||||
throw_(amount_error, "Cannot write out an uninitialized amount");
|
throw_(amount_error, "Cannot write out an uninitialized amount");
|
||||||
|
|
||||||
|
|
@ -1400,6 +1449,9 @@ void amount_t::write(std::ostream& out, bool optimized) const
|
||||||
bool amount_t::valid() const
|
bool amount_t::valid() const
|
||||||
{
|
{
|
||||||
if (quantity) {
|
if (quantity) {
|
||||||
|
if (! quantity->valid())
|
||||||
|
return false;
|
||||||
|
|
||||||
if (quantity->ref == 0) {
|
if (quantity->ref == 0) {
|
||||||
DEBUG("ledger.validate", "amount_t: quantity->ref == 0");
|
DEBUG("ledger.validate", "amount_t: quantity->ref == 0");
|
||||||
return false;
|
return false;
|
||||||
|
|
|
||||||
|
|
@ -351,7 +351,7 @@ public:
|
||||||
* valid() returns true if the balances within the balance pair are
|
* valid() returns true if the balances within the balance pair are
|
||||||
* valid.
|
* valid.
|
||||||
*/
|
*/
|
||||||
virtual bool valid() {
|
bool valid() const {
|
||||||
if (! balance_t::valid())
|
if (! balance_t::valid())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -827,16 +827,16 @@ void write_value(std::ostream& out, const value_t& val)
|
||||||
|
|
||||||
switch (val.type()) {
|
switch (val.type()) {
|
||||||
case value_t::BOOLEAN:
|
case value_t::BOOLEAN:
|
||||||
write_bool(out, const_cast<value_t&>(val).as_boolean_lval());
|
write_bool(out, val.as_boolean());
|
||||||
break;
|
break;
|
||||||
case value_t::INTEGER:
|
case value_t::INTEGER:
|
||||||
write_long(out, const_cast<value_t&>(val).as_long_lval());
|
write_long(out, val.as_long());
|
||||||
break;
|
break;
|
||||||
case value_t::DATETIME:
|
case value_t::DATETIME:
|
||||||
write_number(out, const_cast<value_t&>(val).as_datetime_lval());
|
write_number(out,val.as_datetime());
|
||||||
break;
|
break;
|
||||||
case value_t::AMOUNT:
|
case value_t::AMOUNT:
|
||||||
write_amount(out, const_cast<value_t&>(val).as_amount_lval());
|
write_amount(out, val.as_amount());
|
||||||
break;
|
break;
|
||||||
|
|
||||||
//case value_t::BALANCE:
|
//case value_t::BALANCE:
|
||||||
|
|
|
||||||
|
|
@ -67,7 +67,7 @@ entry_t * derive_new_entry(journal_t& journal,
|
||||||
|
|
||||||
value_t total = account_xdata(*acct).total;
|
value_t total = account_xdata(*acct).total;
|
||||||
if (total.is_type(value_t::AMOUNT))
|
if (total.is_type(value_t::AMOUNT))
|
||||||
xact->amount.set_commodity(total.as_amount_lval().commodity());
|
xact->amount.set_commodity(total.as_amount().commodity());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
36
format.cc
36
format.cc
|
|
@ -355,8 +355,8 @@ void format_t::format(std::ostream& out_str, const details_t& details) const
|
||||||
if (! calc)
|
if (! calc)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
value_t value;
|
value_t value;
|
||||||
balance_t * bal = NULL;
|
const balance_t * bal = NULL;
|
||||||
|
|
||||||
calc->compute(value, details);
|
calc->compute(value, details);
|
||||||
|
|
||||||
|
|
@ -378,54 +378,54 @@ void format_t::format(std::ostream& out_str, const details_t& details) const
|
||||||
|
|
||||||
switch (value.type()) {
|
switch (value.type()) {
|
||||||
case value_t::BOOLEAN:
|
case value_t::BOOLEAN:
|
||||||
out << (value.as_boolean_lval() ? "true" : "false");
|
out << (value.as_boolean() ? "true" : "false");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case value_t::INTEGER:
|
case value_t::INTEGER:
|
||||||
if (ansi_codes && elem->flags & ELEMENT_HIGHLIGHT) {
|
if (ansi_codes && elem->flags & ELEMENT_HIGHLIGHT) {
|
||||||
if (ansi_invert) {
|
if (ansi_invert) {
|
||||||
if (value.as_long_lval() > 0) {
|
if (value.as_long() > 0) {
|
||||||
mark_red(out, elem);
|
mark_red(out, elem);
|
||||||
highlighted = true;
|
highlighted = true;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (value.as_long_lval() < 0) {
|
if (value.as_long() < 0) {
|
||||||
mark_red(out, elem);
|
mark_red(out, elem);
|
||||||
highlighted = true;
|
highlighted = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
out << value.as_long_lval();
|
out << value.as_long();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case value_t::DATETIME:
|
case value_t::DATETIME:
|
||||||
out << value.as_datetime_lval();
|
out << value.as_datetime();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case value_t::AMOUNT:
|
case value_t::AMOUNT:
|
||||||
if (ansi_codes && elem->flags & ELEMENT_HIGHLIGHT) {
|
if (ansi_codes && elem->flags & ELEMENT_HIGHLIGHT) {
|
||||||
if (ansi_invert) {
|
if (ansi_invert) {
|
||||||
if (value.as_amount_lval().sign() > 0) {
|
if (value.as_amount().sign() > 0) {
|
||||||
mark_red(out, elem);
|
mark_red(out, elem);
|
||||||
highlighted = true;
|
highlighted = true;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (value.as_amount_lval().sign() < 0) {
|
if (value.as_amount().sign() < 0) {
|
||||||
mark_red(out, elem);
|
mark_red(out, elem);
|
||||||
highlighted = true;
|
highlighted = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
out << value.as_amount_lval();
|
out << value.as_amount();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case value_t::BALANCE:
|
case value_t::BALANCE:
|
||||||
bal = &(value.as_balance_lval());
|
bal = &(value.as_balance());
|
||||||
// fall through...
|
// fall through...
|
||||||
|
|
||||||
case value_t::BALANCE_PAIR:
|
case value_t::BALANCE_PAIR:
|
||||||
if (! bal)
|
if (! bal)
|
||||||
bal = &(value.as_balance_pair_lval().quantity());
|
bal = &(value.as_balance_pair().quantity());
|
||||||
|
|
||||||
if (ansi_codes && elem->flags & ELEMENT_HIGHLIGHT) {
|
if (ansi_codes && elem->flags & ELEMENT_HIGHLIGHT) {
|
||||||
if (ansi_invert) {
|
if (ansi_invert) {
|
||||||
|
|
@ -949,11 +949,11 @@ void format_equity::flush()
|
||||||
summary.data = &xdata;
|
summary.data = &xdata;
|
||||||
|
|
||||||
if (total.type() >= value_t::BALANCE) {
|
if (total.type() >= value_t::BALANCE) {
|
||||||
balance_t * bal;
|
const balance_t * bal;
|
||||||
if (total.is_type(value_t::BALANCE))
|
if (total.is_type(value_t::BALANCE))
|
||||||
bal = &(total.as_balance_lval());
|
bal = &(total.as_balance());
|
||||||
else if (total.is_type(value_t::BALANCE_PAIR))
|
else if (total.is_type(value_t::BALANCE_PAIR))
|
||||||
bal = &(total.as_balance_pair_lval().quantity());
|
bal = &(total.as_balance_pair().quantity());
|
||||||
else
|
else
|
||||||
assert(false);
|
assert(false);
|
||||||
|
|
||||||
|
|
@ -977,11 +977,11 @@ void format_equity::operator()(account_t& account)
|
||||||
value_t val = account_xdata_(account).value;
|
value_t val = account_xdata_(account).value;
|
||||||
|
|
||||||
if (val.type() >= value_t::BALANCE) {
|
if (val.type() >= value_t::BALANCE) {
|
||||||
balance_t * bal;
|
const balance_t * bal;
|
||||||
if (val.is_type(value_t::BALANCE))
|
if (val.is_type(value_t::BALANCE))
|
||||||
bal = &(val.as_balance_lval());
|
bal = &(val.as_balance());
|
||||||
else if (val.is_type(value_t::BALANCE_PAIR))
|
else if (val.is_type(value_t::BALANCE_PAIR))
|
||||||
bal = &(val.as_balance_pair_lval().quantity());
|
bal = &(val.as_balance_pair().quantity());
|
||||||
else
|
else
|
||||||
assert(false);
|
assert(false);
|
||||||
|
|
||||||
|
|
|
||||||
18
journal.cc
18
journal.cc
|
|
@ -128,7 +128,7 @@ bool entry_base_t::finalize()
|
||||||
|
|
||||||
for (transactions_list::const_iterator x = transactions.begin();
|
for (transactions_list::const_iterator x = transactions.begin();
|
||||||
x != transactions.end();
|
x != transactions.end();
|
||||||
x++)
|
x++) {
|
||||||
if (! (*x)->has_flags(TRANSACTION_VIRTUAL) ||
|
if (! (*x)->has_flags(TRANSACTION_VIRTUAL) ||
|
||||||
(*x)->has_flags(TRANSACTION_BALANCE)) {
|
(*x)->has_flags(TRANSACTION_BALANCE)) {
|
||||||
amount_t& p((*x)->cost ? *(*x)->cost : (*x)->amount);
|
amount_t& p((*x)->cost ? *(*x)->cost : (*x)->amount);
|
||||||
|
|
@ -154,6 +154,9 @@ bool entry_base_t::finalize()
|
||||||
saw_null = true;
|
saw_null = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(balance.valid());
|
||||||
|
|
||||||
// If it's a null entry, then let the user have their fun
|
// If it's a null entry, then let the user have their fun
|
||||||
if (no_amounts)
|
if (no_amounts)
|
||||||
|
|
@ -177,21 +180,24 @@ bool entry_base_t::finalize()
|
||||||
// the balance. This is done for the last eligible commodity.
|
// the balance. This is done for the last eligible commodity.
|
||||||
|
|
||||||
if (! saw_null && balance && balance.is_balance()) {
|
if (! saw_null && balance && balance.is_balance()) {
|
||||||
balance_t& bal(balance.as_balance_lval());
|
const balance_t& bal(balance.as_balance());
|
||||||
if (bal.amounts.size() == 2) {
|
if (bal.amounts.size() == 2) {
|
||||||
transactions_list::const_iterator x = transactions.begin();
|
transactions_list::const_iterator x = transactions.begin();
|
||||||
assert((*x)->amount);
|
assert(! (*x)->amount.is_null());
|
||||||
commodity_t& this_comm = (*x)->amount.commodity();
|
commodity_t& this_comm = (*x)->amount.commodity();
|
||||||
|
|
||||||
balance_t::amounts_map::const_iterator this_bal =
|
balance_t::amounts_map::const_iterator this_bal =
|
||||||
bal.amounts.find(&this_comm);
|
bal.amounts.find(&this_comm);
|
||||||
|
assert(this_bal != bal.amounts.end());
|
||||||
|
|
||||||
balance_t::amounts_map::const_iterator other_bal =
|
balance_t::amounts_map::const_iterator other_bal =
|
||||||
bal.amounts.begin();
|
bal.amounts.begin();
|
||||||
|
|
||||||
if (this_bal == other_bal)
|
if (this_bal == other_bal)
|
||||||
other_bal++;
|
other_bal++;
|
||||||
|
|
||||||
amount_t per_unit_cost =
|
amount_t per_unit_cost =
|
||||||
amount_t((*other_bal).second / (*this_bal).second.number()).unround();
|
((*other_bal).second / (*this_bal).second.number()).unround();
|
||||||
|
|
||||||
for (; x != transactions.end(); x++) {
|
for (; x != transactions.end(); x++) {
|
||||||
if ((*x)->cost || (*x)->has_flags(TRANSACTION_VIRTUAL) ||
|
if ((*x)->cost || (*x)->has_flags(TRANSACTION_VIRTUAL) ||
|
||||||
|
|
@ -241,12 +247,12 @@ bool entry_base_t::finalize()
|
||||||
const balance_t * bal = NULL;
|
const balance_t * bal = NULL;
|
||||||
switch (balance.type()) {
|
switch (balance.type()) {
|
||||||
case value_t::BALANCE_PAIR:
|
case value_t::BALANCE_PAIR:
|
||||||
bal = &balance.as_balance_pair_lval().quantity();
|
bal = &balance.as_balance_pair().quantity();
|
||||||
// fall through...
|
// fall through...
|
||||||
|
|
||||||
case value_t::BALANCE:
|
case value_t::BALANCE:
|
||||||
if (! bal)
|
if (! bal)
|
||||||
bal = &balance.as_balance_lval();
|
bal = &balance.as_balance();
|
||||||
|
|
||||||
if (bal->amounts.size() < 2) {
|
if (bal->amounts.size() < 2) {
|
||||||
balance.cast(value_t::AMOUNT);
|
balance.cast(value_t::AMOUNT);
|
||||||
|
|
|
||||||
164
parsexp.cc
164
parsexp.cc
|
|
@ -155,10 +155,17 @@ void parser_t::token_t::next(std::istream& in, const flags_t flags)
|
||||||
in.get(c);
|
in.get(c);
|
||||||
kind = AT_SYM;
|
kind = AT_SYM;
|
||||||
break;
|
break;
|
||||||
|
#if 0
|
||||||
case '$':
|
case '$':
|
||||||
in.get(c);
|
in.get(c);
|
||||||
kind = DOLLAR;
|
kind = DOLLAR;
|
||||||
break;
|
break;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
case '&':
|
||||||
|
in.get(c);
|
||||||
|
kind = KW_AND;
|
||||||
|
break;
|
||||||
|
|
||||||
case '(':
|
case '(':
|
||||||
in.get(c);
|
in.get(c);
|
||||||
|
|
@ -171,7 +178,7 @@ void parser_t::token_t::next(std::istream& in, const flags_t flags)
|
||||||
|
|
||||||
case '[': {
|
case '[': {
|
||||||
in.get(c);
|
in.get(c);
|
||||||
if (flags & EXPR_PARSE_ALLOW_DATE) {
|
if (! (flags & EXPR_PARSE_NO_DATES)) {
|
||||||
char buf[256];
|
char buf[256];
|
||||||
READ_INTO_(in, buf, 255, c, length, c != ']');
|
READ_INTO_(in, buf, 255, c, length, c != ']');
|
||||||
if (c != ']')
|
if (c != ']')
|
||||||
|
|
@ -193,6 +200,7 @@ void parser_t::token_t::next(std::istream& in, const flags_t flags)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
case '\'':
|
case '\'':
|
||||||
case '"': {
|
case '"': {
|
||||||
char delim;
|
char delim;
|
||||||
|
|
@ -249,10 +257,68 @@ void parser_t::token_t::next(std::istream& in, const flags_t flags)
|
||||||
kind = STAR;
|
kind = STAR;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
#if 0
|
||||||
case '/':
|
case '/':
|
||||||
in.get(c);
|
in.get(c);
|
||||||
kind = SLASH;
|
kind = SLASH;
|
||||||
break;
|
break;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
case 'c':
|
||||||
|
case 'C':
|
||||||
|
case 'p':
|
||||||
|
case 'w':
|
||||||
|
case 'W':
|
||||||
|
case 'e':
|
||||||
|
case '/': {
|
||||||
|
bool code_mask = c == 'c';
|
||||||
|
bool commodity_mask = c == 'C';
|
||||||
|
bool payee_mask = c == 'p';
|
||||||
|
bool note_mask = c == 'e';
|
||||||
|
bool short_account_mask = c == 'w';
|
||||||
|
|
||||||
|
in.get(c);
|
||||||
|
if (c == '/') {
|
||||||
|
c = peek_next_nonws(in);
|
||||||
|
if (c == '/') {
|
||||||
|
in.get(c);
|
||||||
|
c = in.peek();
|
||||||
|
if (c == '/') {
|
||||||
|
in.get(c);
|
||||||
|
c = in.peek();
|
||||||
|
short_account_mask = true;
|
||||||
|
} else {
|
||||||
|
payee_mask = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
in.get(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read in the regexp
|
||||||
|
char buf[256];
|
||||||
|
READ_INTO_(in, buf, 255, c, length, c != '/');
|
||||||
|
if (c != '/')
|
||||||
|
unexpected(c, '/');
|
||||||
|
in.get(c);
|
||||||
|
length++;
|
||||||
|
|
||||||
|
if (short_account_mask)
|
||||||
|
kind = SHORT_ACCOUNT_MASK;
|
||||||
|
else if (code_mask)
|
||||||
|
kind = CODE_MASK;
|
||||||
|
else if (commodity_mask)
|
||||||
|
kind = COMMODITY_MASK;
|
||||||
|
else if (payee_mask)
|
||||||
|
kind = PAYEE_MASK;
|
||||||
|
else if (note_mask)
|
||||||
|
kind = NOTE_MASK;
|
||||||
|
else
|
||||||
|
kind = ACCOUNT_MASK;
|
||||||
|
|
||||||
|
value.set_string(buf);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case '=':
|
case '=':
|
||||||
in.get(c);
|
in.get(c);
|
||||||
|
|
@ -336,7 +402,7 @@ void parser_t::token_t::next(std::istream& in, const flags_t flags)
|
||||||
kind = VALUE;
|
kind = VALUE;
|
||||||
value = temp;
|
value = temp;
|
||||||
}
|
}
|
||||||
catch (amount_error& err) {
|
catch (const amount_error& err) {
|
||||||
// If the amount had no commodity, it must be an unambiguous
|
// If the amount had no commodity, it must be an unambiguous
|
||||||
// variable reference
|
// variable reference
|
||||||
|
|
||||||
|
|
@ -407,6 +473,31 @@ parser_t::parse_value_term(std::istream& in, scope_t& scope, const flags_t tflag
|
||||||
node->set_value(tok.value);
|
node->set_value(tok.value);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case token_t::SHORT_ACCOUNT_MASK:
|
||||||
|
node = new op_t(op_t::F_SHORT_ACCOUNT_MASK);
|
||||||
|
node->set_mask(tok.value.as_string());
|
||||||
|
break;
|
||||||
|
case token_t::CODE_MASK:
|
||||||
|
node = new op_t(op_t::F_CODE_MASK);
|
||||||
|
node->set_mask(tok.value.as_string());
|
||||||
|
break;
|
||||||
|
case token_t::COMMODITY_MASK:
|
||||||
|
node = new op_t(op_t::F_COMMODITY_MASK);
|
||||||
|
node->set_mask(tok.value.as_string());
|
||||||
|
break;
|
||||||
|
case token_t::PAYEE_MASK:
|
||||||
|
node = new op_t(op_t::F_PAYEE_MASK);
|
||||||
|
node->set_mask(tok.value.as_string());
|
||||||
|
break;
|
||||||
|
case token_t::NOTE_MASK:
|
||||||
|
node = new op_t(op_t::F_NOTE_MASK);
|
||||||
|
node->set_mask(tok.value.as_string());
|
||||||
|
break;
|
||||||
|
case token_t::ACCOUNT_MASK:
|
||||||
|
node = new op_t(op_t::F_ACCOUNT_MASK);
|
||||||
|
node->set_mask(tok.value.as_string());
|
||||||
|
break;
|
||||||
|
|
||||||
case token_t::IDENT: {
|
case token_t::IDENT: {
|
||||||
#if 0
|
#if 0
|
||||||
#ifdef USE_BOOST_PYTHON
|
#ifdef USE_BOOST_PYTHON
|
||||||
|
|
@ -473,12 +564,12 @@ parser_t::parse_value_term(std::istream& in, scope_t& scope, const flags_t tflag
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
case token_t::AT_SYM: {
|
case token_t::AT_SYM: {
|
||||||
tok = next_token(in, tflags);
|
tok = next_token(in, tflags);
|
||||||
if (tok.kind != token_t::IDENT)
|
if (tok.kind != token_t::IDENT)
|
||||||
throw_(parse_error, "@ symbol must be followed by attribute name");
|
throw_(parse_error, "@ symbol must be followed by attribute name");
|
||||||
|
|
||||||
#if 0
|
|
||||||
string ident = tok.value.as_string();
|
string ident = tok.value.as_string();
|
||||||
if (optional<node_t::nameid_t> id = document_t::lookup_builtin_id(ident)) {
|
if (optional<node_t::nameid_t> id = document_t::lookup_builtin_id(ident)) {
|
||||||
node = new op_t(op_t::ATTR_ID);
|
node = new op_t(op_t::ATTR_ID);
|
||||||
|
|
@ -488,11 +579,9 @@ parser_t::parse_value_term(std::istream& in, scope_t& scope, const flags_t tflag
|
||||||
node = new op_t(op_t::ATTR_NAME);
|
node = new op_t(op_t::ATTR_NAME);
|
||||||
node->set_string(ident);
|
node->set_string(ident);
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 0
|
|
||||||
case token_t::DOLLAR:
|
case token_t::DOLLAR:
|
||||||
tok = next_token(in, tflags);
|
tok = next_token(in, tflags);
|
||||||
if (tok.kind != token_t::IDENT)
|
if (tok.kind != token_t::IDENT)
|
||||||
|
|
@ -546,7 +635,8 @@ parser_t::parse_value_term(std::istream& in, scope_t& scope, const flags_t tflag
|
||||||
}
|
}
|
||||||
|
|
||||||
ptr_op_t
|
ptr_op_t
|
||||||
parser_t::parse_unary_expr(std::istream& in, scope_t& scope, const flags_t tflags) const
|
parser_t::parse_unary_expr(std::istream& in, scope_t& scope,
|
||||||
|
const flags_t tflags) const
|
||||||
{
|
{
|
||||||
ptr_op_t node;
|
ptr_op_t node;
|
||||||
|
|
||||||
|
|
@ -561,7 +651,7 @@ parser_t::parse_unary_expr(std::istream& in, scope_t& scope, const flags_t tflag
|
||||||
|
|
||||||
// A very quick optimization
|
// A very quick optimization
|
||||||
if (term->kind == op_t::VALUE) {
|
if (term->kind == op_t::VALUE) {
|
||||||
term->as_value().in_place_negate();
|
term->as_value_lval().in_place_negate();
|
||||||
node = term;
|
node = term;
|
||||||
} else {
|
} else {
|
||||||
node = new op_t(op_t::O_NOT);
|
node = new op_t(op_t::O_NOT);
|
||||||
|
|
@ -578,7 +668,7 @@ parser_t::parse_unary_expr(std::istream& in, scope_t& scope, const flags_t tflag
|
||||||
|
|
||||||
// A very quick optimization
|
// A very quick optimization
|
||||||
if (term->kind == op_t::VALUE) {
|
if (term->kind == op_t::VALUE) {
|
||||||
term->as_value().in_place_negate();
|
term->as_value_lval().in_place_negate();
|
||||||
node = term;
|
node = term;
|
||||||
} else {
|
} else {
|
||||||
node = new op_t(op_t::O_NEG);
|
node = new op_t(op_t::O_NEG);
|
||||||
|
|
@ -1406,64 +1496,6 @@ ptr_op_t parse_value_term(std::istream& in, scope_t * scope,
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// Other
|
// Other
|
||||||
#if 0
|
|
||||||
case 'c':
|
|
||||||
case 'C':
|
|
||||||
case 'p':
|
|
||||||
case 'w':
|
|
||||||
case 'W':
|
|
||||||
case 'e':
|
|
||||||
case '/': {
|
|
||||||
bool code_mask = c == 'c';
|
|
||||||
bool commodity_mask = c == 'C';
|
|
||||||
bool payee_mask = c == 'p';
|
|
||||||
bool note_mask = c == 'e';
|
|
||||||
bool short_account_mask = c == 'w';
|
|
||||||
|
|
||||||
if (c == '/') {
|
|
||||||
c = peek_next_nonws(in);
|
|
||||||
if (c == '/') {
|
|
||||||
in.get(c);
|
|
||||||
c = in.peek();
|
|
||||||
if (c == '/') {
|
|
||||||
in.get(c);
|
|
||||||
c = in.peek();
|
|
||||||
short_account_mask = true;
|
|
||||||
} else {
|
|
||||||
payee_mask = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
in.get(c);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Read in the regexp
|
|
||||||
READ_INTO(in, buf, 255, c, c != '/');
|
|
||||||
if (c != '/')
|
|
||||||
unexpected(c, '/');
|
|
||||||
|
|
||||||
op_t::kind_t kind;
|
|
||||||
|
|
||||||
if (short_account_mask)
|
|
||||||
kind = op_t::F_SHORT_ACCOUNT_MASK;
|
|
||||||
else if (code_mask)
|
|
||||||
kind = op_t::F_CODE_MASK;
|
|
||||||
else if (commodity_mask)
|
|
||||||
kind = op_t::F_COMMODITY_MASK;
|
|
||||||
else if (payee_mask)
|
|
||||||
kind = op_t::F_PAYEE_MASK;
|
|
||||||
else if (note_mask)
|
|
||||||
kind = op_t::F_NOTE_MASK;
|
|
||||||
else
|
|
||||||
kind = op_t::F_ACCOUNT_MASK;
|
|
||||||
|
|
||||||
in.get(c);
|
|
||||||
node.reset(new op_t(kind));
|
|
||||||
node->mask = new mask_t(buf);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
case '{': {
|
case '{': {
|
||||||
amount_t temp;
|
amount_t temp;
|
||||||
temp.parse(in, AMOUNT_PARSE_NO_MIGRATE);
|
temp.parse(in, AMOUNT_PARSE_NO_MIGRATE);
|
||||||
|
|
|
||||||
20
parsexp.h
20
parsexp.h
|
|
@ -46,7 +46,7 @@ class parser_t
|
||||||
#define EXPR_PARSE_RELAXED 0x02
|
#define EXPR_PARSE_RELAXED 0x02
|
||||||
#define EXPR_PARSE_NO_MIGRATE 0x04
|
#define EXPR_PARSE_NO_MIGRATE 0x04
|
||||||
#define EXPR_PARSE_NO_REDUCE 0x08
|
#define EXPR_PARSE_NO_REDUCE 0x08
|
||||||
#define EXPR_PARSE_ALLOW_DATE 0x10
|
#define EXPR_PARSE_NO_DATES 0x10
|
||||||
|
|
||||||
public:
|
public:
|
||||||
typedef uint_least8_t flags_t;
|
typedef uint_least8_t flags_t;
|
||||||
|
|
@ -57,6 +57,13 @@ private:
|
||||||
enum kind_t {
|
enum kind_t {
|
||||||
VALUE, // any kind of literal value
|
VALUE, // any kind of literal value
|
||||||
|
|
||||||
|
SHORT_ACCOUNT_MASK,
|
||||||
|
CODE_MASK,
|
||||||
|
COMMODITY_MASK,
|
||||||
|
PAYEE_MASK,
|
||||||
|
NOTE_MASK,
|
||||||
|
ACCOUNT_MASK,
|
||||||
|
|
||||||
IDENT, // [A-Za-z_][-A-Za-z0-9_:]*
|
IDENT, // [A-Za-z_][-A-Za-z0-9_:]*
|
||||||
DOLLAR, // $
|
DOLLAR, // $
|
||||||
AT_SYM, // @
|
AT_SYM, // @
|
||||||
|
|
@ -98,7 +105,7 @@ private:
|
||||||
UNKNOWN
|
UNKNOWN
|
||||||
} kind;
|
} kind;
|
||||||
|
|
||||||
char symbol[3];
|
char symbol[3];
|
||||||
value_t value;
|
value_t value;
|
||||||
std::size_t length;
|
std::size_t length;
|
||||||
|
|
||||||
|
|
@ -225,9 +232,8 @@ public:
|
||||||
return parse_expr(in, empty_string, *global_scope, flags);
|
return parse_expr(in, empty_string, *global_scope, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
value_expr& parse(std::istream& in,
|
value_expr& parse(std::istream& in, scope_t& scope,
|
||||||
const flags_t flags = EXPR_PARSE_RELAXED,
|
const flags_t flags = EXPR_PARSE_RELAXED)
|
||||||
scope_t& scope)
|
|
||||||
{
|
{
|
||||||
return parse_expr(in, empty_string, scope, flags);
|
return parse_expr(in, empty_string, scope, flags);
|
||||||
}
|
}
|
||||||
|
|
@ -238,8 +244,8 @@ public:
|
||||||
return parse_expr(stream, str, *global_scope, flags);
|
return parse_expr(stream, str, *global_scope, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
value_expr& parse(string& str, const flags_t flags = EXPR_PARSE_RELAXED,
|
value_expr& parse(string& str, scope_t& scope,
|
||||||
scope_t& scope)
|
const flags_t flags = EXPR_PARSE_RELAXED)
|
||||||
{
|
{
|
||||||
std::istringstream stream(str);
|
std::istringstream stream(str);
|
||||||
return parse_expr(stream, str, scope, flags);
|
return parse_expr(stream, str, scope, flags);
|
||||||
|
|
|
||||||
|
|
@ -64,8 +64,8 @@ void reconcile_transactions::flush()
|
||||||
cleared_balance.cast(value_t::AMOUNT);
|
cleared_balance.cast(value_t::AMOUNT);
|
||||||
balance.cast(value_t::AMOUNT);
|
balance.cast(value_t::AMOUNT);
|
||||||
|
|
||||||
commodity_t& cb_comm = cleared_balance.as_amount_lval().commodity();
|
commodity_t& cb_comm = cleared_balance.as_amount().commodity();
|
||||||
commodity_t& b_comm = balance.as_amount_lval().commodity();
|
commodity_t& b_comm = balance.as_amount().commodity();
|
||||||
|
|
||||||
balance -= cleared_balance;
|
balance -= cleared_balance;
|
||||||
if (balance.type() >= value_t::BALANCE)
|
if (balance.type() >= value_t::BALANCE)
|
||||||
|
|
@ -76,7 +76,7 @@ void reconcile_transactions::flush()
|
||||||
// then assume an exact match and return the results right away.
|
// then assume an exact match and return the results right away.
|
||||||
amount_t& to_reconcile(balance.as_amount_lval());
|
amount_t& to_reconcile(balance.as_amount_lval());
|
||||||
pending_balance.cast(value_t::AMOUNT);
|
pending_balance.cast(value_t::AMOUNT);
|
||||||
if (to_reconcile == pending_balance.as_amount_lval() ||
|
if (to_reconcile == pending_balance.as_amount() ||
|
||||||
search_for_balance(to_reconcile, &first, first)) {
|
search_for_balance(to_reconcile, &first, first)) {
|
||||||
push_to_handler(first);
|
push_to_handler(first);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
24
textual.cc
24
textual.cc
|
|
@ -186,6 +186,8 @@ transaction_t * parse_transaction(char * line, account_t * account,
|
||||||
"Reduced amount is " << xact->amount);
|
"Reduced amount is " << xact->amount);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// jww (2008-07-24): I don't think this is right, since amount_expr is
|
||||||
|
// always NULL right now
|
||||||
if (xact->amount_expr) {
|
if (xact->amount_expr) {
|
||||||
unsigned long end = (long)in.tellg();
|
unsigned long end = (long)in.tellg();
|
||||||
xact->amount_expr.expr_str = string(line, beg, end - beg);
|
xact->amount_expr.expr_str = string(line, beg, end - beg);
|
||||||
|
|
@ -227,15 +229,18 @@ transaction_t * parse_transaction(char * line, account_t * account,
|
||||||
EXPR_PARSE_NO_MIGRATE))
|
EXPR_PARSE_NO_MIGRATE))
|
||||||
throw new parse_error
|
throw new parse_error
|
||||||
("A transaction's cost must evaluate to a constant value");
|
("A transaction's cost must evaluate to a constant value");
|
||||||
|
assert(xact->cost->valid());
|
||||||
|
|
||||||
unsigned long end = (long)in.tellg();
|
// jww (2008-07-24): I don't think this is right...
|
||||||
|
if (xact->cost_expr) {
|
||||||
if (per_unit)
|
unsigned long end = (long)in.tellg();
|
||||||
xact->cost_expr = (string("@") +
|
if (per_unit)
|
||||||
string(line, beg, end - beg));
|
xact->cost_expr->expr_str = (string("@") +
|
||||||
else
|
string(line, beg, end - beg));
|
||||||
xact->cost_expr = (string("@@") +
|
else
|
||||||
string(line, beg, end - beg));
|
xact->cost_expr->expr_str = (string("@@") +
|
||||||
|
string(line, beg, end - beg));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch (error * err) {
|
catch (error * err) {
|
||||||
err_desc = "While parsing transaction cost:";
|
err_desc = "While parsing transaction cost:";
|
||||||
|
|
@ -554,6 +559,7 @@ static void clock_out_from_timelog(std::list<time_entry_t>& time_entries,
|
||||||
std::sprintf(buf, "%lds", long((curr->_date - event.checkin).seconds()));
|
std::sprintf(buf, "%lds", long((curr->_date - event.checkin).seconds()));
|
||||||
amount_t amt;
|
amount_t amt;
|
||||||
amt.parse(buf);
|
amt.parse(buf);
|
||||||
|
assert(amt.valid());
|
||||||
|
|
||||||
transaction_t * xact
|
transaction_t * xact
|
||||||
= new transaction_t(event.account, amt, TRANSACTION_VIRTUAL);
|
= new transaction_t(event.account, amt, TRANSACTION_VIRTUAL);
|
||||||
|
|
@ -666,6 +672,7 @@ unsigned int textual_parser_t::parse(std::istream& in,
|
||||||
|
|
||||||
case 'D': { // a default commodity for "entry"
|
case 'D': { // a default commodity for "entry"
|
||||||
amount_t amt(skip_ws(line + 1));
|
amount_t amt(skip_ws(line + 1));
|
||||||
|
assert(amt.valid());
|
||||||
amount_t::current_pool->default_commodity = &amt.commodity();
|
amount_t::current_pool->default_commodity = &amt.commodity();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -706,6 +713,7 @@ unsigned int textual_parser_t::parse(std::istream& in,
|
||||||
string symbol;
|
string symbol;
|
||||||
parse_symbol(symbol_and_price, symbol);
|
parse_symbol(symbol_and_price, symbol);
|
||||||
amount_t price(symbol_and_price);
|
amount_t price(symbol_and_price);
|
||||||
|
assert(price.valid());
|
||||||
|
|
||||||
if (commodity_t * commodity =
|
if (commodity_t * commodity =
|
||||||
amount_t::current_pool->find_or_create(symbol))
|
amount_t::current_pool->find_or_create(symbol))
|
||||||
|
|
|
||||||
46
valexpr.cc
46
valexpr.cc
|
|
@ -59,8 +59,10 @@ bool compute_amount(ptr_op_t expr, amount_t& amt,
|
||||||
|
|
||||||
// Most of the time when computing the amount of a transaction this cast
|
// Most of the time when computing the amount of a transaction this cast
|
||||||
// will do nothing at all.
|
// will do nothing at all.
|
||||||
|
assert(result.valid());
|
||||||
result.in_place_cast(value_t::AMOUNT);
|
result.in_place_cast(value_t::AMOUNT);
|
||||||
amt = result.as_amount();
|
amt = result.as_amount();
|
||||||
|
assert(amt.valid());
|
||||||
}
|
}
|
||||||
catch (error * err) {
|
catch (error * err) {
|
||||||
if (err->context.empty() ||
|
if (err->context.empty() ||
|
||||||
|
|
@ -134,7 +136,7 @@ namespace {
|
||||||
} else {
|
} else {
|
||||||
temp.reset(new op_t(op_t::VALUE));
|
temp.reset(new op_t(op_t::VALUE));
|
||||||
temp->set_value(value_t());
|
temp->set_value(value_t());
|
||||||
expr->compute(temp->as_value(), details, context);
|
expr->compute(temp->as_value_lval(), details, context);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
temp.reset(new op_t(op_t::O_COMMA));
|
temp.reset(new op_t(op_t::O_COMMA));
|
||||||
|
|
@ -417,7 +419,7 @@ void op_t::compute(value_t& result, const details_t& details,
|
||||||
long arg_index = 0;
|
long arg_index = 0;
|
||||||
ptr_op_t expr = find_leaf(context, 0, arg_index);
|
ptr_op_t expr = find_leaf(context, 0, arg_index);
|
||||||
expr->compute(result, details, context);
|
expr->compute(result, details, context);
|
||||||
result = result.as_datetime_lval();
|
result = result.as_datetime();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -425,7 +427,7 @@ void op_t::compute(value_t& result, const details_t& details,
|
||||||
long arg_index = 0;
|
long arg_index = 0;
|
||||||
ptr_op_t expr = find_leaf(context, 0, arg_index);
|
ptr_op_t expr = find_leaf(context, 0, arg_index);
|
||||||
expr->compute(result, details, context);
|
expr->compute(result, details, context);
|
||||||
result = result.as_datetime_lval();
|
result = result.as_datetime();
|
||||||
if (! result)
|
if (! result)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
@ -455,7 +457,7 @@ void op_t::compute(value_t& result, const details_t& details,
|
||||||
throw new compute_error("Invalid date passed to year|month|day(date)",
|
throw new compute_error("Invalid date passed to year|month|day(date)",
|
||||||
new valexpr_context(expr));
|
new valexpr_context(expr));
|
||||||
|
|
||||||
datetime_t& moment(result.as_datetime_lval());
|
const datetime_t& moment(result.as_datetime());
|
||||||
switch (kind) {
|
switch (kind) {
|
||||||
case F_YEAR:
|
case F_YEAR:
|
||||||
result = (long)moment.date().year();
|
result = (long)moment.date().year();
|
||||||
|
|
@ -519,7 +521,7 @@ void op_t::compute(value_t& result, const details_t& details,
|
||||||
throw new compute_error("Argument to commodity() must be a commoditized amount",
|
throw new compute_error("Argument to commodity() must be a commoditized amount",
|
||||||
new valexpr_context(expr));
|
new valexpr_context(expr));
|
||||||
amount_t temp("1");
|
amount_t temp("1");
|
||||||
temp.set_commodity(result.as_amount_lval().commodity());
|
temp.set_commodity(result.as_amount().commodity());
|
||||||
result = temp;
|
result = temp;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -538,7 +540,7 @@ void op_t::compute(value_t& result, const details_t& details,
|
||||||
("Second argument to set_commodity() must be a commoditized amount",
|
("Second argument to set_commodity() must be a commoditized amount",
|
||||||
new valexpr_context(expr));
|
new valexpr_context(expr));
|
||||||
amount_t one("1");
|
amount_t one("1");
|
||||||
one.set_commodity(result.as_amount_lval().commodity());
|
one.set_commodity(result.as_amount().commodity());
|
||||||
result = one;
|
result = one;
|
||||||
|
|
||||||
result *= temp;
|
result *= temp;
|
||||||
|
|
@ -550,15 +552,15 @@ void op_t::compute(value_t& result, const details_t& details,
|
||||||
ptr_op_t expr = find_leaf(context, 0, arg_index);
|
ptr_op_t expr = find_leaf(context, 0, arg_index);
|
||||||
expr->compute(result, details, context);
|
expr->compute(result, details, context);
|
||||||
|
|
||||||
balance_t * bal = NULL;
|
const balance_t * bal = NULL;
|
||||||
switch (result.type()) {
|
switch (result.type()) {
|
||||||
case value_t::BALANCE_PAIR:
|
case value_t::BALANCE_PAIR:
|
||||||
bal = &(result.as_balance_pair_lval().quantity());
|
bal = &(result.as_balance_pair().quantity());
|
||||||
// fall through...
|
// fall through...
|
||||||
|
|
||||||
case value_t::BALANCE:
|
case value_t::BALANCE:
|
||||||
if (! bal)
|
if (! bal)
|
||||||
bal = &(result.as_balance_lval());
|
bal = &result.as_balance();
|
||||||
|
|
||||||
if (bal->amounts.size() < 2) {
|
if (bal->amounts.size() < 2) {
|
||||||
result.cast(value_t::AMOUNT);
|
result.cast(value_t::AMOUNT);
|
||||||
|
|
@ -586,55 +588,47 @@ void op_t::compute(value_t& result, const details_t& details,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 0
|
|
||||||
case F_CODE_MASK:
|
case F_CODE_MASK:
|
||||||
assert(mask);
|
if (details.entry && details.entry->code)
|
||||||
if (details.entry)
|
result = as_mask().match(*details.entry->code);
|
||||||
result = mask->match(details.entry->code);
|
|
||||||
else
|
else
|
||||||
result = false;
|
result = false;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case F_PAYEE_MASK:
|
case F_PAYEE_MASK:
|
||||||
assert(mask);
|
|
||||||
if (details.entry)
|
if (details.entry)
|
||||||
result = mask->match(details.entry->payee);
|
result = as_mask().match(details.entry->payee);
|
||||||
else
|
else
|
||||||
result = false;
|
result = false;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case F_NOTE_MASK:
|
case F_NOTE_MASK:
|
||||||
assert(mask);
|
if (details.xact && details.xact->note)
|
||||||
if (details.xact)
|
result = as_mask().match(*details.xact->note);
|
||||||
result = mask->match(details.xact->note);
|
|
||||||
else
|
else
|
||||||
result = false;
|
result = false;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case F_ACCOUNT_MASK:
|
case F_ACCOUNT_MASK:
|
||||||
assert(mask);
|
|
||||||
if (details.account)
|
if (details.account)
|
||||||
result = mask->match(details.account->fullname());
|
result = as_mask().match(details.account->fullname());
|
||||||
else
|
else
|
||||||
result = false;
|
result = false;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case F_SHORT_ACCOUNT_MASK:
|
case F_SHORT_ACCOUNT_MASK:
|
||||||
assert(mask);
|
|
||||||
if (details.account)
|
if (details.account)
|
||||||
result = mask->match(details.account->name);
|
result = as_mask().match(details.account->name);
|
||||||
else
|
else
|
||||||
result = false;
|
result = false;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case F_COMMODITY_MASK:
|
case F_COMMODITY_MASK:
|
||||||
assert(mask);
|
|
||||||
if (details.xact)
|
if (details.xact)
|
||||||
result = mask->match(details.xact->amount.commodity().base_symbol());
|
result = as_mask().match(details.xact->amount.commodity().base_symbol());
|
||||||
else
|
else
|
||||||
result = false;
|
result = false;
|
||||||
break;
|
break;
|
||||||
#endif
|
|
||||||
|
|
||||||
case O_ARG: {
|
case O_ARG: {
|
||||||
long arg_index = 0;
|
long arg_index = 0;
|
||||||
|
|
@ -686,7 +680,7 @@ void op_t::compute(value_t& result, const details_t& details,
|
||||||
throw new compute_error("Invalid date passed to P(value,date)",
|
throw new compute_error("Invalid date passed to P(value,date)",
|
||||||
new valexpr_context(expr));
|
new valexpr_context(expr));
|
||||||
|
|
||||||
result = result.value(moment.as_datetime_lval());
|
result = result.value(moment.as_datetime());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
58
valexpr.h
58
valexpr.h
|
|
@ -340,6 +340,7 @@ struct op_t : public noncopyable
|
||||||
enum kind_t {
|
enum kind_t {
|
||||||
// Constants
|
// Constants
|
||||||
VALUE,
|
VALUE,
|
||||||
|
MASK,
|
||||||
ARG_INDEX,
|
ARG_INDEX,
|
||||||
|
|
||||||
CONSTANTS,
|
CONSTANTS,
|
||||||
|
|
@ -385,12 +386,15 @@ struct op_t : public noncopyable
|
||||||
F_YEAR,
|
F_YEAR,
|
||||||
F_MONTH,
|
F_MONTH,
|
||||||
F_DAY,
|
F_DAY,
|
||||||
|
|
||||||
|
BEGIN_MASKS,
|
||||||
F_CODE_MASK,
|
F_CODE_MASK,
|
||||||
F_PAYEE_MASK,
|
F_PAYEE_MASK,
|
||||||
F_NOTE_MASK,
|
F_NOTE_MASK,
|
||||||
F_ACCOUNT_MASK,
|
F_ACCOUNT_MASK,
|
||||||
F_SHORT_ACCOUNT_MASK,
|
F_SHORT_ACCOUNT_MASK,
|
||||||
F_COMMODITY_MASK,
|
F_COMMODITY_MASK,
|
||||||
|
END_MASKS,
|
||||||
|
|
||||||
TERMINALS,
|
TERMINALS,
|
||||||
|
|
||||||
|
|
@ -449,12 +453,12 @@ struct op_t : public noncopyable
|
||||||
bool is_long() const {
|
bool is_long() const {
|
||||||
return data.type() == typeid(unsigned int);
|
return data.type() == typeid(unsigned int);
|
||||||
}
|
}
|
||||||
unsigned int& as_long() {
|
unsigned int& as_long_lval() {
|
||||||
assert(kind == ARG_INDEX || kind == O_ARG);
|
assert(kind == ARG_INDEX || kind == O_ARG);
|
||||||
return boost::get<unsigned int>(data);
|
return boost::get<unsigned int>(data);
|
||||||
}
|
}
|
||||||
const unsigned int& as_long() const {
|
const unsigned int& as_long() const {
|
||||||
return const_cast<op_t *>(this)->as_long();
|
return const_cast<op_t *>(this)->as_long_lval();
|
||||||
}
|
}
|
||||||
void set_long(unsigned int val) {
|
void set_long(unsigned int val) {
|
||||||
data = val;
|
data = val;
|
||||||
|
|
@ -467,14 +471,17 @@ struct op_t : public noncopyable
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
value_t& as_value() {
|
value_t& as_value_lval() {
|
||||||
assert(is_value());
|
assert(is_value());
|
||||||
return boost::get<value_t>(data);
|
value_t& val(boost::get<value_t>(data));
|
||||||
|
assert(val.valid());
|
||||||
|
return val;
|
||||||
}
|
}
|
||||||
const value_t& as_value() const {
|
const value_t& as_value() const {
|
||||||
return const_cast<op_t *>(this)->as_value();
|
return const_cast<op_t *>(this)->as_value_lval();
|
||||||
}
|
}
|
||||||
void set_value(const value_t& val) {
|
void set_value(const value_t& val) {
|
||||||
|
assert(val.valid());
|
||||||
data = val;
|
data = val;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -485,26 +492,47 @@ struct op_t : public noncopyable
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
string& as_string() {
|
string& as_string_lval() {
|
||||||
assert(is_string());
|
assert(is_string());
|
||||||
return boost::get<value_t>(data).as_string_lval();
|
return boost::get<value_t>(data).as_string_lval();
|
||||||
}
|
}
|
||||||
const string& as_string() const {
|
const string& as_string() const {
|
||||||
return const_cast<op_t *>(this)->as_string();
|
return const_cast<op_t *>(this)->as_string_lval();
|
||||||
}
|
}
|
||||||
void set_string(const string& val) {
|
void set_string(const string& val) {
|
||||||
data = value_t(val);
|
data = value_t(val);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool is_mask() const {
|
||||||
|
if (kind > BEGIN_MASKS && kind < END_MASKS) {
|
||||||
|
assert(data.type() == typeid(mask_t));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
mask_t& as_mask_lval() {
|
||||||
|
assert(is_mask());
|
||||||
|
return boost::get<mask_t>(data);
|
||||||
|
}
|
||||||
|
const mask_t& as_mask() const {
|
||||||
|
return const_cast<op_t *>(this)->as_mask_lval();
|
||||||
|
}
|
||||||
|
void set_mask(const mask_t& val) {
|
||||||
|
data = val;
|
||||||
|
}
|
||||||
|
void set_mask(const string& expr) {
|
||||||
|
data = mask_t(expr);
|
||||||
|
}
|
||||||
|
|
||||||
bool is_function() const {
|
bool is_function() const {
|
||||||
return kind == FUNCTION;
|
return kind == FUNCTION;
|
||||||
}
|
}
|
||||||
function_t& as_function() {
|
function_t& as_function_lval() {
|
||||||
assert(kind == FUNCTION);
|
assert(kind == FUNCTION);
|
||||||
return boost::get<function_t>(data);
|
return boost::get<function_t>(data);
|
||||||
}
|
}
|
||||||
const function_t& as_function() const {
|
const function_t& as_function() const {
|
||||||
return const_cast<op_t *>(this)->as_function();
|
return const_cast<op_t *>(this)->as_function_lval();
|
||||||
}
|
}
|
||||||
void set_function(const function_t& val) {
|
void set_function(const function_t& val) {
|
||||||
data = val;
|
data = val;
|
||||||
|
|
@ -514,24 +542,24 @@ struct op_t : public noncopyable
|
||||||
bool is_name() const {
|
bool is_name() const {
|
||||||
return data.type() == typeid(node_t::nameid_t);
|
return data.type() == typeid(node_t::nameid_t);
|
||||||
}
|
}
|
||||||
node_t::nameid_t& as_name() {
|
node_t::nameid_t& as_name_lval() {
|
||||||
assert(kind == NODE_ID || kind == ATTR_ID);
|
assert(kind == NODE_ID || kind == ATTR_ID);
|
||||||
return boost::get<node_t::nameid_t>(data);
|
return boost::get<node_t::nameid_t>(data);
|
||||||
}
|
}
|
||||||
const node_t::nameid_t& as_name() const {
|
const node_t::nameid_t& as_name() const {
|
||||||
return const_cast<op_t *>(this)->as_name();
|
return const_cast<op_t *>(this)->as_name_lval();
|
||||||
}
|
}
|
||||||
void set_name(const node_t::nameid_t& val) {
|
void set_name(const node_t::nameid_t& val) {
|
||||||
data = val;
|
data = val;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
ptr_op_t& as_op() {
|
ptr_op_t& as_op_lval() {
|
||||||
assert(kind > TERMINALS);
|
assert(kind > TERMINALS);
|
||||||
return boost::get<ptr_op_t>(data);
|
return boost::get<ptr_op_t>(data);
|
||||||
}
|
}
|
||||||
const ptr_op_t& as_op() const {
|
const ptr_op_t& as_op() const {
|
||||||
return const_cast<op_t *>(this)->as_op();
|
return const_cast<op_t *>(this)->as_op_lval();
|
||||||
}
|
}
|
||||||
|
|
||||||
void acquire() const {
|
void acquire() const {
|
||||||
|
|
@ -562,7 +590,7 @@ struct op_t : public noncopyable
|
||||||
|
|
||||||
ptr_op_t& right() {
|
ptr_op_t& right() {
|
||||||
assert(kind > TERMINALS);
|
assert(kind > TERMINALS);
|
||||||
return as_op();
|
return as_op_lval();
|
||||||
}
|
}
|
||||||
const ptr_op_t& right() const {
|
const ptr_op_t& right() const {
|
||||||
assert(kind > TERMINALS);
|
assert(kind > TERMINALS);
|
||||||
|
|
@ -628,7 +656,6 @@ struct op_t : public noncopyable
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
#if 0
|
|
||||||
class op_predicate {
|
class op_predicate {
|
||||||
ptr_op_t op;
|
ptr_op_t op;
|
||||||
|
|
||||||
|
|
@ -638,7 +665,6 @@ public:
|
||||||
return op->calc(scope).to_boolean();
|
return op->calc(scope).to_boolean();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
#endif
|
|
||||||
|
|
||||||
class valexpr_context : public error_context {
|
class valexpr_context : public error_context {
|
||||||
public:
|
public:
|
||||||
|
|
|
||||||
49
value.cc
49
value.cc
|
|
@ -1218,17 +1218,17 @@ value_t value_t::abs() const
|
||||||
{
|
{
|
||||||
switch (type()) {
|
switch (type()) {
|
||||||
case INTEGER: {
|
case INTEGER: {
|
||||||
long val = const_cast<value_t&>(*this).as_long_lval();
|
long val = as_long();
|
||||||
if (val < 0)
|
if (val < 0)
|
||||||
return - val;
|
return - val;
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
case AMOUNT:
|
case AMOUNT:
|
||||||
return const_cast<value_t&>(*this).as_amount_lval().abs();
|
return as_amount().abs();
|
||||||
case BALANCE:
|
case BALANCE:
|
||||||
return const_cast<value_t&>(*this).as_balance_lval().abs();
|
return as_balance().abs();
|
||||||
case BALANCE_PAIR:
|
case BALANCE_PAIR:
|
||||||
return const_cast<value_t&>(*this).as_balance_pair_lval().abs();
|
return as_balance_pair().abs();
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -1436,27 +1436,27 @@ void value_t::print(std::ostream& out, const int first_width,
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case BOOLEAN:
|
case BOOLEAN:
|
||||||
out << const_cast<value_t&>(*this).as_boolean_lval();
|
out << as_boolean();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DATETIME:
|
case DATETIME:
|
||||||
out << const_cast<value_t&>(*this).as_datetime_lval();
|
out << as_datetime();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case INTEGER:
|
case INTEGER:
|
||||||
out << const_cast<value_t&>(*this).as_long_lval();
|
out << as_long();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case AMOUNT:
|
case AMOUNT:
|
||||||
out << const_cast<value_t&>(*this).as_amount_lval();
|
out << as_amount();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case STRING:
|
case STRING:
|
||||||
out << const_cast<value_t&>(*this).as_string_lval();
|
out << as_string();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case POINTER:
|
case POINTER:
|
||||||
out << boost::unsafe_any_cast<void *>(&const_cast<value_t&>(*this).as_any_pointer_lval());
|
out << boost::unsafe_any_cast<const void *>(&as_any_pointer());
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SEQUENCE: {
|
case SEQUENCE: {
|
||||||
|
|
@ -1486,36 +1486,51 @@ void value_t::print(std::ostream& out, const int first_width,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool value_t::valid() const
|
||||||
|
{
|
||||||
|
switch (type()) {
|
||||||
|
case AMOUNT:
|
||||||
|
return as_amount().valid();
|
||||||
|
case BALANCE:
|
||||||
|
return as_balance().valid();
|
||||||
|
case BALANCE_PAIR:
|
||||||
|
return as_balance_pair().valid();
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
void value_context::describe(std::ostream& out) const throw()
|
void value_context::describe(std::ostream& out) const throw()
|
||||||
{
|
{
|
||||||
if (! desc.empty())
|
if (! desc.empty())
|
||||||
out << desc << std::endl;
|
out << desc << std::endl;
|
||||||
|
|
||||||
balance_t * ptr = NULL;
|
const balance_t * ptr = NULL;
|
||||||
|
|
||||||
out << std::right;
|
out << std::right;
|
||||||
out.width(20);
|
out.width(20);
|
||||||
|
|
||||||
switch (bal.type()) {
|
switch (bal.type()) {
|
||||||
case value_t::BOOLEAN:
|
case value_t::BOOLEAN:
|
||||||
out << (const_cast<value_t&>(bal).as_boolean_lval() ? "true" : "false");
|
out << (bal.as_boolean() ? "true" : "false");
|
||||||
break;
|
break;
|
||||||
case value_t::INTEGER:
|
case value_t::INTEGER:
|
||||||
out << const_cast<value_t&>(bal).as_long_lval();
|
out << bal.as_long();
|
||||||
break;
|
break;
|
||||||
case value_t::DATETIME:
|
case value_t::DATETIME:
|
||||||
out << const_cast<value_t&>(bal).as_datetime_lval();
|
out << bal.as_datetime();
|
||||||
break;
|
break;
|
||||||
case value_t::AMOUNT:
|
case value_t::AMOUNT:
|
||||||
out << const_cast<value_t&>(bal).as_amount_lval();
|
out << bal.as_amount();
|
||||||
break;
|
break;
|
||||||
case value_t::BALANCE:
|
case value_t::BALANCE:
|
||||||
ptr = &(const_cast<value_t&>(bal).as_balance_lval());
|
ptr = &bal.as_balance();
|
||||||
// fall through...
|
// fall through...
|
||||||
|
|
||||||
case value_t::BALANCE_PAIR:
|
case value_t::BALANCE_PAIR:
|
||||||
if (! ptr)
|
if (! ptr)
|
||||||
ptr = &(const_cast<value_t&>(bal).as_balance_pair_lval().quantity());
|
ptr = &bal.as_balance_pair().quantity();
|
||||||
|
|
||||||
ptr->print(out, 20);
|
ptr->print(out, 20);
|
||||||
break;
|
break;
|
||||||
|
|
|
||||||
71
value.h
71
value.h
|
|
@ -433,8 +433,8 @@ private:
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
* Data manipulation methods. A value object may be truth tested
|
* Data manipulation methods. A value object may be truth tested for the
|
||||||
* for the existence of every type it can contain:
|
* existence of every type it can contain:
|
||||||
*
|
*
|
||||||
* is_boolean()
|
* is_boolean()
|
||||||
* is_long()
|
* is_long()
|
||||||
|
|
@ -446,20 +446,19 @@ public:
|
||||||
* is_sequence()
|
* is_sequence()
|
||||||
* is_pointer()
|
* is_pointer()
|
||||||
*
|
*
|
||||||
* There are corresponding as_*() methods that represent a value as
|
* There are corresponding as_*() methods that represent a value as a
|
||||||
* a reference to its underlying type. For example, as_integer()
|
* reference to its underlying type. For example, as_long() returns a
|
||||||
* returns a reference to a "const long".
|
* reference to a "const long".
|
||||||
*
|
*
|
||||||
* There are also as_*_lval() methods, which represent the
|
* There are also as_*_lval() methods, which represent the underlying data
|
||||||
* underlying data as a reference to a non-const type. The
|
* as a reference to a non-const type. The difference here is that an
|
||||||
* difference here is that an _lval() call causes the underlying
|
* _lval() call causes the underlying data to be fully copied before the
|
||||||
* data to be fully copied before the resulting reference is
|
* resulting reference is returned.
|
||||||
* returned.
|
|
||||||
*
|
*
|
||||||
* Lastly, there are corresponding set_*(data) methods for directly
|
* Lastly, there are corresponding set_*(data) methods for directly
|
||||||
* assigning data of a particular type, rather than using the
|
* assigning data of a particular type, rather than using the regular
|
||||||
* regular assignment operator (whose implementation simply calls
|
* assignment operator (whose implementation simply calls the various set_
|
||||||
* the various set_ methods).
|
* methods).
|
||||||
*/
|
*/
|
||||||
bool is_boolean() const {
|
bool is_boolean() const {
|
||||||
return is_type(BOOLEAN);
|
return is_type(BOOLEAN);
|
||||||
|
|
@ -518,13 +517,18 @@ public:
|
||||||
amount_t& as_amount_lval() {
|
amount_t& as_amount_lval() {
|
||||||
assert(is_amount());
|
assert(is_amount());
|
||||||
_dup();
|
_dup();
|
||||||
return *(amount_t *) storage->data;
|
amount_t& amt(*(amount_t *) storage->data);
|
||||||
|
assert(amt.valid());
|
||||||
|
return amt;
|
||||||
}
|
}
|
||||||
const amount_t& as_amount() const {
|
const amount_t& as_amount() const {
|
||||||
assert(is_amount());
|
assert(is_amount());
|
||||||
return *(amount_t *) storage->data;
|
amount_t& amt(*(amount_t *) storage->data);
|
||||||
|
assert(amt.valid());
|
||||||
|
return amt;
|
||||||
}
|
}
|
||||||
void set_amount(const amount_t& val) {
|
void set_amount(const amount_t& val) {
|
||||||
|
assert(val.valid());
|
||||||
set_type(AMOUNT);
|
set_type(AMOUNT);
|
||||||
new((amount_t *) storage->data) amount_t(val);
|
new((amount_t *) storage->data) amount_t(val);
|
||||||
}
|
}
|
||||||
|
|
@ -535,13 +539,18 @@ public:
|
||||||
balance_t& as_balance_lval() {
|
balance_t& as_balance_lval() {
|
||||||
assert(is_balance());
|
assert(is_balance());
|
||||||
_dup();
|
_dup();
|
||||||
return **(balance_t **) storage->data;
|
balance_t& bal(**(balance_t **) storage->data);
|
||||||
|
assert(bal.valid());
|
||||||
|
return bal;
|
||||||
}
|
}
|
||||||
const balance_t& as_balance() const {
|
const balance_t& as_balance() const {
|
||||||
assert(is_balance());
|
assert(is_balance());
|
||||||
return **(balance_t **) storage->data;
|
balance_t& bal(**(balance_t **) storage->data);
|
||||||
|
assert(bal.valid());
|
||||||
|
return bal;
|
||||||
}
|
}
|
||||||
void set_balance(const balance_t& val) {
|
void set_balance(const balance_t& val) {
|
||||||
|
assert(val.valid());
|
||||||
set_type(BALANCE);
|
set_type(BALANCE);
|
||||||
*(balance_t **) storage->data = new balance_t(val);
|
*(balance_t **) storage->data = new balance_t(val);
|
||||||
}
|
}
|
||||||
|
|
@ -552,13 +561,18 @@ public:
|
||||||
balance_pair_t& as_balance_pair_lval() {
|
balance_pair_t& as_balance_pair_lval() {
|
||||||
assert(is_balance_pair());
|
assert(is_balance_pair());
|
||||||
_dup();
|
_dup();
|
||||||
return **(balance_pair_t **) storage->data;
|
balance_pair_t& bal_pair(**(balance_pair_t **) storage->data);
|
||||||
|
assert(bal_pair.valid());
|
||||||
|
return bal_pair;
|
||||||
}
|
}
|
||||||
const balance_pair_t& as_balance_pair() const {
|
const balance_pair_t& as_balance_pair() const {
|
||||||
assert(is_balance_pair());
|
assert(is_balance_pair());
|
||||||
return **(balance_pair_t **) storage->data;
|
balance_pair_t& bal_pair(**(balance_pair_t **) storage->data);
|
||||||
|
assert(bal_pair.valid());
|
||||||
|
return bal_pair;
|
||||||
}
|
}
|
||||||
void set_balance_pair(const balance_pair_t& val) {
|
void set_balance_pair(const balance_pair_t& val) {
|
||||||
|
assert(val.valid());
|
||||||
set_type(BALANCE_PAIR);
|
set_type(BALANCE_PAIR);
|
||||||
*(balance_pair_t **) storage->data = new balance_pair_t(val);
|
*(balance_pair_t **) storage->data = new balance_pair_t(val);
|
||||||
}
|
}
|
||||||
|
|
@ -579,6 +593,10 @@ public:
|
||||||
set_type(STRING);
|
set_type(STRING);
|
||||||
new((string *) storage->data) string(val);
|
new((string *) storage->data) string(val);
|
||||||
}
|
}
|
||||||
|
void set_string(const char * val = "") {
|
||||||
|
set_type(STRING);
|
||||||
|
new((string *) storage->data) string(val);
|
||||||
|
}
|
||||||
|
|
||||||
bool is_sequence() const {
|
bool is_sequence() const {
|
||||||
return is_type(SEQUENCE);
|
return is_type(SEQUENCE);
|
||||||
|
|
@ -617,7 +635,7 @@ public:
|
||||||
_dup();
|
_dup();
|
||||||
return *any_cast<T *>(*(boost::any *) storage->data);
|
return *any_cast<T *>(*(boost::any *) storage->data);
|
||||||
}
|
}
|
||||||
boost::any as_any_pointer() const {
|
const boost::any& as_any_pointer() const {
|
||||||
assert(is_pointer());
|
assert(is_pointer());
|
||||||
return *(boost::any *) storage->data;
|
return *(boost::any *) storage->data;
|
||||||
}
|
}
|
||||||
|
|
@ -730,13 +748,13 @@ public:
|
||||||
if (! is_sequence())
|
if (! is_sequence())
|
||||||
in_place_cast(SEQUENCE);
|
in_place_cast(SEQUENCE);
|
||||||
|
|
||||||
value_t::sequence_t& seq(as_sequence_lval());
|
|
||||||
if (! val.is_sequence()) {
|
if (! val.is_sequence()) {
|
||||||
if (! val.is_null())
|
if (! val.is_null())
|
||||||
seq.push_back(val);
|
as_sequence_lval().push_back(val);
|
||||||
} else {
|
} else {
|
||||||
const value_t::sequence_t& val_seq(val.as_sequence());
|
const value_t::sequence_t& val_seq(val.as_sequence());
|
||||||
std::copy(val_seq.begin(), val_seq.end(), back_inserter(seq));
|
std::copy(val_seq.begin(), val_seq.end(),
|
||||||
|
back_inserter(as_sequence_lval()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -750,11 +768,12 @@ public:
|
||||||
} else {
|
} else {
|
||||||
as_sequence_lval().pop_back();
|
as_sequence_lval().pop_back();
|
||||||
|
|
||||||
std::size_t new_size = as_sequence().size();
|
const value_t::sequence_t& seq(as_sequence());
|
||||||
|
std::size_t new_size = seq.size();
|
||||||
if (new_size == 0)
|
if (new_size == 0)
|
||||||
_reset();
|
_reset();
|
||||||
else if (new_size == 1)
|
else if (new_size == 1)
|
||||||
*this = as_sequence().front();
|
*this = seq.front();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -811,6 +830,8 @@ public:
|
||||||
/**
|
/**
|
||||||
* Debugging methods.
|
* Debugging methods.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
bool valid() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define NULL_VALUE (value_t())
|
#define NULL_VALUE (value_t())
|
||||||
|
|
|
||||||
2
walk.cc
2
walk.cc
|
|
@ -230,7 +230,7 @@ void handle_value(const value_t& value,
|
||||||
// fall through...
|
// fall through...
|
||||||
|
|
||||||
case value_t::AMOUNT:
|
case value_t::AMOUNT:
|
||||||
xact.amount = temp.as_amount_lval();
|
xact.amount = temp.as_amount();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case value_t::BALANCE:
|
case value_t::BALANCE:
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue