diff options
author | Bram Moolenaar <Bram@vim.org> | 2008-06-24 22:58:06 +0000 |
---|---|---|
committer | Bram Moolenaar <Bram@vim.org> | 2008-06-24 22:58:06 +0000 |
commit | 8c8de839325eda0bed68917d18179d2003b344d1 (patch) | |
tree | c65b80f0a627f2e77385a07a62ee4206465cbc22 /src/eval.c | |
parent | 864207de089119377a1e1e5d411307d8eb57399e (diff) |
updated for version 7.2av7.2a
Diffstat (limited to 'src/eval.c')
-rw-r--r-- | src/eval.c | 1005 |
1 files changed, 897 insertions, 108 deletions
diff --git a/src/eval.c b/src/eval.c index 54ca054ca1..fada51d646 100644 --- a/src/eval.c +++ b/src/eval.c @@ -16,6 +16,8 @@ #include "vim.h" +#if defined(FEAT_EVAL) || defined(PROTO) + #ifdef AMIGA # include <time.h> /* for strftime() */ #endif @@ -24,12 +26,10 @@ # include <time.h> /* for time_t */ #endif -#ifdef HAVE_FCNTL_H -# include <fcntl.h> +#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H) +# include <math.h> #endif -#if defined(FEAT_EVAL) || defined(PROTO) - #define DICT_MAXNEST 100 /* maximum nesting of lists and dicts */ /* @@ -108,6 +108,7 @@ static char *e_dictrange = N_("E719: Cannot use [:] with a Dictionary"); static char *e_letwrong = N_("E734: Wrong variable type for %s="); static char *e_nofunc = N_("E130: Unknown function: %s"); static char *e_illvar = N_("E461: Illegal variable name: %s"); + /* * All user-defined global variables are stored in dictionary "globvardict". * "globvars_var" is the variable that is used for "g:". @@ -164,13 +165,13 @@ struct ufunc int uf_profiling; /* TRUE when func is being profiled */ /* profiling the function as a whole */ int uf_tm_count; /* nr of calls */ - proftime_T uf_tm_total; /* time spend in function + children */ - proftime_T uf_tm_self; /* time spend in function itself */ + proftime_T uf_tm_total; /* time spent in function + children */ + proftime_T uf_tm_self; /* time spent in function itself */ proftime_T uf_tm_children; /* time spent in children this call */ /* profiling the function per line */ int *uf_tml_count; /* nr of times line was executed */ - proftime_T *uf_tml_total; /* time spend in a line + children */ - proftime_T *uf_tml_self; /* time spend in a line itself */ + proftime_T *uf_tml_total; /* time spent in a line + children */ + proftime_T *uf_tml_self; /* time spent in a line itself */ proftime_T uf_tml_start; /* start time for current line */ proftime_T uf_tml_children; /* time spent in children for this line */ proftime_T uf_tml_wait; /* start wait time for current line */ @@ -346,13 +347,15 @@ static struct vimvar {VV_NAME("mouse_lnum", VAR_NUMBER), 0}, {VV_NAME("mouse_col", VAR_NUMBER), 0}, {VV_NAME("operator", VAR_STRING), VV_RO}, + {VV_NAME("searchforward", VAR_NUMBER), 0}, }; /* shorthand */ -#define vv_type vv_di.di_tv.v_type -#define vv_nr vv_di.di_tv.vval.v_number -#define vv_str vv_di.di_tv.vval.v_string -#define vv_tv vv_di.di_tv +#define vv_type vv_di.di_tv.v_type +#define vv_nr vv_di.di_tv.vval.v_number +#define vv_float vv_di.di_tv.vval.v_float +#define vv_str vv_di.di_tv.vval.v_string +#define vv_tv vv_di.di_tv /* * The v: variables are stored in dictionary "vimvardict". @@ -450,6 +453,9 @@ static int get_dict_tv __ARGS((char_u **arg, typval_T *rettv, int evaluate)); static char_u *echo_string __ARGS((typval_T *tv, char_u **tofree, char_u *numbuf, int copyID)); static char_u *tv2string __ARGS((typval_T *tv, char_u **tofree, char_u *numbuf, int copyID)); static char_u *string_quote __ARGS((char_u *str, int function)); +#ifdef FEAT_FLOAT +static int string2float __ARGS((char_u *text, float_T *value)); +#endif static int get_env_tv __ARGS((char_u **arg, typval_T *rettv, int evaluate)); static int find_internal_func __ARGS((char_u *name)); static char_u *deref_func_name __ARGS((char_u *name, int *lenp)); @@ -457,11 +463,17 @@ static int get_func_tv __ARGS((char_u *name, int len, typval_T *rettv, char_u ** static int call_func __ARGS((char_u *name, int len, typval_T *rettv, int argcount, typval_T *argvars, linenr_T firstline, linenr_T lastline, int *doesrange, int evaluate, dict_T *selfdict)); static void emsg_funcname __ARGS((char *ermsg, char_u *name)); +#ifdef FEAT_FLOAT +static void f_abs __ARGS((typval_T *argvars, typval_T *rettv)); +#endif static void f_add __ARGS((typval_T *argvars, typval_T *rettv)); static void f_append __ARGS((typval_T *argvars, typval_T *rettv)); static void f_argc __ARGS((typval_T *argvars, typval_T *rettv)); static void f_argidx __ARGS((typval_T *argvars, typval_T *rettv)); static void f_argv __ARGS((typval_T *argvars, typval_T *rettv)); +#ifdef FEAT_FLOAT +static void f_atan __ARGS((typval_T *argvars, typval_T *rettv)); +#endif static void f_browse __ARGS((typval_T *argvars, typval_T *rettv)); static void f_browsedir __ARGS((typval_T *argvars, typval_T *rettv)); static void f_bufexists __ARGS((typval_T *argvars, typval_T *rettv)); @@ -473,6 +485,9 @@ static void f_bufwinnr __ARGS((typval_T *argvars, typval_T *rettv)); static void f_byte2line __ARGS((typval_T *argvars, typval_T *rettv)); static void f_byteidx __ARGS((typval_T *argvars, typval_T *rettv)); static void f_call __ARGS((typval_T *argvars, typval_T *rettv)); +#ifdef FEAT_FLOAT +static void f_ceil __ARGS((typval_T *argvars, typval_T *rettv)); +#endif static void f_changenr __ARGS((typval_T *argvars, typval_T *rettv)); static void f_char2nr __ARGS((typval_T *argvars, typval_T *rettv)); static void f_cindent __ARGS((typval_T *argvars, typval_T *rettv)); @@ -485,6 +500,9 @@ static void f_complete_check __ARGS((typval_T *argvars, typval_T *rettv)); #endif static void f_confirm __ARGS((typval_T *argvars, typval_T *rettv)); static void f_copy __ARGS((typval_T *argvars, typval_T *rettv)); +#ifdef FEAT_FLOAT +static void f_cos __ARGS((typval_T *argvars, typval_T *rettv)); +#endif static void f_count __ARGS((typval_T *argvars, typval_T *rettv)); static void f_cscope_connection __ARGS((typval_T *argvars, typval_T *rettv)); static void f_cursor __ARGS((typval_T *argsvars, typval_T *rettv)); @@ -507,6 +525,10 @@ static void f_filewritable __ARGS((typval_T *argvars, typval_T *rettv)); static void f_filter __ARGS((typval_T *argvars, typval_T *rettv)); static void f_finddir __ARGS((typval_T *argvars, typval_T *rettv)); static void f_findfile __ARGS((typval_T *argvars, typval_T *rettv)); +#ifdef FEAT_FLOAT +static void f_float2nr __ARGS((typval_T *argvars, typval_T *rettv)); +static void f_floor __ARGS((typval_T *argvars, typval_T *rettv)); +#endif static void f_fnameescape __ARGS((typval_T *argvars, typval_T *rettv)); static void f_fnamemodify __ARGS((typval_T *argvars, typval_T *rettv)); static void f_foldclosed __ARGS((typval_T *argvars, typval_T *rettv)); @@ -578,6 +600,9 @@ static void f_line __ARGS((typval_T *argvars, typval_T *rettv)); static void f_line2byte __ARGS((typval_T *argvars, typval_T *rettv)); static void f_lispindent __ARGS((typval_T *argvars, typval_T *rettv)); static void f_localtime __ARGS((typval_T *argvars, typval_T *rettv)); +#ifdef FEAT_FLOAT +static void f_log10 __ARGS((typval_T *argvars, typval_T *rettv)); +#endif static void f_map __ARGS((typval_T *argvars, typval_T *rettv)); static void f_maparg __ARGS((typval_T *argvars, typval_T *rettv)); static void f_mapcheck __ARGS((typval_T *argvars, typval_T *rettv)); @@ -597,6 +622,9 @@ static void f_mode __ARGS((typval_T *argvars, typval_T *rettv)); static void f_nextnonblank __ARGS((typval_T *argvars, typval_T *rettv)); static void f_nr2char __ARGS((typval_T *argvars, typval_T *rettv)); static void f_pathshorten __ARGS((typval_T *argvars, typval_T *rettv)); +#ifdef FEAT_FLOAT +static void f_pow __ARGS((typval_T *argvars, typval_T *rettv)); +#endif static void f_prevnonblank __ARGS((typval_T *argvars, typval_T *rettv)); static void f_printf __ARGS((typval_T *argvars, typval_T *rettv)); static void f_pumvisible __ARGS((typval_T *argvars, typval_T *rettv)); @@ -614,6 +642,9 @@ static void f_rename __ARGS((typval_T *argvars, typval_T *rettv)); static void f_repeat __ARGS((typval_T *argvars, typval_T *rettv)); static void f_resolve __ARGS((typval_T *argvars, typval_T *rettv)); static void f_reverse __ARGS((typval_T *argvars, typval_T *rettv)); +#ifdef FEAT_FLOAT +static void f_round __ARGS((typval_T *argvars, typval_T *rettv)); +#endif static void f_search __ARGS((typval_T *argvars, typval_T *rettv)); static void f_searchdecl __ARGS((typval_T *argvars, typval_T *rettv)); static void f_searchpair __ARGS((typval_T *argvars, typval_T *rettv)); @@ -633,11 +664,18 @@ static void f_settabwinvar __ARGS((typval_T *argvars, typval_T *rettv)); static void f_setwinvar __ARGS((typval_T *argvars, typval_T *rettv)); static void f_shellescape __ARGS((typval_T *argvars, typval_T *rettv)); static void f_simplify __ARGS((typval_T *argvars, typval_T *rettv)); +#ifdef FEAT_FLOAT +static void f_sin __ARGS((typval_T *argvars, typval_T *rettv)); +#endif static void f_sort __ARGS((typval_T *argvars, typval_T *rettv)); static void f_soundfold __ARGS((typval_T *argvars, typval_T *rettv)); static void f_spellbadword __ARGS((typval_T *argvars, typval_T *rettv)); static void f_spellsuggest __ARGS((typval_T *argvars, typval_T *rettv)); static void f_split __ARGS((typval_T *argvars, typval_T *rettv)); +#ifdef FEAT_FLOAT +static void f_sqrt __ARGS((typval_T *argvars, typval_T *rettv)); +static void f_str2float __ARGS((typval_T *argvars, typval_T *rettv)); +#endif static void f_str2nr __ARGS((typval_T *argvars, typval_T *rettv)); #ifdef HAVE_STRFTIME static void f_strftime __ARGS((typval_T *argvars, typval_T *rettv)); @@ -665,6 +703,9 @@ static void f_test __ARGS((typval_T *argvars, typval_T *rettv)); static void f_tolower __ARGS((typval_T *argvars, typval_T *rettv)); static void f_toupper __ARGS((typval_T *argvars, typval_T *rettv)); static void f_tr __ARGS((typval_T *argvars, typval_T *rettv)); +#ifdef FEAT_FLOAT +static void f_trunc __ARGS((typval_T *argvars, typval_T *rettv)); +#endif static void f_type __ARGS((typval_T *argvars, typval_T *rettv)); static void f_values __ARGS((typval_T *argvars, typval_T *rettv)); static void f_virtcol __ARGS((typval_T *argvars, typval_T *rettv)); @@ -788,6 +829,7 @@ eval_init() /* add to compat scope dict */ hash_add(&compat_hashtab, p->vv_di.di_key); } + set_vim_var_nr(VV_SEARCHFORWARD, 1L); } #if defined(EXITFREE) || defined(PROTO) @@ -818,15 +860,15 @@ eval_clear() /* global variables */ vars_clear(&globvarht); - /* functions */ - free_all_functions(); - hash_clear(&func_hashtab); - /* autoloaded script names */ ga_clear_strings(&ga_loaded); /* unreferenced lists and dicts */ (void)garbage_collect(); + + /* functions */ + free_all_functions(); + hash_clear(&func_hashtab); } #endif @@ -1422,7 +1464,8 @@ eval_expr(arg, nextcmd) || defined(FEAT_COMPL_FUNC) || defined(PROTO) /* * Call some vimL function and return the result in "*rettv". - * Uses argv[argc] for the function arguments. + * Uses argv[argc] for the function arguments. Only Number and String + * arguments are currently supported. * Returns OK or FAIL. */ static int @@ -2849,16 +2892,36 @@ tv_op(tv1, tv2, op) { /* nr += nr or nr -= nr*/ n = get_tv_number(tv1); - if (*op == '+') - n += get_tv_number(tv2); +#ifdef FEAT_FLOAT + if (tv2->v_type == VAR_FLOAT) + { + float_T f = n; + + if (*op == '+') + f += tv2->vval.v_float; + else + f -= tv2->vval.v_float; + clear_tv(tv1); + tv1->v_type = VAR_FLOAT; + tv1->vval.v_float = f; + } else - n -= get_tv_number(tv2); - clear_tv(tv1); - tv1->v_type = VAR_NUMBER; - tv1->vval.v_number = n; +#endif + { + if (*op == '+') + n += get_tv_number(tv2); + else + n -= get_tv_number(tv2); + clear_tv(tv1); + tv1->v_type = VAR_NUMBER; + tv1->vval.v_number = n; + } } else { + if (tv2->v_type == VAR_FLOAT) + break; + /* str .= str */ s = get_tv_string(tv1); s = concat_str(s, get_tv_string_buf(tv2, numbuf)); @@ -2867,6 +2930,27 @@ tv_op(tv1, tv2, op) tv1->vval.v_string = s; } return OK; + +#ifdef FEAT_FLOAT + case VAR_FLOAT: + { + float_T f; + + if (*op == '.' || (tv2->v_type != VAR_FLOAT + && tv2->v_type != VAR_NUMBER + && tv2->v_type != VAR_STRING)) + break; + if (tv2->v_type == VAR_FLOAT) + f = tv2->vval.v_float; + else + f = get_tv_number(tv2); + if (*op == '+') + tv1->vval.v_float += f; + else + tv1->vval.v_float -= f; + } + return OK; +#endif } } @@ -4115,7 +4199,7 @@ eval4(arg, rettv, evaluate) } /* - * If there is a comparitive operator, use it. + * If there is a comparative operator, use it. */ if (type != TYPE_UNKNOWN) { @@ -4131,7 +4215,7 @@ eval4(arg, rettv, evaluate) ic = FALSE; ++len; } - /* nothing appened: use 'ignorecase' */ + /* nothing appended: use 'ignorecase' */ else ic = p_ic; @@ -4238,6 +4322,40 @@ eval4(arg, rettv, evaluate) } } +#ifdef FEAT_FLOAT + /* + * If one of the two variables is a float, compare as a float. + * When using "=~" or "!~", always compare as string. + */ + else if ((rettv->v_type == VAR_FLOAT || var2.v_type == VAR_FLOAT) + && type != TYPE_MATCH && type != TYPE_NOMATCH) + { + float_T f1, f2; + + if (rettv->v_type == VAR_FLOAT) + f1 = rettv->vval.v_float; + else + f1 = get_tv_number(rettv); + if (var2.v_type == VAR_FLOAT) + f2 = var2.vval.v_float; + else + f2 = get_tv_number(&var2); + n1 = FALSE; + switch (type) + { + case TYPE_EQUAL: n1 = (f1 == f2); break; + case TYPE_NEQUAL: n1 = (f1 != f2); break; + case TYPE_GREATER: n1 = (f1 > f2); break; + case TYPE_GEQUAL: n1 = (f1 >= f2); break; + case TYPE_SMALLER: n1 = (f1 < f2); break; + case TYPE_SEQUAL: n1 = (f1 <= f2); break; + case TYPE_UNKNOWN: + case TYPE_MATCH: + case TYPE_NOMATCH: break; /* avoid gcc warning */ + } + } +#endif + /* * If one of the two variables is a number, compare as a number. * When using "=~" or "!~", always compare as string. @@ -4330,6 +4448,9 @@ eval5(arg, rettv, evaluate) typval_T var3; int op; long n1, n2; +#ifdef FEAT_FLOAT + float_T f1 = 0, f2 = 0; +#endif char_u *s1, *s2; char_u buf1[NUMBUFLEN], buf2[NUMBUFLEN]; char_u *p; @@ -4349,7 +4470,11 @@ eval5(arg, rettv, evaluate) if (op != '+' && op != '-' && op != '.') break; - if (op != '+' || rettv->v_type != VAR_LIST) + if ((op != '+' || rettv->v_type != VAR_LIST) +#ifdef FEAT_FLOAT + && (op == '.' || rettv->v_type != VAR_FLOAT) +#endif + ) { /* For "list + ...", an illegal use of the first operand as * a number cannot be determined before evaluating the 2nd @@ -4413,29 +4538,73 @@ eval5(arg, rettv, evaluate) { int error = FALSE; - n1 = get_tv_number_chk(rettv, &error); - if (error) +#ifdef FEAT_FLOAT + if (rettv->v_type == VAR_FLOAT) { - /* This can only happen for "list + non-list". - * For "non-list + ..." or "something - ...", we returned - * before evaluating the 2nd operand. */ - clear_tv(rettv); - return FAIL; + f1 = rettv->vval.v_float; + n1 = 0; } - n2 = get_tv_number_chk(&var2, &error); - if (error) + else +#endif { - clear_tv(rettv); - clear_tv(&var2); - return FAIL; + n1 = get_tv_number_chk(rettv, &error); + if (error) + { + /* This can only happen for "list + non-list". For + * "non-list + ..." or "something - ...", we returned + * before evaluating the 2nd operand. */ + clear_tv(rettv); + return FAIL; + } +#ifdef FEAT_FLOAT + if (var2.v_type == VAR_FLOAT) + f1 = n1; +#endif + } +#ifdef FEAT_FLOAT + if (var2.v_type == VAR_FLOAT) + { + f2 = var2.vval.v_float; + n2 = 0; + } + else +#endif + { + n2 = get_tv_number_chk(&var2, &error); + if (error) + { + clear_tv(rettv); + clear_tv(&var2); + return FAIL; + } +#ifdef FEAT_FLOAT + if (rettv->v_type == VAR_FLOAT) + f2 = n2; +#endif } clear_tv(rettv); - if (op == '+') - n1 = n1 + n2; + +#ifdef FEAT_FLOAT + /* If there is a float on either side the result is a float. */ + if (rettv->v_type == VAR_FLOAT || var2.v_type == VAR_FLOAT) + { + if (op == '+') + f1 = f1 + f2; + else + f1 = f1 - f2; + rettv->v_type = VAR_FLOAT; + rettv->vval.v_float = f1; + } else - n1 = n1 - n2; - rettv->v_type = VAR_NUMBER; - rettv->vval.v_number = n1; +#endif + { + if (op == '+') + n1 = n1 + n2; + else + n1 = n1 - n2; + rettv->v_type = VAR_NUMBER; + rettv->vval.v_number = n1; + } } clear_tv(&var2); } @@ -4463,6 +4632,10 @@ eval6(arg, rettv, evaluate) typval_T var2; int op; long n1, n2; +#ifdef FEAT_FLOAT + int use_float = FALSE; + float_T f1 = 0, f2; +#endif int error = FALSE; /* @@ -4482,7 +4655,16 @@ eval6(arg, rettv, evaluate) if (evaluate) { - n1 = get_tv_number_chk(rettv, &error); +#ifdef FEAT_FLOAT + if (rettv->v_type == VAR_FLOAT) + { + f1 = rettv->vval.v_float; + use_float = TRUE; + n1 = 0; + } + else +#endif + n1 = get_tv_number_chk(rettv, &error); clear_tv(rettv); if (error) return FAIL; @@ -4499,32 +4681,82 @@ eval6(arg, rettv, evaluate) if (evaluate) { - n2 = get_tv_number_chk(&var2, &error); - clear_tv(&var2); - if (error) - return FAIL; +#ifdef FEAT_FLOAT + if (var2.v_type == VAR_FLOAT) + { + if (!use_float) + { + f1 = n1; + use_float = TRUE; + } + f2 = var2.vval.v_float; + n2 = 0; + } + else +#endif + { + n2 = get_tv_number_chk(&var2, &error); + clear_tv(&var2); + if (error) + return FAIL; +#ifdef FEAT_FLOAT + if (use_float) + f2 = n2; +#endif + } /* * Compute the result. + * When either side is a float the result is a float. */ - if (op == '*') - n1 = n1 * n2; - else if (op == '/') +#ifdef FEAT_FLOAT + if (use_float) { - if (n2 == 0) /* give an error message? */ - n1 = 0x7fffffffL; + if (op == '*') + f1 = f1 * f2; + else if (op == '/') + { + /* We rely on the floating point library to handle divide + * by zero to result in "inf" and not a crash. */ + f1 = f1 / f2; + } else - n1 = n1 / n2; + { + EMSG(_("E804: Cannot use % with float")); + return FAIL; + } + rettv->v_type = VAR_FLOAT; + rettv->vval.v_float = f1; } else +#endif { - if (n2 == 0) /* give an error message? */ - n1 = 0; + if (op == '*') + n1 = n1 * n2; + else if (op == '/') + { + if (n2 == 0) /* give an error message? */ + { + if (n1 == 0) + n1 = -0x7fffffffL - 1L; /* similar to NaN */ + else if (n1 < 0) + n1 = -0x7fffffffL; + else + n1 = 0x7fffffffL; + } + else + n1 = n1 / n2; + } else - n1 = n1 % n2; + { + if (n2 == 0) /* give an error message? */ + n1 = 0; + else + n1 = n1 % n2; + } + rettv->v_type = VAR_NUMBER; + rettv->vval.v_number = n1; } - rettv->v_type = VAR_NUMBER; - rettv->vval.v_number = n1; } } @@ -4566,7 +4798,6 @@ eval7(arg, rettv, evaluate) long n; int len; char_u *s; - int val; char_u *start_leader, *end_leader; int ret = OK; char_u *alias; @@ -4600,14 +4831,55 @@ eval7(arg, rettv, evaluate) case '7': case '8': case '9': - vim_str2nr(*arg, NULL, &len, TRUE, TRUE, &n, NULL); - *arg += len; - if (evaluate) + { +#ifdef FEAT_FLOAT + char_u *p = skipdigits(*arg + 1); + int get_float = FALSE; + + /* We accept a float when the format matches + * "[0-9]\+\.[0-9]\+\([eE][+-]\?[0-9]\+\)\?". This is very + * strict to avoid backwards compatibility problems. */ + if (p[0] == '.' && vim_isdigit(p[1])) { - rettv->v_type = VAR_NUMBER; - rettv->vval.v_number = n; + get_float = TRUE; + p = skipdigits(p + 2); + if (*p == 'e' || *p == 'E') + { + ++p; + if (*p == '-' || *p == '+') + ++p; + if (!vim_isdigit(*p)) + get_float = FALSE; + else + p = skipdigits(p + 1); + } + if (ASCII_ISALPHA(*p) || *p == '.') + get_float = FALSE; + } + if (get_float) + { + float_T f; + + *arg += string2float(*arg, &f); + if (evaluate) + { + rettv->v_type = VAR_FLOAT; + rettv->vval.v_float = f; + } + } + else +#endif + { + vim_str2nr(*arg, NULL, &len, TRUE, TRUE, &n, NULL); + *arg += len; + if (evaluate) + { + rettv->v_type = VAR_NUMBER; + rettv->vval.v_number = n; + } } break; + } /* * String constant: "string". @@ -4735,8 +5007,15 @@ eval7(arg, rettv, evaluate) if (ret == OK && evaluate && end_leader > start_leader) { int error = FALSE; + int val = 0; +#ifdef FEAT_FLOAT + float_T f = 0.0; - val = get_tv_number_chk(rettv, &error); + if (rettv->v_type == VAR_FLOAT) + f = rettv->vval.v_float; + else +#endif + val = get_tv_number_chk(rettv, &error); if (error) { clear_tv(rettv); @@ -4748,13 +5027,37 @@ eval7(arg, rettv, evaluate) { --end_leader; if (*end_leader == '!') - val = !val; + { +#ifdef FEAT_FLOAT + if (rettv->v_type == VAR_FLOAT) + f = !f; + else +#endif + val = !val; + } else if (*end_leader == '-') - val = -val; + { +#ifdef FEAT_FLOAT + if (rettv->v_type == VAR_FLOAT) + f = -f; + else +#endif + val = -val; + } + } +#ifdef FEAT_FLOAT + if (rettv->v_type == VAR_FLOAT) + { + clear_tv(rettv); + rettv->vval.v_float = f; + } + else +#endif + { + clear_tv(rettv); + rettv->v_type = VAR_NUMBER; + rettv->vval.v_number = val; } - clear_tv(rettv); - rettv->v_type = VAR_NUMBER; - rettv->vval.v_number = val; } } @@ -4781,7 +5084,11 @@ eval_index(arg, rettv, evaluate, verbose) char_u *s; char_u *key = NULL; - if (rettv->v_type == VAR_FUNC) + if (rettv->v_type == VAR_FUNC +#ifdef FEAT_FLOAT + || rettv->v_type == VAR_FLOAT +#endif + ) { if (verbose) EMSG(_("E695: Cannot index a Funcref")); @@ -5567,7 +5874,7 @@ dict_equal(d1, d2, ic) /* * Return TRUE if "tv1" and "tv2" have the same value. * Compares the items just like "==" would compare them, but strings and - * numbers are different. + * numbers are different. Floats and numbers are also different. */ static int tv_equal(tv1, tv2, ic) @@ -5609,6 +5916,11 @@ tv_equal(tv1, tv2, ic) case VAR_NUMBER: return tv1->vval.v_number == tv2->vval.v_number; +#ifdef FEAT_FLOAT + case VAR_FLOAT: + return tv1->vval.v_float == tv2->vval.v_float; +#endif + case VAR_STRING: s1 = get_tv_string_buf(tv1, buf1); s2 = get_tv_string_buf(tv2, buf2); @@ -6898,6 +7210,14 @@ echo_string(tv, tofree, numbuf, copyID) r = get_tv_string_buf(tv, numbuf); break; +#ifdef FEAT_FLOAT + case VAR_FLOAT: + *tofree = NULL; + vim_snprintf((char *)numbuf, NUMBUFLEN, "%g", tv->vval.v_float); + r = numbuf; + break; +#endif + default: EMSG2(_(e_intern2), "echo_string()"); *tofree = NULL; @@ -6929,6 +7249,12 @@ tv2string(tv, tofree, numbuf, copyID) case VAR_STRING: *tofree = string_quote(tv->vval.v_string, FALSE); return *tofree; +#ifdef FEAT_FLOAT + case VAR_FLOAT: + *tofree = NULL; + vim_snprintf((char *)numbuf, NUMBUFLEN - 1, "%g", tv->vval.v_float); + return numbuf; +#endif case VAR_NUMBER: case VAR_LIST: case VAR_DICT: @@ -6985,6 +7311,27 @@ string_quote(str, function) return s; } +#ifdef FEAT_FLOAT +/* + * Convert the string "text" to a floating point number. + * This uses strtod(). setlocale(LC_NUMERIC, "C") has been used to make sure + * this always uses a decimal point. + * Returns the length of the text that was consumed. + */ + static int +string2float(text, value) + char_u *text; + float_T *value; /* result stored here */ +{ + char *s = (char *)text; + float_T f; + + f = strtod(s, &s); + *value = f; + return (int)((char_u *)s - text); +} +#endif + /* * Get the value of an environment variable. * "arg" is pointing to the '$'. It is advanced to after the name. @@ -7054,11 +7401,17 @@ static struct fst /* implementation of function */ } functions[] = { +#ifdef FEAT_FLOAT + {"abs", 1, 1, f_abs}, +#endif {"add", 2, 2, f_add}, {"append", 2, 2, f_append}, {"argc", 0, 0, f_argc}, {"argidx", 0, 0, f_argidx}, {"argv", 0, 1, f_argv}, +#ifdef FEAT_FLOAT + {"atan", 1, 1, f_atan}, +#endif {"browse", 4, 4, f_browse}, {"browsedir", 2, 2, f_browsedir}, {"bufexists", 1, 1, f_bufexists}, @@ -7073,6 +7426,9 @@ static struct fst {"byte2line", 1, 1, f_byte2line}, {"byteidx", 2, 2, f_byteidx}, {"call", 2, 3, f_call}, +#ifdef FEAT_FLOAT + {"ceil", 1, 1, f_ceil}, +#endif {"changenr", 0, 0, f_changenr}, {"char2nr", 1, 1, f_char2nr}, {"cindent", 1, 1, f_cindent}, @@ -7085,6 +7441,9 @@ static struct fst #endif {"confirm", 1, 4, f_confirm}, {"copy", 1, 1, f_copy}, +#ifdef FEAT_FLOAT + {"cos", 1, 1, f_cos}, +#endif {"count", 2, 4, f_count}, {"cscope_connection",0,3, f_cscope_connection}, {"cursor", 1, 3, f_cursor}, @@ -7108,6 +7467,10 @@ static struct fst {"filter", 2, 2, f_filter}, {"finddir", 1, 3, f_finddir}, {"findfile", 1, 3, f_findfile}, +#ifdef FEAT_FLOAT + {"float2nr", 1, 1, f_float2nr}, + {"floor", 1, 1, f_floor}, +#endif {"fnameescape", 1, 1, f_fnameescape}, {"fnamemodify", 2, 2, f_fnamemodify}, {"foldclosed", 1, 1, f_foldclosed}, @@ -7182,6 +7545,9 @@ static struct fst {"line2byte", 1, 1, f_line2byte}, {"lispindent", 1, 1, f_lispindent}, {"localtime", 0, 0, f_localtime}, +#ifdef FEAT_FLOAT + {"log10", 1, 1, f_log10}, +#endif {"map", 2, 2, f_map}, {"maparg", 1, 3, f_maparg}, {"mapcheck", 1, 3, f_mapcheck}, @@ -7197,10 +7563,13 @@ static struct fst #ifdef vim_mkdir {"mkdir", 1, 3, f_mkdir}, #endif - {"mode", 0, 0, f_mode}, + {"mode", 0, 1, f_mode}, {"nextnonblank", 1, 1, f_nextnonblank}, {"nr2char", 1, 1, f_nr2char}, {"pathshorten", 1, 1, f_pathshorten}, +#ifdef FEAT_FLOAT + {"pow", 2, 2, f_pow}, +#endif {"prevnonblank", 1, 1, f_prevnonblank}, {"printf", 2, 19, f_printf}, {"pumvisible", 0, 0, f_pumvisible}, @@ -7218,6 +7587,9 @@ static struct fst {"repeat", 2, 2, f_repeat}, {"resolve", 1, 1, f_resolve}, {"reverse", 1, 1, f_reverse}, +#ifdef FEAT_FLOAT + {"round", 1, 1, f_round}, +#endif {"search", 1, 4, f_search}, {"searchdecl", 1, 3, f_searchdecl}, {"searchpair", 3, 7, f_searchpair}, @@ -7237,11 +7609,18 @@ static struct fst {"setwinvar", 3, 3, f_setwinvar}, {"shellescape", 1, 1, f_shellescape}, {"simplify", 1, 1, f_simplify}, +#ifdef FEAT_FLOAT + {"sin", 1, 1, f_sin}, +#endif {"sort", 1, 2, f_sort}, {"soundfold", 1, 1, f_soundfold}, {"spellbadword", 0, 1, f_spellbadword}, {"spellsuggest", 1, 3, f_spellsuggest}, {"split", 1, 3, f_split}, +#ifdef FEAT_FLOAT + {"sqrt", 1, 1, f_sqrt}, + {"str2float", 1, 1, f_str2float}, +#endif {"str2nr", 1, 2, f_str2nr}, #ifdef HAVE_STRFTIME {"strftime", 1, 2, f_strftime}, @@ -7269,6 +7648,9 @@ static struct fst {"tolower", 1, 1, f_tolower}, {"toupper", 1, 1, f_toupper}, {"tr", 3, 3, f_tr}, +#ifdef FEAT_FLOAT + {"trunc", 1, 1, f_trunc}, +#endif {"type", 1, 1, f_type}, {"values", 1, 1, f_values}, {"virtcol", 1, 1, f_virtcol}, @@ -7712,6 +8094,36 @@ emsg_funcname(ermsg, name) * Implementation of the built-in functions */ +#ifdef FEAT_FLOAT +/* + * "abs(expr)" function + */ + static void +f_abs(argvars, rettv) + typval_T *argvars; + typval_T *rettv; +{ + if (argvars[0].v_type == VAR_FLOAT) + { + rettv->v_type = VAR_FLOAT; + rettv->vval.v_float = fabs(argvars[0].vval.v_float); + } + else + { + varnumber_T n; + int error = FALSE; + + n = get_tv_number_chk(&argvars[0], &error); + if (error) + rettv->vval.v_number = -1; + else if (n > 0) + rettv->vval.v_number = n; + else + rettv->vval.v_number = -n; + } +} +#endif + /* * "add(list, item)" function */ @@ -7840,6 +8252,50 @@ f_argv(argvars, rettv) alist_name(&ARGLIST[idx]), -1); } +#ifdef FEAT_FLOAT +static int get_float_arg __ARGS((typval_T *argvars, float_T *f)); + +/* + * Get the float value of "argvars[0]" into "f". + * Returns FAIL when the argument is not a Number or Float. + */ + static int +get_float_arg(argvars, f) + typval_T *argvars; + float_T *f; +{ + if (argvars[0].v_type == VAR_FLOAT) + { + *f = argvars[0].vval.v_float; + return OK; + } + if (argvars[0].v_type == VAR_NUMBER) + { + *f = (float_T)argvars[0].vval.v_number; + return OK; + } + EMSG(_("E808: Number or Float required")); + return FAIL; +} + +/* + * "atan()" function + */ + static void +f_atan(argvars, rettv) + typval_T *argvars; + typval_T *rettv; +{ + float_T f; + + rettv->v_type = VAR_FLOAT; + if (get_float_arg(argvars, &f) == OK) + rettv->vval.v_float = atan(f); + else + rettv->vval.v_float = 0.0; +} +#endif + /* * "browse(save, title, initdir, default)" function */ @@ -8157,7 +8613,7 @@ f_byteidx(argvars, rettv) } rettv->vval.v_number = (varnumber_T)(t - str); #else - if (idx <= STRLEN(str)) + if ((size_t)idx <= STRLEN(str)) rettv->vval.v_number = idx; #endif } @@ -8227,6 +8683,25 @@ f_call(argvars, rettv) clear_tv(&argv[--argc]); } +#ifdef FEAT_FLOAT +/* + * "ceil({float})" function + */ + static void +f_ceil(argvars, rettv) + typval_T *argvars; + typval_T *rettv; +{ + float_T f; + + rettv->v_type = VAR_FLOAT; + if (get_float_arg(argvars, &f) == OK) + rettv->vval.v_float = ceil(f); + else + rettv->vval.v_float = 0.0; +} +#endif + /* * "changenr()" function */ @@ -8487,6 +8962,25 @@ f_copy(argvars, rettv) item_copy(&argvars[0], rettv, FALSE, 0); } +#ifdef FEAT_FLOAT +/* + * "cos()" function + */ + static void +f_cos(argvars, rettv) + typval_T *argvars; + typval_T *rettv; +{ + float_T f; + + rettv->v_type = VAR_FLOAT; + if (get_float_arg(argvars, &f) == OK) + rettv->vval.v_float = cos(f); + else + rettv->vval.v_float = 0.0; +} +#endif + /* * "count()" function */ @@ -8802,6 +9296,11 @@ f_empty(argvars, rettv) case VAR_NUMBER: n = argvars[0].vval.v_number == 0; break; +#ifdef FEAT_FLOAT + case VAR_FLOAT: + n = argvars[0].vval.v_float == 0.0; + break; +#endif case VAR_LIST: n = argvars[0].vval.v_list == NULL || argvars[0].vval.v_list->lv_first == NULL; @@ -9466,6 +9965,48 @@ f_findfile(argvars, rettv) findfilendir(argvars, rettv, FINDFILE_FILE); } +#ifdef FEAT_FLOAT +/* + * "float2nr({float})" function + */ + static void +f_float2nr(argvars, rettv) + typval_T *argvars; + typval_T *rettv; +{ + float_T f; + + if (get_float_arg(argvars, &f) == OK) + { + if (f < -0x7fffffff) + rettv->vval.v_number = -0x7fffffff; + else if (f > 0x7fffffff) + rettv->vval.v_number = 0x7fffffff; + else + rettv->vval.v_number = (varnumber_T)f; + } + else + rettv->vval.v_number = 0; +} + +/* + * "floor({float})" function + */ + static void +f_floor(argvars, rettv) + typval_T *argvars; + typval_T *rettv; +{ + float_T f; + + rettv->v_type = VAR_FLOAT; + if (get_float_arg(argvars, &f) == OK) + rettv->vval.v_float = floor(f); + else + rettv->vval.v_float = 0.0; +} +#endif + /* * "fnameescape({string})" function */ @@ -10600,7 +11141,7 @@ f_getwinposy(argvars, rettv) } /* - * Find window specifed by "vp" in tabpage "tp". + * Find window specified by "vp" in tabpage "tp". */ static win_T * find_win_by_nr(vp, tp) @@ -10892,6 +11433,9 @@ f_has(argvars, rettv) #ifdef FEAT_FIND_ID "find_in_path", #endif +#ifdef FEAT_FLOAT + "float", +#endif #ifdef FEAT_FOLDING "folding", #endif @@ -11002,6 +11546,9 @@ f_has(argvars, rettv) # ifdef FEAT_MOUSE_PTERM "mouse_pterm", # endif +# ifdef FEAT_SYSMOUSE + "mouse_sysmouse", +# endif # ifdef FEAT_MOUSE_XTERM "mouse_xterm", # endif @@ -11813,7 +12360,7 @@ f_inputsave(argvars, rettv) typval_T *argvars; typval_T *rettv; { - /* Add an entry to the stack of typehead storage. */ + /* Add an entry to the stack of typeahead storage. */ if (ga_grow(&ga_userinput, 1) == OK) { save_typeahead((tasave_T *)(ga_userinput.ga_data) @@ -12345,6 +12892,25 @@ get_maparg(argvars, rettv, exact) |