diff options
Diffstat (limited to 'src/textual.cc')
-rw-r--r-- | src/textual.cc | 134 |
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); |