Some minor refactoring of the textual parser
This commit is contained in:
parent
40eae8bf94
commit
69da18cd30
3 changed files with 145 additions and 176 deletions
14
src/post.cc
14
src/post.cc
|
|
@ -417,6 +417,20 @@ expr_t::ptr_op_t post_t::lookup(const symbol_t::kind_t kind,
|
||||||
return item_t::lookup(kind, name);
|
return item_t::lookup(kind, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
amount_t post_t::resolve_expr(scope_t& scope, expr_t& expr)
|
||||||
|
{
|
||||||
|
bind_scope_t bound_scope(scope, *this);
|
||||||
|
value_t result(expr.calc(bound_scope));
|
||||||
|
if (result.is_long()) {
|
||||||
|
return result.to_amount();
|
||||||
|
} else {
|
||||||
|
if (! result.is_amount())
|
||||||
|
throw_(amount_error,
|
||||||
|
_("Amount expressions must result in a simple amount"));
|
||||||
|
return result.as_amount();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool post_t::valid() const
|
bool post_t::valid() const
|
||||||
{
|
{
|
||||||
if (! xact) {
|
if (! xact) {
|
||||||
|
|
|
||||||
|
|
@ -115,6 +115,8 @@ public:
|
||||||
virtual expr_t::ptr_op_t lookup(const symbol_t::kind_t kind,
|
virtual expr_t::ptr_op_t lookup(const symbol_t::kind_t kind,
|
||||||
const string& name);
|
const string& name);
|
||||||
|
|
||||||
|
amount_t resolve_expr(scope_t& scope, expr_t& expr);
|
||||||
|
|
||||||
bool valid() const;
|
bool valid() const;
|
||||||
|
|
||||||
struct xdata_t : public supports_flags<uint_least16_t>
|
struct xdata_t : public supports_flags<uint_least16_t>
|
||||||
|
|
|
||||||
305
src/textual.cc
305
src/textual.cc
|
|
@ -49,52 +49,26 @@
|
||||||
namespace ledger {
|
namespace ledger {
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
class instance_t : public noncopyable, public scope_t
|
typedef std::pair<commodity_t *, amount_t> fixed_rate_t;
|
||||||
|
typedef variant<account_t *, string, fixed_rate_t> state_t;
|
||||||
|
|
||||||
|
class parse_context_t : public noncopyable
|
||||||
{
|
{
|
||||||
static const std::size_t MAX_LINE = 1024;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
typedef std::pair<commodity_t *, amount_t> fixed_rate_t;
|
journal_t& journal;
|
||||||
typedef variant<account_t *, string, fixed_rate_t> state_t;
|
scope_t& scope;
|
||||||
|
std::list<state_t> state_stack;
|
||||||
std::list<state_t>& state_stack;
|
|
||||||
|
|
||||||
#if defined(TIMELOG_SUPPORT)
|
#if defined(TIMELOG_SUPPORT)
|
||||||
time_log_t& timelog;
|
time_log_t timelog;
|
||||||
#endif
|
#endif
|
||||||
instance_t * parent;
|
bool strict;
|
||||||
std::istream& in;
|
std::size_t count;
|
||||||
scope_t& scope;
|
std::size_t errors;
|
||||||
journal_t& journal;
|
std::size_t sequence;
|
||||||
account_t * master;
|
|
||||||
const path * original_file;
|
|
||||||
accounts_map account_aliases;
|
|
||||||
bool strict;
|
|
||||||
path pathname;
|
|
||||||
char linebuf[MAX_LINE + 1];
|
|
||||||
std::size_t linenum;
|
|
||||||
istream_pos_type line_beg_pos;
|
|
||||||
istream_pos_type curr_pos;
|
|
||||||
std::size_t count;
|
|
||||||
std::size_t errors;
|
|
||||||
std::size_t * global_sequence;
|
|
||||||
|
|
||||||
optional<date_t::year_type> current_year;
|
parse_context_t(journal_t& _journal, scope_t& _scope)
|
||||||
|
: journal(_journal), scope(_scope), timelog(journal),
|
||||||
instance_t(std::list<state_t>& _state_stack,
|
strict(false), count(0), errors(0), sequence(1) {}
|
||||||
#if defined(TIMELOG_SUPPORT)
|
|
||||||
time_log_t& _timelog,
|
|
||||||
#endif
|
|
||||||
std::istream& _in,
|
|
||||||
scope_t& _scope,
|
|
||||||
journal_t& _journal,
|
|
||||||
std::size_t * _global_sequence = NULL,
|
|
||||||
account_t * _master = NULL,
|
|
||||||
const path * _original_file = NULL,
|
|
||||||
bool _strict = false,
|
|
||||||
instance_t * _parent = NULL);
|
|
||||||
|
|
||||||
~instance_t();
|
|
||||||
|
|
||||||
bool front_is_account() {
|
bool front_is_account() {
|
||||||
return state_stack.front().type() == typeid(account_t *);
|
return state_stack.front().type() == typeid(account_t *);
|
||||||
|
|
@ -112,6 +86,34 @@ namespace {
|
||||||
return boost::get<account_t *>(state);
|
return boost::get<account_t *>(state);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class instance_t : public noncopyable, public scope_t
|
||||||
|
{
|
||||||
|
static const std::size_t MAX_LINE = 1024;
|
||||||
|
|
||||||
|
public:
|
||||||
|
parse_context_t& context;
|
||||||
|
instance_t * parent;
|
||||||
|
account_t * master;
|
||||||
|
accounts_map account_aliases;
|
||||||
|
const path * original_file;
|
||||||
|
path pathname;
|
||||||
|
std::istream& in;
|
||||||
|
char linebuf[MAX_LINE + 1];
|
||||||
|
std::size_t linenum;
|
||||||
|
istream_pos_type line_beg_pos;
|
||||||
|
istream_pos_type curr_pos;
|
||||||
|
|
||||||
|
optional<date_t::year_type> current_year;
|
||||||
|
|
||||||
|
instance_t(parse_context_t& _context,
|
||||||
|
std::istream& _in,
|
||||||
|
account_t * _master = NULL,
|
||||||
|
const path * _original_file = NULL,
|
||||||
|
instance_t * _parent = NULL);
|
||||||
|
|
||||||
|
~instance_t();
|
||||||
|
|
||||||
void parse();
|
void parse();
|
||||||
std::streamsize read_line(char *& line);
|
std::streamsize read_line(char *& line);
|
||||||
|
|
@ -150,7 +152,6 @@ namespace {
|
||||||
std::streamsize len,
|
std::streamsize len,
|
||||||
account_t * account,
|
account_t * account,
|
||||||
xact_t * xact,
|
xact_t * xact,
|
||||||
bool honor_strict = true,
|
|
||||||
bool defer_expr = false);
|
bool defer_expr = false);
|
||||||
|
|
||||||
bool parse_posts(account_t * account,
|
bool parse_posts(account_t * account,
|
||||||
|
|
@ -165,13 +166,13 @@ namespace {
|
||||||
const string& name);
|
const string& name);
|
||||||
};
|
};
|
||||||
|
|
||||||
void parse_amount_expr(scope_t& scope,
|
void parse_amount_expr(std::istream& in,
|
||||||
std::istream& in,
|
scope_t& scope,
|
||||||
|
post_t& post,
|
||||||
amount_t& amount,
|
amount_t& amount,
|
||||||
optional<expr_t> * amount_expr,
|
const parse_flags_t& flags = PARSE_DEFAULT,
|
||||||
post_t * post,
|
const bool defer_expr = false,
|
||||||
const parse_flags_t& flags = PARSE_DEFAULT,
|
optional<expr_t> * amount_expr = NULL)
|
||||||
const bool defer_expr = false)
|
|
||||||
{
|
{
|
||||||
expr_t expr(in, flags.plus_flags(PARSE_PARTIAL));
|
expr_t expr(in, flags.plus_flags(PARSE_PARTIAL));
|
||||||
|
|
||||||
|
|
@ -187,53 +188,27 @@ namespace {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (expr) {
|
if (expr) {
|
||||||
bind_scope_t bound_scope(scope, *post);
|
if (amount_expr)
|
||||||
if (defer_expr) {
|
|
||||||
assert(amount_expr);
|
|
||||||
*amount_expr = expr;
|
*amount_expr = expr;
|
||||||
(*amount_expr)->compile(bound_scope);
|
if (! defer_expr)
|
||||||
} else {
|
amount = post.resolve_expr(scope, expr);
|
||||||
value_t result(expr.calc(bound_scope));
|
|
||||||
if (result.is_long()) {
|
|
||||||
amount = result.to_amount();
|
|
||||||
} else {
|
|
||||||
if (! result.is_amount())
|
|
||||||
throw_(amount_error,
|
|
||||||
_("Amount expressions must result in a simple amount"));
|
|
||||||
amount = result.as_amount();
|
|
||||||
}
|
|
||||||
DEBUG("textual.parse", "The posting amount is " << amount);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
instance_t::instance_t(std::list<state_t>& _state_stack,
|
instance_t::instance_t(parse_context_t& _context,
|
||||||
#if defined(TIMELOG_SUPPORT)
|
std::istream& _in,
|
||||||
time_log_t& _timelog,
|
account_t * _master,
|
||||||
#endif
|
const path * _original_file,
|
||||||
std::istream& _in,
|
instance_t * _parent)
|
||||||
scope_t& _scope,
|
: context(_context), parent(_parent), master(_master),
|
||||||
journal_t& _journal,
|
original_file(_original_file), in(_in)
|
||||||
std::size_t * _global_sequence,
|
|
||||||
account_t * _master,
|
|
||||||
const path * _original_file,
|
|
||||||
bool _strict,
|
|
||||||
instance_t * _parent)
|
|
||||||
: state_stack(_state_stack),
|
|
||||||
#if defined(TIMELOG_SUPPORT)
|
|
||||||
timelog(_timelog),
|
|
||||||
#endif
|
|
||||||
parent(_parent), in(_in), scope(_scope),
|
|
||||||
journal(_journal), master(_master),
|
|
||||||
original_file(_original_file), strict(_strict),
|
|
||||||
global_sequence(_global_sequence)
|
|
||||||
{
|
{
|
||||||
TRACE_CTOR(instance_t, "...");
|
TRACE_CTOR(instance_t, "...");
|
||||||
|
|
||||||
if (! master)
|
if (! master)
|
||||||
master = journal.master;
|
master = context.journal.master;
|
||||||
state_stack.push_front(master);
|
context.state_stack.push_front(master);
|
||||||
|
|
||||||
if (_original_file)
|
if (_original_file)
|
||||||
pathname = *_original_file;
|
pathname = *_original_file;
|
||||||
|
|
@ -245,8 +220,8 @@ instance_t::~instance_t()
|
||||||
{
|
{
|
||||||
TRACE_DTOR(instance_t);
|
TRACE_DTOR(instance_t);
|
||||||
|
|
||||||
assert(! state_stack.empty());
|
assert(! context.state_stack.empty());
|
||||||
state_stack.pop_front();
|
context.state_stack.pop_front();
|
||||||
}
|
}
|
||||||
|
|
||||||
void instance_t::parse()
|
void instance_t::parse()
|
||||||
|
|
@ -260,8 +235,6 @@ void instance_t::parse()
|
||||||
return;
|
return;
|
||||||
|
|
||||||
linenum = 0;
|
linenum = 0;
|
||||||
errors = 0;
|
|
||||||
count = 0;
|
|
||||||
curr_pos = in.tellg();
|
curr_pos = in.tellg();
|
||||||
|
|
||||||
while (in.good() && ! in.eof()) {
|
while (in.good() && ! in.eof()) {
|
||||||
|
|
@ -290,15 +263,15 @@ void instance_t::parse()
|
||||||
if (caught_signal != NONE_CAUGHT)
|
if (caught_signal != NONE_CAUGHT)
|
||||||
throw;
|
throw;
|
||||||
|
|
||||||
string context = error_context();
|
string err_context = error_context();
|
||||||
if (! context.empty())
|
if (! err_context.empty())
|
||||||
std::cerr << context << std::endl;
|
std::cerr << err_context << std::endl;
|
||||||
|
|
||||||
if (! current_context.empty())
|
if (! current_context.empty())
|
||||||
std::cerr << current_context << std::endl;
|
std::cerr << current_context << std::endl;
|
||||||
|
|
||||||
std::cerr << _("Error: ") << err.what() << std::endl;
|
std::cerr << _("Error: ") << err.what() << std::endl;
|
||||||
errors++;
|
context.errors++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -456,14 +429,14 @@ void instance_t::clock_in_directive(char * line,
|
||||||
position.beg_line = linenum;
|
position.beg_line = linenum;
|
||||||
position.end_pos = curr_pos;
|
position.end_pos = curr_pos;
|
||||||
position.end_line = linenum;
|
position.end_line = linenum;
|
||||||
position.sequence = (*global_sequence)++;
|
position.sequence = context.sequence++;
|
||||||
|
|
||||||
time_xact_t event(position, parse_datetime(datetime, current_year),
|
time_xact_t event(position, parse_datetime(datetime, current_year),
|
||||||
p ? top_account()->find_account(p) : NULL,
|
p ? context.top_account()->find_account(p) : NULL,
|
||||||
n ? n : "",
|
n ? n : "",
|
||||||
end ? end : "");
|
end ? end : "");
|
||||||
|
|
||||||
timelog.clock_in(event);
|
context.timelog.clock_in(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
void instance_t::clock_out_directive(char * line,
|
void instance_t::clock_out_directive(char * line,
|
||||||
|
|
@ -486,15 +459,15 @@ void instance_t::clock_out_directive(char * line,
|
||||||
position.beg_line = linenum;
|
position.beg_line = linenum;
|
||||||
position.end_pos = curr_pos;
|
position.end_pos = curr_pos;
|
||||||
position.end_line = linenum;
|
position.end_line = linenum;
|
||||||
position.sequence = (*global_sequence)++;
|
position.sequence = context.sequence++;
|
||||||
|
|
||||||
time_xact_t event(position, parse_datetime(datetime, current_year),
|
time_xact_t event(position, parse_datetime(datetime, current_year),
|
||||||
p ? top_account()->find_account(p) : NULL,
|
p ? context.top_account()->find_account(p) : NULL,
|
||||||
n ? n : "",
|
n ? n : "",
|
||||||
end ? end : "");
|
end ? end : "");
|
||||||
|
|
||||||
timelog.clock_out(event);
|
context.timelog.clock_out(event);
|
||||||
count++;
|
context.count++;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // TIMELOG_SUPPORT
|
#endif // TIMELOG_SUPPORT
|
||||||
|
|
@ -509,8 +482,8 @@ void instance_t::default_commodity_directive(char * line)
|
||||||
|
|
||||||
void instance_t::default_account_directive(char * line)
|
void instance_t::default_account_directive(char * line)
|
||||||
{
|
{
|
||||||
journal.bucket = top_account()->find_account(skip_ws(line + 1));
|
context.journal.bucket = context.top_account()->find_account(skip_ws(line + 1));
|
||||||
journal.bucket->add_flags(ACCOUNT_KNOWN);
|
context.journal.bucket->add_flags(ACCOUNT_KNOWN);
|
||||||
}
|
}
|
||||||
|
|
||||||
void instance_t::price_conversion_directive(char * line)
|
void instance_t::price_conversion_directive(char * line)
|
||||||
|
|
@ -554,7 +527,7 @@ void instance_t::option_directive(char * line)
|
||||||
*p++ = '\0';
|
*p++ = '\0';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (! process_option(pathname.string(), line + 2, scope, p, line))
|
if (! process_option(pathname.string(), line + 2, context.scope, p, line))
|
||||||
throw_(option_error, _("Illegal option --%1") << line + 2);
|
throw_(option_error, _("Illegal option --%1") << line + 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -573,16 +546,16 @@ void instance_t::automated_xact_directive(char * line)
|
||||||
ae->pos->pathname = pathname;
|
ae->pos->pathname = pathname;
|
||||||
ae->pos->beg_pos = line_beg_pos;
|
ae->pos->beg_pos = line_beg_pos;
|
||||||
ae->pos->beg_line = linenum;
|
ae->pos->beg_line = linenum;
|
||||||
ae->pos->sequence = (*global_sequence)++;
|
ae->pos->sequence = context.sequence++;
|
||||||
|
|
||||||
reveal_context = false;
|
reveal_context = false;
|
||||||
|
|
||||||
if (parse_posts(top_account(), *ae.get(), true)) {
|
if (parse_posts(context.top_account(), *ae.get(), true)) {
|
||||||
reveal_context = true;
|
reveal_context = true;
|
||||||
|
|
||||||
journal.auto_xacts.push_back(ae.get());
|
context.journal.auto_xacts.push_back(ae.get());
|
||||||
|
|
||||||
ae->journal = &journal;
|
ae->journal = &context.journal;
|
||||||
ae->pos->end_pos = curr_pos;
|
ae->pos->end_pos = curr_pos;
|
||||||
ae->pos->end_line = linenum;
|
ae->pos->end_line = linenum;
|
||||||
|
|
||||||
|
|
@ -612,17 +585,17 @@ void instance_t::period_xact_directive(char * line)
|
||||||
pe->pos->pathname = pathname;
|
pe->pos->pathname = pathname;
|
||||||
pe->pos->beg_pos = line_beg_pos;
|
pe->pos->beg_pos = line_beg_pos;
|
||||||
pe->pos->beg_line = linenum;
|
pe->pos->beg_line = linenum;
|
||||||
pe->pos->sequence = (*global_sequence)++;
|
pe->pos->sequence = context.sequence++;
|
||||||
|
|
||||||
reveal_context = false;
|
reveal_context = false;
|
||||||
|
|
||||||
if (parse_posts(top_account(), *pe.get())) {
|
if (parse_posts(context.top_account(), *pe.get())) {
|
||||||
reveal_context = true;
|
reveal_context = true;
|
||||||
pe->journal = &journal;
|
pe->journal = &context.journal;
|
||||||
|
|
||||||
if (pe->finalize()) {
|
if (pe->finalize()) {
|
||||||
journal.extend_xact(pe.get());
|
context.journal.extend_xact(pe.get());
|
||||||
journal.period_xacts.push_back(pe.get());
|
context.journal.period_xacts.push_back(pe.get());
|
||||||
|
|
||||||
pe->pos->end_pos = curr_pos;
|
pe->pos->end_pos = curr_pos;
|
||||||
pe->pos->end_line = linenum;
|
pe->pos->end_line = linenum;
|
||||||
|
|
@ -648,12 +621,12 @@ void instance_t::xact_directive(char * line, std::streamsize len)
|
||||||
{
|
{
|
||||||
TRACE_START(xacts, 1, "Time spent handling transactions:");
|
TRACE_START(xacts, 1, "Time spent handling transactions:");
|
||||||
|
|
||||||
if (xact_t * xact = parse_xact(line, len, top_account())) {
|
if (xact_t * xact = parse_xact(line, len, context.top_account())) {
|
||||||
std::auto_ptr<xact_t> manager(xact);
|
std::auto_ptr<xact_t> manager(xact);
|
||||||
|
|
||||||
if (journal.add_xact(xact)) {
|
if (context.journal.add_xact(xact)) {
|
||||||
manager.release(); // it's owned by the journal now
|
manager.release(); // it's owned by the journal now
|
||||||
count++;
|
context.count++;
|
||||||
}
|
}
|
||||||
// It's perfectly valid for the journal to reject the xact, which it will
|
// It's perfectly valid for the journal to reject the xact, which it will
|
||||||
// do if the xact has no substantive effect (for example, a checking
|
// do if the xact has no substantive effect (for example, a checking
|
||||||
|
|
@ -696,22 +669,14 @@ void instance_t::include_directive(char * line)
|
||||||
|
|
||||||
ifstream stream(filename);
|
ifstream stream(filename);
|
||||||
|
|
||||||
instance_t instance(state_stack,
|
instance_t instance(context, stream, master, &filename, this);
|
||||||
#if defined(TIMELOG_SUPPORT)
|
|
||||||
timelog,
|
|
||||||
#endif
|
|
||||||
stream, scope, journal, global_sequence, master,
|
|
||||||
&filename, strict, this);
|
|
||||||
instance.parse();
|
instance.parse();
|
||||||
|
|
||||||
errors += instance.errors;
|
|
||||||
count += instance.count;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void instance_t::master_account_directive(char * line)
|
void instance_t::master_account_directive(char * line)
|
||||||
{
|
{
|
||||||
if (account_t * acct = top_account()->find_account(line))
|
if (account_t * acct = context.top_account()->find_account(line))
|
||||||
state_stack.push_front(acct);
|
context.state_stack.push_front(acct);
|
||||||
else
|
else
|
||||||
assert(! "Failed to create account");
|
assert(! "Failed to create account");
|
||||||
}
|
}
|
||||||
|
|
@ -720,21 +685,21 @@ void instance_t::end_directive(char * kind)
|
||||||
{
|
{
|
||||||
string name(kind);
|
string name(kind);
|
||||||
|
|
||||||
if ((name.empty() || name == "account") && ! front_is_account())
|
if ((name.empty() || name == "account") && ! context.front_is_account())
|
||||||
throw_(std::runtime_error,
|
throw_(std::runtime_error,
|
||||||
_("'end account' directive does not match open directive"));
|
_("'end account' directive does not match open directive"));
|
||||||
else if (name == "tag" && ! front_is_string())
|
else if (name == "tag" && ! context.front_is_string())
|
||||||
throw_(std::runtime_error,
|
throw_(std::runtime_error,
|
||||||
_("'end tag' directive does not match open directive"));
|
_("'end tag' directive does not match open directive"));
|
||||||
else if (name == "fixed" && ! front_is_fixed_rate())
|
else if (name == "fixed" && ! context.front_is_fixed_rate())
|
||||||
throw_(std::runtime_error,
|
throw_(std::runtime_error,
|
||||||
_("'end fixed' directive does not match open directive"));
|
_("'end fixed' directive does not match open directive"));
|
||||||
|
|
||||||
if (state_stack.size() <= 1)
|
if (context.state_stack.size() <= 1)
|
||||||
throw_(std::runtime_error,
|
throw_(std::runtime_error,
|
||||||
_("'end' found, but no enclosing tag or account directive"));
|
_("'end' found, but no enclosing tag or account directive"));
|
||||||
else
|
else
|
||||||
state_stack.pop_front();
|
context.state_stack.pop_front();
|
||||||
}
|
}
|
||||||
|
|
||||||
void instance_t::alias_directive(char * line)
|
void instance_t::alias_directive(char * line)
|
||||||
|
|
@ -751,7 +716,7 @@ void instance_t::alias_directive(char * line)
|
||||||
// name (e), add a reference to the account in the
|
// name (e), add a reference to the account in the
|
||||||
// `account_aliases' map, which is used by the post
|
// `account_aliases' map, which is used by the post
|
||||||
// parser to resolve alias references.
|
// parser to resolve alias references.
|
||||||
account_t * acct = top_account()->find_account(e);
|
account_t * acct = context.top_account()->find_account(e);
|
||||||
std::pair<accounts_map::iterator, bool> result
|
std::pair<accounts_map::iterator, bool> result
|
||||||
= account_aliases.insert(accounts_map::value_type(b, acct));
|
= account_aliases.insert(accounts_map::value_type(b, acct));
|
||||||
assert(result.second);
|
assert(result.second);
|
||||||
|
|
@ -763,8 +728,8 @@ void instance_t::fixed_directive(char * line)
|
||||||
if (optional<std::pair<commodity_t *, price_point_t> > price_point =
|
if (optional<std::pair<commodity_t *, price_point_t> > price_point =
|
||||||
commodity_pool_t::current_pool->parse_price_directive(trim_ws(line),
|
commodity_pool_t::current_pool->parse_price_directive(trim_ws(line),
|
||||||
true)) {
|
true)) {
|
||||||
state_stack.push_front(fixed_rate_t(price_point->first,
|
context.state_stack.push_front(fixed_rate_t(price_point->first,
|
||||||
price_point->second.price));
|
price_point->second.price));
|
||||||
} else {
|
} else {
|
||||||
throw_(std::runtime_error, _("Error in fixed directive"));
|
throw_(std::runtime_error, _("Error in fixed directive"));
|
||||||
}
|
}
|
||||||
|
|
@ -777,13 +742,13 @@ void instance_t::tag_directive(char * line)
|
||||||
if (tag.find(':') == string::npos)
|
if (tag.find(':') == string::npos)
|
||||||
tag = string(":") + tag + ":";
|
tag = string(":") + tag + ":";
|
||||||
|
|
||||||
state_stack.push_front(tag);
|
context.state_stack.push_front(tag);
|
||||||
}
|
}
|
||||||
|
|
||||||
void instance_t::define_directive(char * line)
|
void instance_t::define_directive(char * line)
|
||||||
{
|
{
|
||||||
expr_t def(skip_ws(line));
|
expr_t def(skip_ws(line));
|
||||||
def.compile(scope); // causes definitions to be established
|
def.compile(context.scope); // causes definitions to be established
|
||||||
}
|
}
|
||||||
|
|
||||||
bool instance_t::general_directive(char * line)
|
bool instance_t::general_directive(char * line)
|
||||||
|
|
@ -874,7 +839,6 @@ post_t * instance_t::parse_post(char * line,
|
||||||
std::streamsize len,
|
std::streamsize len,
|
||||||
account_t * account,
|
account_t * account,
|
||||||
xact_t * xact,
|
xact_t * xact,
|
||||||
bool honor_strict,
|
|
||||||
bool defer_expr)
|
bool defer_expr)
|
||||||
{
|
{
|
||||||
TRACE_START(post_details, 1, "Time spent parsing postings:");
|
TRACE_START(post_details, 1, "Time spent parsing postings:");
|
||||||
|
|
@ -886,7 +850,7 @@ post_t * instance_t::parse_post(char * line,
|
||||||
post->pos->pathname = pathname;
|
post->pos->pathname = pathname;
|
||||||
post->pos->beg_pos = line_beg_pos;
|
post->pos->beg_pos = line_beg_pos;
|
||||||
post->pos->beg_line = linenum;
|
post->pos->beg_line = linenum;
|
||||||
post->pos->sequence = (*global_sequence)++;
|
post->pos->sequence = context.sequence++;
|
||||||
|
|
||||||
char buf[MAX_LINE + 1];
|
char buf[MAX_LINE + 1];
|
||||||
std::strcpy(buf, line);
|
std::strcpy(buf, line);
|
||||||
|
|
@ -958,7 +922,7 @@ post_t * instance_t::parse_post(char * line,
|
||||||
if (! post->account)
|
if (! post->account)
|
||||||
post->account = account->find_account(name);
|
post->account = account->find_account(name);
|
||||||
|
|
||||||
if (honor_strict && strict && ! post->account->has_flags(ACCOUNT_KNOWN)) {
|
if (context.strict && ! post->account->has_flags(ACCOUNT_KNOWN)) {
|
||||||
if (post->_state == item_t::UNCLEARED)
|
if (post->_state == item_t::UNCLEARED)
|
||||||
warning_(_("\"%1\", line %2: Unknown account '%3'")
|
warning_(_("\"%1\", line %2: Unknown account '%3'")
|
||||||
<< pathname << linenum << post->account->fullname());
|
<< pathname << linenum << post->account->fullname());
|
||||||
|
|
@ -978,13 +942,13 @@ post_t * instance_t::parse_post(char * line,
|
||||||
if (*next != '(') // indicates a value expression
|
if (*next != '(') // indicates a value expression
|
||||||
post->amount.parse(stream, PARSE_NO_REDUCE);
|
post->amount.parse(stream, PARSE_NO_REDUCE);
|
||||||
else
|
else
|
||||||
parse_amount_expr(scope, stream, post->amount, &post->amount_expr,
|
parse_amount_expr(stream, context.scope, *post.get(), post->amount,
|
||||||
post.get(), PARSE_NO_REDUCE | PARSE_SINGLE |
|
PARSE_NO_REDUCE | PARSE_SINGLE | PARSE_NO_ASSIGN,
|
||||||
PARSE_NO_ASSIGN, defer_expr);
|
defer_expr, &post->amount_expr);
|
||||||
|
|
||||||
if (! post->amount.is_null() && post->amount.has_commodity()) {
|
if (! post->amount.is_null() && post->amount.has_commodity()) {
|
||||||
if (honor_strict && strict &&
|
if (context.strict &&
|
||||||
! post->amount.commodity().has_flags(COMMODITY_KNOWN)) {
|
! post->amount.commodity().has_flags(COMMODITY_KNOWN)) {
|
||||||
if (post->_state == item_t::UNCLEARED)
|
if (post->_state == item_t::UNCLEARED)
|
||||||
warning_(_("\"%1\", line %2: Unknown commodity '%3'")
|
warning_(_("\"%1\", line %2: Unknown commodity '%3'")
|
||||||
<< pathname << linenum << post->amount.commodity());
|
<< pathname << linenum << post->amount.commodity());
|
||||||
|
|
@ -992,7 +956,7 @@ post_t * instance_t::parse_post(char * line,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (! post->amount.has_annotation()) {
|
if (! post->amount.has_annotation()) {
|
||||||
foreach (state_t& state, state_stack) {
|
foreach (state_t& state, context.state_stack) {
|
||||||
if (state.type() == typeid(fixed_rate_t)) {
|
if (state.type() == typeid(fixed_rate_t)) {
|
||||||
fixed_rate_t& rate(boost::get<fixed_rate_t>(state));
|
fixed_rate_t& rate(boost::get<fixed_rate_t>(state));
|
||||||
if (*rate.first == post->amount.commodity()) {
|
if (*rate.first == post->amount.commodity()) {
|
||||||
|
|
@ -1040,9 +1004,8 @@ post_t * instance_t::parse_post(char * line,
|
||||||
if (*p != '(') // indicates a value expression
|
if (*p != '(') // indicates a value expression
|
||||||
post->cost->parse(cstream, PARSE_NO_MIGRATE);
|
post->cost->parse(cstream, PARSE_NO_MIGRATE);
|
||||||
else
|
else
|
||||||
parse_amount_expr(scope, cstream, *post->cost, NULL, post.get(),
|
parse_amount_expr(cstream, context.scope, *post.get(), *post->cost,
|
||||||
PARSE_NO_MIGRATE | PARSE_SINGLE | PARSE_NO_ASSIGN,
|
PARSE_NO_MIGRATE | PARSE_SINGLE | PARSE_NO_ASSIGN);
|
||||||
defer_expr);
|
|
||||||
|
|
||||||
if (post->cost->sign() < 0)
|
if (post->cost->sign() < 0)
|
||||||
throw parse_error(_("A posting's cost may not be negative"));
|
throw parse_error(_("A posting's cost may not be negative"));
|
||||||
|
|
@ -1095,9 +1058,9 @@ post_t * instance_t::parse_post(char * line,
|
||||||
if (*p != '(') // indicates a value expression
|
if (*p != '(') // indicates a value expression
|
||||||
post->assigned_amount->parse(stream, PARSE_NO_MIGRATE);
|
post->assigned_amount->parse(stream, PARSE_NO_MIGRATE);
|
||||||
else
|
else
|
||||||
parse_amount_expr(scope, stream, *post->assigned_amount, NULL,
|
parse_amount_expr(stream, context.scope, *post.get(),
|
||||||
post.get(), PARSE_SINGLE | PARSE_NO_MIGRATE,
|
*post->assigned_amount,
|
||||||
defer_expr);
|
PARSE_SINGLE | PARSE_NO_MIGRATE);
|
||||||
|
|
||||||
if (post->assigned_amount->is_null()) {
|
if (post->assigned_amount->is_null()) {
|
||||||
if (post->amount.is_null())
|
if (post->amount.is_null())
|
||||||
|
|
@ -1180,8 +1143,8 @@ post_t * instance_t::parse_post(char * line,
|
||||||
post->pos->end_pos = curr_pos;
|
post->pos->end_pos = curr_pos;
|
||||||
post->pos->end_line = linenum;
|
post->pos->end_line = linenum;
|
||||||
|
|
||||||
if (! state_stack.empty()) {
|
if (! context.state_stack.empty()) {
|
||||||
foreach (const state_t& state, state_stack)
|
foreach (const state_t& state, context.state_stack)
|
||||||
if (state.type() == typeid(string))
|
if (state.type() == typeid(string))
|
||||||
post->parse_tags(boost::get<string>(state).c_str());
|
post->parse_tags(boost::get<string>(state).c_str());
|
||||||
}
|
}
|
||||||
|
|
@ -1211,9 +1174,7 @@ bool instance_t::parse_posts(account_t * account,
|
||||||
std::streamsize len = read_line(line);
|
std::streamsize len = read_line(line);
|
||||||
assert(len > 0);
|
assert(len > 0);
|
||||||
|
|
||||||
if (post_t * post =
|
if (post_t * post = parse_post(line, len, account, NULL, defer_expr)) {
|
||||||
parse_post(line, len, account, NULL, /* honor_strict= */ false,
|
|
||||||
defer_expr)) {
|
|
||||||
xact.add_post(post);
|
xact.add_post(post);
|
||||||
added = true;
|
added = true;
|
||||||
}
|
}
|
||||||
|
|
@ -1236,7 +1197,7 @@ xact_t * instance_t::parse_xact(char * line,
|
||||||
xact->pos->pathname = pathname;
|
xact->pos->pathname = pathname;
|
||||||
xact->pos->beg_pos = line_beg_pos;
|
xact->pos->beg_pos = line_beg_pos;
|
||||||
xact->pos->beg_line = linenum;
|
xact->pos->beg_line = linenum;
|
||||||
xact->pos->sequence = (*global_sequence)++;
|
xact->pos->sequence = context.sequence++;
|
||||||
|
|
||||||
bool reveal_context = true;
|
bool reveal_context = true;
|
||||||
|
|
||||||
|
|
@ -1346,8 +1307,8 @@ xact_t * instance_t::parse_xact(char * line,
|
||||||
xact->pos->end_pos = curr_pos;
|
xact->pos->end_pos = curr_pos;
|
||||||
xact->pos->end_line = linenum;
|
xact->pos->end_line = linenum;
|
||||||
|
|
||||||
if (! state_stack.empty()) {
|
if (! context.state_stack.empty()) {
|
||||||
foreach (const state_t& state, state_stack)
|
foreach (const state_t& state, context.state_stack)
|
||||||
if (state.type() == typeid(string))
|
if (state.type() == typeid(string))
|
||||||
xact->parse_tags(boost::get<string>(state).c_str());
|
xact->parse_tags(boost::get<string>(state).c_str());
|
||||||
}
|
}
|
||||||
|
|
@ -1370,7 +1331,7 @@ xact_t * instance_t::parse_xact(char * line,
|
||||||
expr_t::ptr_op_t instance_t::lookup(const symbol_t::kind_t kind,
|
expr_t::ptr_op_t instance_t::lookup(const symbol_t::kind_t kind,
|
||||||
const string& name)
|
const string& name)
|
||||||
{
|
{
|
||||||
return scope.lookup(kind, name);
|
return context.scope.lookup(kind, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::size_t journal_t::parse(std::istream& in,
|
std::size_t journal_t::parse(std::istream& in,
|
||||||
|
|
@ -1381,19 +1342,11 @@ std::size_t journal_t::parse(std::istream& in,
|
||||||
{
|
{
|
||||||
TRACE_START(parsing_total, 1, "Total time spent parsing text:");
|
TRACE_START(parsing_total, 1, "Total time spent parsing text:");
|
||||||
|
|
||||||
std::list<instance_t::state_t> state_stack;
|
parse_context_t context(*this, scope);
|
||||||
#if defined(TIMELOG_SUPPORT)
|
context.strict = strict;
|
||||||
time_log_t timelog(*this);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
std::size_t parsing_sequence = 1;
|
instance_t instance(context, in, master, original_file);
|
||||||
instance_t parsing_instance(state_stack,
|
instance.parse();
|
||||||
#if defined(TIMELOG_SUPPORT)
|
|
||||||
timelog,
|
|
||||||
#endif
|
|
||||||
in, scope, *this, &parsing_sequence, master,
|
|
||||||
original_file, strict);
|
|
||||||
parsing_instance.parse();
|
|
||||||
|
|
||||||
TRACE_STOP(parsing_total, 1);
|
TRACE_STOP(parsing_total, 1);
|
||||||
|
|
||||||
|
|
@ -1405,10 +1358,10 @@ std::size_t journal_t::parse(std::istream& in,
|
||||||
TRACE_FINISH(instance_parse, 1); // report per-instance timers
|
TRACE_FINISH(instance_parse, 1); // report per-instance timers
|
||||||
TRACE_FINISH(parsing_total, 1);
|
TRACE_FINISH(parsing_total, 1);
|
||||||
|
|
||||||
if (parsing_instance.errors > 0)
|
if (context.errors > 0)
|
||||||
throw static_cast<int>(parsing_instance.errors);
|
throw static_cast<int>(context.errors);
|
||||||
|
|
||||||
return parsing_instance.count;
|
return context.count;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace ledger
|
} // namespace ledger
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue