Added a new 'format' debugging command, which dissects the formatting
expression in its argument.
This commit is contained in:
parent
8ed99e621d
commit
ea3b386062
9 changed files with 65 additions and 15 deletions
14
expr.cc
14
expr.cc
|
|
@ -32,6 +32,7 @@
|
|||
#include "expr.h"
|
||||
#include "parser.h"
|
||||
#include "op.h"
|
||||
#include "scope.h" // jww (2008-08-01): not necessary
|
||||
|
||||
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
|
||||
{
|
||||
op_t::print_context_t context(scope);
|
||||
ptr->print(out, context);
|
||||
if (ptr) {
|
||||
op_t::print_context_t context(scope);
|
||||
ptr->print(out, context);
|
||||
}
|
||||
}
|
||||
|
||||
void expr_t::dump(std::ostream& out) const
|
||||
|
|
@ -187,4 +190,11 @@ void expr_t::shutdown()
|
|||
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
|
||||
|
|
|
|||
2
expr.h
2
expr.h
|
|
@ -115,6 +115,8 @@ public:
|
|||
static value_t eval(const string& _expr, scope_t& scope);
|
||||
};
|
||||
|
||||
std::ostream& operator<<(std::ostream& out, const expr_t& expr);
|
||||
|
||||
} // namespace ledger
|
||||
|
||||
#endif // _EXPR_H
|
||||
|
|
|
|||
27
format.cc
27
format.cc
|
|
@ -13,6 +13,31 @@ int format_t::abbrev_length = 2;
|
|||
bool format_t::ansi_codes = 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 {
|
||||
string partial_account_name(const account_t& account)
|
||||
{
|
||||
|
|
@ -160,7 +185,7 @@ format_t::element_t * format_t::parse_elements(const string& fmt)
|
|||
|
||||
default:
|
||||
current->type = element_t::EXPR;
|
||||
current->expr.parse(string("format_") + *p);
|
||||
current->expr.parse(string("fmt_") + *p);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
13
format.h
13
format.h
|
|
@ -34,11 +34,11 @@ class format_t : public noncopyable
|
|||
|
||||
scoped_ptr<struct element_t> next;
|
||||
|
||||
element_t()
|
||||
element_t() throw()
|
||||
: type(STRING), flags(false), min_width(0), max_width(0) {
|
||||
TRACE_CTOR(element_t, "");
|
||||
}
|
||||
~element_t() {
|
||||
~element_t() throw() {
|
||||
TRACE_DTOR(element_t);
|
||||
}
|
||||
|
||||
|
|
@ -55,6 +55,8 @@ class format_t : public noncopyable
|
|||
if (elem->min_width > 0)
|
||||
out.width(elem->min_width);
|
||||
}
|
||||
|
||||
void dump(std::ostream& out) const;
|
||||
};
|
||||
|
||||
string format_string;
|
||||
|
|
@ -92,6 +94,13 @@ public:
|
|||
|
||||
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:
|
||||
static element_t * parse_elements(const string& fmt);
|
||||
|
||||
|
|
|
|||
5
main.cc
5
main.cc
|
|
@ -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;
|
||||
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 journal data.
|
||||
|
|
|
|||
|
|
@ -39,8 +39,8 @@ namespace {
|
|||
op_bool_tuple find_option(scope_t& scope, const string& name)
|
||||
{
|
||||
char buf[128];
|
||||
std::strcpy(buf, "option_");
|
||||
char * p = &buf[7];
|
||||
std::strcpy(buf, "opt_");
|
||||
char * p = &buf[4];
|
||||
foreach (char ch, name) {
|
||||
if (ch == '-')
|
||||
*p++ = '_';
|
||||
|
|
|
|||
|
|
@ -151,10 +151,9 @@ expr_t::parser_t::parse_value_term(std::istream& in,
|
|||
}
|
||||
|
||||
case token_t::LPAREN:
|
||||
node = new op_t(op_t::O_COMMA);
|
||||
node->set_left(parse_value_expr(in, tflags | EXPR_PARSE_PARTIAL));
|
||||
if (! node->left())
|
||||
throw_(parse_error, tok.symbol << " operator not followed by argument");
|
||||
node = parse_value_expr(in, tflags | EXPR_PARSE_PARTIAL);
|
||||
if (! node)
|
||||
throw_(parse_error, tok.symbol << " operator not followed by expression");
|
||||
|
||||
tok = next_token(in, tflags);
|
||||
if (tok.kind != token_t::RPAREN)
|
||||
|
|
|
|||
|
|
@ -352,8 +352,8 @@ expr_t::ptr_op_t report_t::lookup(const string& name)
|
|||
const char * p = name.c_str();
|
||||
switch (*p) {
|
||||
case 'o':
|
||||
if (std::strncmp(p, "option_", 7) == 0) {
|
||||
p = p + 7;
|
||||
if (std::strncmp(p, "opt_", 4) == 0) {
|
||||
p = p + 4;
|
||||
switch (*p) {
|
||||
case 'a':
|
||||
#if 0
|
||||
|
|
|
|||
|
|
@ -292,8 +292,8 @@ expr_t::ptr_op_t session_t::lookup(const string& name)
|
|||
const char * p = name.c_str();
|
||||
switch (*p) {
|
||||
case 'o':
|
||||
if (std::strncmp(p, "option_", 7) == 0) {
|
||||
p = p + 7;
|
||||
if (std::strncmp(p, "opt_", 4) == 0) {
|
||||
p = p + 4;
|
||||
switch (*p) {
|
||||
case 'd':
|
||||
if (std::strcmp(p, "debug_") == 0)
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue