Created
August 11, 2019 16:39
-
-
Save Houl/d28f6b05f14956296fd9328e149d8751 to your computer and use it in GitHub Desktop.
CallOverloaded()
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
" Emulate function overloading. | |
" File: overload.vim | |
" Created: 2014 Aug 01 | |
" Last Change: 2018 Nov 18 | |
" Version: 0.9 | |
" Author: Andy Wokula <[email protected]> | |
" License: Vim License, see :h license | |
" CallOverloaded({func-dict}, {arg-list}, {dict}) | |
" | |
" call one of the functions from {func-dict} with arguments {arg-list}. | |
" The types of {arg-list} values determine which function will be called. | |
" Basically, the function name is a concatenation of detected argument | |
" types. {dict} becomes the dict argument of the function call. | |
" | |
" For example, CallOverloaded(d, ['str'], {}) will attempt to call: | |
" d.S('str') (from high to low priority) | |
" d.S_('str') Hints: `S' = (string) | |
" d.X('str') `_' = optional arguments | |
" d.X_('str') `X' = (number or string) | |
" d._('str') | |
" The function name imposes the function signature: | |
" d.S(str) | |
" d.S_(str, ...) | |
" d.X(num_or_str) | |
" d.X_(num_or_str, ...) | |
" d._(...) | |
" At least one of these functions must be defined for the call to succeed. | |
" Hint: d._(...) should be defined to catch invalid arguments. | |
" | |
" OverloadToken({arg-list}) | |
" | |
" return the function name you can use in the function dict to exactly | |
" match the given arguments {arg-list} (list). | |
" (helper func) | |
" | |
" Examples: | |
" :echo OverloadToken(['a', 1, 2, [], {}, function('tr'), 1.2]) | |
" => SNNLDFR | |
" | |
" :echo OverloadToken([]) | |
" => E | |
" | |
" OverloadFunc({funcnames}, {ovltoken}) | |
" | |
" return the best match for {ovltoken} within {funcnames}. | |
" (helper func) | |
" {funcnames} (list of string) names of the user-defined dict | |
" functions, assumed to be sorted (using sort()) | |
" {ovltoken} (string) result of OverloadToken() | |
" | |
" Example: | |
" :echo OverloadFunc(sort(['NS_', 'NX', 'N_']), 'NN') | |
" => NX | |
" | |
" OverloadInfo() | |
" | |
" return a dict with overloading meta data. | |
" (helper func) | |
" | |
" Notes: | |
" * `X' to match (number or string) is a special case. Vim often | |
" auto-converts between number and string, in which case it was annoying | |
" to be urged to specify different functions. Especially because each | |
" further such argument doubles the number of additional functions. | |
" * Can only check against basic types ... eg cannot look inside a | |
" dictionary to do some "pattern matching" etc. Will not add pattern | |
" matching, but: by convention, a lot of `Is*()' functions exist to check | |
" against a specific type ... | |
" History: | |
" 2017 Nov 03 extracted OverloadFunc(), pattern fix | |
" 2017 Aug 11 added new types (untested) | |
" (!) no longer call .Default() | |
" 2016 Feb 16 added `X' (N => [NX], S => [SX]) ... check dict argument for | |
" flag which specifies conversion of `S' and `N' to `X' | |
" (number or string) | |
" 2015 Oct 16 funcs `SSO' and `SO' => `SO' was called -- bug, must call | |
" the most specific function => change `O' into `_'. | |
" Examples: | |
" asneeded\femu\sutr-dispatch-example.vim | |
" SearchHierarchy(), asneeded\trial\D1845.vim | |
" asneeded\trial\D2046.vim | |
" Constants: {{{ | |
" Mapping of type() results to identifier chars (for use in function name) | |
" Mnemonics: String, Number, List, Dict, Funcref, Real number | |
if exists('v:t_number') | |
let s:TYPEMAP = {v:t_string : 'S', v:t_number : 'N', v:t_list : 'L', v:t_dict : 'D', v:t_func : 'F', v:t_float : 'R', v:t_bool : 'B', v:t_none : 'O', v:t_job : 'J', v:t_channel : 'C'} | |
else | |
let s:TYPEMAP = {1: 'S', 0: 'N', 3: 'L', 4: 'D', 2: 'F', 5: 'R'} | |
endif | |
" optional arguments suffix (must start with a char GT any identifier char) | |
let s:OPTSFX = '_' | |
" name of the function to call when there are no arguments (not required) | |
let s:FNEMPTY = 'E' | |
" identifier char for unknown type (new type not yet recognized by this script) | |
let s:TUNKNOWN = 'U' | |
" identifier char for 'number or string' (must be GT 'N' and GT 'S') | |
let s:NUMORSTR = 'X' | |
"}}} | |
func! CallOverloaded(funcdict, arglist, dict) "{{{ | |
let dt = OverloadToken(a:arglist) | |
if has_key(a:funcdict, dt) | |
let fn = dt | |
else | |
let fn = OverloadFunc(sort(keys(a:funcdict)), dt) | |
endif | |
return call(a:funcdict[fn], a:arglist, a:dict) | |
endfunc "}}} | |
func! OverloadToken(arglist) "{{{ | |
let dt = join(map(range(len(a:arglist)), 'get(s:TYPEMAP, type(a:arglist[v:val]), s:TUNKNOWN)'), "") | |
return dt=="" ? s:FNEMPTY : dt | |
endfunc "}}} | |
func! OverloadFunc(funcnames, ftoken) "{{{ | |
let gft = substitute(a:ftoken, '[NS]', '[&X]', 'g') | |
let pat = '^\%('. gft. '\|\%['. gft. ']'. s:OPTSFX. '\)$' | |
let dt = matchstr(a:funcnames, pat) | |
return dt=="" ? s:OPTSFX : dt | |
endfunc "}}} | |
func! OverloadInfo() "{{{ | |
return {'optsfx': s:OPTSFX, 'fnempty': s:FNEMPTY, 'typemap': copy(s:TYPEMAP), 'tunknown': s:TUNKNOWN, 'tnumorstr': s:NUMORSTR} | |
endfunc "}}} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment