Errors while calculating value expressions now display meaningful error

context.
This commit is contained in:
John Wiegley 2009-01-22 18:54:24 -04:00
parent 9c164bd3dc
commit 7b76ea5cbc
3 changed files with 130 additions and 60 deletions

View file

@ -162,10 +162,8 @@ value_t expr_t::eval(const string& _expr, scope_t& scope)
void expr_t::print(std::ostream& out) const void expr_t::print(std::ostream& out) const
{ {
if (ptr) { if (ptr)
op_t::print_context_t context; ptr->print(out);
ptr->print(out, context);
}
} }
void expr_t::dump(std::ostream& out) const void expr_t::dump(std::ostream& out) const

153
src/op.cc
View file

@ -69,8 +69,28 @@ expr_t::ptr_op_t expr_t::op_t::compile(scope_t& scope)
return intermediate; return intermediate;
} }
namespace {
expr_t::ptr_op_t context_op_ptr;
}
value_t expr_t::op_t::calc(scope_t& scope) value_t expr_t::op_t::calc(scope_t& scope)
{ {
try {
context_op_ptr = ptr_op_t();
return opcalc(scope);
}
catch (const std::exception& err) {
if (context_op_ptr) {
add_error_context("While evaluating value expression:");
add_error_context(expr_context(this, context_op_ptr));
}
throw;
}
}
value_t expr_t::op_t::opcalc(scope_t& scope)
{
try {
switch (kind) { switch (kind) {
case VALUE: case VALUE:
return as_value(); return as_value();
@ -78,7 +98,12 @@ value_t expr_t::op_t::calc(scope_t& scope)
case IDENT: case IDENT:
if (! left()) if (! left())
throw_(calc_error, "Unknown identifier '" << as_ident() << "'"); throw_(calc_error, "Unknown identifier '" << as_ident() << "'");
return left()->calc(scope); return left()->opcalc(scope);
case MASK:
throw_(calc_error,
"Regexs can only be used in a match; did you mean: account =~ /"
<< as_mask() << '/');
case FUNCTION: { case FUNCTION: {
// Evaluating a FUNCTION is the same as calling it directly; this happens // Evaluating a FUNCTION is the same as calling it directly; this happens
@ -91,8 +116,8 @@ value_t expr_t::op_t::calc(scope_t& scope)
case O_CALL: { case O_CALL: {
call_scope_t call_args(scope); call_scope_t call_args(scope);
if (right()) if (has_right())
call_args.set_args(right()->calc(scope)); call_args.set_args(right()->opcalc(scope));
ptr_op_t func = left(); ptr_op_t func = left();
@ -106,8 +131,9 @@ value_t expr_t::op_t::calc(scope_t& scope)
} }
case O_MATCH: case O_MATCH:
assert(right()->is_mask()); if (! right()->is_mask())
return right()->as_mask().match(left()->calc(scope).to_string()); throw_(calc_error, "Right-hand argument to match operator must be a regex");
return right()->as_mask().match(left()->opcalc(scope).to_string());
case INDEX: { case INDEX: {
const call_scope_t& args(downcast<const call_scope_t>(scope)); const call_scope_t& args(downcast<const call_scope_t>(scope));
@ -120,47 +146,47 @@ value_t expr_t::op_t::calc(scope_t& scope)
} }
case O_EQ: case O_EQ:
return left()->calc(scope) == right()->calc(scope); return left()->opcalc(scope) == right()->opcalc(scope);
case O_LT: case O_LT:
return left()->calc(scope) < right()->calc(scope); return left()->opcalc(scope) < right()->opcalc(scope);
case O_LTE: case O_LTE:
return left()->calc(scope) <= right()->calc(scope); return left()->opcalc(scope) <= right()->opcalc(scope);
case O_GT: case O_GT:
return left()->calc(scope) > right()->calc(scope); return left()->opcalc(scope) > right()->opcalc(scope);
case O_GTE: case O_GTE:
return left()->calc(scope) >= right()->calc(scope); return left()->opcalc(scope) >= right()->opcalc(scope);
case O_ADD: case O_ADD:
return left()->calc(scope) + right()->calc(scope); return left()->opcalc(scope) + right()->opcalc(scope);
case O_SUB: case O_SUB:
return left()->calc(scope) - right()->calc(scope); return left()->opcalc(scope) - right()->opcalc(scope);
case O_MUL: case O_MUL:
return left()->calc(scope) * right()->calc(scope); return left()->opcalc(scope) * right()->opcalc(scope);
case O_DIV: case O_DIV:
return left()->calc(scope) / right()->calc(scope); return left()->opcalc(scope) / right()->opcalc(scope);
case O_NEG: case O_NEG:
return left()->calc(scope).negate(); return left()->opcalc(scope).negate();
case O_NOT: case O_NOT:
return ! left()->calc(scope); return ! left()->opcalc(scope);
case O_AND: case O_AND:
return ! left()->calc(scope) ? value_t(false) : right()->calc(scope); return ! left()->opcalc(scope) ? value_t(false) : right()->opcalc(scope);
case O_OR: case O_OR:
if (value_t temp = left()->calc(scope)) if (value_t temp = left()->opcalc(scope))
return temp; return temp;
else else
return right()->calc(scope); return right()->opcalc(scope);
case O_COMMA: { case O_COMMA: {
value_t result(left()->calc(scope)); value_t result(left()->opcalc(scope));
ptr_op_t next = right(); ptr_op_t next = right();
while (next) { while (next) {
ptr_op_t value_op; ptr_op_t value_op;
if (next->kind == O_COMMA /* || next->kind == O_UNION */) { if (next->kind == O_COMMA) {
value_op = next->left(); value_op = next->left();
next = next->right(); next = next->right();
} else { } else {
@ -168,7 +194,7 @@ value_t expr_t::op_t::calc(scope_t& scope)
next = NULL; next = NULL;
} }
result.push_back(value_op->calc(scope)); result.push_back(value_op->opcalc(scope));
} }
return result; return result;
} }
@ -180,15 +206,21 @@ value_t expr_t::op_t::calc(scope_t& scope)
} }
return NULL_VALUE; return NULL_VALUE;
}
catch (const std::exception& err) {
if (! context_op_ptr)
context_op_ptr = this;
throw;
}
} }
bool expr_t::op_t::print(std::ostream& out, print_context_t& context) const bool expr_t::op_t::print(std::ostream& out, const context_t& context) const
{ {
bool found = false; bool found = false;
if (context.start_pos && this == context.op_to_find) { if (context.start_pos && this == context.op_to_find) {
*context.start_pos = out.tellp(); *context.start_pos = out.tellp();
*context.start_pos--; *context.start_pos -= 1;
found = true; found = true;
} }
@ -204,6 +236,10 @@ bool expr_t::op_t::print(std::ostream& out, print_context_t& context) const
out << as_ident(); out << as_ident();
break; break;
case MASK:
out << '/' << as_mask() << '/';
break;
case FUNCTION: case FUNCTION:
out << "<FUNCTION>"; out << "<FUNCTION>";
break; break;
@ -228,7 +264,7 @@ bool expr_t::op_t::print(std::ostream& out, print_context_t& context) const
if (left() && left()->print(out, context)) if (left() && left()->print(out, context))
found = true; found = true;
out << " + "; out << " + ";
if (right() && right()->print(out, context)) if (has_right() && right()->print(out, context))
found = true; found = true;
out << ")"; out << ")";
break; break;
@ -237,7 +273,7 @@ bool expr_t::op_t::print(std::ostream& out, print_context_t& context) const
if (left() && left()->print(out, context)) if (left() && left()->print(out, context))
found = true; found = true;
out << " - "; out << " - ";
if (right() && right()->print(out, context)) if (has_right() && right()->print(out, context))
found = true; found = true;
out << ")"; out << ")";
break; break;
@ -246,7 +282,7 @@ bool expr_t::op_t::print(std::ostream& out, print_context_t& context) const
if (left() && left()->print(out, context)) if (left() && left()->print(out, context))
found = true; found = true;
out << " * "; out << " * ";
if (right() && right()->print(out, context)) if (has_right() && right()->print(out, context))
found = true; found = true;
out << ")"; out << ")";
break; break;
@ -255,7 +291,7 @@ bool expr_t::op_t::print(std::ostream& out, print_context_t& context) const
if (left() && left()->print(out, context)) if (left() && left()->print(out, context))
found = true; found = true;
out << " / "; out << " / ";
if (right() && right()->print(out, context)) if (has_right() && right()->print(out, context))
found = true; found = true;
out << ")"; out << ")";
break; break;
@ -265,7 +301,7 @@ bool expr_t::op_t::print(std::ostream& out, print_context_t& context) const
if (left() && left()->print(out, context)) if (left() && left()->print(out, context))
found = true; found = true;
out << " == "; out << " == ";
if (right() && right()->print(out, context)) if (has_right() && right()->print(out, context))
found = true; found = true;
out << ")"; out << ")";
break; break;
@ -274,7 +310,7 @@ bool expr_t::op_t::print(std::ostream& out, print_context_t& context) const
if (left() && left()->print(out, context)) if (left() && left()->print(out, context))
found = true; found = true;
out << " < "; out << " < ";
if (right() && right()->print(out, context)) if (has_right() && right()->print(out, context))
found = true; found = true;
out << ")"; out << ")";
break; break;
@ -283,7 +319,7 @@ bool expr_t::op_t::print(std::ostream& out, print_context_t& context) const
if (left() && left()->print(out, context)) if (left() && left()->print(out, context))
found = true; found = true;
out << " <= "; out << " <= ";
if (right() && right()->print(out, context)) if (has_right() && right()->print(out, context))
found = true; found = true;
out << ")"; out << ")";
break; break;
@ -292,7 +328,7 @@ bool expr_t::op_t::print(std::ostream& out, print_context_t& context) const
if (left() && left()->print(out, context)) if (left() && left()->print(out, context))
found = true; found = true;
out << " > "; out << " > ";
if (right() && right()->print(out, context)) if (has_right() && right()->print(out, context))
found = true; found = true;
out << ")"; out << ")";
break; break;
@ -301,7 +337,7 @@ bool expr_t::op_t::print(std::ostream& out, print_context_t& context) const
if (left() && left()->print(out, context)) if (left() && left()->print(out, context))
found = true; found = true;
out << " >= "; out << " >= ";
if (right() && right()->print(out, context)) if (has_right() && right()->print(out, context))
found = true; found = true;
out << ")"; out << ")";
break; break;
@ -311,7 +347,7 @@ bool expr_t::op_t::print(std::ostream& out, print_context_t& context) const
if (left() && left()->print(out, context)) if (left() && left()->print(out, context))
found = true; found = true;
out << " & "; out << " & ";
if (right() && right()->print(out, context)) if (has_right() && right()->print(out, context))
found = true; found = true;
out << ")"; out << ")";
break; break;
@ -320,7 +356,7 @@ bool expr_t::op_t::print(std::ostream& out, print_context_t& context) const
if (left() && left()->print(out, context)) if (left() && left()->print(out, context))
found = true; found = true;
out << " | "; out << " | ";
if (right() && right()->print(out, context)) if (has_right() && right()->print(out, context))
found = true; found = true;
out << ")"; out << ")";
break; break;
@ -329,7 +365,7 @@ bool expr_t::op_t::print(std::ostream& out, print_context_t& context) const
if (left() && left()->print(out, context)) if (left() && left()->print(out, context))
found = true; found = true;
out << ", "; out << ", ";
if (right() && right()->print(out, context)) if (has_right() && right()->print(out, context))
found = true; found = true;
break; break;
@ -337,7 +373,7 @@ bool expr_t::op_t::print(std::ostream& out, print_context_t& context) const
if (left() && left()->print(out, context)) if (left() && left()->print(out, context))
found = true; found = true;
out << "("; out << "(";
if (right() && right()->print(out, context)) if (has_right() && right()->print(out, context))
found = true; found = true;
out << ")"; out << ")";
break; break;
@ -347,7 +383,7 @@ bool expr_t::op_t::print(std::ostream& out, print_context_t& context) const
if (left() && left()->print(out, context)) if (left() && left()->print(out, context))
found = true; found = true;
out << "/ =~ "; out << "/ =~ ";
if (right() && right()->print(out, context)) if (has_right() && right()->print(out, context))
found = true; found = true;
break; break;
@ -363,8 +399,10 @@ bool expr_t::op_t::print(std::ostream& out, print_context_t& context) const
out << symbol; out << symbol;
} }
if (context.end_pos && this == context.op_to_find) if (context.end_pos && this == context.op_to_find) {
*context.end_pos = static_cast<unsigned long>(out.tellp()) - 1; *context.end_pos = out.tellp();
*context.end_pos -= 1;
}
return found; return found;
} }
@ -380,15 +418,19 @@ void expr_t::op_t::dump(std::ostream& out, const int depth) const
switch (kind) { switch (kind) {
case VALUE: case VALUE:
out << "VALUE - " << as_value(); out << "VALUE: " << as_value();
break; break;
case IDENT: case IDENT:
out << "IDENT - " << as_ident(); out << "IDENT: " << as_ident();
break;
case MASK:
out << "MASK: " << as_mask();
break; break;
case INDEX: case INDEX:
out << "INDEX - " << as_index(); out << "INDEX: " << as_index();
break; break;
case FUNCTION: case FUNCTION:
@ -430,11 +472,11 @@ void expr_t::op_t::dump(std::ostream& out, const int depth) const
if (kind > TERMINALS || kind == IDENT) { if (kind > TERMINALS || kind == IDENT) {
if (left()) { if (left()) {
left()->dump(out, depth + 1); left()->dump(out, depth + 1);
if (kind > UNARY_OPERATORS && right()) if (kind > UNARY_OPERATORS && has_right())
right()->dump(out, depth + 1); right()->dump(out, depth + 1);
} }
else if (kind > UNARY_OPERATORS) { else if (kind > UNARY_OPERATORS) {
assert(! right()); assert(! has_right());
} }
} }
} }
@ -493,7 +535,7 @@ void expr_t::op_t::write(std::ostream& out) const
left()->write(out); left()->write(out);
if (kind > UNARY_OPERATORS) { if (kind > UNARY_OPERATORS) {
if (right()) { if (has_right()) {
binary::write_bool(out, true); binary::write_bool(out, true);
right()->write(out); right()->write(out);
} else { } else {
@ -523,4 +565,23 @@ void expr_t::op_t::write(std::ostream& out) const
} }
} }
string expr_context(const expr_t::ptr_op_t op, const expr_t::ptr_op_t goal)
{
ostream_pos_type start_pos, end_pos;
expr_t::op_t::context_t context(op, goal, &start_pos, &end_pos);
std::ostringstream buf;
buf << " ";
if (op->print(buf, context)) {
buf << "\n";
for (int i = 0; i <= end_pos; i++) {
if (i > start_pos)
buf << "^";
else
buf << " ";
}
buf << '\n';
}
return buf.str();
}
} // namespace ledger } // namespace ledger

View file

@ -241,6 +241,11 @@ public:
assert(kind > TERMINALS); assert(kind > TERMINALS);
data = expr; data = expr;
} }
bool has_right() const {
if (kind < TERMINALS)
return false;
return as_op();
}
private: private:
void acquire() const { void acquire() const {
@ -274,23 +279,27 @@ private:
public: public:
ptr_op_t compile(scope_t& scope); ptr_op_t compile(scope_t& scope);
value_t calc(scope_t& scope); value_t calc(scope_t& scope);
value_t opcalc(scope_t& scope);
struct print_context_t struct context_t
{ {
const bool relaxed; ptr_op_t expr_op;
const ptr_op_t& op_to_find; ptr_op_t op_to_find;
ostream_pos_type * start_pos; ostream_pos_type * start_pos;
ostream_pos_type * end_pos; ostream_pos_type * end_pos;
bool relaxed;
print_context_t(const bool _relaxed = false, context_t(const ptr_op_t& _expr_op = ptr_op_t(),
const ptr_op_t& _op_to_find = ptr_op_t(), const ptr_op_t& _op_to_find = ptr_op_t(),
ostream_pos_type * _start_pos = NULL, ostream_pos_type * const _start_pos = NULL,
ostream_pos_type * _end_pos = NULL) ostream_pos_type * const _end_pos = NULL,
: relaxed(_relaxed), op_to_find(_op_to_find), const bool _relaxed = true)
start_pos(_start_pos), end_pos(_end_pos) {} : expr_op(_expr_op), op_to_find(_op_to_find),
start_pos(_start_pos), end_pos(_end_pos),
relaxed(_relaxed) {}
}; };
bool print(std::ostream& out, print_context_t& context) const; bool print(std::ostream& out, const context_t& context = context_t()) const;
void dump(std::ostream& out, const int depth) const; void dump(std::ostream& out, const int depth) const;
void read(const char *& data); void read(const char *& data);
@ -324,6 +333,8 @@ inline expr_t::ptr_op_t expr_t::op_t::wrap_functor(const function_t& fobj) {
#define MAKE_FUNCTOR(x) expr_t::op_t::wrap_functor(bind(&x, this, _1)) #define MAKE_FUNCTOR(x) expr_t::op_t::wrap_functor(bind(&x, this, _1))
#define WRAP_FUNCTOR(x) expr_t::op_t::wrap_functor(x) #define WRAP_FUNCTOR(x) expr_t::op_t::wrap_functor(x)
string expr_context(const expr_t::ptr_op_t op, const expr_t::ptr_op_t op);
} // namespace ledger } // namespace ledger
#endif // _OP_H #endif // _OP_H