diff options
61 files changed, 931 insertions, 1045 deletions
@@ -19,6 +19,7 @@ import string import sys import time import tempfile +import datetime try: import hashlib @@ -181,8 +182,7 @@ class PrepareBuild(CommandLineApp): self.current_flavor = 'debug' self.products_dir = None self.build_dir = self.source_dir - self.configure_args = ['--disable-shared', - '--with-included-gettext'] + self.configure_args = ['--with-included-gettext'] self.sys_include_dirs = [] self.sys_library_dirs = [] @@ -385,8 +385,14 @@ class PrepareBuild(CommandLineApp): def current_version(self): if not self.current_ver: if exists('.git') and isdir('.git'): - tag = self.get_stdout('git', 'describe', '--all', '--long') - self.current_ver = re.sub('heads/', '', tag) + date = self.get_stdout('git', 'log', '--format=%ci', 'HEAD^..HEAD') + date = re.sub(" [-+][0-9][0-9][0-9][0-9]$", "", date) + when = datetime.datetime.strptime(date, "%Y-%m-%d %H:%M:%S") + self.current_ver = when.strftime("%Y%m%d_%H%M%S") + commit = self.get_stdout('git', 'log', '--format=%h', 'HEAD^..HEAD') + self.current_ver += "_" + commit + #tag = self.get_stdout('git', 'describe', '--all', '--long') + #self.current_ver = re.sub('heads/', '', tag) else: self.current_ver = "3.0a" return self.current_ver @@ -472,7 +478,7 @@ class PrepareBuild(CommandLineApp): def phase_version(self, *args): self.log.info('Executing phase: version') version_m4 = open('version.m4', 'w') - version_m4.write("m4_define([VERSION_NUMBER], [%s])" % + version_m4.write("m4_define([VERSION_NUMBER], [%s])\n" % self.current_version()) version_m4.close() @@ -749,6 +755,8 @@ class PrepareBuild(CommandLineApp): self.CXXFLAGS.append('-msse3') self.CPPFLAGS.append('-D_GLIBCXX_FULLY_DYNAMIC_STRING=1') + self.configure_args.append('--disable-shared') + self.options.use_glibcxx_debug = True self.locate_my_libraries() diff --git a/lib/utfcpp b/lib/utfcpp -Subproject 629800e376c01b261a5116b2ba8702711ad8ace +Subproject 200cf64535a8a2545414e993349f6c87c8dd64b diff --git a/src/account.cc b/src/account.cc index 23761049..43b7cd56 100644 --- a/src/account.cc +++ b/src/account.cc @@ -241,8 +241,12 @@ namespace { } } -expr_t::ptr_op_t account_t::lookup(const string& name) +expr_t::ptr_op_t account_t::lookup(const symbol_t::kind_t kind, + const string& name) { + if (kind != symbol_t::FUNCTION) + return NULL; + switch (name[0]) { case 'a': if (name == "amount") @@ -378,6 +382,15 @@ account_t::xdata_t::details_t::operator+=(const details_t& other) return *this; } +void account_t::clear_xdata() +{ + xdata_ = none; + + foreach (accounts_map::value_type& pair, accounts) + if (! pair.second->has_flags(ACCOUNT_TEMP)) + pair.second->clear_xdata(); +} + value_t account_t::amount(const optional<expr_t&>& expr) const { if (xdata_ && xdata_->has_flags(ACCOUNT_EXT_VISITED)) { diff --git a/src/account.h b/src/account.h index 4ac69532..dc1d6c9a 100644 --- a/src/account.h +++ b/src/account.h @@ -114,12 +114,33 @@ public: account_t * find_account(const string& name, bool auto_create = true); account_t * find_account_re(const string& regexp); + typedef transform_iterator<function<account_t *(accounts_map::value_type&)>, + accounts_map::iterator> + accounts_map_seconds_iterator; + + accounts_map_seconds_iterator accounts_begin() { + return make_transform_iterator + (accounts.begin(), bind(&accounts_map::value_type::second, _1)); + } + accounts_map_seconds_iterator accounts_end() { + return make_transform_iterator + (accounts.end(), bind(&accounts_map::value_type::second, _1)); + } + void add_post(post_t * post) { posts.push_back(post); } bool remove_post(post_t * post); - virtual expr_t::ptr_op_t lookup(const string& name); + posts_list::iterator posts_begin() { + return posts.begin(); + } + posts_list::iterator posts_end() { + return posts.end(); + } + + virtual expr_t::ptr_op_t lookup(const symbol_t::kind_t kind, + const string& name); bool valid() const; @@ -209,9 +230,7 @@ public: bool has_xdata() const { return xdata_; } - void clear_xdata() { - xdata_ = none; - } + void clear_xdata(); xdata_t& xdata() { if (! xdata_) xdata_ = xdata_t(); @@ -240,7 +259,7 @@ private: friend class boost::serialization::access; template<class Archive> - void serialize(Archive & ar, const unsigned int /* version */) { + void serialize(Archive& ar, const unsigned int /* version */) { ar & boost::serialization::base_object<supports_flags<> >(*this); ar & boost::serialization::base_object<scope_t>(*this); ar & parent; diff --git a/src/amount.h b/src/amount.h index f7d6986e..1cbd5185 100644 --- a/src/amount.h +++ b/src/amount.h @@ -698,7 +698,7 @@ private: friend class boost::serialization::access; template<class Archive> - void serialize(Archive & ar, const unsigned int /* version */); + void serialize(Archive& ar, const unsigned int /* version */); #endif // HAVE_BOOST_SERIALIZATION /*@}*/ diff --git a/src/annotate.h b/src/annotate.h index cb2a1161..0f940849 100644 --- a/src/annotate.h +++ b/src/annotate.h @@ -106,7 +106,7 @@ private: friend class boost::serialization::access; template<class Archive> - void serialize(Archive & ar, const unsigned int /* version */) { + void serialize(Archive& ar, const unsigned int /* version */) { ar & boost::serialization::base_object<supports_flags<> >(*this); ar & price; ar & date; @@ -159,7 +159,7 @@ private: friend class boost::serialization::access; template<class Archive> - void serialize(Archive & ar, const unsigned int /* version */) { + void serialize(Archive& ar, const unsigned int /* version */) { ar & keep_price; ar & keep_date; ar & keep_tag; @@ -230,7 +230,7 @@ private: friend class boost::serialization::access; template<class Archive> - void serialize(Archive & ar, const unsigned int /* version */) { + void serialize(Archive& ar, const unsigned int /* version */) { ar & boost::serialization::base_object<commodity_t>(*this); ar & ptr; ar & details; diff --git a/src/archive.h b/src/archive.h index cd778a03..779b57f9 100644 --- a/src/archive.h +++ b/src/archive.h @@ -90,7 +90,7 @@ private: friend class boost::serialization::access; template<class Archive> - void serialize(Archive & ar, const unsigned int /* version */) { + void serialize(Archive& ar, const unsigned int /* version */) { ar & sources; } #endif // HAVE_BOOST_SERIALIZATION diff --git a/src/balance.h b/src/balance.h index ad340aa5..36a6907a 100644 --- a/src/balance.h +++ b/src/balance.h @@ -556,7 +556,7 @@ private: friend class boost::serialization::access; template<class Archive> - void serialize(Archive & ar, const unsigned int /* version */) { + void serialize(Archive& ar, const unsigned int /* version */) { ar & amounts; } #endif // HAVE_BOOST_SERIALIZATION diff --git a/src/commodity.h b/src/commodity.h index f65df1b9..e2a17638 100644 --- a/src/commodity.h +++ b/src/commodity.h @@ -70,7 +70,7 @@ private: friend class boost::serialization::access; template<class Archive> - void serialize(Archive & ar, const unsigned int /* version */) { + void serialize(Archive& ar, const unsigned int /* version */) { ar & when; ar & price; } @@ -114,7 +114,7 @@ public: friend class boost::serialization::access; template<class Archive> - void serialize(Archive & ar, const unsigned int /* version */) { + void serialize(Archive& ar, const unsigned int /* version */) { ar & prices; } #endif // HAVE_BOOST_SERIALIZATION @@ -152,7 +152,7 @@ public: friend class boost::serialization::access; template<class Archive> - void serialize(Archive & ar, const unsigned int /* version */) { + void serialize(Archive& ar, const unsigned int /* version */) { ar & histories; } #endif // HAVE_BOOST_SERIALIZATION @@ -188,9 +188,10 @@ protected: public: explicit base_t(const string& _symbol) - : supports_flags<uint_least16_t>(commodity_t::european_by_default ? - COMMODITY_STYLE_EUROPEAN : - COMMODITY_STYLE_DEFAULTS), + : supports_flags<uint_least16_t> + (commodity_t::european_by_default ? + static_cast<uint_least16_t>(COMMODITY_STYLE_EUROPEAN) : + static_cast<uint_least16_t>(COMMODITY_STYLE_DEFAULTS)), symbol(_symbol), precision(0), searched(false) { TRACE_CTOR(base_t, "const string&"); } @@ -209,7 +210,7 @@ protected: friend class boost::serialization::access; template<class Archive> - void serialize(Archive & ar, const unsigned int /* version */) { + void serialize(Archive& ar, const unsigned int /* version */) { ar & boost::serialization::base_object<supports_flags<uint_least16_t> >(*this); ar & symbol; ar & precision; @@ -407,7 +408,7 @@ private: friend class boost::serialization::access; template<class Archive> - void serialize(Archive & ar, const unsigned int /* version */) { + void serialize(Archive& ar, const unsigned int /* version */) { ar & boost::serialization::base_object<delegates_flags<uint_least16_t> >(*this); ar & base; ar & parent_; @@ -171,7 +171,7 @@ private: friend class boost::serialization::access; template<class Archive> - void serialize(Archive & ar, const unsigned int /* version */) { + void serialize(Archive& ar, const unsigned int /* version */) { ar & ptr; ar & context; ar & str; diff --git a/src/filters.h b/src/filters.h index 0dcf5e41..42503945 100644 --- a/src/filters.h +++ b/src/filters.h @@ -70,19 +70,6 @@ public: virtual void operator()(post_t&) {} }; -/** - * @brief Brief - * - * Long. - */ -class clear_post_xdata : public item_handler<post_t> -{ -public: - virtual void operator()(post_t& post) { - post.clear_xdata(); - } -}; - class posts_iterator; /** @@ -790,19 +777,6 @@ class forecast_posts : public generate_posts // Account filters // -/** - * @brief Brief - * - * Long. - */ -class clear_account_xdata : public item_handler<account_t> -{ -public: - virtual void operator()(account_t& acct) { - acct.clear_xdata(); - } -}; - class accounts_iterator; /** diff --git a/src/flags.h b/src/flags.h index 33935556..791b3105 100644 --- a/src/flags.h +++ b/src/flags.h @@ -105,7 +105,7 @@ private: friend class boost::serialization::access; template<class Archive> - void serialize(Archive & ar, const unsigned int /* version */) + void serialize(Archive& ar, const unsigned int /* version */) { ar & _flags; } @@ -218,7 +218,7 @@ private: friend class boost::serialization::access; template<class Archive> - void serialize(Archive & ar, const unsigned int /* version */) + void serialize(Archive& ar, const unsigned int /* version */) { ar & _flags; } diff --git a/src/global.cc b/src/global.cc index d9028dd7..2103e32c 100644 --- a/src/global.cc +++ b/src/global.cc @@ -67,6 +67,7 @@ global_scope_t::global_scope_t(char ** envp) // open document, with a separate report_t object for each report it // generated. report_stack.push_front(new report_t(session())); + scope_t::default_scope = &report(); // Read the user's options, in the following order: // @@ -111,7 +112,7 @@ void global_scope_t::read_init() ifstream init(init_file); - if (session().read_journal(init_file, NULL, &report()) > 0 || + if (session().journal->read(init_file, NULL, &report()) > 0 || session().journal->auto_xacts.size() > 0 || session().journal->period_xacts.size() > 0) { throw_(parse_error, _("Transactions found in initialization file '%1'") @@ -314,28 +315,32 @@ option_t<global_scope_t> * global_scope_t::lookup_option(const char * p) return NULL; } -expr_t::ptr_op_t global_scope_t::lookup(const string& name) +expr_t::ptr_op_t global_scope_t::lookup(const symbol_t::kind_t kind, + const string& name) { - const char * p = name.c_str(); - switch (*p) { - case 'o': - if (WANT_OPT()) { p += OPT_PREFIX_LEN; - if (option_t<global_scope_t> * handler = lookup_option(p)) - return MAKE_OPT_HANDLER(global_scope_t, handler); - } + switch (kind) { + case symbol_t::FUNCTION: + if (option_t<global_scope_t> * handler = lookup_option(name.c_str())) + return MAKE_OPT_FUNCTOR(global_scope_t, handler); break; - case 'p': - if (WANT_PRECMD()) { const char * q = p + PRECMD_PREFIX_LEN; - switch (*q) { - case 'p': - if (is_eq(q, "push")) - return MAKE_FUNCTOR(global_scope_t::push_command); - else if (is_eq(q, "pop")) - return MAKE_FUNCTOR(global_scope_t::pop_command); - break; - } + case symbol_t::OPTION: + if (option_t<global_scope_t> * handler = lookup_option(name.c_str())) + return MAKE_OPT_HANDLER(global_scope_t, handler); + break; + + case symbol_t::PRECOMMAND: { + const char * p = name.c_str(); + switch (*p) { + case 'p': + if (is_eq(p, "push")) + return MAKE_FUNCTOR(global_scope_t::push_command); + else if (is_eq(p, "pop")) + return MAKE_FUNCTOR(global_scope_t::pop_command); + break; } + } + default: break; } @@ -396,7 +401,7 @@ void global_scope_t::normalize_session_options() function_t global_scope_t::look_for_precommand(scope_t& scope, const string& verb) { - if (expr_t::ptr_op_t def = scope.lookup(string(PRECMD_PREFIX) + verb)) + if (expr_t::ptr_op_t def = scope.lookup(symbol_t::PRECOMMAND, verb)) return def->as_function(); else return function_t(); @@ -405,7 +410,7 @@ function_t global_scope_t::look_for_precommand(scope_t& scope, function_t global_scope_t::look_for_command(scope_t& scope, const string& verb) { - if (expr_t::ptr_op_t def = scope.lookup(string(CMD_PREFIX) + verb)) + if (expr_t::ptr_op_t def = scope.lookup(symbol_t::COMMAND, verb)) return def->as_function(); else return function_t(); diff --git a/src/global.h b/src/global.h index df9845d5..31a0a480 100644 --- a/src/global.h +++ b/src/global.h @@ -75,10 +75,14 @@ public: void push_report() { report_stack.push_front(new report_t(report_stack.front())); + scope_t::default_scope = &report(); } void pop_report() { - if (! report_stack.empty()) - report_stack.pop_front(); + assert(! report_stack.empty()); + report_stack.pop_front(); + // There should always be the "default report" waiting on the stack. + assert(! report_stack.empty()); + scope_t::default_scope = &report(); } void report_error(const std::exception& err); @@ -117,7 +121,8 @@ See LICENSE file included with the distribution for details and disclaimer."); option_t<global_scope_t> * lookup_option(const char * p); - virtual expr_t::ptr_op_t lookup(const string& name); + virtual expr_t::ptr_op_t lookup(const symbol_t::kind_t kind, + const string& name); OPTION(global_scope_t, args_only); OPTION(global_scope_t, debug_); diff --git a/src/item.cc b/src/item.cc index 37e19a82..acef2e44 100644 --- a/src/item.cc +++ b/src/item.cc @@ -304,8 +304,12 @@ value_t get_comment(item_t& item) } } -expr_t::ptr_op_t item_t::lookup(const string& name) +expr_t::ptr_op_t item_t::lookup(const symbol_t::kind_t kind, + const string& name) { + if (kind != symbol_t::FUNCTION) + return NULL; + switch (name[0]) { case 'a': if (name == "actual") @@ -87,7 +87,7 @@ private: friend class boost::serialization::access; template<class Archive> - void serialize(Archive & ar, const unsigned int /* version */) { + void serialize(Archive& ar, const unsigned int /* version */) { ar & pathname; ar & beg_pos; ar & beg_line; @@ -189,7 +189,8 @@ public: return _state; } - virtual expr_t::ptr_op_t lookup(const string& name); + virtual expr_t::ptr_op_t lookup(const symbol_t::kind_t kind, + const string& name); bool valid() const; @@ -200,7 +201,7 @@ private: friend class boost::serialization::access; template<class Archive> - void serialize(Archive & ar, const unsigned int /* version */) { + void serialize(Archive& ar, const unsigned int /* version */) { ar & boost::serialization::base_object<supports_flags<> >(*this); ar & boost::serialization::base_object<scope_t>(*this); ar & _state; diff --git a/src/journal.cc b/src/journal.cc index 7dbc2907..31557635 100644 --- a/src/journal.cc +++ b/src/journal.cc @@ -41,23 +41,23 @@ namespace ledger { journal_t::journal_t() - : master(new account_t), was_loaded(false), - commodity_pool(new commodity_pool_t) { TRACE_CTOR(journal_t, ""); + initialize(); +} - // Add time commodity conversions, so that timelog's may be parsed - // in terms of seconds, but reported as minutes or hours. - if (commodity_t * commodity = commodity_pool->create("s")) - commodity->add_flags(COMMODITY_BUILTIN | COMMODITY_NOMARKET); - else - assert(false); +journal_t::journal_t(const path& pathname) +{ + TRACE_CTOR(journal_t, "path"); + initialize(); + read(pathname); +} - // Add a "percentile" commodity - if (commodity_t * commodity = commodity_pool->create("%")) - commodity->add_flags(COMMODITY_BUILTIN | COMMODITY_NOMARKET); - else - assert(false); +journal_t::journal_t(const string& str) +{ + TRACE_CTOR(journal_t, "string"); + initialize(); + read(str); } journal_t::~journal_t() @@ -80,6 +80,28 @@ journal_t::~journal_t() commodity_pool.reset(); } +void journal_t::initialize() +{ + master = new account_t; + basket = NULL; + was_loaded = false; + + commodity_pool.reset(new commodity_pool_t); + + // Add time commodity conversions, so that timelog's may be parsed + // in terms of seconds, but reported as minutes or hours. + if (commodity_t * commodity = commodity_pool->create("s")) + commodity->add_flags(COMMODITY_BUILTIN | COMMODITY_NOMARKET); + else + assert(false); + + // Add a "percentile" commodity + if (commodity_t * commodity = commodity_pool->create("%")) + commodity->add_flags(COMMODITY_BUILTIN | COMMODITY_NOMARKET); + else + assert(false); +} + void journal_t::add_account(account_t * acct) { master->add_account(acct); @@ -134,6 +156,72 @@ bool journal_t::remove_xact(xact_t * xact) return true; } +std::size_t journal_t::read(std::istream& in, + const path& pathname, + account_t * master_alt, + scope_t * scope) +{ + std::size_t count = 0; + try { + if (! scope) + scope = scope_t::default_scope; + + if (! scope) + throw_(std::runtime_error, + _("No default scope in which to read journal file '%1'") + << pathname); + + value_t strict = expr_t("strict").calc(*scope); + + count = parse(in, *scope, master_alt ? master_alt : master, + &pathname, strict.to_boolean()); + } + catch (...) { + clear_xdata(); + throw; + } + + // xdata may have been set for some accounts and transaction due to the use + // of balance assertions or other calculations performed in valexpr-based + // posting amounts. + clear_xdata(); + + return count; +} + +std::size_t journal_t::read(const path& pathname, + account_t * master, + scope_t * scope) +{ + path filename = resolve_path(pathname); + + if (! exists(filename)) + throw_(std::runtime_error, + _("Cannot read journal file '%1'") << filename); + + ifstream stream(filename); + std::size_t count = read(stream, filename, master, scope); + sources.push_back(fileinfo_t(filename)); + return count; +} + +void journal_t::clear_xdata() +{ + foreach (xact_t * xact, xacts) + if (! xact->has_flags(ITEM_TEMP)) + xact->clear_xdata(); + + foreach (auto_xact_t * xact, auto_xacts) + if (! xact->has_flags(ITEM_TEMP)) + xact->clear_xdata(); + + foreach (period_xact_t * xact, period_xacts) + if (! xact->has_flags(ITEM_TEMP)) + xact->clear_xdata(); + + master->clear_xdata(); +} + bool journal_t::valid() const { if (! master->valid()) { diff --git a/src/journal.h b/src/journal.h index 88a225c5..e2af0dde 100644 --- a/src/journal.h +++ b/src/journal.h @@ -105,7 +105,7 @@ public: friend class boost::serialization::access; template<class Archive> - void serialize(Archive & ar, const unsigned int /* version */) { + void serialize(Archive& ar, const unsigned int /* version */) { ar & filename; ar & size; ar & modtime; @@ -126,8 +126,19 @@ public: hooks_t<xact_finalizer_t, xact_t> xact_finalize_hooks; journal_t(); + journal_t(const path& pathname); + journal_t(const string& str); ~journal_t(); + void initialize(); + + std::list<fileinfo_t>::iterator sources_begin() { + return sources.begin(); + } + std::list<fileinfo_t>::iterator sources_end() { + return sources.end(); + } + // These four methods are delegated to the current session, since all // accounts processed are gathered together at the session level. void add_account(account_t * acct); @@ -138,6 +149,25 @@ public: bool add_xact(xact_t * xact); bool remove_xact(xact_t * xact); + xacts_list::iterator xacts_begin() { + return xacts.begin(); + } + xacts_list::iterator xacts_end() { + return xacts.end(); + } + auto_xacts_list::iterator auto_xacts_begin() { + return auto_xacts.begin(); + } + auto_xacts_list::iterator auto_xacts_end() { + return auto_xacts.end(); + } + period_xacts_list::iterator period_xacts_begin() { + return period_xacts.begin(); + } + period_xacts_list::iterator period_xacts_end() { + return period_xacts.end(); + } + void add_xact_finalizer(xact_finalizer_t * finalizer) { xact_finalize_hooks.add_hook(finalizer); } @@ -145,12 +175,22 @@ public: xact_finalize_hooks.remove_hook(finalizer); } + std::size_t read(std::istream& in, + const path& pathname, + account_t * master = NULL, + scope_t * scope = NULL); + std::size_t read(const path& pathname, + account_t * master = NULL, + scope_t * scope = NULL); + std::size_t parse(std::istream& in, scope_t& session_scope, account_t * master = NULL, const path * original_file = NULL, bool strict = false); + void clear_xdata(); + bool valid() const; #if defined(HAVE_BOOST_SERIALIZATION) @@ -160,7 +200,7 @@ private: friend class boost::serialization::access; template<class Archive> - void serialize(Archive & ar, const unsigned int /* version */) { + void serialize(Archive& ar, const unsigned int /* version */) { ar & master; ar & basket; ar & xacts; @@ -102,7 +102,7 @@ private: friend class boost::serialization::access; template<class Archive> - void serialize(Archive & ar, const unsigned int /* version */) { + void serialize(Archive& ar, const unsigned int /* version */) { string temp; if (Archive::is_loading::value) { ar & temp; @@ -43,7 +43,7 @@ expr_t::ptr_op_t expr_t::op_t::compile(scope_t& scope, const int depth) if (is_ident()) { DEBUG("expr.compile", "lookup: " << as_ident()); - if (ptr_op_t def = scope.lookup(as_ident())) { + if (ptr_op_t def = scope.lookup(symbol_t::FUNCTION, as_ident())) { // Identifier references are first looked up at the point of // definition, and then at the point of every use if they could // not be found there. @@ -65,11 +65,11 @@ expr_t::ptr_op_t expr_t::op_t::compile(scope_t& scope, const int depth) if (kind == O_DEFINE) { switch (left()->kind) { case IDENT: - scope.define(left()->as_ident(), right()); + scope.define(symbol_t::FUNCTION, left()->as_ident(), right()); break; case O_CALL: if (left()->left()->is_ident()) - scope.define(left()->left()->as_ident(), this); + scope.define(symbol_t::FUNCTION, left()->left()->as_ident(), this); else throw_(compile_error, _("Invalid function definition")); break; @@ -152,9 +152,10 @@ value_t expr_t::op_t::calc(scope_t& scope, ptr_op_t * locus, const int depth) if (! varname->is_ident()) throw_(calc_error, _("Invalid function definition")); else if (args_index == args_count) - local_scope.define(varname->as_ident(), wrap_value(false)); + local_scope.define(symbol_t::FUNCTION, varname->as_ident(), + wrap_value(false)); else - local_scope.define(varname->as_ident(), + local_scope.define(symbol_t::FUNCTION, varname->as_ident(), wrap_value(call_args[args_index++])); } @@ -178,7 +179,8 @@ value_t expr_t::op_t::calc(scope_t& scope, ptr_op_t * locus, const int depth) _("Left operand of . operator is NULL")); } else { scope_t& objscope(*obj.as_scope()); - if (ptr_op_t member = objscope.lookup(right()->as_ident())) { + if (ptr_op_t member = + objscope.lookup(symbol_t::FUNCTION, right()->as_ident())) { result = member->calc(objscope, NULL, depth + 1); break; } @@ -298,7 +298,7 @@ private: friend class boost::serialization::access; template<class Archive> - void serialize(Archive & ar, const unsigned int /* version */) { + void serialize(Archive& ar, const unsigned int /* version */) { ar & refc; ar & kind; if (Archive::is_loading::value || ! left_ || left_->kind != FUNCTION) { diff --git a/src/option.cc b/src/option.cc index 8da66b36..6d230939 100644 --- a/src/option.cc +++ b/src/option.cc @@ -41,8 +41,7 @@ namespace { op_bool_tuple find_option(scope_t& scope, const string& name) { char buf[128]; - std::strcpy(buf, "opt_"); - char * p = &buf[4]; + char * p = buf; foreach (char ch, name) { if (ch == '-') *p++ = '_'; @@ -52,28 +51,27 @@ namespace { *p++ = '_'; *p = '\0'; - if (expr_t::ptr_op_t op = scope.lookup(buf)) + if (expr_t::ptr_op_t op = scope.lookup(symbol_t::OPTION, buf)) return op_bool_tuple(op, true); *--p = '\0'; - return op_bool_tuple(scope.lookup(buf), false); + return op_bool_tuple(scope.lookup(symbol_t::OPTION, buf), false); } op_bool_tuple find_option(scope_t& scope, const char letter) { - char buf[10]; - std::strcpy(buf, "opt_"); - buf[4] = letter; - buf[5] = '_'; - buf[6] = '\0'; + char buf[4]; + buf[0] = letter; + buf[1] = '_'; + buf[2] = '\0'; - if (expr_t::ptr_op_t op = scope.lookup(buf)) + if (expr_t::ptr_op_t op = scope.lookup(symbol_t::OPTION, buf)) return op_bool_tuple(op, true); - buf[5] = '\0'; + buf[1] = '\0'; - return op_bool_tuple(scope.lookup(buf), false); + return op_bool_tuple(scope.lookup(symbol_t::OPTION, buf), false); } void process_option(const string& whence, const function_t& opt, diff --git a/src/option.h b/src/option.h index 0600779c..c9903c03 100644 --- a/src/option.h +++ b/src/option.h @@ -190,6 +190,7 @@ public: virtual value_t operator()(call_scope_t& args) { if (! args.empty()) { + args.push_front(string_value("?expr")); return handler_wrapper(args); } else if (wants_arg) { @@ -282,30 +283,6 @@ inline bool is_eq(const char * p, const char * n) { } \ END(name) -#define OPT_PREFIX "opt_" -#define OPT_PREFIX_LEN 4 - -#define WANT_OPT() \ - (std::strncmp(p, OPT_PREFIX, OPT_PREFIX_LEN) == 0) - -#define PRECMD_PREFIX "precmd_" -#define PRECMD_PREFIX_LEN 7 - -#define WANT_PRECMD() \ - (std::strncmp(p, PRECMD_PREFIX, PRECMD_PREFIX_LEN) == 0) - -#define CMD_PREFIX "cmd_" -#define CMD_PREFIX_LEN 4 - -#define WANT_CMD() \ - (std::strncmp(p, CMD_PREFIX, CMD_PREFIX_LEN) == 0) - -#define DIR_PREFIX "dir_" -#define DIR_PREFIX_LEN 4 - -#define WANT_DIR() \ - (std::strncmp(p, DIR_PREFIX, DIR_PREFIX_LEN) == 0) - bool process_option(const string& whence, const string& name, scope_t& scope, const char * arg, const string& varname); @@ -145,7 +145,7 @@ private: friend class boost::serialization::access; template<class Archive> - void serialize(Archive & ar, const unsigned int /* version */) { + void serialize(Archive& ar, const unsigned int /* version */) { ar & commodities; ar & null_commodity; ar & default_commodity; diff --git a/src/post.cc b/src/post.cc index 2a1663cb..d7923866 100644 --- a/src/post.cc +++ b/src/post.cc @@ -271,8 +271,12 @@ namespace { } } -expr_t::ptr_op_t post_t::lookup(const string& name) +expr_t::ptr_op_t post_t::lookup(const symbol_t::kind_t kind, + const string& name) { + if (kind != symbol_t::FUNCTION) + return item_t::lookup(kind, name); + switch (name[0]) { case 'a': if (name[1] == '\0' || name == "amount") @@ -366,7 +370,7 @@ expr_t::ptr_op_t post_t::lookup(const string& name) break; } - return item_t::lookup(name); + return item_t::lookup(kind, name); } bool post_t::valid() const @@ -119,7 +119,8 @@ public: return ! has_flags(POST_VIRTUAL) || has_flags(POST_MUST_BALANCE); } - virtual expr_t::ptr_op_t lookup(const string& name); + virtual expr_t::ptr_op_t lookup(const symbol_t::kind_t kind, + const string& name); bool valid() const; @@ -215,7 +216,7 @@ private: friend class boost::serialization::access; template<class Archive> - void serialize(Archive & ar, const unsigned int /* version */) { + void serialize(Archive& ar, const unsigned int /* version */) { ar & boost::serialization::base_object<item_t>(*this); ar & xact; ar & account; diff --git a/src/precmd.cc b/src/precmd.cc index a08fd2d6..4cf541f4 100644 --- a/src/precmd.cc +++ b/src/precmd.cc @@ -67,7 +67,7 @@ namespace { { std::istringstream in(str); report.session.journal->parse(in, report.session); - report.session.clean_accounts(); + report.session.journal->clear_xdata(); } } xact_t * first = report.session.journal->xacts.front(); @@ -231,6 +231,9 @@ value_t args_command(call_scope_t& args) out << std::endl << std::endl; std::pair<expr_t, query_parser_t> info = args_to_predicate(begin, end); + if (! info.first) + throw_(std::runtime_error, + _("Invalid query predicate: %1") << join_args(args)); call_scope_t sub_args(static_cast<scope_t&>(args)); sub_args.push_back(string_value(info.first.text())); @@ -242,8 +245,12 @@ value_t args_command(call_scope_t& args) << std::endl << std::endl; call_scope_t disp_sub_args(static_cast<scope_t&>(args)); - disp_sub_args.push_back - (string_value(args_to_predicate(info.second).first.text())); + info = args_to_predicate(info.second); + if (! info.first) + throw_(std::runtime_error, + _("Invalid display predicate: %1") << join_args(args)); + + disp_sub_args.push_back(string_value(info.first.text())); parse_command(disp_sub_args); } diff --git a/src/predicate.h b/src/predicate.h index 5e900234..577e872a 100644 --- a/src/predicate.h +++ b/src/predicate.h @@ -102,7 +102,7 @@ private: friend class boost::serialization::access; template<class Archive> - void serialize(Archive & ar, const unsigned int /* version */) { + void serialize(Archive& ar, const unsigned int /* version */) { ar & predicate; ar & what_to_keep; } @@ -299,8 +299,7 @@ std::pair<expr_t, query_parser_t> args_to_predicate(value_t::sequence_t::const_iterator begin, value_t::sequence_t::const_iterator end); -std::pair<expr_t, query_parser_t> -args_to_predicate(query_parser_t parser); +std::pair<expr_t, query_parser_t> args_to_predicate(query_parser_t parser); } // namespace ledger diff --git a/src/py_account.cc b/src/py_account.cc index 7fa30d0a..8310f5ec 100644 --- a/src/py_account.cc +++ b/src/py_account.cc @@ -142,9 +142,10 @@ void export_account() class_< account_t::xdata_t > ("AccountXData") #if 1 - .def("flags", &supports_flags<uint_least16_t>::flags) + .add_property("flags", + &supports_flags<uint_least16_t>::flags, + &supports_flags<uint_least16_t>::set_flags) .def("has_flags", &supports_flags<uint_least16_t>::has_flags) - .def("set_flags", &supports_flags<uint_least16_t>::set_flags) .def("clear_flags", &supports_flags<uint_least16_t>::clear_flags) .def("add_flags", &supports_flags<uint_least16_t>::add_flags) .def("drop_flags", &supports_flags<uint_least16_t>::drop_flags) @@ -162,9 +163,10 @@ void export_account() class_< account_t > ("Account") #if 1 - .def("flags", &supports_flags<>::flags) + .add_property("flags", + &supports_flags<>::flags, + &supports_flags<>::set_flags) .def("has_flags", &supports_flags<>::has_flags) - .def("set_flags", &supports_flags<>::set_flags) .def("clear_flags", &supports_flags<>::clear_flags) .def("add_flags", &supports_flags<>::add_flags) .def("drop_flags", &supports_flags<>::drop_flags) @@ -172,13 +174,11 @@ void export_account() .add_property("parent", make_getter(&account_t::parent, - return_value_policy<reference_existing_object>())) + return_internal_reference<>())) .def_readwrite("name", &account_t::name) .def_readwrite("note", &account_t::note) .def_readonly("depth", &account_t::depth) - .def_readonly("accounts", &account_t::accounts) - .def_readonly("posts", &account_t::posts) .def(self_ns::str(self)) @@ -199,7 +199,14 @@ void export_account() .def("valid", &account_t::valid) .def("__len__", accounts_len) - .def("__getitem__", accounts_getitem, return_internal_reference<1>()) + .def("__getitem__", accounts_getitem, return_internal_reference<>()) + + .def("__iter__", range<return_internal_reference<> > + (&account_t::accounts_begin, &account_t::accounts_end)) + .def("accounts", range<return_internal_reference<> > + (&account_t::accounts_begin, &account_t::accounts_end)) + .def("posts", range<return_internal_reference<> > + (&account_t::posts_begin, &account_t::posts_end)) .def("has_xdata", &account_t::has_xdata) .def("clear_xdata", &account_t::clear_xdata) diff --git a/src/py_balance.cc b/src/py_balance.cc index effc6937..6d0ad500 100644 --- a/src/py_balance.cc +++ b/src/py_balance.cc @@ -214,6 +214,12 @@ void export_balance() .def("valid", &balance_t::valid) ; + register_optional_to_python<balance_t>(); + + implicitly_convertible<long, balance_t>(); + implicitly_convertible<string, balance_t>(); + implicitly_convertible<amount_t, balance_t>(); + #define EXC_TRANSLATE(type) \ register_exception_translator<type>(&exc_translate_ ## type); diff --git a/src/py_chain.cc b/src/py_chain.cc deleted file mode 100644 index 7dac7fc6..00000000 --- a/src/py_chain.cc +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright (c) 2003-2009, John Wiegley. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of New Artisans LLC nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include <system.hh> - -#include "pyinterp.h" - -namespace ledger { - -using namespace boost::python; - -#define EXC_TRANSLATOR(type) \ - void exc_translate_ ## type(const type& err) { \ - PyErr_SetString(PyExc_ArithmeticError, err.what()); \ - } - -//EXC_TRANSLATOR(chain_error) - -void export_chain() -{ -#if 0 - struct_< item_handler_t > ("ItemHandler") - ; -#endif - - //register_optional_to_python<amount_t>(); - -#define EXC_TRANSLATE(type) \ - register_exception_translator<type>(&exc_translate_ ## type); - - //EXC_TRANSLATE(chain_error); -} - -} // namespace ledger diff --git a/src/py_commodity.cc b/src/py_commodity.cc index c0412a45..c20053ad 100644 --- a/src/py_commodity.cc +++ b/src/py_commodity.cc @@ -130,12 +130,12 @@ void export_commodity() class_< commodity_pool_t, boost::noncopyable > ("CommodityPool", no_init) .add_property("null_commodity", make_getter(&commodity_pool_t::null_commodity, - return_value_policy<reference_existing_object>()), + return_internal_reference<>()), make_setter(&commodity_pool_t::null_commodity, with_custodian_and_ward<1, 2>())) .add_property("default_commodity", make_getter(&commodity_pool_t::default_commodity, - return_value_policy<reference_existing_object>()), + return_internal_reference<>()), make_setter(&commodity_pool_t::default_commodity, with_custodian_and_ward<1, 2>())) @@ -189,9 +189,10 @@ void export_commodity() class_< commodity_t, boost::noncopyable > ("Commodity", no_init) #if 1 - .def("flags", &delegates_flags<uint_least16_t>::flags) + .add_property("flags", + &supports_flags<uint_least16_t>::flags, + &supports_flags<uint_least16_t>::set_flags) .def("has_flags", &delegates_flags<uint_least16_t>::has_flags) - .def("set_flags", &delegates_flags<uint_least16_t>::set_flags) .def("clear_flags", &delegates_flags<uint_least16_t>::clear_flags) .def("add_flags", &delegates_flags<uint_least16_t>::add_flags) .def("drop_flags", &delegates_flags<uint_least16_t>::drop_flags) @@ -248,9 +249,9 @@ void export_commodity() class_< annotation_t > ("Annotation", no_init) #if 1 - .def("flags", &supports_flags<>::flags) + .add_property("flags", &supports_flags<>::flags, + &supports_flags<>::set_flags) .def("has_flags", &supports_flags<>::has_flags) - .def("set_flags", &supports_flags<>::set_flags) .def("clear_flags", &supports_flags<>::clear_flags) .def("add_flags", &supports_flags<>::add_flags) .def("drop_flags", &supports_flags<>::drop_flags) diff --git a/src/py_global.cc b/src/py_global.cc deleted file mode 100644 index 936e3fab..00000000 --- a/src/py_global.cc +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright (c) 2003-2009, John Wiegley. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of New Artisans LLC nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include <system.hh> - -#include "pyinterp.h" - -namespace ledger { - -using namespace boost::python; - -#define EXC_TRANSLATOR(type) \ - void exc_translate_ ## type(const type& err) { \ - PyErr_SetString(PyExc_ArithmeticError, err.what()); \ - } - -//EXC_TRANSLATOR(global_error) - -void export_global() -{ -#if 0 - class_< global_scope_t > ("GlobalScope") - ; -#endif - - //register_optional_to_python<amount_t>(); - - //implicitly_convertible<string, amount_t>(); - -#define EXC_TRANSLATE(type) \ - register_exception_translator<type>(&exc_translate_ ## type); - - //EXC_TRANSLATE(global_error); -} - -} // namespace ledger diff --git a/src/py_item.cc b/src/py_item.cc index ac544c6a..8a6e495a 100644 --- a/src/py_item.cc +++ b/src/py_item.cc @@ -109,9 +109,9 @@ void export_item() class_< item_t > ("JournalItem", init<uint_least8_t>()) #endif #if 1 - .def("flags", &supports_flags<>::flags) + .add_property("flags", &supports_flags<>::flags, + &supports_flags<>::set_flags) .def("has_flags", &supports_flags<>::has_flags) - .def("set_flags", &supports_flags<>::set_flags) .def("clear_flags", &supports_flags<>::clear_flags) .def("add_flags", &supports_flags<>::add_flags) .def("drop_flags", &supports_flags<>::drop_flags) @@ -138,6 +138,9 @@ void export_item() .def("get_tag", py_get_tag_1s) .def("get_tag", py_get_tag_1m) .def("get_tag", py_get_tag_2m) + .def("tag", py_get_tag_1s) + .def("tag", py_get_tag_1m) + .def("tag", py_get_tag_2m) .def("set_tag", &item_t::set_tag) @@ -148,11 +151,11 @@ void export_item() make_getter(&item_t::use_effective_date), make_setter(&item_t::use_effective_date)) - .def("date", &item_t::date) - .def("effective_date", &item_t::effective_date) + .add_property("date", &item_t::date, make_setter(&item_t::_date)) + .add_property("effective_date", &item_t::effective_date, + make_setter(&item_t::_date_eff)) - .def("set_state", &item_t::set_state) - .def("state", &item_t::state) + .add_property("state", &item_t::state, &item_t::set_state) .def("lookup", &item_t::lookup) diff --git a/src/py_journal.cc b/src/py_journal.cc index 873645d3..9b3e7513 100644 --- a/src/py_journal.cc +++ b/src/py_journal.cc @@ -171,6 +171,8 @@ namespace { void export_journal() { class_< journal_t::fileinfo_t > ("FileInfo") + .def(init<path>()) + .add_property("filename", make_getter(&journal_t::fileinfo_t::filename), make_setter(&journal_t::fileinfo_t::filename)) @@ -186,17 +188,19 @@ void export_journal() ; class_< journal_t, boost::noncopyable > ("Journal") + .def(init<path>()) + .def(init<string>()) + .add_property("master", make_getter(&journal_t::master, - return_internal_reference<1>())) + return_internal_reference<>())) .add_property("basket", make_getter(&journal_t::basket, - return_internal_reference<1>()), + return_internal_reference<>()), make_setter(&journal_t::basket)) - .add_property("sources", make_getter(&journal_t::sources)) .add_property("was_loaded", make_getter(&journal_t::was_loaded)) .add_property("commodity_pool", make_getter(&journal_t::commodity_pool, - return_internal_reference<1>())) + return_internal_reference<>())) #if 0 .add_property("xact_finalize_hooks", make_getter(&journal_t::xact_finalize_hooks), @@ -206,10 +210,10 @@ void export_journal() .def("add_account", &journal_t::add_account) .def("remove_account", &journal_t::remove_account) - .def("find_account", py_find_account_1, return_internal_reference<1>()) - .def("find_account", py_find_account_2, return_internal_reference<1>()) + .def("find_account", py_find_account_1, return_internal_reference<>()) + .def("find_account", py_find_account_2, return_internal_reference<>()) .def("find_account_re", &journal_t::find_account_re, - return_internal_reference<1>()) + return_internal_reference<>()) .def("add_xact", &journal_t::add_xact) .def("remove_xact", &journal_t::remove_xact) @@ -221,6 +225,19 @@ void export_journal() .def("__len__", xacts_len) .def("__getitem__", xacts_getitem, return_internal_reference<1>()) + .def("__iter__", range<return_internal_reference<> > + (&journal_t::xacts_begin, &journal_t::xacts_end)) + .def("xacts", range<return_internal_reference<> > + (&journal_t::xacts_begin, &journal_t::xacts_end)) + .def("auto_xacts", range<return_internal_reference<> > + (&journal_t::auto_xacts_begin, &journal_t::auto_xacts_end)) + .def("period_xacts", range<return_internal_reference<> > + (&journal_t::period_xacts_begin, &journal_t::period_xacts_end)) + .def("sources", range<return_internal_reference<> > + (&journal_t::sources_begin, &journal_t::sources_end)) + + .def("clear_xdata", &journal_t::clear_xdata) + .def("valid", &journal_t::valid) ; } diff --git a/src/py_post.cc b/src/py_post.cc index b4849c3d..64bdde83 100644 --- a/src/py_post.cc +++ b/src/py_post.cc @@ -87,9 +87,10 @@ void export_post() class_< post_t::xdata_t > ("PostingXData") #if 1 - .def("flags", &supports_flags<uint_least16_t>::flags) + .add_property("flags", + &supports_flags<uint_least16_t>::flags, + &supports_flags<uint_least16_t>::set_flags) .def("has_flags", &supports_flags<uint_least16_t>::has_flags) - .def("set_flags", &supports_flags<uint_least16_t>::set_flags) .def("clear_flags", &supports_flags<uint_least16_t>::clear_flags) .def("add_flags", &supports_flags<uint_least16_t>::add_flags) .def("drop_flags", &supports_flags<uint_least16_t>::drop_flags) @@ -131,12 +132,12 @@ void export_post() .add_property("xact", make_getter(&post_t::xact, - return_value_policy<reference_existing_object>()), + return_internal_reference<>()), make_setter(&post_t::xact, with_custodian_and_ward<1, 2>())) .add_property("account", make_getter(&post_t::account, - return_value_policy<reference_existing_object>()), + return_internal_reference<>()), make_setter(&post_t::account, with_custodian_and_ward<1, 2>())) .add_property("amount", diff --git a/src/py_report.cc b/src/py_report.cc deleted file mode 100644 index aa70f5f1..00000000 --- a/src/py_report.cc +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright (c) 2003-2009, John Wiegley. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of New Artisans LLC nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include <system.hh> - -#include "pyinterp.h" - -namespace ledger { - -using namespace boost::python; - -#define EXC_TRANSLATOR(type) \ - void exc_translate_ ## type(const type& err) { \ - PyErr_SetString(PyExc_ArithmeticError, err.what()); \ - } - -//EXC_TRANSLATOR(report_error) - -void export_report() -{ -#if 0 - class_< report_t > ("Report") - ; -#endif - - //register_optional_to_python<amount_t>(); - - //implicitly_convertible<string, amount_t>(); - -#define EXC_TRANSLATE(type) \ - register_exception_translator<type>(&exc_translate_ ## type); - - //EXC_TRANSLATE(report_error); -} - -} // namespace ledger diff --git a/src/py_scope.cc b/src/py_scope.cc index cc85030c..c5c4fff6 100644 --- a/src/py_scope.cc +++ b/src/py_scope.cc @@ -38,59 +38,17 @@ namespace ledger { using namespace boost::python; namespace { - void py_scope_define(scope_t& scope, const string& name, expr_t& def) - { - return scope.define(name, def.get_op()); - } - - expr_t py_scope_lookup(scope_t& scope, const string& name) - { - return scope.lookup(name); - } - - value_t py_scope_getattr(scope_t& scope, const string& name) - { - return expr_t(scope.lookup(name)).calc(scope); - } - - struct scope_wrapper : public scope_t - { - PyObject * self; - - scope_wrapper(PyObject * self_) : self(self_) {} - - virtual expr_t::ptr_op_t lookup(const string&) { - return NULL; - } - }; } void export_scope() { - class_< scope_t, scope_wrapper, boost::noncopyable > ("Scope", no_init) - .def("define", py_scope_define) - .def("lookup", py_scope_lookup) - .def("__getattr__", py_scope_getattr) - ; - - class_< child_scope_t, bases<scope_t>, - boost::noncopyable > ("ChildScope") - .def(init<>()) - .def(init<scope_t&>()) - ; - - class_< symbol_scope_t, bases<child_scope_t>, - boost::noncopyable > ("SymbolScope") - .def(init<>()) - .def(init<scope_t&>()) - ; - - class_< call_scope_t, bases<child_scope_t>, - boost::noncopyable > ("CallScope", init<scope_t&>()) - ; - - class_< bind_scope_t, bases<child_scope_t>, - boost::noncopyable > ("BindScope", init<scope_t&, scope_t&>()) + class_< scope_t, boost::noncopyable > ("Scope", no_init) +#if 0 + .def("is_posting", ) + .def("is_transaction", ) + .def("is_account", ) + .def("is_journal", ) +#endif ; } diff --git a/src/py_session.cc b/src/py_session.cc deleted file mode 100644 index 7d9c28f9..00000000 --- a/src/py_session.cc +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright (c) 2003-2009, John Wiegley. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of New Artisans LLC nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include <system.hh> - -#include "pyinterp.h" - -namespace ledger { - -using namespace boost::python; - -#define EXC_TRANSLATOR(type) \ - void exc_translate_ ## type(const type& err) { \ - PyErr_SetString(PyExc_ArithmeticError, err.what()); \ - } - -//EXC_TRANSLATOR(session_error) - -void export_session() -{ - class_< session_t, bases<symbol_scope_t>, - shared_ptr<session_t>, boost::noncopyable > ("SessionBase") - ; - - class_< python_interpreter_t, bases<session_t>, - shared_ptr<python_interpreter_t>, boost::noncopyable > ("Session") - ; - -#define EXC_TRANSLATE(type) \ - register_exception_translator<type>(&exc_translate_ ## type); - - //EXC_TRANSLATE(session_error); -} - -} // namespace ledger diff --git a/src/py_timelog.cc b/src/py_timelog.cc deleted file mode 100644 index afb19266..00000000 --- a/src/py_timelog.cc +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (c) 2003-2009, John Wiegley. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of New Artisans LLC nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include <system.hh> - -#include "pyinterp.h" - -namespace ledger { - -using namespace boost::python; - -#define EXC_TRANSLATOR(type) \ - void exc_translate_ ## type(const type& err) { \ - PyErr_SetString(PyExc_ArithmeticError, err.what()); \ - } - -//EXC_TRANSLATOR(timelog_error) - -void export_timelog() -{ -#if 0 - class_< time_xact_t > ("TimeXact") - ; - class_< time_log_t > ("TimeLog") - ; -#endif - - //register_optional_to_python<amount_t>(); - - //implicitly_convertible<string, amount_t>(); - -#define EXC_TRANSLATE(type) \ - register_exception_translator<type>(&exc_translate_ ## type); - - //EXC_TRANSLATE(timelog_error); -} - -} // namespace ledger diff --git a/src/py_utils.cc b/src/py_utils.cc index 3e788442..b2b9d0f8 100644 --- a/src/py_utils.cc +++ b/src/py_utils.cc @@ -74,11 +74,13 @@ typedef register_python_conversion<bool, bool_to_python, bool_from_python> bool_python_conversion; +#if defined(STRING_VERIFY_ON) + struct string_to_python { - static PyObject* convert(const string& str) + static PyObject* convert(const ledger::string& str) { - return incref(object(*boost::polymorphic_downcast<const std::string *>(&str)).ptr()); + return incref(object(static_cast<const std::string&>(str)).ptr()); } }; @@ -95,15 +97,17 @@ struct string_from_python const char* value = PyString_AsString(obj_ptr); if (value == 0) throw_error_already_set(); void* storage = - reinterpret_cast<converter::rvalue_from_python_storage<string> *>(data)->storage.bytes; - new (storage) string(value); + reinterpret_cast<converter::rvalue_from_python_storage<ledger::string> *>(data)->storage.bytes; + new (storage) ledger::string(value); data->convertible = storage; } }; -typedef register_python_conversion<string, string_to_python, string_from_python> +typedef register_python_conversion<ledger::string, string_to_python, string_from_python> string_python_conversion; +#endif // STRING_VERIFY_ON + struct istream_to_python { @@ -168,9 +172,10 @@ void export_utils() .def(init<supports_flags<uint_least8_t> >()) .def(init<uint_least8_t>()) - .def("flags", &supports_flags<uint_least8_t>::flags) + .add_property("flags", + &supports_flags<uint_least8_t>::flags, + &supports_flags<uint_least8_t>::set_flags) .def("has_flags", &supports_flags<uint_least8_t>::has_flags) - .def("set_flags", &supports_flags<uint_least8_t>::set_flags) .def("clear_flags", &supports_flags<uint_least8_t>::clear_flags) .def("add_flags", &supports_flags<uint_least8_t>::add_flags) .def("drop_flags", &supports_flags<uint_least8_t>::drop_flags) @@ -180,9 +185,10 @@ void export_utils() .def(init<supports_flags<uint_least16_t> >()) .def(init<uint_least16_t>()) - .def("flags", &supports_flags<uint_least16_t>::flags) + .add_property("flags", + &supports_flags<uint_least16_t>::flags, + &supports_flags<uint_least16_t>::set_flags) .def("has_flags", &supports_flags<uint_least16_t>::has_flags) - .def("set_flags", &supports_flags<uint_least16_t>::set_flags) .def("clear_flags", &supports_flags<uint_least16_t>::clear_flags) .def("add_flags", &supports_flags<uint_least16_t>::add_flags) .def("drop_flags", &supports_flags<uint_least16_t>::drop_flags) @@ -200,16 +206,19 @@ void export_utils() class_< delegates_flags<uint_least16_t>, boost::noncopyable > ("DelegatesFlags16", no_init) - .def("flags", &delegates_flags<uint_least16_t>::flags) + .add_property("flags", + &delegates_flags<uint_least16_t>::flags, + &delegates_flags<uint_least16_t>::set_flags) .def("has_flags", &delegates_flags<uint_least16_t>::has_flags) - .def("set_flags", &delegates_flags<uint_least16_t>::set_flags) .def("clear_flags", &delegates_flags<uint_least16_t>::clear_flags) .def("add_flags", &delegates_flags<uint_least16_t>::add_flags) .def("drop_flags", &delegates_flags<uint_least16_t>::drop_flags) ; bool_python_conversion(); +#if defined(STRING_VERIFY_ON) string_python_conversion(); +#endif istream_python_conversion(); ostream_python_conversion(); } diff --git a/src/py_value.cc b/src/py_value.cc index 34ee2d82..6e4afaf7 100644 --- a/src/py_value.cc +++ b/src/py_value.cc @@ -51,7 +51,7 @@ namespace { { if (value.is_scope()) { if (scope_t * scope = value.as_scope()) - return expr_t(scope->lookup(name), scope); + return expr_t(scope->lookup(symbol_t::FUNCTION, name), scope); } throw_(value_error, _("Cannot lookup attributes in %1") << value.label()); return expr_t(); @@ -112,7 +112,7 @@ void export_value() .def(init<balance_t>()) .def(init<mask_t>()) .def(init<std::string>()) - // jww (2009-11-02): Need to support conversion of sequences + // jww (2009-11-02): Need to support conversion eof value_t::sequence_t //.def(init<value_t::sequence_t>()) .def(init<value_t>()) @@ -314,7 +314,9 @@ void export_value() implicitly_convertible<long, value_t>(); implicitly_convertible<string, value_t>(); - // jww (2009-11-02): ask mask objects here + implicitly_convertible<amount_t, value_t>(); + implicitly_convertible<balance_t, value_t>(); + implicitly_convertible<mask_t, value_t>(); implicitly_convertible<date_t, value_t>(); implicitly_convertible<datetime_t, value_t>(); diff --git a/src/py_xact.cc b/src/py_xact.cc index d98d226c..f5453d15 100644 --- a/src/py_xact.cc +++ b/src/py_xact.cc @@ -85,12 +85,9 @@ void export_xact() class_< xact_base_t, bases<item_t> > ("TransactionBase") .add_property("journal", make_getter(&xact_base_t::journal, - return_value_policy<reference_existing_object>()), + return_internal_reference<>()), make_setter(&xact_base_t::journal, with_custodian_and_ward<1, 2>())) - .add_property("posts", - make_getter(&xact_base_t::posts), - make_setter(&xact_base_t::posts)) .def("__len__", posts_len) .def("__getitem__", posts_getitem, @@ -100,6 +97,12 @@ void export_xact() .def("remove_post", &xact_base_t::add_post) .def("finalize", &xact_base_t::finalize) + + .def("__iter__", range<return_internal_reference<> > + (&xact_t::posts_begin, &xact_t::posts_end)) + .def("posts", range<return_internal_reference<> > + (&xact_t::posts_begin, &xact_t::posts_end)) + .def("valid", &xact_base_t::valid) ; @@ -119,6 +122,8 @@ void export_xact() .def("lookup", &xact_t::lookup) + .def("clear_xdata", &xact_t::clear_xdata) + .def("valid", &xact_t::valid) ; @@ -141,7 +146,7 @@ void export_xact() ("AutomatedTransactionFinalizer") .add_property("journal", make_getter(&auto_xact_finalizer_t::journal, - return_value_policy<reference_existing_object>()), + return_internal_reference<>()), make_setter(&auto_xact_finalizer_t::journal, with_custodian_and_ward<1, 2>())) .def("__call__", &auto_xact_finalizer_t::operator()) diff --git a/src/pyinterp.cc b/src/pyinterp.cc index f565f2c0..8c79e9c7 100644 --- a/src/pyinterp.cc +++ b/src/pyinterp.cc @@ -44,19 +44,14 @@ char * argv0; void export_account(); void export_amount(); void export_balance(); -void export_chain(); void export_commodity(); void export_expr(); void export_flags(); void export_format(); -void export_global(); void export_item(); void export_journal(); void export_post(); -void export_report(); void export_scope(); -void export_session(); -void export_timelog(); void export_times(); void export_utils(); void export_value(); @@ -67,25 +62,24 @@ void initialize_for_python() export_account(); export_amount(); export_balance(); - export_chain(); export_commodity(); export_expr(); export_flags(); export_format(); - export_global(); export_item(); export_journal(); export_post(); - export_report(); export_scope(); - export_session(); - export_timelog(); export_times(); export_utils(); export_value(); export_xact(); +#if 0 + // jww (2009-11-04): This is not valid unless I export the session object. + // But I think Python scripters will interace with a journal instead. scope().attr("current_session") = python_session; +#endif } struct python_run @@ -291,38 +285,40 @@ python_interpreter_t::lookup_option(const char * p) return NULL; } -expr_t::ptr_op_t python_interpreter_t::lookup(const string& name) +expr_t::ptr_op_t python_interpreter_t::lookup(const symbol_t::kind_t kind, + const string& name) { // Give our superclass first dibs on symbol definitions - if (expr_t::ptr_op_t op = session_t::lookup(name)) + if (expr_t::ptr_op_t op = session_t::lookup(kind, name)) return op; - const char * p = name.c_str(); - switch (*p) { - case 'o': - if (WANT_OPT()) { const char * q = p + OPT_PREFIX_LEN; - if (option_t<python_interpreter_t> * handler = lookup_option(q)) - return MAKE_OPT_HANDLER(python_interpreter_t, handler); + switch (kind) { + case symbol_t::FUNCTION: + if (is_initialized && main_nspace.has_key(name.c_str())) { + DEBUG("python.interp", "Python lookup: " << name); + + if (python::object obj = main_nspace.get(name.c_str())) + return WRAP_FUNCTOR(functor_t(name, obj)); } break; - case 'p': - if (WANT_PRECMD()) { const char * q = p + PRECMD_PREFIX_LEN; - switch (*q) { - case 'p': - if (is_eq(q, "python")) - return MAKE_FUNCTOR(python_interpreter_t::python_command); - break; - } - } + case symbol_t::OPTION: + if (option_t<python_interpreter_t> * handler = lookup_option(name.c_str())) + return MAKE_OPT_HANDLER(python_interpreter_t, handler); break; - } - if (is_initialized && main_nspace.has_key(name.c_str())) { - DEBUG("python.interp", "Python lookup: " << name); + case symbol_t::PRECOMMAND: { + const char * p = name.c_str(); + switch (*p) { + case 'p': + if (is_eq(p, "python")) + return MAKE_FUNCTOR(python_interpreter_t::python_command); + break; + } + } - if (python::object obj = main_nspace.get(name.c_str())) - return WRAP_FUNCTOR(functor_t(name, obj)); + default: + break; } return NULL; @@ -338,7 +334,7 @@ value_t python_interpreter_t::functor_t::operator()(call_scope_t& args) if (val.check()) return val(); #if 1 - // jww (2009-02-24): Distinguish between "no return" and a value with an + // jww (2009-02-24): Distinguish between "no return" and values with // unconvertable type return NULL_VALUE; #else diff --git a/src/pyinterp.h b/src/pyinterp.h index 4943eb2f..002e8af1 100644 --- a/src/pyinterp.h +++ b/src/pyinterp.h @@ -103,7 +103,8 @@ public: option_t<python_interpreter_t> * lookup_option(const char * p); - virtual expr_t::ptr_op_t lookup(const string& name); + virtual expr_t::ptr_op_t lookup(const symbol_t::kind_t kind, + const string& name); #if BOOST_VERSION >= 103700 OPTION_(python_interpreter_t, import_, DO_(scope) { diff --git a/src/pyutils.h b/src/pyutils.h index d9b94d50..5709eb35 100644 --- a/src/pyutils.h +++ b/src/pyutils.h @@ -32,7 +32,6 @@ #ifndef _PY_UTILS_H #define _PY_UTILS_H - template <typename T, typename TfromPy> struct object_from_python { diff --git a/src/report.cc b/src/report.cc index 60f6955c..e6f3ccb4 100644 --- a/src/report.cc +++ b/src/report.cc @@ -50,7 +50,7 @@ void report_t::posts_report(post_handler_ptr handler) { journal_posts_iterator walker(*session.journal.get()); pass_down_posts(chain_post_handlers(*this, handler), walker); - session.clean_posts(); + session.journal->clear_xdata(); } void report_t::generate_report(post_handler_ptr handler) @@ -70,7 +70,7 @@ void report_t::xact_report(post_handler_ptr handler, xact_t& xact) { xact_posts_iterator walker(xact); pass_down_posts(chain_post_handlers(*this, handler), walker); - session.clean_posts(xact); + xact.clear_xdata(); } void report_t::accounts_report(acct_handler_ptr handler) @@ -101,15 +101,14 @@ void report_t::accounts_report(acct_handler_ptr handler) else pass_down_accounts(handler, *iter.get()); - session.clean_posts(); - session.clean_accounts(); + session.journal->clear_xdata(); } void report_t::commodities_report(post_handler_ptr handler) { posts_commodities_iterator walker(*session.journal.get()); pass_down_posts(chain_post_handlers(*this, handler), walker); - session.clean_posts(); + session.journal->clear_xdata(); } value_t report_t::fn_amount_expr(call_scope_t& scope) @@ -413,6 +412,9 @@ namespace { args.value().as_sequence().end(); std::pair<expr_t, query_parser_t> info = args_to_predicate(begin, end); + if (! info.first) + throw_(std::runtime_error, + _("Invalid query predicate: %1") << join_args(args)); string limit = info.first.text(); if (! limit.empty()) @@ -422,7 +424,12 @@ namespace { "Predicate = " << report.HANDLER(limit_).str()); if (info.second.tokens_remaining()) { - string display = args_to_predicate(info.second).first.text(); + info = args_to_predicate(info.second); + if (! info.first) + throw_(std::runtime_error, + _("Invalid display predicate: %1") << join_args(args)); + + string display = info.first.text(); if (! display.empty()) report.HANDLER(display_).on(whence, display); @@ -456,8 +463,8 @@ value_t report_t::echo_command(call_scope_t& scope) bool report_t::maybe_import(const string& module) { - if (lookup(string(OPT_PREFIX) + "import_")) { - expr_t(string(OPT_PREFIX) + "import_(\"" + module + "\")").calc(*this); + if (lookup(symbol_t::OPTION, "import_")) { + expr_t(string("import_(\"") + module + "\")").calc(*this); return true; } return false; @@ -699,304 +706,316 @@ option_t<report_t> * report_t::lookup_option(const char * p) return NULL; } -void report_t::define(const string& name, expr_t::ptr_op_t def) +void report_t::define(const symbol_t::kind_t kind, const string& name, + expr_t::ptr_op_t def) { - session.define(name, def); + session.define(kind, name, def); } -expr_t::ptr_op_t report_t::lookup(const string& name) +expr_t::ptr_op_t report_t::lookup(const symbol_t::kind_t kind, + const string& name) { - if (expr_t::ptr_op_t def = session.lookup(name)) + if (expr_t::ptr_op_t def = session.lookup(kind, name)) return def; const char * p = name.c_str(); - switch (*p) { - case 'a': - if (is_eq(p, "amount_expr")) - return MAKE_FUNCTOR(report_t::fn_amount_expr); - else if (is_eq(p, "ansify_if")) - return MAKE_FUNCTOR(report_t::fn_ansify_if); - else if (is_eq(p, "abs")) - return MAKE_FUNCTOR(report_t::fn_abs); - break; - - case 'b': - if (is_eq(p, "black")) - return WRAP_FUNCTOR(fn_black); - else if (is_eq(p, "blink")) - return WRAP_FUNCTOR(fn_blink); - else if (is_eq(p, "blue")) - return WRAP_FUNCTOR(fn_blue); - else if (is_eq(p, "bold")) - return WRAP_FUNCTOR(fn_bold); - break; - - case 'c': - if (WANT_CMD()) { const char * q = p + CMD_PREFIX_LEN; - switch (*q) { - case 'b': - if (*(q + 1) == '\0' || is_eq(q, "bal") || is_eq(q, "balance")) { - return expr_t::op_t::wrap_functor - (reporter<account_t, acct_handler_ptr, &report_t::accounts_report> - (new format_accounts(*this, report_format(HANDLER(balance_format_))), - *this, "#balance")); - } - else if (is_eq(q, "budget")) { - HANDLER(amount_).set_expr(string("#budget"), "(amount, 0)"); - budget_flags |= BUDGET_WRAP_VALUES; - if (! (budget_flags & ~BUDGET_WRAP_VALUES)) - budget_flags |= BUDGET_BUDGETED; - - return expr_t::op_t::wrap_functor - (reporter<account_t, acct_handler_ptr, &report_t::accounts_report> - (new format_accounts(*this, report_format(HANDLER(budget_format_))), - *this, "#budget")); - } - break; - - case 'c': - if (is_eq(q, "csv")) { - return WRAP_FUNCTOR - (reporter<> - (new format_posts(*this, report_format(HANDLER(csv_format_))), - *this, "#csv")); - } - else if (is_eq(q, "cleared")) { - HANDLER(amount_).set_expr(string("#cleared"), - "(amount, cleared ? amount : 0)"); - - return expr_t::op_t::wrap_functor - (reporter<account_t, acct_handler_ptr, &report_t::accounts_report> - (new format_accounts(*this, report_format(HANDLER(cleared_format_))), - *this, "#cleared")); - } - break; - - case 'e': - if (is_eq(q, "equity")) - return WRAP_FUNCTOR - (reporter<> - (new format_posts(*this, report_format(HANDLER(print_format_))), - *this, "#equity")); - else if (is_eq(q, "entry")) - return WRAP_FUNCTOR(xact_command); - else if (is_eq(q, "emacs")) - return WRAP_FUNCTOR - (reporter<>(new format_emacs_posts(output_stream), *this, "#emacs")); - else if (is_eq(q, "echo")) - return MAKE_FUNCTOR(report_t::echo_command); - break; - - case 'p': - if (*(q + 1) == '\0' || is_eq(q, "print")) - return WRAP_FUNCTOR - (reporter<> - (new format_posts(*this, report_format(HANDLER(print_format_)), - HANDLED(raw)), *this, "#print")); - else if (is_eq(q, "prices")) - return expr_t::op_t::wrap_functor - (reporter<post_t, post_handler_ptr, &report_t::commodities_report> - (new format_posts(*this, report_format(HANDLER(prices_format_))), - *this, "#prices")); - else if (is_eq(q, "pricesdb")) - return expr_t::op_t::wrap_functor - (reporter<post_t, post_handler_ptr, &report_t::commodities_report> - (new format_posts(*this, report_format(HANDLER(pricesdb_format_))), - *this, "#pricesdb")); - else if (is_eq(q, "python") && maybe_import("ledger.interp")) - return session.lookup(string(CMD_PREFIX) + "python"); - break; - - case 'r': - if (*(q + 1) == '\0' || is_eq(q, "reg") || is_eq(q, "register")) - return WRAP_FUNCTOR - (reporter<> - (new format_posts(*this, report_format(HANDLER(register_format_))), - *this, "#register")); - else if (is_eq(q, "reload")) - return MAKE_FUNCTOR(report_t::reload_command); - break; - - case 's': - if (is_eq(q, "stats") || is_eq(q, "stat")) - return WRAP_FUNCTOR(report_statistics); - else - if (is_eq(q, "server") && maybe_import("ledger.server")) - return session.lookup(string(CMD_PREFIX) + "server"); - break; - - case 'x': - if (is_eq(q, "xact")) - return WRAP_FUNCTOR(xact_command); - break; - } + switch (kind) { + case symbol_t::FUNCTION: + switch (*p) { + case 'a': + if (is_eq(p, "amount_expr")) + return MAKE_FUNCTOR(report_t::fn_amount_expr); + else if (is_eq(p, "ansify_if")) + return MAKE_FUNCTOR(report_t::fn_ansify_if); + else if (is_eq(p, "abs")) + return MAKE_FUNCTOR(report_t::fn_abs); + break; + + case 'b': + if (is_eq(p, "black")) + return WRAP_FUNCTOR(fn_black); + else if (is_eq(p, "blink")) + return WRAP_FUNCTOR(fn_blink); + else if (is_eq(p, "blue")) + return WRAP_FUNCTOR(fn_blue); + else if (is_eq(p, "bold")) + return WRAP_FUNCTOR(fn_bold); + break; + + case 'c': + if (is_eq(p, "cyan")) + return WRAP_FUNCTOR(fn_cyan); + break; + + case 'd': + if (is_eq(p, "display_amount")) + return MAKE_FUNCTOR(report_t::fn_display_amount); + else if (is_eq(p, "display_total")) + return MAKE_FUNCTOR(report_t::fn_display_total); + else if (is_eq(p, "date")) + return MAKE_FUNCTOR(report_t::fn_now); + break; + + case 'f': + if (is_eq(p, "format_date")) + return MAKE_FUNCTOR(report_t::fn_format_date); + break; + + case 'g': + if (is_eq(p, "get_at")) + return MAKE_FUNCTOR(report_t::fn_get_at); + else if (is_eq(p, "green")) + return WRAP_FUNCTOR(fn_green); + break; + + case 'i': + if (is_eq(p, "is_seq")) + return MAKE_FUNCTOR(report_t::fn_is_seq); + break; + + case 'j': + if (is_eq(p, "justify")) + return MAKE_FUNCTOR(report_t::fn_justify); + else if (is_eq(p, "join")) + return MAKE_FUNCTOR(report_t::fn_join); + break; + + case 'm': + if (is_eq(p, "market")) + return MAKE_FUNCTOR(report_t::fn_market); + else if (is_eq(p, "magenta")) + return WRAP_FUNCTOR(fn_magenta); + break; + + case 'n': + if (is_eq(p, "null")) + return WRAP_FUNCTOR(fn_null); + else if (is_eq(p, "now")) + return MAKE_FUNCTOR(report_t::fn_now); + break; + + case 'o': + if (is_eq(p, "options")) + return MAKE_FUNCTOR(report_t::fn_options); + break; + + case 'p': + if (is_eq(p, "post")) + return WRAP_FUNCTOR(fn_false); + else if (is_eq(p, "percent")) + return MAKE_FUNCTOR(report_t::fn_percent); + else if (is_eq(p, "price")) + return MAKE_FUNCTOR(report_t::fn_price); + break; + + case 'q': + if (is_eq(p, "quoted")) + return MAKE_FUNCTOR(report_t::fn_quoted); + else if (is_eq(p, "quantity")) + return MAKE_FUNCTOR(report_t::fn_quantity); + break; + + case 'r': + if (is_eq(p, "rounded")) + return MAKE_FUNCTOR(report_t::fn_rounded); + else if (is_eq(p, "red")) + return WRAP_FUNCTOR(fn_red); + break; + + case 's': + if (is_eq(p, "scrub")) + return MAKE_FUNCTOR(report_t::fn_scrub); + else if (is_eq(p, "strip")) + return MAKE_FUNCTOR(report_t::fn_strip); + break; + + case 't': + if (is_eq(p, "truncated")) + return MAKE_FUNCTOR(report_t::fn_truncated); + else if (is_eq(p, "total_expr")) + return MAKE_FUNCTOR(report_t::fn_total_expr); + else if (is_eq(p, "today")) + return MAKE_FUNCTOR(report_t::fn_today); + else if (is_eq(p, "t")) + return MAKE_FUNCTOR(report_t::fn_display_amount); + break; + + case 'T': + if (is_eq(p, "T")) + return MAKE_FUNCTOR(report_t::fn_display_total); + break; + + case 'u': + if (is_eq(p, "underline")) + return WRAP_FUNCTOR(fn_underline); + else if (is_eq(p, "unrounded")) + return MAKE_FUNCTOR(report_t::fn_unrounded); + break; + + case 'w': + if (is_eq(p, "white")) + return WRAP_FUNCTOR(fn_white); + break; + + case 'y': + if (is_eq(p, "yellow")) + return WRAP_FUNCTOR(fn_yellow); + break; } - else if (is_eq(p, "cyan")) - return WRAP_FUNCTOR(fn_cyan); - break; - case 'd': - if (is_eq(p, "display_amount")) - return MAKE_FUNCTOR(report_t::fn_display_amount); - else if (is_eq(p, "display_total")) - return MAKE_FUNCTOR(report_t::fn_display_total); - else if (is_eq(p, "date")) - return MAKE_FUNCTOR(report_t::fn_now); - break; - - case 'f': - if (is_eq(p, "format_date")) - return MAKE_FUNCTOR(report_t::fn_format_date); + // Check if they are trying to access an option's setting or value. + if (option_t<report_t> * handler = lookup_option(p)) + return MAKE_OPT_FUNCTOR(report_t, handler); break; - case 'g': - if (is_eq(p, "get_at")) - return MAKE_FUNCTOR(report_t::fn_get_at); - else if (is_eq(p, "green")) - return WRAP_FUNCTOR(fn_green); - break; - - case 'i': - if (is_eq(p, "is_seq")) - return MAKE_FUNCTOR(report_t::fn_is_seq); + case symbol_t::OPTION: + if (option_t<report_t> * handler = lookup_option(p)) + return MAKE_OPT_HANDLER(report_t, handler); break; - case 'j': - if (is_eq(p, "justify")) - return MAKE_FUNCTOR(report_t::fn_justify); - else if (is_eq(p, "join")) - return MAKE_FUNCTOR(report_t::fn_join); - break; - - case 'm': - if (is_eq(p, "market")) - return MAKE_FUNCTOR(report_t::fn_market); - else if (is_eq(p, "magenta")) - return WRAP_FUNCTOR(fn_magenta); - break; - - case 'n': - if (is_eq(p, "null")) - return WRAP_FUNCTOR(fn_null); - else if (is_eq(p, "now")) - return MAKE_FUNCTOR(report_t::fn_now); - break; + case symbol_t::COMMAND: + switch (*p) { + case 'b': + if (*(p + 1) == '\0' || is_eq(p, "bal") || is_eq(p, "balance")) { + return expr_t::op_t::wrap_functor + (reporter<account_t, acct_handler_ptr, &report_t::accounts_report> + (new format_accounts(*this, report_format(HANDLER(balance_format_))), + *this, "#balance")); + } + else if (is_eq(p, "budget")) { + HANDLER(amount_).set_expr(string("#budget"), "(amount, 0)"); - case 'o': - if (WANT_OPT()) { const char * q = p + OPT_PREFIX_LEN; - if (option_t<report_t> * handler = lookup_option(q)) - return MAKE_OPT_HANDLER(report_t, handler); - } - else if (is_eq(p, "options")) { - return MAKE_FUNCTOR(report_t::fn_options); - } - break; + budget_flags |= BUDGET_WRAP_VALUES; + if (! (budget_flags & ~BUDGET_WRAP_VALUES)) + budget_flags |= BUDGET_BUDGETED; - case 'p': - if (WANT_PRECMD()) { const char * q = p + PRECMD_PREFIX_LEN; - switch (*q) { - case 'a': - if (is_eq(q, "args")) - return WRAP_FUNCTOR(args_command); - break; - case 'e': - if (is_eq(q, "eval")) - return WRAP_FUNCTOR(eval_command); - break; - case 'f': - if (is_eq(q, "format")) - return WRAP_FUNCTOR(format_command); - break; - case 'g': - if (is_eq(q, "generate")) - return expr_t::op_t::wrap_functor - (reporter<post_t, post_handler_ptr, &report_t::generate_report> - (new format_posts(*this, report_format(HANDLER(print_format_)), - false), *this, "#generate")); - case 'h': - if (is_eq(q, "hello") && maybe_import("ledger.hello")) - return session.lookup(string(PRECMD_PREFIX) + "hello"); - break; - case 'p': - if (is_eq(q, "parse")) - return WRAP_FUNCTOR(parse_command); - else if (is_eq(q, "period")) - return WRAP_FUNCTOR(period_command); - break; - case 't': - if (is_eq(q, "template")) - return WRAP_FUNCTOR(template_command); - break; + return expr_t::op_t::wrap_functor + (reporter<account_t, acct_handler_ptr, &report_t::accounts_report> + (new format_accounts(*this, report_format(HANDLER(budget_format_))), + *this, "#budget")); + } + break; + + case 'c': + if (is_eq(p, "csv")) { + return WRAP_FUNCTOR + (reporter<> + (new format_posts(*this, report_format(HANDLER(csv_format_))), + *this, "#csv")); } + else if (is_eq(p, "cleared")) { + HANDLER(amount_).set_expr(string("#cleared"), + "(amount, cleared ? amount : 0)"); + + return expr_t::op_t::wrap_functor + (reporter<account_t, acct_handler_ptr, &report_t::accounts_report> + (new format_accounts(*this, report_format(HANDLER(cleared_format_))), + *this, "#cleared")); + } + break; + + case 'e': + if (is_eq(p, "equity")) + return WRAP_FUNCTOR + (reporter<> + (new format_posts(*this, report_format(HANDLER(print_format_))), + *this, "#equity")); + else if (is_eq(p, "entry")) + return WRAP_FUNCTOR(xact_command); + else if (is_eq(p, "emacs")) + return WRAP_FUNCTOR + (reporter<>(new format_emacs_posts(output_stream), *this, "#emacs")); + else if (is_eq(p, "echo")) + return MAKE_FUNCTOR(report_t::echo_command); + break; + + case 'p': + if (*(p + 1) == '\0' || is_eq(p, "print")) + return WRAP_FUNCTOR + (reporter<> + (new format_posts(*this, report_format(HANDLER(print_format_)), + HANDLED(raw)), *this, "#print")); + else if (is_eq(p, "prices")) + return expr_t::op_t::wrap_functor + (reporter<post_t, post_handler_ptr, &report_t::commodities_report> + (new format_posts(*this, report_format(HANDLER(prices_format_))), + *this, "#prices")); + else if (is_eq(p, "pricesdb")) + return expr_t::op_t::wrap_functor + (reporter<post_t, post_handler_ptr, &report_t::commodities_report> + (new format_posts(*this, report_format(HANDLER(pricesdb_format_))), + *this, "#pricesdb")); + else if (is_eq(p, "python") && maybe_import("ledger.interp")) + return session.lookup(symbol_t::COMMAND, "python"); + break; + + case 'r': + if (*(p + 1) == '\0' || is_eq(p, "reg") || is_eq(p, "register")) + return WRAP_FUNCTOR + (reporter<> + (new format_posts(*this, report_format(HANDLER(register_format_))), + *this, "#register")); + else if (is_eq(p, "reload")) + return MAKE_FUNCTOR(report_t::reload_command); + break; + + case 's': + if (is_eq(p, "stats") || is_eq(p, "stat")) + return WRAP_FUNCTOR(report_statistics); + else + if (is_eq(p, "server") && maybe_import("ledger.server")) + return session.lookup(symbol_t::COMMAND, "server"); + break; + + case 'x': + if (is_eq(p, "xact")) + return WRAP_FUNCTOR(xact_command); + break; } - else if (is_eq(p, "post")) - return WRAP_FUNCTOR(fn_false); - else if (is_eq(p, "percent")) - return MAKE_FUNCTOR(report_t::fn_percent); - else if (is_eq(p, "price")) - return MAKE_FUNCTOR(report_t::fn_price); - break; - - case 'q': - if (is_eq(p, "quoted")) - return MAKE_FUNCTOR(report_t::fn_quoted); - else if (is_eq(p, "quantity")) - return MAKE_FUNCTOR(report_t::fn_quantity); break; - case 'r': - if (is_eq(p, "rounded")) - return MAKE_FUNCTOR(report_t::fn_rounded); - else if (is_eq(p, "red")) - return WRAP_FUNCTOR(fn_red); - break; - - case 's': - if (is_eq(p, "scrub")) - return MAKE_FUNCTOR(report_t::fn_scrub); - else if (is_eq(p, "strip")) - return MAKE_FUNCTOR(report_t::fn_strip); - break; - - case 't': - if (is_eq(p, "truncated")) - return MAKE_FUNCTOR(report_t::fn_truncated); - else if (is_eq(p, "total_expr")) - return MAKE_FUNCTOR(report_t::fn_total_expr); - else if (is_eq(p, "today")) - return MAKE_FUNCTOR(report_t::fn_today); - else if (is_eq(p, "t")) - return MAKE_FUNCTOR(report_t::fn_display_amount); - break; - - case 'T': - if (is_eq(p, "T")) - return MAKE_FUNCTOR(report_t::fn_display_total); - break; - - case 'u': - if (is_eq(p, "underline")) - return WRAP_FUNCTOR(fn_underline); - else if (is_eq(p, "unrounded")) - return MAKE_FUNCTOR(report_t::fn_unrounded); - break; - - case 'w': - if (is_eq(p, "white")) - return WRAP_FUNCTOR(fn_white); + case symbol_t::PRECOMMAND: + switch (*p) { + case 'a': + if (is_eq(p, "args")) + return WRAP_FUNCTOR(args_command); + break; + case 'e': + if (is_eq(p, "eval")) + return WRAP_FUNCTOR(eval_command); + break; + case 'f': + if (is_eq(p, "format")) + return WRAP_FUNCTOR(format_command); + break; + case 'g': + if (is_eq(p, "generate")) + return expr_t::op_t::wrap_functor + (reporter<post_t, post_handler_ptr, &report_t::generate_report> + (new format_posts(*this, report_format(HANDLER(print_format_)), + false), *this, "#generate")); + case 'h': + if (is_eq(p, "hello") && maybe_import("ledger.hello")) + return session.lookup(symbol_t::PRECOMMAND, "hello"); + break; + case 'p': + if (is_eq(p, "parse")) + return WRAP_FUNCTOR(parse_command); + else if (is_eq(p, "period")) + return WRAP_FUNCTOR(period_command); + break; + case 't': + if (is_eq(p, "template")) + return WRAP_FUNCTOR(template_command); + break; + } break; - case 'y': - if (is_eq(p, "yellow")) - return WRAP_FUNCTOR(fn_yellow); + default: break; } - // Check if they are trying to access an option's setting or value. - if (option_t<report_t> * handler = lookup_option(p)) - return MAKE_OPT_FUNCTOR(report_t, handler); - return NULL; } diff --git a/src/report.h b/src/report.h index e00c6460..32648648 100644 --- a/src/report.h +++ b/src/report.h @@ -311,9 +311,11 @@ public: option_t<report_t> * lookup_option(const char * p); - virtual void define(const string& name, expr_t::ptr_op_t def); + virtual void define(const symbol_t::kind_t kind, const string& name, + expr_t::ptr_op_t def); - virtual expr_t::ptr_op_t lookup(const string& name); + virtual expr_t::ptr_op_t lookup(const symbol_t::kind_t kind, + const string& name); /** * Option handlers diff --git a/src/scope.cc b/src/scope.cc index 92d123ee..99f6b669 100644 --- a/src/scope.cc +++ b/src/scope.cc @@ -35,31 +35,36 @@ namespace ledger { -void symbol_scope_t::define(const string& name, expr_t::ptr_op_t def) +scope_t * scope_t::default_scope = NULL; + +void symbol_scope_t::define(const symbol_t::kind_t kind, + const string& name, expr_t::ptr_op_t def) { DEBUG("scope.symbols", "Defining '" << name << "' = " << def); std::pair<symbol_map::iterator, bool> result - = symbols.insert(symbol_map::value_type(name, def)); + = symbols.insert(symbol_map::value_type(symbol_t(kind, name, def), def)); if (! result.second) { - symbol_map::iterator i = symbols.find(name); + symbol_map::iterator i = symbols.find(symbol_t(kind, name)); assert(i != symbols.end()); symbols.erase(i); - std::pair<symbol_map::iterator, bool> result2 - = symbols.insert(symbol_map::value_type(name, def)); - if (! result2.second) - throw_(compile_error, _("Redefinition of '%1' in same scope") << name); + result = symbols.insert(symbol_map::value_type(symbol_t(kind, name, def), + def)); + if (! result.second) + throw_(compile_error, + _("Redefinition of '%1' in the same scope") << name); } } -expr_t::ptr_op_t symbol_scope_t::lookup(const string& name) +expr_t::ptr_op_t symbol_scope_t::lookup(const symbol_t::kind_t kind, + const string& name) { - symbol_map::const_iterator i = symbols.find(name); + symbol_map::const_iterator i = symbols.find(symbol_t(kind, name)); if (i != symbols.end()) return (*i).second; - return child_scope_t::lookup(name); + return child_scope_t::lookup(kind, name); } } // namespace ledger diff --git a/src/scope.h b/src/scope.h index 7f2680d6..c2c9df20 100644 --- a/src/scope.h +++ b/src/scope.h @@ -55,9 +55,66 @@ namespace ledger { * * Long. */ +struct symbol_t +{ + enum kind_t { + UNKNOWN, + FUNCTION, + OPTION, + PRECOMMAND, + COMMAND, + DIRECTIVE + }; + + kind_t kind; + string name; + expr_t::ptr_op_t definition; + + symbol_t() : kind(UNKNOWN), name(""), definition(NULL) { + TRACE_CTOR(symbol_t, ""); + } + symbol_t(kind_t _kind, string _name, expr_t::ptr_op_t _definition = NULL) + : kind(_kind), name(_name), definition(_definition) { + TRACE_CTOR(symbol_t, "symbol_t::kind_t, string"); + } + symbol_t(const symbol_t& sym) + : kind(sym.kind), name(sym.name), + definition(sym.definition) { + TRACE_CTOR(symbol_t, "copy"); + } + ~symbol_t() throw() { + TRACE_DTOR(symbol_t); + } + + bool operator<(const symbol_t& sym) const { + return kind < sym.kind || name < sym.name; + } + +#if defined(HAVE_BOOST_SERIALIZATION) +private: + /** Serialization. */ + + friend class boost::serialization::access; + + template<class Archive> + void serialize(Archive& ar, const unsigned int /* version */) { + ar & kind; + ar & name; + ar & definition; + } +#endif // HAVE_BOOST_SERIALIZATION +}; + +/** + * @brief Brief + * + * Long. + */ class scope_t { public: + static scope_t * default_scope; + explicit scope_t() { TRACE_CTOR(scope_t, ""); } @@ -65,8 +122,10 @@ public: TRACE_DTOR(scope_t); } - virtual void define(const string&, expr_t::ptr_op_t) {} - virtual expr_t::ptr_op_t lookup(const string& name) = 0; + virtual void define(const symbol_t::kind_t, const string&, + expr_t::ptr_op_t) {} + virtual expr_t::ptr_op_t lookup(const symbol_t::kind_t kind, + const string& name) = 0; #if defined(HAVE_BOOST_SERIALIZATION) private: @@ -75,7 +134,7 @@ private: friend class boost::serialization::access; template<class Archive> - void serialize(Archive &, const unsigned int /* version */) {} + void serialize(Archive&, const unsigned int /* version */) {} #endif // HAVE_BOOST_SERIALIZATION }; @@ -100,14 +159,16 @@ public: TRACE_DTOR(child_scope_t); } - virtual void define(const string& name, expr_t::ptr_op_t def) { + virtual void define(const symbol_t::kind_t kind, + const string& name, expr_t::ptr_op_t def) { if (parent) - parent->define(name, def); + parent->define(kind, name, def); } - virtual expr_t::ptr_op_t lookup(const string& name) { + virtual expr_t::ptr_op_t lookup(const symbol_t::kind_t kind, + const string& name) { if (parent) - return parent->lookup(name); + return parent->lookup(kind, name); return NULL; } @@ -118,7 +179,7 @@ private: friend class boost::serialization::access; template<class Archive> - void serialize(Archive & ar, const unsigned int /* version */) { + void serialize(Archive& ar, const unsigned int /* version */) { ar & boost::serialization::base_object<scope_t>(*this); ar & parent; } @@ -132,7 +193,7 @@ private: */ class symbol_scope_t : public child_scope_t { - typedef std::map<const string, expr_t::ptr_op_t> symbol_map; + typedef std::map<symbol_t, expr_t::ptr_op_t> symbol_map; symbol_map symbols; @@ -147,9 +208,11 @@ public: TRACE_DTOR(symbol_scope_t); } - virtual void define(const string& name, expr_t::ptr_op_t def); + virtual void define(const symbol_t::kind_t kind, const string& name, + expr_t::ptr_op_t def); - virtual expr_t::ptr_op_t lookup(const string& name); + virtual expr_t::ptr_op_t lookup(const symbol_t::kind_t kind, + const string& name); #if defined(HAVE_BOOST_SERIALIZATION) private: @@ -158,7 +221,7 @@ private: friend class boost::serialization::access; template<class Archive> - void serialize(Archive & ar, const unsigned int /* version */) { + void serialize(Archive& ar, const unsigned int /* version */) { ar & boost::serialization::base_object<child_scope_t>(*this); ar & symbols; } @@ -196,6 +259,9 @@ public: return args[index]; } + void push_front(const value_t& val) { + args.push_front(val); + } void push_back(const value_t& val) { args.push_back(val); } @@ -228,7 +294,7 @@ private: friend class boost::serialization::access; template<class Archive> - void serialize(Archive & ar, const unsigned int /* version */) { + void serialize(Archive& ar, const unsigned int /* version */) { ar & boost::serialization::base_object<child_scope_t>(*this); ar & args; } @@ -256,15 +322,17 @@ public: TRACE_DTOR(bind_scope_t); } - virtual void define(const string& name, expr_t::ptr_op_t def) { - parent->define(name, def); - grandchild.define(name, def); + virtual void define(const symbol_t::kind_t kind, const string& name, + expr_t::ptr_op_t def) { + parent->define(kind, name, def); + grandchild.define(kind, name, def); } - virtual expr_t::ptr_op_t lookup(const string& name) { - if (expr_t::ptr_op_t def = grandchild.lookup(name)) + virtual expr_t::ptr_op_t lookup(const symbol_t::kind_t kind, + const string& name) { + if (expr_t::ptr_op_t def = grandchild.lookup(kind, name)) return def; - return child_scope_t::lookup(name); + return child_scope_t::lookup(kind, name); } #if defined(HAVE_BOOST_SERIALIZATION) @@ -274,7 +342,7 @@ private: friend class boost::serialization::access; template<class Archive> - void serialize(Archive & ar, const unsigned int /* version */) { + void serialize(Archive& ar, const unsigned int /* version */) { ar & boost::serialization::base_object<child_scope_t>(*this); ar & grandchild; } diff --git a/src/session.cc b/src/session.cc index 33c27165..afc092f1 100644 --- a/src/session.cc +++ b/src/session.cc @@ -72,35 +72,6 @@ session_t::session_t() HANDLER(price_db_).on(none, path("./.pricedb").string()); } -std::size_t session_t::read_journal(std::istream& in, - const path& pathname, - account_t * master, - scope_t * scope) -{ - if (! master) - master = journal->master; - - std::size_t count = journal->parse(in, scope ? *scope : *this, - master, &pathname, HANDLED(strict)); - - // remove calculated totals and flags - clean_posts(); - clean_accounts(); - - return count; -} - -std::size_t session_t::read_journal(const path& pathname, - account_t * master, - scope_t * scope) -{ - if (! exists(pathname)) - throw_(std::logic_error, _("Cannot read file '%1'") << pathname); - - ifstream stream(pathname); - return read_journal(stream, pathname, master, scope); -} - std::size_t session_t::read_data(const string& master_account) { bool populated_data_files = false; @@ -130,8 +101,6 @@ std::size_t session_t::read_data(const string& master_account) price_db_path = resolve_path(HANDLER(price_db_).str()); optional<archive_t> cache; -#if 1 - // jww (2009-11-01): The binary caching feature is disabled for now. if (HANDLED(cache_) && master_account.empty()) { cache = archive_t(HANDLED(cache_).str()); @@ -140,23 +109,20 @@ std::size_t session_t::read_data(const string& master_account) populated_price_db = true; } } -#endif if (! (cache && cache->should_load(HANDLER(file_).data_files) && cache->load(journal))) { if (price_db_path) { if (exists(*price_db_path)) { - if (read_journal(*price_db_path) > 0) + if (journal->read(*price_db_path) > 0) throw_(parse_error, _("Transactions not allowed in price history file")); - journal->sources.push_back(journal_t::fileinfo_t(*price_db_path)); } HANDLER(file_).data_files.remove(*price_db_path); } foreach (const path& pathname, HANDLER(file_).data_files) { - path filename = resolve_path(pathname); - if (filename == "-") { + if (pathname == "-") { // To avoid problems with stdin and pipes, etc., we read the entire // file in beforehand into a memory buffer, and then parcel it out // from there. @@ -172,15 +138,10 @@ std::size_t session_t::read_data(const string& master_account) std::istringstream buf_in(buffer.str()); - xact_count += read_journal(buf_in, "/dev/stdin", acct); + xact_count += journal->read(buf_in, "/dev/stdin", acct); journal->sources.push_back(journal_t::fileinfo_t()); - } - else if (exists(filename)) { - xact_count += read_journal(filename, acct); - journal->sources.push_back(journal_t::fileinfo_t(filename)); - } - else { - throw_(parse_error, _("Could not read journal file '%1'") << filename); + } else { + xact_count += journal->read(pathname, acct); } } @@ -227,25 +188,6 @@ void session_t::close_journal_files() amount_t::initialize(journal->commodity_pool); } -void session_t::clean_posts() -{ - journal_posts_iterator walker(*journal.get()); - pass_down_posts(post_handler_ptr(new clear_post_xdata), walker); -} - -void session_t::clean_posts(xact_t& xact) -{ - xact_posts_iterator walker(xact); - pass_down_posts(post_handler_ptr(new clear_post_xdata), walker); -} - -void session_t::clean_accounts() -{ - basic_accounts_iterator acct_walker(*journal->master); - pass_down_accounts(acct_handler_ptr(new clear_account_xdata), acct_walker); - journal->master->clear_xdata(); -} - option_t<session_t> * session_t::lookup_option(const char * p) { switch (*p) { @@ -287,23 +229,26 @@ option_t<session_t> * session_t::lookup_option(const char * p) return NULL; } -expr_t::ptr_op_t session_t::lookup(const string& name) +expr_t::ptr_op_t session_t::lookup(const symbol_t::kind_t kind, + const string& name) { - const char * p = name.c_str(); - switch (*p) { - case 'o': - if (WANT_OPT()) { p += OPT_PREFIX_LEN; - if (option_t<session_t> * handler = lookup_option(p)) - return MAKE_OPT_HANDLER(session_t, handler); - } + switch (kind) { + case symbol_t::FUNCTION: + // Check if they are trying to access an option's setting or value. + if (option_t<session_t> * handler = lookup_option(name.c_str())) + return MAKE_OPT_FUNCTOR(session_t, handler); break; - } - // Check if they are trying to access an option's setting or value. - if (option_t<session_t> * handler = lookup_option(p)) - return MAKE_OPT_FUNCTOR(session_t, handler); + case symbol_t::OPTION: + if (option_t<session_t> * handler = lookup_option(name.c_str())) + return MAKE_OPT_HANDLER(session_t, handler); + break; + + default: + break; + } - return symbol_scope_t::lookup(name); + return symbol_scope_t::lookup(kind, name); } } // namespace ledger diff --git a/src/session.h b/src/session.h index 58e33f6b..7c5d47dd 100644 --- a/src/session.h +++ b/src/session.h @@ -80,27 +80,11 @@ public: flush_on_next_data_file = truth; } - std::size_t read_journal(std::istream& in, - const path& pathname, - account_t * master = NULL, - scope_t * scope = NULL); - std::size_t read_journal(const path& pathname, - account_t * master = NULL, - scope_t * scope = NULL); - std::size_t read_data(const string& master_account = ""); void read_journal_files(); void close_journal_files(); - void clean_posts(); - void clean_posts(xact_t& xact); - void clean_accounts(); - void clean_all() { - clean_posts(); - clean_accounts(); - } - void report_options(std::ostream& out) { HANDLER(account_).report(out); @@ -116,7 +100,8 @@ public: option_t<session_t> * lookup_option(const char * p); - virtual expr_t::ptr_op_t lookup(const string& name); + virtual expr_t::ptr_op_t lookup(const symbol_t::kind_t kind, + const string& name); /** * Option handlers diff --git a/src/system.hh.in b/src/system.hh.in index 4a7dc55f..b0b8f1eb 100644 --- a/src/system.hh.in +++ b/src/system.hh.in @@ -155,6 +155,7 @@ typedef std::ostream::pos_type ostream_pos_type; #include <boost/iostreams/stream.hpp> #include <boost/iostreams/write.hpp> #include <boost/iostreams/device/file_descriptor.hpp> +#include <boost/iterator/transform_iterator.hpp> #include <boost/lexical_cast.hpp> #include <boost/operators.hpp> #include <boost/optional.hpp> @@ -242,12 +243,6 @@ void serialize(Archive& ar, istream_pos_type& pos, const unsigned int) #include <boost/python/detail/wrap_python.hpp> #include <datetime.h> -#include <boost/python/exception_translator.hpp> -#include <boost/python/implicit.hpp> -#include <boost/python/args.hpp> -#include <boost/python/module.hpp> -#include <boost/python/def.hpp> -#include <boost/python/to_python_converter.hpp> #include <boost/python/module_init.hpp> #endif // HAVE_BOOST_PYTHON diff --git a/src/textual.cc b/src/textual.cc index c2976ee1..6e2c919f 100644 --- a/src/textual.cc +++ b/src/textual.cc @@ -140,7 +140,8 @@ namespace { std::streamsize len, account_t * account); - virtual expr_t::ptr_op_t lookup(const string& name); + virtual expr_t::ptr_op_t lookup(const symbol_t::kind_t kind, + const string& name); }; void parse_amount_expr(scope_t& scope, @@ -749,11 +750,7 @@ void instance_t::general_directive(char * line) break; } - scoped_array<char> directive(new char[std::strlen(p) + DIR_PREFIX_LEN + 1]); - std::strcpy(directive.get(), DIR_PREFIX); - std::strcpy(directive.get() + DIR_PREFIX_LEN, p); - - if (expr_t::ptr_op_t op = lookup(directive.get())) { + if (expr_t::ptr_op_t op = lookup(symbol_t::DIRECTIVE, p)) { call_scope_t args(*this); args.push_back(string_value(p)); op->as_function()(args); @@ -1233,9 +1230,10 @@ xact_t * instance_t::parse_xact(char * line, } } -expr_t::ptr_op_t instance_t::lookup(const string& name) +expr_t::ptr_op_t instance_t::lookup(const symbol_t::kind_t kind, + const string& name) { - return scope.lookup(name); + return scope.lookup(kind, name); } std::size_t journal_t::parse(std::istream& in, diff --git a/src/times.h b/src/times.h index db83d175..9387320e 100644 --- a/src/times.h +++ b/src/times.h @@ -178,7 +178,7 @@ public: friend class boost::serialization::access; template<class Archive> - void serialize(Archive & ar, const unsigned int /* version */) { + void serialize(Archive& ar, const unsigned int /* version */) { ar & quantum; ar & length; } @@ -265,7 +265,7 @@ private: friend class boost::serialization::access; template<class Archive> - void serialize(Archive & ar, const unsigned int /* version */) { + void serialize(Archive& ar, const unsigned int /* version */) { ar & start; ar & aligned; ar & skip_duration; diff --git a/src/utils.cc b/src/utils.cc index c68737dc..2f2899fb 100644 --- a/src/utils.cc +++ b/src/utils.cc @@ -407,6 +407,8 @@ void report_memory(std::ostream& out, bool report_all) } +#if defined(STRING_VERIFY_ON) + string::string() : std::string() { TRACE_CTOR(string, ""); } @@ -443,6 +445,8 @@ string::~string() throw() { TRACE_DTOR(string); } +#endif // STRING_VERIFY_ON + } // namespace ledger #endif // VERIFY_ON diff --git a/src/utils.h b/src/utils.h index cdb43037..a8784a66 100644 --- a/src/utils.h +++ b/src/utils.h @@ -62,6 +62,10 @@ #define TIMERS_ON 1 #endif +#if defined(VERIFY_ON) +//#define STRING_VERIFY_ON 1 +#endif + /*@}*/ /** @@ -72,7 +76,7 @@ namespace ledger { using namespace boost; -#if defined(VERIFY_ON) +#if defined(STRING_VERIFY_ON) class string; #else typedef std::string string; @@ -158,6 +162,8 @@ void trace_dtor_func(void * ptr, const char * cls_name, std::size_t cls_size); void report_memory(std::ostream& out, bool report_all = false); +#if defined(STRING_VERIFY_ON) + /** * @brief Brief * @@ -186,7 +192,7 @@ private: friend class boost::serialization::access; template<class Archive> - void serialize(Archive & ar, const unsigned int /* version */) { + void serialize(Archive& ar, const unsigned int /* version */) { ar & boost::serialization::base_object<std::string>(*this); } #endif // HAVE_BOOST_SERIALIZATION @@ -236,6 +242,8 @@ inline bool operator!=(const char* __lhs, const string& __rhs) inline bool operator!=(const string& __lhs, const char* __rhs) { return __lhs.compare(__rhs) != 0; } +#endif // STRING_VERIFY_ON + } // namespace ledger #else // ! VERIFY_ON diff --git a/src/value.h b/src/value.h index 2ce90fa2..0993305e 100644 --- a/src/value.h +++ b/src/value.h @@ -87,7 +87,7 @@ public: * The sequence_t member type abstracts the type used to represent a * resizable "array" of value_t objects. */ - typedef std::vector<value_t> sequence_t; + typedef std::deque<value_t> sequence_t; typedef sequence_t::iterator iterator; typedef sequence_t::const_iterator const_iterator; typedef sequence_t::difference_type difference_type; @@ -234,7 +234,7 @@ private: friend class boost::serialization::access; template<class Archive> - void serialize(Archive & ar, const unsigned int /* version */) { + void serialize(Archive& ar, const unsigned int /* version */) { ar & data; ar & type; ar & refc; @@ -800,6 +800,14 @@ public: return null; } + void push_front(const value_t& val) { + if (is_null()) + *this = sequence_t(); + if (! is_sequence()) + in_place_cast(SEQUENCE); + as_sequence_lval().push_front(val); + } + void push_back(const value_t& val) { if (is_null()) *this = sequence_t(); @@ -917,7 +925,7 @@ private: friend class boost::serialization::access; template<class Archive> - void serialize(Archive & ar, const unsigned int /* version */) { + void serialize(Archive& ar, const unsigned int /* version */) { ar & true_value; ar & false_value; ar & storage; diff --git a/src/xact.cc b/src/xact.cc index 3291c5be..9e5f504e 100644 --- a/src/xact.cc +++ b/src/xact.cc @@ -76,6 +76,13 @@ bool xact_base_t::remove_post(post_t * post) return true; } +void xact_base_t::clear_xdata() +{ + foreach (post_t * post, posts) + if (! post->has_flags(ITEM_TEMP)) + post->clear_xdata(); +} + bool xact_base_t::finalize() { // Scan through and compute the total balance for the xact. This is used @@ -422,8 +429,12 @@ namespace { } } -expr_t::ptr_op_t xact_t::lookup(const string& name) +expr_t::ptr_op_t xact_t::lookup(const symbol_t::kind_t kind, + const string& name) { + if (kind != symbol_t::FUNCTION) + return item_t::lookup(kind, name); + switch (name[0]) { case 'c': if (name == "code") @@ -448,7 +459,7 @@ expr_t::ptr_op_t xact_t::lookup(const string& name) break; } - return item_t::lookup(name); + return item_t::lookup(kind, name); } bool xact_t::valid() const @@ -77,7 +77,17 @@ public: virtual void add_post(post_t * post); virtual bool remove_post(post_t * post); + posts_list::iterator posts_begin() { + return posts.begin(); + } + posts_list::iterator posts_end() { + return posts.end(); + } + virtual bool finalize(); + + void clear_xdata(); + virtual bool valid() const { return true; } @@ -89,7 +99,7 @@ private: friend class boost::serialization::access; template<class Archive> - void serialize(Archive & ar, const unsigned int /* version */) { + void serialize(Archive& ar, const unsigned int /* version */) { ar & boost::serialization::base_object<item_t>(*this); ar & journal; ar & posts; @@ -123,7 +133,8 @@ public: string idstring() const; string id() const; - virtual expr_t::ptr_op_t lookup(const string& name); + virtual expr_t::ptr_op_t lookup(const symbol_t::kind_t kind, + const string& name); virtual bool valid() const; @@ -134,7 +145,7 @@ private: friend class boost::serialization::access; template<class Archive> - void serialize(Archive & ar, const unsigned int /* version */) { + void serialize(Archive& ar, const unsigned int /* version */) { ar & boost::serialization::base_object<xact_base_t>(*this); ar & code; ar & payee; @@ -188,7 +199,7 @@ private: friend class boost::serialization::access; template<class Archive> - void serialize(Archive & ar, const unsigned int /* version */) { + void serialize(Archive& ar, const unsigned int /* version */) { ar & boost::serialization::base_object<xact_base_t>(*this); ar & predicate; } @@ -227,7 +238,7 @@ private: friend class boost::serialization::access; template<class Archive> - void serialize(Archive & ar, const unsigned int /* version */) { + void serialize(Archive& ar, const unsigned int /* version */) { ar & journal; } #endif // HAVE_BOOST_SERIALIZATION @@ -267,7 +278,7 @@ private: friend class boost::serialization::access; template<class Archive> - void serialize(Archive & ar, const unsigned int /* version */) { + void serialize(Archive& ar, const unsigned int /* version */) { ar & boost::serialization::base_object<xact_base_t>(*this); ar & period; ar & period_string; diff --git a/tools/Makefile.am b/tools/Makefile.am index 11f79050..f19f9030 100644 --- a/tools/Makefile.am +++ b/tools/Makefile.am @@ -208,19 +208,14 @@ libledger_python_la_SOURCES = \ src/py_account.cc \ src/py_amount.cc \ src/py_balance.cc \ - src/py_chain.cc \ src/py_commodity.cc \ src/py_expr.cc \ src/py_flags.cc \ src/py_format.cc \ - src/py_global.cc \ src/py_item.cc \ src/py_journal.cc \ src/py_post.cc \ - src/py_report.cc \ src/py_scope.cc \ - src/py_session.cc \ - src/py_timelog.cc \ src/py_times.cc \ src/py_utils.cc \ src/py_value.cc \ |