]> granicus.if.org Git - vim/commitdiff
patch 8.2.0675: Vim9: no support for closures v8.2.0675
authorBram Moolenaar <Bram@vim.org>
Fri, 1 May 2020 13:44:29 +0000 (15:44 +0200)
committerBram Moolenaar <Bram@vim.org>
Fri, 1 May 2020 13:44:29 +0000 (15:44 +0200)
Problem:    Vim9: no support for closures.
Solution:   Do not re-use stack entries.

src/evalvars.c
src/ex_docmd.c
src/proto/evalvars.pro
src/proto/ex_docmd.pro
src/version.c
src/vim9compile.c

index f6f077983b3c1df166adff4927b537e239a469dd..08b2990bcc7077f69a7298525a2988262eb4a5a6 100644 (file)
@@ -2495,19 +2495,19 @@ get_script_local_ht(void)
 
 /*
  * Look for "name[len]" in script-local variables.
- * Return -1 when not found.
+ * Return a non-NULL pointer when found, NULL when not found.
  */
-    int
+    void *
 lookup_scriptvar(char_u *name, size_t len, cctx_T *dummy UNUSED)
 {
     hashtab_T  *ht = get_script_local_ht();
     char_u     buffer[30];
     char_u     *p;
-    int                res;
+    void       *res;
     hashitem_T *hi;
 
     if (ht == NULL)
-       return -1;
+       return NULL;
     if (len < sizeof(buffer) - 1)
     {
        vim_strncpy(buffer, name, len);
@@ -2517,15 +2517,15 @@ lookup_scriptvar(char_u *name, size_t len, cctx_T *dummy UNUSED)
     {
        p = vim_strnsave(name, (int)len);
        if (p == NULL)
-           return -1;
+           return NULL;
     }
 
     hi = hash_find(ht, p);
-    res = HASHITEM_EMPTY(hi) ? -1 : 1;
+    res = HASHITEM_EMPTY(hi) ? NULL : hi;
 
     // if not script-local, then perhaps imported
-    if (res == -1 && find_imported(p, 0, NULL) != NULL)
-       res = 1;
+    if (res == NULL && find_imported(p, 0, NULL) != NULL)
+       res = p;
 
     if (p != buffer)
        vim_free(p);
index 65ef936e9f26b5977bf1d2589ae196ae01eb9181..94a3367a3af459c9fb745e41eadce07d386f31a8 100644 (file)
@@ -3157,7 +3157,7 @@ append_command(char_u *cmd)
 find_ex_command(
        exarg_T *eap,
        int     *full UNUSED,
-       int     (*lookup)(char_u *, size_t, cctx_T *) UNUSED,
+       void    *(*lookup)(char_u *, size_t, cctx_T *) UNUSED,
        cctx_T  *cctx UNUSED)
 {
     int                len;
@@ -3197,7 +3197,7 @@ find_ex_command(
            // "g:var = expr"
            // "var = expr"  where "var" is a local var name.
            if (((p - eap->cmd) > 2 && eap->cmd[1] == ':')
-                   || lookup(eap->cmd, p - eap->cmd, cctx) >= 0)
+                   || lookup(eap->cmd, p - eap->cmd, cctx) != NULL)
            {
                eap->cmdidx = CMD_let;
                return eap->cmd;
index e4159328dc16a6791c23f22465120ba1022a84b4..58e922113e79b6068f4c6c1e54678dfb04dc8721 100644 (file)
@@ -55,7 +55,7 @@ int get_var_tv(char_u *name, int len, typval_T *rettv, dictitem_T **dip, int ver
 void check_vars(char_u *name, int len);
 dictitem_T *find_var(char_u *name, hashtab_T **htp, int no_autoload);
 dictitem_T *find_var_in_ht(hashtab_T *ht, int htname, char_u *varname, int no_autoload);
-int lookup_scriptvar(char_u *name, size_t len, cctx_T *dummy);
+void *lookup_scriptvar(char_u *name, size_t len, cctx_T *dummy);
 hashtab_T *find_var_ht(char_u *name, char_u **varname);
 char_u *get_var_value(char_u *name);
 void new_script_vars(scid_T id);
index eba5ee4973e799e17e786f92ecb2ba607db99b04..7f5c691282267d2fc151a5b201f3d16fac208015 100644 (file)
@@ -7,7 +7,7 @@ void *getline_cookie(char_u *(*fgetline)(int, void *, int, int), void *cookie);
 int parse_command_modifiers(exarg_T *eap, char **errormsg, int skip_only);
 int parse_cmd_address(exarg_T *eap, char **errormsg, int silent);
 int checkforcmd(char_u **pp, char *cmd, int len);
-char_u *find_ex_command(exarg_T *eap, int *full, int (*lookup)(char_u *, size_t, cctx_T *), cctx_T *cctx);
+char_u *find_ex_command(exarg_T *eap, int *full, void *((*lookup)(char_u *, size_t, cctx_T *)), cctx_T *cctx);
 int modifier_len(char_u *cmd);
 int cmd_exists(char_u *name);
 cmdidx_T excmd_get_cmdidx(char_u *cmd, int len);
@@ -19,7 +19,7 @@ void separate_nextcmd(exarg_T *eap);
 char_u *skip_cmd_arg(char_u *p, int rembs);
 int get_bad_opt(char_u *p, exarg_T *eap);
 int ends_excmd(int c);
-int ends_excmd2(char_u *before, char_u *cmd);
+int ends_excmd2(char_u *cmd_start, char_u *cmd);
 char_u *find_nextcmd(char_u *p);
 char_u *check_nextcmd(char_u *p);
 char_u *get_command_name(expand_T *xp, int idx);
index 35037f8b2a8985633319f3e56f47bcaa152e3b49..965718551630baff9d4f71189254662002ae29a7 100644 (file)
@@ -746,6 +746,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    675,
 /**/
     674,
 /**/
index 7b433a3b158dc12dbce95dc33ede0b9cbc702339..c3f3bfdfbc883d8b58582667168b5b8f7b3cbc2d 100644 (file)
@@ -97,6 +97,7 @@ struct scope_S {
 typedef struct {
     char_u     *lv_name;
     type_T     *lv_type;
+    int                lv_idx;     // index of the variable on the stack
     int                lv_const;   // when TRUE cannot be assigned to
     int                lv_arg;     // when TRUE this is an argument
 } lvar_T;
@@ -112,7 +113,7 @@ struct cctx_S {
     garray_T   ctx_instr;          // generated instructions
 
     garray_T   ctx_locals;         // currently visible local variables
-    int                ctx_max_local;      // maximum number of locals at one time
+    int                ctx_locals_count;   // total number of local variables
 
     garray_T   ctx_imports;        // imported items
 
@@ -120,6 +121,9 @@ struct cctx_S {
                                    // commands after "else"
     scope_T    *ctx_scope;         // current scope, NULL at toplevel
 
+    cctx_T     *ctx_outer;         // outer scope for lambda or nested
+                                   // function
+
     garray_T   ctx_type_stack;     // type of each item on the stack
     garray_T   *ctx_type_list;     // list of pointers to allocated types
 };
@@ -135,24 +139,25 @@ static void arg_type_mismatch(type_T *expected, type_T *actual, int argidx);
 static int check_type(type_T *expected, type_T *actual, int give_msg);
 
 /*
- * Lookup variable "name" in the local scope and return the index.
+ * Lookup variable "name" in the local scope and return it.
+ * Return NULL if not found.
  */
-    static int
+    static lvar_T *
 lookup_local(char_u *name, size_t len, cctx_T *cctx)
 {
     int            idx;
 
     if (len == 0)
-       return -1;
+       return NULL;
     for (idx = 0; idx < cctx->ctx_locals.ga_len; ++idx)
     {
        lvar_T *lvar = ((lvar_T *)cctx->ctx_locals.ga_data) + idx;
 
        if (STRNCMP(name, lvar->lv_name, len) == 0
                                               && STRLEN(lvar->lv_name) == len)
-           return idx;
+           return lvar;
     }
-    return -1;
+    return NULL;
 }
 
 /*
@@ -217,7 +222,7 @@ check_defined(char_u *p, int len, cctx_T *cctx)
 {
     if (lookup_script(p, len) == OK
            || (cctx != NULL
-               && (lookup_local(p, len, cctx) >= 0
+               && (lookup_local(p, len, cctx) != NULL
                    || find_imported(p, len, cctx) != NULL)))
     {
        semsg("E1073: imported name already defined: %s", p);
@@ -1458,33 +1463,34 @@ generate_EXECCONCAT(cctx_T *cctx, int count)
 
 /*
  * Reserve space for a local variable.
- * Return the index or -1 if it failed.
+ * Return the variable or NULL if it failed.
  */
-    static int
+    static lvar_T *
 reserve_local(cctx_T *cctx, char_u *name, size_t len, int isConst, type_T *type)
 {
-    int            idx;
     lvar_T  *lvar;
 
     if (lookup_arg(name, len, cctx) >= 0 || lookup_vararg(name, len, cctx))
     {
        emsg_namelen(_("E1006: %s is used as an argument"), name, (int)len);
-       return -1;
+       return NULL;
     }
 
     if (ga_grow(&cctx->ctx_locals, 1) == FAIL)
-       return -1;
-    idx = cctx->ctx_locals.ga_len;
-    if (cctx->ctx_max_local < idx + 1)
-       cctx->ctx_max_local = idx + 1;
-    ++cctx->ctx_locals.ga_len;
+       return NULL;
+    lvar = ((lvar_T *)cctx->ctx_locals.ga_data) + cctx->ctx_locals.ga_len++;
+
+    // Every local variable uses the next entry on the stack.  We could re-use
+    // the last ones when leaving a scope, but then variables used in a closure
+    // might get overwritten.  To keep things simple do not re-use stack
+    // entries.  This is less efficient, but memory is cheap these days.
+    lvar->lv_idx = cctx->ctx_locals_count++;
 
-    lvar = ((lvar_T *)cctx->ctx_locals.ga_data) + idx;
     lvar->lv_name = vim_strnsave(name, (int)(len == 0 ? STRLEN(name) : len));
     lvar->lv_const = isConst;
     lvar->lv_type = type;
 
-    return idx;
+    return lvar;
 }
 
 /*
@@ -1511,7 +1517,7 @@ unwind_locals(cctx_T *cctx, int new_top)
  * Free all local variables.
  */
     static void
-free_local(cctx_T *cctx)
+free_locals(cctx_T *cctx)
 {
     unwind_locals(cctx, 0);
     ga_clear(&cctx->ctx_locals);
@@ -2331,10 +2337,12 @@ compile_load(char_u **arg, char_u *end_arg, cctx_T *cctx, int error)
        }
        else
        {
-           idx = lookup_local(*arg, len, cctx);
-           if (idx >= 0)
+           lvar_T *lvar = lookup_local(*arg, len, cctx);
+
+           if (lvar != NULL)
            {
-               type = (((lvar_T *)cctx->ctx_locals.ga_data) + idx)->lv_type;
+               type = lvar->lv_type;
+               idx = lvar->lv_idx;
                gen_load = TRUE;
            }
            else
@@ -4040,7 +4048,6 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx)
     int                semicolon = 0;
     size_t     varlen;
     garray_T   *instr = &cctx->ctx_instr;
-    int                idx = -1;
     int                new_local = FALSE;
     char_u     *op;
     int                opt_type;
@@ -4050,7 +4057,7 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx)
     int                oplen = 0;
     int                heredoc = FALSE;
     type_T     *type = &t_any;
-    lvar_T     *lvar;
+    lvar_T     *lvar = NULL;
     char_u     *name;
     char_u     *sp;
     int                has_type = FALSE;
@@ -4203,6 +4210,8 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx)
        }
        else
        {
+           int idx;
+
            for (idx = 0; reserved[idx] != NULL; ++idx)
                if (STRCMP(reserved[idx], name) == 0)
                {
@@ -4210,8 +4219,8 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx)
                    goto theend;
                }
 
-           idx = lookup_local(arg, varlen, cctx);
-           if (idx >= 0)
+           lvar = lookup_local(arg, varlen, cctx);
+           if (lvar != NULL)
            {
                if (is_decl)
                {
@@ -4220,10 +4229,10 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx)
                }
                else
                {
-                   lvar = ((lvar_T *)cctx->ctx_locals.ga_data) + idx;
                    if (lvar->lv_const)
                    {
-                       semsg(_("E1018: Cannot assign to a constant: %s"), name);
+                       semsg(_("E1018: Cannot assign to a constant: %s"),
+                                                                        name);
                        goto theend;
                    }
                }
@@ -4262,11 +4271,8 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx)
            type = parse_type(&p, cctx->ctx_type_list);
            has_type = TRUE;
        }
-       else if (idx >= 0)
-       {
-           lvar = ((lvar_T *)cctx->ctx_locals.ga_data) + idx;
+       else if (lvar != NULL)
            type = lvar->lv_type;
-       }
     }
 
     sp = p;
@@ -4288,7 +4294,7 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx)
        goto theend;
     }
 
-    if (idx < 0 && dest == dest_local && cctx->ctx_skip != TRUE)
+    if (lvar == NULL && dest == dest_local && cctx->ctx_skip != TRUE)
     {
        if (oplen > 1 && !heredoc)
        {
@@ -4301,8 +4307,8 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx)
        // new local variable
        if (type->tt_type == VAR_FUNC && var_check_func_name(name, TRUE))
            goto theend;
-       idx = reserve_local(cctx, arg, varlen, cmdidx == CMD_const, type);
-       if (idx < 0)
+       lvar = reserve_local(cctx, arg, varlen, cmdidx == CMD_const, type);
+       if (lvar == NULL)
            goto theend;
        new_local = TRUE;
     }
@@ -4370,7 +4376,7 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx)
                    generate_LOADV(cctx, name + 2, TRUE);
                    break;
                case dest_local:
-                   generate_LOAD(cctx, ISN_LOAD, idx, NULL, type);
+                   generate_LOAD(cctx, ISN_LOAD, lvar->lv_idx, NULL, type);
                    break;
            }
        }
@@ -4392,9 +4398,8 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx)
            stack = &cctx->ctx_type_stack;
            stacktype = stack->ga_len == 0 ? &t_void
                              : ((type_T **)stack->ga_data)[stack->ga_len - 1];
-           if (idx >= 0 && (is_decl || !has_type))
+           if (lvar != NULL && (is_decl || !has_type))
            {
-               lvar = ((lvar_T *)cctx->ctx_locals.ga_data) + idx;
                if (new_local && !has_type)
                {
                    if (stacktype->tt_type == VAR_VOID)
@@ -4546,6 +4551,7 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx)
                char_u      *rawname = name + (name[1] == ':' ? 2 : 0);
                imported_T  *import = NULL;
                int         sid = current_sctx.sc_sid;
+               int         idx;
 
                if (name[1] != ':')
                {
@@ -4581,6 +4587,7 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx)
            }
            break;
        case dest_local:
+           if (lvar != NULL)
            {
                isn_T *isn = ((isn_T *)instr->ga_data) + instr->ga_len - 1;
 
@@ -4593,13 +4600,13 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx)
                    garray_T    *stack = &cctx->ctx_type_stack;
 
                    isn->isn_type = ISN_STORENR;
-                   isn->isn_arg.storenr.stnr_idx = idx;
+                   isn->isn_arg.storenr.stnr_idx = lvar->lv_idx;
                    isn->isn_arg.storenr.stnr_val = val;
                    if (stack->ga_len > 0)
                        --stack->ga_len;
                }
                else
-                   generate_STORE(cctx, ISN_STORE, idx, NULL);
+                   generate_STORE(cctx, ISN_STORE, lvar->lv_idx, NULL);
            }
            break;
     }
@@ -5283,8 +5290,8 @@ compile_for(char_u *arg, cctx_T *cctx)
     garray_T   *instr = &cctx->ctx_instr;
     garray_T   *stack = &cctx->ctx_type_stack;
     scope_T    *scope;
-    int                loop_idx;       // index of loop iteration variable
-    int                var_idx;        // index of "var"
+    lvar_T     *loop_lvar;     // loop iteration variable
+    lvar_T     *var_lvar;      // variable for "var"
     type_T     *vartype;
 
     // TODO: list of variables: "for [key, value] in dict"
@@ -5292,8 +5299,8 @@ compile_for(char_u *arg, cctx_T *cctx)
     for (p = arg; eval_isnamec1(*p); ++p)
        ;
     varlen = p - arg;
-    var_idx = lookup_local(arg, varlen, cctx);
-    if (var_idx >= 0)
+    var_lvar = lookup_local(arg, varlen, cctx);
+    if (var_lvar != NULL)
     {
        semsg(_("E1023: variable already defined: %s"), arg);
        return NULL;
@@ -5314,23 +5321,24 @@ compile_for(char_u *arg, cctx_T *cctx)
        return NULL;
 
     // Reserve a variable to store the loop iteration counter.
-    loop_idx = reserve_local(cctx, (char_u *)"", 0, FALSE, &t_number);
-    if (loop_idx < 0)
+    loop_lvar = reserve_local(cctx, (char_u *)"", 0, FALSE, &t_number);
+    if (loop_lvar == NULL)
     {
-       // only happens when out of memory
+       // out of memory
        drop_scope(cctx);
        return NULL;
     }
 
     // Reserve a variable to store "var"
-    var_idx = reserve_local(cctx, arg, varlen, FALSE, &t_any);
-    if (var_idx < 0)
+    var_lvar = reserve_local(cctx, arg, varlen, FALSE, &t_any);
+    if (var_lvar == NULL)
     {
+       // out of memory or used as an argument
        drop_scope(cctx);
        return NULL;
     }
 
-    generate_STORENR(cctx, loop_idx, -1);
+    generate_STORENR(cctx, loop_lvar->lv_idx, -1);
 
     // compile "expr", it remains on the stack until "endfor"
     arg = p;
@@ -5349,17 +5357,13 @@ compile_for(char_u *arg, cctx_T *cctx)
        return NULL;
     }
     if (vartype->tt_member->tt_type != VAR_ANY)
-    {
-       lvar_T *lvar = ((lvar_T *)cctx->ctx_locals.ga_data) + var_idx;
-
-       lvar->lv_type = vartype->tt_member;
-    }
+       var_lvar->lv_type = vartype->tt_member;
 
     // "for_end" is set when ":endfor" is found
     scope->se_u.se_for.fs_top_label = instr->ga_len;
 
-    generate_FOR(cctx, loop_idx);
-    generate_STORE(cctx, ISN_STORE, var_idx, NULL);
+    generate_FOR(cctx, loop_lvar->lv_idx);
+    generate_STORE(cctx, ISN_STORE, var_lvar->lv_idx, NULL);
 
     return arg;
 }
@@ -6158,7 +6162,7 @@ compile_def_function(ufunc_T *ufunc, int set_return_type)
                            || *ea.cmd == '$'
                            || *ea.cmd == '@'
                            || ((p - ea.cmd) > 2 && ea.cmd[1] == ':')
-                           || lookup_local(ea.cmd, p - ea.cmd, &cctx) >= 0
+                           || lookup_local(ea.cmd, p - ea.cmd, &cctx) != NULL
                            || lookup_script(ea.cmd, p - ea.cmd) == OK
                            || find_imported(ea.cmd, p - ea.cmd, &cctx) != NULL)
                    {
@@ -6175,7 +6179,8 @@ compile_def_function(ufunc_T *ufunc, int set_return_type)
         * COMMAND after range
         */
        ea.cmd = skip_range(ea.cmd, NULL);
-       p = find_ex_command(&ea, NULL, is_ex_command ? NULL : lookup_local,
+       p = find_ex_command(&ea, NULL, is_ex_command ? NULL
+                  : (void *(*)(char_u *, size_t, cctx_T *))lookup_local,
                                                                        &cctx);
 
        if (p == ea.cmd && ea.cmdidx != CMD_SIZE)
@@ -6349,7 +6354,7 @@ compile_def_function(ufunc_T *ufunc, int set_return_type)
        dfunc->df_deleted = FALSE;
        dfunc->df_instr = instr->ga_data;
        dfunc->df_instr_count = instr->ga_len;
-       dfunc->df_varcount = cctx.ctx_max_local;
+       dfunc->df_varcount = cctx.ctx_locals_count;
     }
 
     {
@@ -6431,7 +6436,7 @@ erret:
 
     current_sctx = save_current_sctx;
     free_imported(&cctx);
-    free_local(&cctx);
+    free_locals(&cctx);
     ga_clear(&cctx.ctx_type_stack);
 }