summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xacprep32
-rw-r--r--amount.cc52
-rw-r--r--balpair.h2
-rw-r--r--binary.cc8
-rw-r--r--derive.cc2
-rw-r--r--format.cc36
-rw-r--r--journal.cc18
-rw-r--r--parsexp.cc164
-rw-r--r--parsexp.h20
-rw-r--r--reconcile.cc6
-rw-r--r--textual.cc26
-rw-r--r--valexpr.cc46
-rw-r--r--valexpr.h58
-rw-r--r--value.cc49
-rw-r--r--value.h71
-rw-r--r--walk.cc2
16 files changed, 381 insertions, 211 deletions
diff --git a/acprep b/acprep
index 90da3d6c..7276ba05 100755
--- a/acprep
+++ b/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
diff --git a/amount.cc b/amount.cc
index 312c67c6..4fa57b3c 100644
--- a/amount.cc
+++ b/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;
diff --git a/balpair.h b/balpair.h
index 96ccf42a..53acb701 100644
--- a/balpair.h
+++ b/balpair.h
@@ -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;
diff --git a/binary.cc b/binary.cc
index 4b5786d1..c1c2321e 100644
--- a/binary.cc
+++ b/binary.cc
@@ -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:
diff --git a/derive.cc b/derive.cc
index 06581f96..35f89788 100644
--- a/derive.cc
+++ b/derive.cc
@@ -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());
}
}
diff --git a/format.cc b/format.cc
index a2af245b..e25d73fa 100644
--- a/format.cc
+++ b/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);
diff --git a/journal.cc b/journal.cc
index 4186bf35..142eb799 100644
--- a/journal.cc
+++ b/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);
diff --git a/parsexp.cc b/parsexp.cc
index 57a2b7b4..b410965c 100644
--- a/parsexp.cc
+++ b/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);
diff --git a/parsexp.h b/parsexp.h
index 9509b2fd..1ed71e66 100644
--- a/parsexp.h
+++ b/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);
diff --git a/reconcile.cc b/reconcile.cc
index b92ff9f1..8a1be816 100644
--- a/reconcile.cc
+++ b/reconcile.cc
@@ -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 {
diff --git a/textual.cc b/textual.cc
index f89da45f..f928db88 100644
--- a/textual.cc
+++ b/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");
-
- 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));
+ assert(xact->cost->valid());
+
+ // 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))
diff --git a/valexpr.cc b/valexpr.cc
index 509c6fa1..2c087aa3 100644
--- a/valexpr.cc
+++ b/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;
}
diff --git a/valexpr.h b/valexpr.h
index c5796b88..62b85c5a 100644
--- a/valexpr.h
+++ b/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:
diff --git a/value.cc b/value.cc
index 97efe6d4..70bbdc6f 100644
--- a/value.cc
+++ b/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;
diff --git a/value.h b/value.h
index 721d6d63..54f8a502 100644
--- a/value.h
+++ b/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())
diff --git a/walk.cc b/walk.cc
index 34888a8c..75917388 100644
--- a/walk.cc
+++ b/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: