Mercurial > vim
diff src/vim9compile.c @ 20279:49b50843e725 v8.2.0695
patch 8.2.0695: Vim9: cannot define a function inside a function
Commit: https://github.com/vim/vim/commit/04b12697838b232b8b17c553ccc74cf1f1bdb81c
Author: Bram Moolenaar <Bram@vim.org>
Date: Mon May 4 23:24:44 2020 +0200
patch 8.2.0695: Vim9: cannot define a function inside a function
Problem: Vim9: cannot define a function inside a function.
Solution: Initial support for :def inside :def.
author | Bram Moolenaar <Bram@vim.org> |
---|---|
date | Mon, 04 May 2020 23:30:04 +0200 |
parents | 350bb78345ba |
children | ab8c8fd0f868 |
line wrap: on
line diff
--- a/src/vim9compile.c +++ b/src/vim9compile.c @@ -101,6 +101,7 @@ typedef struct { int lv_from_outer; // when TRUE using ctx_outer scope int lv_const; // when TRUE cannot be assigned to int lv_arg; // when TRUE this is an argument + int lv_func_idx; // for nested function } lvar_T; /* @@ -2615,6 +2616,7 @@ compile_call(char_u **arg, size_t varlen int error = FCERR_NONE; ufunc_T *ufunc; int res = FAIL; + lvar_T *lvar; if (varlen >= sizeof(namebuf)) { @@ -2641,6 +2643,16 @@ compile_call(char_u **arg, size_t varlen goto theend; } + // Check if the name is a nested function. + lvar = lookup_local(namebuf, varlen, cctx); + if (lvar != NULL && lvar->lv_func_idx > 0) + { + dfunc_T *dfunc = ((dfunc_T *)def_functions.ga_data) + + lvar->lv_func_idx; + res = generate_CALL(cctx, dfunc->df_ufunc, argcount); + goto theend; + } + // If we can find the function by name generate the right call. ufunc = find_func(name, FALSE, cctx); if (ufunc != NULL) @@ -4049,6 +4061,64 @@ compile_return(char_u *arg, int set_retu } /* + * Get a line from the compilation context, compatible with exarg_T getline(). + * Return a pointer to the line in allocated memory. + * Return NULL for end-of-file or some error. + */ + static char_u * +exarg_getline( + int c UNUSED, + void *cookie, + int indent UNUSED, + int do_concat UNUSED) +{ + cctx_T *cctx = (cctx_T *)cookie; + + if (cctx->ctx_lnum == cctx->ctx_ufunc->uf_lines.ga_len) + { + iemsg("Heredoc got to end"); + return NULL; + } + ++cctx->ctx_lnum; + return vim_strsave(((char_u **)cctx->ctx_ufunc->uf_lines.ga_data) + [cctx->ctx_lnum]); +} + +/* + * Compile a nested :def command. + */ + static char_u * +compile_nested_function(exarg_T *eap, cctx_T *cctx) +{ + char_u *name_start = eap->arg; + char_u *name_end = to_name_end(eap->arg, FALSE); + char_u *name = get_lambda_name(); + lvar_T *lvar; + ufunc_T *ufunc; + + eap->arg = name_end; + eap->getline = exarg_getline; + eap->cookie = cctx; + eap->skip = cctx->ctx_skip == TRUE; + eap->forceit = FALSE; + ufunc = def_function(eap, name, cctx); + + if (ufunc == NULL) + return NULL; + + // Define a local variable for the function, but change the index to -1 to + // mark it as a function name. + lvar = reserve_local(cctx, name_start, name_end - name_start, + TRUE, &t_func_unknown); + lvar->lv_idx = 0; + ++cctx->ctx_locals_count; // doesn't count as a local variable + lvar->lv_func_idx = ufunc->uf_dfunc_idx; + + // TODO: warning for trailing? + return (char_u *)""; +} + +/* * Return the length of an assignment operator, or zero if there isn't one. */ int @@ -4077,30 +4147,6 @@ static char *reserved[] = { NULL }; -/* - * Get a line for "=<<". - * Return a pointer to the line in allocated memory. - * Return NULL for end-of-file or some error. - */ - static char_u * -heredoc_getline( - int c UNUSED, - void *cookie, - int indent UNUSED, - int do_concat UNUSED) -{ - cctx_T *cctx = (cctx_T *)cookie; - - if (cctx->ctx_lnum == cctx->ctx_ufunc->uf_lines.ga_len) - { - iemsg("Heredoc got to end"); - return NULL; - } - ++cctx->ctx_lnum; - return vim_strsave(((char_u **)cctx->ctx_ufunc->uf_lines.ga_data) - [cctx->ctx_lnum]); -} - typedef enum { dest_local, dest_option, @@ -4394,7 +4440,7 @@ compile_assignment(char_u *arg, exarg_T listitem_T *li; // [let] varname =<< [trim] {end} - eap->getline = heredoc_getline; + eap->getline = exarg_getline; eap->cookie = cctx; l = heredoc_get(eap, op + 3, FALSE); @@ -6299,9 +6345,12 @@ compile_def_function(ufunc_T *ufunc, int switch (ea.cmdidx) { case CMD_def: + ea.arg = p; + line = compile_nested_function(&ea, &cctx); + break; + case CMD_function: - // TODO: Nested function - emsg("Nested function not implemented yet"); + emsg(_("E1086: Cannot use :function inside :def")); goto erret; case CMD_return: