Revised the way that exceptions are thrown around. Instead of context being a

complicated string of pointers, it's now just a global block of text that gets
appended to as the error is being thrown up, and can be displayed at the catch
point if desired.  There are almost no cases where a thrown exception will not
result in an error message being displayed to the user.
This commit is contained in:
John Wiegley 2008-07-31 06:24:45 -04:00
parent 8afd926a27
commit 99313ebc6c
36 changed files with 242 additions and 406 deletions

View file

@ -54,7 +54,7 @@ class commodity_t;
class annotation_t; class annotation_t;
class commodity_pool_t; class commodity_pool_t;
DECLARE_EXCEPTION(error, amount_error); DECLARE_EXCEPTION(amount_error, std::runtime_error);
/** /**
* @class amount_t * @class amount_t

View file

@ -48,7 +48,7 @@
namespace ledger { namespace ledger {
DECLARE_EXCEPTION(error, balance_error); DECLARE_EXCEPTION(balance_error, std::runtime_error);
/** /**
* @class balance_t * @class balance_t

View file

@ -727,8 +727,8 @@ std::size_t read_session(std::istream& in,
// expression passed to an option, we'll just override the flags, but // expression passed to an option, we'll just override the flags, but
// keep the commodity pointer intact. // keep the commodity pointer intact.
if (c == commodity_t::base_t::commodities.end()) if (c == commodity_t::base_t::commodities.end())
throw new error(string("Failed to read base commodity from cache: ") + throw_(cache_error, "Failed to read base commodity from cache: "
commodity->symbol); << commodity->symbol);
(*c).second->name = commodity->name; (*c).second->name = commodity->name;
(*c).second->note = commodity->note; (*c).second->note = commodity->note;
@ -769,8 +769,8 @@ std::size_t read_session(std::istream& in,
commodities_map::iterator c = commodities_map::iterator c =
commodity_t::commodities.find(mapping_key); commodity_t::commodities.find(mapping_key);
if (c == commodity_t::commodities.end()) if (c == commodity_t::commodities.end())
throw new error(string("Failed to read commodity from cache: ") + throw_(cache_error, "Failed to read commodity from cache: "
commodity->symbol()); << commodity->symbol());
*(commodities_next - 1) = (*c).second; *(commodities_next - 1) = (*c).second;
checked_delete(commodity); checked_delete(commodity);

View file

@ -39,6 +39,8 @@
namespace ledger { namespace ledger {
DECLARE_EXCEPTION(cache_error, std::runtime_error);
class binary_cache_t class binary_cache_t
{ {
static const unsigned long binary_magic_number = 0xFFEED765; static const unsigned long binary_magic_number = 0xFFEED765;

View file

@ -18,7 +18,7 @@ entry_t * derive_new_entry(report_t& report,
//added->_date = *i++; //added->_date = *i++;
added->_date = boost::posix_time::time_from_string(*i++); added->_date = boost::posix_time::time_from_string(*i++);
if (i == end) if (i == end)
throw new error("Too few arguments to 'entry'"); throw std::runtime_error("Too few arguments to 'entry'");
mask_t regexp(*i++); mask_t regexp(*i++);
@ -196,7 +196,7 @@ entry_t * derive_new_entry(report_t& report,
! added->finalize() || ! added->finalize() ||
(matching && (matching &&
! matching->journal->entry_finalize_hooks.run_hooks(*added, true))) ! matching->journal->entry_finalize_hooks.run_hooks(*added, true)))
throw new error("Failed to finalize derived entry (check commodities)"); throw std::runtime_error("Failed to finalize derived entry (check commodities)");
return added.release(); return added.release();
} }

View file

@ -320,12 +320,14 @@ bool entry_base_t::finalize()
if (! balance.is_null()) { if (! balance.is_null()) {
balance.round(); balance.round();
if (! balance.is_zero()) { if (! balance.is_zero()) {
#if 0
error * err = error * err =
new balance_error("Entry does not balance", new balance_error("Entry does not balance",
new entry_context(*this, "While balancing entry:")); new entry_context(*this, "While balancing entry:"));
err->context.push_front err->context.push_front
(new value_context(balance, "Unbalanced remainder is:")); (new value_context(balance, "Unbalanced remainder is:"));
throw err; throw err;
#endif
} }
} }
@ -381,7 +383,7 @@ namespace {
value_t get_payee(call_scope_t& scope) value_t get_payee(call_scope_t& scope)
{ {
entry_t& entry(downcast<entry_t>(*scope.parent)); entry_t& entry(downcast<entry_t>(*scope.parent));
return value_t(entry.payee, true); return string_value(entry.payee);
} }
} }
@ -425,6 +427,7 @@ bool entry_t::valid() const
return true; return true;
} }
#if 0
void entry_context::describe(std::ostream& out) const throw() void entry_context::describe(std::ostream& out) const throw()
{ {
if (! desc.empty()) if (! desc.empty())
@ -432,6 +435,7 @@ void entry_context::describe(std::ostream& out) const throw()
print_entry(out, entry, " "); print_entry(out, entry, " ");
} }
#endif
void auto_entry_t::extend_entry(entry_base_t& entry, bool post) void auto_entry_t::extend_entry(entry_base_t& entry, bool post)
{ {

12
entry.h
View file

@ -124,18 +124,6 @@ struct entry_finalizer_t {
virtual bool operator()(entry_t& entry, bool post) = 0; virtual bool operator()(entry_t& entry, bool post) = 0;
}; };
class entry_context : public error_context {
public:
const entry_base_t& entry;
entry_context(const entry_base_t& _entry,
const string& _desc = "") throw()
: error_context(_desc), entry(_entry) {}
virtual ~entry_context() throw() {}
virtual void describe(std::ostream& out) const throw();
};
class auto_entry_t : public entry_base_t class auto_entry_t : public entry_base_t
{ {
public: public:

196
error.h
View file

@ -1,132 +1,84 @@
/*
* Copyright (c) 2003-2008, 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.
*/
#ifndef _ERROR_H #ifndef _ERROR_H
#define _ERROR_H #define _ERROR_H
#include <exception>
#include <stdexcept>
#include <string>
#include <cstring>
#include <sstream>
#include <list>
namespace ledger { namespace ledger {
class error_context extern std::ostringstream _desc_buffer;
{
public:
string desc;
error_context(const string& _desc) throw() : desc(_desc) {} template <typename T>
virtual ~error_context() throw() {} inline void throw_func(const std::string& message) {
virtual void describe(std::ostream& out) const throw() { _desc_buffer.str("");
if (! desc.empty()) throw T(message);
out << desc << std::endl; }
#define throw_(cls, msg) \
((_desc_buffer << msg), throw_func<cls>(_desc_buffer.str()))
extern std::ostringstream _ctxt_buffer;
#define add_error_context(msg) \
((static_cast<unsigned long>(_ctxt_buffer.tellp()) == 0) ? \
(_ctxt_buffer << msg) : (_ctxt_buffer << std::endl << msg))
inline string error_context() {
string context = _ctxt_buffer.str();
_ctxt_buffer.str("");
return context;
}
inline string file_context(const path& file, std::size_t line) {
std::ostringstream buf;
buf << "\"" << file << "\", line " << line << ": ";
return buf.str();
}
inline string line_context(const string& line, long pos) {
std::ostringstream buf;
buf << " " << line << std::endl << " ";
long idx = pos < 0 ? line.length() - 1 : pos;
for (int i = 0; i < idx; i++)
buf << " ";
buf << "^" << std::endl;
return buf.str();
}
#define DECLARE_EXCEPTION(name, kind) \
class name : public kind { \
public: \
explicit name(const string& why) throw() : kind(why) {} \
virtual ~name() throw() {} \
} }
};
class file_context : public error_context
{
protected:
path file;
unsigned long line;
public:
file_context(const path& _file, unsigned long _line,
const string& desc = "") throw()
: error_context(desc), file(_file), line(_line) {}
virtual ~file_context() throw() {}
virtual void describe(std::ostream& out) const throw() {
if (! desc.empty())
out << desc << " ";
out << "\"" << file << "\", line " << line << ": ";
}
};
class line_context : public error_context
{
public:
string line;
long pos;
line_context(const string& _line, long _pos,
const string& desc = "") throw()
: error_context(desc), line(_line), pos(_pos) {}
virtual ~line_context() throw() {}
virtual void describe(std::ostream& out) const throw() {
if (! desc.empty())
out << desc << std::endl;
out << " " << line << std::endl << " ";
long idx = pos < 0 ? line.length() - 1 : pos;
for (int i = 0; i < idx; i++)
out << " ";
out << "^" << std::endl;
}
};
//////////////////////////////////////////////////////////////////////
class str_exception : public std::logic_error
{
public:
std::list<error_context *> context;
str_exception(const string& why,
error_context * ctxt = NULL) throw()
: std::logic_error(why), context() {
if (ctxt)
context.push_back(ctxt);
}
virtual ~str_exception() throw() {
for (std::list<error_context *>::iterator i = context.begin();
i != context.end();
i++)
checked_delete(*i);
}
virtual void reveal_context(std::ostream& out,
const string& kind) const throw() {
for (std::list<error_context *>::const_reverse_iterator i =
context.rbegin();
i != context.rend();
i++) {
std::list<error_context *>::const_reverse_iterator x = i;
if (++x == context.rend())
out << kind << ": ";
(*i)->describe(out);
}
}
};
#define DECLARE_EXCEPTION(kind, name) \
class name : public kind { \
public: \
name(const string& why, error_context * ctxt = NULL) throw() \
: kind(why, ctxt) {} \
}
class error : public str_exception {
public:
error(const string& why, error_context * ctxt = NULL) throw()
: str_exception(why, ctxt) {}
virtual ~error() throw() {}
};
class fatal : public str_exception {
public:
fatal(const string& why, error_context * ctxt = NULL) throw()
: str_exception(why, ctxt) {}
virtual ~fatal() throw() {}
};
class fatal_assert : public fatal {
public:
fatal_assert(const string& why, error_context * ctxt = NULL) throw()
: fatal(string("assertion failed '") + why + "'", ctxt) {}
virtual ~fatal_assert() throw() {}
};
} // namespace ledger } // namespace ledger

6
expr.h
View file

@ -36,9 +36,9 @@
namespace ledger { namespace ledger {
DECLARE_EXCEPTION(error, parse_error); DECLARE_EXCEPTION(parse_error, std::runtime_error);
DECLARE_EXCEPTION(error, compile_error); DECLARE_EXCEPTION(compile_error, std::runtime_error);
DECLARE_EXCEPTION(error, calc_error); DECLARE_EXCEPTION(calc_error, std::runtime_error);
class scope_t; class scope_t;
class call_scope_t; class call_scope_t;

View file

@ -214,7 +214,7 @@ element_t * format_t::parse_elements(const string& fmt)
p++; p++;
} }
if (*p != ')') if (*p != ')')
throw new format_error("Missing ')'"); throw format_error("Missing ')'");
current->type = element_t::VALUE_EXPR; current->type = element_t::VALUE_EXPR;
@ -235,7 +235,7 @@ element_t * format_t::parse_elements(const string& fmt)
p++; p++;
} }
if (*p != ']') if (*p != ']')
throw new format_error("Missing ']'"); throw format_error("Missing ']'");
current->type = element_t::DATE_STRING; current->type = element_t::DATE_STRING;
current->chars = string(b, p); current->chars = string(b, p);

View file

@ -219,13 +219,7 @@ class format_equity : public item_handler<account_t>
virtual void operator()(account_t& account); virtual void operator()(account_t& account);
}; };
class format_error : public error DECLARE_EXCEPTION(format_error, std::runtime_error);
{
public:
format_error(const string& reason, error_context * ctxt = NULL) throw()
: error(reason, ctxt) {}
virtual ~format_error() throw() {}
};
} // namespace ledger } // namespace ledger

View file

@ -394,7 +394,7 @@ unsigned int gnucash_parser_t::parse(std::istream& in,
//unsigned long line = XML_GetCurrentLineNumber(parser) - offset++; //unsigned long line = XML_GetCurrentLineNumber(parser) - offset++;
const char * msg = XML_ErrorString(XML_GetErrorCode(parser)); const char * msg = XML_ErrorString(XML_GetErrorCode(parser));
XML_ParserFree(parser); XML_ParserFree(parser);
throw new parse_error(msg); throw parse_error(msg);
} }
if (! have_error.empty()) { if (! have_error.empty()) {

View file

@ -118,14 +118,6 @@ public:
const path * original_file = NULL); const path * original_file = NULL);
}; };
class parse_error : public error
{
public:
parse_error(const string& reason, error_context * ctxt = NULL) throw()
: error(reason, ctxt) {}
virtual ~parse_error() throw() {}
};
bool valid() const; bool valid() const;
}; };

25
main.cc
View file

@ -297,7 +297,7 @@ static int read_and_report(ledger::report_t& report, int argc, char * argv[],
command_args.push_back(value_t(out)); command_args.push_back(value_t(out));
for (strings_list::iterator i = arg; i != args.end(); i++) for (strings_list::iterator i = arg; i != args.end(); i++)
command_args.push_back(value_t(*i, true)); command_args.push_back(string_value(*i));
INFO_START(command, "Did user command '" << verb << "'"); INFO_START(command, "Did user command '" << verb << "'");
@ -422,29 +422,10 @@ int main(int argc, char * argv[], char * envp[])
session.release(); session.release();
} }
} }
catch (ledger::error * err) {
std::cout.flush();
// Push a null here since there's no file context
if (err->context.empty() ||
! dynamic_cast<ledger::xact_context *>(err->context.front()))
err->context.push_front(new ledger::error_context(""));
err->reveal_context(std::cerr, "Error");
std::cerr << err->what() << std::endl;
ledger::checked_delete(err);
}
catch (ledger::fatal * err) {
std::cout.flush();
// Push a null here since there's no file context
if (err->context.empty() ||
! dynamic_cast<ledger::xact_context *>(err->context.front()))
err->context.push_front(new ledger::error_context(""));
err->reveal_context(std::cerr, "Fatal");
std::cerr << err->what() << std::endl;
ledger::checked_delete(err);
}
catch (const std::exception& err) { catch (const std::exception& err) {
std::cout.flush(); std::cout.flush();
std::cerr << "Exception: " << err.what() << std::endl; std::cerr << "Error: " << ledger::error_context() << err.what()
<< std::endl;
} }
catch (int _status) { catch (int _status) {
status = _status; status = _status;

57
op.cc
View file

@ -43,7 +43,7 @@ void expr_t::op_t::compute(value_t& result,
try { try {
switch (kind) { switch (kind) {
case INDEX: case INDEX:
throw new compute_error("Cannot directly compute an argument index"); throw compute_error("Cannot directly compute an argument index");
case VALUE: case VALUE:
result = as_value(); result = as_value();
@ -280,8 +280,8 @@ void expr_t::op_t::compute(value_t& result,
moment.cast(value_t::INTEGER); moment.cast(value_t::INTEGER);
result -= moment; result -= moment;
} else { } else {
throw new compute_error("Invalid date passed to datecmp(value,date)", add_error_context(expr_context(expr));
new valexpr_context(expr)); throw compute_error("Invalid date passed to datecmp(value,date)");
} }
break; break;
} }
@ -293,9 +293,10 @@ void expr_t::op_t::compute(value_t& result,
ptr_op_t expr = find_leaf(context, 0, arg_index); ptr_op_t expr = find_leaf(context, 0, arg_index);
expr->compute(result, details, context); expr->compute(result, details, context);
if (! result.is_type(value_t::DATETIME)) if (! result.is_type(value_t::DATETIME)) {
throw new compute_error("Invalid date passed to year|month|day(date)", add_error_context(expr_context(expr));
new valexpr_context(expr)); throw compute_error("Invalid date passed to year|month|day(date)");
}
const datetime_t& moment(result.as_datetime()); const datetime_t& moment(result.as_datetime());
switch (kind) { switch (kind) {
@ -357,9 +358,10 @@ void expr_t::op_t::compute(value_t& result,
long arg_index = 0; long arg_index = 0;
ptr_op_t expr = find_leaf(context, 0, arg_index); ptr_op_t expr = find_leaf(context, 0, arg_index);
expr->compute(result, details, context); expr->compute(result, details, context);
if (! result.is_type(value_t::AMOUNT)) if (! result.is_type(value_t::AMOUNT)) {
throw new compute_error("Argument to commodity() must be a commoditized amount", add_error_context(expr_context(expr));
new valexpr_context(expr)); throw compute_error("Argument to commodity() must be a commoditized amount");
}
amount_t temp("1"); amount_t temp("1");
temp.set_commodity(result.as_amount().commodity()); temp.set_commodity(result.as_amount().commodity());
result = temp; result = temp;
@ -375,10 +377,10 @@ void expr_t::op_t::compute(value_t& result,
arg_index = 0; arg_index = 0;
expr = find_leaf(context, 1, arg_index); expr = find_leaf(context, 1, arg_index);
expr->compute(result, details, context); expr->compute(result, details, context);
if (! result.is_type(value_t::AMOUNT)) if (! result.is_type(value_t::AMOUNT)) {
throw new compute_error add_error_context(expr_context(expr));
("Second argument to set_commodity() must be a commoditized amount", throw compute_error("Second argument to set_commodity() must be a commoditized amount");
new valexpr_context(expr)); }
amount_t one("1"); amount_t one("1");
one.set_commodity(result.as_amount().commodity()); one.set_commodity(result.as_amount().commodity());
result = one; result = one;
@ -482,13 +484,14 @@ void expr_t::op_t::compute(value_t& result,
} }
case O_COMMA: case O_COMMA:
if (! left()) if (! left()) {
throw new compute_error("Comma operator missing left operand", add_error_context(expr_context(*this));
new valexpr_context(const_cast<op_t *>(this))); throw compute_error("Comma operator missing left operand");
if (! right()) }
throw new compute_error("Comma operator missing right operand", if (! right()) {
new valexpr_context(const_cast<op_t *>(this))); add_error_context(expr_context(*this));
left()->compute(result, details, context); throw compute_error("Comma operator missing right operand");
}
right()->compute(result, details, context); right()->compute(result, details, context);
break; break;
@ -516,10 +519,10 @@ void expr_t::op_t::compute(value_t& result,
expr = find_leaf(context, 1, arg_index); expr = find_leaf(context, 1, arg_index);
value_t moment; value_t moment;
expr->compute(moment, details, context); expr->compute(moment, details, context);
if (! moment.is_type(value_t::DATETIME)) if (! moment.is_type(value_t::DATETIME)) {
throw new compute_error("Invalid date passed to P(value,date)", add_error_context(expr_context(expr));
new valexpr_context(expr)); throw compute_error("Invalid date passed to P(value,date)");
}
result = result.value(moment.as_datetime()); result = result.value(moment.as_datetime());
break; break;
} }
@ -624,10 +627,8 @@ void expr_t::op_t::compute(value_t& result,
break; break;
} }
} }
catch (error * err) { catch (const std::exception& err) {
if (err->context.empty() || add_error_context(expr_context(*this));
! dynamic_cast<valexpr_context *>(err->context.back()))
err->context.push_back(new valexpr_context(const_cast<op_t *>(this)));
throw err; throw err;
} }
} }

View file

@ -79,25 +79,22 @@ namespace {
void process_option(const function_t& opt, scope_t& scope, void process_option(const function_t& opt, scope_t& scope,
const char * arg) const char * arg)
{ {
#if 0
try { try {
#endif
call_scope_t args(scope); call_scope_t args(scope);
if (arg) if (arg)
args.push_back(value_t(arg, true)); args.push_back(string_value(arg));
opt(args); opt(args);
#if 0
} }
catch (error * err) { catch (const std::exception& err) {
err->context.push_back #if 0
(new error_context add_error_context("While parsing option '--" << opt->long_opt
(string("While parsing option '--") + opt->long_opt + << "'" << (opt->short_opt != '\0' ?
"'" + (opt->short_opt != '\0' ? (string(" (-") + opt->short_opt + "):") :
(string(" (-") + opt->short_opt + "):") : ":"))); ": "));
#endif
throw err; throw err;
} }
#endif
} }
} }
@ -130,20 +127,14 @@ void process_environment(const char ** envp, const string& tag,
*r = '\0'; *r = '\0';
if (*q == '=') { if (*q == '=') {
#if 0
try { try {
#endif
process_option(string(buf), scope, q + 1); process_option(string(buf), scope, q + 1);
#if 0
} }
catch (error * err) { catch (const std::exception& err) {
err->context.push_back add_error_context("While parsing environment variable option '"
(new error_context << *p << "':");
(string("While parsing environment variable option '") +
*p + "':"));
throw err; throw err;
} }
#endif
} }
} }
} }
@ -429,8 +420,8 @@ OPT_BEGIN(init_file, "i:") {
if (access(path.c_str(), R_OK) != -1) if (access(path.c_str(), R_OK) != -1)
config->init_file = path; config->init_file = path;
else else
throw new error(std::string("The init file '") + path + throw_(std::invalid_argument,
"' does not exist or is not readable"); "The init file '" << path << "' does not exist or is not readable");
} OPT_END(init_file); } OPT_END(init_file);
OPT_BEGIN(file, "f:") { OPT_BEGIN(file, "f:") {
@ -441,8 +432,8 @@ OPT_BEGIN(file, "f:") {
if (access(path.c_str(), R_OK) != -1) if (access(path.c_str(), R_OK) != -1)
config->data_file = path; config->data_file = path;
else else
throw new error(std::string("The ledger file '") + path + throw_(std::invalid_argument,
"' does not exist or is not readable"); "The ledger file '" << path << "' does not exist or is not readable");
} }
} OPT_END(file); } OPT_END(file);
@ -490,8 +481,8 @@ OPT_BEGIN(begin, "b:") {
char buf[128]; char buf[128];
interval_t interval(optarg); interval_t interval(optarg);
if (! interval.begin) if (! interval.begin)
throw new error(std::string("Could not determine beginning of period '") + throw_(std::invalid_argument,
optarg + "'"); "Could not determine beginning of period '" << optarg << "'");
if (! report->predicate.empty()) if (! report->predicate.empty())
report->predicate += "&"; report->predicate += "&";
@ -504,8 +495,8 @@ OPT_BEGIN(end, "e:") {
char buf[128]; char buf[128];
interval_t interval(optarg); interval_t interval(optarg);
if (! interval.begin) if (! interval.begin)
throw new error(std::string("Could not determine end of period '") + throw_(std::invalid_argument,
optarg + "'"); "Could not determine end of period '" << optarg << "'");
if (! report->predicate.empty()) if (! report->predicate.empty())
report->predicate += "&"; report->predicate += "&";

View file

@ -45,7 +45,7 @@ void process_environment(const char ** envp, const string& tag,
void process_arguments(int argc, char ** argv, const bool anywhere, void process_arguments(int argc, char ** argv, const bool anywhere,
scope_t& scope, std::list<string>& args); scope_t& scope, std::list<string>& args);
DECLARE_EXCEPTION(error, option_error); DECLARE_EXCEPTION(option_error, std::runtime_error);
} // namespace ledger } // namespace ledger

View file

@ -419,9 +419,7 @@ expr_t::parser_t::parse_value_expr(std::istream& in,
expr_t::ptr_op_t expr_t::ptr_op_t
expr_t::parser_t::parse(std::istream& in, const flags_t flags) expr_t::parser_t::parse(std::istream& in, const flags_t flags)
{ {
#if 0
try { try {
#endif
ptr_op_t top_node = parse_value_expr(in, flags); ptr_op_t top_node = parse_value_expr(in, flags);
if (use_lookahead) { if (use_lookahead) {
@ -431,15 +429,14 @@ expr_t::parser_t::parse(std::istream& in, const flags_t flags)
lookahead.clear(); lookahead.clear();
return top_node; return top_node;
#if 0
} }
catch (error * err) { catch (const std::exception& err) {
err->context.push_back add_error_context("While parsing value expression:\n");
(new line_context(str, (long)in.tellg() - 1, #if 0
"While parsing value expression:")); add_error_context(line_context(str, (long)in.tellg() - 1));
#endif
throw err; throw err;
} }
#endif
} }
} // namespace ledger } // namespace ledger

5
qif.cc
View file

@ -75,7 +75,7 @@ unsigned int qif_parser_t::parse(std::istream& in,
case '\t': case '\t':
if (peek_next_nonws(in) != '\n') { if (peek_next_nonws(in) != '\n') {
get_line(in); get_line(in);
throw new parse_error("Line begins with whitespace"); throw parse_error("Line begins with whitespace");
} }
// fall through... // fall through...
@ -92,8 +92,7 @@ unsigned int qif_parser_t::parse(std::istream& in,
std::strcmp(line, "Type:Cat") == 0 || std::strcmp(line, "Type:Cat") == 0 ||
std::strcmp(line, "Type:Class") == 0 || std::strcmp(line, "Type:Class") == 0 ||
std::strcmp(line, "Type:Memorized") == 0) std::strcmp(line, "Type:Memorized") == 0)
throw new parse_error(string("QIF files of type ") + line + throw_(parse_error, "QIF files of type " << line << " are not supported.");
" are not supported.");
break; break;
case 'D': case 'D':

View file

@ -68,9 +68,9 @@ void quotes_by_script::operator()(commodity_base_t& commodity,
<< " " << commodity.symbol << " " << price << endl; << " " << commodity.symbol << " " << price << endl;
} }
} else { } else {
throw new error(string("Failed to download price for '") + throw_(std::runtime_error,
commodity.symbol + "' (command: \"getquote " + "Failed to download price for '" << commodity.symbol
commodity.symbol + "\")"); << "' (command: \"getquote " << commodity.symbol << "\")");
} }
} }
#endif #endif

View file

@ -59,7 +59,7 @@ void reconcile_xacts::flush()
} }
if (cleared_balance.type() >= value_t::BALANCE) if (cleared_balance.type() >= value_t::BALANCE)
throw new error("Cannot reconcile accounts with multiple commodities"); throw std::runtime_error("Cannot reconcile accounts with multiple commodities");
cleared_balance.cast(value_t::AMOUNT); cleared_balance.cast(value_t::AMOUNT);
balance.cast(value_t::AMOUNT); balance.cast(value_t::AMOUNT);
@ -69,8 +69,9 @@ void reconcile_xacts::flush()
balance -= cleared_balance; balance -= cleared_balance;
if (balance.type() >= value_t::BALANCE) if (balance.type() >= value_t::BALANCE)
throw new error(string("Reconcile balance is not of the same commodity ('") + throw_(std::runtime_error,
b_comm.symbol() + string("' != '") + cb_comm.symbol() + "')"); "Reconcile balance is not of the same commodity ('"
<< b_comm.symbol() << "' != '" << cb_comm.symbol() << "')");
// If the amount to reconcile is the same as the pending balance, // If the amount to reconcile is the same as the pending balance,
// then assume an exact match and return the results right away. // then assume an exact match and return the results right away.
@ -80,7 +81,7 @@ void reconcile_xacts::flush()
search_for_balance(to_reconcile, &first, first)) { search_for_balance(to_reconcile, &first, first)) {
push_to_handler(first); push_to_handler(first);
} else { } else {
throw new error("Could not reconcile account!"); throw std::runtime_error("Could not reconcile account!");
} }
} }

View file

@ -319,7 +319,7 @@ value_t report_t::ftime(call_scope_t& args)
else else
date_format = moment_t::output_format; date_format = moment_t::output_format;
return value_t(date.as_string(date_format), true); return string_value(date.as_string(date_format));
#else #else
return NULL_VALUE; return NULL_VALUE;
#endif #endif

View file

@ -266,7 +266,7 @@ value_t session_t::resolve(const string& name, expr_t::scope_t& locals)
#if 0 #if 0
if (name == "date_format") { if (name == "date_format") {
// jww (2007-04-18): What to do here? // jww (2007-04-18): What to do here?
return value_t(moment_t::output_format, true); return string_value(moment_t::output_format);
} }
#endif #endif
break; break;
@ -282,7 +282,7 @@ value_t session_t::resolve(const string& name, expr_t::scope_t& locals)
case 'r': case 'r':
if (name == "register_format") if (name == "register_format")
return value_t(register_format, true); return string_value(register_format);
break; break;
} }
return expr_t::scope_t::resolve(name, locals); return expr_t::scope_t::resolve(name, locals);

View file

@ -124,7 +124,7 @@ xact_t * parse_xact(char * line, account_t * account,
} }
if (account_beg == account_end) if (account_beg == account_end)
throw new parse_error("No account was specified"); throw parse_error("No account was specified");
char * b = &line[account_beg]; char * b = &line[account_beg];
char * e = &line[account_end]; char * e = &line[account_end];
@ -189,8 +189,8 @@ xact_t * parse_xact(char * line, account_t * account,
xact->amount_expr->set_text(string(line, beg, end - beg)); xact->amount_expr->set_text(string(line, beg, end - beg));
} }
} }
catch (error * err) { catch (const std::exception& err) {
err_desc = "While parsing transaction amount:"; add_error_context("While parsing transaction amount:\n");
throw err; throw err;
} }
} }
@ -201,7 +201,7 @@ xact_t * parse_xact(char * line, account_t * account,
p = peek_next_nonws(in); p = peek_next_nonws(in);
if (p == '@') { if (p == '@') {
if (! saw_amount) if (! saw_amount)
throw new parse_error throw parse_error
("Transaction cannot have a cost expression with an amount"); ("Transaction cannot have a cost expression with an amount");
DEBUG("ledger.textual.parse", "line " << linenum << ": " << DEBUG("ledger.textual.parse", "line " << linenum << ": " <<
@ -236,13 +236,13 @@ xact_t * parse_xact(char * line, account_t * account,
string(line, beg, end - beg)); string(line, beg, end - beg));
} }
} }
catch (error * err) { catch (const std::exception& err) {
err_desc = "While parsing transaction cost:"; add_error_context("While parsing transaction cost:\n");
throw err; throw err;
} }
if (xact->cost->sign() < 0) if (xact->cost->sign() < 0)
throw new parse_error("A transaction's cost may not be negative"); throw parse_error("A transaction's cost may not be negative");
amount_t per_unit_cost(*xact->cost); amount_t per_unit_cost(*xact->cost);
if (per_unit) if (per_unit)
@ -303,7 +303,7 @@ xact_t * parse_xact(char * line, account_t * account,
if (parse_amount_expr(in, amt, xact.get(), if (parse_amount_expr(in, amt, xact.get(),
EXPR_PARSE_NO_MIGRATE)) EXPR_PARSE_NO_MIGRATE))
throw new parse_error throw parse_error
("An assigned balance must evaluate to a constant value"); ("An assigned balance must evaluate to a constant value");
DEBUG("ledger.textual.parse", "line " << linenum << ": " << DEBUG("ledger.textual.parse", "line " << linenum << ": " <<
@ -352,8 +352,8 @@ xact_t * parse_xact(char * line, account_t * account,
xdata.value = amt; xdata.value = amt;
} }
} }
catch (error * err) { catch (const std::exception& err) {
err_desc = "While parsing assigned balance:"; add_error_context("While parsing assigned balance:\n");
throw err; throw err;
} }
} }
@ -396,11 +396,9 @@ xact_t * parse_xact(char * line, account_t * account,
return xact.release(); return xact.release();
} }
catch (error * err) { catch (const std::exception& err) {
err->context.push_back add_error_context("While parsing transaction:\n");
(new line_context(line, static_cast<unsigned long>(in.tellg()) - 1, add_error_context(line_context(line, static_cast<unsigned long>(in.tellg()) - 1));
! err_desc.empty() ?
err_desc : "While parsing transaction:"));
throw err; throw err;
} }
} }
@ -549,7 +547,7 @@ static inline void parse_symbol(char *& p, string& symbol)
if (*p == '"') { if (*p == '"') {
char * q = std::strchr(p + 1, '"'); char * q = std::strchr(p + 1, '"');
if (! q) if (! q)
throw new parse_error("Quoted commodity symbol lacks closing quote"); throw parse_error("Quoted commodity symbol lacks closing quote");
symbol = string(p + 1, 0, q - p - 1); symbol = string(p + 1, 0, q - p - 1);
p = q + 2; p = q + 2;
} else { } else {
@ -561,7 +559,7 @@ static inline void parse_symbol(char *& p, string& symbol)
p += symbol.length(); p += symbol.length();
} }
if (symbol.empty()) if (symbol.empty())
throw new parse_error("Failed to parse commodity"); throw parse_error("Failed to parse commodity");
} }
bool textual_parser_t::test(std::istream& in) const bool textual_parser_t::test(std::istream& in) const
@ -571,9 +569,9 @@ bool textual_parser_t::test(std::istream& in) const
in.read(buf, 5); in.read(buf, 5);
if (std::strncmp(buf, "<?xml", 5) == 0) { if (std::strncmp(buf, "<?xml", 5) == 0) {
#if defined(HAVE_EXPAT) || defined(HAVE_XMLPARSE) #if defined(HAVE_EXPAT) || defined(HAVE_XMLPARSE)
throw new parse_error("Ledger file contains XML data, but format was not recognized"); throw parse_error("Ledger file contains XML data, but format was not recognized");
#else #else
throw new parse_error("Ledger file contains XML data, but no XML support present"); throw parse_error("Ledger file contains XML data, but no XML support present");
#endif #endif
} }
@ -596,10 +594,10 @@ static void clock_out_from_timelog(std::list<time_entry_t>& time_entries,
time_entries.clear(); time_entries.clear();
} }
else if (time_entries.empty()) { else if (time_entries.empty()) {
throw new parse_error("Timelog check-out event without a check-in"); throw parse_error("Timelog check-out event without a check-in");
} }
else if (! account) { else if (! account) {
throw new parse_error throw parse_error
("When multiple check-ins are active, checking out requires an account"); ("When multiple check-ins are active, checking out requires an account");
} }
else { else {
@ -616,7 +614,7 @@ static void clock_out_from_timelog(std::list<time_entry_t>& time_entries,
} }
if (! found) if (! found)
throw new parse_error throw parse_error
("Timelog check-out event does not match any current check-ins"); ("Timelog check-out event does not match any current check-ins");
} }
@ -631,7 +629,7 @@ static void clock_out_from_timelog(std::list<time_entry_t>& time_entries,
curr->payee = event.desc; curr->payee = event.desc;
if (curr->_date < event.checkin) if (curr->_date < event.checkin)
throw new parse_error throw parse_error
("Timelog check-out date less than corresponding check-in"); ("Timelog check-out date less than corresponding check-in");
char buf[32]; char buf[32];
@ -646,7 +644,7 @@ static void clock_out_from_timelog(std::list<time_entry_t>& time_entries,
curr->add_xact(xact); curr->add_xact(xact);
if (! journal.add_entry(curr.get())) if (! journal.add_entry(curr.get()))
throw new parse_error("Failed to record 'out' timelog entry"); throw parse_error("Failed to record 'out' timelog entry");
else else
curr.release(); curr.release();
} }
@ -704,7 +702,7 @@ unsigned int textual_parser_t::parse(std::istream& in,
case '\t': { case '\t': {
char * p = skip_ws(line); char * p = skip_ws(line);
if (*p) if (*p)
throw new parse_error("Line begins with whitespace"); throw parse_error("Line begins with whitespace");
break; break;
} }
@ -724,7 +722,7 @@ unsigned int textual_parser_t::parse(std::istream& in,
i != time_entries.end(); i != time_entries.end();
i++) i++)
if (event.account == (*i).account) if (event.account == (*i).account)
throw new parse_error throw parse_error
("Cannot double check-in to the same account"); ("Cannot double check-in to the same account");
time_entries.push_back(event); time_entries.push_back(event);
@ -734,7 +732,7 @@ unsigned int textual_parser_t::parse(std::istream& in,
case 'o': case 'o':
case 'O': case 'O':
if (time_entries.empty()) { if (time_entries.empty()) {
throw new parse_error("Timelog check-out event without a check-in"); throw parse_error("Timelog check-out event without a check-in");
} else { } else {
string date(line, 2, 19); string date(line, 2, 19);
@ -858,7 +856,7 @@ unsigned int textual_parser_t::parse(std::istream& in,
case '~': { // period entry case '~': { // period entry
period_entry_t * pe = new period_entry_t(skip_ws(line + 1)); period_entry_t * pe = new period_entry_t(skip_ws(line + 1));
if (! pe->period) if (! pe->period)
throw new parse_error(string("Parsing time period '") + line + "'"); throw_(parse_error, "Parsing time period '" << line << "'");
if (parse_xacts(in, account_stack.front(), *pe, if (parse_xacts(in, account_stack.front(), *pe,
"period", end_pos)) { "period", end_pos)) {
@ -960,10 +958,10 @@ unsigned int textual_parser_t::parse(std::istream& in,
count++; count++;
} else { } else {
checked_delete(entry); checked_delete(entry);
throw new parse_error("Entry does not balance"); throw parse_error("Entry does not balance");
} }
} else { } else {
throw new parse_error("Failed to parse entry"); throw parse_error("Failed to parse entry");
} }
end_pos = pos; end_pos = pos;
TRACE_STOP(entries, 1); TRACE_STOP(entries, 1);
@ -971,21 +969,21 @@ unsigned int textual_parser_t::parse(std::istream& in,
} }
} }
} }
catch (error * err) { catch (const std::exception& err) {
for (std::list<std::pair<path, int> >::reverse_iterator i = for (std::list<std::pair<path, int> >::reverse_iterator i =
include_stack.rbegin(); include_stack.rbegin();
i != include_stack.rend(); i != include_stack.rend();
i++) i++) {
err->context.push_back(new include_context((*i).first, (*i).second, add_error_context("In file included from ");
"In file included from")); #if 0
err->context.push_front(new file_context(pathname, linenum - 1)); add_error_context(include_context((*i).first, (*i).second));
#endif
}
add_error_context(file_context(pathname, linenum - 1));
std::cout.flush(); std::cout.flush();
if (errors > 0 && err->context.size() > 1) std::cerr << "Error: " << error_context() << err.what()
std::cerr << std::endl; << std::endl;
err->reveal_context(std::cerr, "Error");
std::cerr << err->what() << std::endl;
checked_delete(err);
errors++; errors++;
} }
beg_pos = end_pos; beg_pos = end_pos;
@ -1061,8 +1059,8 @@ void write_textual_journal(journal_t& journal,
} }
if (found.empty()) if (found.empty())
throw new error(string("Journal does not refer to file '") + throw_(std::runtime_error,
string(pathname.string()) + "'"); "Journal does not refer to file '" << pathname << "'");
entries_list::iterator el = journal.entries.begin(); entries_list::iterator el = journal.entries.begin();
auto_entries_list::iterator al = journal.auto_entries.begin(); auto_entries_list::iterator al = journal.auto_entries.begin();

View file

@ -28,6 +28,7 @@ void write_textual_journal(journal_t& journal,
const string& write_hdr_format, const string& write_hdr_format,
std::ostream& out); std::ostream& out);
#if 0
class include_context : public file_context class include_context : public file_context
{ {
public: public:
@ -43,6 +44,7 @@ class include_context : public file_context
<< std::endl; << std::endl;
} }
}; };
#endif
} // namespace ledger } // namespace ledger

View file

@ -192,7 +192,7 @@ namespace {
struct std::tm when; struct std::tm when;
if (! parse_date_mask(word.c_str(), &when)) if (! parse_date_mask(word.c_str(), &when))
throw new datetime_error(string("Could not parse date mask: ") + word); throw_(datetime_error, "Could not parse date mask: " << word);
when.tm_hour = 0; when.tm_hour = 0;
when.tm_min = 0; when.tm_min = 0;

View file

@ -61,7 +61,7 @@ extern int current_year;
extern string input_time_format; extern string input_time_format;
extern string output_time_format; extern string output_time_format;
DECLARE_EXCEPTION(error, datetime_error); DECLARE_EXCEPTION(datetime_error, std::runtime_error);
struct interval_t struct interval_t
{ {

View file

@ -40,7 +40,7 @@
namespace ledger { namespace ledger {
DECLARE_EXCEPTION(fatal, assertion_failed); DECLARE_EXCEPTION(assertion_failed, std::logic_error);
void debug_assert(const string& reason, void debug_assert(const string& reason,
const string& func, const string& func,
@ -649,8 +649,8 @@ void finish_timer(const char * name)
namespace ledger { namespace ledger {
std::ostringstream _exc_buffer; std::ostringstream _desc_buffer;
/*ptr_list<context> context_stack;*/ std::ostringstream _ctxt_buffer;
} // namespace ledger } // namespace ledger
@ -666,9 +666,7 @@ path expand_path(const path& pathname)
if (pathname.empty()) if (pathname.empty())
return pathname; return pathname;
#if 1 #if 0
return pathname;
#else
// jww (2007-04-30): I need to port this code to use // jww (2007-04-30): I need to port this code to use
// boost::filesystem::path // boost::filesystem::path
const char * pfx = NULL; const char * pfx = NULL;
@ -711,6 +709,8 @@ path expand_path(const path& pathname)
result += pathname.substr(pos + 1); result += pathname.substr(pos + 1);
return result; return result;
#else
return pathname;
#endif #endif
} }

48
utils.h
View file

@ -463,53 +463,13 @@ void finish_timer(const char * name);
/********************************************************************** /**********************************************************************
* *
* Exception handling * - Exception handling helpers
* - Date/time support classes
* - General support for objects with "flags"
* - Support for scoped execution and variable restoration
*/ */
#include "error.h" #include "error.h"
namespace ledger {
extern std::ostringstream _exc_buffer;
template <typename T>
inline void throw_func(const std::string& message) {
_exc_buffer.str("");
throw T(message);
}
#define throw_(cls, msg) \
((_exc_buffer << msg), throw_func<cls>(_exc_buffer.str()))
#if 0
inline void throw_unexpected_error(char c, char wanted) {
if (c == -1) {
if (wanted)
throw new error(string("Missing '") + wanted + "'");
else
throw new error("Unexpected end of input");
} else {
if (wanted)
throw new error(string("Invalid char '") + c +
"' (wanted '" + wanted + "')");
else
throw new error(string("Invalid char '") + c + "'");
}
}
#else
inline void throw_unexpected_error(char, char) {
}
#endif
} // namespace ledger
/**********************************************************************
*
* Date/time support classes
* General support for objects with "flags"
* Support for scoped execution and variable restoration
*/
#include "times.h" #include "times.h"
#include "flags.h" #include "flags.h"
#include "pushvar.h" #include "pushvar.h"

View file

@ -1378,7 +1378,7 @@ value_t value_t::annotated_tag() const
optional<string> temp = as_amount().annotation_details().tag; optional<string> temp = as_amount().annotation_details().tag;
if (! temp) if (! temp)
return false; return false;
return value_t(*temp, true); return string_value(*temp);
} }
case STRING: case STRING:
@ -1679,15 +1679,4 @@ bool value_t::valid() const
return true; return true;
} }
void value_context::describe(std::ostream& out) const throw()
{
if (! desc.empty())
out << desc << std::endl;
out << std::right;
out.width(20);
bal.print(out);
out << std::endl;
}
} // namespace ledger } // namespace ledger

22
value.h
View file

@ -48,6 +48,8 @@
namespace ledger { namespace ledger {
DECLARE_EXCEPTION(value_error, std::runtime_error);
/** /**
* @class value_t * @class value_t
* *
@ -880,18 +882,14 @@ inline std::ostream& operator<<(std::ostream& out, const value_t& val) {
return out; return out;
} }
class value_context : public error_context inline string value_context(const value_t& val) {
{ std::ostringstream buf;
value_t bal; buf << std::right;
public: buf.width(20);
value_context(const value_t& _bal, const string& desc = "") throw() val.print(buf);
: error_context(desc), bal(_bal) {} buf << std::endl;
virtual ~value_context() throw() {} return buf.str();
}
virtual void describe(std::ostream& out) const throw();
};
DECLARE_EXCEPTION(error, value_error);
} // namespace ledger } // namespace ledger

View file

@ -217,9 +217,11 @@ void calc_xacts::operator()(xact_t& xact)
last_xact = &xact; last_xact = &xact;
} }
catch (error * err) { catch (const std::exception& err) {
err->context.push_front add_error_context("Calculating transaction at");
(new xact_context(xact, "Calculating transaction at")); #if 0
add_error_context(xact_context(xact));
#endif
throw err; throw err;
} }
} }

8
walk.h
View file

@ -693,14 +693,6 @@ public:
virtual void operator()(xact_t& xact); virtual void operator()(xact_t& xact);
}; };
class interval_expr_error : public error {
public:
interval_expr_error(const string& reason,
error_context * ctxt = NULL) throw()
: error(reason, ctxt) {}
virtual ~interval_expr_error() throw() {}
};
class interval_xacts : public subtotal_xacts class interval_xacts : public subtotal_xacts
{ {
interval_t interval; interval_t interval;

View file

@ -72,7 +72,7 @@ namespace {
value_t get_payee(call_scope_t& scope) value_t get_payee(call_scope_t& scope)
{ {
xact_t& xact(downcast<xact_t>(*scope.parent)); xact_t& xact(downcast<xact_t>(*scope.parent));
return value_t(xact.entry->payee, true); return string_value(xact.entry->payee);
} }
value_t get_account(call_scope_t& scope) value_t get_account(call_scope_t& scope)
@ -87,7 +87,7 @@ namespace {
else else
name = string("(") + name + ")"; name = string("(") + name + ")";
} }
return value_t(name, true); return string_value(name);
} }
value_t get_account_base(call_scope_t& scope) value_t get_account_base(call_scope_t& scope)
@ -163,6 +163,7 @@ bool xact_t::valid() const
return true; return true;
} }
#if 0
xact_context::xact_context(const xact_t& _xact, const string& desc) throw() xact_context::xact_context(const xact_t& _xact, const string& desc) throw()
: file_context("", 0, desc), xact(_xact) : file_context("", 0, desc), xact(_xact)
{ {
@ -177,5 +178,6 @@ xact_context::xact_context(const xact_t& _xact, const string& desc) throw()
} }
line = xact.beg_line; line = xact.beg_line;
} }
#endif
} // namespace ledger } // namespace ledger

9
xact.h
View file

@ -131,15 +131,6 @@ class xact_t : public supports_flags<>, public scope_t
bool valid() const; bool valid() const;
}; };
class xact_context : public file_context {
public:
const xact_t& xact;
xact_context(const xact_t& _xact,
const string& desc = "") throw();
virtual ~xact_context() throw() {}
};
} // namespace ledger } // namespace ledger
#endif // _XACT_H #endif // _XACT_H

4
xml.cc
View file

@ -209,7 +209,7 @@ unsigned int xml_parser_t::parse(std::istream& in,
catch (const std::exception& err) { catch (const std::exception& err) {
//unsigned long line = XML_GetCurrentLineNumber(parser) - offset++; //unsigned long line = XML_GetCurrentLineNumber(parser) - offset++;
XML_ParserFree(parser); XML_ParserFree(parser);
throw new parse_error(err.what()); throw parse_error(err.what());
} }
if (! have_error.empty()) { if (! have_error.empty()) {
@ -223,7 +223,7 @@ unsigned int xml_parser_t::parse(std::istream& in,
//unsigned long line = XML_GetCurrentLineNumber(parser) - offset++; //unsigned long line = XML_GetCurrentLineNumber(parser) - offset++;
const char * err = XML_ErrorString(XML_GetErrorCode(parser)); const char * err = XML_ErrorString(XML_GetErrorCode(parser));
XML_ParserFree(parser); XML_ParserFree(parser);
throw new parse_error(err); throw parse_error(err);
} }
} }