пятница, 14 сентября 2012 г., 1:59:05 UTC+4 пользователь Francisco Lopes 
написал:
> Some days ago I've created a topic about using libffi for an enhanced native 
> call interface.
> I've changed my mind all the way about how to build a native call interface 
> for VIM, right
> now I'm changing VIM sources to implement it as I'm thinking, some comments 
> at this stage
> would be good.
>
> Goals:
>     Make VIM able to call and be called, efficiently, from native libraries 
> built as VIM plugins.
> 
> Non Goals:
>     Make VIM able to call any native function.
>     Make VIM automatically marshal VIM types to C types.
> 
> I started thinking of using libffi to do something as python ctypes for VIM 
> but I thought it was not
> a good idea because:
> 
>     Too much complexity for marshaling VIM types to C equivalents.
>     Marshaling is not efficient.
>     If there going be limitations at which functions are able to be called 
> from VIM, why expend time on this.
>     What I, myself, really want is build efficient plugins for VIM in C, not 
> being able to call any function.
> 
> So this is about a interface to call VIM crafted plugins, exporting specific 
> prototypes to be called from VIM
> with not overhead.
> 
> How I'm building this:
> 
>     libload
>         function to load a library from path/name and return a Libhandle.
>     libfunc
>         function to get a Libfunc from a Libhandle and function name.
>     libcall / libcallex / call (not decided yet which one to use)
>         function to call a Libfunc passing a raw VIM List of raw VIM types as 
> arguments and returning a raw
>         VIM type.
>     libinit
>         function initialize a VIM library from a Libhandle. This function 
> will try to call an exported initialization
>         function from the library:
>             void vim( void *(*vim_get)(char *name) )
>         If the function exist, the library should use the given vim_get 
> function to ask for VIM functions and settings
>         by name.
>         The functions exposed by this function should be an API to allow the 
> library to deal with raw VIM types
>         without overhead and without internal implementation knowledge. 
> Beyond dealing with VIM types
>         it should export functions for VIM evaluation from strings and maybe 
> other stuff.
>         This API should be documented and may be extended over time.
> 
> To have libload and libfunc, I needed a way to represent library handles and 
> function pointers. No VIM type
> can represent that well, so I started by extending VIM variables to become 
> yet more two types, Libhandle and
> Libfunc. These types only show up in the context of these functions. 
> Variables of these types can only be assigned,
> compared (==, !=) and used in the empty function to check for nullity.
> 
> Right now I've extend VIM variables, I'm implementing the functions, the hard 
> part will be to define and implement
> what the vim_get callback will return.
> 
> Any comments please?
If I were doing this thing I would change function references to have type

    typedef struct funcref_S funcref_T;
    struct funcref_S {
        void      *fv_data;
        funcdef_T *fv_func_def;
        int        fv_refcount;
        int        fv_copyid;
        funcref_T *fv_used_prev;
        funcref_T *fv_used_next;
    }
    typedef struct {
        int     (*fd_call)   __ARGS((void *data, typval_T *argvars, dict_T 
*selfdict, typval_T *rettv));
        char_u *(*fd_string) __ARGS((void *data)); /* string() implementation */
        void    (*fd_print)  __ARGS((void *data)); /* :function Funcref output
                                                    * Maybe it is worth being
                                                    * char ** (*fd_print)(void 
*)
                                                    */
        int     (*fd_free)   __ARGS((void *data)); /* Called when there are no 
more references left */
    } funcdef_T;
There is a reason behind exactly this interface:
1. This avoids useless dictionary (user functions) or even binary (built-in 
functions) searches when using the funcref.
2. This makes it much easier to implement equivalent of
       vim.bindeval('function("tr")')("a", "b", "c") # Python
       vim.funcref("tr")("a", "b", "c")  -- Lua, if I did not mistake anything
                                         -- Requires recent patches from Luis 
Carvalho
   for vimscript.
3. Being implemented properly this purges out the situations like

      function s:ScriptLocal()
      endfunction
      let d={'f': function('s:ScriptLocal')}
      call FunctionFromAnotherPlugin(d.f) " An error: there is no script-local
                                          " function with this name
                                          " in another plugin
   and
      function Func()
      endfunction
      let d={'f': function('Func')}
      delfunction Func
      call d.f() " The error: function no longer exists

Unfortunately I currently do not have time for such a change (more true, I do 
not want to invest it in what I do not believe will be accepted, comments from 
Bram are needed on the subject). With this interface I get the second (and 
hence will implement funcrefs calling python functions) and everybody get first 
and last as a benefits.

You then will have no need in one of new data types and remove the need in 
libcall/libcallex/call (the latter will do the trick for all types of 
functions). You can also remove a need in the second one if you do the 
following instead:
1. Add libfunc(path_to_lib, function_name). It should do the following:
   1. Normalize path_to_lib and lookup it in special dictionary with library 
handles. If it is found export symbol from there and return.
   2. If not, get library handle.
   3. Then get symbol "vim_init" or whatever and use it to initialize.
   4. Then get function_name, return.
   In returned structure reference to the symbol, its name and a structure 
describing library are stored. It assumes library itself does not have any 
global state, all state is to be stored in arguments if needed. If you do want 
to support state skip this point (except the description of what is stored in 
void *fv_data) and go on with libload+libinit.
2. fd_call should just do the following:
       int
    fd_call (data, argvars,  selfdict, rettv)
        struct {
            int (*func) (typval_T *, typval_T *, typval_T *);
            char_u *name;
            struct {
                void *libhandle;
                char_u *path;
                /* GC stuff here */
            } *libhandle;
        } *data;
        int (*data) (typval_T *, typval_T *, typval_T *);
        typval_T *argvars;
        typval_T *selfdict;
        typval_T *rettv;
    {
        return data->func(argvars, selfdict, rettv);
    }
3. fd_string emits "libfunc(path, name)".
4. fd_print prints path to library and symbol name.
5. fd_free is freeing data and unreferencing opened library, unloading if 
needed. Unreferencing and unloading in both cases: whether you stick to 
internal dictionary with already opened libraries or use libload+..., it only 
makes a difference at the first point.

As you see here adding external libraries support is trivial. What is less 
trivial is changing every piece when funcrefs are involved.

-- 
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

Raspunde prin e-mail lui