Revised the way that parsing flags get passed around.

This commit is contained in:
John Wiegley 2009-01-29 02:24:25 -04:00
parent 5b388af626
commit 8b75b5cbfb
12 changed files with 178 additions and 94 deletions

View file

@ -149,9 +149,6 @@ EXC_TRANSLATOR(amount_error)
void export_amount()
{
scope().attr("AMOUNT_PARSE_NO_MIGRATE") = AMOUNT_PARSE_NO_MIGRATE;
scope().attr("AMOUNT_PARSE_NO_REDUCE") = AMOUNT_PARSE_NO_REDUCE;
class_< amount_t > ("Amount")
.def("initialize", &amount_t::initialize)
.staticmethod("initialize")
@ -385,6 +382,13 @@ internal precision.")
.def("valid", &amount_t::valid)
;
enum_< amount_t::parse_flags_enum_t >("AmountParse")
.value("PARSE_DEFAULT", amount_t::PARSE_DEFAULT)
.value("PARSE_NO_MIGRATE", amount_t::PARSE_NO_MIGRATE)
.value("PARSE_NO_REDUCE", amount_t::PARSE_NO_REDUCE)
.value("PARSE_SOFT_FAIL", amount_t::PARSE_SOFT_FAIL)
;
register_optional_to_python<amount_t>();
#ifdef HAVE_GDTOA

View file

@ -859,7 +859,7 @@ namespace {
}
}
bool amount_t::parse(std::istream& in, flags_t flags)
bool amount_t::parse(std::istream& in, const parse_flags_t& flags)
{
// The possible syntax for an amount is:
//
@ -911,7 +911,7 @@ bool amount_t::parse(std::istream& in, flags_t flags)
}
if (quant.empty()) {
if (flags & AMOUNT_PARSE_SOFT_FAIL)
if (flags.has_flags(PARSE_SOFT_FAIL))
return false;
else
throw_(amount_error, "No quantity specified for amount");
@ -983,7 +983,7 @@ bool amount_t::parse(std::istream& in, flags_t flags)
// Set the commodity's flags and precision accordingly
if (commodity_ && ! (flags & AMOUNT_PARSE_NO_MIGRATE)) {
if (commodity_ && ! flags.has_flags(PARSE_NO_MIGRATE)) {
commodity().add_flags(comm_flags);
if (quantity->prec > commodity().precision())
@ -992,7 +992,7 @@ bool amount_t::parse(std::istream& in, flags_t flags)
// Setup the amount's own flags
if (flags & AMOUNT_PARSE_NO_MIGRATE)
if (flags.has_flags(PARSE_NO_MIGRATE))
quantity->add_flags(BIGINT_KEEP_PREC);
// Now we have the final number. Remove commas and periods, if
@ -1020,7 +1020,7 @@ bool amount_t::parse(std::istream& in, flags_t flags)
if (negative)
in_place_negate();
if (! (flags & AMOUNT_PARSE_NO_REDUCE))
if (! flags.has_flags(PARSE_NO_REDUCE))
in_place_reduce();
safe_holder.release(); // `this->quantity' owns the pointer
@ -1035,8 +1035,8 @@ void amount_t::parse_conversion(const string& larger_str,
{
amount_t larger, smaller;
larger.parse(larger_str, AMOUNT_PARSE_NO_REDUCE);
smaller.parse(smaller_str, AMOUNT_PARSE_NO_REDUCE);
larger.parse(larger_str, PARSE_NO_REDUCE);
smaller.parse(smaller_str, PARSE_NO_REDUCE);
larger *= smaller.number();
@ -1324,8 +1324,8 @@ void amount_t::read(const char *& data,
quantity->prec = *reinterpret_cast<precision_t *>(const_cast<char *>(data));
data += sizeof(precision_t);
quantity->set_flags(*reinterpret_cast<flags_t *>(const_cast<char *>(data)));
data += sizeof(flags_t);
quantity->set_flags(*reinterpret_cast<bigint_t::flags_t *>(const_cast<char *>(data)));
data += sizeof(bigint_t::flags_t);
if (byte == 2)
quantity->add_flags(BIGINT_BULK_ALLOC);

View file

@ -633,17 +633,36 @@ public:
* between scaling commodity values. For example, Ledger uses it to
* define the relationships among various time values:
*
* @code
* amount_t::parse_conversion("1.0m", "60s"); // a minute is 60 seconds
* amount_t::parse_conversion("1.0h", "60m"); // an hour is 60 minutes
* @endcode
*/
#define AMOUNT_PARSE_NO_MIGRATE 0x01
#define AMOUNT_PARSE_NO_REDUCE 0x02
#define AMOUNT_PARSE_SOFT_FAIL 0x04
enum parse_flags_enum_t {
PARSE_DEFAULT = 0x00,
PARSE_NO_MIGRATE = 0x01,
PARSE_NO_REDUCE = 0x02,
PARSE_SOFT_FAIL = 0x04
};
typedef uint_least8_t flags_t;
typedef basic_flags_t<parse_flags_enum_t, uint_least8_t> parse_flags_t;
bool parse(std::istream& in, flags_t flags = 0);
bool parse(const string& str, flags_t flags = 0) {
/**
* The method parse() is used to parse an amount from an input stream
* or a string. A global operator>>() is also defined which simply
* calls parse on the input stream. The parse() method has two forms:
*
* parse(istream, flags_t) parses an amount from the given input
* stream.
*
* parse(string, flags_t) parses an amount from the given string.
*
* parse(string, flags_t) also parses an amount from a string.
*/
bool parse(std::istream& in,
const parse_flags_t& flags = PARSE_DEFAULT);
bool parse(const string& str,
const parse_flags_t& flags = PARSE_DEFAULT) {
std::istringstream stream(str);
bool result = parse(stream, flags);
assert(stream.eof());

View file

@ -630,7 +630,7 @@ void annotation_t::parse(std::istream& in)
throw_(amount_error, "Commodity price lacks closing brace");
amount_t temp;
temp.parse(buf, AMOUNT_PARSE_NO_MIGRATE);
temp.parse(buf, amount_t::PARSE_NO_MIGRATE);
temp.in_place_reduce();
// Since this price will maintain its own precision, make sure

View file

@ -48,7 +48,7 @@ expr_t::expr_t(const expr_t& other)
TRACE_CTOR(expr_t, "copy");
}
expr_t::expr_t(const string& _str, const unsigned int flags)
expr_t::expr_t(const string& _str, const uint_least8_t flags)
: str(_str), compiled(false)
{
TRACE_CTOR(expr_t, "const string&");
@ -57,7 +57,7 @@ expr_t::expr_t(const string& _str, const unsigned int flags)
ptr = parser->parse(str, flags);
}
expr_t::expr_t(std::istream& in, const unsigned int flags)
expr_t::expr_t(std::istream& in, const uint_least8_t flags)
: compiled(false)
{
TRACE_CTOR(expr_t, "std::istream&");

View file

@ -57,6 +57,16 @@ public:
class op_t;
typedef intrusive_ptr<op_t> ptr_op_t;
enum parse_flags_enum_t {
PARSE_NORMAL = 0x00,
PARSE_PARTIAL = 0x01,
PARSE_SINGLE = 0x02,
PARSE_NO_MIGRATE = 0x04,
PARSE_NO_REDUCE = 0x08,
PARSE_NO_ASSIGN = 0x10,
PARSE_NO_DATES = 0x20
};
private:
ptr_op_t ptr;
string str;
@ -75,8 +85,8 @@ public:
expr_t(const expr_t& other);
expr_t(const ptr_op_t& _ptr, const string& _str = "");
expr_t(const string& _str, const unsigned int flags = 0);
expr_t(std::istream& in, const unsigned int flags = 0);
expr_t(const string& _str, const uint_least8_t flags = 0);
expr_t(std::istream& in, const uint_least8_t flags = 0);
virtual ~expr_t() throw();

View file

@ -32,7 +32,7 @@
#ifndef _FLAGS_H
#define _FLAGS_H
template <typename T = boost::uint_least8_t>
template <typename T = boost::uint_least8_t, typename U = T>
class supports_flags
{
public:
@ -42,7 +42,7 @@ protected:
flags_t _flags;
public:
supports_flags() : _flags(0) {
supports_flags() : _flags(static_cast<T>(0)) {
TRACE_CTOR(supports_flags, "");
}
supports_flags(const supports_flags& arg) : _flags(arg._flags) {
@ -66,13 +66,60 @@ public:
_flags = arg;
}
void clear_flags() {
_flags = 0;
_flags = static_cast<T>(0);
}
void add_flags(const flags_t arg) {
_flags |= arg;
_flags = static_cast<T>(static_cast<U>(_flags) | static_cast<U>(arg));
}
void drop_flags(const flags_t arg) {
_flags &= ~arg;
_flags = static_cast<T>(static_cast<U>(_flags) & static_cast<U>(~arg));
}
};
template <typename T = boost::uint_least8_t, typename U = T>
class basic_flags_t : public supports_flags<T, U>
{
public:
basic_flags_t() {
TRACE_CTOR(basic_flags_t, "");
}
basic_flags_t(const T& bits) {
TRACE_CTOR(basic_flags_t, "const T&");
set_flags(bits);
}
basic_flags_t(const U& bits) {
TRACE_CTOR(basic_flags_t, "const U&");
set_flags(static_cast<T>(bits));
}
~basic_flags_t() throw() {
TRACE_DTOR(basic_flags_t);
}
basic_flags_t& operator=(const basic_flags_t& other) {
set_flags(other.flags());
return *this;
}
basic_flags_t& operator=(const T& bits) {
set_flags(bits);
return *this;
}
operator T() const {
return supports_flags<T, U>::flags();
}
operator U() const {
return supports_flags<T, U>::flags();
}
basic_flags_t plus_flags(const T& arg) const {
basic_flags_t temp(*this);
temp.add_flags(arg);
return temp;
}
basic_flags_t minus_flags(const T& arg) const {
basic_flags_t temp(*this);
temp.drop_flags(arg);
return temp;
}
};

View file

@ -31,7 +31,6 @@
#include "format.h"
#include "account.h"
#include "parser.h"
namespace ledger {
@ -213,7 +212,7 @@ format_t::element_t * format_t::parse_elements(const string& fmt)
std::istringstream str(p);
current->type = element_t::EXPR;
string temp(p);
current->expr.parse(str, EXPR_PARSE_SINGLE, &temp);
current->expr.parse(str, expr_t::PARSE_SINGLE, &temp);
if (str.eof()) {
current->expr.set_text(p);
p += std::strlen(p);

View file

@ -34,8 +34,8 @@
namespace ledger {
expr_t::ptr_op_t
expr_t::parser_t::parse_value_term(std::istream& in,
const flags_t tflags) const
expr_t::parser_t::parse_value_term(std::istream& in,
const parse_flags_t& tflags) const
{
ptr_op_t node;
@ -66,7 +66,7 @@ expr_t::parser_t::parse_value_term(std::istream& in,
node = call_node;
push_token(tok); // let the parser see it again
node->set_right(parse_value_expr(in, tflags | EXPR_PARSE_SINGLE));
node->set_right(parse_value_expr(in, tflags.plus_flags(PARSE_SINGLE)));
} else {
push_token(tok);
}
@ -74,8 +74,7 @@ expr_t::parser_t::parse_value_term(std::istream& in,
}
case token_t::LPAREN:
node = parse_value_expr(in, (tflags | EXPR_PARSE_PARTIAL) &
~EXPR_PARSE_SINGLE);
node = parse_value_expr(in, tflags.plus_flags(PARSE_PARTIAL).minus_flags(PARSE_SINGLE));
tok = next_token(in, tflags);
if (tok.kind != token_t::RPAREN)
tok.expected(')');
@ -91,7 +90,7 @@ expr_t::parser_t::parse_value_term(std::istream& in,
expr_t::ptr_op_t
expr_t::parser_t::parse_unary_expr(std::istream& in,
const flags_t tflags) const
const parse_flags_t& tflags) const
{
ptr_op_t node;
@ -143,11 +142,11 @@ expr_t::parser_t::parse_unary_expr(std::istream& in,
expr_t::ptr_op_t
expr_t::parser_t::parse_mul_expr(std::istream& in,
const flags_t tflags) const
const parse_flags_t& tflags) const
{
ptr_op_t node(parse_unary_expr(in, tflags));
if (node && ! (tflags & EXPR_PARSE_SINGLE)) {
if (node && ! tflags.has_flags(PARSE_SINGLE)) {
token_t& tok = next_token(in, tflags);
if (tok.kind == token_t::STAR || tok.kind == token_t::KW_DIV) {
@ -169,11 +168,11 @@ expr_t::parser_t::parse_mul_expr(std::istream& in,
expr_t::ptr_op_t
expr_t::parser_t::parse_add_expr(std::istream& in,
const flags_t tflags) const
const parse_flags_t& tflags) const
{
ptr_op_t node(parse_mul_expr(in, tflags));
if (node && ! (tflags & EXPR_PARSE_SINGLE)) {
if (node && ! tflags.has_flags(PARSE_SINGLE)) {
token_t& tok = next_token(in, tflags);
if (tok.kind == token_t::PLUS ||
@ -196,19 +195,19 @@ expr_t::parser_t::parse_add_expr(std::istream& in,
expr_t::ptr_op_t
expr_t::parser_t::parse_logic_expr(std::istream& in,
const flags_t tflags) const
const parse_flags_t& tflags) const
{
ptr_op_t node(parse_add_expr(in, tflags));
if (node && ! (tflags & EXPR_PARSE_SINGLE)) {
op_t::kind_t kind = op_t::LAST;
flags_t _flags = tflags;
token_t& tok = next_token(in, tflags);
bool negate = false;
if (node && ! tflags.has_flags(PARSE_SINGLE)) {
op_t::kind_t kind = op_t::LAST;
parse_flags_t _flags = tflags;
token_t& tok = next_token(in, tflags);
bool negate = false;
switch (tok.kind) {
case token_t::EQUAL:
if (tflags & EXPR_PARSE_NO_ASSIGN)
if (tflags.has_flags(PARSE_NO_ASSIGN))
tok.rewind(in);
else
kind = op_t::O_EQ;
@ -264,11 +263,11 @@ expr_t::parser_t::parse_logic_expr(std::istream& in,
expr_t::ptr_op_t
expr_t::parser_t::parse_and_expr(std::istream& in,
const flags_t tflags) const
const parse_flags_t& tflags) const
{
ptr_op_t node(parse_logic_expr(in, tflags));
if (node && ! (tflags & EXPR_PARSE_SINGLE)) {
if (node && ! tflags.has_flags(PARSE_SINGLE)) {
token_t& tok = next_token(in, tflags);
if (tok.kind == token_t::KW_AND) {
@ -288,11 +287,11 @@ expr_t::parser_t::parse_and_expr(std::istream& in,
expr_t::ptr_op_t
expr_t::parser_t::parse_or_expr(std::istream& in,
const flags_t tflags) const
const parse_flags_t& tflags) const
{
ptr_op_t node(parse_and_expr(in, tflags));
if (node && ! (tflags & EXPR_PARSE_SINGLE)) {
if (node && ! tflags.has_flags(PARSE_SINGLE)) {
token_t& tok = next_token(in, tflags);
if (tok.kind == token_t::KW_OR) {
@ -312,11 +311,11 @@ expr_t::parser_t::parse_or_expr(std::istream& in,
expr_t::ptr_op_t
expr_t::parser_t::parse_querycolon_expr(std::istream& in,
const flags_t tflags) const
const parse_flags_t& tflags) const
{
ptr_op_t node(parse_or_expr(in, tflags));
if (node && ! (tflags & EXPR_PARSE_SINGLE)) {
if (node && ! tflags.has_flags(PARSE_SINGLE)) {
token_t& tok = next_token(in, tflags);
if (tok.kind == token_t::QUERY) {
@ -348,11 +347,11 @@ expr_t::parser_t::parse_querycolon_expr(std::istream& in,
expr_t::ptr_op_t
expr_t::parser_t::parse_value_expr(std::istream& in,
const flags_t tflags) const
const parse_flags_t& tflags) const
{
ptr_op_t node(parse_querycolon_expr(in, tflags));
if (node && ! (tflags & EXPR_PARSE_SINGLE)) {
if (node && ! tflags.has_flags(PARSE_SINGLE)) {
token_t& tok = next_token(in, tflags);
if (tok.kind == token_t::COMMA) {
@ -367,14 +366,14 @@ expr_t::parser_t::parse_value_expr(std::istream& in,
}
if (tok.kind != token_t::TOK_EOF) {
if (tflags & EXPR_PARSE_PARTIAL)
if (tflags.has_flags(PARSE_PARTIAL))
push_token(tok);
else
tok.unexpected();
}
}
else if (! (tflags & (EXPR_PARSE_PARTIAL |
EXPR_PARSE_SINGLE))) {
else if (! tflags.has_flags(PARSE_PARTIAL) &&
! tflags.has_flags(PARSE_SINGLE)) {
throw_(parse_error, "Failed to parse value expression");
}
@ -382,7 +381,7 @@ expr_t::parser_t::parse_value_expr(std::istream& in,
}
expr_t::ptr_op_t
expr_t::parser_t::parse(std::istream& in, const flags_t flags,
expr_t::parser_t::parse(std::istream& in, const parse_flags_t& flags,
const string * original_string)
{
try {

View file

@ -39,22 +39,14 @@ namespace ledger {
class expr_t::parser_t : public noncopyable
{
#define EXPR_PARSE_NORMAL 0x00
#define EXPR_PARSE_PARTIAL 0x01
#define EXPR_PARSE_SINGLE 0x02
#define EXPR_PARSE_NO_MIGRATE 0x04
#define EXPR_PARSE_NO_REDUCE 0x08
#define EXPR_PARSE_NO_ASSIGN 0x10
#define EXPR_PARSE_NO_DATES 0x20
public:
typedef uint_least8_t flags_t;
typedef basic_flags_t<parse_flags_enum_t, uint_least8_t> parse_flags_t;
private:
mutable token_t lookahead;
mutable bool use_lookahead;
token_t& next_token(std::istream& in, flags_t tflags) const {
token_t& next_token(std::istream& in, const parse_flags_t& tflags) const {
if (use_lookahead)
use_lookahead = false;
else
@ -70,15 +62,24 @@ private:
use_lookahead = true;
}
ptr_op_t parse_value_term(std::istream& in, const flags_t flags) const;
ptr_op_t parse_unary_expr(std::istream& in, const flags_t flags) const;
ptr_op_t parse_mul_expr(std::istream& in, const flags_t flags) const;
ptr_op_t parse_add_expr(std::istream& in, const flags_t flags) const;
ptr_op_t parse_logic_expr(std::istream& in, const flags_t flags) const;
ptr_op_t parse_and_expr(std::istream& in, const flags_t flags) const;
ptr_op_t parse_or_expr(std::istream& in, const flags_t flags) const;
ptr_op_t parse_querycolon_expr(std::istream& in, const flags_t flags) const;
ptr_op_t parse_value_expr(std::istream& in, const flags_t flags) const;
ptr_op_t parse_value_term(std::istream& in,
const parse_flags_t& flags) const;
ptr_op_t parse_unary_expr(std::istream& in,
const parse_flags_t& flags) const;
ptr_op_t parse_mul_expr(std::istream& in,
const parse_flags_t& flags) const;
ptr_op_t parse_add_expr(std::istream& in,
const parse_flags_t& flags) const;
ptr_op_t parse_logic_expr(std::istream& in,
const parse_flags_t& flags) const;
ptr_op_t parse_and_expr(std::istream& in,
const parse_flags_t& flags) const;
ptr_op_t parse_or_expr(std::istream& in,
const parse_flags_t& flags) const;
ptr_op_t parse_querycolon_expr(std::istream& in,
const parse_flags_t& flags) const;
ptr_op_t parse_value_expr(std::istream& in,
const parse_flags_t& flags) const;
public:
parser_t() : use_lookahead(false) {
@ -88,9 +89,11 @@ public:
TRACE_DTOR(parser_t);
}
ptr_op_t parse(std::istream& in, const flags_t flags = EXPR_PARSE_NORMAL,
const string * original_string = NULL);
ptr_op_t parse(string& str, const flags_t flags = EXPR_PARSE_NORMAL) {
ptr_op_t parse(std::istream& in,
const parse_flags_t& flags = PARSE_NORMAL,
const string * original_string = NULL);
ptr_op_t parse(const string& str,
const parse_flags_t& flags = PARSE_NORMAL) {
std::istringstream stream(str);
return parse(stream, flags, &str);
}

View file

@ -84,9 +84,9 @@ namespace {
optional<expr_t> parse_amount_expr(std::istream& in,
amount_t& amount,
xact_t * xact,
unsigned short flags = 0)
uint_least8_t flags = 0)
{
expr_t expr(in, flags | EXPR_PARSE_PARTIAL);
expr_t expr(in, flags | static_cast<uint_least8_t>(expr_t::PARSE_PARTIAL));
DEBUG("textual.parse", "line " << linenum << ": " <<
"Parsed an amount expression");
@ -204,7 +204,8 @@ xact_t * parse_xact(char * line, account_t * account, entry_t * entry = NULL)
xact->amount_expr =
parse_amount_expr(in, xact->amount, xact.get(),
EXPR_PARSE_NO_REDUCE | EXPR_PARSE_NO_ASSIGN);
static_cast<uint_least8_t>(expr_t::PARSE_NO_REDUCE) |
static_cast<uint_least8_t>(expr_t::PARSE_NO_ASSIGN));
saw_amount = true;
if (! xact->amount.is_null()) {
@ -257,8 +258,8 @@ xact_t * parse_xact(char * line, account_t * account, entry_t * entry = NULL)
xact->cost_expr =
parse_amount_expr(in, *xact->cost, xact.get(),
EXPR_PARSE_NO_MIGRATE |
EXPR_PARSE_NO_ASSIGN);
static_cast<uint_least8_t>(expr_t::PARSE_NO_MIGRATE) |
static_cast<uint_least8_t>(expr_t::PARSE_NO_ASSIGN));
if (xact->cost_expr) {
istream_pos_type end = in.tellg();
@ -315,7 +316,7 @@ xact_t * parse_xact(char * line, account_t * account, entry_t * entry = NULL)
xact->assigned_amount_expr =
parse_amount_expr(in, *xact->assigned_amount, xact.get(),
EXPR_PARSE_NO_MIGRATE);
static_cast<uint_least8_t>(expr_t::PARSE_NO_MIGRATE));
if (xact->assigned_amount->is_null())
throw parse_error

View file

@ -198,7 +198,7 @@ void expr_t::token_t::next(std::istream& in, const uint_least8_t pflags)
case '{': {
in.get(c);
amount_t temp;
temp.parse(in, AMOUNT_PARSE_NO_MIGRATE);
temp.parse(in, amount_t::PARSE_NO_MIGRATE);
in.get(c);
if (c != '}')
expected('}', c);
@ -343,15 +343,17 @@ void expr_t::token_t::next(std::istream& in, const uint_least8_t pflags)
// When in relaxed parsing mode, we want to migrate commodity flags
// so that any precision specified by the user updates the current
// maximum displayed precision.
amount_t::flags_t parse_flags = 0;
if (pflags & EXPR_PARSE_NO_MIGRATE)
parse_flags |= AMOUNT_PARSE_NO_MIGRATE;
if (pflags & EXPR_PARSE_NO_REDUCE)
parse_flags |= AMOUNT_PARSE_NO_REDUCE;
amount_t::parse_flags_t parse_flags;
parser_t::parse_flags_t pflags_copy(pflags);
if (pflags_copy.has_flags(PARSE_NO_MIGRATE))
parse_flags.add_flags(amount_t::PARSE_NO_MIGRATE);
if (pflags_copy.has_flags(PARSE_NO_REDUCE))
parse_flags.add_flags(amount_t::PARSE_NO_REDUCE);
try {
amount_t temp;
if (! temp.parse(in, parse_flags | AMOUNT_PARSE_SOFT_FAIL)) {
if (! temp.parse(in, parse_flags.plus_flags(amount_t::PARSE_SOFT_FAIL))) {
// If the amount had no commodity, it must be an unambiguous
// variable reference