2016-07-19 22:30 GMT+03:00 Bram Moolenaar <[email protected]>:
>
> Nikolay Pavlov wrote:
>
>> One of the points of initial suggestion was that `submatch()` is too
>> long to type, `{m, c1, c2 -> c2 . c1 }` (pattern looks like `\(c1\)
>> \(c2\)`, `m='c1 c2'`) is easier. Using lambdas like this just avoids
>> escaping, though it alone already is a good improvement over current
>> \= syntax.
>
> Yeah, I was wondering if we can pass the list of submatches to the
> function.
>
>         substitute(text, '\<\k*\>', {m -> 'key-' . m[0]}, 'g')
>
> Currently it would be:
>
>         substitute(text, '\<\k*\>', {-> 'key-' . submatch(0)}, 'g'
>
> It does require that the function takes one argument, even when not
> using it:
>
>         substitute(text, '\<\k*\>', {m -> 'key-' . g:key}, 'g')

Actually, not. It is possible to determine how many arguments a
function accepts (also whether it accepts variable number, do not
repeat one of the Neovim bugs) and construct argument list
accordingly. Without this dealing with capturing groups may be tricky
(specifically I mean cases when there *is* capturing group, but it
matched nothing or it did not match: if I am not mistaking, regexp
engine does not report how many capturing groups there are in the
pattern).

Note: unless `text` could be a list `submatch()` is no longer needed
for substitute() with lambdas: the only feature lambdas do not provide
here is the second non-zero argument of submatch().

Probably, the easiest implementation would be something like below,
but it has one downside: it will allocate memory for all captured
groups and match, even if none are used (note: I have neither tested
nor compiled this, it just shows the idea).

diff -r 3fb3f944d642 src/evalfunc.c
--- a/src/evalfunc.c Вт июл 19 23:46:24 2016 +0300
+++ b/src/evalfunc.c Ср июл 20 00:07:20 2016 +0300
@@ -965,8 +965,10 @@ call_internal_func(
  char_u    *name,
  int    argcount,
  typval_T    *argvars,
- typval_T    *rettv)
-{
+ typval_T    *rettv,
+ int    allow_too_much_args)
+{
+    vartype_T saved_lastvartype;
     int i;

     i = find_internal_func(name);
@@ -975,7 +977,13 @@ call_internal_func(
     if (argcount < functions[i].f_min_argc)
  return ERROR_TOOFEW;
     if (argcount > functions[i].f_max_argc)
- return ERROR_TOOMANY;
+    {
+ if (allow_too_much_args)
+    argcount = functions[i].f_max_argc;
+ else
+    return ERROR_TOOMANY;
+    }
+    saved_lastvartype = argvars[argcount].v_type;
     argvars[argcount].v_type = VAR_UNKNOWN;
     functions[i].f_func(argvars, rettv);
     return ERROR_NONE;
diff -r 3fb3f944d642 src/proto/evalfunc.pro
--- a/src/proto/evalfunc.pro Вт июл 19 23:46:24 2016 +0300
+++ b/src/proto/evalfunc.pro Ср июл 20 00:07:20 2016 +0300
@@ -2,7 +2,7 @@
 char_u *get_function_name(expand_T *xp, int idx);
 char_u *get_expr_name(expand_T *xp, int idx);
 int find_internal_func(char_u *name);
-int call_internal_func(char_u *name, int argcount, typval_T *argvars,
typval_T *rettv);
+int call_internal_func(char_u *name, int argcount, typval_T *argvars,
typval_T *rettv, int allow_too_much_args);
 buf_T *buflist_find_by_name(char_u *name, int curtab_only);
 void execute_redir_str(char_u *value, int value_len);
 void mzscheme_call_vim(char_u *name, typval_T *args, typval_T *rettv);
diff -r 3fb3f944d642 src/regexp.c
--- a/src/regexp.c Вт июл 19 23:46:24 2016 +0300
+++ b/src/regexp.c Ср июл 20 00:07:20 2016 +0300
@@ -7427,10 +7427,11 @@ vim_regsub_both(

     if (expr != NULL)
     {
- typval_T argv[1];
+ typval_T argv[NSUBEXP + 2];
  int dummy;
  char_u buf[NUMBUFLEN];
  typval_T rettv;
+ int i;

  rettv.v_type = VAR_STRING;
  rettv.vval.v_string = NULL;
@@ -7438,19 +7439,30 @@ vim_regsub_both(
  {
     /* can't do this recursively */
  }
- else if (expr->v_type == VAR_FUNC)
+ else if (expr->v_type == VAR_PARTIAL
+ || expr->v_type == VAR_FUNC)
  {
-    s = expr->vval.v_string;
-    call_func(s, (int)STRLEN(s), &rettv, 0, argv,
-     0L, 0L, &dummy, TRUE, NULL, NULL);
- }
- else if (expr->v_type == VAR_PARTIAL)
- {
-    partial_T   *partial = expr->vval.v_partial;
-
-    s = partial->pt_name;
-    call_func(s, (int)STRLEN(s), &rettv, 0, argv,
+    partial_T   *partial = NULL;
+
+    if (expr->v_type == VAR_PARTIAL)
+    {
+ partial = expr->vval.v_partial;
+ s = partial->pt_name;
+    }
+    else
+ s = expr->vval.v_string;
+
+    argv[0].v_type = VAR_STRING;
+    argv[0].vval.v_string = reg_submatch(0);
+    for (i = 1; i <= NSUBEXP; i++)
+    {
+ argv[i].v_type = VAR_STRING;
+ argv[i].vval.v_string = reg_submatch(i);
+    }
+    call_func(s, (int)STRLEN(s), &rettv, -(NSUBEXP + 1), argv,
   0L, 0L, &dummy, TRUE, partial, NULL);
+    for (i = 0; i < NSUBEXP + 1; i++)
+ vim_free(argv[i].vval.v_string);
  }
  eval_result = get_tv_string_buf_chk(&rettv, buf);
  if (eval_result != NULL)
diff -r 3fb3f944d642 src/userfunc.c
--- a/src/userfunc.c Вт июл 19 23:46:24 2016 +0300
+++ b/src/userfunc.c Ср июл 20 00:07:20 2016 +0300
@@ -1147,6 +1147,9 @@ func_call(
  * Call a function with its resolved parameters
  * Return FAIL when the function can't be called,  OK otherwise.
  * Also returns OK when an error was encountered while executing the function.
+ *
+ * If argcount_in is -N then it calls function with 0..N arguments,
depending on
+ * how much arguments it can accept.
  */
     int
 call_func(
@@ -1171,7 +1174,8 @@ call_func(
     char_u *tofree = NULL;
     char_u *fname;
     char_u *name;
-    int argcount = argcount_in;
+    int allow_too_much_args = (argcount_in < 0);
+    int argcount = argcount_in < 0 ? -argcount_in : argcount_in;
     typval_T *argvars = argvars_in;
     dict_T *selfdict = selfdict_in;
     typval_T argv[MAX_FUNC_ARGS + 1]; /* used when "partial" is not NULL */
@@ -1251,7 +1255,8 @@ call_func(
     *doesrange = TRUE;
  if (argcount < fp->uf_args.ga_len)
     error = ERROR_TOOFEW;
- else if (!fp->uf_varargs && argcount > fp->uf_args.ga_len)
+ else if (!fp->uf_varargs && !allow_too_much_args
+ && argcount > fp->uf_args.ga_len)
     error = ERROR_TOOMANY;
  else if ((fp->uf_flags & FC_DICT) && selfdict == NULL)
     error = ERROR_DICT;
@@ -1273,9 +1278,16 @@ call_func(
  did_save_redo = TRUE;
     }
     ++fp->uf_calls;
-    call_user_func(fp, argcount, argvars, rettv,
-       firstline, lastline,
-  (fp->uf_flags & FC_DICT) ? selfdict : NULL);
+    call_user_func(
+    fp,
+    (argcount > fp->uf_args.ga_len
+     ? fp->uf_args.ga_len
+     : argcount),
+    argvars,
+    rettv,
+    firstline,
+    lastline,
+    (fp->uf_flags & FC_DICT) ? selfdict : NULL);
     if (--fp->uf_calls <= 0 && (isdigit(*fp->uf_name)
  || STRNCMP(fp->uf_name, "<lambda>", 8) == 0)
       && fp->uf_refcount <= 0)
@@ -1294,7 +1306,8 @@ call_func(
     /*
      * Find the function name in the table, call its implementation.
      */
-    error = call_internal_func(fname, argcount, argvars, rettv);
+    error = call_internal_func(fname, argcount, argvars, rettv,
+    allow_too_much_args);
  }
  /*
  * The function call (or "FuncUndefined" autocommand sequence) might

-- 
-- 
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php

--- 
You received this message because you are subscribed to the Google Groups 
"vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
For more options, visit https://groups.google.com/d/optout.

Raspunde prin e-mail lui