Added a new 'format' debugging command, which dissects the formatting

expression in its argument.
This commit is contained in:
John Wiegley 2008-08-01 03:44:22 -04:00
parent 8ed99e621d
commit ea3b386062
9 changed files with 65 additions and 15 deletions

14
expr.cc
View file

@ -32,6 +32,7 @@
#include "expr.h" #include "expr.h"
#include "parser.h" #include "parser.h"
#include "op.h" #include "op.h"
#include "scope.h" // jww (2008-08-01): not necessary
namespace ledger { namespace ledger {
@ -153,8 +154,10 @@ value_t expr_t::eval(const string& _expr, scope_t& scope)
void expr_t::print(std::ostream& out, scope_t& scope) const void expr_t::print(std::ostream& out, scope_t& scope) const
{ {
op_t::print_context_t context(scope); if (ptr) {
ptr->print(out, context); op_t::print_context_t context(scope);
ptr->print(out, context);
}
} }
void expr_t::dump(std::ostream& out) const void expr_t::dump(std::ostream& out) const
@ -187,4 +190,11 @@ void expr_t::shutdown()
parser.reset(); parser.reset();
} }
std::ostream& operator<<(std::ostream& out, const expr_t& expr) {
// jww (2008-08-01): shouldn't be necessary
symbol_scope_t scope;
expr.print(out, scope);
return out;
}
} // namespace ledger } // namespace ledger

2
expr.h
View file

@ -115,6 +115,8 @@ public:
static value_t eval(const string& _expr, scope_t& scope); static value_t eval(const string& _expr, scope_t& scope);
}; };
std::ostream& operator<<(std::ostream& out, const expr_t& expr);
} // namespace ledger } // namespace ledger
#endif // _EXPR_H #endif // _EXPR_H

View file

@ -13,6 +13,31 @@ int format_t::abbrev_length = 2;
bool format_t::ansi_codes = false; bool format_t::ansi_codes = false;
bool format_t::ansi_invert = false; bool format_t::ansi_invert = false;
void format_t::element_t::dump(std::ostream& out) const
{
out << "Element: ";
switch (type) {
case STRING: out << " STRING"; break;
case EXPR: out << " EXPR"; break;
}
out << " flags: " << int(flags);
out << " min: ";
out << std::right;
out.width(2);
out << int(min_width);
out << " max: ";
out << std::right;
out.width(2);
out << int(max_width);
switch (type) {
case STRING: out << " str: '" << chars << "'" << std::endl; break;
case EXPR: out << " expr: " << expr << std::endl; break;
}
}
namespace { namespace {
string partial_account_name(const account_t& account) string partial_account_name(const account_t& account)
{ {
@ -160,7 +185,7 @@ format_t::element_t * format_t::parse_elements(const string& fmt)
default: default:
current->type = element_t::EXPR; current->type = element_t::EXPR;
current->expr.parse(string("format_") + *p); current->expr.parse(string("fmt_") + *p);
break; break;
} }
} }

View file

@ -34,11 +34,11 @@ class format_t : public noncopyable
scoped_ptr<struct element_t> next; scoped_ptr<struct element_t> next;
element_t() element_t() throw()
: type(STRING), flags(false), min_width(0), max_width(0) { : type(STRING), flags(false), min_width(0), max_width(0) {
TRACE_CTOR(element_t, ""); TRACE_CTOR(element_t, "");
} }
~element_t() { ~element_t() throw() {
TRACE_DTOR(element_t); TRACE_DTOR(element_t);
} }
@ -55,6 +55,8 @@ class format_t : public noncopyable
if (elem->min_width > 0) if (elem->min_width > 0)
out.width(elem->min_width); out.width(elem->min_width);
} }
void dump(std::ostream& out) const;
}; };
string format_string; string format_string;
@ -92,6 +94,13 @@ public:
void format(std::ostream& out, scope_t& scope) const; void format(std::ostream& out, scope_t& scope) const;
void dump(std::ostream& out) const {
for (const element_t * elem = elements.get();
elem;
elem = elem->next.get())
elem->dump(out);
}
private: private:
static element_t * parse_elements(const string& fmt); static element_t * parse_elements(const string& fmt);

View file

@ -217,6 +217,11 @@ static int read_and_report(ledger::report_t& report, int argc, char * argv[],
*out << expr.calc(report).strip_annotations() << std::endl; *out << expr.calc(report).strip_annotations() << std::endl;
return 0; return 0;
} }
else if (verb == "format") {
format_t fmt(*arg);
fmt.dump(*out);
return 0;
}
// Parse the initialization file, which can only be textual; then // Parse the initialization file, which can only be textual; then
// parse the journal data. // parse the journal data.

View file

@ -39,8 +39,8 @@ namespace {
op_bool_tuple find_option(scope_t& scope, const string& name) op_bool_tuple find_option(scope_t& scope, const string& name)
{ {
char buf[128]; char buf[128];
std::strcpy(buf, "option_"); std::strcpy(buf, "opt_");
char * p = &buf[7]; char * p = &buf[4];
foreach (char ch, name) { foreach (char ch, name) {
if (ch == '-') if (ch == '-')
*p++ = '_'; *p++ = '_';

View file

@ -151,10 +151,9 @@ expr_t::parser_t::parse_value_term(std::istream& in,
} }
case token_t::LPAREN: case token_t::LPAREN:
node = new op_t(op_t::O_COMMA); node = parse_value_expr(in, tflags | EXPR_PARSE_PARTIAL);
node->set_left(parse_value_expr(in, tflags | EXPR_PARSE_PARTIAL)); if (! node)
if (! node->left()) throw_(parse_error, tok.symbol << " operator not followed by expression");
throw_(parse_error, tok.symbol << " operator not followed by argument");
tok = next_token(in, tflags); tok = next_token(in, tflags);
if (tok.kind != token_t::RPAREN) if (tok.kind != token_t::RPAREN)

View file

@ -352,8 +352,8 @@ expr_t::ptr_op_t report_t::lookup(const string& name)
const char * p = name.c_str(); const char * p = name.c_str();
switch (*p) { switch (*p) {
case 'o': case 'o':
if (std::strncmp(p, "option_", 7) == 0) { if (std::strncmp(p, "opt_", 4) == 0) {
p = p + 7; p = p + 4;
switch (*p) { switch (*p) {
case 'a': case 'a':
#if 0 #if 0

View file

@ -292,8 +292,8 @@ expr_t::ptr_op_t session_t::lookup(const string& name)
const char * p = name.c_str(); const char * p = name.c_str();
switch (*p) { switch (*p) {
case 'o': case 'o':
if (std::strncmp(p, "option_", 7) == 0) { if (std::strncmp(p, "opt_", 4) == 0) {
p = p + 7; p = p + 4;
switch (*p) { switch (*p) {
case 'd': case 'd':
if (std::strcmp(p, "debug_") == 0) if (std::strcmp(p, "debug_") == 0)