diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/account.h | 4 | ||||
-rw-r--r-- | src/amount.cc | 6 | ||||
-rw-r--r-- | src/amount.h | 2 | ||||
-rw-r--r-- | src/commodity.cc | 64 | ||||
-rw-r--r-- | src/compare.cc | 8 | ||||
-rw-r--r-- | src/expr.cc | 42 | ||||
-rw-r--r-- | src/expr.h | 4 | ||||
-rw-r--r-- | src/flags.h | 4 | ||||
-rw-r--r-- | src/global.h | 4 | ||||
-rw-r--r-- | src/op.cc | 138 | ||||
-rw-r--r-- | src/op.h | 11 | ||||
-rw-r--r-- | src/output.cc | 20 | ||||
-rw-r--r-- | src/parser.cc | 135 | ||||
-rw-r--r-- | src/parser.h | 6 | ||||
-rw-r--r-- | src/post.h | 10 | ||||
-rw-r--r-- | src/py_amount.cc | 1 | ||||
-rw-r--r-- | src/py_item.cc | 2 | ||||
-rw-r--r-- | src/py_xact.cc | 2 | ||||
-rw-r--r-- | src/query.cc | 42 | ||||
-rw-r--r-- | src/query.h | 4 | ||||
-rw-r--r-- | src/report.cc | 29 | ||||
-rw-r--r-- | src/report.h | 8 | ||||
-rw-r--r-- | src/scope.h | 33 | ||||
-rw-r--r-- | src/session.h | 4 | ||||
-rw-r--r-- | src/stream.cc | 4 | ||||
-rw-r--r-- | src/system.hh.in | 6 | ||||
-rw-r--r-- | src/textual.cc | 4 | ||||
-rw-r--r-- | src/token.cc | 31 | ||||
-rw-r--r-- | src/token.h | 15 | ||||
-rw-r--r-- | src/xact.h | 30 |
30 files changed, 453 insertions, 220 deletions
diff --git a/src/account.h b/src/account.h index 26ebe261..7a632b35 100644 --- a/src/account.h +++ b/src/account.h @@ -89,6 +89,10 @@ public: } ~account_t(); + virtual string description() { + return string(_("account ")) + fullname(); + } + operator string() const { return fullname(); } diff --git a/src/amount.cc b/src/amount.cc index 1fbc96c8..d5b7f03d 100644 --- a/src/amount.cc +++ b/src/amount.cc @@ -998,7 +998,8 @@ bool amount_t::parse(std::istream& in, const parse_flags_t& flags) if (! symbol.empty()) comm_flags |= COMMODITY_STYLE_SUFFIXED; - if (! in.eof() && ((n = static_cast<char>(in.peek())) != '\n')) + if (! flags.has_flags(PARSE_NO_ANNOT) && + ! in.eof() && ((n = static_cast<char>(in.peek())) != '\n')) details.parse(in); } } else { @@ -1010,7 +1011,8 @@ bool amount_t::parse(std::istream& in, const parse_flags_t& flags) parse_quantity(in, quant); - if (! quant.empty() && ! in.eof() && + if (! flags.has_flags(PARSE_NO_ANNOT) && + ! quant.empty() && ! in.eof() && ((n = static_cast<char>(in.peek())) != '\n')) details.parse(in); } diff --git a/src/amount.h b/src/amount.h index 1dfb4234..8a2ebf04 100644 --- a/src/amount.h +++ b/src/amount.h @@ -72,7 +72,7 @@ enum parse_flags_enum_t { PARSE_NO_MIGRATE = 0x04, PARSE_NO_REDUCE = 0x08, PARSE_NO_ASSIGN = 0x10, - PARSE_NO_DATES = 0x20, + PARSE_NO_ANNOT = 0x20, PARSE_OP_CONTEXT = 0x40, PARSE_SOFT_FAIL = 0x80 }; diff --git a/src/commodity.cc b/src/commodity.cc index 179bbc05..81183b25 100644 --- a/src/commodity.cc +++ b/src/commodity.cc @@ -490,16 +490,32 @@ commodity_t::operator bool() const return this != pool().null_commodity; } -bool commodity_t::symbol_needs_quotes(const string& symbol) -{ - foreach (char ch, symbol) - if (std::isspace(ch) || std::isdigit(ch) || ch == '-' || ch == '.') - return true; +namespace { + // Invalid commodity characters: + // SPACE, TAB, NEWLINE, RETURN + // 0-9 . , ; : ? ! - + * / ^ & | = + // < > { } [ ] ( ) @ - return false; -} + static int invalid_chars[256] = { + /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ + /* 00 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, + /* 10 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 20 */ 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, + /* 30 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + /* 40 */ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 50 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, + /* 60 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 70 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, + /* 80 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 90 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* a0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* b0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* c0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* d0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* e0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* f0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + }; -namespace { bool is_reserved_token(const char * buf) { switch (buf[0]) { @@ -524,33 +540,17 @@ namespace { } } -void commodity_t::parse_symbol(std::istream& in, string& symbol) +bool commodity_t::symbol_needs_quotes(const string& symbol) { - // Invalid commodity characters: - // SPACE, TAB, NEWLINE, RETURN - // 0-9 . , ; : ? ! - + * / ^ & | = - // < > { } [ ] ( ) @ + foreach (char ch, symbol) + if (invalid_chars[static_cast<unsigned char>(ch)]) + return true; - static int invalid_chars[256] = { - /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ - /* 00 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, - /* 10 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - /* 20 */ 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, - /* 30 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - /* 40 */ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - /* 50 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, - /* 60 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - /* 70 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, - /* 80 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - /* 90 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - /* a0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - /* b0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - /* c0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - /* d0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - /* e0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - /* f0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - }; + return false; +} +void commodity_t::parse_symbol(std::istream& in, string& symbol) +{ istream_pos_type pos = in.tellg(); char buf[256]; diff --git a/src/compare.cc b/src/compare.cc index 99e430a7..12114c7d 100644 --- a/src/compare.cc +++ b/src/compare.cc @@ -42,8 +42,10 @@ void push_sort_value(std::list<sort_value_t>& sort_values, expr_t::ptr_op_t node, scope_t& scope) { if (node->kind == expr_t::op_t::O_CONS) { - push_sort_value(sort_values, node->left(), scope); - push_sort_value(sort_values, node->right(), scope); + while (node && node->kind == expr_t::op_t::O_CONS) { + push_sort_value(sort_values, node->left(), scope); + node = node->right(); + } } else { bool inverted = false; @@ -54,7 +56,7 @@ void push_sort_value(std::list<sort_value_t>& sort_values, sort_values.push_back(sort_value_t()); sort_values.back().inverted = inverted; - sort_values.back().value = expr_t(node).calc(scope).simplified(); + sort_values.back().value = expr_t(node).calc(scope).simplified(); if (sort_values.back().value.is_null()) throw_(calc_error, diff --git a/src/expr.cc b/src/expr.cc index 5bc537d9..b3d4abcd 100644 --- a/src/expr.cc +++ b/src/expr.cc @@ -33,6 +33,7 @@ #include "expr.h" #include "parser.h" +#include "scope.h" namespace ledger { @@ -162,4 +163,45 @@ void expr_t::dump(std::ostream& out) const if (ptr) ptr->dump(out, 0); } +value_t source_command(call_scope_t& args) +{ + std::istream * in = NULL; + scoped_ptr<ifstream> stream; + string pathname; + + if (args.has(0)) { + pathname = args.get<string>(0); + stream.reset(new ifstream(path(pathname))); + in = stream.get(); + } else { + pathname = "<stdin>"; + in = &std::cin; + } + + symbol_scope_t file_locals(args); + std::size_t linenum = 0; + char buf[4096]; + istream_pos_type pos; + + while (in->good() && ! in->eof()) { + pos = in->tellg(); + in->getline(buf, 4095); + linenum++; + + char * p = skip_ws(buf); + if (*p && *p != ';') { + try { + expr_t(p).calc(file_locals); + } + catch (const std::exception&) { + add_error_context(_("While parsing value expression on line %1:") + << linenum); + add_error_context(source_context(pathname, pos, in->tellg(), "> ")); + } + } + } + + return true; +} + } // namespace ledger @@ -160,6 +160,10 @@ inline value_t expr_value(expr_t::ptr_op_t op) { return temp; } +class call_scope_t; + +value_t source_command(call_scope_t& scope); + } // namespace ledger #endif // _EXPR_H diff --git a/src/flags.h b/src/flags.h index 03f47ff9..09b7eec4 100644 --- a/src/flags.h +++ b/src/flags.h @@ -112,11 +112,11 @@ public: } basic_flags_t(const T& bits) { TRACE_CTOR(basic_flags_t, "const T&"); - set_flags(bits); + supports_flags<T, U>::set_flags(bits); } basic_flags_t(const U& bits) { TRACE_CTOR(basic_flags_t, "const U&"); - set_flags(static_cast<T>(bits)); + supports_flags<T, U>::set_flags(static_cast<T>(bits)); } ~basic_flags_t() throw() { TRACE_DTOR(basic_flags_t); diff --git a/src/global.h b/src/global.h index 115183a5..6504230d 100644 --- a/src/global.h +++ b/src/global.h @@ -55,6 +55,10 @@ public: global_scope_t(char ** envp); ~global_scope_t(); + virtual string description() { + return _("global scope"); + } + void read_init(); void read_environment_settings(char * envp[]); strings_list read_command_arguments(scope_t& scope, strings_list args); @@ -108,10 +108,15 @@ expr_t::ptr_op_t expr_t::op_t::compile(scope_t& scope, const int depth) scope.define(symbol_t::FUNCTION, left()->as_ident(), right()); break; case O_CALL: - if (left()->left()->is_ident()) - scope.define(symbol_t::FUNCTION, left()->left()->as_ident(), this); - else + if (left()->left()->is_ident()) { + ptr_op_t node(new op_t(op_t::O_LAMBDA)); + node->set_left(left()->right()); + node->set_right(right()); + + scope.define(symbol_t::FUNCTION, left()->left()->as_ident(), node); + } else { throw_(compile_error, _("Invalid function definition")); + } break; default: throw_(compile_error, _("Invalid function definition")); @@ -151,15 +156,21 @@ value_t expr_t::op_t::calc(scope_t& scope, ptr_op_t * locus, const int depth) break; case IDENT: { - if (! left()) + ptr_op_t definition = left(); + if (! definition) { + // If no definition was pre-compiled for this identifier, look it + // up in the current scope. + definition = scope.lookup(symbol_t::FUNCTION, as_ident()); + } + if (! definition) throw_(calc_error, _("Unknown identifier '%1'") << as_ident()); // Evaluating an identifier is the same as calling its definition // directly, so we create an empty call_scope_t to reflect the scope for // this implicit call. call_scope_t call_args(scope, locus, depth); - result = left()->compile(call_args, depth + 1) - ->calc(call_args, locus, depth + 1); + result = definition->compile(call_args, depth + 1) + ->calc(call_args, locus, depth + 1); check_type_context(scope, result); break; } @@ -177,74 +188,68 @@ value_t expr_t::op_t::calc(scope_t& scope, ptr_op_t * locus, const int depth) break; } - case O_DEFINE: { + case O_LAMBDA: { call_scope_t& call_args(downcast<call_scope_t>(scope)); - std::size_t args_count = call_args.size(); - std::size_t args_index = 0; - - assert(left()->kind == O_CALL); + std::size_t args_count(call_args.size()); + std::size_t args_index(0); + symbol_scope_t call_scope(call_args); + ptr_op_t sym(left()); - for (ptr_op_t sym = left()->right(); - sym; - sym = sym->has_right() ? sym->right() : NULL) { + for (; sym; sym = sym->has_right() ? sym->right() : NULL) { ptr_op_t varname = sym; if (sym->kind == O_CONS) varname = sym->left(); - if (! varname->is_ident()) + if (! varname->is_ident()) { throw_(calc_error, _("Invalid function definition")); - else if (args_index == args_count) - scope.define(symbol_t::FUNCTION, varname->as_ident(), - wrap_value(false)); - else - scope.define(symbol_t::FUNCTION, varname->as_ident(), - wrap_value(call_args[args_index++])); + } + else if (args_index == args_count) { + call_scope.define(symbol_t::FUNCTION, varname->as_ident(), + wrap_value(NULL_VALUE)); + } + else { + DEBUG("expr.compile", + "Defining function parameter " << varname->as_ident()); + call_scope.define(symbol_t::FUNCTION, varname->as_ident(), + wrap_value(call_args[args_index++])); + } } if (args_index < args_count) throw_(calc_error, - _("Too many arguments in function call (saw %1)") << args_count); + _("Too few arguments in function call (saw %1)") << args_count); - result = right()->calc(scope, locus, depth + 1); + result = right()->calc(call_scope, locus, depth + 1); break; } case O_LOOKUP: { context_scope_t context_scope(scope, value_t::SCOPE); + bool scope_error = true; if (value_t obj = left()->calc(context_scope, locus, depth + 1)) { - if (obj.is_scope()) { - if (obj.as_scope() == NULL) { - throw_(calc_error, _("Left operand of . operator is NULL")); - } else { - scope_t& objscope(*obj.as_scope()); - if (ptr_op_t member = - objscope.lookup(symbol_t::FUNCTION, right()->as_ident())) { - result = member->calc(objscope, NULL, depth + 1); - break; - } - } + if (obj.is_scope() && obj.as_scope() != NULL) { + bind_scope_t bound_scope(scope, *obj.as_scope()); + result = right()->calc(bound_scope, locus, depth + 1); + scope_error = false; } } - if (right()->kind != IDENT) - throw_(calc_error, - _("Right operand of . operator must be an identifier")); - else - throw_(calc_error, - _("Failed to lookup member '%1'") << right()->as_ident()); + if (scope_error) + throw_(calc_error, _("Left operand does not evaluate to an object")); break; } case O_CALL: { call_scope_t call_args(scope, locus, depth); if (has_right()) - call_args.set_args(split_cons_expr(right()->kind == O_SEQ ? - right()->left() : right())); + call_args.set_args(split_cons_expr(right())); ptr_op_t func = left(); const string& name(func->as_ident()); func = func->left(); if (! func) + func = scope.lookup(symbol_t::FUNCTION, name); + if (! func) throw_(calc_error, _("Calling unknown function '%1'") << name); if (func->is_function()) @@ -467,6 +472,9 @@ bool expr_t::op_t::print(std::ostream& out, const context_t& context) const string symbol; + if (kind > TERMINALS && (kind != O_CALL && kind != O_DEFINE)) + out << '('; + switch (kind) { case VALUE: as_value().dump(out, context.relaxed); @@ -481,118 +489,94 @@ bool expr_t::op_t::print(std::ostream& out, const context_t& context) const break; case O_NOT: - out << "!("; + out << "! "; if (left() && left()->print(out, context)) found = true; - out << ")"; break; case O_NEG: - out << "-("; + out << "- "; if (left() && left()->print(out, context)) found = true; - out << ")"; break; case O_ADD: - out << "("; if (left() && left()->print(out, context)) found = true; out << " + "; if (has_right() && right()->print(out, context)) found = true; - out << ")"; break; case O_SUB: - out << "("; if (left() && left()->print(out, context)) found = true; out << " - "; if (has_right() && right()->print(out, context)) found = true; - out << ")"; break; case O_MUL: - out << "("; if (left() && left()->print(out, context)) found = true; out << " * "; if (has_right() && right()->print(out, context)) found = true; - out << ")"; break; case O_DIV: - out << "("; if (left() && left()->print(out, context)) found = true; out << " / "; if (has_right() && right()->print(out, context)) found = true; - out << ")"; break; case O_EQ: - out << "("; if (left() && left()->print(out, context)) found = true; out << " == "; if (has_right() && right()->print(out, context)) found = true; - out << ")"; break; case O_LT: - out << "("; if (left() && left()->print(out, context)) found = true; out << " < "; if (has_right() && right()->print(out, context)) found = true; - out << ")"; break; case O_LTE: - out << "("; if (left() && left()->print(out, context)) found = true; out << " <= "; if (has_right() && right()->print(out, context)) found = true; - out << ")"; break; case O_GT: - out << "("; if (left() && left()->print(out, context)) found = true; out << " > "; if (has_right() && right()->print(out, context)) found = true; - out << ")"; break; case O_GTE: - out << "("; if (left() && left()->print(out, context)) found = true; out << " >= "; if (has_right() && right()->print(out, context)) found = true; - out << ")"; break; case O_AND: - out << "("; if (left() && left()->print(out, context)) found = true; out << " & "; if (has_right() && right()->print(out, context)) found = true; - out << ")"; break; case O_OR: - out << "("; if (left() && left()->print(out, context)) found = true; out << " | "; if (has_right() && right()->print(out, context)) found = true; - out << ")"; break; case O_QUERY: @@ -616,15 +600,13 @@ bool expr_t::op_t::print(std::ostream& out, const context_t& context) const break; case O_SEQ: - out << "("; found = print_seq(out, this, context); - out << ")"; break; case O_DEFINE: if (left() && left()->print(out, context)) found = true; - out << " := "; + out << " = "; if (has_right() && right()->print(out, context)) found = true; break; @@ -637,11 +619,19 @@ bool expr_t::op_t::print(std::ostream& out, const context_t& context) const found = true; break; + case O_LAMBDA: + if (left() && left()->print(out, context)) + found = true; + out << " -> "; + if (has_right() && right()->print(out, context)) + found = true; + break; + case O_CALL: if (left() && left()->print(out, context)) found = true; if (has_right()) { - if (right()->kind == O_SEQ) { + if (right()->kind == O_CONS) { if (right()->print(out, context)) found = true; } else { @@ -669,6 +659,9 @@ bool expr_t::op_t::print(std::ostream& out, const context_t& context) const break; } + if (kind > TERMINALS && (kind != O_CALL && kind != O_DEFINE)) + out << ')'; + if (! symbol.empty()) { if (commodity_pool_t::current_pool->find(symbol)) out << '@'; @@ -708,6 +701,7 @@ void expr_t::op_t::dump(std::ostream& out, const int depth) const case O_DEFINE: out << "O_DEFINE"; break; case O_LOOKUP: out << "O_LOOKUP"; break; + case O_LAMBDA: out << "O_LAMBDA"; break; case O_CALL: out << "O_CALL"; break; case O_MATCH: out << "O_MATCH"; break; @@ -104,6 +104,7 @@ public: O_DEFINE, O_LOOKUP, + O_LAMBDA, O_CALL, O_MATCH, @@ -266,8 +267,10 @@ public: ostream_pos_type * end_pos; bool relaxed; - context_t(const ptr_op_t& _expr_op = NULL, - const ptr_op_t& _op_to_find = NULL, + context_t() : start_pos(NULL), end_pos(NULL), relaxed(false) {} + + context_t(const ptr_op_t& _expr_op, + const ptr_op_t& _op_to_find, ostream_pos_type * const _start_pos = NULL, ostream_pos_type * const _end_pos = NULL, const bool _relaxed = true) @@ -280,7 +283,7 @@ public: void dump(std::ostream& out, const int depth = 0) const; static ptr_op_t wrap_value(const value_t& val); - static ptr_op_t wrap_functor(const expr_t::func_t& fobj); + static ptr_op_t wrap_functor(expr_t::func_t fobj); #if defined(HAVE_BOOST_SERIALIZATION) private: @@ -326,7 +329,7 @@ inline expr_t::ptr_op_t expr_t::op_t::wrap_value(const value_t& val) { } inline expr_t::ptr_op_t -expr_t::op_t::wrap_functor(const expr_t::func_t& fobj) { +expr_t::op_t::wrap_functor(expr_t::func_t fobj) { ptr_op_t temp(new op_t(op_t::FUNCTION)); temp->set_function(fobj); return temp; diff --git a/src/output.cc b/src/output.cc index f53e60c9..9d2e0cb6 100644 --- a/src/output.cc +++ b/src/output.cc @@ -90,14 +90,10 @@ void format_posts::operator()(post_t& post) else out << '\n'; - value_scope_t val_scope(string_value(report_title)); - bind_scope_t inner_scope(bound_scope, val_scope); - - format_t group_title_format; - group_title_format - .parse_format(report.HANDLER(group_title_format_).str()); + value_scope_t val_scope(bound_scope, string_value(report_title)); + format_t group_title_format(report.HANDLER(group_title_format_).str()); - out << group_title_format(inner_scope); + out << group_title_format(val_scope); report_title = ""; } @@ -176,14 +172,10 @@ std::size_t format_accounts::post_account(account_t& account, const bool flat) else out << '\n'; - value_scope_t val_scope(string_value(report_title)); - bind_scope_t inner_scope(bound_scope, val_scope); - - format_t group_title_format; - group_title_format - .parse_format(report.HANDLER(group_title_format_).str()); + value_scope_t val_scope(bound_scope, string_value(report_title)); + format_t group_title_format(report.HANDLER(group_title_format_).str()); - out << group_title_format(inner_scope); + out << group_title_format(val_scope); report_title = ""; } diff --git a/src/parser.cc b/src/parser.cc index 9a1ebf6f..f0085295 100644 --- a/src/parser.cc +++ b/src/parser.cc @@ -65,9 +65,6 @@ expr_t::parser_t::parse_value_term(std::istream& in, push_token(tok); // let the parser see it again node->set_right(parse_value_expr(in, tflags.plus_flags(PARSE_SINGLE))); - - if (node->has_right() && node->right()->kind == op_t::O_CONS) - node->set_right(node->right()->left()); } else { push_token(tok); } @@ -78,12 +75,6 @@ expr_t::parser_t::parse_value_term(std::istream& in, node = parse_value_expr(in, tflags.plus_flags(PARSE_PARTIAL) .minus_flags(PARSE_SINGLE)); tok = next_token(in, tflags, ')'); - - if (node && node->kind == op_t::O_CONS) { - ptr_op_t prev(node); - node = new op_t(op_t::O_SEQ); - node->set_left(prev); - } break; default: @@ -241,15 +232,12 @@ expr_t::parser_t::parse_logic_expr(std::istream& in, if (node && ! tflags.has_flags(PARSE_SINGLE)) { while (true) { - op_t::kind_t kind = op_t::LAST; + op_t::kind_t kind = op_t::LAST; parse_flags_t _flags = tflags; - token_t& tok = next_token(in, tflags.plus_flags(PARSE_OP_CONTEXT)); - bool negate = false; + token_t& tok = next_token(in, tflags.plus_flags(PARSE_OP_CONTEXT)); + bool negate = false; switch (tok.kind) { - case token_t::DEFINE: - kind = op_t::O_DEFINE; - break; case token_t::EQUAL: if (tflags.has_flags(PARSE_NO_ASSIGN)) tok.rewind(in); @@ -431,39 +419,120 @@ expr_t::parser_t::parse_querycolon_expr(std::istream& in, } expr_t::ptr_op_t -expr_t::parser_t::parse_value_expr(std::istream& in, +expr_t::parser_t::parse_comma_expr(std::istream& in, const parse_flags_t& tflags) const { ptr_op_t node(parse_querycolon_expr(in, tflags)); if (node && ! tflags.has_flags(PARSE_SINGLE)) { - token_t& tok = next_token(in, tflags.plus_flags(PARSE_OP_CONTEXT)); + ptr_op_t next; + while (true) { + token_t& tok = next_token(in, tflags.plus_flags(PARSE_OP_CONTEXT)); - if (tok.kind == token_t::COMMA || tok.kind == token_t::SEMI) { - bool comma_op = tok.kind == token_t::COMMA; + if (tok.kind == token_t::COMMA) { + if (! next) { + ptr_op_t prev(node); + node = new op_t(op_t::O_CONS); + node->set_left(prev); + + next = node; + } + + token_t& ntok = next_token(in, tflags); + push_token(ntok); + if (ntok.kind == token_t::RPAREN) + break; + + ptr_op_t chain(new op_t(op_t::O_CONS)); + chain->set_left(parse_querycolon_expr(in, tflags)); + next->set_right(chain); + next = chain; + } else { + push_token(tok); + break; + } + } + } + + return node; +} + +expr_t::ptr_op_t +expr_t::parser_t::parse_lambda_expr(std::istream& in, + const parse_flags_t& tflags) const +{ + ptr_op_t node(parse_comma_expr(in, tflags)); + + if (node && ! tflags.has_flags(PARSE_SINGLE)) { + token_t& tok = next_token(in, tflags.plus_flags(PARSE_OP_CONTEXT)); + + if (tok.kind == token_t::ARROW) { ptr_op_t prev(node); - node = new op_t(comma_op ? op_t::O_CONS : op_t::O_SEQ); + node = new op_t(op_t::O_LAMBDA); node->set_left(prev); - node->set_right(parse_value_expr(in, tflags)); - if (! node->right()) - throw_(parse_error, - _("%1 operator not followed by argument") << tok.symbol); + node->set_right(parse_querycolon_expr(in, tflags)); + } else { + push_token(tok); + } + } - tok = next_token(in, tflags.plus_flags(PARSE_OP_CONTEXT)); + return node; +} + +expr_t::ptr_op_t +expr_t::parser_t::parse_assign_expr(std::istream& in, + const parse_flags_t& tflags) const +{ + ptr_op_t node(parse_lambda_expr(in, tflags)); + + if (node && ! tflags.has_flags(PARSE_SINGLE)) { + token_t& tok = next_token(in, tflags.plus_flags(PARSE_OP_CONTEXT)); + + if (tok.kind == token_t::ASSIGN) { + ptr_op_t prev(node); + node = new op_t(op_t::O_DEFINE); + node->set_left(prev); + node->set_right(parse_lambda_expr(in, tflags)); + } else { + push_token(tok); } + } + + return node; +} - if (tok.kind != token_t::TOK_EOF) { - if (tflags.has_flags(PARSE_PARTIAL)) +expr_t::ptr_op_t +expr_t::parser_t::parse_value_expr(std::istream& in, + const parse_flags_t& tflags) const +{ + ptr_op_t node(parse_assign_expr(in, tflags)); + + if (node && ! tflags.has_flags(PARSE_SINGLE)) { + ptr_op_t next; + while (true) { + token_t& tok = next_token(in, tflags.plus_flags(PARSE_OP_CONTEXT)); + + if (tok.kind == token_t::SEMI) { + if (! next) { + ptr_op_t prev(node); + node = new op_t(op_t::O_SEQ); + node->set_left(prev); + + next = node; + } + + ptr_op_t chain(new op_t(op_t::O_SEQ)); + chain->set_left(parse_assign_expr(in, tflags)); + + next->set_right(chain); + next = chain; + } else { push_token(tok); - else - tok.unexpected(); + break; + } } } - else if (! tflags.has_flags(PARSE_PARTIAL) && - ! tflags.has_flags(PARSE_SINGLE)) { - throw_(parse_error, _("Failed to parse value expression")); - } return node; } diff --git a/src/parser.h b/src/parser.h index 93ea994f..9a65765d 100644 --- a/src/parser.h +++ b/src/parser.h @@ -93,6 +93,12 @@ class expr_t::parser_t : public noncopyable const parse_flags_t& flags) const; ptr_op_t parse_querycolon_expr(std::istream& in, const parse_flags_t& flags) const; + ptr_op_t parse_comma_expr(std::istream& in, + const parse_flags_t& flags) const; + ptr_op_t parse_lambda_expr(std::istream& in, + const parse_flags_t& flags) const; + ptr_op_t parse_assign_expr(std::istream& in, + const parse_flags_t& flags) const; ptr_op_t parse_value_expr(std::istream& in, const parse_flags_t& flags) const; @@ -99,6 +99,16 @@ public: TRACE_DTOR(post_t); } + virtual string description() { + if (pos) { + std::ostringstream buf; + buf << _("posting at line %1") << pos->beg_line; + return buf.str(); + } else { + return string(_("generated posting")); + } + } + virtual bool has_tag(const string& tag, bool inherit = true) const; virtual bool has_tag(const mask_t& tag_mask, diff --git a/src/py_amount.cc b/src/py_amount.cc index 3cb9f0eb..0b9e0410 100644 --- a/src/py_amount.cc +++ b/src/py_amount.cc @@ -295,7 +295,6 @@ internal precision.")) .value("NoMigrate", PARSE_NO_MIGRATE) .value("NoReduce", PARSE_NO_REDUCE) .value("NoAssign", PARSE_NO_ASSIGN) - .value("NoDates", PARSE_NO_DATES) .value("OpContext", PARSE_OP_CONTEXT) .value("SoftFail", PARSE_SOFT_FAIL) ; diff --git a/src/py_item.cc b/src/py_item.cc index 0e95f24f..e37228fe 100644 --- a/src/py_item.cc +++ b/src/py_item.cc @@ -106,7 +106,7 @@ void export_item() #if 0 class_< item_t, bases<scope_t> > ("JournalItem", init<uint_least8_t>()) #else - class_< item_t > ("JournalItem", init<uint_least8_t>()) + class_< item_t, noncopyable > ("JournalItem", no_init) #endif #if 1 .add_property("flags", &supports_flags<>::flags, diff --git a/src/py_xact.cc b/src/py_xact.cc index 5ab0d90d..b7582854 100644 --- a/src/py_xact.cc +++ b/src/py_xact.cc @@ -82,7 +82,7 @@ using namespace boost::python; void export_xact() { - class_< xact_base_t, bases<item_t> > ("TransactionBase") + class_< xact_base_t, bases<item_t>, noncopyable > ("TransactionBase", no_init) .add_property("journal", make_getter(&xact_base_t::journal, return_internal_reference<>()), diff --git a/src/query.cc b/src/query.cc index bed6afae..5480336c 100644 --- a/src/query.cc +++ b/src/query.cc @@ -186,6 +186,8 @@ test_ident: return token_t(token_t::TOK_META); else if (ident == "show") return token_t(token_t::TOK_SHOW); + else if (ident == "only") + return token_t(token_t::TOK_ONLY); else if (ident == "bold") return token_t(token_t::TOK_BOLD); else if (ident == "for") @@ -249,6 +251,7 @@ query_t::parser_t::parse_query_term(query_t::lexer_t::token_t::kind_t tok_contex lexer_t::token_t tok = lexer.next_token(); switch (tok.kind) { case lexer_t::token_t::TOK_SHOW: + case lexer_t::token_t::TOK_ONLY: case lexer_t::token_t::TOK_BOLD: case lexer_t::token_t::TOK_FOR: case lexer_t::token_t::TOK_SINCE: @@ -452,9 +455,26 @@ query_t::parser_t::parse_query_expr(lexer_t::token_t::kind_t tok_context, lexer_t::token_t tok = lexer.peek_token(); while (tok.kind != lexer_t::token_t::END_REACHED) { switch (tok.kind) { - case lexer_t::token_t::TOK_SHOW: { + case lexer_t::token_t::TOK_SHOW: + case lexer_t::token_t::TOK_ONLY: + case lexer_t::token_t::TOK_BOLD: { lexer.next_token(); + kind_t kind; + switch (tok.kind) { + case lexer_t::token_t::TOK_SHOW: + kind = QUERY_SHOW; + break; + case lexer_t::token_t::TOK_ONLY: + kind = QUERY_ONLY; + break; + case lexer_t::token_t::TOK_BOLD: + kind = QUERY_BOLD; + break; + default: + break; + } + expr_t::ptr_op_t node; while (expr_t::ptr_op_t next = parse_or_expr(tok_context)) { if (! node) { @@ -470,25 +490,7 @@ query_t::parser_t::parse_query_expr(lexer_t::token_t::kind_t tok_context, if (node) query_map.insert (query_map_t::value_type - (QUERY_SHOW, predicate_t(node, what_to_keep).print_to_str())); - break; - } - - case lexer_t::token_t::TOK_BOLD: { - lexer.next_token(); - - expr_t::ptr_op_t node = parse_or_expr(tok_context); - while (expr_t::ptr_op_t next = parse_or_expr(tok_context)) { - expr_t::ptr_op_t prev(node); - node = new expr_t::op_t(expr_t::op_t::O_OR); - node->set_left(prev); - node->set_right(next); - } - - if (node) - query_map.insert - (query_map_t::value_type - (QUERY_BOLD, predicate_t(node, what_to_keep).print_to_str())); + (kind, predicate_t(node, what_to_keep).print_to_str())); break; } diff --git a/src/query.h b/src/query.h index 5a4651a0..b5b3b0fc 100644 --- a/src/query.h +++ b/src/query.h @@ -90,6 +90,7 @@ public: TOK_EXPR, TOK_SHOW, + TOK_ONLY, TOK_BOLD, TOK_FOR, TOK_SINCE, @@ -144,6 +145,7 @@ public: case TOK_META: return "TOK_META"; case TOK_EXPR: return "TOK_EXPR"; case TOK_SHOW: return "TOK_SHOW"; + case TOK_ONLY: return "TOK_ONLY"; case TOK_BOLD: return "TOK_BOLD"; case TOK_FOR: return "TOK_FOR"; case TOK_SINCE: return "TOK_SINCE"; @@ -170,6 +172,7 @@ public: case TOK_META: return "meta"; case TOK_EXPR: return "expr"; case TOK_SHOW: return "show"; + case TOK_ONLY: return "only"; case TOK_BOLD: return "bold"; case TOK_FOR: return "for"; case TOK_SINCE: return "since"; @@ -234,6 +237,7 @@ public: enum kind_t { QUERY_LIMIT, QUERY_SHOW, + QUERY_ONLY, QUERY_BOLD, QUERY_FOR }; diff --git a/src/report.cc b/src/report.cc index 9d733674..5c7bf01d 100644 --- a/src/report.cc +++ b/src/report.cc @@ -267,6 +267,11 @@ void report_t::parse_query_args(const value_t& args, const string& whence) DEBUG("report.predicate", "Limit predicate = " << HANDLER(limit_).str()); } + if (query.has_query(query_t::QUERY_ONLY)) { + HANDLER(only_).on(whence, query.get_query(query_t::QUERY_ONLY)); + DEBUG("report.predicate", "Only predicate = " << HANDLER(only_).str()); + } + if (query.has_query(query_t::QUERY_SHOW)) { HANDLER(display_).on(whence, query.get_query(query_t::QUERY_SHOW)); DEBUG("report.predicate", "Display predicate = " << HANDLER(display_).str()); @@ -544,17 +549,19 @@ value_t report_t::fn_trim(call_scope_t& args) } } +value_t report_t::fn_format(call_scope_t& args) +{ + format_t format(args.get<string>(0)); + std::ostringstream out; + out << format(args); + return string_value(out.str()); +} + value_t report_t::fn_print(call_scope_t& args) { - std::ostream& out(output_stream); - bool first = true; - for (std::size_t i = 0; i < args.size(); i++) { - if (first) - first = false; - else - out << ' '; - args[i].print(out); - } + for (std::size_t i = 0; i < args.size(); i++) + args[i].print(output_stream); + static_cast<std::ostream&>(output_stream) << std::endl; return true; } @@ -1173,6 +1180,8 @@ expr_t::ptr_op_t report_t::lookup(const symbol_t::kind_t kind, case 'f': if (is_eq(p, "format_date")) return MAKE_FUNCTOR(report_t::fn_format_date); + else if (is_eq(p, "format")) + return MAKE_FUNCTOR(report_t::fn_format); else if (is_eq(p, "floor")) return MAKE_FUNCTOR(report_t::fn_floor); break; @@ -1444,6 +1453,8 @@ expr_t::ptr_op_t report_t::lookup(const symbol_t::kind_t kind, case 's': if (is_eq(p, "stats") || is_eq(p, "stat")) return WRAP_FUNCTOR(report_statistics); + else if (is_eq(p, "source")) + return WRAP_FUNCTOR(source_command); break; case 'x': diff --git a/src/report.h b/src/report.h index 59a632e6..5c172ee9 100644 --- a/src/report.h +++ b/src/report.h @@ -125,6 +125,10 @@ public: output_stream.close(); } + virtual string description() { + return _("current report"); + } + void normalize_options(const string& verb); void normalize_period(); void parse_query_args(const value_t& args, const string& whence); @@ -147,6 +151,7 @@ public: value_t fn_is_seq(call_scope_t& scope); value_t fn_strip(call_scope_t& scope); value_t fn_trim(call_scope_t& scope); + value_t fn_format(call_scope_t& scope); value_t fn_print(call_scope_t& scope); value_t fn_scrub(call_scope_t& scope); value_t fn_quantity(call_scope_t& scope); @@ -389,6 +394,7 @@ public: " ansify_if(partial_account(options.flat), blue if color)," " bold if should_bold))\n%/" "%$1\n%/" + "%(prepend_width ? \" \" * prepend_width : \"\")" "--------------------\n"); }); @@ -446,6 +452,7 @@ public: " %(!options.flat ? depth_spacer : \"\")" "%-(ansify_if(partial_account(options.flat), blue if color))\n" "%/%$1 %$2 %$3 %$4\n%/" + "%(prepend_width ? \" \" * prepend_width : \"\")" "------------ ------------ ------------ -----\n"); }); @@ -464,6 +471,7 @@ public: " %(!options.flat ? depth_spacer : \"\")" "%-(ansify_if(partial_account(options.flat), blue if color))\n%/" "%$1 %$2 %$3\n%/" + "%(prepend_width ? \" \" * prepend_width : \"\")" "---------------- ---------------- ---------\n"); }); diff --git a/src/scope.h b/src/scope.h index dac6eba3..31b10f6b 100644 --- a/src/scope.h +++ b/src/scope.h @@ -109,6 +109,8 @@ public: TRACE_DTOR(scope_t); } + virtual string description() = 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, @@ -191,6 +193,10 @@ public: TRACE_DTOR(bind_scope_t); } + virtual string description() { + return grandchild.description(); + } + virtual void define(const symbol_t::kind_t kind, const string& name, expr_t::ptr_op_t def) { parent->define(kind, name, def); @@ -262,6 +268,16 @@ public: TRACE_DTOR(symbol_scope_t); } + virtual string description() { + if (parent) + return parent->description(); +#if !defined(NO_ASSERTS) + else + assert(false); +#endif + return empty_string; + } + virtual void define(const symbol_t::kind_t kind, const string& name, expr_t::ptr_op_t def); @@ -299,6 +315,10 @@ public: TRACE_DTOR(context_scope_t); } + virtual string description() { + return parent->description(); + } + virtual value_t::type_t type_context() const { return value_type_context; } @@ -351,6 +371,10 @@ public: TRACE_DTOR(call_scope_t); } + virtual string description() { + return context_scope_t::description(); + } + void set_args(const value_t& _args) { args = _args; } @@ -605,7 +629,7 @@ call_scope_t::get<expr_t::ptr_op_t>(std::size_t index, bool) { return args[index].as_any<expr_t::ptr_op_t>(); } -class value_scope_t : public scope_t +class value_scope_t : public child_scope_t { value_t value; @@ -614,8 +638,13 @@ class value_scope_t : public scope_t } public: - value_scope_t(const value_t& _value) : value(_value) {} + value_scope_t(scope_t& _parent, const value_t& _value) + : child_scope_t(_parent), value(_value) {} + virtual string description() { + return parent->description(); + } + virtual expr_t::ptr_op_t lookup(const symbol_t::kind_t kind, const string& name) { diff --git a/src/session.h b/src/session.h index 6de4b2dd..b8fd52f2 100644 --- a/src/session.h +++ b/src/session.h @@ -64,6 +64,10 @@ public: TRACE_DTOR(session_t); } + virtual string description() { + return _("current session"); + } + void set_flush_on_next_data_file(const bool truth) { flush_on_next_data_file = truth; } diff --git a/src/stream.cc b/src/stream.cc index 001e7760..5d4cf5e0 100644 --- a/src/stream.cc +++ b/src/stream.cc @@ -102,7 +102,11 @@ namespace { else { // parent close(pfd[0]); typedef iostreams::stream<iostreams::file_descriptor_sink> fdstream; +#if BOOST_VERSION >= 104400 + *os = new fdstream(pfd[1], iostreams::never_close_handle); +#else // BOOST_VERSION >= 104400 *os = new fdstream(pfd[1]); +#endif // BOOST_VERSION >= 104400 } return pfd[1]; #else diff --git a/src/system.hh.in b/src/system.hh.in index d9e664e3..6f709684 100644 --- a/src/system.hh.in +++ b/src/system.hh.in @@ -160,7 +160,6 @@ typedef std::ostream::pos_type ostream_pos_type; #include <boost/operators.hpp> #include <boost/optional.hpp> #include <boost/ptr_container/ptr_list.hpp> -#include <boost/ptr_container/serialize_ptr_deque.hpp> #include <boost/random/mersenne_twister.hpp> #include <boost/random/uniform_int.hpp> #include <boost/random/uniform_real.hpp> @@ -194,6 +193,7 @@ typedef std::ostream::pos_type ostream_pos_type; #include <boost/date_time/posix_time/time_serialize.hpp> #include <boost/date_time/gregorian/greg_serialize.hpp> +#include <boost/ptr_container/serialize_ptr_deque.hpp> namespace boost { namespace serialization { @@ -239,6 +239,10 @@ void serialize(Archive& ar, istream_pos_type& pos, const unsigned int) } // namespace serialization } // namespace boost +#else // HAVE_BOOST_SERIALIZATION + +#include <boost/ptr_container/ptr_deque.hpp> + #endif // HAVE_BOOST_SERIALIZATION #if defined(HAVE_BOOST_PYTHON) diff --git a/src/textual.cc b/src/textual.cc index 7ddb5251..3dbae9a1 100644 --- a/src/textual.cc +++ b/src/textual.cc @@ -112,6 +112,10 @@ namespace { ~instance_t(); + virtual string description() { + return _("textual parser"); + } + void parse(); std::streamsize read_line(char *& line); bool peek_whitespace_line() { diff --git a/src/token.cc b/src/token.cc index 67cff65e..199c3b3c 100644 --- a/src/token.cc +++ b/src/token.cc @@ -60,8 +60,7 @@ int expr_t::token_t::parse_reserved_word(std::istream& in) case 'd': if (std::strcmp(buf, "div") == 0) { symbol[0] = '/'; - symbol[1] = '/'; - symbol[2] = '\0'; + symbol[1] = '\0'; kind = KW_DIV; return 1; } @@ -69,9 +68,7 @@ int expr_t::token_t::parse_reserved_word(std::istream& in) case 'e': if (std::strcmp(buf, "else") == 0) { - symbol[0] = 'L'; - symbol[1] = 'S'; - symbol[2] = '\0'; + std::strcpy(symbol, "else"); kind = KW_ELSE; return 1; } @@ -79,6 +76,7 @@ int expr_t::token_t::parse_reserved_word(std::istream& in) case 'f': if (std::strcmp(buf, "false") == 0) { + std::strcpy(symbol, "false"); kind = VALUE; value = false; return 1; @@ -115,6 +113,7 @@ int expr_t::token_t::parse_reserved_word(std::istream& in) case 't': if (std::strcmp(buf, "true") == 0) { + std::strcpy(symbol, "true"); kind = VALUE; value = true; return 1; @@ -231,6 +230,7 @@ void expr_t::token_t::next(std::istream& in, const parse_flags_t& pflags, break; } +#if 0 case '{': { in.get(c); amount_t temp; @@ -243,6 +243,7 @@ void expr_t::token_t::next(std::istream& in, const parse_flags_t& pflags, value = temp; break; } +#endif case '!': in.get(c); @@ -268,6 +269,15 @@ void expr_t::token_t::next(std::istream& in, const parse_flags_t& pflags, case '-': in.get(c); + c = static_cast<char>(in.peek()); + if (c == '>') { + in.get(c); + symbol[1] = c; + symbol[2] = '\0'; + kind = ARROW; + length = 2; + break; + } kind = MINUS; break; case '+': @@ -287,14 +297,6 @@ void expr_t::token_t::next(std::istream& in, const parse_flags_t& pflags, case ':': in.get(c); c = static_cast<char>(in.peek()); - if (c == '=') { - in.get(c); - symbol[1] = c; - symbol[2] = '\0'; - kind = DEFINE; - length = 2; - break; - } kind = COLON; break; @@ -336,7 +338,7 @@ void expr_t::token_t::next(std::istream& in, const parse_flags_t& pflags, length = 2; break; } - kind = EQUAL; + kind = ASSIGN; break; case '<': @@ -403,6 +405,7 @@ void expr_t::token_t::next(std::istream& in, const parse_flags_t& pflags, // maximum displayed precision. parse_flags_t parse_flags; + parse_flags.add_flags(PARSE_NO_ANNOT); if (pflags.has_flags(PARSE_NO_MIGRATE)) parse_flags.add_flags(PARSE_NO_MIGRATE); if (pflags.has_flags(PARSE_NO_REDUCE)) diff --git a/src/token.h b/src/token.h index aae73837..13a799cb 100644 --- a/src/token.h +++ b/src/token.h @@ -56,6 +56,8 @@ struct expr_t::token_t : public noncopyable LPAREN, // ( RPAREN, // ) + LBRACE, // { + RBRACE, // } EQUAL, // == NEQUAL, // != @@ -64,7 +66,6 @@ struct expr_t::token_t : public noncopyable GREATER, // > GREATEREQ, // >= - DEFINE, // := ASSIGN, // = MATCH, // =~ NMATCH, // !~ @@ -72,6 +73,7 @@ struct expr_t::token_t : public noncopyable PLUS, // + STAR, // * SLASH, // / + ARROW, // -> KW_DIV, // div EXCLAM, // !, not @@ -94,7 +96,7 @@ struct expr_t::token_t : public noncopyable } kind; - char symbol[3]; + char symbol[6]; value_t value; std::size_t length; @@ -113,13 +115,10 @@ struct expr_t::token_t : public noncopyable } void clear() { - kind = UNKNOWN; - length = 0; - value = NULL_VALUE; - + kind = UNKNOWN; + length = 0; + value = NULL_VALUE; symbol[0] = '\0'; - symbol[1] = '\0'; - symbol[2] = '\0'; } int parse_reserved_word(std::istream& in); @@ -117,6 +117,16 @@ public: TRACE_DTOR(xact_t); } + virtual string description() { + if (pos) { + std::ostringstream buf; + buf << _("transaction at line %1") << pos->beg_line; + return buf.str(); + } else { + return string(_("generated transaction")); + } + } + virtual void add_post(post_t * post); string idstring() const; @@ -194,6 +204,16 @@ public: TRACE_DTOR(auto_xact_t); } + virtual string description() { + if (pos) { + std::ostringstream buf; + buf << _("automated transaction at line %1") << pos->beg_line; + return buf.str(); + } else { + return string(_("generated automated transaction")); + } + } + virtual void parse_tags(const char * p, scope_t&, bool overwrite_existing = true) { @@ -242,6 +262,16 @@ class period_xact_t : public xact_base_t TRACE_DTOR(period_xact_t); } + virtual string description() { + if (pos) { + std::ostringstream buf; + buf << _("periodic transaction at line %1") << pos->beg_line; + return buf.str(); + } else { + return string(_("generated periodic transaction")); + } + } + #if defined(HAVE_BOOST_SERIALIZATION) private: /** Serialization. */ |