diff --git a/src/builtins/math.cpp b/src/builtins/math.cpp index 9aba8f290..979e13435 100644 --- a/src/builtins/math.cpp +++ b/src/builtins/math.cpp @@ -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; diff --git a/src/tinyexpr.cpp b/src/tinyexpr.cpp index af4f4802f..884c432a0 100644 --- a/src/tinyexpr.cpp +++ b/src/tinyexpr.cpp @@ -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(tok - start_) + 1}; + te_error_t err{error_, static_cast(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); } diff --git a/src/tinyexpr.h b/src/tinyexpr.h index c722417af..5ffec3537 100644 --- a/src/tinyexpr.h +++ b/src/tinyexpr.h @@ -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. */ diff --git a/tests/checks/math.fish b/tests/checks/math.fish index 17e5010c3..8bcdbe01b 100644 --- a/tests/checks/math.fish +++ b/tests/checks/math.fish @@ -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