math: Add error length

Like we now do for syntax errors, this marks the extent of the error.

Currently for unknown functions only, would be cool for division too
This commit is contained in:
Fabian Boehm 2022-09-08 17:54:45 +02:00
parent 5edba044a3
commit 52e065e479
4 changed files with 16 additions and 5 deletions

View File

@ -258,7 +258,12 @@ static int evaluate_expression(const wchar_t *cmd, const parser_t &parser, io_st
} else {
streams.err.append_format(L"%ls: Error: %ls\n", cmd, math_describe_error(error));
streams.err.append_format(L"'%ls'\n", expression.c_str());
streams.err.append_format(L"%*ls%ls\n", error.position - 1, L" ", L"^");
if (error.len >= 2) {
wcstring tildes(error.len - 2, L'~');
streams.err.append_format(L"%*ls%ls%ls%ls\n", error.position - 1, L" ", L"^", tildes.c_str(), L"^");
} else {
streams.err.append_format(L"%*ls%ls\n", error.position - 1, L" ", L"^");
}
retval = STATUS_CMD_ERROR;
}
return retval;

View File

@ -113,11 +113,11 @@ struct state {
double eval() { return expr(); }
[[nodiscard]] te_error_t error() const {
if (type_ == TOK_END) return {TE_ERROR_NONE, 0};
if (type_ == TOK_END) return {TE_ERROR_NONE, 0, 0};
// If we have an error position set, use that,
// otherwise the current position.
const wchar_t *tok = errpos_ ? errpos_ : next_;
te_error_t err{error_, static_cast<int>(tok - start_) + 1};
te_error_t err{error_, static_cast<int>(tok - start_) + 1, errlen_};
if (error_ == TE_ERROR_NONE) {
// If we're not at the end but there's no error, then that means we have a
// superfluous token that we have no idea what to do with.
@ -133,6 +133,7 @@ struct state {
const wchar_t *start_;
const wchar_t *next_;
const wchar_t *errpos_{nullptr};
int errlen_{0};
te_fun_t current_{NAN};
void next_token();
@ -312,6 +313,9 @@ void state::next_token() {
// Our error is more specific, so it takes precedence.
type_ = TOK_ERROR;
error_ = TE_ERROR_UNKNOWN_FUNCTION;
errpos_ = start + 1;
errlen_ = next_ - start;
}
} else {
/* Look for an operator or special character. */
@ -533,6 +537,7 @@ double state::term() {
error_ = TE_ERROR_DIV_BY_ZERO;
// Error position is the "/" or "%" sign for now
errpos_ = tok;
errlen_ = 1;
}
ret = fn(ret, ret2);
}

View File

@ -44,6 +44,7 @@ typedef enum {
typedef struct te_error_t {
te_error_type_t type;
int position;
int len;
} te_error_t;
/* Parses the input expression, evaluates it, and frees it. */

View File

@ -113,7 +113,7 @@ not math 'ncr(1)'
not math 'blah()'
# CHECKERR: math: Error: Unknown function
# CHECKERR: 'blah()'
# CHECKERR: ^
# CHECKERR: ^~~^
math n + 4
# CHECKERR: math: Error: Unknown function
@ -167,7 +167,7 @@ math 2x 4
math 2 x4 # ERROR
# CHECKERR: math: Error: Unknown function
# CHECKERR: '2 x4'
# CHECKERR: ^
# CHECKERR: ^^
math 0x 3
# CHECK: 2
# CHECK: 20