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"
|
||||
|
||||
if [ -x /usr/bin/g++-4.2 ]; then
|
||||
CXX=g++-4.2
|
||||
fi
|
||||
|
||||
|
||||
SYSTEM=`uname -s`
|
||||
|
||||
|
|
@ -85,44 +89,50 @@ while [ -n "$1" ]; do
|
|||
SWITCHES="$SWITCHES --disable-shared"
|
||||
CPPFLAGS="$CPPFLAGS -DBOOST_MULTI_INDEX_ENABLE_INVARIANT_CHECKING=1"
|
||||
CPPFLAGS="$CPPFLAGS -DBOOST_MULTI_INDEX_ENABLE_SAFE_MODE=1"
|
||||
;;
|
||||
shift 1 ;;
|
||||
|
||||
--debug)
|
||||
SWITCHES="$SWITCHES --enable-debug"
|
||||
#CPPFLAGS="$CPPFLAGS -D_GLIBCXX_DEBUG=1"
|
||||
CXXFLAGS="$CXXFLAGS -g" ;;
|
||||
|
||||
CXXFLAGS="$CXXFLAGS -g"
|
||||
shift 1 ;;
|
||||
|
||||
--boost)
|
||||
shift 1
|
||||
SWITCHES="$SWITCHES --with-boost-suffix=$1"
|
||||
;;
|
||||
shift 1 ;;
|
||||
|
||||
--gcov)
|
||||
CXXFLAGS="$CXXFLAGS -fprofile-arcs -ftest-coverage" ;;
|
||||
CXXFLAGS="$CXXFLAGS -fprofile-arcs -ftest-coverage"
|
||||
shift 1 ;;
|
||||
|
||||
--gprof)
|
||||
CXXFLAGS="$CXXFLAGS -g -pg" ;;
|
||||
CXXFLAGS="$CXXFLAGS -g -pg"
|
||||
shift 1 ;;
|
||||
|
||||
--python)
|
||||
if [ -d "$PYTHON_HOME" ]; then
|
||||
SWITCHES="$SWITCHES --enable-python"
|
||||
CPPFLAGS="$CPPFLAGS -I$PYTHON_HOME/include/python2.5"
|
||||
LDFLAGS="$LDFLAGS -L$PYTHON_HOME/lib/python2.5/config"
|
||||
fi ;;
|
||||
fi
|
||||
shift 1;;
|
||||
|
||||
--pic)
|
||||
CXXFLAGS="$CXXFLAGS -fPIC" ;;
|
||||
CXXFLAGS="$CXXFLAGS -fPIC"
|
||||
shift 1 ;;
|
||||
|
||||
--opt)
|
||||
CXXFLAGS="$CXXFLAGS -fomit-frame-pointer -O3" ;;
|
||||
CXXFLAGS="$CXXFLAGS -fomit-frame-pointer -O3"
|
||||
shift 1 ;;
|
||||
|
||||
--local)
|
||||
LOCAL=true ;;
|
||||
LOCAL=true
|
||||
shift 1 ;;
|
||||
|
||||
*)
|
||||
break ;;
|
||||
esac
|
||||
shift 1
|
||||
done
|
||||
|
||||
|
||||
|
|
|
|||
52
amount.cc
52
amount.cc
|
|
@ -97,6 +97,25 @@ struct amount_t::bigint_t : public supports_flags<>
|
|||
assert(ref == 0);
|
||||
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()
|
||||
|
|
@ -139,6 +158,8 @@ void amount_t::shutdown()
|
|||
|
||||
void amount_t::_copy(const amount_t& amt)
|
||||
{
|
||||
assert(amt.valid());
|
||||
|
||||
if (quantity != amt.quantity) {
|
||||
if (quantity)
|
||||
_release();
|
||||
|
|
@ -155,15 +176,21 @@ void amount_t::_copy(const amount_t& amt)
|
|||
}
|
||||
}
|
||||
commodity_ = amt.commodity_;
|
||||
|
||||
assert(valid());
|
||||
}
|
||||
|
||||
void amount_t::_dup()
|
||||
{
|
||||
assert(valid());
|
||||
|
||||
if (quantity->ref > 1) {
|
||||
bigint_t * q = new bigint_t(*quantity);
|
||||
_release();
|
||||
quantity = q;
|
||||
}
|
||||
|
||||
assert(valid());
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
quantity->prec = prec;
|
||||
|
||||
assert(valid());
|
||||
}
|
||||
|
||||
void amount_t::_clear()
|
||||
|
|
@ -195,6 +224,8 @@ void amount_t::_clear()
|
|||
|
||||
void amount_t::_release()
|
||||
{
|
||||
assert(valid());
|
||||
|
||||
DEBUG("amounts.refs", quantity << " ref--, now " << (quantity->ref - 1));
|
||||
|
||||
if (--quantity->ref == 0) {
|
||||
|
|
@ -202,7 +233,11 @@ void amount_t::_release()
|
|||
quantity->~bigint_t();
|
||||
else
|
||||
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
|
||||
{
|
||||
assert(amt.valid());
|
||||
|
||||
if (! quantity || ! amt.quantity) {
|
||||
if (quantity)
|
||||
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)
|
||||
{
|
||||
assert(amt.valid());
|
||||
|
||||
if (! quantity || ! amt.quantity) {
|
||||
if (quantity)
|
||||
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)
|
||||
{
|
||||
assert(amt.valid());
|
||||
|
||||
if (! quantity || ! amt.quantity) {
|
||||
if (quantity)
|
||||
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)
|
||||
{
|
||||
assert(amt.valid());
|
||||
|
||||
if (! quantity || ! amt.quantity) {
|
||||
if (quantity)
|
||||
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)
|
||||
{
|
||||
assert(amt.valid());
|
||||
|
||||
if (! quantity || ! amt.quantity) {
|
||||
if (quantity)
|
||||
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();
|
||||
|
||||
safe_holder.release(); // `this->quantity' owns the pointer
|
||||
|
||||
assert(valid());
|
||||
}
|
||||
|
||||
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,
|
||||
bool full_precision) const
|
||||
{
|
||||
assert(valid());
|
||||
|
||||
if (! quantity)
|
||||
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
|
||||
{
|
||||
if (quantity) {
|
||||
if (! quantity->valid())
|
||||
return false;
|
||||
|
||||
if (quantity->ref == 0) {
|
||||
DEBUG("ledger.validate", "amount_t: quantity->ref == 0");
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -351,7 +351,7 @@ public:
|
|||
* valid() returns true if the balances within the balance pair are
|
||||
* valid.
|
||||
*/
|
||||
virtual bool valid() {
|
||||
bool valid() const {
|
||||
if (! balance_t::valid())
|
||||
return false;
|
||||
|
||||
|
|
|
|||
|
|
@ -827,16 +827,16 @@ void write_value(std::ostream& out, const value_t& val)
|
|||
|
||||
switch (val.type()) {
|
||||
case value_t::BOOLEAN:
|
||||
write_bool(out, const_cast<value_t&>(val).as_boolean_lval());
|
||||
write_bool(out, val.as_boolean());
|
||||
break;
|
||||
case value_t::INTEGER:
|
||||
write_long(out, const_cast<value_t&>(val).as_long_lval());
|
||||
write_long(out, val.as_long());
|
||||
break;
|
||||
case value_t::DATETIME:
|
||||
write_number(out, const_cast<value_t&>(val).as_datetime_lval());
|
||||
write_number(out,val.as_datetime());
|
||||
break;
|
||||
case value_t::AMOUNT:
|
||||
write_amount(out, const_cast<value_t&>(val).as_amount_lval());
|
||||
write_amount(out, val.as_amount());
|
||||
break;
|
||||
|
||||
//case value_t::BALANCE:
|
||||
|
|
|
|||
|
|
@ -67,7 +67,7 @@ entry_t * derive_new_entry(journal_t& journal,
|
|||
|
||||
value_t total = account_xdata(*acct).total;
|
||||
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)
|
||||
break;
|
||||
|
||||
value_t value;
|
||||
balance_t * bal = NULL;
|
||||
value_t value;
|
||||
const balance_t * bal = NULL;
|
||||
|
||||
calc->compute(value, details);
|
||||
|
||||
|
|
@ -378,54 +378,54 @@ void format_t::format(std::ostream& out_str, const details_t& details) const
|
|||
|
||||
switch (value.type()) {
|
||||
case value_t::BOOLEAN:
|
||||
out << (value.as_boolean_lval() ? "true" : "false");
|
||||
out << (value.as_boolean() ? "true" : "false");
|
||||
break;
|
||||
|
||||
case value_t::INTEGER:
|
||||
if (ansi_codes && elem->flags & ELEMENT_HIGHLIGHT) {
|
||||
if (ansi_invert) {
|
||||
if (value.as_long_lval() > 0) {
|
||||
if (value.as_long() > 0) {
|
||||
mark_red(out, elem);
|
||||
highlighted = true;
|
||||
}
|
||||
} else {
|
||||
if (value.as_long_lval() < 0) {
|
||||
if (value.as_long() < 0) {
|
||||
mark_red(out, elem);
|
||||
highlighted = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
out << value.as_long_lval();
|
||||
out << value.as_long();
|
||||
break;
|
||||
|
||||
case value_t::DATETIME:
|
||||
out << value.as_datetime_lval();
|
||||
out << value.as_datetime();
|
||||
break;
|
||||
|
||||
case value_t::AMOUNT:
|
||||
if (ansi_codes && elem->flags & ELEMENT_HIGHLIGHT) {
|
||||
if (ansi_invert) {
|
||||
if (value.as_amount_lval().sign() > 0) {
|
||||
if (value.as_amount().sign() > 0) {
|
||||
mark_red(out, elem);
|
||||
highlighted = true;
|
||||
}
|
||||
} else {
|
||||
if (value.as_amount_lval().sign() < 0) {
|
||||
if (value.as_amount().sign() < 0) {
|
||||
mark_red(out, elem);
|
||||
highlighted = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
out << value.as_amount_lval();
|
||||
out << value.as_amount();
|
||||
break;
|
||||
|
||||
case value_t::BALANCE:
|
||||
bal = &(value.as_balance_lval());
|
||||
bal = &(value.as_balance());
|
||||
// fall through...
|
||||
|
||||
case value_t::BALANCE_PAIR:
|
||||
if (! bal)
|
||||
bal = &(value.as_balance_pair_lval().quantity());
|
||||
bal = &(value.as_balance_pair().quantity());
|
||||
|
||||
if (ansi_codes && elem->flags & ELEMENT_HIGHLIGHT) {
|
||||
if (ansi_invert) {
|
||||
|
|
@ -949,11 +949,11 @@ void format_equity::flush()
|
|||
summary.data = &xdata;
|
||||
|
||||
if (total.type() >= value_t::BALANCE) {
|
||||
balance_t * bal;
|
||||
const balance_t * bal;
|
||||
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))
|
||||
bal = &(total.as_balance_pair_lval().quantity());
|
||||
bal = &(total.as_balance_pair().quantity());
|
||||
else
|
||||
assert(false);
|
||||
|
||||
|
|
@ -977,11 +977,11 @@ void format_equity::operator()(account_t& account)
|
|||
value_t val = account_xdata_(account).value;
|
||||
|
||||
if (val.type() >= value_t::BALANCE) {
|
||||
balance_t * bal;
|
||||
const balance_t * bal;
|
||||
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))
|
||||
bal = &(val.as_balance_pair_lval().quantity());
|
||||
bal = &(val.as_balance_pair().quantity());
|
||||
else
|
||||
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();
|
||||
x != transactions.end();
|
||||
x++)
|
||||
x++) {
|
||||
if (! (*x)->has_flags(TRANSACTION_VIRTUAL) ||
|
||||
(*x)->has_flags(TRANSACTION_BALANCE)) {
|
||||
amount_t& p((*x)->cost ? *(*x)->cost : (*x)->amount);
|
||||
|
|
@ -154,6 +154,9 @@ bool entry_base_t::finalize()
|
|||
saw_null = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
assert(balance.valid());
|
||||
|
||||
// If it's a null entry, then let the user have their fun
|
||||
if (no_amounts)
|
||||
|
|
@ -177,21 +180,24 @@ bool entry_base_t::finalize()
|
|||
// the balance. This is done for the last eligible commodity.
|
||||
|
||||
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) {
|
||||
transactions_list::const_iterator x = transactions.begin();
|
||||
assert((*x)->amount);
|
||||
assert(! (*x)->amount.is_null());
|
||||
commodity_t& this_comm = (*x)->amount.commodity();
|
||||
|
||||
balance_t::amounts_map::const_iterator this_bal =
|
||||
bal.amounts.find(&this_comm);
|
||||
assert(this_bal != bal.amounts.end());
|
||||
|
||||
balance_t::amounts_map::const_iterator other_bal =
|
||||
bal.amounts.begin();
|
||||
|
||||
if (this_bal == other_bal)
|
||||
other_bal++;
|
||||
|
||||
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++) {
|
||||
if ((*x)->cost || (*x)->has_flags(TRANSACTION_VIRTUAL) ||
|
||||
|
|
@ -241,12 +247,12 @@ bool entry_base_t::finalize()
|
|||
const balance_t * bal = NULL;
|
||||
switch (balance.type()) {
|
||||
case value_t::BALANCE_PAIR:
|
||||
bal = &balance.as_balance_pair_lval().quantity();
|
||||
bal = &balance.as_balance_pair().quantity();
|
||||
// fall through...
|
||||
|
||||
case value_t::BALANCE:
|
||||
if (! bal)
|
||||
bal = &balance.as_balance_lval();
|
||||
bal = &balance.as_balance();
|
||||
|
||||
if (bal->amounts.size() < 2) {
|
||||
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);
|
||||
kind = AT_SYM;
|
||||
break;
|
||||
#if 0
|
||||
case '$':
|
||||
in.get(c);
|
||||
kind = DOLLAR;
|
||||
break;
|
||||
#endif
|
||||
|
||||
case '&':
|
||||
in.get(c);
|
||||
kind = KW_AND;
|
||||
break;
|
||||
|
||||
case '(':
|
||||
in.get(c);
|
||||
|
|
@ -171,7 +178,7 @@ void parser_t::token_t::next(std::istream& in, const flags_t flags)
|
|||
|
||||
case '[': {
|
||||
in.get(c);
|
||||
if (flags & EXPR_PARSE_ALLOW_DATE) {
|
||||
if (! (flags & EXPR_PARSE_NO_DATES)) {
|
||||
char buf[256];
|
||||
READ_INTO_(in, buf, 255, c, length, c != ']');
|
||||
if (c != ']')
|
||||
|
|
@ -193,6 +200,7 @@ void parser_t::token_t::next(std::istream& in, const flags_t flags)
|
|||
break;
|
||||
}
|
||||
|
||||
|
||||
case '\'':
|
||||
case '"': {
|
||||
char delim;
|
||||
|
|
@ -249,10 +257,68 @@ void parser_t::token_t::next(std::istream& in, const flags_t flags)
|
|||
kind = STAR;
|
||||
break;
|
||||
|
||||
#if 0
|
||||
case '/':
|
||||
in.get(c);
|
||||
kind = SLASH;
|
||||
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 '=':
|
||||
in.get(c);
|
||||
|
|
@ -336,7 +402,7 @@ void parser_t::token_t::next(std::istream& in, const flags_t flags)
|
|||
kind = VALUE;
|
||||
value = temp;
|
||||
}
|
||||
catch (amount_error& err) {
|
||||
catch (const amount_error& err) {
|
||||
// If the amount had no commodity, it must be an unambiguous
|
||||
// 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);
|
||||
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: {
|
||||
#if 0
|
||||
#ifdef USE_BOOST_PYTHON
|
||||
|
|
@ -473,12 +564,12 @@ parser_t::parse_value_term(std::istream& in, scope_t& scope, const flags_t tflag
|
|||
break;
|
||||
}
|
||||
|
||||
#if 0
|
||||
case token_t::AT_SYM: {
|
||||
tok = next_token(in, tflags);
|
||||
if (tok.kind != token_t::IDENT)
|
||||
throw_(parse_error, "@ symbol must be followed by attribute name");
|
||||
|
||||
#if 0
|
||||
string ident = tok.value.as_string();
|
||||
if (optional<node_t::nameid_t> id = document_t::lookup_builtin_id(ident)) {
|
||||
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->set_string(ident);
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
|
||||
#if 0
|
||||
case token_t::DOLLAR:
|
||||
tok = next_token(in, tflags);
|
||||
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
|
||||
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;
|
||||
|
||||
|
|
@ -561,7 +651,7 @@ parser_t::parse_unary_expr(std::istream& in, scope_t& scope, const flags_t tflag
|
|||
|
||||
// A very quick optimization
|
||||
if (term->kind == op_t::VALUE) {
|
||||
term->as_value().in_place_negate();
|
||||
term->as_value_lval().in_place_negate();
|
||||
node = term;
|
||||
} else {
|
||||
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
|
||||
if (term->kind == op_t::VALUE) {
|
||||
term->as_value().in_place_negate();
|
||||
term->as_value_lval().in_place_negate();
|
||||
node = term;
|
||||
} else {
|
||||
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;
|
||||
|
||||
// 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 '{': {
|
||||
amount_t temp;
|
||||
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_NO_MIGRATE 0x04
|
||||
#define EXPR_PARSE_NO_REDUCE 0x08
|
||||
#define EXPR_PARSE_ALLOW_DATE 0x10
|
||||
#define EXPR_PARSE_NO_DATES 0x10
|
||||
|
||||
public:
|
||||
typedef uint_least8_t flags_t;
|
||||
|
|
@ -57,6 +57,13 @@ private:
|
|||
enum kind_t {
|
||||
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_:]*
|
||||
DOLLAR, // $
|
||||
AT_SYM, // @
|
||||
|
|
@ -98,7 +105,7 @@ private:
|
|||
UNKNOWN
|
||||
} kind;
|
||||
|
||||
char symbol[3];
|
||||
char symbol[3];
|
||||
value_t value;
|
||||
std::size_t length;
|
||||
|
||||
|
|
@ -225,9 +232,8 @@ public:
|
|||
return parse_expr(in, empty_string, *global_scope, flags);
|
||||
}
|
||||
|
||||
value_expr& parse(std::istream& in,
|
||||
const flags_t flags = EXPR_PARSE_RELAXED,
|
||||
scope_t& scope)
|
||||
value_expr& parse(std::istream& in, scope_t& scope,
|
||||
const flags_t flags = EXPR_PARSE_RELAXED)
|
||||
{
|
||||
return parse_expr(in, empty_string, scope, flags);
|
||||
}
|
||||
|
|
@ -238,8 +244,8 @@ public:
|
|||
return parse_expr(stream, str, *global_scope, flags);
|
||||
}
|
||||
|
||||
value_expr& parse(string& str, const flags_t flags = EXPR_PARSE_RELAXED,
|
||||
scope_t& scope)
|
||||
value_expr& parse(string& str, scope_t& scope,
|
||||
const flags_t flags = EXPR_PARSE_RELAXED)
|
||||
{
|
||||
std::istringstream stream(str);
|
||||
return parse_expr(stream, str, scope, flags);
|
||||
|
|
|
|||
|
|
@ -64,8 +64,8 @@ void reconcile_transactions::flush()
|
|||
cleared_balance.cast(value_t::AMOUNT);
|
||||
balance.cast(value_t::AMOUNT);
|
||||
|
||||
commodity_t& cb_comm = cleared_balance.as_amount_lval().commodity();
|
||||
commodity_t& b_comm = balance.as_amount_lval().commodity();
|
||||
commodity_t& cb_comm = cleared_balance.as_amount().commodity();
|
||||
commodity_t& b_comm = balance.as_amount().commodity();
|
||||
|
||||
balance -= cleared_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.
|
||||
amount_t& to_reconcile(balance.as_amount_lval());
|
||||
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)) {
|
||||
push_to_handler(first);
|
||||
} 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);
|
||||
}
|
||||
|
||||
// jww (2008-07-24): I don't think this is right, since amount_expr is
|
||||
// always NULL right now
|
||||
if (xact->amount_expr) {
|
||||
unsigned long end = (long)in.tellg();
|
||||
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))
|
||||
throw new parse_error
|
||||
("A transaction's cost must evaluate to a constant value");
|
||||
assert(xact->cost->valid());
|
||||
|
||||
unsigned long end = (long)in.tellg();
|
||||
|
||||
if (per_unit)
|
||||
xact->cost_expr = (string("@") +
|
||||
string(line, beg, end - beg));
|
||||
else
|
||||
xact->cost_expr = (string("@@") +
|
||||
string(line, beg, end - beg));
|
||||
// jww (2008-07-24): I don't think this is right...
|
||||
if (xact->cost_expr) {
|
||||
unsigned long end = (long)in.tellg();
|
||||
if (per_unit)
|
||||
xact->cost_expr->expr_str = (string("@") +
|
||||
string(line, beg, end - beg));
|
||||
else
|
||||
xact->cost_expr->expr_str = (string("@@") +
|
||||
string(line, beg, end - beg));
|
||||
}
|
||||
}
|
||||
catch (error * err) {
|
||||
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()));
|
||||
amount_t amt;
|
||||
amt.parse(buf);
|
||||
assert(amt.valid());
|
||||
|
||||
transaction_t * xact
|
||||
= 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"
|
||||
amount_t amt(skip_ws(line + 1));
|
||||
assert(amt.valid());
|
||||
amount_t::current_pool->default_commodity = &amt.commodity();
|
||||
break;
|
||||
}
|
||||
|
|
@ -706,6 +713,7 @@ unsigned int textual_parser_t::parse(std::istream& in,
|
|||
string symbol;
|
||||
parse_symbol(symbol_and_price, symbol);
|
||||
amount_t price(symbol_and_price);
|
||||
assert(price.valid());
|
||||
|
||||
if (commodity_t * commodity =
|
||||
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
|
||||
// will do nothing at all.
|
||||
assert(result.valid());
|
||||
result.in_place_cast(value_t::AMOUNT);
|
||||
amt = result.as_amount();
|
||||
assert(amt.valid());
|
||||
}
|
||||
catch (error * err) {
|
||||
if (err->context.empty() ||
|
||||
|
|
@ -134,7 +136,7 @@ namespace {
|
|||
} else {
|
||||
temp.reset(new op_t(op_t::VALUE));
|
||||
temp->set_value(value_t());
|
||||
expr->compute(temp->as_value(), details, context);
|
||||
expr->compute(temp->as_value_lval(), details, context);
|
||||
}
|
||||
} else {
|
||||
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;
|
||||
ptr_op_t expr = find_leaf(context, 0, arg_index);
|
||||
expr->compute(result, details, context);
|
||||
result = result.as_datetime_lval();
|
||||
result = result.as_datetime();
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
@ -425,7 +427,7 @@ void op_t::compute(value_t& result, const details_t& details,
|
|||
long arg_index = 0;
|
||||
ptr_op_t expr = find_leaf(context, 0, arg_index);
|
||||
expr->compute(result, details, context);
|
||||
result = result.as_datetime_lval();
|
||||
result = result.as_datetime();
|
||||
if (! result)
|
||||
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)",
|
||||
new valexpr_context(expr));
|
||||
|
||||
datetime_t& moment(result.as_datetime_lval());
|
||||
const datetime_t& moment(result.as_datetime());
|
||||
switch (kind) {
|
||||
case F_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",
|
||||
new valexpr_context(expr));
|
||||
amount_t temp("1");
|
||||
temp.set_commodity(result.as_amount_lval().commodity());
|
||||
temp.set_commodity(result.as_amount().commodity());
|
||||
result = temp;
|
||||
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",
|
||||
new valexpr_context(expr));
|
||||
amount_t one("1");
|
||||
one.set_commodity(result.as_amount_lval().commodity());
|
||||
one.set_commodity(result.as_amount().commodity());
|
||||
result = one;
|
||||
|
||||
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);
|
||||
expr->compute(result, details, context);
|
||||
|
||||
balance_t * bal = NULL;
|
||||
const balance_t * bal = NULL;
|
||||
switch (result.type()) {
|
||||
case value_t::BALANCE_PAIR:
|
||||
bal = &(result.as_balance_pair_lval().quantity());
|
||||
bal = &(result.as_balance_pair().quantity());
|
||||
// fall through...
|
||||
|
||||
case value_t::BALANCE:
|
||||
if (! bal)
|
||||
bal = &(result.as_balance_lval());
|
||||
bal = &result.as_balance();
|
||||
|
||||
if (bal->amounts.size() < 2) {
|
||||
result.cast(value_t::AMOUNT);
|
||||
|
|
@ -586,55 +588,47 @@ void op_t::compute(value_t& result, const details_t& details,
|
|||
break;
|
||||
}
|
||||
|
||||
#if 0
|
||||
case F_CODE_MASK:
|
||||
assert(mask);
|
||||
if (details.entry)
|
||||
result = mask->match(details.entry->code);
|
||||
if (details.entry && details.entry->code)
|
||||
result = as_mask().match(*details.entry->code);
|
||||
else
|
||||
result = false;
|
||||
break;
|
||||
|
||||
case F_PAYEE_MASK:
|
||||
assert(mask);
|
||||
if (details.entry)
|
||||
result = mask->match(details.entry->payee);
|
||||
result = as_mask().match(details.entry->payee);
|
||||
else
|
||||
result = false;
|
||||
break;
|
||||
|
||||
case F_NOTE_MASK:
|
||||
assert(mask);
|
||||
if (details.xact)
|
||||
result = mask->match(details.xact->note);
|
||||
if (details.xact && details.xact->note)
|
||||
result = as_mask().match(*details.xact->note);
|
||||
else
|
||||
result = false;
|
||||
break;
|
||||
|
||||
case F_ACCOUNT_MASK:
|
||||
assert(mask);
|
||||
if (details.account)
|
||||
result = mask->match(details.account->fullname());
|
||||
result = as_mask().match(details.account->fullname());
|
||||
else
|
||||
result = false;
|
||||
break;
|
||||
|
||||
case F_SHORT_ACCOUNT_MASK:
|
||||
assert(mask);
|
||||
if (details.account)
|
||||
result = mask->match(details.account->name);
|
||||
result = as_mask().match(details.account->name);
|
||||
else
|
||||
result = false;
|
||||
break;
|
||||
|
||||
case F_COMMODITY_MASK:
|
||||
assert(mask);
|
||||
if (details.xact)
|
||||
result = mask->match(details.xact->amount.commodity().base_symbol());
|
||||
result = as_mask().match(details.xact->amount.commodity().base_symbol());
|
||||
else
|
||||
result = false;
|
||||
break;
|
||||
#endif
|
||||
|
||||
case O_ARG: {
|
||||
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)",
|
||||
new valexpr_context(expr));
|
||||
|
||||
result = result.value(moment.as_datetime_lval());
|
||||
result = result.value(moment.as_datetime());
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
|
|||
58
valexpr.h
58
valexpr.h
|
|
@ -340,6 +340,7 @@ struct op_t : public noncopyable
|
|||
enum kind_t {
|
||||
// Constants
|
||||
VALUE,
|
||||
MASK,
|
||||
ARG_INDEX,
|
||||
|
||||
CONSTANTS,
|
||||
|
|
@ -385,12 +386,15 @@ struct op_t : public noncopyable
|
|||
F_YEAR,
|
||||
F_MONTH,
|
||||
F_DAY,
|
||||
|
||||
BEGIN_MASKS,
|
||||
F_CODE_MASK,
|
||||
F_PAYEE_MASK,
|
||||
F_NOTE_MASK,
|
||||
F_ACCOUNT_MASK,
|
||||
F_SHORT_ACCOUNT_MASK,
|
||||
F_COMMODITY_MASK,
|
||||
END_MASKS,
|
||||
|
||||
TERMINALS,
|
||||
|
||||
|
|
@ -449,12 +453,12 @@ struct op_t : public noncopyable
|
|||
bool is_long() const {
|
||||
return data.type() == typeid(unsigned int);
|
||||
}
|
||||
unsigned int& as_long() {
|
||||
unsigned int& as_long_lval() {
|
||||
assert(kind == ARG_INDEX || kind == O_ARG);
|
||||
return boost::get<unsigned int>(data);
|
||||
}
|
||||
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) {
|
||||
data = val;
|
||||
|
|
@ -467,14 +471,17 @@ struct op_t : public noncopyable
|
|||
}
|
||||
return false;
|
||||
}
|
||||
value_t& as_value() {
|
||||
value_t& as_value_lval() {
|
||||
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 {
|
||||
return const_cast<op_t *>(this)->as_value();
|
||||
return const_cast<op_t *>(this)->as_value_lval();
|
||||
}
|
||||
void set_value(const value_t& val) {
|
||||
assert(val.valid());
|
||||
data = val;
|
||||
}
|
||||
|
||||
|
|
@ -485,26 +492,47 @@ struct op_t : public noncopyable
|
|||
}
|
||||
return false;
|
||||
}
|
||||
string& as_string() {
|
||||
string& as_string_lval() {
|
||||
assert(is_string());
|
||||
return boost::get<value_t>(data).as_string_lval();
|
||||
}
|
||||
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) {
|
||||
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 {
|
||||
return kind == FUNCTION;
|
||||
}
|
||||
function_t& as_function() {
|
||||
function_t& as_function_lval() {
|
||||
assert(kind == FUNCTION);
|
||||
return boost::get<function_t>(data);
|
||||
}
|
||||
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) {
|
||||
data = val;
|
||||
|
|
@ -514,24 +542,24 @@ struct op_t : public noncopyable
|
|||
bool is_name() const {
|
||||
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);
|
||||
return boost::get<node_t::nameid_t>(data);
|
||||
}
|
||||
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) {
|
||||
data = val;
|
||||
}
|
||||
#endif
|
||||
|
||||
ptr_op_t& as_op() {
|
||||
ptr_op_t& as_op_lval() {
|
||||
assert(kind > TERMINALS);
|
||||
return boost::get<ptr_op_t>(data);
|
||||
}
|
||||
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 {
|
||||
|
|
@ -562,7 +590,7 @@ struct op_t : public noncopyable
|
|||
|
||||
ptr_op_t& right() {
|
||||
assert(kind > TERMINALS);
|
||||
return as_op();
|
||||
return as_op_lval();
|
||||
}
|
||||
const ptr_op_t& right() const {
|
||||
assert(kind > TERMINALS);
|
||||
|
|
@ -628,7 +656,6 @@ struct op_t : public noncopyable
|
|||
}
|
||||
};
|
||||
|
||||
#if 0
|
||||
class op_predicate {
|
||||
ptr_op_t op;
|
||||
|
||||
|
|
@ -638,7 +665,6 @@ public:
|
|||
return op->calc(scope).to_boolean();
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
class valexpr_context : public error_context {
|
||||
public:
|
||||
|
|
|
|||
49
value.cc
49
value.cc
|
|
@ -1218,17 +1218,17 @@ value_t value_t::abs() const
|
|||
{
|
||||
switch (type()) {
|
||||
case INTEGER: {
|
||||
long val = const_cast<value_t&>(*this).as_long_lval();
|
||||
long val = as_long();
|
||||
if (val < 0)
|
||||
return - val;
|
||||
return val;
|
||||
}
|
||||
case AMOUNT:
|
||||
return const_cast<value_t&>(*this).as_amount_lval().abs();
|
||||
return as_amount().abs();
|
||||
case BALANCE:
|
||||
return const_cast<value_t&>(*this).as_balance_lval().abs();
|
||||
return as_balance().abs();
|
||||
case BALANCE_PAIR:
|
||||
return const_cast<value_t&>(*this).as_balance_pair_lval().abs();
|
||||
return as_balance_pair().abs();
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
@ -1436,27 +1436,27 @@ void value_t::print(std::ostream& out, const int first_width,
|
|||
break;
|
||||
|
||||
case BOOLEAN:
|
||||
out << const_cast<value_t&>(*this).as_boolean_lval();
|
||||
out << as_boolean();
|
||||
break;
|
||||
|
||||
case DATETIME:
|
||||
out << const_cast<value_t&>(*this).as_datetime_lval();
|
||||
out << as_datetime();
|
||||
break;
|
||||
|
||||
case INTEGER:
|
||||
out << const_cast<value_t&>(*this).as_long_lval();
|
||||
out << as_long();
|
||||
break;
|
||||
|
||||
case AMOUNT:
|
||||
out << const_cast<value_t&>(*this).as_amount_lval();
|
||||
out << as_amount();
|
||||
break;
|
||||
|
||||
case STRING:
|
||||
out << const_cast<value_t&>(*this).as_string_lval();
|
||||
out << as_string();
|
||||
break;
|
||||
|
||||
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;
|
||||
|
||||
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()
|
||||
{
|
||||
if (! desc.empty())
|
||||
out << desc << std::endl;
|
||||
|
||||
balance_t * ptr = NULL;
|
||||
const balance_t * ptr = NULL;
|
||||
|
||||
out << std::right;
|
||||
out.width(20);
|
||||
|
||||
switch (bal.type()) {
|
||||
case value_t::BOOLEAN:
|
||||
out << (const_cast<value_t&>(bal).as_boolean_lval() ? "true" : "false");
|
||||
out << (bal.as_boolean() ? "true" : "false");
|
||||
break;
|
||||
case value_t::INTEGER:
|
||||
out << const_cast<value_t&>(bal).as_long_lval();
|
||||
out << bal.as_long();
|
||||
break;
|
||||
case value_t::DATETIME:
|
||||
out << const_cast<value_t&>(bal).as_datetime_lval();
|
||||
out << bal.as_datetime();
|
||||
break;
|
||||
case value_t::AMOUNT:
|
||||
out << const_cast<value_t&>(bal).as_amount_lval();
|
||||
out << bal.as_amount();
|
||||
break;
|
||||
case value_t::BALANCE:
|
||||
ptr = &(const_cast<value_t&>(bal).as_balance_lval());
|
||||
ptr = &bal.as_balance();
|
||||
// fall through...
|
||||
|
||||
case value_t::BALANCE_PAIR:
|
||||
if (! ptr)
|
||||
ptr = &(const_cast<value_t&>(bal).as_balance_pair_lval().quantity());
|
||||
ptr = &bal.as_balance_pair().quantity();
|
||||
|
||||
ptr->print(out, 20);
|
||||
break;
|
||||
|
|
|
|||
71
value.h
71
value.h
|
|
@ -433,8 +433,8 @@ private:
|
|||
|
||||
public:
|
||||
/**
|
||||
* Data manipulation methods. A value object may be truth tested
|
||||
* for the existence of every type it can contain:
|
||||
* Data manipulation methods. A value object may be truth tested for the
|
||||
* existence of every type it can contain:
|
||||
*
|
||||
* is_boolean()
|
||||
* is_long()
|
||||
|
|
@ -446,20 +446,19 @@ public:
|
|||
* is_sequence()
|
||||
* is_pointer()
|
||||
*
|
||||
* There are corresponding as_*() methods that represent a value as
|
||||
* a reference to its underlying type. For example, as_integer()
|
||||
* returns a reference to a "const long".
|
||||
* There are corresponding as_*() methods that represent a value as a
|
||||
* reference to its underlying type. For example, as_long() returns a
|
||||
* reference to a "const long".
|
||||
*
|
||||
* There are also as_*_lval() methods, which represent the
|
||||
* underlying data as a reference to a non-const type. The
|
||||
* difference here is that an _lval() call causes the underlying
|
||||
* data to be fully copied before the resulting reference is
|
||||
* returned.
|
||||
* There are also as_*_lval() methods, which represent the underlying data
|
||||
* as a reference to a non-const type. The difference here is that an
|
||||
* _lval() call causes the underlying data to be fully copied before the
|
||||
* resulting reference is returned.
|
||||
*
|
||||
* Lastly, there are corresponding set_*(data) methods for directly
|
||||
* assigning data of a particular type, rather than using the
|
||||
* regular assignment operator (whose implementation simply calls
|
||||
* the various set_ methods).
|
||||
* assigning data of a particular type, rather than using the regular
|
||||
* assignment operator (whose implementation simply calls the various set_
|
||||
* methods).
|
||||
*/
|
||||
bool is_boolean() const {
|
||||
return is_type(BOOLEAN);
|
||||
|
|
@ -518,13 +517,18 @@ public:
|
|||
amount_t& as_amount_lval() {
|
||||
assert(is_amount());
|
||||
_dup();
|
||||
return *(amount_t *) storage->data;
|
||||
amount_t& amt(*(amount_t *) storage->data);
|
||||
assert(amt.valid());
|
||||
return amt;
|
||||
}
|
||||
const amount_t& as_amount() const {
|
||||
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) {
|
||||
assert(val.valid());
|
||||
set_type(AMOUNT);
|
||||
new((amount_t *) storage->data) amount_t(val);
|
||||
}
|
||||
|
|
@ -535,13 +539,18 @@ public:
|
|||
balance_t& as_balance_lval() {
|
||||
assert(is_balance());
|
||||
_dup();
|
||||
return **(balance_t **) storage->data;
|
||||
balance_t& bal(**(balance_t **) storage->data);
|
||||
assert(bal.valid());
|
||||
return bal;
|
||||
}
|
||||
const balance_t& as_balance() const {
|
||||
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) {
|
||||
assert(val.valid());
|
||||
set_type(BALANCE);
|
||||
*(balance_t **) storage->data = new balance_t(val);
|
||||
}
|
||||
|
|
@ -552,13 +561,18 @@ public:
|
|||
balance_pair_t& as_balance_pair_lval() {
|
||||
assert(is_balance_pair());
|
||||
_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 {
|
||||
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) {
|
||||
assert(val.valid());
|
||||
set_type(BALANCE_PAIR);
|
||||
*(balance_pair_t **) storage->data = new balance_pair_t(val);
|
||||
}
|
||||
|
|
@ -579,6 +593,10 @@ public:
|
|||
set_type(STRING);
|
||||
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 {
|
||||
return is_type(SEQUENCE);
|
||||
|
|
@ -617,7 +635,7 @@ public:
|
|||
_dup();
|
||||
return *any_cast<T *>(*(boost::any *) storage->data);
|
||||
}
|
||||
boost::any as_any_pointer() const {
|
||||
const boost::any& as_any_pointer() const {
|
||||
assert(is_pointer());
|
||||
return *(boost::any *) storage->data;
|
||||
}
|
||||
|
|
@ -730,13 +748,13 @@ public:
|
|||
if (! is_sequence())
|
||||
in_place_cast(SEQUENCE);
|
||||
|
||||
value_t::sequence_t& seq(as_sequence_lval());
|
||||
if (! val.is_sequence()) {
|
||||
if (! val.is_null())
|
||||
seq.push_back(val);
|
||||
as_sequence_lval().push_back(val);
|
||||
} else {
|
||||
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 {
|
||||
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)
|
||||
_reset();
|
||||
else if (new_size == 1)
|
||||
*this = as_sequence().front();
|
||||
*this = seq.front();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -811,6 +830,8 @@ public:
|
|||
/**
|
||||
* Debugging methods.
|
||||
*/
|
||||
|
||||
bool valid() const;
|
||||
};
|
||||
|
||||
#define NULL_VALUE (value_t())
|
||||
|
|
|
|||
2
walk.cc
2
walk.cc
|
|
@ -230,7 +230,7 @@ void handle_value(const value_t& value,
|
|||
// fall through...
|
||||
|
||||
case value_t::AMOUNT:
|
||||
xact.amount = temp.as_amount_lval();
|
||||
xact.amount = temp.as_amount();
|
||||
break;
|
||||
|
||||
case value_t::BALANCE:
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue