mirror of
https://github.com/fish-shell/fish-shell
synced 2024-11-10 23:24:39 +00:00
math: Use wchar
This was doing a bunch of work narrowing strings for no reason.
This commit is contained in:
parent
edbb8ad0a4
commit
97cd87f3b2
3 changed files with 43 additions and 44 deletions
|
@ -223,13 +223,12 @@ static int evaluate_expression(const wchar_t *cmd, const parser_t &parser, io_st
|
|||
|
||||
int retval = STATUS_CMD_OK;
|
||||
te_error_t error;
|
||||
std::string narrow_str = wcs2string(expression);
|
||||
// Switch locale while computing stuff.
|
||||
// This means that the "." is always the radix character,
|
||||
// so numbers work the same across locales.
|
||||
char *saved_locale = strdup(setlocale(LC_NUMERIC, nullptr));
|
||||
setlocale(LC_NUMERIC, "C");
|
||||
double v = te_interp(narrow_str.c_str(), &error);
|
||||
double v = te_interp(expression.c_str(), &error);
|
||||
|
||||
if (error.position == 0) {
|
||||
// Check some runtime errors after the fact.
|
||||
|
|
|
@ -75,7 +75,7 @@ typedef struct te_expr {
|
|||
} te_expr;
|
||||
|
||||
using te_builtin = struct {
|
||||
const char *name;
|
||||
const wchar_t *name;
|
||||
const void *address;
|
||||
int type;
|
||||
};
|
||||
|
@ -85,15 +85,15 @@ using state = struct {
|
|||
double value;
|
||||
const void *function;
|
||||
};
|
||||
const char *start;
|
||||
const char *next;
|
||||
const wchar_t *start;
|
||||
const wchar_t *next;
|
||||
int type;
|
||||
te_error_type_t error;
|
||||
};
|
||||
|
||||
/* Parses the input expression. */
|
||||
/* Returns NULL on error. */
|
||||
te_expr *te_compile(const char *expression, te_error_t *error);
|
||||
te_expr *te_compile(const wchar_t *expression, te_error_t *error);
|
||||
|
||||
/* Evaluates the expression. */
|
||||
double te_eval(const te_expr *n);
|
||||
|
@ -182,47 +182,47 @@ static constexpr double bit_xor(double a, double b) {
|
|||
|
||||
static const te_builtin functions[] = {
|
||||
/* must be in alphabetical order */
|
||||
{"abs", reinterpret_cast<const void *>(static_cast<te_fun1>(fabs)), TE_FUNCTION1},
|
||||
{"acos", reinterpret_cast<const void *>(static_cast<te_fun1>(acos)), TE_FUNCTION1},
|
||||
{"asin", reinterpret_cast<const void *>(static_cast<te_fun1>(asin)), TE_FUNCTION1},
|
||||
{"atan", reinterpret_cast<const void *>(static_cast<te_fun1>(atan)), TE_FUNCTION1},
|
||||
{"atan2", reinterpret_cast<const void *>(static_cast<te_fun2>(atan2)), TE_FUNCTION2},
|
||||
{"bitand", reinterpret_cast<const void *>(static_cast<te_fun2>(bit_and)), TE_FUNCTION2},
|
||||
{"bitor", reinterpret_cast<const void *>(static_cast<te_fun2>(bit_or)), TE_FUNCTION2},
|
||||
{"bitxor", reinterpret_cast<const void *>(static_cast<te_fun2>(bit_xor)), TE_FUNCTION2},
|
||||
{"ceil", reinterpret_cast<const void *>(static_cast<te_fun1>(ceil)), TE_FUNCTION1},
|
||||
{"cos", reinterpret_cast<const void *>(static_cast<te_fun1>(cos)), TE_FUNCTION1},
|
||||
{"cosh", reinterpret_cast<const void *>(static_cast<te_fun1>(cosh)), TE_FUNCTION1},
|
||||
{"e", reinterpret_cast<const void *>(static_cast<te_fun0>(e)), TE_FUNCTION0},
|
||||
{"exp", reinterpret_cast<const void *>(static_cast<te_fun1>(exp)), TE_FUNCTION1},
|
||||
{"fac", reinterpret_cast<const void *>(static_cast<te_fun1>(fac)), TE_FUNCTION1},
|
||||
{"floor", reinterpret_cast<const void *>(static_cast<te_fun1>(floor)), TE_FUNCTION1},
|
||||
{"ln", reinterpret_cast<const void *>(static_cast<te_fun1>(log)), TE_FUNCTION1},
|
||||
{"log", reinterpret_cast<const void *>(static_cast<te_fun1>(log10)), TE_FUNCTION1},
|
||||
{"log10", reinterpret_cast<const void *>(static_cast<te_fun1>(log10)), TE_FUNCTION1},
|
||||
{"ncr", reinterpret_cast<const void *>(static_cast<te_fun2>(ncr)), TE_FUNCTION2},
|
||||
{"npr", reinterpret_cast<const void *>(static_cast<te_fun2>(npr)), TE_FUNCTION2},
|
||||
{"pi", reinterpret_cast<const void *>(static_cast<te_fun0>(pi)), TE_FUNCTION0},
|
||||
{"pow", reinterpret_cast<const void *>(static_cast<te_fun2>(pow)), TE_FUNCTION2},
|
||||
{"round", reinterpret_cast<const void *>(static_cast<te_fun1>(round)), TE_FUNCTION1},
|
||||
{"sin", reinterpret_cast<const void *>(static_cast<te_fun1>(sin)), TE_FUNCTION1},
|
||||
{"sinh", reinterpret_cast<const void *>(static_cast<te_fun1>(sinh)), TE_FUNCTION1},
|
||||
{"sqrt", reinterpret_cast<const void *>(static_cast<te_fun1>(sqrt)), TE_FUNCTION1},
|
||||
{"tan", reinterpret_cast<const void *>(static_cast<te_fun1>(tan)), TE_FUNCTION1},
|
||||
{"tanh", reinterpret_cast<const void *>(static_cast<te_fun1>(tanh)), TE_FUNCTION1},
|
||||
{"tau", reinterpret_cast<const void *>(static_cast<te_fun0>(tau)), TE_FUNCTION0},
|
||||
{L"abs", reinterpret_cast<const void *>(static_cast<te_fun1>(fabs)), TE_FUNCTION1},
|
||||
{L"acos", reinterpret_cast<const void *>(static_cast<te_fun1>(acos)), TE_FUNCTION1},
|
||||
{L"asin", reinterpret_cast<const void *>(static_cast<te_fun1>(asin)), TE_FUNCTION1},
|
||||
{L"atan", reinterpret_cast<const void *>(static_cast<te_fun1>(atan)), TE_FUNCTION1},
|
||||
{L"atan2", reinterpret_cast<const void *>(static_cast<te_fun2>(atan2)), TE_FUNCTION2},
|
||||
{L"bitand", reinterpret_cast<const void *>(static_cast<te_fun2>(bit_and)), TE_FUNCTION2},
|
||||
{L"bitor", reinterpret_cast<const void *>(static_cast<te_fun2>(bit_or)), TE_FUNCTION2},
|
||||
{L"bitxor", reinterpret_cast<const void *>(static_cast<te_fun2>(bit_xor)), TE_FUNCTION2},
|
||||
{L"ceil", reinterpret_cast<const void *>(static_cast<te_fun1>(ceil)), TE_FUNCTION1},
|
||||
{L"cos", reinterpret_cast<const void *>(static_cast<te_fun1>(cos)), TE_FUNCTION1},
|
||||
{L"cosh", reinterpret_cast<const void *>(static_cast<te_fun1>(cosh)), TE_FUNCTION1},
|
||||
{L"e", reinterpret_cast<const void *>(static_cast<te_fun0>(e)), TE_FUNCTION0},
|
||||
{L"exp", reinterpret_cast<const void *>(static_cast<te_fun1>(exp)), TE_FUNCTION1},
|
||||
{L"fac", reinterpret_cast<const void *>(static_cast<te_fun1>(fac)), TE_FUNCTION1},
|
||||
{L"floor", reinterpret_cast<const void *>(static_cast<te_fun1>(floor)), TE_FUNCTION1},
|
||||
{L"ln", reinterpret_cast<const void *>(static_cast<te_fun1>(log)), TE_FUNCTION1},
|
||||
{L"log", reinterpret_cast<const void *>(static_cast<te_fun1>(log10)), TE_FUNCTION1},
|
||||
{L"log10", reinterpret_cast<const void *>(static_cast<te_fun1>(log10)), TE_FUNCTION1},
|
||||
{L"ncr", reinterpret_cast<const void *>(static_cast<te_fun2>(ncr)), TE_FUNCTION2},
|
||||
{L"npr", reinterpret_cast<const void *>(static_cast<te_fun2>(npr)), TE_FUNCTION2},
|
||||
{L"pi", reinterpret_cast<const void *>(static_cast<te_fun0>(pi)), TE_FUNCTION0},
|
||||
{L"pow", reinterpret_cast<const void *>(static_cast<te_fun2>(pow)), TE_FUNCTION2},
|
||||
{L"round", reinterpret_cast<const void *>(static_cast<te_fun1>(round)), TE_FUNCTION1},
|
||||
{L"sin", reinterpret_cast<const void *>(static_cast<te_fun1>(sin)), TE_FUNCTION1},
|
||||
{L"sinh", reinterpret_cast<const void *>(static_cast<te_fun1>(sinh)), TE_FUNCTION1},
|
||||
{L"sqrt", reinterpret_cast<const void *>(static_cast<te_fun1>(sqrt)), TE_FUNCTION1},
|
||||
{L"tan", reinterpret_cast<const void *>(static_cast<te_fun1>(tan)), TE_FUNCTION1},
|
||||
{L"tanh", reinterpret_cast<const void *>(static_cast<te_fun1>(tanh)), TE_FUNCTION1},
|
||||
{L"tau", reinterpret_cast<const void *>(static_cast<te_fun0>(tau)), TE_FUNCTION0},
|
||||
};
|
||||
|
||||
static const te_builtin *find_builtin(const char *name, int len) {
|
||||
static const te_builtin *find_builtin(const wchar_t *name, int len) {
|
||||
const auto end = std::end(functions);
|
||||
const te_builtin *found = std::lower_bound(std::begin(functions), end, name,
|
||||
[len](const te_builtin &lhs, const char *rhs) {
|
||||
[len](const te_builtin &lhs, const wchar_t *rhs) {
|
||||
// The length is important because that's where
|
||||
// the parens start
|
||||
return std::strncmp(lhs.name, rhs, len) < 0;
|
||||
return std::wcsncmp(lhs.name, rhs, len) < 0;
|
||||
});
|
||||
// We need to compare again because we might have gotten the first "larger" element.
|
||||
if (found != end && std::strncmp(found->name, name, len) == 0 && found->name[len] == 0)
|
||||
if (found != end && std::wcsncmp(found->name, name, len) == 0 && found->name[len] == 0)
|
||||
return found;
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -250,7 +250,7 @@ static void next_token(state *s) {
|
|||
|
||||
/* Try reading a number. */
|
||||
if ((s->next[0] >= '0' && s->next[0] <= '9') || s->next[0] == '.') {
|
||||
s->value = strtod(s->next, const_cast<char **>(&s->next));
|
||||
s->value = wcstod(s->next, const_cast<wchar_t **>(&s->next));
|
||||
s->type = TOK_NUMBER;
|
||||
} else {
|
||||
/* Look for a function call. */
|
||||
|
@ -258,7 +258,7 @@ static void next_token(state *s) {
|
|||
// - that's the alternative multiplication operator.
|
||||
if (s->next[0] >= 'a' && s->next[0] <= 'z' &&
|
||||
!(s->next[0] == 'x' && isspace(s->next[1]))) {
|
||||
const char *start;
|
||||
const wchar_t *start;
|
||||
start = s->next;
|
||||
while ((s->next[0] >= 'a' && s->next[0] <= 'z') ||
|
||||
(s->next[0] >= '0' && s->next[0] <= '9') || (s->next[0] == '_'))
|
||||
|
@ -571,7 +571,7 @@ static void optimize(te_expr *n) {
|
|||
}
|
||||
}
|
||||
|
||||
te_expr *te_compile(const char *expression, te_error_t *error) {
|
||||
te_expr *te_compile(const wchar_t *expression, te_error_t *error) {
|
||||
state s;
|
||||
s.start = s.next = expression;
|
||||
s.error = TE_ERROR_NONE;
|
||||
|
@ -602,7 +602,7 @@ te_expr *te_compile(const char *expression, te_error_t *error) {
|
|||
}
|
||||
}
|
||||
|
||||
double te_interp(const char *expression, te_error_t *error) {
|
||||
double te_interp(const wchar_t *expression, te_error_t *error) {
|
||||
te_expr *n = te_compile(expression, error);
|
||||
double ret;
|
||||
if (n) {
|
||||
|
|
|
@ -47,6 +47,6 @@ typedef struct te_error_t {
|
|||
|
||||
/* Parses the input expression, evaluates it, and frees it. */
|
||||
/* Returns NaN on error. */
|
||||
double te_interp(const char *expression, te_error_t *error);
|
||||
double te_interp(const wchar_t *expression, te_error_t *error);
|
||||
|
||||
#endif /*__TINYEXPR_H__*/
|
||||
|
|
Loading…
Reference in a new issue