summaryrefslogtreecommitdiff
path: root/src/textual.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/textual.cc')
-rw-r--r--src/textual.cc134
1 files changed, 93 insertions, 41 deletions
diff --git a/src/textual.cc b/src/textual.cc
index 95635184..a8cb844b 100644
--- a/src/textual.cc
+++ b/src/textual.cc
@@ -71,22 +71,22 @@ namespace {
class instance_t : public noncopyable, public scope_t
{
-
public:
- parse_context_stack_t& context_stack;
- parse_context_t& context;
- std::istream& in;
- instance_t * parent;
-
+ parse_context_stack_t& context_stack;
+ parse_context_t& context;
+ std::istream& in;
+ instance_t * parent;
std::list<application_t> apply_stack;
#if defined(TIMELOG_SUPPORT)
- time_log_t timelog;
+ time_log_t timelog;
#endif
instance_t(parse_context_stack_t& _context_stack,
- parse_context_t& _context, instance_t * _parent = NULL)
+ parse_context_t& _context,
+ instance_t * _parent = NULL)
: context_stack(_context_stack), context(_context),
- in(*context.stream.get()), parent(_parent), timelog(context) {}
+ in(*context.stream.get()), parent(_parent),
+ timelog(context) {}
virtual string description() {
return _("textual parser");
@@ -107,10 +107,12 @@ namespace {
return (in.good() && ! in.eof() &&
(in.peek() == ' ' || in.peek() == '\t'));
}
+#if defined(HAVE_BOOST_PYTHON)
bool peek_blank_line() {
return (in.good() && ! in.eof() &&
(in.peek() == '\n' || in.peek() == '\r'));
}
+#endif
void read_next_directive();
@@ -124,6 +126,7 @@ namespace {
void account_directive(char * line);
void account_alias_directive(account_t * account, string alias);
void account_payee_directive(account_t * account, string payee);
+ void account_value_directive(account_t * account, string expr_str);
void account_default_directive(account_t * account);
void default_account_directive(char * line);
@@ -134,6 +137,7 @@ namespace {
void commodity_directive(char * line);
void commodity_alias_directive(commodity_t& comm, string alias);
+ void commodity_value_directive(commodity_t& comm, string expr_str);
void commodity_format_directive(commodity_t& comm, string format);
void commodity_nomarket_directive(commodity_t& comm);
void commodity_default_directive(commodity_t& comm);
@@ -163,10 +167,10 @@ namespace {
void eval_directive(char * line);
void assert_directive(char * line);
void check_directive(char * line);
+ void value_directive(char * line);
-#if defined(HAVE_BOOST_PYTHON)
+ void import_directive(char * line);
void python_directive(char * line);
-#endif
post_t * parse_post(char * line,
std::streamsize len,
@@ -527,7 +531,7 @@ void instance_t::automated_xact_directive(char * line)
query.parse_args(string_value(skip_ws(line + 1)).to_sequence(),
keeper, false, true);
- std::auto_ptr<auto_xact_t> ae(new auto_xact_t(predicate_t(expr, keeper)));
+ unique_ptr<auto_xact_t> ae(new auto_xact_t(predicate_t(expr, keeper)));
ae->pos = position_t();
ae->pos->pathname = context.pathname;
ae->pos->beg_pos = context.line_beg_pos;
@@ -557,11 +561,6 @@ void instance_t::automated_xact_directive(char * line)
item->add_flags(ITEM_NOTE_ON_NEXT_LINE);
item->pos->end_pos = context.curr_pos;
item->pos->end_line++;
-
- // If there was no last_post yet, then deferred notes get applied to
- // the matched posting. Other notes get applied to the auto-generated
- // posting.
- ae->deferred_notes->back().apply_to_post = last_post;
}
else if ((remlen > 7 && *p == 'a' &&
std::strncmp(p, "assert", 6) == 0 && std::isspace(p[6])) ||
@@ -589,7 +588,7 @@ void instance_t::automated_xact_directive(char * line)
parse_post(p, len - (p - line), top_account(), NULL, true)) {
reveal_context = true;
ae->add_post(post);
- last_post = post;
+ ae->active_post = last_post = post;
}
reveal_context = true;
}
@@ -621,7 +620,7 @@ void instance_t::period_xact_directive(char * line)
try {
- std::auto_ptr<period_xact_t> pe(new period_xact_t(skip_ws(line + 1)));
+ unique_ptr<period_xact_t> pe(new period_xact_t(skip_ws(line + 1)));
pe->pos = position_t();
pe->pos->pathname = context.pathname;
pe->pos->beg_pos = context.line_beg_pos;
@@ -665,7 +664,7 @@ void instance_t::xact_directive(char * line, std::streamsize len)
TRACE_START(xacts, 1, "Time spent handling transactions:");
if (xact_t * xact = parse_xact(line, len, top_account())) {
- std::auto_ptr<xact_t> manager(xact);
+ unique_ptr<xact_t> manager(xact);
if (context.journal->add_xact(xact)) {
manager.release(); // it's owned by the journal now
@@ -874,7 +873,7 @@ void instance_t::account_directive(char * line)
char * p = skip_ws(line);
account_t * account =
context.journal->register_account(p, NULL, top_account());
- std::auto_ptr<auto_xact_t> ae;
+ unique_ptr<auto_xact_t> ae;
while (peek_whitespace_line()) {
read_line(line);
@@ -890,6 +889,9 @@ void instance_t::account_directive(char * line)
else if (keyword == "payee") {
account_payee_directive(account, b);
}
+ else if (keyword == "value") {
+ account_value_directive(account, b);
+ }
else if (keyword == "default") {
account_default_directive(account);
}
@@ -943,10 +945,14 @@ void instance_t::account_alias_directive(account_t * account, string alias)
// (account), add a reference to the account in the `account_aliases'
// map, which is used by the post parser to resolve alias references.
trim(alias);
- std::pair<accounts_map::iterator, bool> result
- = context.journal
- ->account_aliases.insert(accounts_map::value_type(alias, account));
+#if defined(DEBUG_ON)
+ std::pair<accounts_map::iterator, bool> result =
+#endif
+ context.journal->account_aliases.insert
+ (accounts_map::value_type(alias, account));
+#if defined(DEBUG_ON)
assert(result.second);
+#endif
}
void instance_t::alias_directive(char * line)
@@ -975,6 +981,11 @@ void instance_t::account_default_directive(account_t * account)
context.journal->bucket = account;
}
+void instance_t::account_value_directive(account_t * account, string expr_str)
+{
+ account->value_expr = expr_t(expr_str);
+}
+
void instance_t::payee_directive(char * line)
{
string payee = context.journal->register_payee(line, NULL);
@@ -1019,6 +1030,8 @@ void instance_t::commodity_directive(char * line)
string keyword(q);
if (keyword == "alias")
commodity_alias_directive(*commodity, b);
+ else if (keyword == "value")
+ commodity_value_directive(*commodity, b);
else if (keyword == "format")
commodity_format_directive(*commodity, b);
else if (keyword == "nomarket")
@@ -1031,17 +1044,15 @@ void instance_t::commodity_directive(char * line)
}
}
-void instance_t::commodity_alias_directive(commodity_t&, string)
+void instance_t::commodity_alias_directive(commodity_t& comm, string alias)
{
-#if 0
trim(alias);
- std::pair<commodity_pool_t::commodities_map::iterator, bool> result
- = commodity_pool_t::current_pool->commodities.insert
- (commodity_pool_t::commodities_map::value_type(alias, &comm));
- if (! result.second)
- throw_(parse_error,
- _("Cannot use existing commodity name as an alias: %1") << alias);
-#endif
+ commodity_pool_t::current_pool->alias(alias, comm);
+}
+
+void instance_t::commodity_value_directive(commodity_t& comm, string expr_str)
+{
+ comm.set_value_expr(expr_t(expr_str));
}
void instance_t::commodity_format_directive(commodity_t&, string format)
@@ -1109,6 +1120,11 @@ void instance_t::check_directive(char * line)
context.warning(STR(_("Check failed: %1") << line));
}
+void instance_t::value_directive(char * line)
+{
+ context.journal->value_expr = expr_t(line);
+}
+
void instance_t::comment_directive(char * line)
{
while (in.good() && ! in.eof()) {
@@ -1121,6 +1137,14 @@ void instance_t::comment_directive(char * line)
}
#if defined(HAVE_BOOST_PYTHON)
+
+void instance_t::import_directive(char * line)
+{
+ string module_name(line);
+ trim(module_name);
+ python_session->import_option(module_name);
+}
+
void instance_t::python_directive(char * line)
{
std::ostringstream script;
@@ -1160,6 +1184,21 @@ void instance_t::python_directive(char * line)
("journal", python::object(python::ptr(context.journal)));
python_session->eval(script.str(), python_interpreter_t::PY_EVAL_MULTI);
}
+
+#else
+
+void instance_t::import_directive(char *)
+{
+ throw_(parse_error,
+ _("'python' directive seen, but Python support is missing"));
+}
+
+void instance_t::python_directive(char *)
+{
+ throw_(parse_error,
+ _("'import' directive seen, but Python support is missing"));
+}
+
#endif // HAVE_BOOST_PYTHON
bool instance_t::general_directive(char * line)
@@ -1239,6 +1278,10 @@ bool instance_t::general_directive(char * line)
include_directive(arg);
return true;
}
+ else if (std::strcmp(p, "import") == 0) {
+ import_directive(arg);
+ return true;
+ }
break;
case 'p':
@@ -1247,12 +1290,7 @@ bool instance_t::general_directive(char * line)
return true;
}
else if (std::strcmp(p, "python") == 0) {
-#if defined(HAVE_BOOST_PYTHON)
python_directive(arg);
-#else
- throw_(parse_error,
- _("'python' directive seen, but Python support is missing"));
-#endif
return true;
}
break;
@@ -1267,6 +1305,13 @@ bool instance_t::general_directive(char * line)
return true;
}
break;
+
+ case 'v':
+ if (std::strcmp(p, "value") == 0) {
+ value_directive(arg);
+ return true;
+ }
+ break;
}
if (expr_t::ptr_op_t op = lookup(symbol_t::DIRECTIVE, p)) {
@@ -1287,7 +1332,7 @@ post_t * instance_t::parse_post(char * line,
{
TRACE_START(post_details, 1, "Time spent parsing postings:");
- std::auto_ptr<post_t> post(new post_t);
+ unique_ptr<post_t> post(new post_t);
post->xact = xact; // this could be NULL
post->pos = position_t();
@@ -1402,12 +1447,16 @@ post_t * instance_t::parse_post(char * line,
// Parse the optional cost (@ PER-UNIT-COST, @@ TOTAL-COST)
- if (*next == '@') {
+ if (*next == '@' || (*next == '(' && *(next + 1) == '@')) {
DEBUG("textual.parse", "line " << context.linenum << ": "
<< "Found a price indicator");
- bool per_unit = true;
+ if (*next == '(') {
+ post->add_flags(POST_COST_VIRTUAL);
+ ++next;
+ }
+ bool per_unit = true;
if (*++next == '@') {
per_unit = false;
post->add_flags(POST_COST_IN_FULL);
@@ -1415,6 +1464,9 @@ post_t * instance_t::parse_post(char * line,
<< "And it's for a total price");
}
+ if (post->has_flags(POST_COST_VIRTUAL) && *(next + 1) == ')')
+ ++next;
+
beg = static_cast<std::streamsize>(++next - line);
p = skip_ws(next);