diff options
author | John Wiegley <johnw@newartisans.com> | 2009-11-04 20:40:07 -0500 |
---|---|---|
committer | John Wiegley <johnw@newartisans.com> | 2009-11-04 20:40:48 -0500 |
commit | 78e6770c4c276db3647952f21a6bf3ea465edb88 (patch) | |
tree | 64190d80ea0c3933dffaee3cf0e43cde5ea0e6a6 /src | |
parent | 4a14f3224b9063202ca39a67c9aff42ae4274942 (diff) | |
download | fork-ledger-78e6770c4c276db3647952f21a6bf3ea465edb88.tar.gz fork-ledger-78e6770c4c276db3647952f21a6bf3ea465edb88.tar.bz2 fork-ledger-78e6770c4c276db3647952f21a6bf3ea465edb88.zip |
Segregated symbols into 5 separate namespaces
The different namespaces are:
Function Value expression functions, which receive a "context"
Option Command-line options
Precommand Commands which are invoked before reading the journal
Command Commands which are invoked after reading the journal
Directive Directives that occur at column 0 in a data file
This greatly eases the ability for Python uses to add intercept hooks to
change how the basic Ledger module functions. An example of what should
be possible soon:
import ledger
def my_foo_handler(value):
print "--foo received:", value
ledger.add_handler(ledger.Option, "foo=", my_foo_handler)
Diffstat (limited to 'src')
-rw-r--r-- | src/account.cc | 6 | ||||
-rw-r--r-- | src/account.h | 3 | ||||
-rw-r--r-- | src/global.cc | 44 | ||||
-rw-r--r-- | src/global.h | 3 | ||||
-rw-r--r-- | src/item.cc | 6 | ||||
-rw-r--r-- | src/item.h | 3 | ||||
-rw-r--r-- | src/op.cc | 14 | ||||
-rw-r--r-- | src/option.cc | 22 | ||||
-rw-r--r-- | src/option.h | 24 | ||||
-rw-r--r-- | src/post.cc | 8 | ||||
-rw-r--r-- | src/post.h | 3 | ||||
-rw-r--r-- | src/py_value.cc | 2 | ||||
-rw-r--r-- | src/pyinterp.cc | 46 | ||||
-rw-r--r-- | src/pyinterp.h | 3 | ||||
-rw-r--r-- | src/report.cc | 562 | ||||
-rw-r--r-- | src/report.h | 6 | ||||
-rw-r--r-- | src/scope.cc | 23 | ||||
-rw-r--r-- | src/scope.h | 93 | ||||
-rw-r--r-- | src/session.cc | 29 | ||||
-rw-r--r-- | src/session.h | 3 | ||||
-rw-r--r-- | src/textual.cc | 14 | ||||
-rw-r--r-- | src/xact.cc | 8 | ||||
-rw-r--r-- | src/xact.h | 3 |
23 files changed, 507 insertions, 421 deletions
diff --git a/src/account.cc b/src/account.cc index 23761049..2a75a6ac 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") diff --git a/src/account.h b/src/account.h index ac4a4788..7d51a08e 100644 --- a/src/account.h +++ b/src/account.h @@ -119,7 +119,8 @@ public: } bool remove_post(post_t * post); - 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; diff --git a/src/global.cc b/src/global.cc index d9028dd7..97a46cce 100644 --- a/src/global.cc +++ b/src/global.cc @@ -314,28 +314,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 +400,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 +409,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..34577656 100644 --- a/src/global.h +++ b/src/global.h @@ -117,7 +117,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") @@ -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; @@ -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; } 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 7e2e0629..c9903c03 100644 --- a/src/option.h +++ b/src/option.h @@ -283,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); 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; diff --git a/src/py_value.cc b/src/py_value.cc index 86311736..eec3b833 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(); diff --git a/src/pyinterp.cc b/src/pyinterp.cc index 005fc57a..8c79e9c7 100644 --- a/src/pyinterp.cc +++ b/src/pyinterp.cc @@ -285,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; 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/report.cc b/src/report.cc index fe482a2e..883b324a 100644 --- a/src/report.cc +++ b/src/report.cc @@ -464,8 +464,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; @@ -707,304 +707,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); + // 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 '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); + case symbol_t::OPTION: + if (option_t<report_t> * handler = lookup_option(p)) + return MAKE_OPT_HANDLER(report_t, handler); 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 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..998eac64 100644 --- a/src/scope.cc +++ b/src/scope.cc @@ -35,31 +35,34 @@ namespace ledger { -void symbol_scope_t::define(const string& name, expr_t::ptr_op_t def) +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 36eb54f1..7cf89c3e 100644 --- a/src/scope.h +++ b/src/scope.h @@ -55,6 +55,61 @@ 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: @@ -65,8 +120,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: @@ -100,14 +157,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; } @@ -132,7 +191,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 +206,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: @@ -259,15 +320,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) diff --git a/src/session.cc b/src/session.cc index 2b8d8d58..67f19ca9 100644 --- a/src/session.cc +++ b/src/session.cc @@ -284,23 +284,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..972a97ba 100644 --- a/src/session.h +++ b/src/session.h @@ -116,7 +116,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/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/xact.cc b/src/xact.cc index 3291c5be..473837b6 100644 --- a/src/xact.cc +++ b/src/xact.cc @@ -422,8 +422,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 +452,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 @@ -123,7 +123,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; |