diff --git a/Makefile b/Makefile index 5e181069..57aa651f 100644 --- a/Makefile +++ b/Makefile @@ -2,10 +2,10 @@ COMPILED_FILES:=js/vimlparser.js py/vimlparser.py all: $(COMPILED_FILES) -js/vimlparser.js: autoload/vimlparser.vim js/jscompiler.vim js/vimlfunc.js +js/vimlparser.js: autoload/vital/__vimlparser__/VimLParser.vim js/jscompiler.vim js/vimlfunc.js scripts/jscompile.sh $< $@ -py/vimlparser.py: autoload/vimlparser.vim py/pycompiler.vim py/vimlfunc.py +py/vimlparser.py: autoload/vital/__vimlparser__/VimLParser.vim py/pycompiler.vim py/vimlfunc.py scripts/pycompile.sh $< $@ clean_compiled: diff --git a/README.mkd b/README.mkd index 9745d3a0..29b9ccac 100644 --- a/README.mkd +++ b/README.mkd @@ -14,7 +14,7 @@ This parser provide same feature for following languages. * Vim script * Python -* Javascript +* JavaScript ## Example diff --git a/autoload/vimlparser.vim b/autoload/vimlparser.vim index 4b897ef7..2f61271a 100644 --- a/autoload/vimlparser.vim +++ b/autoload/vimlparser.vim @@ -1,9 +1,13 @@ -" vim:set ts=8 sts=2 sw=2 tw=0 et: +" The main code was moved to autoload/vital/__vimlparser__/VimLParser.vim to +" make vim-vimlparser.vim vital-module. " -" VimL parser - Vim Script Parser -" -" License: This file is placed in the public domain. +" See https://github.com/vim-jp/vital.vim for vital module. + +call extend(s:, vital#vimlparser#import('VimLParser').import()) +" To Vim plugin developer who want to depend on vim-vimlparser: +" Please use vimlparser as vital-module instead of this autoload function. +" We do not ensure that future changes are backward compatible. function! vimlparser#import() return s: endfunction @@ -28,5348 +32,31 @@ function! vimlparser#test(input, ...) endtry endfunction -function! s:numtoname(num) - let sig = printf("function('%s')", a:num) - for k in keys(s:) - if type(s:[k]) == type({}) - for name in keys(s:[k]) - if type(s:[k][name]) == type(function('tr')) && string(s:[k][name]) == sig - return printf('%s.%s', k, name) - endif - endfor - endif - endfor - return a:num -endfunction - -let s:NIL = [] -let s:TRUE = 1 -let s:FALSE = 0 - -let s:NODE_TOPLEVEL = 1 -let s:NODE_COMMENT = 2 -let s:NODE_EXCMD = 3 -let s:NODE_FUNCTION = 4 -let s:NODE_ENDFUNCTION = 5 -let s:NODE_DELFUNCTION = 6 -let s:NODE_RETURN = 7 -let s:NODE_EXCALL = 8 -let s:NODE_LET = 9 -let s:NODE_UNLET = 10 -let s:NODE_LOCKVAR = 11 -let s:NODE_UNLOCKVAR = 12 -let s:NODE_IF = 13 -let s:NODE_ELSEIF = 14 -let s:NODE_ELSE = 15 -let s:NODE_ENDIF = 16 -let s:NODE_WHILE = 17 -let s:NODE_ENDWHILE = 18 -let s:NODE_FOR = 19 -let s:NODE_ENDFOR = 20 -let s:NODE_CONTINUE = 21 -let s:NODE_BREAK = 22 -let s:NODE_TRY = 23 -let s:NODE_CATCH = 24 -let s:NODE_FINALLY = 25 -let s:NODE_ENDTRY = 26 -let s:NODE_THROW = 27 -let s:NODE_ECHO = 28 -let s:NODE_ECHON = 29 -let s:NODE_ECHOHL = 30 -let s:NODE_ECHOMSG = 31 -let s:NODE_ECHOERR = 32 -let s:NODE_EXECUTE = 33 -let s:NODE_TERNARY = 34 -let s:NODE_OR = 35 -let s:NODE_AND = 36 -let s:NODE_EQUAL = 37 -let s:NODE_EQUALCI = 38 -let s:NODE_EQUALCS = 39 -let s:NODE_NEQUAL = 40 -let s:NODE_NEQUALCI = 41 -let s:NODE_NEQUALCS = 42 -let s:NODE_GREATER = 43 -let s:NODE_GREATERCI = 44 -let s:NODE_GREATERCS = 45 -let s:NODE_GEQUAL = 46 -let s:NODE_GEQUALCI = 47 -let s:NODE_GEQUALCS = 48 -let s:NODE_SMALLER = 49 -let s:NODE_SMALLERCI = 50 -let s:NODE_SMALLERCS = 51 -let s:NODE_SEQUAL = 52 -let s:NODE_SEQUALCI = 53 -let s:NODE_SEQUALCS = 54 -let s:NODE_MATCH = 55 -let s:NODE_MATCHCI = 56 -let s:NODE_MATCHCS = 57 -let s:NODE_NOMATCH = 58 -let s:NODE_NOMATCHCI = 59 -let s:NODE_NOMATCHCS = 60 -let s:NODE_IS = 61 -let s:NODE_ISCI = 62 -let s:NODE_ISCS = 63 -let s:NODE_ISNOT = 64 -let s:NODE_ISNOTCI = 65 -let s:NODE_ISNOTCS = 66 -let s:NODE_ADD = 67 -let s:NODE_SUBTRACT = 68 -let s:NODE_CONCAT = 69 -let s:NODE_MULTIPLY = 70 -let s:NODE_DIVIDE = 71 -let s:NODE_REMAINDER = 72 -let s:NODE_NOT = 73 -let s:NODE_MINUS = 74 -let s:NODE_PLUS = 75 -let s:NODE_SUBSCRIPT = 76 -let s:NODE_SLICE = 77 -let s:NODE_CALL = 78 -let s:NODE_DOT = 79 -let s:NODE_NUMBER = 80 -let s:NODE_STRING = 81 -let s:NODE_LIST = 82 -let s:NODE_DICT = 83 -let s:NODE_OPTION = 85 -let s:NODE_IDENTIFIER = 86 -let s:NODE_CURLYNAME = 87 -let s:NODE_ENV = 88 -let s:NODE_REG = 89 -let s:NODE_CURLYNAMEPART = 90 -let s:NODE_CURLYNAMEEXPR = 91 -let s:NODE_LAMBDA = 92 - -let s:TOKEN_EOF = 1 -let s:TOKEN_EOL = 2 -let s:TOKEN_SPACE = 3 -let s:TOKEN_OROR = 4 -let s:TOKEN_ANDAND = 5 -let s:TOKEN_EQEQ = 6 -let s:TOKEN_EQEQCI = 7 -let s:TOKEN_EQEQCS = 8 -let s:TOKEN_NEQ = 9 -let s:TOKEN_NEQCI = 10 -let s:TOKEN_NEQCS = 11 -let s:TOKEN_GT = 12 -let s:TOKEN_GTCI = 13 -let s:TOKEN_GTCS = 14 -let s:TOKEN_GTEQ = 15 -let s:TOKEN_GTEQCI = 16 -let s:TOKEN_GTEQCS = 17 -let s:TOKEN_LT = 18 -let s:TOKEN_LTCI = 19 -let s:TOKEN_LTCS = 20 -let s:TOKEN_LTEQ = 21 -let s:TOKEN_LTEQCI = 22 -let s:TOKEN_LTEQCS = 23 -let s:TOKEN_MATCH = 24 -let s:TOKEN_MATCHCI = 25 -let s:TOKEN_MATCHCS = 26 -let s:TOKEN_NOMATCH = 27 -let s:TOKEN_NOMATCHCI = 28 -let s:TOKEN_NOMATCHCS = 29 -let s:TOKEN_IS = 30 -let s:TOKEN_ISCI = 31 -let s:TOKEN_ISCS = 32 -let s:TOKEN_ISNOT = 33 -let s:TOKEN_ISNOTCI = 34 -let s:TOKEN_ISNOTCS = 35 -let s:TOKEN_PLUS = 36 -let s:TOKEN_MINUS = 37 -let s:TOKEN_DOT = 38 -let s:TOKEN_STAR = 39 -let s:TOKEN_SLASH = 40 -let s:TOKEN_PERCENT = 41 -let s:TOKEN_NOT = 42 -let s:TOKEN_QUESTION = 43 -let s:TOKEN_COLON = 44 -let s:TOKEN_POPEN = 45 -let s:TOKEN_PCLOSE = 46 -let s:TOKEN_SQOPEN = 47 -let s:TOKEN_SQCLOSE = 48 -let s:TOKEN_COPEN = 49 -let s:TOKEN_CCLOSE = 50 -let s:TOKEN_COMMA = 51 -let s:TOKEN_NUMBER = 52 -let s:TOKEN_SQUOTE = 53 -let s:TOKEN_DQUOTE = 54 -let s:TOKEN_OPTION = 55 -let s:TOKEN_IDENTIFIER = 56 -let s:TOKEN_ENV = 57 -let s:TOKEN_REG = 58 -let s:TOKEN_EQ = 59 -let s:TOKEN_OR = 60 -let s:TOKEN_SEMICOLON = 61 -let s:TOKEN_BACKTICK = 62 -let s:TOKEN_DOTDOTDOT = 63 -let s:TOKEN_SHARP = 64 -let s:TOKEN_ARROW = 65 - -let s:MAX_FUNC_ARGS = 20 - -function! s:isalpha(c) - return a:c =~# '^[A-Za-z]$' -endfunction - -function! s:isalnum(c) - return a:c =~# '^[0-9A-Za-z]$' -endfunction - -function! s:isdigit(c) - return a:c =~# '^[0-9]$' -endfunction - -function! s:isodigit(c) - return a:c =~# '^[0-7]$' -endfunction - -function! s:isxdigit(c) - return a:c =~# '^[0-9A-Fa-f]$' -endfunction - -function! s:iswordc(c) - return a:c =~# '^[0-9A-Za-z_]$' -endfunction - -function! s:iswordc1(c) - return a:c =~# '^[A-Za-z_]$' -endfunction - -function! s:iswhite(c) - return a:c =~# '^[ \t]$' -endfunction - -function! s:isnamec(c) - return a:c =~# '^[0-9A-Za-z_:#]$' -endfunction - -function! s:isnamec1(c) - return a:c =~# '^[A-Za-z_]$' -endfunction - -function! s:isargname(s) - return a:s =~# '^[A-Za-z_][0-9A-Za-z_]*$' -endfunction - -function! s:isvarname(s) - return a:s =~# '^[vgslabwt]:$\|^\([vgslabwt]:\)\?[A-Za-z_][0-9A-Za-z_#]*$' -endfunction - -" FIXME: -function! s:isidc(c) - return a:c =~# '^[0-9A-Za-z_]$' -endfunction - -function! s:isupper(c) - return a:c =~# '^[A-Z]$' -endfunction - -function! s:islower(c) - return a:c =~# '^[a-z]$' -endfunction - -function! s:ExArg() - let ea = {} - let ea.forceit = s:FALSE - let ea.addr_count = 0 - let ea.line1 = 0 - let ea.line2 = 0 - let ea.flags = 0 - let ea.do_ecmd_cmd = '' - let ea.do_ecmd_lnum = 0 - let ea.append = 0 - let ea.usefilter = s:FALSE - let ea.amount = 0 - let ea.regname = 0 - let ea.force_bin = 0 - let ea.read_edit = 0 - let ea.force_ff = 0 - let ea.force_enc = 0 - let ea.bad_char = 0 - let ea.linepos = {} - let ea.cmdpos = [] - let ea.argpos = [] - let ea.cmd = {} - let ea.modifiers = [] - let ea.range = [] - let ea.argopt = {} - let ea.argcmd = {} - return ea -endfunction - -" struct node { -" int type -" pos pos -" node left -" node right -" node cond -" node rest -" node[] list -" node[] rlist -" node[] body -" string op -" string str -" int depth -" variant value -" } -" TOPLEVEL .body -" COMMENT .str -" EXCMD .ea .str -" FUNCTION .ea .body .left .rlist .attr .endfunction -" ENDFUNCTION .ea -" DELFUNCTION .ea .left -" RETURN .ea .left -" EXCALL .ea .left -" LET .ea .op .left .list .rest .right -" UNLET .ea .list -" LOCKVAR .ea .depth .list -" UNLOCKVAR .ea .depth .list -" IF .ea .body .cond .elseif .else .endif -" ELSEIF .ea .body .cond -" ELSE .ea .body -" ENDIF .ea -" WHILE .ea .body .cond .endwhile -" ENDWHILE .ea -" FOR .ea .body .left .list .rest .right .endfor -" ENDFOR .ea -" CONTINUE .ea -" BREAK .ea -" TRY .ea .body .catch .finally .endtry -" CATCH .ea .body .pattern -" FINALLY .ea .body -" ENDTRY .ea -" THROW .ea .left -" ECHO .ea .list -" ECHON .ea .list -" ECHOHL .ea .str -" ECHOMSG .ea .list -" ECHOERR .ea .list -" EXECUTE .ea .list -" TERNARY .cond .left .right -" OR .left .right -" AND .left .right -" EQUAL .left .right -" EQUALCI .left .right -" EQUALCS .left .right -" NEQUAL .left .right -" NEQUALCI .left .right -" NEQUALCS .left .right -" GREATER .left .right -" GREATERCI .left .right -" GREATERCS .left .right -" GEQUAL .left .right -" GEQUALCI .left .right -" GEQUALCS .left .right -" SMALLER .left .right -" SMALLERCI .left .right -" SMALLERCS .left .right -" SEQUAL .left .right -" SEQUALCI .left .right -" SEQUALCS .left .right -" MATCH .left .right -" MATCHCI .left .right -" MATCHCS .left .right -" NOMATCH .left .right -" NOMATCHCI .left .right -" NOMATCHCS .left .right -" IS .left .right -" ISCI .left .right -" ISCS .left .right -" ISNOT .left .right -" ISNOTCI .left .right -" ISNOTCS .left .right -" ADD .left .right -" SUBTRACT .left .right -" CONCAT .left .right -" MULTIPLY .left .right -" DIVIDE .left .right -" REMAINDER .left .right -" NOT .left -" MINUS .left -" PLUS .left -" SUBSCRIPT .left .right -" SLICE .left .rlist -" CALL .left .rlist -" DOT .left .right -" NUMBER .value -" STRING .value -" LIST .value -" DICT .value -" NESTING .left -" OPTION .value -" IDENTIFIER .value -" CURLYNAME .value -" ENV .value -" REG .value -" CURLYNAMEPART .value -" CURLYNAMEEXPR .value -" LAMBDA .rlist .left -function! s:Node(type) - return {'type': a:type} -endfunction - -function! s:Err(msg, pos) - return printf('vimlparser: %s: line %d col %d', a:msg, a:pos.lnum, a:pos.col) -endfunction - -let s:VimLParser = {} - -function! s:VimLParser.new(...) - let obj = copy(self) - call call(obj.__init__, a:000, obj) - return obj -endfunction - -function! s:VimLParser.__init__(...) - if len(a:000) > 0 - let self.neovim = a:000[0] - else - let self.neovim = 0 - endif - - let self.find_command_cache = {} -endfunction - -function! s:VimLParser.push_context(node) - call insert(self.context, a:node) -endfunction - -function! s:VimLParser.pop_context() - call remove(self.context, 0) -endfunction - -function! s:VimLParser.find_context(type) - let i = 0 - for node in self.context - if node.type == a:type - return i - endif - let i += 1 - endfor - return -1 -endfunction - -function! s:VimLParser.add_node(node) - call add(self.context[0].body, a:node) -endfunction - -function! s:VimLParser.check_missing_endfunction(ends, pos) - if self.context[0].type == s:NODE_FUNCTION - throw s:Err(printf('E126: Missing :endfunction: %s', a:ends), a:pos) - endif -endfunction - -function! s:VimLParser.check_missing_endif(ends, pos) - if self.context[0].type == s:NODE_IF || self.context[0].type == s:NODE_ELSEIF || self.context[0].type == s:NODE_ELSE - throw s:Err(printf('E171: Missing :endif: %s', a:ends), a:pos) - endif -endfunction - -function! s:VimLParser.check_missing_endtry(ends, pos) - if self.context[0].type == s:NODE_TRY || self.context[0].type == s:NODE_CATCH || self.context[0].type == s:NODE_FINALLY - throw s:Err(printf('E600: Missing :endtry: %s', a:ends), a:pos) - endif -endfunction - -function! s:VimLParser.check_missing_endwhile(ends, pos) - if self.context[0].type == s:NODE_WHILE - throw s:Err(printf('E170: Missing :endwhile: %s', a:ends), a:pos) - endif -endfunction - -function! s:VimLParser.check_missing_endfor(ends, pos) - if self.context[0].type == s:NODE_FOR - throw s:Err(printf('E170: Missing :endfor: %s', a:ends), a:pos) - endif -endfunction - -function! s:VimLParser.parse(reader) - let self.reader = a:reader - let self.context = [] - let toplevel = s:Node(s:NODE_TOPLEVEL) - let toplevel.pos = self.reader.getpos() - let toplevel.body = [] - call self.push_context(toplevel) - while self.reader.peek() !=# '<EOF>' - call self.parse_one_cmd() - endwhile - call self.check_missing_endfunction('TOPLEVEL', self.reader.getpos()) - call self.check_missing_endif('TOPLEVEL', self.reader.getpos()) - call self.check_missing_endtry('TOPLEVEL', self.reader.getpos()) - call self.check_missing_endwhile('TOPLEVEL', self.reader.getpos()) - call self.check_missing_endfor('TOPLEVEL', self.reader.getpos()) - call self.pop_context() - return toplevel -endfunction - -function! s:VimLParser.parse_one_cmd() - let self.ea = s:ExArg() - - if self.reader.peekn(2) ==# '#!' - call self.parse_hashbang() - call self.reader.get() - return - endif - call self.reader.skip_white_and_colon() - if self.reader.peekn(1) ==# '' - call self.reader.get() - return - endif - if self.reader.peekn(1) ==# '"' - call self.parse_comment() - call self.reader.get() - return - endif - let self.ea.linepos = self.reader.getpos() - call self.parse_command_modifiers() - call self.parse_range() - call self.parse_command() - call self.parse_trail() -endfunction - -" FIXME: -function! s:VimLParser.parse_command_modifiers() - let modifiers = [] - while s:TRUE - let pos = self.reader.tell() - let d = '' - if s:isdigit(self.reader.peekn(1)) - let d = self.reader.read_digit() - call self.reader.skip_white() - endif - let k = self.reader.read_alpha() - let c = self.reader.peekn(1) - call self.reader.skip_white() - if stridx('aboveleft', k) == 0 && len(k) >= 3 " abo\%[veleft] - call add(modifiers, {'name': 'aboveleft'}) - elseif stridx('belowright', k) == 0 && len(k) >= 3 " bel\%[owright] - call add(modifiers, {'name': 'belowright'}) - elseif stridx('browse', k) == 0 && len(k) >= 3 " bro\%[wse] - call add(modifiers, {'name': 'browse'}) - elseif stridx('botright', k) == 0 && len(k) >= 2 " bo\%[tright] - call add(modifiers, {'name': 'botright'}) - elseif stridx('confirm', k) == 0 && len(k) >= 4 " conf\%[irm] - call add(modifiers, {'name': 'confirm'}) - elseif stridx('keepmarks', k) == 0 && len(k) >= 3 " kee\%[pmarks] - call add(modifiers, {'name': 'keepmarks'}) - elseif stridx('keepalt', k) == 0 && len(k) >= 5 " keepa\%[lt] - call add(modifiers, {'name': 'keepalt'}) - elseif stridx('keepjumps', k) == 0 && len(k) >= 5 " keepj\%[umps] - call add(modifiers, {'name': 'keepjumps'}) - elseif stridx('keeppatterns', k) == 0 && len(k) >= 5 " keepp\%[atterns] - call add(modifiers, {'name': 'keeppatterns'}) - elseif stridx('hide', k) == 0 && len(k) >= 3 "hid\%[e] - if self.ends_excmds(c) - break - endif - call add(modifiers, {'name': 'hide'}) - elseif stridx('lockmarks', k) == 0 && len(k) >= 3 " loc\%[kmarks] - call add(modifiers, {'name': 'lockmarks'}) - elseif stridx('leftabove', k) == 0 && len(k) >= 5 " lefta\%[bove] - call add(modifiers, {'name': 'leftabove'}) - elseif stridx('noautocmd', k) == 0 && len(k) >= 3 " noa\%[utocmd] - call add(modifiers, {'name': 'noautocmd'}) - elseif stridx('noswapfile', k) == 0 && len(k) >= 3 " :nos\%[wapfile] - call add(modifiers, {'name': 'noswapfile'}) - elseif stridx('rightbelow', k) == 0 && len(k) >= 6 "rightb\%[elow] - call add(modifiers, {'name': 'rightbelow'}) - elseif stridx('sandbox', k) == 0 && len(k) >= 3 " san\%[dbox] - call add(modifiers, {'name': 'sandbox'}) - elseif stridx('silent', k) == 0 && len(k) >= 3 " sil\%[ent] - if c ==# '!' - call self.reader.get() - call add(modifiers, {'name': 'silent', 'bang': 1}) - else - call add(modifiers, {'name': 'silent', 'bang': 0}) - endif - elseif k ==# 'tab' " tab - if d !=# '' - call add(modifiers, {'name': 'tab', 'count': str2nr(d, 10)}) - else - call add(modifiers, {'name': 'tab'}) - endif - elseif stridx('topleft', k) == 0 && len(k) >= 2 " to\%[pleft] - call add(modifiers, {'name': 'topleft'}) - elseif stridx('unsilent', k) == 0 && len(k) >= 3 " uns\%[ilent] - call add(modifiers, {'name': 'unsilent'}) - elseif stridx('vertical', k) == 0 && len(k) >= 4 " vert\%[ical] - call add(modifiers, {'name': 'vertical'}) - elseif stridx('verbose', k) == 0 && len(k) >= 4 " verb\%[ose] - if d !=# '' - call add(modifiers, {'name': 'verbose', 'count': str2nr(d, 10)}) - else - call add(modifiers, {'name': 'verbose', 'count': 1}) - endif - else - call self.reader.seek_set(pos) - break - endif - endwhile - let self.ea.modifiers = modifiers -endfunction - -" FIXME: -function! s:VimLParser.parse_range() - let tokens = [] - - while s:TRUE - - while s:TRUE - call self.reader.skip_white() - - let c = self.reader.peekn(1) - if c ==# '' - break - endif - - if c ==# '.' - call add(tokens, self.reader.getn(1)) - elseif c ==# '$' - call add(tokens, self.reader.getn(1)) - elseif c ==# "'" - call self.reader.getn(1) - let m = self.reader.getn(1) - if m ==# '' - break - endif - call add(tokens, "'" . m) - elseif c ==# '/' - call self.reader.getn(1) - let [pattern, _] = self.parse_pattern(c) - call add(tokens, pattern) - elseif c ==# '?' - call self.reader.getn(1) - let [pattern, _] = self.parse_pattern(c) - call add(tokens, pattern) - elseif c ==# '\' - let m = self.reader.p(1) - if m ==# '&' || m ==# '?' || m ==# '/' - call self.reader.seek_cur(2) - call add(tokens, '\' . m) - else - throw s:Err('E10: \\ should be followed by /, ? or &', self.reader.getpos()) - endif - elseif s:isdigit(c) - call add(tokens, self.reader.read_digit()) - endif - - while s:TRUE - call self.reader.skip_white() - if self.reader.peekn(1) ==# '' - break - endif - let n = self.reader.read_integer() - if n ==# '' - break - endif - call add(tokens, n) - endwhile - - if self.reader.p(0) !=# '/' && self.reader.p(0) !=# '?' - break - endif - endwhile - - if self.reader.peekn(1) ==# '%' - call add(tokens, self.reader.getn(1)) - elseif self.reader.peekn(1) ==# '*' " && &cpoptions !~ '\*' - call add(tokens, self.reader.getn(1)) - endif - - if self.reader.peekn(1) ==# ';' - call add(tokens, self.reader.getn(1)) - continue - elseif self.reader.peekn(1) ==# ',' - call add(tokens, self.reader.getn(1)) - continue - endif - - break - endwhile - - let self.ea.range = tokens -endfunction - -" FIXME: -function! s:VimLParser.parse_pattern(delimiter) - let pattern = '' - let endc = '' - let inbracket = 0 - while s:TRUE - let c = self.reader.getn(1) - if c ==# '' - break - endif - if c ==# a:delimiter && inbracket == 0 - let endc = c - break - endif - let pattern .= c - if c ==# '\' - let c = self.reader.peekn(1) - if c ==# '' - throw s:Err('E682: Invalid search pattern or delimiter', self.reader.getpos()) - endif - call self.reader.getn(1) - let pattern .= c - elseif c ==# '[' - let inbracket += 1 - elseif c ==# ']' - let inbracket -= 1 - endif - endwhile - return [pattern, endc] -endfunction - -function! s:VimLParser.parse_command() - call self.reader.skip_white_and_colon() - - let self.ea.cmdpos = self.reader.getpos() - - if self.reader.peekn(1) ==# '' || self.reader.peekn(1) ==# '"' - if !empty(self.ea.modifiers) || !empty(self.ea.range) - call self.parse_cmd_modifier_range() - endif - return - endif - - let self.ea.cmd = self.find_command() - - if self.ea.cmd is s:NIL - call self.reader.setpos(self.ea.cmdpos) - throw s:Err(printf('E492: Not an editor command: %s', self.reader.peekline()), self.ea.cmdpos) - endif - - if self.reader.peekn(1) ==# '!' && self.ea.cmd.name !=# 'substitute' && self.ea.cmd.name !=# 'smagic' && self.ea.cmd.name !=# 'snomagic' - call self.reader.getn(1) - let self.ea.forceit = s:TRUE - else - let self.ea.forceit = s:FALSE - endif - - if self.ea.cmd.flags !~# '\<BANG\>' && self.ea.forceit && self.ea.cmd.flags !~# '\<USERCMD\>' - throw s:Err('E477: No ! allowed', self.ea.cmdpos) - endif - - if self.ea.cmd.name !=# '!' - call self.reader.skip_white() - endif - - let self.ea.argpos = self.reader.getpos() - - if self.ea.cmd.flags =~# '\<ARGOPT\>' - call self.parse_argopt() - endif - - if self.ea.cmd.name ==# 'write' || self.ea.cmd.name ==# 'update' - if self.reader.p(0) ==# '>' - if self.reader.p(1) !=# '>' - throw s:Err('E494: Use w or w>>', self.ea.cmdpos) - endif - call self.reader.seek_cur(2) - call self.reader.skip_white() - let self.ea.append = 1 - elseif self.reader.peekn(1) ==# '!' && self.ea.cmd.name ==# 'write' - call self.reader.getn(1) - let self.ea.usefilter = s:TRUE - endif - endif - - if self.ea.cmd.name ==# 'read' - if self.ea.forceit - let self.ea.usefilter = s:TRUE - let self.ea.forceit = s:FALSE - elseif self.reader.peekn(1) ==# '!' - call self.reader.getn(1) - let self.ea.usefilter = s:TRUE - endif - endif - - if self.ea.cmd.name ==# '<' || self.ea.cmd.name ==# '>' - let self.ea.amount = 1 - while self.reader.peekn(1) ==# self.ea.cmd.name - call self.reader.getn(1) - let self.ea.amount += 1 - endwhile - call self.reader.skip_white() - endif - - if self.ea.cmd.flags =~# '\<EDITCMD\>' && !self.ea.usefilter - call self.parse_argcmd() - endif - - call self._parse_command(self.ea.cmd.parser) -endfunction - -function! s:VimLParser._parse_command(parser) abort - if a:parser == 'parse_cmd_append' - call self.parse_cmd_append() - elseif a:parser == 'parse_cmd_break' - call self.parse_cmd_break() - elseif a:parser == 'parse_cmd_call' - call self.parse_cmd_call() - elseif a:parser == 'parse_cmd_catch' - call self.parse_cmd_catch() - elseif a:parser == 'parse_cmd_common' - call self.parse_cmd_common() - elseif a:parser == 'parse_cmd_continue' - call self.parse_cmd_continue() - elseif a:parser == 'parse_cmd_delfunction' - call self.parse_cmd_delfunction() - elseif a:parser == 'parse_cmd_echo' - call self.parse_cmd_echo() - elseif a:parser == 'parse_cmd_echoerr' - call self.parse_cmd_echoerr() - elseif a:parser == 'parse_cmd_echohl' - call self.parse_cmd_echohl() - elseif a:parser == 'parse_cmd_echomsg' - call self.parse_cmd_echomsg() - elseif a:parser == 'parse_cmd_echon' - call self.parse_cmd_echon() - elseif a:parser == 'parse_cmd_else' - call self.parse_cmd_else() - elseif a:parser == 'parse_cmd_elseif' - call self.parse_cmd_elseif() - elseif a:parser == 'parse_cmd_endfor' - call self.parse_cmd_endfor() - elseif a:parser == 'parse_cmd_endfunction' - call self.parse_cmd_endfunction() - elseif a:parser == 'parse_cmd_endif' - call self.parse_cmd_endif() - elseif a:parser == 'parse_cmd_endtry' - call self.parse_cmd_endtry() - elseif a:parser == 'parse_cmd_endwhile' - call self.parse_cmd_endwhile() - elseif a:parser == 'parse_cmd_execute' - call self.parse_cmd_execute() - elseif a:parser == 'parse_cmd_finally' - call self.parse_cmd_finally() - elseif a:parser == 'parse_cmd_finish' - call self.parse_cmd_finish() - elseif a:parser == 'parse_cmd_for' - call self.parse_cmd_for() - elseif a:parser == 'parse_cmd_function' - call self.parse_cmd_function() - elseif a:parser == 'parse_cmd_if' - call self.parse_cmd_if() - elseif a:parser == 'parse_cmd_insert' - call self.parse_cmd_insert() - elseif a:parser == 'parse_cmd_let' - call self.parse_cmd_let() - elseif a:parser == 'parse_cmd_loadkeymap' - call self.parse_cmd_loadkeymap() - elseif a:parser == 'parse_cmd_lockvar' - call self.parse_cmd_lockvar() - elseif a:parser == 'parse_cmd_lua' - call self.parse_cmd_lua() - elseif a:parser == 'parse_cmd_modifier_range' - call self.parse_cmd_modifier_range() - elseif a:parser == 'parse_cmd_mzscheme' - call self.parse_cmd_mzscheme() - elseif a:parser == 'parse_cmd_perl' - call self.parse_cmd_perl() - elseif a:parser == 'parse_cmd_python' - call self.parse_cmd_python() - elseif a:parser == 'parse_cmd_python3' - call self.parse_cmd_python3() - elseif a:parser == 'parse_cmd_return' - call self.parse_cmd_return() - elseif a:parser == 'parse_cmd_ruby' - call self.parse_cmd_ruby() - elseif a:parser == 'parse_cmd_tcl' - call self.parse_cmd_tcl() - elseif a:parser == 'parse_cmd_throw' - call self.parse_cmd_throw() - elseif a:parser == 'parse_cmd_try' - call self.parse_cmd_try() - elseif a:parser == 'parse_cmd_unlet' - call self.parse_cmd_unlet() - elseif a:parser == 'parse_cmd_unlockvar' - call self.parse_cmd_unlockvar() - elseif a:parser == 'parse_cmd_usercmd' - call self.parse_cmd_usercmd() - elseif a:parser == 'parse_cmd_while' - call self.parse_cmd_while() - elseif a:parser == 'parse_wincmd' - call self.parse_wincmd() - elseif a:parser == 'parse_cmd_syntax' - call self.parse_cmd_syntax() - else - throw printf('unknown parser: %s', string(a:parser)) - endif -endfunction - -function! s:VimLParser.find_command() - let c = self.reader.peekn(1) - let name = '' - - if c ==# 'k' - call self.reader.getn(1) - let name = 'k' - elseif c ==# 's' && self.reader.peekn(5) =~# '\v^s%(c[^sr][^i][^p]|g|i[^mlg]|I|r[^e])' - call self.reader.getn(1) - let name = 'substitute' - elseif c =~# '[@*!=><&~#]' - call self.reader.getn(1) - let name = c - elseif self.reader.peekn(2) ==# 'py' - let name = self.reader.read_alnum() - else - let pos = self.reader.tell() - let name = self.reader.read_alpha() - if name !=# 'del' && name =~# '\v^d%[elete][lp]$' - call self.reader.seek_set(pos) - let name = self.reader.getn(len(name) - 1) - endif - endif - - if name == '' - return s:NIL - endif - - if has_key(self.find_command_cache, name) - return self.find_command_cache[name] - endif - - let cmd = s:NIL - - for x in self.builtin_commands - if stridx(x.name, name) == 0 && len(name) >= x.minlen - unlet cmd - let cmd = x - break - endif - endfor - - if self.neovim - for x in self.neovim_additional_commands - if stridx(x.name, name) == 0 && len(name) >= x.minlen - unlet cmd - let cmd = x - break +if has('patch-7.4.1842') + function! s:numtoname(num) + for k in keys(s:) + if type(s:[k]) == type({}) + for name in keys(s:[k]) + if type(s:[k][name]) == type(function('tr')) && get(s:[k][name], 'name') == a:num + return printf('%s.%s', k, name) + endif + endfor endif endfor - - for x in self.neovim_removed_commands - if stridx(x.name, name) == 0 && len(name) >= x.minlen - unlet cmd - let cmd = s:NIL - break + return a:num + endfunction +else + function! s:numtoname(num) + let sig = printf("function('%s')", a:num) + for k in keys(s:) + if type(s:[k]) == type({}) + for name in keys(s:[k]) + if type(s:[k][name]) == type(function('tr')) && string(s:[k][name]) == sig + return printf('%s.%s', k, name) + endif + endfor endif endfor - endif - - " FIXME: user defined command - if (cmd is s:NIL || cmd.name ==# 'Print') && name =~# '^[A-Z]' - let name .= self.reader.read_alnum() - unlet cmd - let cmd = {'name': name, 'flags': 'USERCMD', 'parser': 'parse_cmd_usercmd'} - endif - - let self.find_command_cache[name] = cmd - - return cmd -endfunction - -" TODO: -function! s:VimLParser.parse_hashbang() - call self.reader.getn(-1) -endfunction - -" TODO: -" ++opt=val -function! s:VimLParser.parse_argopt() - while self.reader.p(0) ==# '+' && self.reader.p(1) ==# '+' - let s = self.reader.peekn(20) - if s =~# '^++bin\>' - call self.reader.getn(5) - let self.ea.force_bin = 1 - elseif s =~# '^++nobin\>' - call self.reader.getn(7) - let self.ea.force_bin = 2 - elseif s =~# '^++edit\>' - call self.reader.getn(6) - let self.ea.read_edit = 1 - elseif s =~# '^++ff=\(dos\|unix\|mac\)\>' - call self.reader.getn(5) - let self.ea.force_ff = self.reader.read_alpha() - elseif s =~# '^++fileformat=\(dos\|unix\|mac\)\>' - call self.reader.getn(13) - let self.ea.force_ff = self.reader.read_alpha() - elseif s =~# '^++enc=\S' - call self.reader.getn(6) - let self.ea.force_enc = self.reader.read_nonwhite() - elseif s =~# '^++encoding=\S' - call self.reader.getn(11) - let self.ea.force_enc = self.reader.read_nonwhite() - elseif s =~# '^++bad=\(keep\|drop\|.\)\>' - call self.reader.getn(6) - if s =~# '^++bad=keep' - let self.ea.bad_char = self.reader.getn(4) - elseif s =~# '^++bad=drop' - let self.ea.bad_char = self.reader.getn(4) - else - let self.ea.bad_char = self.reader.getn(1) - endif - elseif s =~# '^++' - throw s:Err('E474: Invalid Argument', self.reader.getpos()) - else - break - endif - call self.reader.skip_white() - endwhile -endfunction - -" TODO: -" +command -function! s:VimLParser.parse_argcmd() - if self.reader.peekn(1) ==# '+' - call self.reader.getn(1) - if self.reader.peekn(1) ==# ' ' - let self.ea.do_ecmd_cmd = '$' - else - let self.ea.do_ecmd_cmd = self.read_cmdarg() - endif - endif -endfunction - -function! s:VimLParser.read_cmdarg() - let r = '' - while s:TRUE - let c = self.reader.peekn(1) - if c ==# '' || s:iswhite(c) - break - endif - call self.reader.getn(1) - if c ==# '\' - let c = self.reader.getn(1) - endif - let r .= c - endwhile - return r -endfunction - -function! s:VimLParser.parse_comment() - let npos = self.reader.getpos() - let c = self.reader.get() - if c !=# '"' - throw s:Err(printf('unexpected character: %s', c), npos) - endif - let node = s:Node(s:NODE_COMMENT) - let node.pos = npos - let node.str = self.reader.getn(-1) - call self.add_node(node) -endfunction - -function! s:VimLParser.parse_trail() - call self.reader.skip_white() - let c = self.reader.peek() - if c ==# '<EOF>' - " pass - elseif c ==# '<EOL>' - call self.reader.get() - elseif c ==# '|' - call self.reader.get() - elseif c ==# '"' - call self.parse_comment() - call self.reader.get() - else - throw s:Err(printf('E488: Trailing characters: %s', c), self.reader.getpos()) - endif -endfunction - -" modifier or range only command line -function! s:VimLParser.parse_cmd_modifier_range() - let node = s:Node(s:NODE_EXCMD) - let node.pos = self.ea.cmdpos - let node.ea = self.ea - let node.str = self.reader.getstr(self.ea.linepos, self.reader.getpos()) - call self.add_node(node) -endfunction - -" TODO: -function! s:VimLParser.parse_cmd_common() - let end = self.reader.getpos() - if self.ea.cmd.flags =~# '\<TRLBAR\>' && !self.ea.usefilter - let end = self.separate_nextcmd() - elseif self.ea.cmd.name ==# '!' || self.ea.cmd.name ==# 'global' || self.ea.cmd.name ==# 'vglobal' || self.ea.usefilter - while s:TRUE - let end = self.reader.getpos() - if self.reader.getn(1) ==# '' - break - endif - endwhile - else - while s:TRUE - let end = self.reader.getpos() - if self.reader.getn(1) ==# '' - break - endif - endwhile - endif - let node = s:Node(s:NODE_EXCMD) - let node.pos = self.ea.cmdpos - let node.ea = self.ea - let node.str = self.reader.getstr(self.ea.linepos, end) - call self.add_node(node) -endfunction - -function! s:VimLParser.separate_nextcmd() - if self.ea.cmd.name ==# 'vimgrep' || self.ea.cmd.name ==# 'vimgrepadd' || self.ea.cmd.name ==# 'lvimgrep' || self.ea.cmd.name ==# 'lvimgrepadd' - call self.skip_vimgrep_pat() - endif - let pc = '' - let end = self.reader.getpos() - let nospend = end - while s:TRUE - let end = self.reader.getpos() - if !s:iswhite(pc) - let nospend = end - endif - let c = self.reader.peek() - if c ==# '<EOF>' || c ==# '<EOL>' - break - elseif c ==# "\x16" " <C-V> - call self.reader.get() - let end = self.reader.getpos() - let nospend = self.reader.getpos() - let c = self.reader.peek() - if c ==# '<EOF>' || c ==# '<EOL>' - break - endif - call self.reader.get() - elseif self.reader.peekn(2) ==# '`=' && self.ea.cmd.flags =~# '\<\(XFILE\|FILES\|FILE1\)\>' - call self.reader.getn(2) - call self.parse_expr() - let c = self.reader.peekn(1) - if c !=# '`' - throw s:Err(printf('unexpected character: %s', c), self.reader.getpos()) - endif - call self.reader.getn(1) - elseif c ==# '|' || c ==# "\n" || - \ (c ==# '"' && self.ea.cmd.flags !~# '\<NOTRLCOM\>' - \ && ((self.ea.cmd.name !=# '@' && self.ea.cmd.name !=# '*') - \ || self.reader.getpos() !=# self.ea.argpos) - \ && (self.ea.cmd.name !=# 'redir' - \ || self.reader.getpos().i != self.ea.argpos.i + 1 || pc !=# '@')) - let has_cpo_bar = s:FALSE " &cpoptions =~ 'b' - if (!has_cpo_bar || self.ea.cmd.flags !~# '\<USECTRLV\>') && pc ==# '\' - call self.reader.get() - else - break - endif - else - call self.reader.get() - endif - let pc = c - endwhile - if self.ea.cmd.flags !~# '\<NOTRLCOM\>' - let end = nospend - endif - return end -endfunction - -" FIXME -function! s:VimLParser.skip_vimgrep_pat() - if self.reader.peekn(1) ==# '' - " pass - elseif s:isidc(self.reader.peekn(1)) - " :vimgrep pattern fname - call self.reader.read_nonwhite() - else - " :vimgrep /pattern/[g][j] fname - let c = self.reader.getn(1) - let [_, endc] = self.parse_pattern(c) - if c !=# endc - return - endif - while self.reader.p(0) ==# 'g' || self.reader.p(0) ==# 'j' - call self.reader.getn(1) - endwhile - endif -endfunction - -function! s:VimLParser.parse_cmd_append() - call self.reader.setpos(self.ea.linepos) - let cmdline = self.reader.readline() - let lines = [cmdline] - let m = '.' - while s:TRUE - if self.reader.peek() ==# '<EOF>' - break - endif - let line = self.reader.getn(-1) - call add(lines, line) - if line ==# m - break - endif - call self.reader.get() - endwhile - let node = s:Node(s:NODE_EXCMD) - let node.pos = self.ea.cmdpos - let node.ea = self.ea - let node.str = join(lines, "\n") - call self.add_node(node) -endfunction - -function! s:VimLParser.parse_cmd_insert() - call self.parse_cmd_append() -endfunction - -function! s:VimLParser.parse_cmd_loadkeymap() - call self.reader.setpos(self.ea.linepos) - let cmdline = self.reader.readline() - let lines = [cmdline] - while s:TRUE - if self.reader.peek() ==# '<EOF>' - break - endif - let line = self.reader.readline() - call add(lines, line) - endwhile - let node = s:Node(s:NODE_EXCMD) - let node.pos = self.ea.cmdpos - let node.ea = self.ea - let node.str = join(lines, "\n") - call self.add_node(node) -endfunction - -function! s:VimLParser.parse_cmd_lua() - let lines = [] - call self.reader.skip_white() - if self.reader.peekn(2) ==# '<<' - call self.reader.getn(2) - call self.reader.skip_white() - let m = self.reader.readline() - if m ==# '' - let m = '.' - endif - call self.reader.setpos(self.ea.linepos) - let cmdline = self.reader.getn(-1) - let lines = [cmdline] - call self.reader.get() - while s:TRUE - if self.reader.peek() ==# '<EOF>' - break - endif - let line = self.reader.getn(-1) - call add(lines, line) - if line ==# m - break - endif - call self.reader.get() - endwhile - else - call self.reader.setpos(self.ea.linepos) - let cmdline = self.reader.getn(-1) - let lines = [cmdline] - endif - let node = s:Node(s:NODE_EXCMD) - let node.pos = self.ea.cmdpos - let node.ea = self.ea - let node.str = join(lines, "\n") - call self.add_node(node) -endfunction - -function! s:VimLParser.parse_cmd_mzscheme() - call self.parse_cmd_lua() -endfunction - -function! s:VimLParser.parse_cmd_perl() - call self.parse_cmd_lua() -endfunction - -function! s:VimLParser.parse_cmd_python() - call self.parse_cmd_lua() -endfunction - -function! s:VimLParser.parse_cmd_python3() - call self.parse_cmd_lua() -endfunction - -function! s:VimLParser.parse_cmd_ruby() - call self.parse_cmd_lua() -endfunction - -function! s:VimLParser.parse_cmd_tcl() - call self.parse_cmd_lua() -endfunction - -function! s:VimLParser.parse_cmd_finish() - call self.parse_cmd_common() - if self.context[0].type == s:NODE_TOPLEVEL - call self.reader.seek_end(0) - endif -endfunction - -" FIXME -function! s:VimLParser.parse_cmd_usercmd() - call self.parse_cmd_common() -endfunction - -function! s:VimLParser.parse_cmd_function() - let pos = self.reader.tell() - call self.reader.skip_white() - - " :function - if self.ends_excmds(self.reader.peek()) - call self.reader.seek_set(pos) - call self.parse_cmd_common() - return - endif - - " :function /pattern - if self.reader.peekn(1) ==# '/' - call self.reader.seek_set(pos) - call self.parse_cmd_common() - return - endif - - let left = self.parse_lvalue_func() - call self.reader.skip_white() - - if left.type == s:NODE_IDENTIFIER - let s = left.value - let ss = split(s, '\zs') - if ss[0] !=# '<' && !s:isupper(ss[0]) && stridx(s, ':') == -1 && stridx(s, '#') == -1 - throw s:Err(printf('E128: Function name must start with a capital or contain a colon: %s', s), left.pos) - endif - endif - - " :function {name} - if self.reader.peekn(1) !=# '(' - call self.reader.seek_set(pos) - call self.parse_cmd_common() - return - endif - - " :function[!] {name}([arguments]) [range] [abort] [dict] [closure] - let node = s:Node(s:NODE_FUNCTION) - let node.pos = self.ea.cmdpos - let node.body = [] - let node.ea = self.ea - let node.left = left - let node.rlist = [] - let node.attr = {'range': 0, 'abort': 0, 'dict': 0, 'closure': 0} - let node.endfunction = s:NIL - call self.reader.getn(1) - let tokenizer = s:ExprTokenizer.new(self.reader) - if tokenizer.peek().type == s:TOKEN_PCLOSE - call tokenizer.get() - else - let named = {} - while s:TRUE - let varnode = s:Node(s:NODE_IDENTIFIER) - let token = tokenizer.get() - if token.type == s:TOKEN_IDENTIFIER - if !s:isargname(token.value) || token.value ==# 'firstline' || token.value ==# 'lastline' - throw s:Err(printf('E125: Illegal argument: %s', token.value), token.pos) - elseif has_key(named, token.value) - throw s:Err(printf('E853: Duplicate argument name: %s', token.value), token.pos) - endif - let named[token.value] = 1 - let varnode.pos = token.pos - let varnode.value = token.value - call add(node.rlist, varnode) - " XXX: Vim doesn't skip white space before comma. F(a ,b) => E475 - if s:iswhite(self.reader.p(0)) && tokenizer.peek().type == s:TOKEN_COMMA - throw s:Err('E475: Invalid argument: White space is not allowed before comma', self.reader.getpos()) - endif - let token = tokenizer.get() - if token.type == s:TOKEN_COMMA - " XXX: Vim allows last comma. F(a, b, ) => OK - if tokenizer.peek().type == s:TOKEN_PCLOSE - call tokenizer.get() - break - endif - elseif token.type == s:TOKEN_PCLOSE - break - else - throw s:Err(printf('unexpected token: %s', token.value), token.pos) - endif - elseif token.type == s:TOKEN_DOTDOTDOT - let varnode.pos = token.pos - let varnode.value = token.value - call add(node.rlist, varnode) - let token = tokenizer.get() - if token.type == s:TOKEN_PCLOSE - break - else - throw s:Err(printf('unexpected token: %s', token.value), token.pos) - endif - else - throw s:Err(printf('unexpected token: %s', token.value), token.pos) - endif - endwhile - endif - while s:TRUE - call self.reader.skip_white() - let epos = self.reader.getpos() - let key = self.reader.read_alpha() - if key ==# '' - break - elseif key ==# 'range' - let node.attr.range = s:TRUE - elseif key ==# 'abort' - let node.attr.abort = s:TRUE - elseif key ==# 'dict' - let node.attr.dict = s:TRUE - elseif key ==# 'closure' - let node.attr.closure = s:TRUE - else - throw s:Err(printf('unexpected token: %s', key), epos) - endif - endwhile - call self.add_node(node) - call self.push_context(node) -endfunction - -function! s:VimLParser.parse_cmd_endfunction() - call self.check_missing_endif('ENDFUNCTION', self.ea.cmdpos) - call self.check_missing_endtry('ENDFUNCTION', self.ea.cmdpos) - call self.check_missing_endwhile('ENDFUNCTION', self.ea.cmdpos) - call self.check_missing_endfor('ENDFUNCTION', self.ea.cmdpos) - if self.context[0].type != s:NODE_FUNCTION - throw s:Err('E193: :endfunction not inside a function', self.ea.cmdpos) - endif - call self.reader.getn(-1) - let node = s:Node(s:NODE_ENDFUNCTION) - let node.pos = self.ea.cmdpos - let node.ea = self.ea - let self.context[0].endfunction = node - call self.pop_context() -endfunction - -function! s:VimLParser.parse_cmd_delfunction() - let node = s:Node(s:NODE_DELFUNCTION) - let node.pos = self.ea.cmdpos - let node.ea = self.ea - let node.left = self.parse_lvalue_func() - call self.add_node(node) -endfunction - -function! s:VimLParser.parse_cmd_return() - if self.find_context(s:NODE_FUNCTION) == -1 - throw s:Err('E133: :return not inside a function', self.ea.cmdpos) - endif - let node = s:Node(s:NODE_RETURN) - let node.pos = self.ea.cmdpos - let node.ea = self.ea - let node.left = s:NIL - call self.reader.skip_white() - let c = self.reader.peek() - if c ==# '"' || !self.ends_excmds(c) - let node.left = self.parse_expr() - endif - call self.add_node(node) -endfunction - -function! s:VimLParser.parse_cmd_call() - let node = s:Node(s:NODE_EXCALL) - let node.pos = self.ea.cmdpos - let node.ea = self.ea - call self.reader.skip_white() - let c = self.reader.peek() - if self.ends_excmds(c) - throw s:Err('E471: Argument required', self.reader.getpos()) - endif - let node.left = self.parse_expr() - if node.left.type != s:NODE_CALL - throw s:Err('Not an function call', node.left.pos) - endif - call self.add_node(node) -endfunction - -function! s:VimLParser.parse_cmd_let() - let pos = self.reader.tell() - call self.reader.skip_white() - - " :let - if self.ends_excmds(self.reader.peek()) - call self.reader.seek_set(pos) - call self.parse_cmd_common() - return - endif - - let lhs = self.parse_letlhs() - call self.reader.skip_white() - let s1 = self.reader.peekn(1) - let s2 = self.reader.peekn(2) - - " :let {var-name} .. - if self.ends_excmds(s1) || (s2 !=# '+=' && s2 !=# '-=' && s2 !=# '.=' && s1 !=# '=') - call self.reader.seek_set(pos) - call self.parse_cmd_common() - return - endif - - " :let left op right - let node = s:Node(s:NODE_LET) - let node.pos = self.ea.cmdpos - let node.ea = self.ea - let node.op = '' - let node.left = lhs.left - let node.list = lhs.list - let node.rest = lhs.rest - let node.right = s:NIL - if s2 ==# '+=' || s2 ==# '-=' || s2 ==# '.=' - call self.reader.getn(2) - let node.op = s2 - elseif s1 ==# '=' - call self.reader.getn(1) - let node.op = s1 - else - throw 'NOT REACHED' - endif - let node.right = self.parse_expr() - call self.add_node(node) -endfunction - -function! s:VimLParser.parse_cmd_unlet() - let node = s:Node(s:NODE_UNLET) - let node.pos = self.ea.cmdpos - let node.ea = self.ea - let node.list = self.parse_lvaluelist() - call self.add_node(node) -endfunction - -function! s:VimLParser.parse_cmd_lockvar() - let node = s:Node(s:NODE_LOCKVAR) - let node.pos = self.ea.cmdpos - let node.ea = self.ea - let node.depth = s:NIL - let node.list = [] - call self.reader.skip_white() - if s:isdigit(self.reader.peekn(1)) - let node.depth = str2nr(self.reader.read_digit(), 10) - endif - let node.list = self.parse_lvaluelist() - call self.add_node(node) -endfunction - -function! s:VimLParser.parse_cmd_unlockvar() - let node = s:Node(s:NODE_UNLOCKVAR) - let node.pos = self.ea.cmdpos - let node.ea = self.ea - let node.depth = s:NIL - let node.list = [] - call self.reader.skip_white() - if s:isdigit(self.reader.peekn(1)) - let node.depth = str2nr(self.reader.read_digit(), 10) - endif - let node.list = self.parse_lvaluelist() - call self.add_node(node) -endfunction - -function! s:VimLParser.parse_cmd_if() - let node = s:Node(s:NODE_IF) - let node.pos = self.ea.cmdpos - let node.body = [] - let node.ea = self.ea - let node.cond = self.parse_expr() - let node.elseif = [] - let node.else = s:NIL - let node.endif = s:NIL - call self.add_node(node) - call self.push_context(node) -endfunction - -function! s:VimLParser.parse_cmd_elseif() - if self.context[0].type != s:NODE_IF && self.context[0].type != s:NODE_ELSEIF - throw s:Err('E582: :elseif without :if', self.ea.cmdpos) - endif - if self.context[0].type != s:NODE_IF - call self.pop_context() - endif - let node = s:Node(s:NODE_ELSEIF) - let node.pos = self.ea.cmdpos - let node.body = [] - let node.ea = self.ea - let node.cond = self.parse_expr() - call add(self.context[0].elseif, node) - call self.push_context(node) -endfunction - -function! s:VimLParser.parse_cmd_else() - if self.context[0].type != s:NODE_IF && self.context[0].type != s:NODE_ELSEIF - throw s:Err('E581: :else without :if', self.ea.cmdpos) - endif - if self.context[0].type != s:NODE_IF - call self.pop_context() - endif - let node = s:Node(s:NODE_ELSE) - let node.pos = self.ea.cmdpos - let node.body = [] - let node.ea = self.ea - let self.context[0].else = node - call self.push_context(node) -endfunction - -function! s:VimLParser.parse_cmd_endif() - if self.context[0].type != s:NODE_IF && self.context[0].type != s:NODE_ELSEIF && self.context[0].type != s:NODE_ELSE - throw s:Err('E580: :endif without :if', self.ea.cmdpos) - endif - if self.context[0].type != s:NODE_IF - call self.pop_context() - endif - let node = s:Node(s:NODE_ENDIF) - let node.pos = self.ea.cmdpos - let node.ea = self.ea - let self.context[0].endif = node - call self.pop_context() -endfunction - -function! s:VimLParser.parse_cmd_while() - let node = s:Node(s:NODE_WHILE) - let node.pos = self.ea.cmdpos - let node.body = [] - let node.ea = self.ea - let node.cond = self.parse_expr() - let node.endwhile = s:NIL - call self.add_node(node) - call self.push_context(node) -endfunction - -function! s:VimLParser.parse_cmd_endwhile() - if self.context[0].type != s:NODE_WHILE - throw s:Err('E588: :endwhile without :while', self.ea.cmdpos) - endif - let node = s:Node(s:NODE_ENDWHILE) - let node.pos = self.ea.cmdpos - let node.ea = self.ea - let self.context[0].endwhile = node - call self.pop_context() -endfunction - -function! s:VimLParser.parse_cmd_for() - let node = s:Node(s:NODE_FOR) - let node.pos = self.ea.cmdpos - let node.body = [] - let node.ea = self.ea - let node.left = s:NIL - let node.right = s:NIL - let node.endfor = s:NIL - let lhs = self.parse_letlhs() - let node.left = lhs.left - let node.list = lhs.list - let node.rest = lhs.rest - call self.reader.skip_white() - let epos = self.reader.getpos() - if self.reader.read_alpha() !=# 'in' - throw s:Err('Missing "in" after :for', epos) - endif - let node.right = self.parse_expr() - call self.add_node(node) - call self.push_context(node) -endfunction - -function! s:VimLParser.parse_cmd_endfor() - if self.context[0].type != s:NODE_FOR - throw s:Err('E588: :endfor without :for', self.ea.cmdpos) - endif - let node = s:Node(s:NODE_ENDFOR) - let node.pos = self.ea.cmdpos - let node.ea = self.ea - let self.context[0].endfor = node - call self.pop_context() -endfunction - -function! s:VimLParser.parse_cmd_continue() - if self.find_context(s:NODE_WHILE) == -1 && self.find_context(s:NODE_FOR) == -1 - throw s:Err('E586: :continue without :while or :for', self.ea.cmdpos) - endif - let node = s:Node(s:NODE_CONTINUE) - let node.pos = self.ea.cmdpos - let node.ea = self.ea - call self.add_node(node) -endfunction - -function! s:VimLParser.parse_cmd_break() - if self.find_context(s:NODE_WHILE) == -1 && self.find_context(s:NODE_FOR) == -1 - throw s:Err('E587: :break without :while or :for', self.ea.cmdpos) - endif - let node = s:Node(s:NODE_BREAK) - let node.pos = self.ea.cmdpos - let node.ea = self.ea - call self.add_node(node) -endfunction - -function! s:VimLParser.parse_cmd_try() - let node = s:Node(s:NODE_TRY) - let node.pos = self.ea.cmdpos - let node.body = [] - let node.ea = self.ea - let node.catch = [] - let node.finally = s:NIL - let node.endtry = s:NIL - call self.add_node(node) - call self.push_context(node) -endfunction - -function! s:VimLParser.parse_cmd_catch() - if self.context[0].type == s:NODE_FINALLY - throw s:Err('E604: :catch after :finally', self.ea.cmdpos) - elseif self.context[0].type != s:NODE_TRY && self.context[0].type != s:NODE_CATCH - throw s:Err('E603: :catch without :try', self.ea.cmdpos) - endif - if self.context[0].type != s:NODE_TRY - call self.pop_context() - endif - let node = s:Node(s:NODE_CATCH) - let node.pos = self.ea.cmdpos - let node.body = [] - let node.ea = self.ea - let node.pattern = s:NIL - call self.reader.skip_white() - if !self.ends_excmds(self.reader.peek()) - let [node.pattern, _] = self.parse_pattern(self.reader.get()) - endif - call add(self.context[0].catch, node) - call self.push_context(node) -endfunction - -function! s:VimLParser.parse_cmd_finally() - if self.context[0].type != s:NODE_TRY && self.context[0].type != s:NODE_CATCH - throw s:Err('E606: :finally without :try', self.ea.cmdpos) - endif - if self.context[0].type != s:NODE_TRY - call self.pop_context() - endif - let node = s:Node(s:NODE_FINALLY) - let node.pos = self.ea.cmdpos - let node.body = [] - let node.ea = self.ea - let self.context[0].finally = node - call self.push_context(node) -endfunction - -function! s:VimLParser.parse_cmd_endtry() - if self.context[0].type != s:NODE_TRY && self.context[0].type != s:NODE_CATCH && self.context[0].type != s:NODE_FINALLY - throw s:Err('E602: :endtry without :try', self.ea.cmdpos) - endif - if self.context[0].type != s:NODE_TRY - call self.pop_context() - endif - let node = s:Node(s:NODE_ENDTRY) - let node.pos = self.ea.cmdpos - let node.ea = self.ea - let self.context[0].endtry = node - call self.pop_context() -endfunction - -function! s:VimLParser.parse_cmd_throw() - let node = s:Node(s:NODE_THROW) - let node.pos = self.ea.cmdpos - let node.ea = self.ea - let node.left = self.parse_expr() - call self.add_node(node) -endfunction - -function! s:VimLParser.parse_cmd_echo() - let node = s:Node(s:NODE_ECHO) - let node.pos = self.ea.cmdpos - let node.ea = self.ea - let node.list = self.parse_exprlist() - call self.add_node(node) -endfunction - -function! s:VimLParser.parse_cmd_echon() - let node = s:Node(s:NODE_ECHON) - let node.pos = self.ea.cmdpos - let node.ea = self.ea - let node.list = self.parse_exprlist() - call self.add_node(node) -endfunction - -function! s:VimLParser.parse_cmd_echohl() - let node = s:Node(s:NODE_ECHOHL) - let node.pos = self.ea.cmdpos - let node.ea = self.ea - let node.str = '' - while !self.ends_excmds(self.reader.peek()) - let node.str .= self.reader.get() - endwhile - call self.add_node(node) -endfunction - -function! s:VimLParser.parse_cmd_echomsg() - let node = s:Node(s:NODE_ECHOMSG) - let node.pos = self.ea.cmdpos - let node.ea = self.ea - let node.list = self.parse_exprlist() - call self.add_node(node) -endfunction - -function! s:VimLParser.parse_cmd_echoerr() - let node = s:Node(s:NODE_ECHOERR) - let node.pos = self.ea.cmdpos - let node.ea = self.ea - let node.list = self.parse_exprlist() - call self.add_node(node) -endfunction - -function! s:VimLParser.parse_cmd_execute() - let node = s:Node(s:NODE_EXECUTE) - let node.pos = self.ea.cmdpos - let node.ea = self.ea - let node.list = self.parse_exprlist() - call self.add_node(node) -endfunction - -function! s:VimLParser.parse_expr() - return s:ExprParser.new(self.reader).parse() -endfunction - -function! s:VimLParser.parse_exprlist() - let list = [] - while s:TRUE - call self.reader.skip_white() - let c = self.reader.peek() - if c !=# '"' && self.ends_excmds(c) - break - endif - let node = self.parse_expr() - call add(list, node) - endwhile - return list -endfunction - -function! s:VimLParser.parse_lvalue_func() - let p = s:LvalueParser.new(self.reader) - let node = p.parse() - if node.type == s:NODE_IDENTIFIER || node.type == s:NODE_CURLYNAME || node.type == s:NODE_SUBSCRIPT || node.type == s:NODE_DOT || node.type == s:NODE_OPTION || node.type == s:NODE_ENV || node.type == s:NODE_REG - return node - endif - throw s:Err('Invalid Expression', node.pos) -endfunction - -" FIXME: -function! s:VimLParser.parse_lvalue() - let p = s:LvalueParser.new(self.reader) - let node = p.parse() - if node.type == s:NODE_IDENTIFIER - if !s:isvarname(node.value) - throw s:Err(printf('E461: Illegal variable name: %s', node.value), node.pos) - endif - endif - if node.type == s:NODE_IDENTIFIER || node.type == s:NODE_CURLYNAME || node.type == s:NODE_SUBSCRIPT || node.type == s:NODE_SLICE || node.type == s:NODE_DOT || node.type == s:NODE_OPTION || node.type == s:NODE_ENV || node.type == s:NODE_REG - return node - endif - throw s:Err('Invalid Expression', node.pos) -endfunction - -function! s:VimLParser.parse_lvaluelist() - let list = [] - let node = self.parse_expr() - call add(list, node) - while s:TRUE - call self.reader.skip_white() - if self.ends_excmds(self.reader.peek()) - break - endif - let node = self.parse_lvalue() - call add(list, node) - endwhile - return list -endfunction - -" FIXME: -function! s:VimLParser.parse_letlhs() - let lhs = {'left': s:NIL, 'list': s:NIL, 'rest': s:NIL} - let tokenizer = s:ExprTokenizer.new(self.reader) - if tokenizer.peek().type == s:TOKEN_SQOPEN - call tokenizer.get() - let lhs.list = [] - while s:TRUE - let node = self.parse_lvalue() - call add(lhs.list, node) - let token = tokenizer.get() - if token.type == s:TOKEN_SQCLOSE - break - elseif token.type == s:TOKEN_COMMA - continue - elseif token.type == s:TOKEN_SEMICOLON - let node = self.parse_lvalue() - let lhs.rest = node - let token = tokenizer.get() - if token.type == s:TOKEN_SQCLOSE - break - else - throw s:Err(printf('E475 Invalid argument: %s', token.value), token.pos) - endif - else - throw s:Err(printf('E475 Invalid argument: %s', token.value), token.pos) - endif - endwhile - else - let lhs.left = self.parse_lvalue() - endif - return lhs -endfunction - -function! s:VimLParser.ends_excmds(c) - return a:c ==# '' || a:c ==# '|' || a:c ==# '"' || a:c ==# '<EOF>' || a:c ==# '<EOL>' -endfunction - -" FIXME: validate argument -function! s:VimLParser.parse_wincmd() - let c = self.reader.getn(1) - if c ==# '' - throw s:Err('E471: Argument required', self.reader.getpos()) - elseif c ==# 'g' || c ==# "\x07" " <C-G> - let c2 = self.reader.getn(1) - if c2 ==# '' || s:iswhite(c2) - throw s:Err('E474: Invalid Argument', self.reader.getpos()) - endif - endif - let end = self.reader.getpos() - call self.reader.skip_white() - if !self.ends_excmds(self.reader.peek()) - throw s:Err('E474: Invalid Argument', self.reader.getpos()) - endif - let node = s:Node(s:NODE_EXCMD) - let node.pos = self.ea.cmdpos - let node.ea = self.ea - let node.str = self.reader.getstr(self.ea.linepos, end) - call self.add_node(node) -endfunction - -" FIXME: validate argument -function! s:VimLParser.parse_cmd_syntax() - let end = self.reader.getpos() - while s:TRUE - let end = self.reader.getpos() - let c = self.reader.peek() - if c == "/" || c == "'" || c == "\"" - call self.reader.getn(1) - call self.parse_pattern(c) - elseif c == "=" - call self.reader.getn(1) - call self.parse_pattern(" ") - elseif self.ends_excmds(c) - break - endif - call self.reader.getn(1) - endwhile - let node = s:Node(s:NODE_EXCMD) - let node.pos = self.ea.cmdpos - let node.ea = self.ea - let node.str = self.reader.getstr(self.ea.linepos, end) - call self.add_node(node) -endfunction - -let s:VimLParser.neovim_additional_commands = [ - \ {'name': 'rshada', 'minlen': 3, 'flags': 'BANG|FILE1|TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'wshada', 'minlen': 3, 'flags': 'BANG|FILE1|TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}] - -let s:VimLParser.neovim_removed_commands = [ - \ {'name': 'Print', 'minlen':1, 'flags': 'RANGE|WHOLEFOLD|COUNT|EXFLAGS|TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'fixdel', 'minlen':3, 'flags': 'TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'helpfind', 'minlen':5, 'flags': 'EXTRA|NOTRLCOM', 'parser': 'parse_cmd_common'}, - \ {'name': 'open', 'minlen':1, 'flags': 'RANGE|BANG|EXTRA', 'parser': 'parse_cmd_common'}, - \ {'name': 'shell', 'minlen':2, 'flags': 'TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'tearoff', 'minlen':2, 'flags': 'NEEDARG|EXTRA|TRLBAR|NOTRLCOM|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'gvim', 'minlen':2, 'flags': 'BANG|FILES|EDITCMD|ARGOPT|TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}] - -" To find new builtin_commands, run the below script. -" $ scripts/update_builtin_commands.sh /path/to/vim/src/ex_cmds.h -let s:VimLParser.builtin_commands = [ - \ {'name': 'append', 'minlen': 1, 'flags': 'BANG|RANGE|ZEROR|TRLBAR|CMDWIN|MODIFY', 'parser': 'parse_cmd_append'}, - \ {'name': 'abbreviate', 'minlen': 2, 'flags': 'EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'abclear', 'minlen': 3, 'flags': 'EXTRA|TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'aboveleft', 'minlen': 3, 'flags': 'NEEDARG|EXTRA|NOTRLCOM', 'parser': 'parse_cmd_common'}, - \ {'name': 'all', 'minlen': 2, 'flags': 'BANG|RANGE|NOTADR|COUNT|TRLBAR', 'parser': 'parse_cmd_common'}, - \ {'name': 'amenu', 'minlen': 2, 'flags': 'RANGE|NOTADR|ZEROR|EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'anoremenu', 'minlen': 2, 'flags': 'RANGE|NOTADR|ZEROR|EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'args', 'minlen': 2, 'flags': 'BANG|FILES|EDITCMD|ARGOPT|TRLBAR', 'parser': 'parse_cmd_common'}, - \ {'name': 'argadd', 'minlen': 4, 'flags': 'BANG|NEEDARG|RANGE|NOTADR|ZEROR|FILES|TRLBAR', 'parser': 'parse_cmd_common'}, - \ {'name': 'argdelete', 'minlen': 4, 'flags': 'BANG|RANGE|NOTADR|FILES|TRLBAR', 'parser': 'parse_cmd_common'}, - \ {'name': 'argedit', 'minlen': 4, 'flags': 'BANG|NEEDARG|RANGE|NOTADR|FILE1|EDITCMD|ARGOPT|TRLBAR', 'parser': 'parse_cmd_common'}, - \ {'name': 'argdo', 'minlen': 5, 'flags': 'BANG|NEEDARG|EXTRA|NOTRLCOM', 'parser': 'parse_cmd_common'}, - \ {'name': 'argglobal', 'minlen': 4, 'flags': 'BANG|FILES|EDITCMD|ARGOPT|TRLBAR', 'parser': 'parse_cmd_common'}, - \ {'name': 'arglocal', 'minlen': 4, 'flags': 'BANG|FILES|EDITCMD|ARGOPT|TRLBAR', 'parser': 'parse_cmd_common'}, - \ {'name': 'argument', 'minlen': 4, 'flags': 'BANG|RANGE|NOTADR|COUNT|EXTRA|EDITCMD|ARGOPT|TRLBAR', 'parser': 'parse_cmd_common'}, - \ {'name': 'ascii', 'minlen': 2, 'flags': 'TRLBAR|SBOXOK|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'autocmd', 'minlen': 2, 'flags': 'BANG|EXTRA|NOTRLCOM|USECTRLV|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'augroup', 'minlen': 3, 'flags': 'BANG|WORD1|TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'aunmenu', 'minlen': 3, 'flags': 'EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'buffer', 'minlen': 1, 'flags': 'BANG|RANGE|NOTADR|BUFNAME|BUFUNL|COUNT|EXTRA|TRLBAR', 'parser': 'parse_cmd_common'}, - \ {'name': 'bNext', 'minlen': 2, 'flags': 'BANG|RANGE|NOTADR|COUNT|TRLBAR', 'parser': 'parse_cmd_common'}, - \ {'name': 'ball', 'minlen': 2, 'flags': 'RANGE|NOTADR|COUNT|TRLBAR', 'parser': 'parse_cmd_common'}, - \ {'name': 'badd', 'minlen': 3, 'flags': 'NEEDARG|FILE1|EDITCMD|TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'bdelete', 'minlen': 2, 'flags': 'BANG|RANGE|NOTADR|BUFNAME|COUNT|EXTRA|TRLBAR', 'parser': 'parse_cmd_common'}, - \ {'name': 'behave', 'minlen': 2, 'flags': 'NEEDARG|WORD1|TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'belowright', 'minlen': 3, 'flags': 'NEEDARG|EXTRA|NOTRLCOM', 'parser': 'parse_cmd_common'}, - \ {'name': 'bfirst', 'minlen': 2, 'flags': 'BANG|RANGE|NOTADR|TRLBAR', 'parser': 'parse_cmd_common'}, - \ {'name': 'blast', 'minlen': 2, 'flags': 'BANG|RANGE|NOTADR|TRLBAR', 'parser': 'parse_cmd_common'}, - \ {'name': 'bmodified', 'minlen': 2, 'flags': 'BANG|RANGE|NOTADR|COUNT|TRLBAR', 'parser': 'parse_cmd_common'}, - \ {'name': 'bnext', 'minlen': 2, 'flags': 'BANG|RANGE|NOTADR|COUNT|TRLBAR', 'parser': 'parse_cmd_common'}, - \ {'name': 'botright', 'minlen': 2, 'flags': 'NEEDARG|EXTRA|NOTRLCOM', 'parser': 'parse_cmd_common'}, - \ {'name': 'bprevious', 'minlen': 2, 'flags': 'BANG|RANGE|NOTADR|COUNT|TRLBAR', 'parser': 'parse_cmd_common'}, - \ {'name': 'brewind', 'minlen': 2, 'flags': 'BANG|RANGE|NOTADR|TRLBAR', 'parser': 'parse_cmd_common'}, - \ {'name': 'break', 'minlen': 4, 'flags': 'TRLBAR|SBOXOK|CMDWIN', 'parser': 'parse_cmd_break'}, - \ {'name': 'breakadd', 'minlen': 6, 'flags': 'EXTRA|TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'breakdel', 'minlen': 6, 'flags': 'EXTRA|TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'breaklist', 'minlen': 6, 'flags': 'EXTRA|TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'browse', 'minlen': 3, 'flags': 'NEEDARG|EXTRA|NOTRLCOM|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'bufdo', 'minlen': 5, 'flags': 'BANG|NEEDARG|EXTRA|NOTRLCOM', 'parser': 'parse_cmd_common'}, - \ {'name': 'buffers', 'minlen': 7, 'flags': 'BANG|TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'bunload', 'minlen': 3, 'flags': 'BANG|RANGE|NOTADR|BUFNAME|COUNT|EXTRA|TRLBAR', 'parser': 'parse_cmd_common'}, - \ {'name': 'bwipeout', 'minlen': 2, 'flags': 'BANG|RANGE|NOTADR|BUFNAME|BUFUNL|COUNT|EXTRA|TRLBAR', 'parser': 'parse_cmd_common'}, - \ {'name': 'change', 'minlen': 1, 'flags': 'BANG|WHOLEFOLD|RANGE|COUNT|TRLBAR|CMDWIN|MODIFY', 'parser': 'parse_cmd_common'}, - \ {'name': 'cNext', 'minlen': 2, 'flags': 'RANGE|NOTADR|COUNT|TRLBAR|BANG', 'parser': 'parse_cmd_common'}, - \ {'name': 'cNfile', 'minlen': 3, 'flags': 'RANGE|NOTADR|COUNT|TRLBAR|BANG', 'parser': 'parse_cmd_common'}, - \ {'name': 'cabbrev', 'minlen': 2, 'flags': 'EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'cabclear', 'minlen': 4, 'flags': 'EXTRA|TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'caddbuffer', 'minlen': 3, 'flags': 'RANGE|NOTADR|WORD1|TRLBAR', 'parser': 'parse_cmd_common'}, - \ {'name': 'caddexpr', 'minlen': 5, 'flags': 'NEEDARG|WORD1|NOTRLCOM|TRLBAR', 'parser': 'parse_cmd_common'}, - \ {'name': 'caddfile', 'minlen': 5, 'flags': 'TRLBAR|FILE1', 'parser': 'parse_cmd_common'}, - \ {'name': 'call', 'minlen': 3, 'flags': 'RANGE|NEEDARG|EXTRA|NOTRLCOM|SBOXOK|CMDWIN', 'parser': 'parse_cmd_call'}, - \ {'name': 'catch', 'minlen': 3, 'flags': 'EXTRA|SBOXOK|CMDWIN', 'parser': 'parse_cmd_catch'}, - \ {'name': 'cbuffer', 'minlen': 2, 'flags': 'BANG|RANGE|NOTADR|WORD1|TRLBAR', 'parser': 'parse_cmd_common'}, - \ {'name': 'cc', 'minlen': 2, 'flags': 'RANGE|NOTADR|COUNT|TRLBAR|BANG', 'parser': 'parse_cmd_common'}, - \ {'name': 'cclose', 'minlen': 3, 'flags': 'RANGE|NOTADR|COUNT|TRLBAR', 'parser': 'parse_cmd_common'}, - \ {'name': 'cd', 'minlen': 2, 'flags': 'BANG|FILE1|TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'center', 'minlen': 2, 'flags': 'TRLBAR|RANGE|WHOLEFOLD|EXTRA|CMDWIN|MODIFY', 'parser': 'parse_cmd_common'}, - \ {'name': 'cexpr', 'minlen': 3, 'flags': 'NEEDARG|WORD1|NOTRLCOM|TRLBAR|BANG', 'parser': 'parse_cmd_common'}, - \ {'name': 'cfile', 'minlen': 2, 'flags': 'TRLBAR|FILE1|BANG', 'parser': 'parse_cmd_common'}, - \ {'name': 'cfirst', 'minlen': 4, 'flags': 'RANGE|NOTADR|COUNT|TRLBAR|BANG', 'parser': 'parse_cmd_common'}, - \ {'name': 'cgetbuffer', 'minlen': 5, 'flags': 'RANGE|NOTADR|WORD1|TRLBAR', 'parser': 'parse_cmd_common'}, - \ {'name': 'cgetexpr', 'minlen': 5, 'flags': 'NEEDARG|WORD1|NOTRLCOM|TRLBAR', 'parser': 'parse_cmd_common'}, - \ {'name': 'cgetfile', 'minlen': 2, 'flags': 'TRLBAR|FILE1', 'parser': 'parse_cmd_common'}, - \ {'name': 'changes', 'minlen': 7, 'flags': 'TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'chdir', 'minlen': 3, 'flags': 'BANG|FILE1|TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'checkpath', 'minlen': 3, 'flags': 'TRLBAR|BANG|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'checktime', 'minlen': 6, 'flags': 'RANGE|NOTADR|BUFNAME|COUNT|EXTRA|TRLBAR', 'parser': 'parse_cmd_common'}, - \ {'name': 'clist', 'minlen': 2, 'flags': 'BANG|EXTRA|TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'clast', 'minlen': 3, 'flags': 'RANGE|NOTADR|COUNT|TRLBAR|BANG', 'parser': 'parse_cmd_common'}, - \ {'name': 'close', 'minlen': 3, 'flags': 'BANG|TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'cmap', 'minlen': 2, 'flags': 'EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'cmapclear', 'minlen': 5, 'flags': 'EXTRA|TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'cmenu', 'minlen': 3, 'flags': 'RANGE|NOTADR|ZEROR|EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'cnext', 'minlen': 2, 'flags': 'RANGE|NOTADR|COUNT|TRLBAR|BANG', 'parser': 'parse_cmd_common'}, - \ {'name': 'cnewer', 'minlen': 4, 'flags': 'RANGE|NOTADR|COUNT|TRLBAR', 'parser': 'parse_cmd_common'}, - \ {'name': 'cnfile', 'minlen': 3, 'flags': 'RANGE|NOTADR|COUNT|TRLBAR|BANG', 'parser': 'parse_cmd_common'}, - \ {'name': 'cnoremap', 'minlen': 3, 'flags': 'EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'cnoreabbrev', 'minlen': 6, 'flags': 'EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'cnoremenu', 'minlen': 7, 'flags': 'RANGE|NOTADR|ZEROR|EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'copy', 'minlen': 2, 'flags': 'RANGE|WHOLEFOLD|EXTRA|TRLBAR|CMDWIN|MODIFY', 'parser': 'parse_cmd_common'}, - \ {'name': 'colder', 'minlen': 3, 'flags': 'RANGE|NOTADR|COUNT|TRLBAR', 'parser': 'parse_cmd_common'}, - \ {'name': 'colorscheme', 'minlen': 4, 'flags': 'WORD1|TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'command', 'minlen': 3, 'flags': 'EXTRA|BANG|NOTRLCOM|USECTRLV|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'comclear', 'minlen': 4, 'flags': 'TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'compiler', 'minlen': 4, 'flags': 'BANG|TRLBAR|WORD1|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'continue', 'minlen': 3, 'flags': 'TRLBAR|SBOXOK|CMDWIN', 'parser': 'parse_cmd_continue'}, - \ {'name': 'confirm', 'minlen': 4, 'flags': 'NEEDARG|EXTRA|NOTRLCOM|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'copen', 'minlen': 4, 'flags': 'RANGE|NOTADR|COUNT|TRLBAR', 'parser': 'parse_cmd_common'}, - \ {'name': 'cprevious', 'minlen': 2, 'flags': 'RANGE|NOTADR|COUNT|TRLBAR|BANG', 'parser': 'parse_cmd_common'}, - \ {'name': 'cpfile', 'minlen': 3, 'flags': 'RANGE|NOTADR|COUNT|TRLBAR|BANG', 'parser': 'parse_cmd_common'}, - \ {'name': 'cquit', 'minlen': 2, 'flags': 'TRLBAR|BANG', 'parser': 'parse_cmd_common'}, - \ {'name': 'crewind', 'minlen': 2, 'flags': 'RANGE|NOTADR|COUNT|TRLBAR|BANG', 'parser': 'parse_cmd_common'}, - \ {'name': 'cscope', 'minlen': 2, 'flags': 'EXTRA|NOTRLCOM|XFILE', 'parser': 'parse_cmd_common'}, - \ {'name': 'cstag', 'minlen': 3, 'flags': 'BANG|TRLBAR|WORD1', 'parser': 'parse_cmd_common'}, - \ {'name': 'cunmap', 'minlen': 2, 'flags': 'EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'cunabbrev', 'minlen': 4, 'flags': 'EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'cunmenu', 'minlen': 5, 'flags': 'EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'cwindow', 'minlen': 2, 'flags': 'RANGE|NOTADR|COUNT|TRLBAR', 'parser': 'parse_cmd_common'}, - \ {'name': 'delete', 'minlen': 1, 'flags': 'RANGE|WHOLEFOLD|REGSTR|COUNT|TRLBAR|CMDWIN|MODIFY', 'parser': 'parse_cmd_common'}, - \ {'name': 'delmarks', 'minlen': 4, 'flags': 'BANG|EXTRA|TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'debug', 'minlen': 3, 'flags': 'NEEDARG|EXTRA|NOTRLCOM|SBOXOK|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'debuggreedy', 'minlen': 6, 'flags': 'RANGE|NOTADR|ZEROR|TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'delcommand', 'minlen': 4, 'flags': 'NEEDARG|WORD1|TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'delfunction', 'minlen': 4, 'flags': 'NEEDARG|WORD1|CMDWIN', 'parser': 'parse_cmd_delfunction'}, - \ {'name': 'diffupdate', 'minlen': 3, 'flags': 'BANG|TRLBAR', 'parser': 'parse_cmd_common'}, - \ {'name': 'diffget', 'minlen': 5, 'flags': 'RANGE|EXTRA|TRLBAR|MODIFY', 'parser': 'parse_cmd_common'}, - \ {'name': 'diffoff', 'minlen': 5, 'flags': 'BANG|TRLBAR', 'parser': 'parse_cmd_common'}, - \ {'name': 'diffpatch', 'minlen': 5, 'flags': 'EXTRA|FILE1|TRLBAR|MODIFY', 'parser': 'parse_cmd_common'}, - \ {'name': 'diffput', 'minlen': 6, 'flags': 'RANGE|EXTRA|TRLBAR', 'parser': 'parse_cmd_common'}, - \ {'name': 'diffsplit', 'minlen': 5, 'flags': 'EXTRA|FILE1|TRLBAR', 'parser': 'parse_cmd_common'}, - \ {'name': 'diffthis', 'minlen': 5, 'flags': 'TRLBAR', 'parser': 'parse_cmd_common'}, - \ {'name': 'digraphs', 'minlen': 3, 'flags': 'EXTRA|TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'display', 'minlen': 2, 'flags': 'EXTRA|NOTRLCOM|TRLBAR|SBOXOK|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'djump', 'minlen': 2, 'flags': 'BANG|RANGE|DFLALL|WHOLEFOLD|EXTRA', 'parser': 'parse_cmd_common'}, - \ {'name': 'dlist', 'minlen': 2, 'flags': 'BANG|RANGE|DFLALL|WHOLEFOLD|EXTRA|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'doautocmd', 'minlen': 2, 'flags': 'EXTRA|TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'doautoall', 'minlen': 7, 'flags': 'EXTRA|TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'drop', 'minlen': 2, 'flags': 'FILES|EDITCMD|NEEDARG|ARGOPT|TRLBAR', 'parser': 'parse_cmd_common'}, - \ {'name': 'dsearch', 'minlen': 2, 'flags': 'BANG|RANGE|DFLALL|WHOLEFOLD|EXTRA|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'dsplit', 'minlen': 3, 'flags': 'BANG|RANGE|DFLALL|WHOLEFOLD|EXTRA', 'parser': 'parse_cmd_common'}, - \ {'name': 'edit', 'minlen': 1, 'flags': 'BANG|FILE1|EDITCMD|ARGOPT|TRLBAR', 'parser': 'parse_cmd_common'}, - \ {'name': 'earlier', 'minlen': 2, 'flags': 'TRLBAR|EXTRA|NOSPC|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'echo', 'minlen': 2, 'flags': 'EXTRA|NOTRLCOM|SBOXOK|CMDWIN', 'parser': 'parse_cmd_echo'}, - \ {'name': 'echoerr', 'minlen': 5, 'flags': 'EXTRA|NOTRLCOM|SBOXOK|CMDWIN', 'parser': 'parse_cmd_echoerr'}, - \ {'name': 'echohl', 'minlen': 5, 'flags': 'EXTRA|TRLBAR|SBOXOK|CMDWIN', 'parser': 'parse_cmd_echohl'}, - \ {'name': 'echomsg', 'minlen': 5, 'flags': 'EXTRA|NOTRLCOM|SBOXOK|CMDWIN', 'parser': 'parse_cmd_echomsg'}, - \ {'name': 'echon', 'minlen': 5, 'flags': 'EXTRA|NOTRLCOM|SBOXOK|CMDWIN', 'parser': 'parse_cmd_echon'}, - \ {'name': 'else', 'minlen': 2, 'flags': 'TRLBAR|SBOXOK|CMDWIN', 'parser': 'parse_cmd_else'}, - \ {'name': 'elseif', 'minlen': 5, 'flags': 'EXTRA|NOTRLCOM|SBOXOK|CMDWIN', 'parser': 'parse_cmd_elseif'}, - \ {'name': 'emenu', 'minlen': 2, 'flags': 'NEEDARG|EXTRA|TRLBAR|NOTRLCOM|RANGE|NOTADR|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'endif', 'minlen': 2, 'flags': 'TRLBAR|SBOXOK|CMDWIN', 'parser': 'parse_cmd_endif'}, - \ {'name': 'endfor', 'minlen': 5, 'flags': 'TRLBAR|SBOXOK|CMDWIN', 'parser': 'parse_cmd_endfor'}, - \ {'name': 'endfunction', 'minlen': 4, 'flags': 'TRLBAR|CMDWIN', 'parser': 'parse_cmd_endfunction'}, - \ {'name': 'endtry', 'minlen': 4, 'flags': 'TRLBAR|SBOXOK|CMDWIN', 'parser': 'parse_cmd_endtry'}, - \ {'name': 'endwhile', 'minlen': 4, 'flags': 'TRLBAR|SBOXOK|CMDWIN', 'parser': 'parse_cmd_endwhile'}, - \ {'name': 'enew', 'minlen': 3, 'flags': 'BANG|TRLBAR', 'parser': 'parse_cmd_common'}, - \ {'name': 'ex', 'minlen': 2, 'flags': 'BANG|FILE1|EDITCMD|ARGOPT|TRLBAR', 'parser': 'parse_cmd_common'}, - \ {'name': 'execute', 'minlen': 3, 'flags': 'EXTRA|NOTRLCOM|SBOXOK|CMDWIN', 'parser': 'parse_cmd_execute'}, - \ {'name': 'exit', 'minlen': 3, 'flags': 'RANGE|WHOLEFOLD|BANG|FILE1|ARGOPT|DFLALL|TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'exusage', 'minlen': 3, 'flags': 'TRLBAR', 'parser': 'parse_cmd_common'}, - \ {'name': 'file', 'minlen': 1, 'flags': 'RANGE|NOTADR|ZEROR|BANG|FILE1|TRLBAR', 'parser': 'parse_cmd_common'}, - \ {'name': 'files', 'minlen': 5, 'flags': 'BANG|TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'filetype', 'minlen': 5, 'flags': 'EXTRA|TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'find', 'minlen': 3, 'flags': 'RANGE|NOTADR|BANG|FILE1|EDITCMD|ARGOPT|TRLBAR', 'parser': 'parse_cmd_common'}, - \ {'name': 'finally', 'minlen': 4, 'flags': 'TRLBAR|SBOXOK|CMDWIN', 'parser': 'parse_cmd_finally'}, - \ {'name': 'finish', 'minlen': 4, 'flags': 'TRLBAR|SBOXOK|CMDWIN', 'parser': 'parse_cmd_finish'}, - \ {'name': 'first', 'minlen': 3, 'flags': 'EXTRA|BANG|EDITCMD|ARGOPT|TRLBAR', 'parser': 'parse_cmd_common'}, - \ {'name': 'fixdel', 'minlen': 3, 'flags': 'TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'fold', 'minlen': 2, 'flags': 'RANGE|WHOLEFOLD|TRLBAR|SBOXOK|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'foldclose', 'minlen': 5, 'flags': 'RANGE|BANG|WHOLEFOLD|TRLBAR|SBOXOK|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'folddoopen', 'minlen': 5, 'flags': 'RANGE|DFLALL|NEEDARG|EXTRA|NOTRLCOM', 'parser': 'parse_cmd_common'}, - \ {'name': 'folddoclosed', 'minlen': 7, 'flags': 'RANGE|DFLALL|NEEDARG|EXTRA|NOTRLCOM', 'parser': 'parse_cmd_common'}, - \ {'name': 'foldopen', 'minlen': 5, 'flags': 'RANGE|BANG|WHOLEFOLD|TRLBAR|SBOXOK|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'for', 'minlen': 3, 'flags': 'EXTRA|NOTRLCOM|SBOXOK|CMDWIN', 'parser': 'parse_cmd_for'}, - \ {'name': 'function', 'minlen': 2, 'flags': 'EXTRA|BANG|CMDWIN', 'parser': 'parse_cmd_function'}, - \ {'name': 'global', 'minlen': 1, 'flags': 'RANGE|WHOLEFOLD|BANG|EXTRA|DFLALL|SBOXOK|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'goto', 'minlen': 2, 'flags': 'RANGE|NOTADR|COUNT|TRLBAR|SBOXOK|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'grep', 'minlen': 2, 'flags': 'RANGE|NOTADR|BANG|NEEDARG|EXTRA|NOTRLCOM|TRLBAR|XFILE', 'parser': 'parse_cmd_common'}, - \ {'name': 'grepadd', 'minlen': 5, 'flags': 'RANGE|NOTADR|BANG|NEEDARG|EXTRA|NOTRLCOM|TRLBAR|XFILE', 'parser': 'parse_cmd_common'}, - \ {'name': 'gui', 'minlen': 2, 'flags': 'BANG|FILES|EDITCMD|ARGOPT|TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'gvim', 'minlen': 2, 'flags': 'BANG|FILES|EDITCMD|ARGOPT|TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'hardcopy', 'minlen': 2, 'flags': 'RANGE|COUNT|EXTRA|TRLBAR|DFLALL|BANG', 'parser': 'parse_cmd_common'}, - \ {'name': 'help', 'minlen': 1, 'flags': 'BANG|EXTRA|NOTRLCOM', 'parser': 'parse_cmd_common'}, - \ {'name': 'helpfind', 'minlen': 5, 'flags': 'EXTRA|NOTRLCOM', 'parser': 'parse_cmd_common'}, - \ {'name': 'helpgrep', 'minlen': 5, 'flags': 'EXTRA|NOTRLCOM|NEEDARG', 'parser': 'parse_cmd_common'}, - \ {'name': 'helptags', 'minlen': 5, 'flags': 'NEEDARG|FILES|TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'highlight', 'minlen': 2, 'flags': 'BANG|EXTRA|TRLBAR|SBOXOK|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'hide', 'minlen': 3, 'flags': 'BANG|EXTRA|NOTRLCOM', 'parser': 'parse_cmd_common'}, - \ {'name': 'history', 'minlen': 3, 'flags': 'EXTRA|TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'insert', 'minlen': 1, 'flags': 'BANG|RANGE|TRLBAR|CMDWIN|MODIFY', 'parser': 'parse_cmd_insert'}, - \ {'name': 'iabbrev', 'minlen': 2, 'flags': 'EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'iabclear', 'minlen': 4, 'flags': 'EXTRA|TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'if', 'minlen': 2, 'flags': 'EXTRA|NOTRLCOM|SBOXOK|CMDWIN', 'parser': 'parse_cmd_if'}, - \ {'name': 'ijump', 'minlen': 2, 'flags': 'BANG|RANGE|DFLALL|WHOLEFOLD|EXTRA', 'parser': 'parse_cmd_common'}, - \ {'name': 'ilist', 'minlen': 2, 'flags': 'BANG|RANGE|DFLALL|WHOLEFOLD|EXTRA|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'imap', 'minlen': 2, 'flags': 'EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'imapclear', 'minlen': 5, 'flags': 'EXTRA|TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'imenu', 'minlen': 3, 'flags': 'RANGE|NOTADR|ZEROR|EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'inoremap', 'minlen': 3, 'flags': 'EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'inoreabbrev', 'minlen': 6, 'flags': 'EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'inoremenu', 'minlen': 7, 'flags': 'RANGE|NOTADR|ZEROR|EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'intro', 'minlen': 3, 'flags': 'TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'isearch', 'minlen': 2, 'flags': 'BANG|RANGE|DFLALL|WHOLEFOLD|EXTRA|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'isplit', 'minlen': 3, 'flags': 'BANG|RANGE|DFLALL|WHOLEFOLD|EXTRA', 'parser': 'parse_cmd_common'}, - \ {'name': 'iunmap', 'minlen': 2, 'flags': 'EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'iunabbrev', 'minlen': 4, 'flags': 'EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'iunmenu', 'minlen': 5, 'flags': 'EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'join', 'minlen': 1, 'flags': 'BANG|RANGE|WHOLEFOLD|COUNT|EXFLAGS|TRLBAR|CMDWIN|MODIFY', 'parser': 'parse_cmd_common'}, - \ {'name': 'jumps', 'minlen': 2, 'flags': 'TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'k', 'minlen': 1, 'flags': 'RANGE|WORD1|TRLBAR|SBOXOK|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'keepalt', 'minlen': 5, 'flags': 'NEEDARG|EXTRA|NOTRLCOM', 'parser': 'parse_cmd_common'}, - \ {'name': 'keepmarks', 'minlen': 3, 'flags': 'NEEDARG|EXTRA|NOTRLCOM', 'parser': 'parse_cmd_common'}, - \ {'name': 'keepjumps', 'minlen': 5, 'flags': 'NEEDARG|EXTRA|NOTRLCOM', 'parser': 'parse_cmd_common'}, - \ {'name': 'keeppatterns', 'minlen': 5, 'flags': 'NEEDARG|EXTRA|NOTRLCOM', 'parser': 'parse_cmd_common'}, - \ {'name': 'lNext', 'minlen': 2, 'flags': 'RANGE|NOTADR|COUNT|TRLBAR|BANG', 'parser': 'parse_cmd_common'}, - \ {'name': 'lNfile', 'minlen': 3, 'flags': 'RANGE|NOTADR|COUNT|TRLBAR|BANG', 'parser': 'parse_cmd_common'}, - \ {'name': 'list', 'minlen': 1, 'flags': 'RANGE|WHOLEFOLD|COUNT|EXFLAGS|TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'laddexpr', 'minlen': 3, 'flags': 'NEEDARG|WORD1|NOTRLCOM|TRLBAR', 'parser': 'parse_cmd_common'}, - \ {'name': 'laddbuffer', 'minlen': 5, 'flags': 'RANGE|NOTADR|WORD1|TRLBAR', 'parser': 'parse_cmd_common'}, - \ {'name': 'laddfile', 'minlen': 5, 'flags': 'TRLBAR|FILE1', 'parser': 'parse_cmd_common'}, - \ {'name': 'last', 'minlen': 2, 'flags': 'EXTRA|BANG|EDITCMD|ARGOPT|TRLBAR', 'parser': 'parse_cmd_common'}, - \ {'name': 'language', 'minlen': 3, 'flags': 'EXTRA|TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'later', 'minlen': 3, 'flags': 'TRLBAR|EXTRA|NOSPC|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'lbuffer', 'minlen': 2, 'flags': 'BANG|RANGE|NOTADR|WORD1|TRLBAR', 'parser': 'parse_cmd_common'}, - \ {'name': 'lcd', 'minlen': 2, 'flags': 'BANG|FILE1|TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'lchdir', 'minlen': 3, 'flags': 'BANG|FILE1|TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'lclose', 'minlen': 3, 'flags': 'RANGE|NOTADR|COUNT|TRLBAR', 'parser': 'parse_cmd_common'}, - \ {'name': 'lcscope', 'minlen': 3, 'flags': 'EXTRA|NOTRLCOM|XFILE', 'parser': 'parse_cmd_common'}, - \ {'name': 'left', 'minlen': 2, 'flags': 'TRLBAR|RANGE|WHOLEFOLD|EXTRA|CMDWIN|MODIFY', 'parser': 'parse_cmd_common'}, - \ {'name': 'leftabove', 'minlen': 5, 'flags': 'NEEDARG|EXTRA|NOTRLCOM', 'parser': 'parse_cmd_common'}, - \ {'name': 'let', 'minlen': 3, 'flags': 'EXTRA|NOTRLCOM|SBOXOK|CMDWIN', 'parser': 'parse_cmd_let'}, - \ {'name': 'lexpr', 'minlen': 3, 'flags': 'NEEDARG|WORD1|NOTRLCOM|TRLBAR|BANG', 'parser': 'parse_cmd_common'}, - \ {'name': 'lfile', 'minlen': 2, 'flags': 'TRLBAR|FILE1|BANG', 'parser': 'parse_cmd_common'}, - \ {'name': 'lfirst', 'minlen': 4, 'flags': 'RANGE|NOTADR|COUNT|TRLBAR|BANG', 'parser': 'parse_cmd_common'}, - \ {'name': 'lgetbuffer', 'minlen': 5, 'flags': 'RANGE|NOTADR|WORD1|TRLBAR', 'parser': 'parse_cmd_common'}, - \ {'name': 'lgetexpr', 'minlen': 5, 'flags': 'NEEDARG|WORD1|NOTRLCOM|TRLBAR', 'parser': 'parse_cmd_common'}, - \ {'name': 'lgetfile', 'minlen': 2, 'flags': 'TRLBAR|FILE1', 'parser': 'parse_cmd_common'}, - \ {'name': 'lgrep', 'minlen': 3, 'flags': 'RANGE|NOTADR|BANG|NEEDARG|EXTRA|NOTRLCOM|TRLBAR|XFILE', 'parser': 'parse_cmd_common'}, - \ {'name': 'lgrepadd', 'minlen': 6, 'flags': 'RANGE|NOTADR|BANG|NEEDARG|EXTRA|NOTRLCOM|TRLBAR|XFILE', 'parser': 'parse_cmd_common'}, - \ {'name': 'lhelpgrep', 'minlen': 2, 'flags': 'EXTRA|NOTRLCOM|NEEDARG', 'parser': 'parse_cmd_common'}, - \ {'name': 'll', 'minlen': 2, 'flags': 'RANGE|NOTADR|COUNT|TRLBAR|BANG', 'parser': 'parse_cmd_common'}, - \ {'name': 'llast', 'minlen': 3, 'flags': 'RANGE|NOTADR|COUNT|TRLBAR|BANG', 'parser': 'parse_cmd_common'}, - \ {'name': 'list', 'minlen': 3, 'flags': 'BANG|EXTRA|TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'lmake', 'minlen': 4, 'flags': 'BANG|EXTRA|NOTRLCOM|TRLBAR|XFILE', 'parser': 'parse_cmd_common'}, - \ {'name': 'lmap', 'minlen': 2, 'flags': 'EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'lmapclear', 'minlen': 5, 'flags': 'EXTRA|TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'lnext', 'minlen': 3, 'flags': 'RANGE|NOTADR|COUNT|TRLBAR|BANG', 'parser': 'parse_cmd_common'}, - \ {'name': 'lnewer', 'minlen': 4, 'flags': 'RANGE|NOTADR|COUNT|TRLBAR', 'parser': 'parse_cmd_common'}, - \ {'name': 'lnfile', 'minlen': 3, 'flags': 'RANGE|NOTADR|COUNT|TRLBAR|BANG', 'parser': 'parse_cmd_common'}, - \ {'name': 'lnoremap', 'minlen': 2, 'flags': 'EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'loadkeymap', 'minlen': 5, 'flags': 'CMDWIN', 'parser': 'parse_cmd_loadkeymap'}, - \ {'name': 'loadview', 'minlen': 2, 'flags': 'FILE1|TRLBAR', 'parser': 'parse_cmd_common'}, - \ {'name': 'lockmarks', 'minlen': 3, 'flags': 'NEEDARG|EXTRA|NOTRLCOM', 'parser': 'parse_cmd_common'}, - \ {'name': 'lockvar', 'minlen': 5, 'flags': 'BANG|EXTRA|NEEDARG|SBOXOK|CMDWIN', 'parser': 'parse_cmd_lockvar'}, - \ {'name': 'lolder', 'minlen': 3, 'flags': 'RANGE|NOTADR|COUNT|TRLBAR', 'parser': 'parse_cmd_common'}, - \ {'name': 'lopen', 'minlen': 3, 'flags': 'RANGE|NOTADR|COUNT|TRLBAR', 'parser': 'parse_cmd_common'}, - \ {'name': 'lprevious', 'minlen': 2, 'flags': 'RANGE|NOTADR|COUNT|TRLBAR|BANG', 'parser': 'parse_cmd_common'}, - \ {'name': 'lpfile', 'minlen': 3, 'flags': 'RANGE|NOTADR|COUNT|TRLBAR|BANG', 'parser': 'parse_cmd_common'}, - \ {'name': 'lrewind', 'minlen': 2, 'flags': 'RANGE|NOTADR|COUNT|TRLBAR|BANG', 'parser': 'parse_cmd_common'}, - \ {'name': 'ls', 'minlen': 2, 'flags': 'BANG|TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'ltag', 'minlen': 2, 'flags': 'NOTADR|TRLBAR|BANG|WORD1', 'parser': 'parse_cmd_common'}, - \ {'name': 'lunmap', 'minlen': 2, 'flags': 'EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'lua', 'minlen': 3, 'flags': 'RANGE|EXTRA|NEEDARG|CMDWIN', 'parser': 'parse_cmd_lua'}, - \ {'name': 'luado', 'minlen': 4, 'flags': 'RANGE|DFLALL|EXTRA|NEEDARG|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'luafile', 'minlen': 4, 'flags': 'RANGE|FILE1|NEEDARG|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'lvimgrep', 'minlen': 2, 'flags': 'RANGE|NOTADR|BANG|NEEDARG|EXTRA|NOTRLCOM|TRLBAR|XFILE', 'parser': 'parse_cmd_common'}, - \ {'name': 'lvimgrepadd', 'minlen': 9, 'flags': 'RANGE|NOTADR|BANG|NEEDARG|EXTRA|NOTRLCOM|TRLBAR|XFILE', 'parser': 'parse_cmd_common'}, - \ {'name': 'lwindow', 'minlen': 2, 'flags': 'RANGE|NOTADR|COUNT|TRLBAR', 'parser': 'parse_cmd_common'}, - \ {'name': 'move', 'minlen': 1, 'flags': 'RANGE|WHOLEFOLD|EXTRA|TRLBAR|CMDWIN|MODIFY', 'parser': 'parse_cmd_common'}, - \ {'name': 'mark', 'minlen': 2, 'flags': 'RANGE|WORD1|TRLBAR|SBOXOK|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'make', 'minlen': 3, 'flags': 'BANG|EXTRA|NOTRLCOM|TRLBAR|XFILE', 'parser': 'parse_cmd_common'}, - \ {'name': 'map', 'minlen': 3, 'flags': 'BANG|EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'mapclear', 'minlen': 4, 'flags': 'EXTRA|BANG|TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'marks', 'minlen': 5, 'flags': 'EXTRA|TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'match', 'minlen': 3, 'flags': 'RANGE|NOTADR|EXTRA|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'menu', 'minlen': 2, 'flags': 'RANGE|NOTADR|ZEROR|BANG|EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'menutranslate', 'minlen': 5, 'flags': 'EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'messages', 'minlen': 3, 'flags': 'TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'mkexrc', 'minlen': 2, 'flags': 'BANG|FILE1|TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'mksession', 'minlen': 3, 'flags': 'BANG|FILE1|TRLBAR', 'parser': 'parse_cmd_common'}, - \ {'name': 'mkspell', 'minlen': 4, 'flags': 'BANG|NEEDARG|EXTRA|NOTRLCOM|TRLBAR|XFILE', 'parser': 'parse_cmd_common'}, - \ {'name': 'mkvimrc', 'minlen': 3, 'flags': 'BANG|FILE1|TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'mkview', 'minlen': 5, 'flags': 'BANG|FILE1|TRLBAR', 'parser': 'parse_cmd_common'}, - \ {'name': 'mode', 'minlen': 3, 'flags': 'WORD1|TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'mzscheme', 'minlen': 2, 'flags': 'RANGE|EXTRA|DFLALL|NEEDARG|CMDWIN|SBOXOK', 'parser': 'parse_cmd_mzscheme'}, - \ {'name': 'mzfile', 'minlen': 3, 'flags': 'RANGE|FILE1|NEEDARG|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'nbclose', 'minlen': 3, 'flags': 'TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'nbkey', 'minlen': 2, 'flags': 'EXTRA|NOTADR|NEEDARG', 'parser': 'parse_cmd_common'}, - \ {'name': 'nbstart', 'minlen': 3, 'flags': 'WORD1|TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'next', 'minlen': 1, 'flags': 'RANGE|NOTADR|BANG|FILES|EDITCMD|ARGOPT|TRLBAR', 'parser': 'parse_cmd_common'}, - \ {'name': 'new', 'minlen': 3, 'flags': 'BANG|FILE1|RANGE|NOTADR|EDITCMD|ARGOPT|TRLBAR', 'parser': 'parse_cmd_common'}, - \ {'name': 'nmap', 'minlen': 2, 'flags': 'EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'nmapclear', 'minlen': 5, 'flags': 'EXTRA|TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'nmenu', 'minlen': 3, 'flags': 'RANGE|NOTADR|ZEROR|EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'nnoremap', 'minlen': 2, 'flags': 'EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'nnoremenu', 'minlen': 7, 'flags': 'RANGE|NOTADR|ZEROR|EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'noautocmd', 'minlen': 3, 'flags': 'NEEDARG|EXTRA|NOTRLCOM', 'parser': 'parse_cmd_common'}, - \ {'name': 'noremap', 'minlen': 2, 'flags': 'BANG|EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'nohlsearch', 'minlen': 3, 'flags': 'TRLBAR|SBOXOK|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'noreabbrev', 'minlen': 5, 'flags': 'EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'noremenu', 'minlen': 6, 'flags': 'RANGE|NOTADR|ZEROR|BANG|EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'normal', 'minlen': 4, 'flags': 'RANGE|BANG|EXTRA|NEEDARG|NOTRLCOM|USECTRLV|SBOXOK|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'number', 'minlen': 2, 'flags': 'RANGE|WHOLEFOLD|COUNT|EXFLAGS|TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'nunmap', 'minlen': 3, 'flags': 'EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'nunmenu', 'minlen': 5, 'flags': 'EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'oldfiles', 'minlen': 2, 'flags': 'BANG|TRLBAR|SBOXOK|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'open', 'minlen': 1, 'flags': 'RANGE|BANG|EXTRA', 'parser': 'parse_cmd_common'}, - \ {'name': 'omap', 'minlen': 2, 'flags': 'EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'omapclear', 'minlen': 5, 'flags': 'EXTRA|TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'omenu', 'minlen': 3, 'flags': 'RANGE|NOTADR|ZEROR|EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'only', 'minlen': 2, 'flags': 'BANG|TRLBAR', 'parser': 'parse_cmd_common'}, - \ {'name': 'onoremap', 'minlen': 3, 'flags': 'EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'onoremenu', 'minlen': 7, 'flags': 'RANGE|NOTADR|ZEROR|EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'options', 'minlen': 3, 'flags': 'TRLBAR', 'parser': 'parse_cmd_common'}, - \ {'name': 'ounmap', 'minlen': 2, 'flags': 'EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'ounmenu', 'minlen': 5, 'flags': 'EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'ownsyntax', 'minlen': 2, 'flags': 'EXTRA|NOTRLCOM|SBOXOK|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'pclose', 'minlen': 2, 'flags': 'BANG|TRLBAR', 'parser': 'parse_cmd_common'}, - \ {'name': 'pedit', 'minlen': 3, 'flags': 'BANG|FILE1|EDITCMD|ARGOPT|TRLBAR', 'parser': 'parse_cmd_common'}, - \ {'name': 'perl', 'minlen': 2, 'flags': 'RANGE|EXTRA|DFLALL|NEEDARG|SBOXOK|CMDWIN', 'parser': 'parse_cmd_perl'}, - \ {'name': 'print', 'minlen': 1, 'flags': 'RANGE|WHOLEFOLD|COUNT|EXFLAGS|TRLBAR|CMDWIN|SBOXOK', 'parser': 'parse_cmd_common'}, - \ {'name': 'profdel', 'minlen': 5, 'flags': 'EXTRA|TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'profile', 'minlen': 4, 'flags': 'BANG|EXTRA|TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'promptfind', 'minlen': 3, 'flags': 'EXTRA|NOTRLCOM|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'promptrepl', 'minlen': 7, 'flags': 'EXTRA|NOTRLCOM|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'perldo', 'minlen': 5, 'flags': 'RANGE|EXTRA|DFLALL|NEEDARG|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'pop', 'minlen': 2, 'flags': 'RANGE|NOTADR|BANG|COUNT|TRLBAR|ZEROR', 'parser': 'parse_cmd_common'}, - \ {'name': 'popup', 'minlen': 4, 'flags': 'NEEDARG|EXTRA|BANG|TRLBAR|NOTRLCOM|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'ppop', 'minlen': 2, 'flags': 'RANGE|NOTADR|BANG|COUNT|TRLBAR|ZEROR', 'parser': 'parse_cmd_common'}, - \ {'name': 'preserve', 'minlen': 3, 'flags': 'TRLBAR', 'parser': 'parse_cmd_common'}, - \ {'name': 'previous', 'minlen': 4, 'flags': 'EXTRA|RANGE|NOTADR|COUNT|BANG|EDITCMD|ARGOPT|TRLBAR', 'parser': 'parse_cmd_common'}, - \ {'name': 'psearch', 'minlen': 2, 'flags': 'BANG|RANGE|WHOLEFOLD|DFLALL|EXTRA', 'parser': 'parse_cmd_common'}, - \ {'name': 'ptag', 'minlen': 2, 'flags': 'RANGE|NOTADR|BANG|WORD1|TRLBAR|ZEROR', 'parser': 'parse_cmd_common'}, - \ {'name': 'ptNext', 'minlen': 3, 'flags': 'RANGE|NOTADR|BANG|TRLBAR|ZEROR', 'parser': 'parse_cmd_common'}, - \ {'name': 'ptfirst', 'minlen': 3, 'flags': 'RANGE|NOTADR|BANG|TRLBAR|ZEROR', 'parser': 'parse_cmd_common'}, - \ {'name': 'ptjump', 'minlen': 3, 'flags': 'BANG|TRLBAR|WORD1', 'parser': 'parse_cmd_common'}, - \ {'name': 'ptlast', 'minlen': 3, 'flags': 'BANG|TRLBAR', 'parser': 'parse_cmd_common'}, - \ {'name': 'ptnext', 'minlen': 3, 'flags': 'RANGE|NOTADR|BANG|TRLBAR|ZEROR', 'parser': 'parse_cmd_common'}, - \ {'name': 'ptprevious', 'minlen': 3, 'flags': 'RANGE|NOTADR|BANG|TRLBAR|ZEROR', 'parser': 'parse_cmd_common'}, - \ {'name': 'ptrewind', 'minlen': 3, 'flags': 'RANGE|NOTADR|BANG|TRLBAR|ZEROR', 'parser': 'parse_cmd_common'}, - \ {'name': 'ptselect', 'minlen': 3, 'flags': 'BANG|TRLBAR|WORD1', 'parser': 'parse_cmd_common'}, - \ {'name': 'put', 'minlen': 2, 'flags': 'RANGE|WHOLEFOLD|BANG|REGSTR|TRLBAR|ZEROR|CMDWIN|MODIFY', 'parser': 'parse_cmd_common'}, - \ {'name': 'pwd', 'minlen': 2, 'flags': 'TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'py3', 'minlen': 3, 'flags': 'RANGE|EXTRA|NEEDARG|CMDWIN', 'parser': 'parse_cmd_python3'}, - \ {'name': 'python3', 'minlen': 7, 'flags': 'RANGE|EXTRA|NEEDARG|CMDWIN', 'parser': 'parse_cmd_python3'}, - \ {'name': 'py3file', 'minlen': 4, 'flags': 'RANGE|FILE1|NEEDARG|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'python', 'minlen': 2, 'flags': 'RANGE|EXTRA|NEEDARG|CMDWIN', 'parser': 'parse_cmd_python'}, - \ {'name': 'pyfile', 'minlen': 3, 'flags': 'RANGE|FILE1|NEEDARG|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'pydo', 'minlen': 3, 'flags': 'RANGE|DFLALL|EXTRA|NEEDARG|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'py3do', 'minlen': 4, 'flags': 'RANGE|DFLALL|EXTRA|NEEDARG|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'quit', 'minlen': 1, 'flags': 'BANG|TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'quitall', 'minlen': 5, 'flags': 'BANG|TRLBAR', 'parser': 'parse_cmd_common'}, - \ {'name': 'qall', 'minlen': 2, 'flags': 'BANG|TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'read', 'minlen': 1, 'flags': 'BANG|RANGE|WHOLEFOLD|FILE1|ARGOPT|TRLBAR|ZEROR|CMDWIN|MODIFY', 'parser': 'parse_cmd_common'}, - \ {'name': 'recover', 'minlen': 3, 'flags': 'BANG|FILE1|TRLBAR', 'parser': 'parse_cmd_common'}, - \ {'name': 'redo', 'minlen': 3, 'flags': 'TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'redir', 'minlen': 4, 'flags': 'BANG|FILES|TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'redraw', 'minlen': 4, 'flags': 'BANG|TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'redrawstatus', 'minlen': 7, 'flags': 'BANG|TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'registers', 'minlen': 3, 'flags': 'EXTRA|NOTRLCOM|TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'resize', 'minlen': 3, 'flags': 'RANGE|NOTADR|TRLBAR|WORD1', 'parser': 'parse_cmd_common'}, - \ {'name': 'retab', 'minlen': 3, 'flags': 'TRLBAR|RANGE|WHOLEFOLD|DFLALL|BANG|WORD1|CMDWIN|MODIFY', 'parser': 'parse_cmd_common'}, - \ {'name': 'return', 'minlen': 4, 'flags': 'EXTRA|NOTRLCOM|SBOXOK|CMDWIN', 'parser': 'parse_cmd_return'}, - \ {'name': 'rewind', 'minlen': 3, 'flags': 'EXTRA|BANG|EDITCMD|ARGOPT|TRLBAR', 'parser': 'parse_cmd_common'}, - \ {'name': 'right', 'minlen': 2, 'flags': 'TRLBAR|RANGE|WHOLEFOLD|EXTRA|CMDWIN|MODIFY', 'parser': 'parse_cmd_common'}, - \ {'name': 'rightbelow', 'minlen': 6, 'flags': 'NEEDARG|EXTRA|NOTRLCOM', 'parser': 'parse_cmd_common'}, - \ {'name': 'ruby', 'minlen': 3, 'flags': 'RANGE|EXTRA|NEEDARG|CMDWIN', 'parser': 'parse_cmd_ruby'}, - \ {'name': 'rubydo', 'minlen': 5, 'flags': 'RANGE|DFLALL|EXTRA|NEEDARG|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'rubyfile', 'minlen': 5, 'flags': 'RANGE|FILE1|NEEDARG|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'rundo', 'minlen': 4, 'flags': 'NEEDARG|FILE1', 'parser': 'parse_cmd_common'}, - \ {'name': 'runtime', 'minlen': 2, 'flags': 'BANG|NEEDARG|FILES|TRLBAR|SBOXOK|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'rviminfo', 'minlen': 2, 'flags': 'BANG|FILE1|TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'substitute', 'minlen': 1, 'flags': 'RANGE|WHOLEFOLD|EXTRA|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'sNext', 'minlen': 2, 'flags': 'EXTRA|RANGE|NOTADR|COUNT|BANG|EDITCMD|ARGOPT|TRLBAR', 'parser': 'parse_cmd_common'}, - \ {'name': 'sandbox', 'minlen': 3, 'flags': 'NEEDARG|EXTRA|NOTRLCOM', 'parser': 'parse_cmd_common'}, - \ {'name': 'sargument', 'minlen': 2, 'flags': 'BANG|RANGE|NOTADR|COUNT|EXTRA|EDITCMD|ARGOPT|TRLBAR', 'parser': 'parse_cmd_common'}, - \ {'name': 'sall', 'minlen': 3, 'flags': 'BANG|RANGE|NOTADR|COUNT|TRLBAR', 'parser': 'parse_cmd_common'}, - \ {'name': 'saveas', 'minlen': 3, 'flags': 'BANG|DFLALL|FILE1|ARGOPT|CMDWIN|TRLBAR', 'parser': 'parse_cmd_common'}, - \ {'name': 'sbuffer', 'minlen': 2, 'flags': 'BANG|RANGE|NOTADR|BUFNAME|BUFUNL|COUNT|EXTRA|TRLBAR', 'parser': 'parse_cmd_common'}, - \ {'name': 'sbNext', 'minlen': 3, 'flags': 'RANGE|NOTADR|COUNT|TRLBAR', 'parser': 'parse_cmd_common'}, - \ {'name': 'sball', 'minlen': 3, 'flags': 'RANGE|NOTADR|COUNT|TRLBAR', 'parser': 'parse_cmd_common'}, - \ {'name': 'sbfirst', 'minlen': 3, 'flags': 'TRLBAR', 'parser': 'parse_cmd_common'}, - \ {'name': 'sblast', 'minlen': 3, 'flags': 'TRLBAR', 'parser': 'parse_cmd_common'}, - \ {'name': 'sbmodified', 'minlen': 3, 'flags': 'RANGE|NOTADR|COUNT|TRLBAR', 'parser': 'parse_cmd_common'}, - \ {'name': 'sbnext', 'minlen': 3, 'flags': 'RANGE|NOTADR|COUNT|TRLBAR', 'parser': 'parse_cmd_common'}, - \ {'name': 'sbprevious', 'minlen': 3, 'flags': 'RANGE|NOTADR|COUNT|TRLBAR', 'parser': 'parse_cmd_common'}, - \ {'name': 'sbrewind', 'minlen': 3, 'flags': 'TRLBAR', 'parser': 'parse_cmd_common'}, - \ {'name': 'scriptnames', 'minlen': 3, 'flags': 'TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'scriptencoding', 'minlen': 7, 'flags': 'WORD1|TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'scscope', 'minlen': 3, 'flags': 'EXTRA|NOTRLCOM', 'parser': 'parse_cmd_common'}, - \ {'name': 'set', 'minlen': 2, 'flags': 'TRLBAR|EXTRA|CMDWIN|SBOXOK', 'parser': 'parse_cmd_common'}, - \ {'name': 'setfiletype', 'minlen': 4, 'flags': 'TRLBAR|EXTRA|NEEDARG|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'setglobal', 'minlen': 4, 'flags': 'TRLBAR|EXTRA|CMDWIN|SBOXOK', 'parser': 'parse_cmd_common'}, - \ {'name': 'setlocal', 'minlen': 4, 'flags': 'TRLBAR|EXTRA|CMDWIN|SBOXOK', 'parser': 'parse_cmd_common'}, - \ {'name': 'sfind', 'minlen': 2, 'flags': 'BANG|FILE1|RANGE|NOTADR|EDITCMD|ARGOPT|TRLBAR', 'parser': 'parse_cmd_common'}, - \ {'name': 'sfirst', 'minlen': 4, 'flags': 'EXTRA|BANG|EDITCMD|ARGOPT|TRLBAR', 'parser': 'parse_cmd_common'}, - \ {'name': 'shell', 'minlen': 2, 'flags': 'TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'simalt', 'minlen': 3, 'flags': 'NEEDARG|WORD1|TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'sign', 'minlen': 3, 'flags': 'NEEDARG|RANGE|NOTADR|EXTRA|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'silent', 'minlen': 3, 'flags': 'NEEDARG|EXTRA|BANG|NOTRLCOM|SBOXOK|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'sleep', 'minlen': 2, 'flags': 'RANGE|NOTADR|COUNT|EXTRA|TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'slast', 'minlen': 3, 'flags': 'EXTRA|BANG|EDITCMD|ARGOPT|TRLBAR', 'parser': 'parse_cmd_common'}, - \ {'name': 'smagic', 'minlen': 2, 'flags': 'RANGE|WHOLEFOLD|EXTRA|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'smap', 'minlen': 4, 'flags': 'EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'smapclear', 'minlen': 5, 'flags': 'EXTRA|TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'smenu', 'minlen': 3, 'flags': 'RANGE|NOTADR|ZEROR|EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'snext', 'minlen': 2, 'flags': 'RANGE|NOTADR|BANG|FILES|EDITCMD|ARGOPT|TRLBAR', 'parser': 'parse_cmd_common'}, - \ {'name': 'sniff', 'minlen': 3, 'flags': 'EXTRA|TRLBAR', 'parser': 'parse_cmd_common'}, - \ {'name': 'snomagic', 'minlen': 3, 'flags': 'RANGE|WHOLEFOLD|EXTRA|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'snoremap', 'minlen': 4, 'flags': 'EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'snoremenu', 'minlen': 7, 'flags': 'RANGE|NOTADR|ZEROR|EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'sort', 'minlen': 3, 'flags': 'RANGE|DFLALL|WHOLEFOLD|BANG|EXTRA|NOTRLCOM|MODIFY', 'parser': 'parse_cmd_common'}, - \ {'name': 'source', 'minlen': 2, 'flags': 'BANG|FILE1|TRLBAR|SBOXOK|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'spelldump', 'minlen': 6, 'flags': 'BANG|TRLBAR', 'parser': 'parse_cmd_common'}, - \ {'name': 'spellgood', 'minlen': 3, 'flags': 'BANG|RANGE|NOTADR|NEEDARG|EXTRA|TRLBAR', 'parser': 'parse_cmd_common'}, - \ {'name': 'spellinfo', 'minlen': 6, 'flags': 'TRLBAR', 'parser': 'parse_cmd_common'}, - \ {'name': 'spellrepall', 'minlen': 6, 'flags': 'TRLBAR', 'parser': 'parse_cmd_common'}, - \ {'name': 'spellundo', 'minlen': 6, 'flags': 'BANG|RANGE|NOTADR|NEEDARG|EXTRA|TRLBAR', 'parser': 'parse_cmd_common'}, - \ {'name': 'spellwrong', 'minlen': 6, 'flags': 'BANG|RANGE|NOTADR|NEEDARG|EXTRA|TRLBAR', 'parser': 'parse_cmd_common'}, - \ {'name': 'split', 'minlen': 2, 'flags': 'BANG|FILE1|RANGE|NOTADR|EDITCMD|ARGOPT|TRLBAR', 'parser': 'parse_cmd_common'}, - \ {'name': 'sprevious', 'minlen': 3, 'flags': 'EXTRA|RANGE|NOTADR|COUNT|BANG|EDITCMD|ARGOPT|TRLBAR', 'parser': 'parse_cmd_common'}, - \ {'name': 'srewind', 'minlen': 3, 'flags': 'EXTRA|BANG|EDITCMD|ARGOPT|TRLBAR', 'parser': 'parse_cmd_common'}, - \ {'name': 'stop', 'minlen': 2, 'flags': 'TRLBAR|BANG|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'stag', 'minlen': 3, 'flags': 'RANGE|NOTADR|BANG|WORD1|TRLBAR|ZEROR', 'parser': 'parse_cmd_common'}, - \ {'name': 'startinsert', 'minlen': 4, 'flags': 'BANG|TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'startgreplace', 'minlen': 6, 'flags': 'BANG|TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'startreplace', 'minlen': 6, 'flags': 'BANG|TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'stopinsert', 'minlen': 5, 'flags': 'BANG|TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'stjump', 'minlen': 3, 'flags': 'BANG|TRLBAR|WORD1', 'parser': 'parse_cmd_common'}, - \ {'name': 'stselect', 'minlen': 3, 'flags': 'BANG|TRLBAR|WORD1', 'parser': 'parse_cmd_common'}, - \ {'name': 'sunhide', 'minlen': 3, 'flags': 'RANGE|NOTADR|COUNT|TRLBAR', 'parser': 'parse_cmd_common'}, - \ {'name': 'sunmap', 'minlen': 4, 'flags': 'EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'sunmenu', 'minlen': 5, 'flags': 'EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'suspend', 'minlen': 3, 'flags': 'TRLBAR|BANG|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'sview', 'minlen': 2, 'flags': 'BANG|FILE1|RANGE|NOTADR|EDITCMD|ARGOPT|TRLBAR', 'parser': 'parse_cmd_common'}, - \ {'name': 'swapname', 'minlen': 2, 'flags': 'TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'syntax', 'minlen': 2, 'flags': 'EXTRA|NOTRLCOM|CMDWIN', 'parser': 'parse_cmd_syntax'}, - \ {'name': 'syntime', 'minlen': 5, 'flags': 'NEEDARG|WORD1|TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'syncbind', 'minlen': 4, 'flags': 'TRLBAR', 'parser': 'parse_cmd_common'}, - \ {'name': 't', 'minlen': 1, 'flags': 'RANGE|WHOLEFOLD|EXTRA|TRLBAR|CMDWIN|MODIFY', 'parser': 'parse_cmd_common'}, - \ {'name': 'tNext', 'minlen': 2, 'flags': 'RANGE|NOTADR|BANG|TRLBAR|ZEROR', 'parser': 'parse_cmd_common'}, - \ {'name': 'tabNext', 'minlen': 4, 'flags': 'RANGE|NOTADR|COUNT|TRLBAR', 'parser': 'parse_cmd_common'}, - \ {'name': 'tabclose', 'minlen': 4, 'flags': 'RANGE|NOTADR|COUNT|BANG|TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'tabdo', 'minlen': 4, 'flags': 'NEEDARG|EXTRA|NOTRLCOM', 'parser': 'parse_cmd_common'}, - \ {'name': 'tabedit', 'minlen': 4, 'flags': 'BANG|FILE1|RANGE|NOTADR|ZEROR|EDITCMD|ARGOPT|TRLBAR', 'parser': 'parse_cmd_common'}, - \ {'name': 'tabfind', 'minlen': 4, 'flags': 'BANG|FILE1|RANGE|NOTADR|ZEROR|EDITCMD|ARGOPT|NEEDARG|TRLBAR', 'parser': 'parse_cmd_common'}, - \ {'name': 'tabfirst', 'minlen': 6, 'flags': 'TRLBAR', 'parser': 'parse_cmd_common'}, - \ {'name': 'tablast', 'minlen': 4, 'flags': 'TRLBAR', 'parser': 'parse_cmd_common'}, - \ {'name': 'tabmove', 'minlen': 4, 'flags': 'RANGE|NOTADR|ZEROR|EXTRA|NOSPC|TRLBAR', 'parser': 'parse_cmd_common'}, - \ {'name': 'tabnew', 'minlen': 6, 'flags': 'BANG|FILE1|RANGE|NOTADR|ZEROR|EDITCMD|ARGOPT|TRLBAR', 'parser': 'parse_cmd_common'}, - \ {'name': 'tabnext', 'minlen': 4, 'flags': 'RANGE|NOTADR|COUNT|TRLBAR', 'parser': 'parse_cmd_common'}, - \ {'name': 'tabonly', 'minlen': 4, 'flags': 'BANG|TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'tabprevious', 'minlen': 4, 'flags': 'RANGE|NOTADR|COUNT|TRLBAR', 'parser': 'parse_cmd_common'}, - \ {'name': 'tabrewind', 'minlen': 4, 'flags': 'TRLBAR', 'parser': 'parse_cmd_common'}, - \ {'name': 'tabs', 'minlen': 4, 'flags': 'TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'tab', 'minlen': 3, 'flags': 'NEEDARG|EXTRA|NOTRLCOM', 'parser': 'parse_cmd_common'}, - \ {'name': 'tag', 'minlen': 2, 'flags': 'RANGE|NOTADR|BANG|WORD1|TRLBAR|ZEROR', 'parser': 'parse_cmd_common'}, - \ {'name': 'tags', 'minlen': 4, 'flags': 'TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'tcl', 'minlen': 2, 'flags': 'RANGE|EXTRA|NEEDARG|CMDWIN', 'parser': 'parse_cmd_tcl'}, - \ {'name': 'tcldo', 'minlen': 4, 'flags': 'RANGE|DFLALL|EXTRA|NEEDARG|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'tclfile', 'minlen': 4, 'flags': 'RANGE|FILE1|NEEDARG|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'tearoff', 'minlen': 2, 'flags': 'NEEDARG|EXTRA|TRLBAR|NOTRLCOM|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'tfirst', 'minlen': 2, 'flags': 'RANGE|NOTADR|BANG|TRLBAR|ZEROR', 'parser': 'parse_cmd_common'}, - \ {'name': 'throw', 'minlen': 2, 'flags': 'EXTRA|NEEDARG|SBOXOK|CMDWIN', 'parser': 'parse_cmd_throw'}, - \ {'name': 'tjump', 'minlen': 2, 'flags': 'BANG|TRLBAR|WORD1', 'parser': 'parse_cmd_common'}, - \ {'name': 'tlast', 'minlen': 2, 'flags': 'BANG|TRLBAR', 'parser': 'parse_cmd_common'}, - \ {'name': 'tmenu', 'minlen': 2, 'flags': 'RANGE|NOTADR|ZEROR|EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'tnext', 'minlen': 2, 'flags': 'RANGE|NOTADR|BANG|TRLBAR|ZEROR', 'parser': 'parse_cmd_common'}, - \ {'name': 'topleft', 'minlen': 2, 'flags': 'NEEDARG|EXTRA|NOTRLCOM', 'parser': 'parse_cmd_common'}, - \ {'name': 'tprevious', 'minlen': 2, 'flags': 'RANGE|NOTADR|BANG|TRLBAR|ZEROR', 'parser': 'parse_cmd_common'}, - \ {'name': 'trewind', 'minlen': 2, 'flags': 'RANGE|NOTADR|BANG|TRLBAR|ZEROR', 'parser': 'parse_cmd_common'}, - \ {'name': 'try', 'minlen': 3, 'flags': 'TRLBAR|SBOXOK|CMDWIN', 'parser': 'parse_cmd_try'}, - \ {'name': 'tselect', 'minlen': 2, 'flags': 'BANG|TRLBAR|WORD1', 'parser': 'parse_cmd_common'}, - \ {'name': 'tunmenu', 'minlen': 2, 'flags': 'EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'undo', 'minlen': 1, 'flags': 'RANGE|NOTADR|COUNT|ZEROR|TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'undojoin', 'minlen': 5, 'flags': 'TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'undolist', 'minlen': 5, 'flags': 'TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'unabbreviate', 'minlen': 3, 'flags': 'EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'unhide', 'minlen': 3, 'flags': 'RANGE|NOTADR|COUNT|TRLBAR', 'parser': 'parse_cmd_common'}, - \ {'name': 'unlet', 'minlen': 3, 'flags': 'BANG|EXTRA|NEEDARG|SBOXOK|CMDWIN', 'parser': 'parse_cmd_unlet'}, - \ {'name': 'unlockvar', 'minlen': 4, 'flags': 'BANG|EXTRA|NEEDARG|SBOXOK|CMDWIN', 'parser': 'parse_cmd_unlockvar'}, - \ {'name': 'unmap', 'minlen': 3, 'flags': 'BANG|EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'unmenu', 'minlen': 4, 'flags': 'BANG|EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'unsilent', 'minlen': 3, 'flags': 'NEEDARG|EXTRA|NOTRLCOM|SBOXOK|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'update', 'minlen': 2, 'flags': 'RANGE|WHOLEFOLD|BANG|FILE1|ARGOPT|DFLALL|TRLBAR', 'parser': 'parse_cmd_common'}, - \ {'name': 'vglobal', 'minlen': 1, 'flags': 'RANGE|WHOLEFOLD|EXTRA|DFLALL|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'version', 'minlen': 2, 'flags': 'EXTRA|TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'verbose', 'minlen': 4, 'flags': 'NEEDARG|RANGE|NOTADR|EXTRA|NOTRLCOM|SBOXOK|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'vertical', 'minlen': 4, 'flags': 'NEEDARG|EXTRA|NOTRLCOM', 'parser': 'parse_cmd_common'}, - \ {'name': 'vimgrep', 'minlen': 3, 'flags': 'RANGE|NOTADR|BANG|NEEDARG|EXTRA|NOTRLCOM|TRLBAR|XFILE', 'parser': 'parse_cmd_common'}, - \ {'name': 'vimgrepadd', 'minlen': 8, 'flags': 'RANGE|NOTADR|BANG|NEEDARG|EXTRA|NOTRLCOM|TRLBAR|XFILE', 'parser': 'parse_cmd_common'}, - \ {'name': 'visual', 'minlen': 2, 'flags': 'BANG|FILE1|EDITCMD|ARGOPT|TRLBAR', 'parser': 'parse_cmd_common'}, - \ {'name': 'viusage', 'minlen': 3, 'flags': 'TRLBAR', 'parser': 'parse_cmd_common'}, - \ {'name': 'view', 'minlen': 3, 'flags': 'BANG|FILE1|EDITCMD|ARGOPT|TRLBAR', 'parser': 'parse_cmd_common'}, - \ {'name': 'vmap', 'minlen': 2, 'flags': 'EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'vmapclear', 'minlen': 5, 'flags': 'EXTRA|TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'vmenu', 'minlen': 3, 'flags': 'RANGE|NOTADR|ZEROR|EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'vnew', 'minlen': 3, 'flags': 'BANG|FILE1|RANGE|NOTADR|EDITCMD|ARGOPT|TRLBAR', 'parser': 'parse_cmd_common'}, - \ {'name': 'vnoremap', 'minlen': 2, 'flags': 'EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'vnoremenu', 'minlen': 7, 'flags': 'RANGE|NOTADR|ZEROR|EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'vsplit', 'minlen': 2, 'flags': 'BANG|FILE1|RANGE|NOTADR|EDITCMD|ARGOPT|TRLBAR', 'parser': 'parse_cmd_common'}, - \ {'name': 'vunmap', 'minlen': 2, 'flags': 'EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'vunmenu', 'minlen': 5, 'flags': 'EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'windo', 'minlen': 5, 'flags': 'BANG|NEEDARG|EXTRA|NOTRLCOM', 'parser': 'parse_cmd_common'}, - \ {'name': 'write', 'minlen': 1, 'flags': 'RANGE|WHOLEFOLD|BANG|FILE1|ARGOPT|DFLALL|TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'wNext', 'minlen': 2, 'flags': 'RANGE|WHOLEFOLD|NOTADR|BANG|FILE1|ARGOPT|TRLBAR', 'parser': 'parse_cmd_common'}, - \ {'name': 'wall', 'minlen': 2, 'flags': 'BANG|TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'while', 'minlen': 2, 'flags': 'EXTRA|NOTRLCOM|SBOXOK|CMDWIN', 'parser': 'parse_cmd_while'}, - \ {'name': 'winsize', 'minlen': 2, 'flags': 'EXTRA|NEEDARG|TRLBAR', 'parser': 'parse_cmd_common'}, - \ {'name': 'wincmd', 'minlen': 4, 'flags': 'NEEDARG|WORD1|RANGE|NOTADR', 'parser': 'parse_wincmd'}, - \ {'name': 'winpos', 'minlen': 4, 'flags': 'EXTRA|TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'wnext', 'minlen': 2, 'flags': 'RANGE|NOTADR|BANG|FILE1|ARGOPT|TRLBAR', 'parser': 'parse_cmd_common'}, - \ {'name': 'wprevious', 'minlen': 2, 'flags': 'RANGE|NOTADR|BANG|FILE1|ARGOPT|TRLBAR', 'parser': 'parse_cmd_common'}, - \ {'name': 'wq', 'minlen': 2, 'flags': 'RANGE|WHOLEFOLD|BANG|FILE1|ARGOPT|DFLALL|TRLBAR', 'parser': 'parse_cmd_common'}, - \ {'name': 'wqall', 'minlen': 3, 'flags': 'BANG|FILE1|ARGOPT|DFLALL|TRLBAR', 'parser': 'parse_cmd_common'}, - \ {'name': 'wsverb', 'minlen': 2, 'flags': 'EXTRA|NOTADR|NEEDARG', 'parser': 'parse_cmd_common'}, - \ {'name': 'wundo', 'minlen': 2, 'flags': 'BANG|NEEDARG|FILE1', 'parser': 'parse_cmd_common'}, - \ {'name': 'wviminfo', 'minlen': 2, 'flags': 'BANG|FILE1|TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'xit', 'minlen': 1, 'flags': 'RANGE|WHOLEFOLD|BANG|FILE1|ARGOPT|DFLALL|TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'xall', 'minlen': 2, 'flags': 'BANG|TRLBAR', 'parser': 'parse_cmd_common'}, - \ {'name': 'xmapclear', 'minlen': 5, 'flags': 'EXTRA|TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'xmap', 'minlen': 2, 'flags': 'EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'xmenu', 'minlen': 3, 'flags': 'RANGE|NOTADR|ZEROR|EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'xnoremap', 'minlen': 2, 'flags': 'EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'xnoremenu', 'minlen': 7, 'flags': 'RANGE|NOTADR|ZEROR|EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'xunmap', 'minlen': 2, 'flags': 'EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'xunmenu', 'minlen': 5, 'flags': 'EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'yank', 'minlen': 1, 'flags': 'RANGE|WHOLEFOLD|REGSTR|COUNT|TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'z', 'minlen': 1, 'flags': 'RANGE|WHOLEFOLD|EXTRA|EXFLAGS|TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': '!', 'minlen': 1, 'flags': 'RANGE|WHOLEFOLD|BANG|FILES|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': '#', 'minlen': 1, 'flags': 'RANGE|WHOLEFOLD|COUNT|EXFLAGS|TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': '&', 'minlen': 1, 'flags': 'RANGE|WHOLEFOLD|EXTRA|CMDWIN|MODIFY', 'parser': 'parse_cmd_common'}, - \ {'name': '*', 'minlen': 1, 'flags': 'RANGE|WHOLEFOLD|EXTRA|TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': '<', 'minlen': 1, 'flags': 'RANGE|WHOLEFOLD|COUNT|EXFLAGS|TRLBAR|CMDWIN|MODIFY', 'parser': 'parse_cmd_common'}, - \ {'name': '=', 'minlen': 1, 'flags': 'RANGE|TRLBAR|DFLALL|EXFLAGS|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': '>', 'minlen': 1, 'flags': 'RANGE|WHOLEFOLD|COUNT|EXFLAGS|TRLBAR|CMDWIN|MODIFY', 'parser': 'parse_cmd_common'}, - \ {'name': '@', 'minlen': 1, 'flags': 'RANGE|WHOLEFOLD|EXTRA|TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'Next', 'minlen': 1, 'flags': 'EXTRA|RANGE|NOTADR|COUNT|BANG|EDITCMD|ARGOPT|TRLBAR', 'parser': 'parse_cmd_common'}, - \ {'name': 'Print', 'minlen': 1, 'flags': 'RANGE|WHOLEFOLD|COUNT|EXFLAGS|TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, - \ {'name': 'X', 'minlen': 1, 'flags': 'TRLBAR', 'parser': 'parse_cmd_common'}, - \ {'name': '~', 'minlen': 1, 'flags': 'RANGE|WHOLEFOLD|EXTRA|CMDWIN|MODIFY', 'parser': 'parse_cmd_common'}, - \ - \ {'flags': 'TRLBAR', 'minlen': 3, 'name': 'cbottom', 'parser': 'parse_cmd_common'}, - \ {'flags': 'BANG|NEEDARG|EXTRA|NOTRLCOM|RANGE|NOTADR|DFLALL', 'minlen': 3, 'name': 'cdo', 'parser': 'parse_cmd_common'}, - \ {'flags': 'BANG|NEEDARG|EXTRA|NOTRLCOM|RANGE|NOTADR|DFLALL', 'minlen': 3, 'name': 'cfdo', 'parser': 'parse_cmd_common'}, - \ {'flags': 'TRLBAR', 'minlen': 3, 'name': 'chistory', 'parser': 'parse_cmd_common'}, - \ {'flags': 'TRLBAR|CMDWIN', 'minlen': 3, 'name': 'clearjumps', 'parser': 'parse_cmd_common'}, - \ {'flags': 'BANG|NEEDARG|EXTRA|NOTRLCOM', 'minlen': 4, 'name': 'filter', 'parser': 'parse_cmd_common'}, - \ {'flags': 'RANGE|NOTADR|COUNT|TRLBAR', 'minlen': 5, 'name': 'helpclose', 'parser': 'parse_cmd_common'}, - \ {'flags': 'TRLBAR', 'minlen': 3, 'name': 'lbottom', 'parser': 'parse_cmd_common'}, - \ {'flags': 'BANG|NEEDARG|EXTRA|NOTRLCOM|RANGE|NOTADR|DFLALL', 'minlen': 2, 'name': 'ldo', 'parser': 'parse_cmd_common'}, - \ {'flags': 'BANG|NEEDARG|EXTRA|NOTRLCOM|RANGE|NOTADR|DFLALL', 'minlen': 3, 'name': 'lfdo', 'parser': 'parse_cmd_common'}, - \ {'flags': 'TRLBAR', 'minlen': 3, 'name': 'lhistory', 'parser': 'parse_cmd_common'}, - \ {'flags': 'BANG|EXTRA|TRLBAR|CMDWIN', 'minlen': 3, 'name': 'llist', 'parser': 'parse_cmd_common'}, - \ {'flags': 'NEEDARG|EXTRA|NOTRLCOM', 'minlen': 3, 'name': 'noswapfile', 'parser': 'parse_cmd_common'}, - \ {'flags': 'BANG|FILE1|NEEDARG|TRLBAR|SBOXOK|CMDWIN', 'minlen': 2, 'name': 'packadd', 'parser': 'parse_cmd_common'}, - \ {'flags': 'BANG|TRLBAR|SBOXOK|CMDWIN', 'minlen': 5, 'name': 'packloadall', 'parser': 'parse_cmd_common'}, - \ {'flags': 'TRLBAR|CMDWIN|SBOXOK', 'minlen': 3, 'name': 'smile', 'parser': 'parse_cmd_common'}, - \ {'flags': 'RANGE|EXTRA|NEEDARG|CMDWIN', 'minlen': 3, 'name': 'pyx', 'parser': 'parse_cmd_common'}, - \ {'flags': 'RANGE|DFLALL|EXTRA|NEEDARG|CMDWIN', 'minlen': 4, 'name': 'pyxdo', 'parser': 'parse_cmd_common'}, - \ {'flags': 'RANGE|EXTRA|NEEDARG|CMDWIN', 'minlen': 7, 'name': 'pythonx', 'parser': 'parse_cmd_common'}, - \ {'flags': 'RANGE|FILE1|NEEDARG|CMDWIN', 'minlen': 4, 'name': 'pyxfile', 'parser': 'parse_cmd_common'}, - \ {'flags': 'RANGE|BANG|FILES|CMDWIN', 'minlen': 3, 'name': 'terminal', 'parser': 'parse_cmd_common'}, - \ {'flags': 'EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN', 'minlen': 3, 'name': 'tmap', 'parser': 'parse_cmd_common'}, - \ {'flags': 'EXTRA|TRLBAR|CMDWIN', 'minlen': 5, 'name': 'tmapclear', 'parser': 'parse_cmd_common'}, - \ {'flags': 'EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN', 'minlen': 3, 'name': 'tnoremap', 'parser': 'parse_cmd_common'}, - \ {'flags': 'EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN', 'minlen': 5, 'name': 'tunmap', 'parser': 'parse_cmd_common'}, - \] - -let s:ExprTokenizer = {} - -function! s:ExprTokenizer.new(...) - let obj = copy(self) - call call(obj.__init__, a:000, obj) - return obj -endfunction - -function! s:ExprTokenizer.__init__(reader) - let self.reader = a:reader - let self.cache = {} -endfunction - -function! s:ExprTokenizer.token(type, value, pos) - return {'type': a:type, 'value': a:value, 'pos': a:pos} -endfunction - -function! s:ExprTokenizer.peek() - let pos = self.reader.tell() - let r = self.get() - call self.reader.seek_set(pos) - return r -endfunction - -function! s:ExprTokenizer.get() - " FIXME: remove dirty hack - if has_key(self.cache, self.reader.tell()) - let x = self.cache[self.reader.tell()] - call self.reader.seek_set(x[0]) - return x[1] - endif - let pos = self.reader.tell() - call self.reader.skip_white() - let r = self.get2() - let self.cache[pos] = [self.reader.tell(), r] - return r -endfunction - -function! s:ExprTokenizer.get2() - let r = self.reader - let pos = r.getpos() - let c = r.peek() - if c ==# '<EOF>' - return self.token(s:TOKEN_EOF, c, pos) - elseif c ==# '<EOL>' - call r.seek_cur(1) - return self.token(s:TOKEN_EOL, c, pos) - elseif s:iswhite(c) - let s = r.read_white() - return self.token(s:TOKEN_SPACE, s, pos) - elseif c ==# '0' && (r.p(1) ==# 'X' || r.p(1) ==# 'x') && s:isxdigit(r.p(2)) - let s = r.getn(3) - let s .= r.read_xdigit() - return self.token(s:TOKEN_NUMBER, s, pos) - elseif s:isdigit(c) - let s = r.read_digit() - if r.p(0) ==# '.' && s:isdigit(r.p(1)) - let s .= r.getn(1) - let s .= r.read_digit() - if (r.p(0) ==# 'E' || r.p(0) ==# 'e') && (s:isdigit(r.p(1)) || ((r.p(1) ==# '-' || r.p(1) ==# '+') && s:isdigit(r.p(2)))) - let s .= r.getn(2) - let s .= r.read_digit() - endif - endif - return self.token(s:TOKEN_NUMBER, s, pos) - elseif c ==# 'i' && r.p(1) ==# 's' && !s:isidc(r.p(2)) - if r.p(2) ==# '?' - call r.seek_cur(3) - return self.token(s:TOKEN_ISCI, 'is?', pos) - elseif r.p(2) ==# '#' - call r.seek_cur(3) - return self.token(s:TOKEN_ISCS, 'is#', pos) - else - call r.seek_cur(2) - return self.token(s:TOKEN_IS, 'is', pos) - endif - elseif c ==# 'i' && r.p(1) ==# 's' && r.p(2) ==# 'n' && r.p(3) ==# 'o' && r.p(4) ==# 't' && !s:isidc(r.p(5)) - if r.p(5) ==# '?' - call r.seek_cur(6) - return self.token(s:TOKEN_ISNOTCI, 'isnot?', pos) - elseif r.p(5) ==# '#' - call r.seek_cur(6) - return self.token(s:TOKEN_ISNOTCS, 'isnot#', pos) - else - call r.seek_cur(5) - return self.token(s:TOKEN_ISNOT, 'isnot', pos) - endif - elseif s:isnamec1(c) - let s = r.read_name() - return self.token(s:TOKEN_IDENTIFIER, s, pos) - elseif c ==# '|' && r.p(1) ==# '|' - call r.seek_cur(2) - return self.token(s:TOKEN_OROR, '||', pos) - elseif c ==# '&' && r.p(1) ==# '&' - call r.seek_cur(2) - return self.token(s:TOKEN_ANDAND, '&&', pos) - elseif c ==# '=' && r.p(1) ==# '=' - if r.p(2) ==# '?' - call r.seek_cur(3) - return self.token(s:TOKEN_EQEQCI, '==?', pos) - elseif r.p(2) ==# '#' - call r.seek_cur(3) - return self.token(s:TOKEN_EQEQCS, '==#', pos) - else - call r.seek_cur(2) - return self.token(s:TOKEN_EQEQ, '==', pos) - endif - elseif c ==# '!' && r.p(1) ==# '=' - if r.p(2) ==# '?' - call r.seek_cur(3) - return self.token(s:TOKEN_NEQCI, '!=?', pos) - elseif r.p(2) ==# '#' - call r.seek_cur(3) - return self.token(s:TOKEN_NEQCS, '!=#', pos) - else - call r.seek_cur(2) - return self.token(s:TOKEN_NEQ, '!=', pos) - endif - elseif c ==# '>' && r.p(1) ==# '=' - if r.p(2) ==# '?' - call r.seek_cur(3) - return self.token(s:TOKEN_GTEQCI, '>=?', pos) - elseif r.p(2) ==# '#' - call r.seek_cur(3) - return self.token(s:TOKEN_GTEQCS, '>=#', pos) - else - call r.seek_cur(2) - return self.token(s:TOKEN_GTEQ, '>=', pos) - endif - elseif c ==# '<' && r.p(1) ==# '=' - if r.p(2) ==# '?' - call r.seek_cur(3) - return self.token(s:TOKEN_LTEQCI, '<=?', pos) - elseif r.p(2) ==# '#' - call r.seek_cur(3) - return self.token(s:TOKEN_LTEQCS, '<=#', pos) - else - call r.seek_cur(2) - return self.token(s:TOKEN_LTEQ, '<=', pos) - endif - elseif c ==# '=' && r.p(1) ==# '~' - if r.p(2) ==# '?' - call r.seek_cur(3) - return self.token(s:TOKEN_MATCHCI, '=~?', pos) - elseif r.p(2) ==# '#' - call r.seek_cur(3) - return self.token(s:TOKEN_MATCHCS, '=~#', pos) - else - call r.seek_cur(2) - return self.token(s:TOKEN_MATCH, '=~', pos) - endif - elseif c ==# '!' && r.p(1) ==# '~' - if r.p(2) ==# '?' - call r.seek_cur(3) - return self.token(s:TOKEN_NOMATCHCI, '!~?', pos) - elseif r.p(2) ==# '#' - call r.seek_cur(3) - return self.token(s:TOKEN_NOMATCHCS, '!~#', pos) - else - call r.seek_cur(2) - return self.token(s:TOKEN_NOMATCH, '!~', pos) - endif - elseif c ==# '>' - if r.p(1) ==# '?' - call r.seek_cur(2) - return self.token(s:TOKEN_GTCI, '>?', pos) - elseif r.p(1) ==# '#' - call r.seek_cur(2) - return self.token(s:TOKEN_GTCS, '>#', pos) - else - call r.seek_cur(1) - return self.token(s:TOKEN_GT, '>', pos) - endif - elseif c ==# '<' - if r.p(1) ==# '?' - call r.seek_cur(2) - return self.token(s:TOKEN_LTCI, '<?', pos) - elseif r.p(1) ==# '#' - call r.seek_cur(2) - return self.token(s:TOKEN_LTCS, '<#', pos) - else - call r.seek_cur(1) - return self.token(s:TOKEN_LT, '<', pos) - endif - elseif c ==# '+' - call r.seek_cur(1) - return self.token(s:TOKEN_PLUS, '+', pos) - elseif c ==# '-' - if r.p(1) ==# '>' - call r.seek_cur(2) - return self.token(s:TOKEN_ARROW, '->', pos) - else - call r.seek_cur(1) - return self.token(s:TOKEN_MINUS, '-', pos) - endif - elseif c ==# '.' - if r.p(1) ==# '.' && r.p(2) ==# '.' - call r.seek_cur(3) - return self.token(s:TOKEN_DOTDOTDOT, '...', pos) - else - call r.seek_cur(1) - return self.token(s:TOKEN_DOT, '.', pos) - endif - elseif c ==# '*' - call r.seek_cur(1) - return self.token(s:TOKEN_STAR, '*', pos) - elseif c ==# '/' - call r.seek_cur(1) - return self.token(s:TOKEN_SLASH, '/', pos) - elseif c ==# '%' - call r.seek_cur(1) - return self.token(s:TOKEN_PERCENT, '%', pos) - elseif c ==# '!' - call r.seek_cur(1) - return self.token(s:TOKEN_NOT, '!', pos) - elseif c ==# '?' - call r.seek_cur(1) - return self.token(s:TOKEN_QUESTION, '?', pos) - elseif c ==# ':' - call r.seek_cur(1) - return self.token(s:TOKEN_COLON, ':', pos) - elseif c ==# '#' - call r.seek_cur(1) - return self.token(s:TOKEN_SHARP, '#', pos) - elseif c ==# '(' - call r.seek_cur(1) - return self.token(s:TOKEN_POPEN, '(', pos) - elseif c ==# ')' - call r.seek_cur(1) - return self.token(s:TOKEN_PCLOSE, ')', pos) - elseif c ==# '[' - call r.seek_cur(1) - return self.token(s:TOKEN_SQOPEN, '[', pos) - elseif c ==# ']' - call r.seek_cur(1) - return self.token(s:TOKEN_SQCLOSE, ']', pos) - elseif c ==# '{' - call r.seek_cur(1) - return self.token(s:TOKEN_COPEN, '{', pos) - elseif c ==# '}' - call r.seek_cur(1) - return self.token(s:TOKEN_CCLOSE, '}', pos) - elseif c ==# ',' - call r.seek_cur(1) - return self.token(s:TOKEN_COMMA, ',', pos) - elseif c ==# "'" - call r.seek_cur(1) - return self.token(s:TOKEN_SQUOTE, "'", pos) - elseif c ==# '"' - call r.seek_cur(1) - return self.token(s:TOKEN_DQUOTE, '"', pos) - elseif c ==# '$' - let s = r.getn(1) - let s .= r.read_word() - return self.token(s:TOKEN_ENV, s, pos) - elseif c ==# '@' - " @<EOL> is treated as @" - return self.token(s:TOKEN_REG, r.getn(2), pos) - elseif c ==# '&' - let s = '' - if (r.p(1) ==# 'g' || r.p(1) ==# 'l') && r.p(2) ==# ':' - let s = r.getn(3) . r.read_word() - else - let s = r.getn(1) . r.read_word() - endif - return self.token(s:TOKEN_OPTION, s, pos) - elseif c ==# '=' - call r.seek_cur(1) - return self.token(s:TOKEN_EQ, '=', pos) - elseif c ==# '|' - call r.seek_cur(1) - return self.token(s:TOKEN_OR, '|', pos) - elseif c ==# ';' - call r.seek_cur(1) - return self.token(s:TOKEN_SEMICOLON, ';', pos) - elseif c ==# '`' - call r.seek_cur(1) - return self.token(s:TOKEN_BACKTICK, '`', pos) - else - throw s:Err(printf('unexpected character: %s', c), self.reader.getpos()) - endif -endfunction - -function! s:ExprTokenizer.get_sstring() - call self.reader.skip_white() - let c = self.reader.p(0) - if c !=# "'" - throw s:Err(printf('unexpected character: %s', c), self.reader.getpos()) - endif - call self.reader.seek_cur(1) - let s = '' - while s:TRUE - let c = self.reader.p(0) - if c ==# '<EOF>' || c ==# '<EOL>' - throw s:Err('unexpected EOL', self.reader.getpos()) - elseif c ==# "'" - call self.reader.seek_cur(1) - if self.reader.p(0) ==# "'" - call self.reader.seek_cur(1) - let s .= "''" - else - break - endif - else - call self.reader.seek_cur(1) - let s .= c - endif - endwhile - return s -endfunction - -function! s:ExprTokenizer.get_dstring() - call self.reader.skip_white() - let c = self.reader.p(0) - if c !=# '"' - throw s:Err(printf('unexpected character: %s', c), self.reader.getpos()) - endif - call self.reader.seek_cur(1) - let s = '' - while s:TRUE - let c = self.reader.p(0) - if c ==# '<EOF>' || c ==# '<EOL>' - throw s:Err('unexpectd EOL', self.reader.getpos()) - elseif c ==# '"' - call self.reader.seek_cur(1) - break - elseif c ==# '\' - call self.reader.seek_cur(1) - let s .= c - let c = self.reader.p(0) - if c ==# '<EOF>' || c ==# '<EOL>' - throw s:Err('ExprTokenizer: unexpected EOL', self.reader.getpos()) - endif - call self.reader.seek_cur(1) - let s .= c - else - call self.reader.seek_cur(1) - let s .= c - endif - endwhile - return s -endfunction - -let s:ExprParser = {} - -function! s:ExprParser.new(...) - let obj = copy(self) - call call(obj.__init__, a:000, obj) - return obj -endfunction - -function! s:ExprParser.__init__(reader) - let self.reader = a:reader - let self.tokenizer = s:ExprTokenizer.new(a:reader) -endfunction - -function! s:ExprParser.parse() - return self.parse_expr1() -endfunction - -" expr1: expr2 ? expr1 : expr1 -function! s:ExprParser.parse_expr1() - let left = self.parse_expr2() - let pos = self.reader.tell() - let token = self.tokenizer.get() - if token.type == s:TOKEN_QUESTION - let node = s:Node(s:NODE_TERNARY) - let node.pos = token.pos - let node.cond = left - let node.left = self.parse_expr1() - let token = self.tokenizer.get() - if token.type != s:TOKEN_COLON - throw s:Err(printf('unexpected token: %s', token.value), token.pos) - endif - let node.right = self.parse_expr1() - let left = node - else - call self.reader.seek_set(pos) - endif - return left -endfunction - -" expr2: expr3 || expr3 .. -function! s:ExprParser.parse_expr2() - let left = self.parse_expr3() - while s:TRUE - let pos = self.reader.tell() - let token = self.tokenizer.get() - if token.type == s:TOKEN_OROR - let node = s:Node(s:NODE_OR) - let node.pos = token.pos - let node.left = left - let node.right = self.parse_expr3() - let left = node - else - call self.reader.seek_set(pos) - break - endif - endwhile - return left -endfunction - -" expr3: expr4 && expr4 -function! s:ExprParser.parse_expr3() - let left = self.parse_expr4() - while s:TRUE - let pos = self.reader.tell() - let token = self.tokenizer.get() - if token.type == s:TOKEN_ANDAND - let node = s:Node(s:NODE_AND) - let node.pos = token.pos - let node.left = left - let node.right = self.parse_expr4() - let left = node - else - call self.reader.seek_set(pos) - break - endif - endwhile - return left -endfunction - -" expr4: expr5 == expr5 -" expr5 != expr5 -" expr5 > expr5 -" expr5 >= expr5 -" expr5 < expr5 -" expr5 <= expr5 -" expr5 =~ expr5 -" expr5 !~ expr5 -" -" expr5 ==? expr5 -" expr5 ==# expr5 -" etc. -" -" expr5 is expr5 -" expr5 isnot expr5 -function! s:ExprParser.parse_expr4() - let left = self.parse_expr5() - let pos = self.reader.tell() - let token = self.tokenizer.get() - if token.type == s:TOKEN_EQEQ - let node = s:Node(s:NODE_EQUAL) - let node.pos = token.pos - let node.left = left - let node.right = self.parse_expr5() - let left = node - elseif token.type == s:TOKEN_EQEQCI - let node = s:Node(s:NODE_EQUALCI) - let node.pos = token.pos - let node.left = left - let node.right = self.parse_expr5() - let left = node - elseif token.type == s:TOKEN_EQEQCS - let node = s:Node(s:NODE_EQUALCS) - let node.pos = token.pos - let node.left = left - let node.right = self.parse_expr5() - let left = node - elseif token.type == s:TOKEN_NEQ - let node = s:Node(s:NODE_NEQUAL) - let node.pos = token.pos - let node.left = left - let node.right = self.parse_expr5() - let left = node - elseif token.type == s:TOKEN_NEQCI - let node = s:Node(s:NODE_NEQUALCI) - let node.pos = token.pos - let node.left = left - let node.right = self.parse_expr5() - let left = node - elseif token.type == s:TOKEN_NEQCS - let node = s:Node(s:NODE_NEQUALCS) - let node.pos = token.pos - let node.left = left - let node.right = self.parse_expr5() - let left = node - elseif token.type == s:TOKEN_GT - let node = s:Node(s:NODE_GREATER) - let node.pos = token.pos - let node.left = left - let node.right = self.parse_expr5() - let left = node - elseif token.type == s:TOKEN_GTCI - let node = s:Node(s:NODE_GREATERCI) - let node.pos = token.pos - let node.left = left - let node.right = self.parse_expr5() - let left = node - elseif token.type == s:TOKEN_GTCS - let node = s:Node(s:NODE_GREATERCS) - let node.pos = token.pos - let node.left = left - let node.right = self.parse_expr5() - let left = node - elseif token.type == s:TOKEN_GTEQ - let node = s:Node(s:NODE_GEQUAL) - let node.pos = token.pos - let node.left = left - let node.right = self.parse_expr5() - let left = node - elseif token.type == s:TOKEN_GTEQCI - let node = s:Node(s:NODE_GEQUALCI) - let node.pos = token.pos - let node.left = left - let node.right = self.parse_expr5() - let left = node - elseif token.type == s:TOKEN_GTEQCS - let node = s:Node(s:NODE_GEQUALCS) - let node.pos = token.pos - let node.left = left - let node.right = self.parse_expr5() - let left = node - elseif token.type == s:TOKEN_LT - let node = s:Node(s:NODE_SMALLER) - let node.pos = token.pos - let node.left = left - let node.right = self.parse_expr5() - let left = node - elseif token.type == s:TOKEN_LTCI - let node = s:Node(s:NODE_SMALLERCI) - let node.pos = token.pos - let node.left = left - let node.right = self.parse_expr5() - let left = node - elseif token.type == s:TOKEN_LTCS - let node = s:Node(s:NODE_SMALLERCS) - let node.pos = token.pos - let node.left = left - let node.right = self.parse_expr5() - let left = node - elseif token.type == s:TOKEN_LTEQ - let node = s:Node(s:NODE_SEQUAL) - let node.pos = token.pos - let node.left = left - let node.right = self.parse_expr5() - let left = node - elseif token.type == s:TOKEN_LTEQCI - let node = s:Node(s:NODE_SEQUALCI) - let node.pos = token.pos - let node.left = left - let node.right = self.parse_expr5() - let left = node - elseif token.type == s:TOKEN_LTEQCS - let node = s:Node(s:NODE_SEQUALCS) - let node.pos = token.pos - let node.left = left - let node.right = self.parse_expr5() - let left = node - elseif token.type == s:TOKEN_MATCH - let node = s:Node(s:NODE_MATCH) - let node.pos = token.pos - let node.left = left - let node.right = self.parse_expr5() - let left = node - elseif token.type == s:TOKEN_MATCHCI - let node = s:Node(s:NODE_MATCHCI) - let node.pos = token.pos - let node.left = left - let node.right = self.parse_expr5() - let left = node - elseif token.type == s:TOKEN_MATCHCS - let node = s:Node(s:NODE_MATCHCS) - let node.pos = token.pos - let node.left = left - let node.right = self.parse_expr5() - let left = node - elseif token.type == s:TOKEN_NOMATCH - let node = s:Node(s:NODE_NOMATCH) - let node.pos = token.pos - let node.left = left - let node.right = self.parse_expr5() - let left = node - elseif token.type == s:TOKEN_NOMATCHCI - let node = s:Node(s:NODE_NOMATCHCI) - let node.pos = token.pos - let node.left = left - let node.right = self.parse_expr5() - let left = node - elseif token.type == s:TOKEN_NOMATCHCS - let node = s:Node(s:NODE_NOMATCHCS) - let node.pos = token.pos - let node.left = left - let node.right = self.parse_expr5() - let left = node - elseif token.type == s:TOKEN_IS - let node = s:Node(s:NODE_IS) - let node.pos = token.pos - let node.left = left - let node.right = self.parse_expr5() - let left = node - elseif token.type == s:TOKEN_ISCI - let node = s:Node(s:NODE_ISCI) - let node.pos = token.pos - let node.left = left - let node.right = self.parse_expr5() - let left = node - elseif token.type == s:TOKEN_ISCS - let node = s:Node(s:NODE_ISCS) - let node.pos = token.pos - let node.left = left - let node.right = self.parse_expr5() - let left = node - elseif token.type == s:TOKEN_ISNOT - let node = s:Node(s:NODE_ISNOT) - let node.pos = token.pos - let node.left = left - let node.right = self.parse_expr5() - let left = node - elseif token.type == s:TOKEN_ISNOTCI - let node = s:Node(s:NODE_ISNOTCI) - let node.pos = token.pos - let node.left = left - let node.right = self.parse_expr5() - let left = node - elseif token.type == s:TOKEN_ISNOTCS - let node = s:Node(s:NODE_ISNOTCS) - let node.pos = token.pos - let node.left = left - let node.right = self.parse_expr5() - let left = node - else - call self.reader.seek_set(pos) - endif - return left -endfunction - -" expr5: expr6 + expr6 .. -" expr6 - expr6 .. -" expr6 . expr6 .. -function! s:ExprParser.parse_expr5() - let left = self.parse_expr6() - while s:TRUE - let pos = self.reader.tell() - let token = self.tokenizer.get() - if token.type == s:TOKEN_PLUS - let node = s:Node(s:NODE_ADD) - let node.pos = token.pos - let node.left = left - let node.right = self.parse_expr6() - let left = node - elseif token.type == s:TOKEN_MINUS - let node = s:Node(s:NODE_SUBTRACT) - let node.pos = token.pos - let node.left = left - let node.right = self.parse_expr6() - let left = node - elseif token.type == s:TOKEN_DOT - let node = s:Node(s:NODE_CONCAT) - let node.pos = token.pos - let node.left = left - let node.right = self.parse_expr6() - let left = node - else - call self.reader.seek_set(pos) - break - endif - endwhile - return left -endfunction - -" expr6: expr7 * expr7 .. -" expr7 / expr7 .. -" expr7 % expr7 .. -function! s:ExprParser.parse_expr6() - let left = self.parse_expr7() - while s:TRUE - let pos = self.reader.tell() - let token = self.tokenizer.get() - if token.type == s:TOKEN_STAR - let node = s:Node(s:NODE_MULTIPLY) - let node.pos = token.pos - let node.left = left - let node.right = self.parse_expr7() - let left = node - elseif token.type == s:TOKEN_SLASH - let node = s:Node(s:NODE_DIVIDE) - let node.pos = token.pos - let node.left = left - let node.right = self.parse_expr7() - let left = node - elseif token.type == s:TOKEN_PERCENT - let node = s:Node(s:NODE_REMAINDER) - let node.pos = token.pos - let node.left = left - let node.right = self.parse_expr7() - let left = node - else - call self.reader.seek_set(pos) - break - endif - endwhile - return left -endfunction - -" expr7: ! expr7 -" - expr7 -" + expr7 -function! s:ExprParser.parse_expr7() - let pos = self.reader.tell() - let token = self.tokenizer.get() - if token.type == s:TOKEN_NOT - let node = s:Node(s:NODE_NOT) - let node.pos = token.pos - let node.left = self.parse_expr7() - return node - elseif token.type == s:TOKEN_MINUS - let node = s:Node(s:NODE_MINUS) - let node.pos = token.pos - let node.left = self.parse_expr7() - return node - elseif token.type == s:TOKEN_PLUS - let node = s:Node(s:NODE_PLUS) - let node.pos = token.pos - let node.left = self.parse_expr7() - return node - else - call self.reader.seek_set(pos) - let node = self.parse_expr8() - return node - endif -endfunction - -" expr8: expr8[expr1] -" expr8[expr1 : expr1] -" expr8.name -" expr8(expr1, ...) -function! s:ExprParser.parse_expr8() - let left = self.parse_expr9() - while s:TRUE - let pos = self.reader.tell() - let c = self.reader.peek() - let token = self.tokenizer.get() - if !s:iswhite(c) && token.type == s:TOKEN_SQOPEN - let npos = token.pos - if self.tokenizer.peek().type == s:TOKEN_COLON - call self.tokenizer.get() - let node = s:Node(s:NODE_SLICE) - let node.pos = npos - let node.left = left - let node.rlist = [s:NIL, s:NIL] - let token = self.tokenizer.peek() - if token.type != s:TOKEN_SQCLOSE - let node.rlist[1] = self.parse_expr1() - endif - let token = self.tokenizer.get() - if token.type != s:TOKEN_SQCLOSE - throw s:Err(printf('unexpected token: %s', token.value), token.pos) - endif - let left = node - else - let right = self.parse_expr1() - if self.tokenizer.peek().type == s:TOKEN_COLON - call self.tokenizer.get() - let node = s:Node(s:NODE_SLICE) - let node.pos = npos - let node.left = left - let node.rlist = [right, s:NIL] - let token = self.tokenizer.peek() - if token.type != s:TOKEN_SQCLOSE - let node.rlist[1] = self.parse_expr1() - endif - let token = self.tokenizer.get() - if token.type != s:TOKEN_SQCLOSE - throw s:Err(printf('unexpected token: %s', token.value), token.pos) - endif - let left = node - else - let node = s:Node(s:NODE_SUBSCRIPT) - let node.pos = npos - let node.left = left - let node.right = right - let token = self.tokenizer.get() - if token.type != s:TOKEN_SQCLOSE - throw s:Err(printf('unexpected token: %s', token.value), token.pos) - endif - let left = node - endif - endif - unlet node - elseif token.type == s:TOKEN_POPEN - let node = s:Node(s:NODE_CALL) - let node.pos = token.pos - let node.left = left - let node.rlist = [] - if self.tokenizer.peek().type == s:TOKEN_PCLOSE - call self.tokenizer.get() - else - while s:TRUE - call add(node.rlist, self.parse_expr1()) - let token = self.tokenizer.get() - if token.type == s:TOKEN_COMMA - " XXX: Vim allows foo(a, b, ). Lint should warn it. - if self.tokenizer.peek().type == s:TOKEN_PCLOSE - call self.tokenizer.get() - break - endif - elseif token.type == s:TOKEN_PCLOSE - break - else - throw s:Err(printf('unexpected token: %s', token.value), token.pos) - endif - endwhile - endif - if len(node.rlist) > s:MAX_FUNC_ARGS - " TODO: funcname E740: Too many arguments for function: %s - throw s:Err('E740: Too many arguments for function', node.pos) - endif - let left = node - unlet node - elseif !s:iswhite(c) && token.type == s:TOKEN_DOT - let node = self.parse_dot(token, left) - if node is s:NIL - call self.reader.seek_set(pos) - break - endif - let left = node - unlet node - else - call self.reader.seek_set(pos) - break - endif - endwhile - return left -endfunction - -" expr9: number -" "string" -" 'string' -" [expr1, ...] -" {expr1: expr1, ...} -" {args -> expr1} -" &option -" (expr1) -" variable -" var{ria}ble -" $VAR -" @r -" function(expr1, ...) -" func{ti}on(expr1, ...) -function! s:ExprParser.parse_expr9() - let pos = self.reader.tell() - let token = self.tokenizer.get() - let node = s:Node(-1) - if token.type == s:TOKEN_NUMBER - let node = s:Node(s:NODE_NUMBER) - let node.pos = token.pos - let node.value = token.value - elseif token.type == s:TOKEN_DQUOTE - call self.reader.seek_set(pos) - let node = s:Node(s:NODE_STRING) - let node.pos = token.pos - let node.value = '"' . self.tokenizer.get_dstring() . '"' - elseif token.type == s:TOKEN_SQUOTE - call self.reader.seek_set(pos) - let node = s:Node(s:NODE_STRING) - let node.pos = token.pos - let node.value = "'" . self.tokenizer.get_sstring() . "'" - elseif token.type == s:TOKEN_SQOPEN - let node = s:Node(s:NODE_LIST) - let node.pos = token.pos - let node.value = [] - let token = self.tokenizer.peek() - if token.type == s:TOKEN_SQCLOSE - call self.tokenizer.get() - else - while s:TRUE - call add(node.value, self.parse_expr1()) - let token = self.tokenizer.peek() - if token.type == s:TOKEN_COMMA - call self.tokenizer.get() - if self.tokenizer.peek().type == s:TOKEN_SQCLOSE - call self.tokenizer.get() - break - endif - elseif token.type == s:TOKEN_SQCLOSE - call self.tokenizer.get() - break - else - throw s:Err(printf('unexpected token: %s', token.value), token.pos) - endif - endwhile - endif - elseif token.type == s:TOKEN_COPEN - let savepos = self.reader.tell() - let nodepos = token.pos - let token = self.tokenizer.get() - let lambda = token.type == s:TOKEN_ARROW - if !lambda && !(token.type == s:TOKEN_SQUOTE || token.type == s:TOKEN_DQUOTE) - " if the token type is stirng, we cannot peek next token and we can - " assume it's not lambda. - let token2 = self.tokenizer.peek() - let lambda = token2.type == s:TOKEN_ARROW || token2.type == s:TOKEN_COMMA - endif - " fallback to dict or {expr} if true - let fallback = s:FALSE - if lambda - " lambda {token,...} {->...} {token->...} - let node = s:Node(s:NODE_LAMBDA) - let node.pos = nodepos - let node.rlist = [] - let named = {} - while s:TRUE - if token.type == s:TOKEN_ARROW - break - elseif token.type == s:TOKEN_IDENTIFIER - if !s:isargname(token.value) - throw s:Err(printf('E125: Illegal argument: %s', token.value), token.pos) - elseif has_key(named, token.value) - throw s:Err(printf('E853: Duplicate argument name: %s', token.value), token.pos) - endif - let named[token.value] = 1 - let varnode = s:Node(s:NODE_IDENTIFIER) - let varnode.pos = token.pos - let varnode.value = token.value - " XXX: Vim doesn't skip white space before comma. {a ,b -> ...} => E475 - if s:iswhite(self.reader.p(0)) && self.tokenizer.peek().type == s:TOKEN_COMMA - throw s:Err('E475: Invalid argument: White space is not allowed before comma', self.reader.getpos()) - endif - let token = self.tokenizer.get() - call add(node.rlist, varnode) - if token.type == s:TOKEN_COMMA - " XXX: Vim allows last comma. {a, b, -> ...} => OK - let token = self.tokenizer.peek() - if token.type == s:TOKEN_ARROW - call self.tokenizer.get() - break - endif - elseif token.type == s:TOKEN_ARROW - break - else - throw s:Err(printf('unexpected token: %s, type: %d', token.value, token.type), token.pos) - endif - elseif token.type == s:TOKEN_DOTDOTDOT - let varnode = s:Node(s:NODE_IDENTIFIER) - let varnode.pos = token.pos - let varnode.value = token.value - call add(node.rlist, varnode) - let token = self.tokenizer.peek() - if token.type == s:TOKEN_ARROW - call self.tokenizer.get() - break - else - throw s:Err(printf('unexpected token: %s', token.value), token.pos) - endif - else - let fallback = s:TRUE - break - endif - let token = self.tokenizer.get() - endwhile - if !fallback - let node.left = self.parse_expr1() - let token = self.tokenizer.get() - if token.type != s:TOKEN_CCLOSE - throw s:Err(printf('unexpected token: %s', token.value), token.pos) - endif - return node - endif - endif - " dict - let node = s:Node(s:NODE_DICT) - let node.pos = nodepos - let node.value = [] - call self.reader.seek_set(savepos) - let token = self.tokenizer.peek() - if token.type == s:TOKEN_CCLOSE - call self.tokenizer.get() - return node - endif - while 1 - let key = self.parse_expr1() - let token = self.tokenizer.get() - if token.type == s:TOKEN_CCLOSE - if !empty(node.value) - throw s:Err(printf('unexpected token: %s', token.value), token.pos) - endif - call self.reader.seek_set(pos) - let node = self.parse_identifier() - break - endif - if token.type != s:TOKEN_COLON - throw s:Err(printf('unexpected token: %s', token.value), token.pos) - endif - let val = self.parse_expr1() - call add(node.value, [key, val]) - let token = self.tokenizer.get() - if token.type == s:TOKEN_COMMA - if self.tokenizer.peek().type == s:TOKEN_CCLOSE - call self.tokenizer.get() - break - endif - elseif token.type == s:TOKEN_CCLOSE - break - else - throw s:Err(printf('unexpected token: %s', token.value), token.pos) - endif - endwhile - return node - elseif token.type == s:TOKEN_POPEN - let node = self.parse_expr1() - let token = self.tokenizer.get() - if token.type != s:TOKEN_PCLOSE - throw s:Err(printf('unexpected token: %s', token.value), token.pos) - endif - elseif token.type == s:TOKEN_OPTION - let node = s:Node(s:NODE_OPTION) - let node.pos = token.pos - let node.value = token.value - elseif token.type == s:TOKEN_IDENTIFIER - call self.reader.seek_set(pos) - let node = self.parse_identifier() - elseif s:FALSE && (token.type == s:TOKEN_COLON || token.type == s:TOKEN_SHARP) - " XXX: no parse error but invalid expression - call self.reader.seek_set(pos) - let node = self.parse_identifier() - elseif token.type == s:TOKEN_LT && self.reader.peekn(4) ==? 'SID>' - call self.reader.seek_set(pos) - let node = self.parse_identifier() - elseif token.type == s:TOKEN_IS || token.type == s:TOKEN_ISCS || token.type == s:TOKEN_ISNOT || token.type == s:TOKEN_ISNOTCS - call self.reader.seek_set(pos) - let node = self.parse_identifier() - elseif token.type == s:TOKEN_ENV - let node = s:Node(s:NODE_ENV) - let node.pos = token.pos - let node.value = token.value - elseif token.type == s:TOKEN_REG - let node = s:Node(s:NODE_REG) - let node.pos = token.pos - let node.value = token.value - else - throw s:Err(printf('unexpected token: %s', token.value), token.pos) - endif - return node -endfunction - -" SUBSCRIPT or CONCAT -" dict "." [0-9A-Za-z_]+ => (subscript dict key) -" str "." expr6 => (concat str expr6) -function! s:ExprParser.parse_dot(token, left) - if a:left.type != s:NODE_IDENTIFIER && a:left.type != s:NODE_CURLYNAME && a:left.type != s:NODE_DICT && a:left.type != s:NODE_SUBSCRIPT && a:left.type != s:NODE_CALL && a:left.type != s:NODE_DOT - return s:NIL - endif - if !s:iswordc(self.reader.p(0)) - return s:NIL - endif - let pos = self.reader.getpos() - let name = self.reader.read_word() - if s:isnamec(self.reader.p(0)) - " XXX: foo is str => ok, foo is obj => invalid expression - " foo.s:bar or foo.bar#baz - return s:NIL - endif - let node = s:Node(s:NODE_DOT) - let node.pos = a:token.pos - let node.left = a:left - let node.right = s:Node(s:NODE_IDENTIFIER) - let node.right.pos = pos - let node.right.value = name - return node -endfunction - -function! s:ExprParser.parse_identifier() - call self.reader.skip_white() - let npos = self.reader.getpos() - let curly_parts = self.parse_curly_parts() - if len(curly_parts) == 1 && curly_parts[0].type == s:NODE_CURLYNAMEPART - let node = s:Node(s:NODE_IDENTIFIER) - let node.pos = npos - let node.value = curly_parts[0].value - return node - else - let node = s:Node(s:NODE_CURLYNAME) - let node.pos = npos - let node.value = curly_parts - return node - endif -endfunction - -function! s:ExprParser.parse_curly_parts() - let curly_parts = [] - let c = self.reader.peek() - let pos = self.reader.getpos() - if c ==# '<' && self.reader.peekn(5) ==? '<SID>' - let name = self.reader.getn(5) - let node = s:Node(s:NODE_CURLYNAMEPART) - let node.curly = s:FALSE " Keep backword compatibility for the curly attribute - let node.pos = pos - let node.value = name - call add(curly_parts, node) - endif - while s:TRUE - let c = self.reader.peek() - if s:isnamec(c) - let pos = self.reader.getpos() - let name = self.reader.read_name() - let node = s:Node(s:NODE_CURLYNAMEPART) - let node.curly = s:FALSE " Keep backword compatibility for the curly attribute - let node.pos = pos - let node.value = name - call add(curly_parts, node) - elseif c ==# '{' - call self.reader.get() - let pos = self.reader.getpos() - let node = s:Node(s:NODE_CURLYNAMEEXPR) - let node.curly = s:TRUE " Keep backword compatibility for the curly attribute - let node.pos = pos - let node.value = self.parse_expr1() - call add(curly_parts, node) - call self.reader.skip_white() - let c = self.reader.p(0) - if c !=# '}' - throw s:Err(printf('unexpected token: %s', c), self.reader.getpos()) - endif - call self.reader.seek_cur(1) - else - break - endif - endwhile - return curly_parts -endfunction - -let s:LvalueParser = copy(s:ExprParser) - -function! s:LvalueParser.parse() - return self.parse_lv8() -endfunction - -" expr8: expr8[expr1] -" expr8[expr1 : expr1] -" expr8.name -function! s:LvalueParser.parse_lv8() - let left = self.parse_lv9() - while s:TRUE - let pos = self.reader.tell() - let c = self.reader.peek() - let token = self.tokenizer.get() - if !s:iswhite(c) && token.type == s:TOKEN_SQOPEN - let npos = token.pos - let node = s:Node(-1) - if self.tokenizer.peek().type == s:TOKEN_COLON - call self.tokenizer.get() - let node = s:Node(s:NODE_SLICE) - let node.pos = npos - let node.left = left - let node.rlist = [s:NIL, s:NIL] - let token = self.tokenizer.peek() - if token.type != s:TOKEN_SQCLOSE - let node.rlist[1] = self.parse_expr1() - endif - let token = self.tokenizer.get() - if token.type != s:TOKEN_SQCLOSE - throw s:Err(printf('unexpected token: %s', token.value), token.pos) - endif - else - let right = self.parse_expr1() - if self.tokenizer.peek().type == s:TOKEN_COLON - call self.tokenizer.get() - let node = s:Node(s:NODE_SLICE) - let node.pos = npos - let node.left = left - let node.rlist = [right, s:NIL] - let token = self.tokenizer.peek() - if token.type != s:TOKEN_SQCLOSE - let node.rlist[1] = self.parse_expr1() - endif - let token = self.tokenizer.get() - if token.type != s:TOKEN_SQCLOSE - throw s:Err(printf('unexpected token: %s', token.value), token.pos) - endif - else - let node = s:Node(s:NODE_SUBSCRIPT) - let node.pos = npos - let node.left = left - let node.right = right - let token = self.tokenizer.get() - if token.type != s:TOKEN_SQCLOSE - throw s:Err(printf('unexpected token: %s', token.value), token.pos) - endif - endif - endif - let left = node - unlet node - elseif !s:iswhite(c) && token.type == s:TOKEN_DOT - let node = self.parse_dot(token, left) - if node is s:NIL - call self.reader.seek_set(pos) - break - endif - let left = node - unlet node - else - call self.reader.seek_set(pos) - break - endif - endwhile - return left -endfunction - -" expr9: &option -" variable -" var{ria}ble -" $VAR -" @r -function! s:LvalueParser.parse_lv9() - let pos = self.reader.tell() - let token = self.tokenizer.get() - let node = s:Node(-1) - if token.type == s:TOKEN_COPEN - call self.reader.seek_set(pos) - let node = self.parse_identifier() - elseif token.type == s:TOKEN_OPTION - let node = s:Node(s:NODE_OPTION) - let node.pos = token.pos - let node.value = token.value - elseif token.type == s:TOKEN_IDENTIFIER - call self.reader.seek_set(pos) - let node = self.parse_identifier() - elseif token.type == s:TOKEN_LT && self.reader.peekn(4) ==? 'SID>' - call self.reader.seek_set(pos) - let node = self.parse_identifier() - elseif token.type == s:TOKEN_ENV - let node = s:Node(s:NODE_ENV) - let node.pos = token.pos - let node.value = token.value - elseif token.type == s:TOKEN_REG - let node = s:Node(s:NODE_REG) - let node.pos = token.pos - let node.pos = token.pos - let node.value = token.value - else - throw s:Err(printf('unexpected token: %s', token.value), token.pos) - endif - return node -endfunction - -let s:StringReader = {} - -function! s:StringReader.new(...) - let obj = copy(self) - call call(obj.__init__, a:000, obj) - return obj -endfunction - -function! s:StringReader.__init__(lines) - let self.buf = [] - let self.pos = [] - let lnum = 0 - let offset = 0 - while lnum < len(a:lines) - let col = 0 - for c in split(a:lines[lnum], '\zs') - call add(self.buf, c) - call add(self.pos, [lnum + 1, col + 1, offset]) - let col += len(c) - let offset += len(c) - endfor - while lnum + 1 < len(a:lines) && a:lines[lnum + 1] =~# '^\s*\\' - let skip = s:TRUE - let col = 0 - for c in split(a:lines[lnum + 1], '\zs') - if skip - if c == '\' - let skip = s:FALSE - endif - else - call add(self.buf, c) - call add(self.pos, [lnum + 2, col + 1, offset]) - endif - let col += len(c) - let offset += len(c) - endfor - let lnum += 1 - let offset += 1 - endwhile - call add(self.buf, '<EOL>') - call add(self.pos, [lnum + 1, col + 1, offset]) - let lnum += 1 - let offset += 1 - endwhile - " for <EOF> - call add(self.pos, [lnum + 1, 0, offset]) - let self.i = 0 -endfunction - -function! s:StringReader.eof() - return self.i >= len(self.buf) -endfunction - -function! s:StringReader.tell() - return self.i -endfunction - -function! s:StringReader.seek_set(i) - let self.i = a:i -endfunction - -function! s:StringReader.seek_cur(i) - let self.i = self.i + a:i -endfunction - -function! s:StringReader.seek_end(i) - let self.i = len(self.buf) + a:i -endfunction - -function! s:StringReader.p(i) - if self.i >= len(self.buf) - return '<EOF>' - endif - return self.buf[self.i + a:i] -endfunction - -function! s:StringReader.peek() - if self.i >= len(self.buf) - return '<EOF>' - endif - return self.buf[self.i] -endfunction - -function! s:StringReader.get() - if self.i >= len(self.buf) - return '<EOF>' - endif - let self.i += 1 - return self.buf[self.i - 1] -endfunction - -function! s:StringReader.peekn(n) - let pos = self.tell() - let r = self.getn(a:n) - call self.seek_set(pos) - return r -endfunction - -function! s:StringReader.getn(n) - let r = '' - let j = 0 - while self.i < len(self.buf) && (a:n < 0 || j < a:n) - let c = self.buf[self.i] - if c ==# '<EOL>' - break - endif - let r .= c - let self.i += 1 - let j += 1 - endwhile - return r -endfunction - -function! s:StringReader.peekline() - return self.peekn(-1) -endfunction - -function! s:StringReader.readline() - let r = self.getn(-1) - call self.get() - return r -endfunction - -function! s:StringReader.getstr(begin, end) - let r = '' - for i in range(a:begin.i, a:end.i - 1) - if i >= len(self.buf) - break - endif - let c = self.buf[i] - if c ==# '<EOL>' - let c = "\n" - endif - let r .= c - endfor - return r -endfunction - -function! s:StringReader.getpos() - let [lnum, col, offset] = self.pos[self.i] - return {'i': self.i, 'lnum': lnum, 'col': col, 'offset': offset} -endfunction - -function! s:StringReader.setpos(pos) - let self.i = a:pos.i -endfunction - -function! s:StringReader.read_alpha() - let r = '' - while s:isalpha(self.peekn(1)) - let r .= self.getn(1) - endwhile - return r -endfunction - -function! s:StringReader.read_alnum() - let r = '' - while s:isalnum(self.peekn(1)) - let r .= self.getn(1) - endwhile - return r -endfunction - -function! s:StringReader.read_digit() - let r = '' - while s:isdigit(self.peekn(1)) - let r .= self.getn(1) - endwhile - return r -endfunction - -function! s:StringReader.read_odigit() - let r = '' - while s:isodigit(self.peekn(1)) - let r .= self.getn(1) - endwhile - return r -endfunction - -function! s:StringReader.read_xdigit() - let r = '' - while s:isxdigit(self.peekn(1)) - let r .= self.getn(1) - endwhile - return r -endfunction - -function! s:StringReader.read_integer() - let r = '' - let c = self.peekn(1) - if c == '-' || c == '+' - let r = self.getn(1) - endif - return r . self.read_digit() -endfunction - -function! s:StringReader.read_word() - let r = '' - while s:iswordc(self.peekn(1)) - let r .= self.getn(1) - endwhile - return r -endfunction - -function! s:StringReader.read_white() - let r = '' - while s:iswhite(self.peekn(1)) - let r .= self.getn(1) - endwhile - return r -endfunction - -function! s:StringReader.read_nonwhite() - let r = '' - while !s:iswhite(self.peekn(1)) - let r .= self.getn(1) - endwhile - return r -endfunction - -function! s:StringReader.read_name() - let r = '' - while s:isnamec(self.peekn(1)) - let r .= self.getn(1) - endwhile - return r -endfunction - -function! s:StringReader.skip_white() - while s:iswhite(self.peekn(1)) - call self.seek_cur(1) - endwhile -endfunction - -function! s:StringReader.skip_white_and_colon() - while s:TRUE - let c = self.peekn(1) - if !s:iswhite(c) && c !=# ':' - break - endif - call self.seek_cur(1) - endwhile -endfunction - -let s:Compiler = {} - -function! s:Compiler.new(...) - let obj = copy(self) - call call(obj.__init__, a:000, obj) - return obj -endfunction - -function! s:Compiler.__init__() - let self.indent = [''] - let self.lines = [] -endfunction - -function! s:Compiler.out(...) - if len(a:000) == 1 - if a:000[0][0] ==# ')' - let self.lines[-1] .= a:000[0] - else - call add(self.lines, self.indent[0] . a:000[0]) - endif - else - call add(self.lines, self.indent[0] . call('printf', a:000)) - endif -endfunction - -function! s:Compiler.incindent(s) - call insert(self.indent, self.indent[0] . a:s) -endfunction - -function! s:Compiler.decindent() - call remove(self.indent, 0) -endfunction - -function! s:Compiler.compile(node) - if a:node.type == s:NODE_TOPLEVEL - return self.compile_toplevel(a:node) - elseif a:node.type == s:NODE_COMMENT - call self.compile_comment(a:node) - return s:NIL - elseif a:node.type == s:NODE_EXCMD - call self.compile_excmd(a:node) - return s:NIL - elseif a:node.type == s:NODE_FUNCTION - call self.compile_function(a:node) - return s:NIL - elseif a:node.type == s:NODE_DELFUNCTION - call self.compile_delfunction(a:node) - return s:NIL - elseif a:node.type == s:NODE_RETURN - call self.compile_return(a:node) - return s:NIL - elseif a:node.type == s:NODE_EXCALL - call self.compile_excall(a:node) - return s:NIL - elseif a:node.type == s:NODE_LET - call self.compile_let(a:node) - return s:NIL - elseif a:node.type == s:NODE_UNLET - call self.compile_unlet(a:node) - return s:NIL - elseif a:node.type == s:NODE_LOCKVAR - call self.compile_lockvar(a:node) - return s:NIL - elseif a:node.type == s:NODE_UNLOCKVAR - call self.compile_unlockvar(a:node) - return s:NIL - elseif a:node.type == s:NODE_IF - call self.compile_if(a:node) - return s:NIL - elseif a:node.type == s:NODE_WHILE - call self.compile_while(a:node) - return s:NIL - elseif a:node.type == s:NODE_FOR - call self.compile_for(a:node) - return s:NIL - elseif a:node.type == s:NODE_CONTINUE - call self.compile_continue(a:node) - return s:NIL - elseif a:node.type == s:NODE_BREAK - call self.compile_break(a:node) - return s:NIL - elseif a:node.type == s:NODE_TRY - call self.compile_try(a:node) - return s:NIL - elseif a:node.type == s:NODE_THROW - call self.compile_throw(a:node) - return s:NIL - elseif a:node.type == s:NODE_ECHO - call self.compile_echo(a:node) - return s:NIL - elseif a:node.type == s:NODE_ECHON - call self.compile_echon(a:node) - return s:NIL - elseif a:node.type == s:NODE_ECHOHL - call self.compile_echohl(a:node) - return s:NIL - elseif a:node.type == s:NODE_ECHOMSG - call self.compile_echomsg(a:node) - return s:NIL - elseif a:node.type == s:NODE_ECHOERR - call self.compile_echoerr(a:node) - return s:NIL - elseif a:node.type == s:NODE_EXECUTE - call self.compile_execute(a:node) - return s:NIL - elseif a:node.type == s:NODE_TERNARY - return self.compile_ternary(a:node) - elseif a:node.type == s:NODE_OR - return self.compile_or(a:node) - elseif a:node.type == s:NODE_AND - return self.compile_and(a:node) - elseif a:node.type == s:NODE_EQUAL - return self.compile_equal(a:node) - elseif a:node.type == s:NODE_EQUALCI - return self.compile_equalci(a:node) - elseif a:node.type == s:NODE_EQUALCS - return self.compile_equalcs(a:node) - elseif a:node.type == s:NODE_NEQUAL - return self.compile_nequal(a:node) - elseif a:node.type == s:NODE_NEQUALCI - return self.compile_nequalci(a:node) - elseif a:node.type == s:NODE_NEQUALCS - return self.compile_nequalcs(a:node) - elseif a:node.type == s:NODE_GREATER - return self.compile_greater(a:node) - elseif a:node.type == s:NODE_GREATERCI - return self.compile_greaterci(a:node) - elseif a:node.type == s:NODE_GREATERCS - return self.compile_greatercs(a:node) - elseif a:node.type == s:NODE_GEQUAL - return self.compile_gequal(a:node) - elseif a:node.type == s:NODE_GEQUALCI - return self.compile_gequalci(a:node) - elseif a:node.type == s:NODE_GEQUALCS - return self.compile_gequalcs(a:node) - elseif a:node.type == s:NODE_SMALLER - return self.compile_smaller(a:node) - elseif a:node.type == s:NODE_SMALLERCI - return self.compile_smallerci(a:node) - elseif a:node.type == s:NODE_SMALLERCS - return self.compile_smallercs(a:node) - elseif a:node.type == s:NODE_SEQUAL - return self.compile_sequal(a:node) - elseif a:node.type == s:NODE_SEQUALCI - return self.compile_sequalci(a:node) - elseif a:node.type == s:NODE_SEQUALCS - return self.compile_sequalcs(a:node) - elseif a:node.type == s:NODE_MATCH - return self.compile_match(a:node) - elseif a:node.type == s:NODE_MATCHCI - return self.compile_matchci(a:node) - elseif a:node.type == s:NODE_MATCHCS - return self.compile_matchcs(a:node) - elseif a:node.type == s:NODE_NOMATCH - return self.compile_nomatch(a:node) - elseif a:node.type == s:NODE_NOMATCHCI - return self.compile_nomatchci(a:node) - elseif a:node.type == s:NODE_NOMATCHCS - return self.compile_nomatchcs(a:node) - elseif a:node.type == s:NODE_IS - return self.compile_is(a:node) - elseif a:node.type == s:NODE_ISCI - return self.compile_isci(a:node) - elseif a:node.type == s:NODE_ISCS - return self.compile_iscs(a:node) - elseif a:node.type == s:NODE_ISNOT - return self.compile_isnot(a:node) - elseif a:node.type == s:NODE_ISNOTCI - return self.compile_isnotci(a:node) - elseif a:node.type == s:NODE_ISNOTCS - return self.compile_isnotcs(a:node) - elseif a:node.type == s:NODE_ADD - return self.compile_add(a:node) - elseif a:node.type == s:NODE_SUBTRACT - return self.compile_subtract(a:node) - elseif a:node.type == s:NODE_CONCAT - return self.compile_concat(a:node) - elseif a:node.type == s:NODE_MULTIPLY - return self.compile_multiply(a:node) - elseif a:node.type == s:NODE_DIVIDE - return self.compile_divide(a:node) - elseif a:node.type == s:NODE_REMAINDER - return self.compile_remainder(a:node) - elseif a:node.type == s:NODE_NOT - return self.compile_not(a:node) - elseif a:node.type == s:NODE_PLUS - return self.compile_plus(a:node) - elseif a:node.type == s:NODE_MINUS - return self.compile_minus(a:node) - elseif a:node.type == s:NODE_SUBSCRIPT - return self.compile_subscript(a:node) - elseif a:node.type == s:NODE_SLICE - return self.compile_slice(a:node) - elseif a:node.type == s:NODE_DOT - return self.compile_dot(a:node) - elseif a:node.type == s:NODE_CALL - return self.compile_call(a:node) - elseif a:node.type == s:NODE_NUMBER - return self.compile_number(a:node) - elseif a:node.type == s:NODE_STRING - return self.compile_string(a:node) - elseif a:node.type == s:NODE_LIST - return self.compile_list(a:node) - elseif a:node.type == s:NODE_DICT - return self.compile_dict(a:node) - elseif a:node.type == s:NODE_OPTION - return self.compile_option(a:node) - elseif a:node.type == s:NODE_IDENTIFIER - return self.compile_identifier(a:node) - elseif a:node.type == s:NODE_CURLYNAME - return self.compile_curlyname(a:node) - elseif a:node.type == s:NODE_ENV - return self.compile_env(a:node) - elseif a:node.type == s:NODE_REG - return self.compile_reg(a:node) - elseif a:node.type == s:NODE_CURLYNAMEPART - return self.compile_curlynamepart(a:node) - elseif a:node.type == s:NODE_CURLYNAMEEXPR - return self.compile_curlynameexpr(a:node) - elseif a:node.type == s:NODE_LAMBDA - return self.compile_lambda(a:node) - else - throw printf('Compiler: unknown node: %s', string(a:node)) - endif - return s:NIL -endfunction - -function! s:Compiler.compile_body(body) - for node in a:body - call self.compile(node) - endfor -endfunction - -function! s:Compiler.compile_toplevel(node) - call self.compile_body(a:node.body) - return self.lines -endfunction - -function! s:Compiler.compile_comment(node) - call self.out(';%s', a:node.str) -endfunction - -function! s:Compiler.compile_excmd(node) - call self.out('(excmd "%s")', escape(a:node.str, '\"')) -endfunction - -function! s:Compiler.compile_function(node) - let left = self.compile(a:node.left) - let rlist = map(a:node.rlist, 'self.compile(v:val)') - if !empty(rlist) && rlist[-1] ==# '...' - let rlist[-1] = '. ...' - endif - if empty(rlist) - call self.out('(function (%s)', left) - else - call self.out('(function (%s %s)', left, join(rlist, ' ')) - endif - call self.incindent(' ') - call self.compile_body(a:node.body) - call self.out(')') - call self.decindent() -endfunction - -function! s:Compiler.compile_delfunction(node) - call self.out('(delfunction %s)', self.compile(a:node.left)) -endfunction - -function! s:Compiler.compile_return(node) - if a:node.left is s:NIL - call self.out('(return)') - else - call self.out('(return %s)', self.compile(a:node.left)) - endif -endfunction - -function! s:Compiler.compile_excall(node) - call self.out('(call %s)', self.compile(a:node.left)) -endfunction - -function! s:Compiler.compile_let(node) - let left = '' - if a:node.left isnot s:NIL - let left = self.compile(a:node.left) - else - let left = join(map(a:node.list, 'self.compile(v:val)'), ' ') - if a:node.rest isnot s:NIL - let left .= ' . ' . self.compile(a:node.rest) - endif - let left = '(' . left . ')' - endif - let right = self.compile(a:node.right) - call self.out('(let %s %s %s)', a:node.op, left, right) -endfunction - -function! s:Compiler.compile_unlet(node) - let list = map(a:node.list, 'self.compile(v:val)') - call self.out('(unlet %s)', join(list, ' ')) -endfunction - -function! s:Compiler.compile_lockvar(node) - let list = map(a:node.list, 'self.compile(v:val)') - if a:node.depth is s:NIL - call self.out('(lockvar %s)', join(list, ' ')) - else - call self.out('(lockvar %s %s)', a:node.depth, join(list, ' ')) - endif -endfunction - -function! s:Compiler.compile_unlockvar(node) - let list = map(a:node.list, 'self.compile(v:val)') - if a:node.depth is s:NIL - call self.out('(unlockvar %s)', join(list, ' ')) - else - call self.out('(unlockvar %s %s)', a:node.depth, join(list, ' ')) - endif -endfunction - -function! s:Compiler.compile_if(node) - call self.out('(if %s', self.compile(a:node.cond)) - call self.incindent(' ') - call self.compile_body(a:node.body) - call self.decindent() - for enode in a:node.elseif - call self.out(' elseif %s', self.compile(enode.cond)) - call self.incindent(' ') - call self.compile_body(enode.body) - call self.decindent() - endfor - if a:node.else isnot s:NIL - call self.out(' else') - call self.incindent(' ') - call self.compile_body(a:node.else.body) - call self.decindent() - endif - call self.incindent(' ') - call self.out(')') - call self.decindent() -endfunction - -function! s:Compiler.compile_while(node) - call self.out('(while %s', self.compile(a:node.cond)) - call self.incindent(' ') - call self.compile_body(a:node.body) - call self.out(')') - call self.decindent() -endfunction - -function! s:Compiler.compile_for(node) - let left = '' - if a:node.left isnot s:NIL - let left = self.compile(a:node.left) - else - let left = join(map(a:node.list, 'self.compile(v:val)'), ' ') - if a:node.rest isnot s:NIL - let left .= ' . ' . self.compile(a:node.rest) - endif - let left = '(' . left . ')' - endif - let right = self.compile(a:node.right) - call self.out('(for %s %s', left, right) - call self.incindent(' ') - call self.compile_body(a:node.body) - call self.out(')') - call self.decindent() -endfunction - -function! s:Compiler.compile_continue(node) - call self.out('(continue)') -endfunction - -function! s:Compiler.compile_break(node) - call self.out('(break)') -endfunction - -function! s:Compiler.compile_try(node) - call self.out('(try') - call self.incindent(' ') - call self.compile_body(a:node.body) - for cnode in a:node.catch - if cnode.pattern isnot s:NIL - call self.decindent() - call self.out(' catch /%s/', cnode.pattern) - call self.incindent(' ') - call self.compile_body(cnode.body) - else - call self.decindent() - call self.out(' catch') - call self.incindent(' ') - call self.compile_body(cnode.body) - endif - endfor - if a:node.finally isnot s:NIL - call self.decindent() - call self.out(' finally') - call self.incindent(' ') - call self.compile_body(a:node.finally.body) - endif - call self.out(')') - call self.decindent() -endfunction - -function! s:Compiler.compile_throw(node) - call self.out('(throw %s)', self.compile(a:node.left)) -endfunction - -function! s:Compiler.compile_echo(node) - let list = map(a:node.list, 'self.compile(v:val)') - call self.out('(echo %s)', join(list, ' ')) -endfunction - -function! s:Compiler.compile_echon(node) - let list = map(a:node.list, 'self.compile(v:val)') - call self.out('(echon %s)', join(list, ' ')) -endfunction - -function! s:Compiler.compile_echohl(node) - call self.out('(echohl "%s")', escape(a:node.str, '\"')) -endfunction - -function! s:Compiler.compile_echomsg(node) - let list = map(a:node.list, 'self.compile(v:val)') - call self.out('(echomsg %s)', join(list, ' ')) -endfunction - -function! s:Compiler.compile_echoerr(node) - let list = map(a:node.list, 'self.compile(v:val)') - call self.out('(echoerr %s)', join(list, ' ')) -endfunction - -function! s:Compiler.compile_execute(node) - let list = map(a:node.list, 'self.compile(v:val)') - call self.out('(execute %s)', join(list, ' ')) -endfunction - -function! s:Compiler.compile_ternary(node) - return printf('(?: %s %s %s)', self.compile(a:node.cond), self.compile(a:node.left), self.compile(a:node.right)) -endfunction - -function! s:Compiler.compile_or(node) - return printf('(|| %s %s)', self.compile(a:node.left), self.compile(a:node.right)) -endfunction - -function! s:Compiler.compile_and(node) - return printf('(&& %s %s)', self.compile(a:node.left), self.compile(a:node.right)) -endfunction - -function! s:Compiler.compile_equal(node) - return printf('(== %s %s)', self.compile(a:node.left), self.compile(a:node.right)) -endfunction - -function! s:Compiler.compile_equalci(node) - return printf('(==? %s %s)', self.compile(a:node.left), self.compile(a:node.right)) -endfunction - -function! s:Compiler.compile_equalcs(node) - return printf('(==# %s %s)', self.compile(a:node.left), self.compile(a:node.right)) -endfunction - -function! s:Compiler.compile_nequal(node) - return printf('(!= %s %s)', self.compile(a:node.left), self.compile(a:node.right)) -endfunction - -function! s:Compiler.compile_nequalci(node) - return printf('(!=? %s %s)', self.compile(a:node.left), self.compile(a:node.right)) -endfunction - -function! s:Compiler.compile_nequalcs(node) - return printf('(!=# %s %s)', self.compile(a:node.left), self.compile(a:node.right)) -endfunction - -function! s:Compiler.compile_greater(node) - return printf('(> %s %s)', self.compile(a:node.left), self.compile(a:node.right)) -endfunction - -function! s:Compiler.compile_greaterci(node) - return printf('(>? %s %s)', self.compile(a:node.left), self.compile(a:node.right)) -endfunction - -function! s:Compiler.compile_greatercs(node) - return printf('(># %s %s)', self.compile(a:node.left), self.compile(a:node.right)) -endfunction - -function! s:Compiler.compile_gequal(node) - return printf('(>= %s %s)', self.compile(a:node.left), self.compile(a:node.right)) -endfunction - -function! s:Compiler.compile_gequalci(node) - return printf('(>=? %s %s)', self.compile(a:node.left), self.compile(a:node.right)) -endfunction - -function! s:Compiler.compile_gequalcs(node) - return printf('(>=# %s %s)', self.compile(a:node.left), self.compile(a:node.right)) -endfunction - -function! s:Compiler.compile_smaller(node) - return printf('(< %s %s)', self.compile(a:node.left), self.compile(a:node.right)) -endfunction - -function! s:Compiler.compile_smallerci(node) - return printf('(<? %s %s)', self.compile(a:node.left), self.compile(a:node.right)) -endfunction - -function! s:Compiler.compile_smallercs(node) - return printf('(<# %s %s)', self.compile(a:node.left), self.compile(a:node.right)) -endfunction - -function! s:Compiler.compile_sequal(node) - return printf('(<= %s %s)', self.compile(a:node.left), self.compile(a:node.right)) -endfunction - -function! s:Compiler.compile_sequalci(node) - return printf('(<=? %s %s)', self.compile(a:node.left), self.compile(a:node.right)) -endfunction - -function! s:Compiler.compile_sequalcs(node) - return printf('(<=# %s %s)', self.compile(a:node.left), self.compile(a:node.right)) -endfunction - -function! s:Compiler.compile_match(node) - return printf('(=~ %s %s)', self.compile(a:node.left), self.compile(a:node.right)) -endfunction - -function! s:Compiler.compile_matchci(node) - return printf('(=~? %s %s)', self.compile(a:node.left), self.compile(a:node.right)) -endfunction - -function! s:Compiler.compile_matchcs(node) - return printf('(=~# %s %s)', self.compile(a:node.left), self.compile(a:node.right)) -endfunction - -function! s:Compiler.compile_nomatch(node) - return printf('(!~ %s %s)', self.compile(a:node.left), self.compile(a:node.right)) -endfunction - -function! s:Compiler.compile_nomatchci(node) - return printf('(!~? %s %s)', self.compile(a:node.left), self.compile(a:node.right)) -endfunction - -function! s:Compiler.compile_nomatchcs(node) - return printf('(!~# %s %s)', self.compile(a:node.left), self.compile(a:node.right)) -endfunction - -function! s:Compiler.compile_is(node) - return printf('(is %s %s)', self.compile(a:node.left), self.compile(a:node.right)) -endfunction - -function! s:Compiler.compile_isci(node) - return printf('(is? %s %s)', self.compile(a:node.left), self.compile(a:node.right)) -endfunction - -function! s:Compiler.compile_iscs(node) - return printf('(is# %s %s)', self.compile(a:node.left), self.compile(a:node.right)) -endfunction - -function! s:Compiler.compile_isnot(node) - return printf('(isnot %s %s)', self.compile(a:node.left), self.compile(a:node.right)) -endfunction - -function! s:Compiler.compile_isnotci(node) - return printf('(isnot? %s %s)', self.compile(a:node.left), self.compile(a:node.right)) -endfunction - -function! s:Compiler.compile_isnotcs(node) - return printf('(isnot# %s %s)', self.compile(a:node.left), self.compile(a:node.right)) -endfunction - -function! s:Compiler.compile_add(node) - return printf('(+ %s %s)', self.compile(a:node.left), self.compile(a:node.right)) -endfunction - -function! s:Compiler.compile_subtract(node) - return printf('(- %s %s)', self.compile(a:node.left), self.compile(a:node.right)) -endfunction - -function! s:Compiler.compile_concat(node) - return printf('(concat %s %s)', self.compile(a:node.left), self.compile(a:node.right)) -endfunction - -function! s:Compiler.compile_multiply(node) - return printf('(* %s %s)', self.compile(a:node.left), self.compile(a:node.right)) -endfunction - -function! s:Compiler.compile_divide(node) - return printf('(/ %s %s)', self.compile(a:node.left), self.compile(a:node.right)) -endfunction - -function! s:Compiler.compile_remainder(node) - return printf('(%% %s %s)', self.compile(a:node.left), self.compile(a:node.right)) -endfunction - -function! s:Compiler.compile_not(node) - return printf('(! %s)', self.compile(a:node.left)) -endfunction - -function! s:Compiler.compile_plus(node) - return printf('(+ %s)', self.compile(a:node.left)) -endfunction - -function! s:Compiler.compile_minus(node) - return printf('(- %s)', self.compile(a:node.left)) -endfunction - -function! s:Compiler.compile_subscript(node) - return printf('(subscript %s %s)', self.compile(a:node.left), self.compile(a:node.right)) -endfunction - -function! s:Compiler.compile_slice(node) - let r0 = a:node.rlist[0] is s:NIL ? 'nil' : self.compile(a:node.rlist[0]) - let r1 = a:node.rlist[1] is s:NIL ? 'nil' : self.compile(a:node.rlist[1]) - return printf('(slice %s %s %s)', self.compile(a:node.left), r0, r1) -endfunction - -function! s:Compiler.compile_dot(node) - return printf('(dot %s %s)', self.compile(a:node.left), self.compile(a:node.right)) -endfunction - -function! s:Compiler.compile_call(node) - let rlist = map(a:node.rlist, 'self.compile(v:val)') - if empty(rlist) - return printf('(%s)', self.compile(a:node.left)) - else - return printf('(%s %s)', self.compile(a:node.left), join(rlist, ' ')) - endif -endfunction - -function! s:Compiler.compile_number(node) - return a:node.value -endfunction - -function! s:Compiler.compile_string(node) - return a:node.value -endfunction - -function! s:Compiler.compile_list(node) - let value = map(a:node.value, 'self.compile(v:val)') - if empty(value) - return '(list)' - else - return printf('(list %s)', join(value, ' ')) - endif -endfunction - -function! s:Compiler.compile_dict(node) - let value = map(a:node.value, '"(" . self.compile(v:val[0]) . " " . self.compile(v:val[1]) . ")"') - if empty(value) - return '(dict)' - else - return printf('(dict %s)', join(value, ' ')) - endif -endfunction - -function! s:Compiler.compile_option(node) - return a:node.value -endfunction - -function! s:Compiler.compile_identifier(node) - return a:node.value -endfunction - -function! s:Compiler.compile_curlyname(node) - return join(map(a:node.value, 'self.compile(v:val)'), '') -endfunction - -function! s:Compiler.compile_env(node) - return a:node.value -endfunction - -function! s:Compiler.compile_reg(node) - return a:node.value -endfunction - -function! s:Compiler.compile_curlynamepart(node) - return a:node.value -endfunction - -function! s:Compiler.compile_curlynameexpr(node) - return '{' . self.compile(a:node.value) . '}' -endfunction - -function! s:Compiler.compile_lambda(node) - let rlist = map(a:node.rlist, 'self.compile(v:val)') - return printf('(lambda (%s) %s)', join(rlist, ' '), self.compile(a:node.left)) -endfunction - -" TODO: under construction -let s:RegexpParser = {} - -let s:RegexpParser.RE_VERY_NOMAGIC = 1 -let s:RegexpParser.RE_NOMAGIC = 2 -let s:RegexpParser.RE_MAGIC = 3 -let s:RegexpParser.RE_VERY_MAGIC = 4 - -function! s:RegexpParser.new(...) - let obj = copy(self) - call call(obj.__init__, a:000, obj) - return obj -endfunction - -function! s:RegexpParser.__init__(reader, cmd, delim) - let self.reader = a:reader - let self.cmd = a:cmd - let self.delim = a:delim - let self.reg_magic = self.RE_MAGIC -endfunction - -function! s:RegexpParser.isend(c) - return a:c ==# '<EOF>' || a:c ==# '<EOL>' || a:c ==# self.delim -endfunction - -function! s:RegexpParser.parse_regexp() - let prevtoken = '' - let ntoken = '' - let ret = [] - if self.reader.peekn(4) ==# '\%#=' - let epos = self.reader.getpos() - let token = self.reader.getn(5) - if token !=# '\%#=0' && token !=# '\%#=1' && token !=# '\%#=2' - throw s:Err('E864: \%#= can only be followed by 0, 1, or 2', epos) - endif - call add(ret, token) - endif - while !self.isend(self.reader.peek()) - let prevtoken = ntoken - let [token, ntoken] = self.get_token() - if ntoken ==# '\m' - let self.reg_magic = self.RE_MAGIC - elseif ntoken ==# '\M' - let self.reg_magic = self.RE_NOMAGIC - elseif ntoken ==# '\v' - let self.reg_magic = self.RE_VERY_MAGIC - elseif ntoken ==# '\V' - let self.reg_magic = self.RE_VERY_NOMAGIC - elseif ntoken ==# '\*' - " '*' is not magic as the very first character. - if prevtoken ==# '' || prevtoken ==# '\^' || prevtoken ==# '\&' || prevtoken ==# '\|' || prevtoken ==# '\(' - let ntoken = '*' - endif - elseif ntoken ==# '\^' - " '^' is only magic as the very first character. - if self.reg_magic != self.RE_VERY_MAGIC && prevtoken !=# '' && prevtoken !=# '\&' && prevtoken !=# '\|' && prevtoken !=# '\n' && prevtoken !=# '\(' && prevtoken !=# '\%(' - let ntoken = '^' - endif - elseif ntoken ==# '\$' - " '$' is only magic as the very last character - let pos = self.reader.tell() - if self.reg_magic != self.RE_VERY_MAGIC - while !self.isend(self.reader.peek()) - let [t, n] = self.get_token() - " XXX: Vim doesn't check \v and \V? - if n ==# '\c' || n ==# '\C' || n ==# '\m' || n ==# '\M' || n ==# '\Z' - continue - endif - if n !=# '\|' && n !=# '\&' && n !=# '\n' && n !=# '\)' - let ntoken = '$' - endif - break - endwhile - endif - call self.reader.seek_set(pos) - elseif ntoken ==# '\?' - " '?' is literal in '?' command. - if self.cmd ==# '?' - let ntoken = '?' - endif - endif - call add(ret, ntoken) - endwhile - return ret -endfunction - -" @return [actual_token, normalized_token] -function! s:RegexpParser.get_token() - if self.reg_magic == self.RE_VERY_MAGIC - return self.get_token_very_magic() - elseif self.reg_magic == self.RE_MAGIC - return self.get_token_magic() - elseif self.reg_magic == self.RE_NOMAGIC - return self.get_token_nomagic() - elseif self.reg_magic == self.RE_VERY_NOMAGIC - return self.get_token_very_nomagic() - endif -endfunction - -function! s:RegexpParser.get_token_very_magic() - if self.isend(self.reader.peek()) - return ['<END>', '<END>'] - endif - let c = self.reader.get() - if c ==# '\' - return self.get_token_backslash_common() - elseif c ==# '*' - return ['*', '\*'] - elseif c ==# '+' - return ['+', '\+'] - elseif c ==# '=' - return ['=', '\='] - elseif c ==# '?' - return ['?', '\?'] - elseif c ==# '{' - return self.get_token_brace('{') - elseif c ==# '@' - return self.get_token_at('@') - elseif c ==# '^' - return ['^', '\^'] - elseif c ==# '$' - return ['$', '\$'] - elseif c ==# '.' - return ['.', '\.'] - elseif c ==# '<' - return ['<', '\<'] - elseif c ==# '>' - return ['>', '\>'] - elseif c ==# '%' - return self.get_token_percent('%') - elseif c ==# '[' - return self.get_token_sq('[') - elseif c ==# '~' - return ['~', '\~'] - elseif c ==# '|' - return ['|', '\|'] - elseif c ==# '&' - return ['&', '\&'] - elseif c ==# '(' - return ['(', '\('] - elseif c ==# ')' - return [')', '\)'] - endif - return [c, c] -endfunction - -function! s:RegexpParser.get_token_magic() - if self.isend(self.reader.peek()) - return ['<END>', '<END>'] - endif - let c = self.reader.get() - if c ==# '\' - let pos = self.reader.tell() - let c = self.reader.get() - if c ==# '+' - return ['\+', '\+'] - elseif c ==# '=' - return ['\=', '\='] - elseif c ==# '?' - return ['\?', '\?'] - elseif c ==# '{' - return self.get_token_brace('\{') - elseif c ==# '@' - return self.get_token_at('\@') - elseif c ==# '<' - return ['\<', '\<'] - elseif c ==# '>' - return ['\>', '\>'] - elseif c ==# '%' - return self.get_token_percent('\%') - elseif c ==# '|' - return ['\|', '\|'] - elseif c ==# '&' - return ['\&', '\&'] - elseif c ==# '(' - return ['\(', '\('] - elseif c ==# ')' - return ['\)', '\)'] - endif - call self.reader.seek_set(pos) - return self.get_token_backslash_common() - elseif c ==# '*' - return ['*', '\*'] - elseif c ==# '^' - return ['^', '\^'] - elseif c ==# '$' - return ['$', '\$'] - elseif c ==# '.' - return ['.', '\.'] - elseif c ==# '[' - return self.get_token_sq('[') - elseif c ==# '~' - return ['~', '\~'] - endif - return [c, c] -endfunction - -function! s:RegexpParser.get_token_nomagic() - if self.isend(self.reader.peek()) - return ['<END>', '<END>'] - endif - let c = self.reader.get() - if c ==# '\' - let pos = self.reader.tell() - let c = self.reader.get() - if c ==# '*' - return ['\*', '\*'] - elseif c ==# '+' - return ['\+', '\+'] - elseif c ==# '=' - return ['\=', '\='] - elseif c ==# '?' - return ['\?', '\?'] - elseif c ==# '{' - return self.get_token_brace('\{') - elseif c ==# '@' - return self.get_token_at('\@') - elseif c ==# '.' - return ['\.', '\.'] - elseif c ==# '<' - return ['\<', '\<'] - elseif c ==# '>' - return ['\>', '\>'] - elseif c ==# '%' - return self.get_token_percent('\%') - elseif c ==# '~' - return ['\~', '\^'] - elseif c ==# '[' - return self.get_token_sq('\[') - elseif c ==# '|' - return ['\|', '\|'] - elseif c ==# '&' - return ['\&', '\&'] - elseif c ==# '(' - return ['\(', '\('] - elseif c ==# ')' - return ['\)', '\)'] - endif - call self.reader.seek_set(pos) - return self.get_token_backslash_common() - elseif c ==# '^' - return ['^', '\^'] - elseif c ==# '$' - return ['$', '\$'] - endif - return [c, c] -endfunction - -function! s:RegexpParser.get_token_very_nomagic() - if self.isend(self.reader.peek()) - return ['<END>', '<END>'] - endif - let c = self.reader.get() - if c ==# '\' - let pos = self.reader.tell() - let c = self.reader.get() - if c ==# '*' - return ['\*', '\*'] - elseif c ==# '+' - return ['\+', '\+'] - elseif c ==# '=' - return ['\=', '\='] - elseif c ==# '?' - return ['\?', '\?'] - elseif c ==# '{' - return self.get_token_brace('\{') - elseif c ==# '@' - return self.get_token_at('\@') - elseif c ==# '^' - return ['\^', '\^'] - elseif c ==# '$' - return ['\$', '\$'] - elseif c ==# '<' - return ['\<', '\<'] - elseif c ==# '>' - return ['\>', '\>'] - elseif c ==# '%' - return self.get_token_percent('\%') - elseif c ==# '~' - return ['\~', '\~'] - elseif c ==# '[' - return self.get_token_sq('\[') - elseif c ==# '|' - return ['\|', '\|'] - elseif c ==# '&' - return ['\&', '\&'] - elseif c ==# '(' - return ['\(', '\('] - elseif c ==# ')' - return ['\)', '\)'] - endif - call self.reader.seek_set(pos) - return self.get_token_backslash_common() - endif - return [c, c] -endfunction - -function! s:RegexpParser.get_token_backslash_common() - let cclass = 'iIkKfFpPsSdDxXoOwWhHaAlLuU' - let c = self.reader.get() - if c ==# '\' - return ['\\', '\\'] - elseif stridx(cclass, c) != -1 - return ['\' . c, '\' . c] - elseif c == '_' - let epos = self.reader.getpos() - let c = self.reader.get() - if stridx(cclass, c) != -1 - return ['\_' . c, '\_ . c'] - elseif c ==# '^' - return ['\_^', '\_^'] - elseif c ==# '$' - return ['\_$', '\_$'] - elseif c ==# '.' - return ['\_.', '\_.'] - elseif c ==# '[' - return self.get_token_sq('\_[') - endif - throw s:Err('E63: invalid use of \_', epos) - elseif stridx('etrb', c) != -1 - return ['\' . c, '\' . c] - elseif stridx('123456789', c) != -1 - return ['\' . c, '\' . c] - elseif c == 'z' - let epos = self.reader.getpos() - let c = self.reader.get() - if stridx('123456789', c) != -1 - return ['\z' . c, '\z' . c] - elseif c ==# 's' - return ['\zs', '\zs'] - elseif c ==# 'e' - return ['\ze', '\ze'] - elseif c ==# '(' - return ['\z(', '\z('] - endif - throw s:Err('E68: Invalid character after \z', epos) - elseif stridx('cCmMvVZ', c) != -1 - return ['\' . c, '\' . c] - elseif c == '%' - let epos = self.reader.getpos() - let c = self.reader.get() - if c ==# 'd' - let r = self.getdecchrs() - if r !=# '' - return ['\%d' . r, '\%d' . r] - endif - elseif c ==# 'o' - let r = self.getoctchrs() - if r !=# '' - return ['\%o' . r, '\%o' . r] - endif - elseif c ==# 'x' - let r = self.gethexchrs(2) - if r !=# '' - return ['\%x' . r, '\%x' . r] - endif - elseif c ==# 'u' - let r = self.gethexchrs(4) - if r !=# '' - return ['\%u' . r, '\%u' . r] - endif - elseif c ==# 'U' - let r = self.gethexchrs(8) - if r !=# '' - return ['\%U' . r, '\%U' . r] - endif - endif - throw s:Err('E678: Invalid character after \%[dxouU]', epos) - endif - return ['\' . c, c] -endfunction - -" \{} -function! s:RegexpParser.get_token_brace(pre) - let r = '' - let minus = '' - let comma = '' - let n = '' - let m = '' - if self.reader.p(0) ==# '-' - let minus = self.reader.get() - let r .= minus - endif - if s:isdigit(self.reader.p(0)) - let n = self.reader.read_digit() - let r .= n - endif - if self.reader.p(0) ==# ',' - let comma = self.rader.get() - let r .= comma - endif - if s:isdigit(self.reader.p(0)) - let m = self.reader.read_digit() - let r .= m - endif - if self.reader.p(0) ==# '\' - let r .= self.reader.get() - endif - if self.reader.p(0) !=# '}' - throw s:Err('E554: Syntax error in \{...}', self.reader.getpos()) - endif - call self.reader.get() - return [a:pre . r, '\{' . minus . n . comma . m . '}'] -endfunction - -" \[] -function! s:RegexpParser.get_token_sq(pre) - let start = self.reader.tell() - let r = '' - " Complement of range - if self.reader.p(0) ==# '^' - let r .= self.reader.get() - endif - " At the start ']' and '-' mean the literal character. - if self.reader.p(0) ==# ']' || self.reader.p(0) ==# '-' - let r .= self.reader.get() - endif - while s:TRUE - let startc = 0 - let c = self.reader.p(0) - if self.isend(c) - " If there is no matching ']', we assume the '[' is a normal character. - call self.reader.seek_set(start) - return [a:pre, '['] - elseif c ==# ']' - call self.reader.seek_cur(1) - return [a:pre . r . ']', '\[' . r . ']'] - elseif c ==# '[' - let e = self.get_token_sq_char_class() - if e ==# '' - let e = self.get_token_sq_equi_class() - if e ==# '' - let e = self.get_token_sq_coll_element() - if e ==# '' - let [e, startc] = self.get_token_sq_c() - endif - endif - endif - let r .= e - else - let [e, startc] = self.get_token_sq_c() - let r .= e - endif - if startc != 0 && self.reader.p(0) ==# '-' && !self.isend(self.reader.p(1)) && !(self.reader.p(1) ==# '\' && self.reader.p(2) ==# 'n') - call self.reader.seek_cur(1) - let r .= '-' - let c = self.reader.p(0) - if c ==# '[' - let e = self.get_token_sq_coll_element() - if e !=# '' - let endc = char2nr(e[2]) - else - let [e, endc] = self.get_token_sq_c() - endif - let r .= e - else - let [e, endc] = self.get_token_sq_c() - let r .= e - endif - if startc > endc || endc > startc + 256 - throw s:Err('E16: Invalid range', self.reader.getpos()) - endif - endif - endwhile -endfunction - -" [c] -function! s:RegexpParser.get_token_sq_c() - let c = self.reader.p(0) - if c ==# '\' - call self.reader.seek_cur(1) - let c = self.reader.p(0) - if c ==# 'n' - call self.reader.seek_cur(1) - return ['\n', 0] - elseif c ==# 'r' - call self.reader.seek_cur(1) - return ['\r', char2nr("\r")] - elseif c ==# 't' - call self.reader.seek_cur(1) - return ['\t', char2nr("\t")] - elseif c ==# 'e' - call self.reader.seek_cur(1) - return ['\e', char2nr("\e")] - elseif c ==# 'b' - call self.reader.seek_cur(1) - return ['\b', char2nr("\b")] - elseif stridx(']^-\', c) != -1 - call self.reader.seek_cur(1) - return ['\' . c, char2nr(c)] - elseif stridx('doxuU', c) != -1 - let [c, n] = self.get_token_sq_coll_char() - return [c, n] - else - return ['\', char2nr('\')] - endif - elseif c ==# '-' - call self.reader.seek_cur(1) - return ['-', char2nr('-')] - else - call self.reader.seek_cur(1) - return [c, char2nr(c)] - endif -endfunction - -" [\d123] -function! s:RegexpParser.get_token_sq_coll_char() - let pos = self.reader.tell() - let c = self.reader.get() - if c ==# 'd' - let r = self.getdecchrs() - let n = str2nr(r, 10) - elseif c ==# 'o' - let r = self.getoctchrs() - let n = str2nr(r, 8) - elseif c ==# 'x' - let r = self.gethexchrs(2) - let n = str2nr(r, 16) - elseif c ==# 'u' - let r = self.gethexchrs(4) - let n = str2nr(r, 16) - elseif c ==# 'U' - let r = self.gethexchrs(8) - let n = str2nr(r, 16) - else - let r = '' - endif - if r ==# '' - call self.reader.seek_set(pos) - return '\' - endif - return ['\' . c . r, n] -endfunction - -" [[.a.]] -function! s:RegexpParser.get_token_sq_coll_element() - if self.reader.p(0) ==# '[' && self.reader.p(1) ==# '.' && !self.isend(self.reader.p(2)) && self.reader.p(3) ==# '.' && self.reader.p(4) ==# ']' - return self.reader.getn(5) - endif - return '' -endfunction - -" [[=a=]] -function! s:RegexpParser.get_token_sq_equi_class() - if self.reader.p(0) ==# '[' && self.reader.p(1) ==# '=' && !self.isend(self.reader.p(2)) && self.reader.p(3) ==# '=' && self.reader.p(4) ==# ']' - return self.reader.getn(5) - endif - return '' -endfunction - -" [[:alpha:]] -function! s:RegexpParser.get_token_sq_char_class() - let class_names = ["alnum", "alpha", "blank", "cntrl", "digit", "graph", "lower", "print", "punct", "space", "upper", "xdigit", "tab", "return", "backspace", "escape"] - let pos = self.reader.tell() - if self.reader.p(0) ==# '[' && self.reader.p(1) ==# ':' - call self.reader.seek_cur(2) - let r = self.reader.read_alpha() - if self.reader.p(0) ==# ':' && self.reader.p(1) ==# ']' - call self.reader.seek_cur(2) - for name in class_names - if r ==# name - return '[:' . name . ':]' - endif - endfor - endif - endif - call self.reader.seek_set(pos) - return '' -endfunction - -" \@... -function! s:RegexpParser.get_token_at(pre) - let epos = self.reader.getpos() - let c = self.reader.get() - if c ==# '>' - return [a:pre . '>', '\@>'] - elseif c ==# '=' - return [a:pre . '=', '\@='] - elseif c ==# '!' - return [a:pre . '!', '\@!'] - elseif c ==# '<' - let c = self.reader.get() - if c ==# '=' - return [a:pre . '<=', '\@<='] - elseif c ==# '!' - return [a:pre . '<!', '\@<!'] - endif - endif - throw s:Err('E64: @ follows nothing', epos) -endfunction - -" \%... -function! s:RegexpParser.get_token_percent(pre) - let c = self.reader.get() - if c ==# '^' - return [a:pre . '^', '\%^'] - elseif c ==# '$' - return [a:pre . '$', '\%$'] - elseif c ==# 'V' - return [a:pre . 'V', '\%V'] - elseif c ==# '#' - return [a:pre . '#', '\%#'] - elseif c ==# '[' - return self.get_token_percent_sq(a:pre . '[') - elseif c ==# '(' - return [a:pre . '(', '\%('] - else - return self.get_token_mlcv(a:pre) - endif -endfunction - -" \%[] -function! s:RegexpParser.get_token_percent_sq(pre) - let r = '' - while s:TRUE - let c = self.reader.peek() - if self.isend(c) - throw s:Err('E69: Missing ] after \%[', self.reader.getpos()) - elseif c ==# ']' - if r ==# '' - throw s:Err('E70: Empty \%[', self.reader.getpos()) - endif - call self.reader.seek_cur(1) - break - endif - call self.reader.seek_cur(1) - let r .= c - endwhile - return [a:pre . r . ']', '\%[' . r . ']'] -endfunction - -" \%'m \%l \%c \%v -function! s:RegexpParser.get_token_mlvc(pre) - let r = '' - let cmp = '' - if self.reader.p(0) ==# '<' || self.reader.p(0) ==# '>' - let cmp = self.reader.get() - let r .= cmp - endif - if self.reader.p(0) ==# "'" - let r .= self.reader.get() - let c = self.reader.p(0) - if self.isend(c) - " FIXME: Should be error? Vim allow this. - let c = '' - else - let c = self.reader.get() - endif - return [a:pre . r . c, '\%' . cmp . "'" . c] - elseif s:isdigit(self.reader.p(0)) - let d = self.reader.read_digit() - let r .= d - let c = self.reader.p(0) - if c ==# 'l' - call self.reader.get() - return [a:pre . r . 'l', '\%' . cmp . d . 'l'] - elseif c ==# 'c' - call self.reader.get() - return [a:pre . r . 'c', '\%' . cmp . d . 'c'] - elseif c ==# 'v' - call self.reader.get() - return [a:pre . r . 'v', '\%' . cmp . d . 'v'] - endif - endif - throw s:Err('E71: Invalid character after %', self.reader.getpos()) -endfunction - -function! s:RegexpParser.getdecchrs() - return self.reader.read_digit() -endfunction - -function! s:RegexpParser.getoctchrs() - return self.reader.read_odigit() -endfunction - -function! s:RegexpParser.gethexchrs(n) - let r = '' - for i in range(a:n) - let c = self.reader.peek() - if !s:isxdigit(c) - break - endif - let r .= self.reader.get() - endfor - return r -endfunction - + return a:num + endfunction +endif diff --git a/autoload/vital.vim b/autoload/vital.vim new file mode 100644 index 00000000..f1ba849a --- /dev/null +++ b/autoload/vital.vim @@ -0,0 +1,12 @@ +function! vital#of(name) abort + let files = globpath(&runtimepath, 'autoload/vital/' . a:name . '.vital', 1) + let file = split(files, "\n") + if empty(file) + throw 'vital: version file not found: ' . a:name + endif + let ver = readfile(file[0], 'b') + if empty(ver) + throw 'vital: invalid version file: ' . a:name + endif + return vital#_{substitute(ver[0], '\W', '', 'g')}#new() +endfunction diff --git a/autoload/vital/__vimlparser__/VimLParser.vim b/autoload/vital/__vimlparser__/VimLParser.vim new file mode 100644 index 00000000..80df8a04 --- /dev/null +++ b/autoload/vital/__vimlparser__/VimLParser.vim @@ -0,0 +1,5366 @@ +" vim:set ts=8 sts=2 sw=2 tw=0 et: +" +" VimL parser - Vim Script Parser +" +" License: This file is placed in the public domain. + +" s:import is only public API and you can access this script-local function via +" vital.vim. See https://github.com/vim-jp/vital.vim for more detail. +" +" Historically, vimlparser.vim is not vital module and there are other exported +" functions as vital-module, but they are not expected to be used. +" The one reason we didn't make them as private function (add `_` prefix to +" script local function) is that this file will be translated into other +" languages like Python and JavaScript. Also, vimlparser developers have no +" need to learn vital.vim convention and develop vimlparser same as before as +" much as possible. +" +" Example: +" call extend(s:, vital#vital#import('VimLParser').import()) +" +" function! s:run() abort +" let code = [ +" \ 'let s:message = printf("hello %d", 1+(2*3))' +" \ ] +" let r = s:StringReader.new(code) +" let p = s:VimLParser.new() +" let c = s:Compiler.new() +" echo join(c.compile(p.parse(r)), "\n") +" endfunction +" +" call s:run() +function! s:import() abort + return s: +endfunction + +let s:NIL = [] +let s:TRUE = 1 +let s:FALSE = 0 + +let s:NODE_TOPLEVEL = 1 +let s:NODE_COMMENT = 2 +let s:NODE_EXCMD = 3 +let s:NODE_FUNCTION = 4 +let s:NODE_ENDFUNCTION = 5 +let s:NODE_DELFUNCTION = 6 +let s:NODE_RETURN = 7 +let s:NODE_EXCALL = 8 +let s:NODE_LET = 9 +let s:NODE_UNLET = 10 +let s:NODE_LOCKVAR = 11 +let s:NODE_UNLOCKVAR = 12 +let s:NODE_IF = 13 +let s:NODE_ELSEIF = 14 +let s:NODE_ELSE = 15 +let s:NODE_ENDIF = 16 +let s:NODE_WHILE = 17 +let s:NODE_ENDWHILE = 18 +let s:NODE_FOR = 19 +let s:NODE_ENDFOR = 20 +let s:NODE_CONTINUE = 21 +let s:NODE_BREAK = 22 +let s:NODE_TRY = 23 +let s:NODE_CATCH = 24 +let s:NODE_FINALLY = 25 +let s:NODE_ENDTRY = 26 +let s:NODE_THROW = 27 +let s:NODE_ECHO = 28 +let s:NODE_ECHON = 29 +let s:NODE_ECHOHL = 30 +let s:NODE_ECHOMSG = 31 +let s:NODE_ECHOERR = 32 +let s:NODE_EXECUTE = 33 +let s:NODE_TERNARY = 34 +let s:NODE_OR = 35 +let s:NODE_AND = 36 +let s:NODE_EQUAL = 37 +let s:NODE_EQUALCI = 38 +let s:NODE_EQUALCS = 39 +let s:NODE_NEQUAL = 40 +let s:NODE_NEQUALCI = 41 +let s:NODE_NEQUALCS = 42 +let s:NODE_GREATER = 43 +let s:NODE_GREATERCI = 44 +let s:NODE_GREATERCS = 45 +let s:NODE_GEQUAL = 46 +let s:NODE_GEQUALCI = 47 +let s:NODE_GEQUALCS = 48 +let s:NODE_SMALLER = 49 +let s:NODE_SMALLERCI = 50 +let s:NODE_SMALLERCS = 51 +let s:NODE_SEQUAL = 52 +let s:NODE_SEQUALCI = 53 +let s:NODE_SEQUALCS = 54 +let s:NODE_MATCH = 55 +let s:NODE_MATCHCI = 56 +let s:NODE_MATCHCS = 57 +let s:NODE_NOMATCH = 58 +let s:NODE_NOMATCHCI = 59 +let s:NODE_NOMATCHCS = 60 +let s:NODE_IS = 61 +let s:NODE_ISCI = 62 +let s:NODE_ISCS = 63 +let s:NODE_ISNOT = 64 +let s:NODE_ISNOTCI = 65 +let s:NODE_ISNOTCS = 66 +let s:NODE_ADD = 67 +let s:NODE_SUBTRACT = 68 +let s:NODE_CONCAT = 69 +let s:NODE_MULTIPLY = 70 +let s:NODE_DIVIDE = 71 +let s:NODE_REMAINDER = 72 +let s:NODE_NOT = 73 +let s:NODE_MINUS = 74 +let s:NODE_PLUS = 75 +let s:NODE_SUBSCRIPT = 76 +let s:NODE_SLICE = 77 +let s:NODE_CALL = 78 +let s:NODE_DOT = 79 +let s:NODE_NUMBER = 80 +let s:NODE_STRING = 81 +let s:NODE_LIST = 82 +let s:NODE_DICT = 83 +let s:NODE_OPTION = 85 +let s:NODE_IDENTIFIER = 86 +let s:NODE_CURLYNAME = 87 +let s:NODE_ENV = 88 +let s:NODE_REG = 89 +let s:NODE_CURLYNAMEPART = 90 +let s:NODE_CURLYNAMEEXPR = 91 +let s:NODE_LAMBDA = 92 + +let s:TOKEN_EOF = 1 +let s:TOKEN_EOL = 2 +let s:TOKEN_SPACE = 3 +let s:TOKEN_OROR = 4 +let s:TOKEN_ANDAND = 5 +let s:TOKEN_EQEQ = 6 +let s:TOKEN_EQEQCI = 7 +let s:TOKEN_EQEQCS = 8 +let s:TOKEN_NEQ = 9 +let s:TOKEN_NEQCI = 10 +let s:TOKEN_NEQCS = 11 +let s:TOKEN_GT = 12 +let s:TOKEN_GTCI = 13 +let s:TOKEN_GTCS = 14 +let s:TOKEN_GTEQ = 15 +let s:TOKEN_GTEQCI = 16 +let s:TOKEN_GTEQCS = 17 +let s:TOKEN_LT = 18 +let s:TOKEN_LTCI = 19 +let s:TOKEN_LTCS = 20 +let s:TOKEN_LTEQ = 21 +let s:TOKEN_LTEQCI = 22 +let s:TOKEN_LTEQCS = 23 +let s:TOKEN_MATCH = 24 +let s:TOKEN_MATCHCI = 25 +let s:TOKEN_MATCHCS = 26 +let s:TOKEN_NOMATCH = 27 +let s:TOKEN_NOMATCHCI = 28 +let s:TOKEN_NOMATCHCS = 29 +let s:TOKEN_IS = 30 +let s:TOKEN_ISCI = 31 +let s:TOKEN_ISCS = 32 +let s:TOKEN_ISNOT = 33 +let s:TOKEN_ISNOTCI = 34 +let s:TOKEN_ISNOTCS = 35 +let s:TOKEN_PLUS = 36 +let s:TOKEN_MINUS = 37 +let s:TOKEN_DOT = 38 +let s:TOKEN_STAR = 39 +let s:TOKEN_SLASH = 40 +let s:TOKEN_PERCENT = 41 +let s:TOKEN_NOT = 42 +let s:TOKEN_QUESTION = 43 +let s:TOKEN_COLON = 44 +let s:TOKEN_POPEN = 45 +let s:TOKEN_PCLOSE = 46 +let s:TOKEN_SQOPEN = 47 +let s:TOKEN_SQCLOSE = 48 +let s:TOKEN_COPEN = 49 +let s:TOKEN_CCLOSE = 50 +let s:TOKEN_COMMA = 51 +let s:TOKEN_NUMBER = 52 +let s:TOKEN_SQUOTE = 53 +let s:TOKEN_DQUOTE = 54 +let s:TOKEN_OPTION = 55 +let s:TOKEN_IDENTIFIER = 56 +let s:TOKEN_ENV = 57 +let s:TOKEN_REG = 58 +let s:TOKEN_EQ = 59 +let s:TOKEN_OR = 60 +let s:TOKEN_SEMICOLON = 61 +let s:TOKEN_BACKTICK = 62 +let s:TOKEN_DOTDOTDOT = 63 +let s:TOKEN_SHARP = 64 +let s:TOKEN_ARROW = 65 + +let s:MAX_FUNC_ARGS = 20 + +function! s:isalpha(c) + return a:c =~# '^[A-Za-z]$' +endfunction + +function! s:isalnum(c) + return a:c =~# '^[0-9A-Za-z]$' +endfunction + +function! s:isdigit(c) + return a:c =~# '^[0-9]$' +endfunction + +function! s:isodigit(c) + return a:c =~# '^[0-7]$' +endfunction + +function! s:isxdigit(c) + return a:c =~# '^[0-9A-Fa-f]$' +endfunction + +function! s:iswordc(c) + return a:c =~# '^[0-9A-Za-z_]$' +endfunction + +function! s:iswordc1(c) + return a:c =~# '^[A-Za-z_]$' +endfunction + +function! s:iswhite(c) + return a:c =~# '^[ \t]$' +endfunction + +function! s:isnamec(c) + return a:c =~# '^[0-9A-Za-z_:#]$' +endfunction + +function! s:isnamec1(c) + return a:c =~# '^[A-Za-z_]$' +endfunction + +function! s:isargname(s) + return a:s =~# '^[A-Za-z_][0-9A-Za-z_]*$' +endfunction + +function! s:isvarname(s) + return a:s =~# '^[vgslabwt]:$\|^\([vgslabwt]:\)\?[A-Za-z_][0-9A-Za-z_#]*$' +endfunction + +" FIXME: +function! s:isidc(c) + return a:c =~# '^[0-9A-Za-z_]$' +endfunction + +function! s:isupper(c) + return a:c =~# '^[A-Z]$' +endfunction + +function! s:islower(c) + return a:c =~# '^[a-z]$' +endfunction + +function! s:ExArg() + let ea = {} + let ea.forceit = s:FALSE + let ea.addr_count = 0 + let ea.line1 = 0 + let ea.line2 = 0 + let ea.flags = 0 + let ea.do_ecmd_cmd = '' + let ea.do_ecmd_lnum = 0 + let ea.append = 0 + let ea.usefilter = s:FALSE + let ea.amount = 0 + let ea.regname = 0 + let ea.force_bin = 0 + let ea.read_edit = 0 + let ea.force_ff = 0 + let ea.force_enc = 0 + let ea.bad_char = 0 + let ea.linepos = {} + let ea.cmdpos = [] + let ea.argpos = [] + let ea.cmd = {} + let ea.modifiers = [] + let ea.range = [] + let ea.argopt = {} + let ea.argcmd = {} + return ea +endfunction + +" struct node { +" int type +" pos pos +" node left +" node right +" node cond +" node rest +" node[] list +" node[] rlist +" node[] body +" string op +" string str +" int depth +" variant value +" } +" TOPLEVEL .body +" COMMENT .str +" EXCMD .ea .str +" FUNCTION .ea .body .left .rlist .attr .endfunction +" ENDFUNCTION .ea +" DELFUNCTION .ea .left +" RETURN .ea .left +" EXCALL .ea .left +" LET .ea .op .left .list .rest .right +" UNLET .ea .list +" LOCKVAR .ea .depth .list +" UNLOCKVAR .ea .depth .list +" IF .ea .body .cond .elseif .else .endif +" ELSEIF .ea .body .cond +" ELSE .ea .body +" ENDIF .ea +" WHILE .ea .body .cond .endwhile +" ENDWHILE .ea +" FOR .ea .body .left .list .rest .right .endfor +" ENDFOR .ea +" CONTINUE .ea +" BREAK .ea +" TRY .ea .body .catch .finally .endtry +" CATCH .ea .body .pattern +" FINALLY .ea .body +" ENDTRY .ea +" THROW .ea .left +" ECHO .ea .list +" ECHON .ea .list +" ECHOHL .ea .str +" ECHOMSG .ea .list +" ECHOERR .ea .list +" EXECUTE .ea .list +" TERNARY .cond .left .right +" OR .left .right +" AND .left .right +" EQUAL .left .right +" EQUALCI .left .right +" EQUALCS .left .right +" NEQUAL .left .right +" NEQUALCI .left .right +" NEQUALCS .left .right +" GREATER .left .right +" GREATERCI .left .right +" GREATERCS .left .right +" GEQUAL .left .right +" GEQUALCI .left .right +" GEQUALCS .left .right +" SMALLER .left .right +" SMALLERCI .left .right +" SMALLERCS .left .right +" SEQUAL .left .right +" SEQUALCI .left .right +" SEQUALCS .left .right +" MATCH .left .right +" MATCHCI .left .right +" MATCHCS .left .right +" NOMATCH .left .right +" NOMATCHCI .left .right +" NOMATCHCS .left .right +" IS .left .right +" ISCI .left .right +" ISCS .left .right +" ISNOT .left .right +" ISNOTCI .left .right +" ISNOTCS .left .right +" ADD .left .right +" SUBTRACT .left .right +" CONCAT .left .right +" MULTIPLY .left .right +" DIVIDE .left .right +" REMAINDER .left .right +" NOT .left +" MINUS .left +" PLUS .left +" SUBSCRIPT .left .right +" SLICE .left .rlist +" CALL .left .rlist +" DOT .left .right +" NUMBER .value +" STRING .value +" LIST .value +" DICT .value +" NESTING .left +" OPTION .value +" IDENTIFIER .value +" CURLYNAME .value +" ENV .value +" REG .value +" CURLYNAMEPART .value +" CURLYNAMEEXPR .value +" LAMBDA .rlist .left +function! s:Node(type) + return {'type': a:type} +endfunction + +function! s:Err(msg, pos) + return printf('vimlparser: %s: line %d col %d', a:msg, a:pos.lnum, a:pos.col) +endfunction + +let s:VimLParser = {} + +function! s:VimLParser.new(...) + let obj = copy(self) + call call(obj.__init__, a:000, obj) + return obj +endfunction + +function! s:VimLParser.__init__(...) + if len(a:000) > 0 + let self.neovim = a:000[0] + else + let self.neovim = 0 + endif + + let self.find_command_cache = {} +endfunction + +function! s:VimLParser.push_context(node) + call insert(self.context, a:node) +endfunction + +function! s:VimLParser.pop_context() + call remove(self.context, 0) +endfunction + +function! s:VimLParser.find_context(type) + let i = 0 + for node in self.context + if node.type == a:type + return i + endif + let i += 1 + endfor + return -1 +endfunction + +function! s:VimLParser.add_node(node) + call add(self.context[0].body, a:node) +endfunction + +function! s:VimLParser.check_missing_endfunction(ends, pos) + if self.context[0].type == s:NODE_FUNCTION + throw s:Err(printf('E126: Missing :endfunction: %s', a:ends), a:pos) + endif +endfunction + +function! s:VimLParser.check_missing_endif(ends, pos) + if self.context[0].type == s:NODE_IF || self.context[0].type == s:NODE_ELSEIF || self.context[0].type == s:NODE_ELSE + throw s:Err(printf('E171: Missing :endif: %s', a:ends), a:pos) + endif +endfunction + +function! s:VimLParser.check_missing_endtry(ends, pos) + if self.context[0].type == s:NODE_TRY || self.context[0].type == s:NODE_CATCH || self.context[0].type == s:NODE_FINALLY + throw s:Err(printf('E600: Missing :endtry: %s', a:ends), a:pos) + endif +endfunction + +function! s:VimLParser.check_missing_endwhile(ends, pos) + if self.context[0].type == s:NODE_WHILE + throw s:Err(printf('E170: Missing :endwhile: %s', a:ends), a:pos) + endif +endfunction + +function! s:VimLParser.check_missing_endfor(ends, pos) + if self.context[0].type == s:NODE_FOR + throw s:Err(printf('E170: Missing :endfor: %s', a:ends), a:pos) + endif +endfunction + +function! s:VimLParser.parse(reader) + let self.reader = a:reader + let self.context = [] + let toplevel = s:Node(s:NODE_TOPLEVEL) + let toplevel.pos = self.reader.getpos() + let toplevel.body = [] + call self.push_context(toplevel) + while self.reader.peek() !=# '<EOF>' + call self.parse_one_cmd() + endwhile + call self.check_missing_endfunction('TOPLEVEL', self.reader.getpos()) + call self.check_missing_endif('TOPLEVEL', self.reader.getpos()) + call self.check_missing_endtry('TOPLEVEL', self.reader.getpos()) + call self.check_missing_endwhile('TOPLEVEL', self.reader.getpos()) + call self.check_missing_endfor('TOPLEVEL', self.reader.getpos()) + call self.pop_context() + return toplevel +endfunction + +function! s:VimLParser.parse_one_cmd() + let self.ea = s:ExArg() + + if self.reader.peekn(2) ==# '#!' + call self.parse_hashbang() + call self.reader.get() + return + endif + call self.reader.skip_white_and_colon() + if self.reader.peekn(1) ==# '' + call self.reader.get() + return + endif + if self.reader.peekn(1) ==# '"' + call self.parse_comment() + call self.reader.get() + return + endif + let self.ea.linepos = self.reader.getpos() + call self.parse_command_modifiers() + call self.parse_range() + call self.parse_command() + call self.parse_trail() +endfunction + +" FIXME: +function! s:VimLParser.parse_command_modifiers() + let modifiers = [] + while s:TRUE + let pos = self.reader.tell() + let d = '' + if s:isdigit(self.reader.peekn(1)) + let d = self.reader.read_digit() + call self.reader.skip_white() + endif + let k = self.reader.read_alpha() + let c = self.reader.peekn(1) + call self.reader.skip_white() + if stridx('aboveleft', k) == 0 && len(k) >= 3 " abo\%[veleft] + call add(modifiers, {'name': 'aboveleft'}) + elseif stridx('belowright', k) == 0 && len(k) >= 3 " bel\%[owright] + call add(modifiers, {'name': 'belowright'}) + elseif stridx('browse', k) == 0 && len(k) >= 3 " bro\%[wse] + call add(modifiers, {'name': 'browse'}) + elseif stridx('botright', k) == 0 && len(k) >= 2 " bo\%[tright] + call add(modifiers, {'name': 'botright'}) + elseif stridx('confirm', k) == 0 && len(k) >= 4 " conf\%[irm] + call add(modifiers, {'name': 'confirm'}) + elseif stridx('keepmarks', k) == 0 && len(k) >= 3 " kee\%[pmarks] + call add(modifiers, {'name': 'keepmarks'}) + elseif stridx('keepalt', k) == 0 && len(k) >= 5 " keepa\%[lt] + call add(modifiers, {'name': 'keepalt'}) + elseif stridx('keepjumps', k) == 0 && len(k) >= 5 " keepj\%[umps] + call add(modifiers, {'name': 'keepjumps'}) + elseif stridx('keeppatterns', k) == 0 && len(k) >= 5 " keepp\%[atterns] + call add(modifiers, {'name': 'keeppatterns'}) + elseif stridx('hide', k) == 0 && len(k) >= 3 "hid\%[e] + if self.ends_excmds(c) + break + endif + call add(modifiers, {'name': 'hide'}) + elseif stridx('lockmarks', k) == 0 && len(k) >= 3 " loc\%[kmarks] + call add(modifiers, {'name': 'lockmarks'}) + elseif stridx('leftabove', k) == 0 && len(k) >= 5 " lefta\%[bove] + call add(modifiers, {'name': 'leftabove'}) + elseif stridx('noautocmd', k) == 0 && len(k) >= 3 " noa\%[utocmd] + call add(modifiers, {'name': 'noautocmd'}) + elseif stridx('noswapfile', k) == 0 && len(k) >= 3 " :nos\%[wapfile] + call add(modifiers, {'name': 'noswapfile'}) + elseif stridx('rightbelow', k) == 0 && len(k) >= 6 "rightb\%[elow] + call add(modifiers, {'name': 'rightbelow'}) + elseif stridx('sandbox', k) == 0 && len(k) >= 3 " san\%[dbox] + call add(modifiers, {'name': 'sandbox'}) + elseif stridx('silent', k) == 0 && len(k) >= 3 " sil\%[ent] + if c ==# '!' + call self.reader.get() + call add(modifiers, {'name': 'silent', 'bang': 1}) + else + call add(modifiers, {'name': 'silent', 'bang': 0}) + endif + elseif k ==# 'tab' " tab + if d !=# '' + call add(modifiers, {'name': 'tab', 'count': str2nr(d, 10)}) + else + call add(modifiers, {'name': 'tab'}) + endif + elseif stridx('topleft', k) == 0 && len(k) >= 2 " to\%[pleft] + call add(modifiers, {'name': 'topleft'}) + elseif stridx('unsilent', k) == 0 && len(k) >= 3 " uns\%[ilent] + call add(modifiers, {'name': 'unsilent'}) + elseif stridx('vertical', k) == 0 && len(k) >= 4 " vert\%[ical] + call add(modifiers, {'name': 'vertical'}) + elseif stridx('verbose', k) == 0 && len(k) >= 4 " verb\%[ose] + if d !=# '' + call add(modifiers, {'name': 'verbose', 'count': str2nr(d, 10)}) + else + call add(modifiers, {'name': 'verbose', 'count': 1}) + endif + else + call self.reader.seek_set(pos) + break + endif + endwhile + let self.ea.modifiers = modifiers +endfunction + +" FIXME: +function! s:VimLParser.parse_range() + let tokens = [] + + while s:TRUE + + while s:TRUE + call self.reader.skip_white() + + let c = self.reader.peekn(1) + if c ==# '' + break + endif + + if c ==# '.' + call add(tokens, self.reader.getn(1)) + elseif c ==# '$' + call add(tokens, self.reader.getn(1)) + elseif c ==# "'" + call self.reader.getn(1) + let m = self.reader.getn(1) + if m ==# '' + break + endif + call add(tokens, "'" . m) + elseif c ==# '/' + call self.reader.getn(1) + let [pattern, _] = self.parse_pattern(c) + call add(tokens, pattern) + elseif c ==# '?' + call self.reader.getn(1) + let [pattern, _] = self.parse_pattern(c) + call add(tokens, pattern) + elseif c ==# '\' + let m = self.reader.p(1) + if m ==# '&' || m ==# '?' || m ==# '/' + call self.reader.seek_cur(2) + call add(tokens, '\' . m) + else + throw s:Err('E10: \\ should be followed by /, ? or &', self.reader.getpos()) + endif + elseif s:isdigit(c) + call add(tokens, self.reader.read_digit()) + endif + + while s:TRUE + call self.reader.skip_white() + if self.reader.peekn(1) ==# '' + break + endif + let n = self.reader.read_integer() + if n ==# '' + break + endif + call add(tokens, n) + endwhile + + if self.reader.p(0) !=# '/' && self.reader.p(0) !=# '?' + break + endif + endwhile + + if self.reader.peekn(1) ==# '%' + call add(tokens, self.reader.getn(1)) + elseif self.reader.peekn(1) ==# '*' " && &cpoptions !~ '\*' + call add(tokens, self.reader.getn(1)) + endif + + if self.reader.peekn(1) ==# ';' + call add(tokens, self.reader.getn(1)) + continue + elseif self.reader.peekn(1) ==# ',' + call add(tokens, self.reader.getn(1)) + continue + endif + + break + endwhile + + let self.ea.range = tokens +endfunction + +" FIXME: +function! s:VimLParser.parse_pattern(delimiter) + let pattern = '' + let endc = '' + let inbracket = 0 + while s:TRUE + let c = self.reader.getn(1) + if c ==# '' + break + endif + if c ==# a:delimiter && inbracket == 0 + let endc = c + break + endif + let pattern .= c + if c ==# '\' + let c = self.reader.peekn(1) + if c ==# '' + throw s:Err('E682: Invalid search pattern or delimiter', self.reader.getpos()) + endif + call self.reader.getn(1) + let pattern .= c + elseif c ==# '[' + let inbracket += 1 + elseif c ==# ']' + let inbracket -= 1 + endif + endwhile + return [pattern, endc] +endfunction + +function! s:VimLParser.parse_command() + call self.reader.skip_white_and_colon() + + let self.ea.cmdpos = self.reader.getpos() + + if self.reader.peekn(1) ==# '' || self.reader.peekn(1) ==# '"' + if !empty(self.ea.modifiers) || !empty(self.ea.range) + call self.parse_cmd_modifier_range() + endif + return + endif + + let self.ea.cmd = self.find_command() + + if self.ea.cmd is s:NIL + call self.reader.setpos(self.ea.cmdpos) + throw s:Err(printf('E492: Not an editor command: %s', self.reader.peekline()), self.ea.cmdpos) + endif + + if self.reader.peekn(1) ==# '!' && self.ea.cmd.name !=# 'substitute' && self.ea.cmd.name !=# 'smagic' && self.ea.cmd.name !=# 'snomagic' + call self.reader.getn(1) + let self.ea.forceit = s:TRUE + else + let self.ea.forceit = s:FALSE + endif + + if self.ea.cmd.flags !~# '\<BANG\>' && self.ea.forceit && self.ea.cmd.flags !~# '\<USERCMD\>' + throw s:Err('E477: No ! allowed', self.ea.cmdpos) + endif + + if self.ea.cmd.name !=# '!' + call self.reader.skip_white() + endif + + let self.ea.argpos = self.reader.getpos() + + if self.ea.cmd.flags =~# '\<ARGOPT\>' + call self.parse_argopt() + endif + + if self.ea.cmd.name ==# 'write' || self.ea.cmd.name ==# 'update' + if self.reader.p(0) ==# '>' + if self.reader.p(1) !=# '>' + throw s:Err('E494: Use w or w>>', self.ea.cmdpos) + endif + call self.reader.seek_cur(2) + call self.reader.skip_white() + let self.ea.append = 1 + elseif self.reader.peekn(1) ==# '!' && self.ea.cmd.name ==# 'write' + call self.reader.getn(1) + let self.ea.usefilter = s:TRUE + endif + endif + + if self.ea.cmd.name ==# 'read' + if self.ea.forceit + let self.ea.usefilter = s:TRUE + let self.ea.forceit = s:FALSE + elseif self.reader.peekn(1) ==# '!' + call self.reader.getn(1) + let self.ea.usefilter = s:TRUE + endif + endif + + if self.ea.cmd.name ==# '<' || self.ea.cmd.name ==# '>' + let self.ea.amount = 1 + while self.reader.peekn(1) ==# self.ea.cmd.name + call self.reader.getn(1) + let self.ea.amount += 1 + endwhile + call self.reader.skip_white() + endif + + if self.ea.cmd.flags =~# '\<EDITCMD\>' && !self.ea.usefilter + call self.parse_argcmd() + endif + + call self._parse_command(self.ea.cmd.parser) +endfunction + +function! s:VimLParser._parse_command(parser) abort + if a:parser == 'parse_cmd_append' + call self.parse_cmd_append() + elseif a:parser == 'parse_cmd_break' + call self.parse_cmd_break() + elseif a:parser == 'parse_cmd_call' + call self.parse_cmd_call() + elseif a:parser == 'parse_cmd_catch' + call self.parse_cmd_catch() + elseif a:parser == 'parse_cmd_common' + call self.parse_cmd_common() + elseif a:parser == 'parse_cmd_continue' + call self.parse_cmd_continue() + elseif a:parser == 'parse_cmd_delfunction' + call self.parse_cmd_delfunction() + elseif a:parser == 'parse_cmd_echo' + call self.parse_cmd_echo() + elseif a:parser == 'parse_cmd_echoerr' + call self.parse_cmd_echoerr() + elseif a:parser == 'parse_cmd_echohl' + call self.parse_cmd_echohl() + elseif a:parser == 'parse_cmd_echomsg' + call self.parse_cmd_echomsg() + elseif a:parser == 'parse_cmd_echon' + call self.parse_cmd_echon() + elseif a:parser == 'parse_cmd_else' + call self.parse_cmd_else() + elseif a:parser == 'parse_cmd_elseif' + call self.parse_cmd_elseif() + elseif a:parser == 'parse_cmd_endfor' + call self.parse_cmd_endfor() + elseif a:parser == 'parse_cmd_endfunction' + call self.parse_cmd_endfunction() + elseif a:parser == 'parse_cmd_endif' + call self.parse_cmd_endif() + elseif a:parser == 'parse_cmd_endtry' + call self.parse_cmd_endtry() + elseif a:parser == 'parse_cmd_endwhile' + call self.parse_cmd_endwhile() + elseif a:parser == 'parse_cmd_execute' + call self.parse_cmd_execute() + elseif a:parser == 'parse_cmd_finally' + call self.parse_cmd_finally() + elseif a:parser == 'parse_cmd_finish' + call self.parse_cmd_finish() + elseif a:parser == 'parse_cmd_for' + call self.parse_cmd_for() + elseif a:parser == 'parse_cmd_function' + call self.parse_cmd_function() + elseif a:parser == 'parse_cmd_if' + call self.parse_cmd_if() + elseif a:parser == 'parse_cmd_insert' + call self.parse_cmd_insert() + elseif a:parser == 'parse_cmd_let' + call self.parse_cmd_let() + elseif a:parser == 'parse_cmd_loadkeymap' + call self.parse_cmd_loadkeymap() + elseif a:parser == 'parse_cmd_lockvar' + call self.parse_cmd_lockvar() + elseif a:parser == 'parse_cmd_lua' + call self.parse_cmd_lua() + elseif a:parser == 'parse_cmd_modifier_range' + call self.parse_cmd_modifier_range() + elseif a:parser == 'parse_cmd_mzscheme' + call self.parse_cmd_mzscheme() + elseif a:parser == 'parse_cmd_perl' + call self.parse_cmd_perl() + elseif a:parser == 'parse_cmd_python' + call self.parse_cmd_python() + elseif a:parser == 'parse_cmd_python3' + call self.parse_cmd_python3() + elseif a:parser == 'parse_cmd_return' + call self.parse_cmd_return() + elseif a:parser == 'parse_cmd_ruby' + call self.parse_cmd_ruby() + elseif a:parser == 'parse_cmd_tcl' + call self.parse_cmd_tcl() + elseif a:parser == 'parse_cmd_throw' + call self.parse_cmd_throw() + elseif a:parser == 'parse_cmd_try' + call self.parse_cmd_try() + elseif a:parser == 'parse_cmd_unlet' + call self.parse_cmd_unlet() + elseif a:parser == 'parse_cmd_unlockvar' + call self.parse_cmd_unlockvar() + elseif a:parser == 'parse_cmd_usercmd' + call self.parse_cmd_usercmd() + elseif a:parser == 'parse_cmd_while' + call self.parse_cmd_while() + elseif a:parser == 'parse_wincmd' + call self.parse_wincmd() + elseif a:parser == 'parse_cmd_syntax' + call self.parse_cmd_syntax() + else + throw printf('unknown parser: %s', string(a:parser)) + endif +endfunction + +function! s:VimLParser.find_command() + let c = self.reader.peekn(1) + let name = '' + + if c ==# 'k' + call self.reader.getn(1) + let name = 'k' + elseif c ==# 's' && self.reader.peekn(5) =~# '\v^s%(c[^sr][^i][^p]|g|i[^mlg]|I|r[^e])' + call self.reader.getn(1) + let name = 'substitute' + elseif c =~# '[@*!=><&~#]' + call self.reader.getn(1) + let name = c + elseif self.reader.peekn(2) ==# 'py' + let name = self.reader.read_alnum() + else + let pos = self.reader.tell() + let name = self.reader.read_alpha() + if name !=# 'del' && name =~# '\v^d%[elete][lp]$' + call self.reader.seek_set(pos) + let name = self.reader.getn(len(name) - 1) + endif + endif + + if name == '' + return s:NIL + endif + + if has_key(self.find_command_cache, name) + return self.find_command_cache[name] + endif + + let cmd = s:NIL + + for x in self.builtin_commands + if stridx(x.name, name) == 0 && len(name) >= x.minlen + unlet cmd + let cmd = x + break + endif + endfor + + if self.neovim + for x in self.neovim_additional_commands + if stridx(x.name, name) == 0 && len(name) >= x.minlen + unlet cmd + let cmd = x + break + endif + endfor + + for x in self.neovim_removed_commands + if stridx(x.name, name) == 0 && len(name) >= x.minlen + unlet cmd + let cmd = s:NIL + break + endif + endfor + endif + + " FIXME: user defined command + if (cmd is s:NIL || cmd.name ==# 'Print') && name =~# '^[A-Z]' + let name .= self.reader.read_alnum() + unlet cmd + let cmd = {'name': name, 'flags': 'USERCMD', 'parser': 'parse_cmd_usercmd'} + endif + + let self.find_command_cache[name] = cmd + + return cmd +endfunction + +" TODO: +function! s:VimLParser.parse_hashbang() + call self.reader.getn(-1) +endfunction + +" TODO: +" ++opt=val +function! s:VimLParser.parse_argopt() + while self.reader.p(0) ==# '+' && self.reader.p(1) ==# '+' + let s = self.reader.peekn(20) + if s =~# '^++bin\>' + call self.reader.getn(5) + let self.ea.force_bin = 1 + elseif s =~# '^++nobin\>' + call self.reader.getn(7) + let self.ea.force_bin = 2 + elseif s =~# '^++edit\>' + call self.reader.getn(6) + let self.ea.read_edit = 1 + elseif s =~# '^++ff=\(dos\|unix\|mac\)\>' + call self.reader.getn(5) + let self.ea.force_ff = self.reader.read_alpha() + elseif s =~# '^++fileformat=\(dos\|unix\|mac\)\>' + call self.reader.getn(13) + let self.ea.force_ff = self.reader.read_alpha() + elseif s =~# '^++enc=\S' + call self.reader.getn(6) + let self.ea.force_enc = self.reader.read_nonwhite() + elseif s =~# '^++encoding=\S' + call self.reader.getn(11) + let self.ea.force_enc = self.reader.read_nonwhite() + elseif s =~# '^++bad=\(keep\|drop\|.\)\>' + call self.reader.getn(6) + if s =~# '^++bad=keep' + let self.ea.bad_char = self.reader.getn(4) + elseif s =~# '^++bad=drop' + let self.ea.bad_char = self.reader.getn(4) + else + let self.ea.bad_char = self.reader.getn(1) + endif + elseif s =~# '^++' + throw s:Err('E474: Invalid Argument', self.reader.getpos()) + else + break + endif + call self.reader.skip_white() + endwhile +endfunction + +" TODO: +" +command +function! s:VimLParser.parse_argcmd() + if self.reader.peekn(1) ==# '+' + call self.reader.getn(1) + if self.reader.peekn(1) ==# ' ' + let self.ea.do_ecmd_cmd = '$' + else + let self.ea.do_ecmd_cmd = self.read_cmdarg() + endif + endif +endfunction + +function! s:VimLParser.read_cmdarg() + let r = '' + while s:TRUE + let c = self.reader.peekn(1) + if c ==# '' || s:iswhite(c) + break + endif + call self.reader.getn(1) + if c ==# '\' + let c = self.reader.getn(1) + endif + let r .= c + endwhile + return r +endfunction + +function! s:VimLParser.parse_comment() + let npos = self.reader.getpos() + let c = self.reader.get() + if c !=# '"' + throw s:Err(printf('unexpected character: %s', c), npos) + endif + let node = s:Node(s:NODE_COMMENT) + let node.pos = npos + let node.str = self.reader.getn(-1) + call self.add_node(node) +endfunction + +function! s:VimLParser.parse_trail() + call self.reader.skip_white() + let c = self.reader.peek() + if c ==# '<EOF>' + " pass + elseif c ==# '<EOL>' + call self.reader.get() + elseif c ==# '|' + call self.reader.get() + elseif c ==# '"' + call self.parse_comment() + call self.reader.get() + else + throw s:Err(printf('E488: Trailing characters: %s', c), self.reader.getpos()) + endif +endfunction + +" modifier or range only command line +function! s:VimLParser.parse_cmd_modifier_range() + let node = s:Node(s:NODE_EXCMD) + let node.pos = self.ea.cmdpos + let node.ea = self.ea + let node.str = self.reader.getstr(self.ea.linepos, self.reader.getpos()) + call self.add_node(node) +endfunction + +" TODO: +function! s:VimLParser.parse_cmd_common() + let end = self.reader.getpos() + if self.ea.cmd.flags =~# '\<TRLBAR\>' && !self.ea.usefilter + let end = self.separate_nextcmd() + elseif self.ea.cmd.name ==# '!' || self.ea.cmd.name ==# 'global' || self.ea.cmd.name ==# 'vglobal' || self.ea.usefilter + while s:TRUE + let end = self.reader.getpos() + if self.reader.getn(1) ==# '' + break + endif + endwhile + else + while s:TRUE + let end = self.reader.getpos() + if self.reader.getn(1) ==# '' + break + endif + endwhile + endif + let node = s:Node(s:NODE_EXCMD) + let node.pos = self.ea.cmdpos + let node.ea = self.ea + let node.str = self.reader.getstr(self.ea.linepos, end) + call self.add_node(node) +endfunction + +function! s:VimLParser.separate_nextcmd() + if self.ea.cmd.name ==# 'vimgrep' || self.ea.cmd.name ==# 'vimgrepadd' || self.ea.cmd.name ==# 'lvimgrep' || self.ea.cmd.name ==# 'lvimgrepadd' + call self.skip_vimgrep_pat() + endif + let pc = '' + let end = self.reader.getpos() + let nospend = end + while s:TRUE + let end = self.reader.getpos() + if !s:iswhite(pc) + let nospend = end + endif + let c = self.reader.peek() + if c ==# '<EOF>' || c ==# '<EOL>' + break + elseif c ==# "\x16" " <C-V> + call self.reader.get() + let end = self.reader.getpos() + let nospend = self.reader.getpos() + let c = self.reader.peek() + if c ==# '<EOF>' || c ==# '<EOL>' + break + endif + call self.reader.get() + elseif self.reader.peekn(2) ==# '`=' && self.ea.cmd.flags =~# '\<\(XFILE\|FILES\|FILE1\)\>' + call self.reader.getn(2) + call self.parse_expr() + let c = self.reader.peekn(1) + if c !=# '`' + throw s:Err(printf('unexpected character: %s', c), self.reader.getpos()) + endif + call self.reader.getn(1) + elseif c ==# '|' || c ==# "\n" || + \ (c ==# '"' && self.ea.cmd.flags !~# '\<NOTRLCOM\>' + \ && ((self.ea.cmd.name !=# '@' && self.ea.cmd.name !=# '*') + \ || self.reader.getpos() !=# self.ea.argpos) + \ && (self.ea.cmd.name !=# 'redir' + \ || self.reader.getpos().i != self.ea.argpos.i + 1 || pc !=# '@')) + let has_cpo_bar = s:FALSE " &cpoptions =~ 'b' + if (!has_cpo_bar || self.ea.cmd.flags !~# '\<USECTRLV\>') && pc ==# '\' + call self.reader.get() + else + break + endif + else + call self.reader.get() + endif + let pc = c + endwhile + if self.ea.cmd.flags !~# '\<NOTRLCOM\>' + let end = nospend + endif + return end +endfunction + +" FIXME +function! s:VimLParser.skip_vimgrep_pat() + if self.reader.peekn(1) ==# '' + " pass + elseif s:isidc(self.reader.peekn(1)) + " :vimgrep pattern fname + call self.reader.read_nonwhite() + else + " :vimgrep /pattern/[g][j] fname + let c = self.reader.getn(1) + let [_, endc] = self.parse_pattern(c) + if c !=# endc + return + endif + while self.reader.p(0) ==# 'g' || self.reader.p(0) ==# 'j' + call self.reader.getn(1) + endwhile + endif +endfunction + +function! s:VimLParser.parse_cmd_append() + call self.reader.setpos(self.ea.linepos) + let cmdline = self.reader.readline() + let lines = [cmdline] + let m = '.' + while s:TRUE + if self.reader.peek() ==# '<EOF>' + break + endif + let line = self.reader.getn(-1) + call add(lines, line) + if line ==# m + break + endif + call self.reader.get() + endwhile + let node = s:Node(s:NODE_EXCMD) + let node.pos = self.ea.cmdpos + let node.ea = self.ea + let node.str = join(lines, "\n") + call self.add_node(node) +endfunction + +function! s:VimLParser.parse_cmd_insert() + call self.parse_cmd_append() +endfunction + +function! s:VimLParser.parse_cmd_loadkeymap() + call self.reader.setpos(self.ea.linepos) + let cmdline = self.reader.readline() + let lines = [cmdline] + while s:TRUE + if self.reader.peek() ==# '<EOF>' + break + endif + let line = self.reader.readline() + call add(lines, line) + endwhile + let node = s:Node(s:NODE_EXCMD) + let node.pos = self.ea.cmdpos + let node.ea = self.ea + let node.str = join(lines, "\n") + call self.add_node(node) +endfunction + +function! s:VimLParser.parse_cmd_lua() + let lines = [] + call self.reader.skip_white() + if self.reader.peekn(2) ==# '<<' + call self.reader.getn(2) + call self.reader.skip_white() + let m = self.reader.readline() + if m ==# '' + let m = '.' + endif + call self.reader.setpos(self.ea.linepos) + let cmdline = self.reader.getn(-1) + let lines = [cmdline] + call self.reader.get() + while s:TRUE + if self.reader.peek() ==# '<EOF>' + break + endif + let line = self.reader.getn(-1) + call add(lines, line) + if line ==# m + break + endif + call self.reader.get() + endwhile + else + call self.reader.setpos(self.ea.linepos) + let cmdline = self.reader.getn(-1) + let lines = [cmdline] + endif + let node = s:Node(s:NODE_EXCMD) + let node.pos = self.ea.cmdpos + let node.ea = self.ea + let node.str = join(lines, "\n") + call self.add_node(node) +endfunction + +function! s:VimLParser.parse_cmd_mzscheme() + call self.parse_cmd_lua() +endfunction + +function! s:VimLParser.parse_cmd_perl() + call self.parse_cmd_lua() +endfunction + +function! s:VimLParser.parse_cmd_python() + call self.parse_cmd_lua() +endfunction + +function! s:VimLParser.parse_cmd_python3() + call self.parse_cmd_lua() +endfunction + +function! s:VimLParser.parse_cmd_ruby() + call self.parse_cmd_lua() +endfunction + +function! s:VimLParser.parse_cmd_tcl() + call self.parse_cmd_lua() +endfunction + +function! s:VimLParser.parse_cmd_finish() + call self.parse_cmd_common() + if self.context[0].type == s:NODE_TOPLEVEL + call self.reader.seek_end(0) + endif +endfunction + +" FIXME +function! s:VimLParser.parse_cmd_usercmd() + call self.parse_cmd_common() +endfunction + +function! s:VimLParser.parse_cmd_function() + let pos = self.reader.tell() + call self.reader.skip_white() + + " :function + if self.ends_excmds(self.reader.peek()) + call self.reader.seek_set(pos) + call self.parse_cmd_common() + return + endif + + " :function /pattern + if self.reader.peekn(1) ==# '/' + call self.reader.seek_set(pos) + call self.parse_cmd_common() + return + endif + + let left = self.parse_lvalue_func() + call self.reader.skip_white() + + if left.type == s:NODE_IDENTIFIER + let s = left.value + let ss = split(s, '\zs') + if ss[0] !=# '<' && !s:isupper(ss[0]) && stridx(s, ':') == -1 && stridx(s, '#') == -1 + throw s:Err(printf('E128: Function name must start with a capital or contain a colon: %s', s), left.pos) + endif + endif + + " :function {name} + if self.reader.peekn(1) !=# '(' + call self.reader.seek_set(pos) + call self.parse_cmd_common() + return + endif + + " :function[!] {name}([arguments]) [range] [abort] [dict] [closure] + let node = s:Node(s:NODE_FUNCTION) + let node.pos = self.ea.cmdpos + let node.body = [] + let node.ea = self.ea + let node.left = left + let node.rlist = [] + let node.attr = {'range': 0, 'abort': 0, 'dict': 0, 'closure': 0} + let node.endfunction = s:NIL + call self.reader.getn(1) + let tokenizer = s:ExprTokenizer.new(self.reader) + if tokenizer.peek().type == s:TOKEN_PCLOSE + call tokenizer.get() + else + let named = {} + while s:TRUE + let varnode = s:Node(s:NODE_IDENTIFIER) + let token = tokenizer.get() + if token.type == s:TOKEN_IDENTIFIER + if !s:isargname(token.value) || token.value ==# 'firstline' || token.value ==# 'lastline' + throw s:Err(printf('E125: Illegal argument: %s', token.value), token.pos) + elseif has_key(named, token.value) + throw s:Err(printf('E853: Duplicate argument name: %s', token.value), token.pos) + endif + let named[token.value] = 1 + let varnode.pos = token.pos + let varnode.value = token.value + call add(node.rlist, varnode) + " XXX: Vim doesn't skip white space before comma. F(a ,b) => E475 + if s:iswhite(self.reader.p(0)) && tokenizer.peek().type == s:TOKEN_COMMA + throw s:Err('E475: Invalid argument: White space is not allowed before comma', self.reader.getpos()) + endif + let token = tokenizer.get() + if token.type == s:TOKEN_COMMA + " XXX: Vim allows last comma. F(a, b, ) => OK + if tokenizer.peek().type == s:TOKEN_PCLOSE + call tokenizer.get() + break + endif + elseif token.type == s:TOKEN_PCLOSE + break + else + throw s:Err(printf('unexpected token: %s', token.value), token.pos) + endif + elseif token.type == s:TOKEN_DOTDOTDOT + let varnode.pos = token.pos + let varnode.value = token.value + call add(node.rlist, varnode) + let token = tokenizer.get() + if token.type == s:TOKEN_PCLOSE + break + else + throw s:Err(printf('unexpected token: %s', token.value), token.pos) + endif + else + throw s:Err(printf('unexpected token: %s', token.value), token.pos) + endif + endwhile + endif + while s:TRUE + call self.reader.skip_white() + let epos = self.reader.getpos() + let key = self.reader.read_alpha() + if key ==# '' + break + elseif key ==# 'range' + let node.attr.range = s:TRUE + elseif key ==# 'abort' + let node.attr.abort = s:TRUE + elseif key ==# 'dict' + let node.attr.dict = s:TRUE + elseif key ==# 'closure' + let node.attr.closure = s:TRUE + else + throw s:Err(printf('unexpected token: %s', key), epos) + endif + endwhile + call self.add_node(node) + call self.push_context(node) +endfunction + +function! s:VimLParser.parse_cmd_endfunction() + call self.check_missing_endif('ENDFUNCTION', self.ea.cmdpos) + call self.check_missing_endtry('ENDFUNCTION', self.ea.cmdpos) + call self.check_missing_endwhile('ENDFUNCTION', self.ea.cmdpos) + call self.check_missing_endfor('ENDFUNCTION', self.ea.cmdpos) + if self.context[0].type != s:NODE_FUNCTION + throw s:Err('E193: :endfunction not inside a function', self.ea.cmdpos) + endif + call self.reader.getn(-1) + let node = s:Node(s:NODE_ENDFUNCTION) + let node.pos = self.ea.cmdpos + let node.ea = self.ea + let self.context[0].endfunction = node + call self.pop_context() +endfunction + +function! s:VimLParser.parse_cmd_delfunction() + let node = s:Node(s:NODE_DELFUNCTION) + let node.pos = self.ea.cmdpos + let node.ea = self.ea + let node.left = self.parse_lvalue_func() + call self.add_node(node) +endfunction + +function! s:VimLParser.parse_cmd_return() + if self.find_context(s:NODE_FUNCTION) == -1 + throw s:Err('E133: :return not inside a function', self.ea.cmdpos) + endif + let node = s:Node(s:NODE_RETURN) + let node.pos = self.ea.cmdpos + let node.ea = self.ea + let node.left = s:NIL + call self.reader.skip_white() + let c = self.reader.peek() + if c ==# '"' || !self.ends_excmds(c) + let node.left = self.parse_expr() + endif + call self.add_node(node) +endfunction + +function! s:VimLParser.parse_cmd_call() + let node = s:Node(s:NODE_EXCALL) + let node.pos = self.ea.cmdpos + let node.ea = self.ea + call self.reader.skip_white() + let c = self.reader.peek() + if self.ends_excmds(c) + throw s:Err('E471: Argument required', self.reader.getpos()) + endif + let node.left = self.parse_expr() + if node.left.type != s:NODE_CALL + throw s:Err('Not an function call', node.left.pos) + endif + call self.add_node(node) +endfunction + +function! s:VimLParser.parse_cmd_let() + let pos = self.reader.tell() + call self.reader.skip_white() + + " :let + if self.ends_excmds(self.reader.peek()) + call self.reader.seek_set(pos) + call self.parse_cmd_common() + return + endif + + let lhs = self.parse_letlhs() + call self.reader.skip_white() + let s1 = self.reader.peekn(1) + let s2 = self.reader.peekn(2) + + " :let {var-name} .. + if self.ends_excmds(s1) || (s2 !=# '+=' && s2 !=# '-=' && s2 !=# '.=' && s1 !=# '=') + call self.reader.seek_set(pos) + call self.parse_cmd_common() + return + endif + + " :let left op right + let node = s:Node(s:NODE_LET) + let node.pos = self.ea.cmdpos + let node.ea = self.ea + let node.op = '' + let node.left = lhs.left + let node.list = lhs.list + let node.rest = lhs.rest + let node.right = s:NIL + if s2 ==# '+=' || s2 ==# '-=' || s2 ==# '.=' + call self.reader.getn(2) + let node.op = s2 + elseif s1 ==# '=' + call self.reader.getn(1) + let node.op = s1 + else + throw 'NOT REACHED' + endif + let node.right = self.parse_expr() + call self.add_node(node) +endfunction + +function! s:VimLParser.parse_cmd_unlet() + let node = s:Node(s:NODE_UNLET) + let node.pos = self.ea.cmdpos + let node.ea = self.ea + let node.list = self.parse_lvaluelist() + call self.add_node(node) +endfunction + +function! s:VimLParser.parse_cmd_lockvar() + let node = s:Node(s:NODE_LOCKVAR) + let node.pos = self.ea.cmdpos + let node.ea = self.ea + let node.depth = s:NIL + let node.list = [] + call self.reader.skip_white() + if s:isdigit(self.reader.peekn(1)) + let node.depth = str2nr(self.reader.read_digit(), 10) + endif + let node.list = self.parse_lvaluelist() + call self.add_node(node) +endfunction + +function! s:VimLParser.parse_cmd_unlockvar() + let node = s:Node(s:NODE_UNLOCKVAR) + let node.pos = self.ea.cmdpos + let node.ea = self.ea + let node.depth = s:NIL + let node.list = [] + call self.reader.skip_white() + if s:isdigit(self.reader.peekn(1)) + let node.depth = str2nr(self.reader.read_digit(), 10) + endif + let node.list = self.parse_lvaluelist() + call self.add_node(node) +endfunction + +function! s:VimLParser.parse_cmd_if() + let node = s:Node(s:NODE_IF) + let node.pos = self.ea.cmdpos + let node.body = [] + let node.ea = self.ea + let node.cond = self.parse_expr() + let node.elseif = [] + let node.else = s:NIL + let node.endif = s:NIL + call self.add_node(node) + call self.push_context(node) +endfunction + +function! s:VimLParser.parse_cmd_elseif() + if self.context[0].type != s:NODE_IF && self.context[0].type != s:NODE_ELSEIF + throw s:Err('E582: :elseif without :if', self.ea.cmdpos) + endif + if self.context[0].type != s:NODE_IF + call self.pop_context() + endif + let node = s:Node(s:NODE_ELSEIF) + let node.pos = self.ea.cmdpos + let node.body = [] + let node.ea = self.ea + let node.cond = self.parse_expr() + call add(self.context[0].elseif, node) + call self.push_context(node) +endfunction + +function! s:VimLParser.parse_cmd_else() + if self.context[0].type != s:NODE_IF && self.context[0].type != s:NODE_ELSEIF + throw s:Err('E581: :else without :if', self.ea.cmdpos) + endif + if self.context[0].type != s:NODE_IF + call self.pop_context() + endif + let node = s:Node(s:NODE_ELSE) + let node.pos = self.ea.cmdpos + let node.body = [] + let node.ea = self.ea + let self.context[0].else = node + call self.push_context(node) +endfunction + +function! s:VimLParser.parse_cmd_endif() + if self.context[0].type != s:NODE_IF && self.context[0].type != s:NODE_ELSEIF && self.context[0].type != s:NODE_ELSE + throw s:Err('E580: :endif without :if', self.ea.cmdpos) + endif + if self.context[0].type != s:NODE_IF + call self.pop_context() + endif + let node = s:Node(s:NODE_ENDIF) + let node.pos = self.ea.cmdpos + let node.ea = self.ea + let self.context[0].endif = node + call self.pop_context() +endfunction + +function! s:VimLParser.parse_cmd_while() + let node = s:Node(s:NODE_WHILE) + let node.pos = self.ea.cmdpos + let node.body = [] + let node.ea = self.ea + let node.cond = self.parse_expr() + let node.endwhile = s:NIL + call self.add_node(node) + call self.push_context(node) +endfunction + +function! s:VimLParser.parse_cmd_endwhile() + if self.context[0].type != s:NODE_WHILE + throw s:Err('E588: :endwhile without :while', self.ea.cmdpos) + endif + let node = s:Node(s:NODE_ENDWHILE) + let node.pos = self.ea.cmdpos + let node.ea = self.ea + let self.context[0].endwhile = node + call self.pop_context() +endfunction + +function! s:VimLParser.parse_cmd_for() + let node = s:Node(s:NODE_FOR) + let node.pos = self.ea.cmdpos + let node.body = [] + let node.ea = self.ea + let node.left = s:NIL + let node.right = s:NIL + let node.endfor = s:NIL + let lhs = self.parse_letlhs() + let node.left = lhs.left + let node.list = lhs.list + let node.rest = lhs.rest + call self.reader.skip_white() + let epos = self.reader.getpos() + if self.reader.read_alpha() !=# 'in' + throw s:Err('Missing "in" after :for', epos) + endif + let node.right = self.parse_expr() + call self.add_node(node) + call self.push_context(node) +endfunction + +function! s:VimLParser.parse_cmd_endfor() + if self.context[0].type != s:NODE_FOR + throw s:Err('E588: :endfor without :for', self.ea.cmdpos) + endif + let node = s:Node(s:NODE_ENDFOR) + let node.pos = self.ea.cmdpos + let node.ea = self.ea + let self.context[0].endfor = node + call self.pop_context() +endfunction + +function! s:VimLParser.parse_cmd_continue() + if self.find_context(s:NODE_WHILE) == -1 && self.find_context(s:NODE_FOR) == -1 + throw s:Err('E586: :continue without :while or :for', self.ea.cmdpos) + endif + let node = s:Node(s:NODE_CONTINUE) + let node.pos = self.ea.cmdpos + let node.ea = self.ea + call self.add_node(node) +endfunction + +function! s:VimLParser.parse_cmd_break() + if self.find_context(s:NODE_WHILE) == -1 && self.find_context(s:NODE_FOR) == -1 + throw s:Err('E587: :break without :while or :for', self.ea.cmdpos) + endif + let node = s:Node(s:NODE_BREAK) + let node.pos = self.ea.cmdpos + let node.ea = self.ea + call self.add_node(node) +endfunction + +function! s:VimLParser.parse_cmd_try() + let node = s:Node(s:NODE_TRY) + let node.pos = self.ea.cmdpos + let node.body = [] + let node.ea = self.ea + let node.catch = [] + let node.finally = s:NIL + let node.endtry = s:NIL + call self.add_node(node) + call self.push_context(node) +endfunction + +function! s:VimLParser.parse_cmd_catch() + if self.context[0].type == s:NODE_FINALLY + throw s:Err('E604: :catch after :finally', self.ea.cmdpos) + elseif self.context[0].type != s:NODE_TRY && self.context[0].type != s:NODE_CATCH + throw s:Err('E603: :catch without :try', self.ea.cmdpos) + endif + if self.context[0].type != s:NODE_TRY + call self.pop_context() + endif + let node = s:Node(s:NODE_CATCH) + let node.pos = self.ea.cmdpos + let node.body = [] + let node.ea = self.ea + let node.pattern = s:NIL + call self.reader.skip_white() + if !self.ends_excmds(self.reader.peek()) + let [node.pattern, _] = self.parse_pattern(self.reader.get()) + endif + call add(self.context[0].catch, node) + call self.push_context(node) +endfunction + +function! s:VimLParser.parse_cmd_finally() + if self.context[0].type != s:NODE_TRY && self.context[0].type != s:NODE_CATCH + throw s:Err('E606: :finally without :try', self.ea.cmdpos) + endif + if self.context[0].type != s:NODE_TRY + call self.pop_context() + endif + let node = s:Node(s:NODE_FINALLY) + let node.pos = self.ea.cmdpos + let node.body = [] + let node.ea = self.ea + let self.context[0].finally = node + call self.push_context(node) +endfunction + +function! s:VimLParser.parse_cmd_endtry() + if self.context[0].type != s:NODE_TRY && self.context[0].type != s:NODE_CATCH && self.context[0].type != s:NODE_FINALLY + throw s:Err('E602: :endtry without :try', self.ea.cmdpos) + endif + if self.context[0].type != s:NODE_TRY + call self.pop_context() + endif + let node = s:Node(s:NODE_ENDTRY) + let node.pos = self.ea.cmdpos + let node.ea = self.ea + let self.context[0].endtry = node + call self.pop_context() +endfunction + +function! s:VimLParser.parse_cmd_throw() + let node = s:Node(s:NODE_THROW) + let node.pos = self.ea.cmdpos + let node.ea = self.ea + let node.left = self.parse_expr() + call self.add_node(node) +endfunction + +function! s:VimLParser.parse_cmd_echo() + let node = s:Node(s:NODE_ECHO) + let node.pos = self.ea.cmdpos + let node.ea = self.ea + let node.list = self.parse_exprlist() + call self.add_node(node) +endfunction + +function! s:VimLParser.parse_cmd_echon() + let node = s:Node(s:NODE_ECHON) + let node.pos = self.ea.cmdpos + let node.ea = self.ea + let node.list = self.parse_exprlist() + call self.add_node(node) +endfunction + +function! s:VimLParser.parse_cmd_echohl() + let node = s:Node(s:NODE_ECHOHL) + let node.pos = self.ea.cmdpos + let node.ea = self.ea + let node.str = '' + while !self.ends_excmds(self.reader.peek()) + let node.str .= self.reader.get() + endwhile + call self.add_node(node) +endfunction + +function! s:VimLParser.parse_cmd_echomsg() + let node = s:Node(s:NODE_ECHOMSG) + let node.pos = self.ea.cmdpos + let node.ea = self.ea + let node.list = self.parse_exprlist() + call self.add_node(node) +endfunction + +function! s:VimLParser.parse_cmd_echoerr() + let node = s:Node(s:NODE_ECHOERR) + let node.pos = self.ea.cmdpos + let node.ea = self.ea + let node.list = self.parse_exprlist() + call self.add_node(node) +endfunction + +function! s:VimLParser.parse_cmd_execute() + let node = s:Node(s:NODE_EXECUTE) + let node.pos = self.ea.cmdpos + let node.ea = self.ea + let node.list = self.parse_exprlist() + call self.add_node(node) +endfunction + +function! s:VimLParser.parse_expr() + return s:ExprParser.new(self.reader).parse() +endfunction + +function! s:VimLParser.parse_exprlist() + let list = [] + while s:TRUE + call self.reader.skip_white() + let c = self.reader.peek() + if c !=# '"' && self.ends_excmds(c) + break + endif + let node = self.parse_expr() + call add(list, node) + endwhile + return list +endfunction + +function! s:VimLParser.parse_lvalue_func() + let p = s:LvalueParser.new(self.reader) + let node = p.parse() + if node.type == s:NODE_IDENTIFIER || node.type == s:NODE_CURLYNAME || node.type == s:NODE_SUBSCRIPT || node.type == s:NODE_DOT || node.type == s:NODE_OPTION || node.type == s:NODE_ENV || node.type == s:NODE_REG + return node + endif + throw s:Err('Invalid Expression', node.pos) +endfunction + +" FIXME: +function! s:VimLParser.parse_lvalue() + let p = s:LvalueParser.new(self.reader) + let node = p.parse() + if node.type == s:NODE_IDENTIFIER + if !s:isvarname(node.value) + throw s:Err(printf('E461: Illegal variable name: %s', node.value), node.pos) + endif + endif + if node.type == s:NODE_IDENTIFIER || node.type == s:NODE_CURLYNAME || node.type == s:NODE_SUBSCRIPT || node.type == s:NODE_SLICE || node.type == s:NODE_DOT || node.type == s:NODE_OPTION || node.type == s:NODE_ENV || node.type == s:NODE_REG + return node + endif + throw s:Err('Invalid Expression', node.pos) +endfunction + +function! s:VimLParser.parse_lvaluelist() + let list = [] + let node = self.parse_expr() + call add(list, node) + while s:TRUE + call self.reader.skip_white() + if self.ends_excmds(self.reader.peek()) + break + endif + let node = self.parse_lvalue() + call add(list, node) + endwhile + return list +endfunction + +" FIXME: +function! s:VimLParser.parse_letlhs() + let lhs = {'left': s:NIL, 'list': s:NIL, 'rest': s:NIL} + let tokenizer = s:ExprTokenizer.new(self.reader) + if tokenizer.peek().type == s:TOKEN_SQOPEN + call tokenizer.get() + let lhs.list = [] + while s:TRUE + let node = self.parse_lvalue() + call add(lhs.list, node) + let token = tokenizer.get() + if token.type == s:TOKEN_SQCLOSE + break + elseif token.type == s:TOKEN_COMMA + continue + elseif token.type == s:TOKEN_SEMICOLON + let node = self.parse_lvalue() + let lhs.rest = node + let token = tokenizer.get() + if token.type == s:TOKEN_SQCLOSE + break + else + throw s:Err(printf('E475 Invalid argument: %s', token.value), token.pos) + endif + else + throw s:Err(printf('E475 Invalid argument: %s', token.value), token.pos) + endif + endwhile + else + let lhs.left = self.parse_lvalue() + endif + return lhs +endfunction + +function! s:VimLParser.ends_excmds(c) + return a:c ==# '' || a:c ==# '|' || a:c ==# '"' || a:c ==# '<EOF>' || a:c ==# '<EOL>' +endfunction + +" FIXME: validate argument +function! s:VimLParser.parse_wincmd() + let c = self.reader.getn(1) + if c ==# '' + throw s:Err('E471: Argument required', self.reader.getpos()) + elseif c ==# 'g' || c ==# "\x07" " <C-G> + let c2 = self.reader.getn(1) + if c2 ==# '' || s:iswhite(c2) + throw s:Err('E474: Invalid Argument', self.reader.getpos()) + endif + endif + let end = self.reader.getpos() + call self.reader.skip_white() + if !self.ends_excmds(self.reader.peek()) + throw s:Err('E474: Invalid Argument', self.reader.getpos()) + endif + let node = s:Node(s:NODE_EXCMD) + let node.pos = self.ea.cmdpos + let node.ea = self.ea + let node.str = self.reader.getstr(self.ea.linepos, end) + call self.add_node(node) +endfunction + +" FIXME: validate argument +function! s:VimLParser.parse_cmd_syntax() + let end = self.reader.getpos() + while s:TRUE + let end = self.reader.getpos() + let c = self.reader.peek() + if c == "/" || c == "'" || c == "\"" + call self.reader.getn(1) + call self.parse_pattern(c) + elseif c == "=" + call self.reader.getn(1) + call self.parse_pattern(" ") + elseif self.ends_excmds(c) + break + endif + call self.reader.getn(1) + endwhile + let node = s:Node(s:NODE_EXCMD) + let node.pos = self.ea.cmdpos + let node.ea = self.ea + let node.str = self.reader.getstr(self.ea.linepos, end) + call self.add_node(node) +endfunction + +let s:VimLParser.neovim_additional_commands = [ + \ {'name': 'rshada', 'minlen': 3, 'flags': 'BANG|FILE1|TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'wshada', 'minlen': 3, 'flags': 'BANG|FILE1|TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}] + +let s:VimLParser.neovim_removed_commands = [ + \ {'name': 'Print', 'minlen':1, 'flags': 'RANGE|WHOLEFOLD|COUNT|EXFLAGS|TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'fixdel', 'minlen':3, 'flags': 'TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'helpfind', 'minlen':5, 'flags': 'EXTRA|NOTRLCOM', 'parser': 'parse_cmd_common'}, + \ {'name': 'open', 'minlen':1, 'flags': 'RANGE|BANG|EXTRA', 'parser': 'parse_cmd_common'}, + \ {'name': 'shell', 'minlen':2, 'flags': 'TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'tearoff', 'minlen':2, 'flags': 'NEEDARG|EXTRA|TRLBAR|NOTRLCOM|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'gvim', 'minlen':2, 'flags': 'BANG|FILES|EDITCMD|ARGOPT|TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}] + +" To find new builtin_commands, run the below script. +" $ scripts/update_builtin_commands.sh /path/to/vim/src/ex_cmds.h +let s:VimLParser.builtin_commands = [ + \ {'name': 'append', 'minlen': 1, 'flags': 'BANG|RANGE|ZEROR|TRLBAR|CMDWIN|MODIFY', 'parser': 'parse_cmd_append'}, + \ {'name': 'abbreviate', 'minlen': 2, 'flags': 'EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'abclear', 'minlen': 3, 'flags': 'EXTRA|TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'aboveleft', 'minlen': 3, 'flags': 'NEEDARG|EXTRA|NOTRLCOM', 'parser': 'parse_cmd_common'}, + \ {'name': 'all', 'minlen': 2, 'flags': 'BANG|RANGE|NOTADR|COUNT|TRLBAR', 'parser': 'parse_cmd_common'}, + \ {'name': 'amenu', 'minlen': 2, 'flags': 'RANGE|NOTADR|ZEROR|EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'anoremenu', 'minlen': 2, 'flags': 'RANGE|NOTADR|ZEROR|EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'args', 'minlen': 2, 'flags': 'BANG|FILES|EDITCMD|ARGOPT|TRLBAR', 'parser': 'parse_cmd_common'}, + \ {'name': 'argadd', 'minlen': 4, 'flags': 'BANG|NEEDARG|RANGE|NOTADR|ZEROR|FILES|TRLBAR', 'parser': 'parse_cmd_common'}, + \ {'name': 'argdelete', 'minlen': 4, 'flags': 'BANG|RANGE|NOTADR|FILES|TRLBAR', 'parser': 'parse_cmd_common'}, + \ {'name': 'argedit', 'minlen': 4, 'flags': 'BANG|NEEDARG|RANGE|NOTADR|FILE1|EDITCMD|ARGOPT|TRLBAR', 'parser': 'parse_cmd_common'}, + \ {'name': 'argdo', 'minlen': 5, 'flags': 'BANG|NEEDARG|EXTRA|NOTRLCOM', 'parser': 'parse_cmd_common'}, + \ {'name': 'argglobal', 'minlen': 4, 'flags': 'BANG|FILES|EDITCMD|ARGOPT|TRLBAR', 'parser': 'parse_cmd_common'}, + \ {'name': 'arglocal', 'minlen': 4, 'flags': 'BANG|FILES|EDITCMD|ARGOPT|TRLBAR', 'parser': 'parse_cmd_common'}, + \ {'name': 'argument', 'minlen': 4, 'flags': 'BANG|RANGE|NOTADR|COUNT|EXTRA|EDITCMD|ARGOPT|TRLBAR', 'parser': 'parse_cmd_common'}, + \ {'name': 'ascii', 'minlen': 2, 'flags': 'TRLBAR|SBOXOK|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'autocmd', 'minlen': 2, 'flags': 'BANG|EXTRA|NOTRLCOM|USECTRLV|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'augroup', 'minlen': 3, 'flags': 'BANG|WORD1|TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'aunmenu', 'minlen': 3, 'flags': 'EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'buffer', 'minlen': 1, 'flags': 'BANG|RANGE|NOTADR|BUFNAME|BUFUNL|COUNT|EXTRA|TRLBAR', 'parser': 'parse_cmd_common'}, + \ {'name': 'bNext', 'minlen': 2, 'flags': 'BANG|RANGE|NOTADR|COUNT|TRLBAR', 'parser': 'parse_cmd_common'}, + \ {'name': 'ball', 'minlen': 2, 'flags': 'RANGE|NOTADR|COUNT|TRLBAR', 'parser': 'parse_cmd_common'}, + \ {'name': 'badd', 'minlen': 3, 'flags': 'NEEDARG|FILE1|EDITCMD|TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'bdelete', 'minlen': 2, 'flags': 'BANG|RANGE|NOTADR|BUFNAME|COUNT|EXTRA|TRLBAR', 'parser': 'parse_cmd_common'}, + \ {'name': 'behave', 'minlen': 2, 'flags': 'NEEDARG|WORD1|TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'belowright', 'minlen': 3, 'flags': 'NEEDARG|EXTRA|NOTRLCOM', 'parser': 'parse_cmd_common'}, + \ {'name': 'bfirst', 'minlen': 2, 'flags': 'BANG|RANGE|NOTADR|TRLBAR', 'parser': 'parse_cmd_common'}, + \ {'name': 'blast', 'minlen': 2, 'flags': 'BANG|RANGE|NOTADR|TRLBAR', 'parser': 'parse_cmd_common'}, + \ {'name': 'bmodified', 'minlen': 2, 'flags': 'BANG|RANGE|NOTADR|COUNT|TRLBAR', 'parser': 'parse_cmd_common'}, + \ {'name': 'bnext', 'minlen': 2, 'flags': 'BANG|RANGE|NOTADR|COUNT|TRLBAR', 'parser': 'parse_cmd_common'}, + \ {'name': 'botright', 'minlen': 2, 'flags': 'NEEDARG|EXTRA|NOTRLCOM', 'parser': 'parse_cmd_common'}, + \ {'name': 'bprevious', 'minlen': 2, 'flags': 'BANG|RANGE|NOTADR|COUNT|TRLBAR', 'parser': 'parse_cmd_common'}, + \ {'name': 'brewind', 'minlen': 2, 'flags': 'BANG|RANGE|NOTADR|TRLBAR', 'parser': 'parse_cmd_common'}, + \ {'name': 'break', 'minlen': 4, 'flags': 'TRLBAR|SBOXOK|CMDWIN', 'parser': 'parse_cmd_break'}, + \ {'name': 'breakadd', 'minlen': 6, 'flags': 'EXTRA|TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'breakdel', 'minlen': 6, 'flags': 'EXTRA|TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'breaklist', 'minlen': 6, 'flags': 'EXTRA|TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'browse', 'minlen': 3, 'flags': 'NEEDARG|EXTRA|NOTRLCOM|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'bufdo', 'minlen': 5, 'flags': 'BANG|NEEDARG|EXTRA|NOTRLCOM', 'parser': 'parse_cmd_common'}, + \ {'name': 'buffers', 'minlen': 7, 'flags': 'BANG|TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'bunload', 'minlen': 3, 'flags': 'BANG|RANGE|NOTADR|BUFNAME|COUNT|EXTRA|TRLBAR', 'parser': 'parse_cmd_common'}, + \ {'name': 'bwipeout', 'minlen': 2, 'flags': 'BANG|RANGE|NOTADR|BUFNAME|BUFUNL|COUNT|EXTRA|TRLBAR', 'parser': 'parse_cmd_common'}, + \ {'name': 'change', 'minlen': 1, 'flags': 'BANG|WHOLEFOLD|RANGE|COUNT|TRLBAR|CMDWIN|MODIFY', 'parser': 'parse_cmd_common'}, + \ {'name': 'cNext', 'minlen': 2, 'flags': 'RANGE|NOTADR|COUNT|TRLBAR|BANG', 'parser': 'parse_cmd_common'}, + \ {'name': 'cNfile', 'minlen': 3, 'flags': 'RANGE|NOTADR|COUNT|TRLBAR|BANG', 'parser': 'parse_cmd_common'}, + \ {'name': 'cabbrev', 'minlen': 2, 'flags': 'EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'cabclear', 'minlen': 4, 'flags': 'EXTRA|TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'caddbuffer', 'minlen': 3, 'flags': 'RANGE|NOTADR|WORD1|TRLBAR', 'parser': 'parse_cmd_common'}, + \ {'name': 'caddexpr', 'minlen': 5, 'flags': 'NEEDARG|WORD1|NOTRLCOM|TRLBAR', 'parser': 'parse_cmd_common'}, + \ {'name': 'caddfile', 'minlen': 5, 'flags': 'TRLBAR|FILE1', 'parser': 'parse_cmd_common'}, + \ {'name': 'call', 'minlen': 3, 'flags': 'RANGE|NEEDARG|EXTRA|NOTRLCOM|SBOXOK|CMDWIN', 'parser': 'parse_cmd_call'}, + \ {'name': 'catch', 'minlen': 3, 'flags': 'EXTRA|SBOXOK|CMDWIN', 'parser': 'parse_cmd_catch'}, + \ {'name': 'cbuffer', 'minlen': 2, 'flags': 'BANG|RANGE|NOTADR|WORD1|TRLBAR', 'parser': 'parse_cmd_common'}, + \ {'name': 'cc', 'minlen': 2, 'flags': 'RANGE|NOTADR|COUNT|TRLBAR|BANG', 'parser': 'parse_cmd_common'}, + \ {'name': 'cclose', 'minlen': 3, 'flags': 'RANGE|NOTADR|COUNT|TRLBAR', 'parser': 'parse_cmd_common'}, + \ {'name': 'cd', 'minlen': 2, 'flags': 'BANG|FILE1|TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'center', 'minlen': 2, 'flags': 'TRLBAR|RANGE|WHOLEFOLD|EXTRA|CMDWIN|MODIFY', 'parser': 'parse_cmd_common'}, + \ {'name': 'cexpr', 'minlen': 3, 'flags': 'NEEDARG|WORD1|NOTRLCOM|TRLBAR|BANG', 'parser': 'parse_cmd_common'}, + \ {'name': 'cfile', 'minlen': 2, 'flags': 'TRLBAR|FILE1|BANG', 'parser': 'parse_cmd_common'}, + \ {'name': 'cfirst', 'minlen': 4, 'flags': 'RANGE|NOTADR|COUNT|TRLBAR|BANG', 'parser': 'parse_cmd_common'}, + \ {'name': 'cgetbuffer', 'minlen': 5, 'flags': 'RANGE|NOTADR|WORD1|TRLBAR', 'parser': 'parse_cmd_common'}, + \ {'name': 'cgetexpr', 'minlen': 5, 'flags': 'NEEDARG|WORD1|NOTRLCOM|TRLBAR', 'parser': 'parse_cmd_common'}, + \ {'name': 'cgetfile', 'minlen': 2, 'flags': 'TRLBAR|FILE1', 'parser': 'parse_cmd_common'}, + \ {'name': 'changes', 'minlen': 7, 'flags': 'TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'chdir', 'minlen': 3, 'flags': 'BANG|FILE1|TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'checkpath', 'minlen': 3, 'flags': 'TRLBAR|BANG|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'checktime', 'minlen': 6, 'flags': 'RANGE|NOTADR|BUFNAME|COUNT|EXTRA|TRLBAR', 'parser': 'parse_cmd_common'}, + \ {'name': 'clist', 'minlen': 2, 'flags': 'BANG|EXTRA|TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'clast', 'minlen': 3, 'flags': 'RANGE|NOTADR|COUNT|TRLBAR|BANG', 'parser': 'parse_cmd_common'}, + \ {'name': 'close', 'minlen': 3, 'flags': 'BANG|TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'cmap', 'minlen': 2, 'flags': 'EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'cmapclear', 'minlen': 5, 'flags': 'EXTRA|TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'cmenu', 'minlen': 3, 'flags': 'RANGE|NOTADR|ZEROR|EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'cnext', 'minlen': 2, 'flags': 'RANGE|NOTADR|COUNT|TRLBAR|BANG', 'parser': 'parse_cmd_common'}, + \ {'name': 'cnewer', 'minlen': 4, 'flags': 'RANGE|NOTADR|COUNT|TRLBAR', 'parser': 'parse_cmd_common'}, + \ {'name': 'cnfile', 'minlen': 3, 'flags': 'RANGE|NOTADR|COUNT|TRLBAR|BANG', 'parser': 'parse_cmd_common'}, + \ {'name': 'cnoremap', 'minlen': 3, 'flags': 'EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'cnoreabbrev', 'minlen': 6, 'flags': 'EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'cnoremenu', 'minlen': 7, 'flags': 'RANGE|NOTADR|ZEROR|EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'copy', 'minlen': 2, 'flags': 'RANGE|WHOLEFOLD|EXTRA|TRLBAR|CMDWIN|MODIFY', 'parser': 'parse_cmd_common'}, + \ {'name': 'colder', 'minlen': 3, 'flags': 'RANGE|NOTADR|COUNT|TRLBAR', 'parser': 'parse_cmd_common'}, + \ {'name': 'colorscheme', 'minlen': 4, 'flags': 'WORD1|TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'command', 'minlen': 3, 'flags': 'EXTRA|BANG|NOTRLCOM|USECTRLV|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'comclear', 'minlen': 4, 'flags': 'TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'compiler', 'minlen': 4, 'flags': 'BANG|TRLBAR|WORD1|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'continue', 'minlen': 3, 'flags': 'TRLBAR|SBOXOK|CMDWIN', 'parser': 'parse_cmd_continue'}, + \ {'name': 'confirm', 'minlen': 4, 'flags': 'NEEDARG|EXTRA|NOTRLCOM|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'copen', 'minlen': 4, 'flags': 'RANGE|NOTADR|COUNT|TRLBAR', 'parser': 'parse_cmd_common'}, + \ {'name': 'cprevious', 'minlen': 2, 'flags': 'RANGE|NOTADR|COUNT|TRLBAR|BANG', 'parser': 'parse_cmd_common'}, + \ {'name': 'cpfile', 'minlen': 3, 'flags': 'RANGE|NOTADR|COUNT|TRLBAR|BANG', 'parser': 'parse_cmd_common'}, + \ {'name': 'cquit', 'minlen': 2, 'flags': 'TRLBAR|BANG', 'parser': 'parse_cmd_common'}, + \ {'name': 'crewind', 'minlen': 2, 'flags': 'RANGE|NOTADR|COUNT|TRLBAR|BANG', 'parser': 'parse_cmd_common'}, + \ {'name': 'cscope', 'minlen': 2, 'flags': 'EXTRA|NOTRLCOM|XFILE', 'parser': 'parse_cmd_common'}, + \ {'name': 'cstag', 'minlen': 3, 'flags': 'BANG|TRLBAR|WORD1', 'parser': 'parse_cmd_common'}, + \ {'name': 'cunmap', 'minlen': 2, 'flags': 'EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'cunabbrev', 'minlen': 4, 'flags': 'EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'cunmenu', 'minlen': 5, 'flags': 'EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'cwindow', 'minlen': 2, 'flags': 'RANGE|NOTADR|COUNT|TRLBAR', 'parser': 'parse_cmd_common'}, + \ {'name': 'delete', 'minlen': 1, 'flags': 'RANGE|WHOLEFOLD|REGSTR|COUNT|TRLBAR|CMDWIN|MODIFY', 'parser': 'parse_cmd_common'}, + \ {'name': 'delmarks', 'minlen': 4, 'flags': 'BANG|EXTRA|TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'debug', 'minlen': 3, 'flags': 'NEEDARG|EXTRA|NOTRLCOM|SBOXOK|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'debuggreedy', 'minlen': 6, 'flags': 'RANGE|NOTADR|ZEROR|TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'delcommand', 'minlen': 4, 'flags': 'NEEDARG|WORD1|TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'delfunction', 'minlen': 4, 'flags': 'NEEDARG|WORD1|CMDWIN', 'parser': 'parse_cmd_delfunction'}, + \ {'name': 'diffupdate', 'minlen': 3, 'flags': 'BANG|TRLBAR', 'parser': 'parse_cmd_common'}, + \ {'name': 'diffget', 'minlen': 5, 'flags': 'RANGE|EXTRA|TRLBAR|MODIFY', 'parser': 'parse_cmd_common'}, + \ {'name': 'diffoff', 'minlen': 5, 'flags': 'BANG|TRLBAR', 'parser': 'parse_cmd_common'}, + \ {'name': 'diffpatch', 'minlen': 5, 'flags': 'EXTRA|FILE1|TRLBAR|MODIFY', 'parser': 'parse_cmd_common'}, + \ {'name': 'diffput', 'minlen': 6, 'flags': 'RANGE|EXTRA|TRLBAR', 'parser': 'parse_cmd_common'}, + \ {'name': 'diffsplit', 'minlen': 5, 'flags': 'EXTRA|FILE1|TRLBAR', 'parser': 'parse_cmd_common'}, + \ {'name': 'diffthis', 'minlen': 5, 'flags': 'TRLBAR', 'parser': 'parse_cmd_common'}, + \ {'name': 'digraphs', 'minlen': 3, 'flags': 'EXTRA|TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'display', 'minlen': 2, 'flags': 'EXTRA|NOTRLCOM|TRLBAR|SBOXOK|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'djump', 'minlen': 2, 'flags': 'BANG|RANGE|DFLALL|WHOLEFOLD|EXTRA', 'parser': 'parse_cmd_common'}, + \ {'name': 'dlist', 'minlen': 2, 'flags': 'BANG|RANGE|DFLALL|WHOLEFOLD|EXTRA|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'doautocmd', 'minlen': 2, 'flags': 'EXTRA|TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'doautoall', 'minlen': 7, 'flags': 'EXTRA|TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'drop', 'minlen': 2, 'flags': 'FILES|EDITCMD|NEEDARG|ARGOPT|TRLBAR', 'parser': 'parse_cmd_common'}, + \ {'name': 'dsearch', 'minlen': 2, 'flags': 'BANG|RANGE|DFLALL|WHOLEFOLD|EXTRA|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'dsplit', 'minlen': 3, 'flags': 'BANG|RANGE|DFLALL|WHOLEFOLD|EXTRA', 'parser': 'parse_cmd_common'}, + \ {'name': 'edit', 'minlen': 1, 'flags': 'BANG|FILE1|EDITCMD|ARGOPT|TRLBAR', 'parser': 'parse_cmd_common'}, + \ {'name': 'earlier', 'minlen': 2, 'flags': 'TRLBAR|EXTRA|NOSPC|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'echo', 'minlen': 2, 'flags': 'EXTRA|NOTRLCOM|SBOXOK|CMDWIN', 'parser': 'parse_cmd_echo'}, + \ {'name': 'echoerr', 'minlen': 5, 'flags': 'EXTRA|NOTRLCOM|SBOXOK|CMDWIN', 'parser': 'parse_cmd_echoerr'}, + \ {'name': 'echohl', 'minlen': 5, 'flags': 'EXTRA|TRLBAR|SBOXOK|CMDWIN', 'parser': 'parse_cmd_echohl'}, + \ {'name': 'echomsg', 'minlen': 5, 'flags': 'EXTRA|NOTRLCOM|SBOXOK|CMDWIN', 'parser': 'parse_cmd_echomsg'}, + \ {'name': 'echon', 'minlen': 5, 'flags': 'EXTRA|NOTRLCOM|SBOXOK|CMDWIN', 'parser': 'parse_cmd_echon'}, + \ {'name': 'else', 'minlen': 2, 'flags': 'TRLBAR|SBOXOK|CMDWIN', 'parser': 'parse_cmd_else'}, + \ {'name': 'elseif', 'minlen': 5, 'flags': 'EXTRA|NOTRLCOM|SBOXOK|CMDWIN', 'parser': 'parse_cmd_elseif'}, + \ {'name': 'emenu', 'minlen': 2, 'flags': 'NEEDARG|EXTRA|TRLBAR|NOTRLCOM|RANGE|NOTADR|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'endif', 'minlen': 2, 'flags': 'TRLBAR|SBOXOK|CMDWIN', 'parser': 'parse_cmd_endif'}, + \ {'name': 'endfor', 'minlen': 5, 'flags': 'TRLBAR|SBOXOK|CMDWIN', 'parser': 'parse_cmd_endfor'}, + \ {'name': 'endfunction', 'minlen': 4, 'flags': 'TRLBAR|CMDWIN', 'parser': 'parse_cmd_endfunction'}, + \ {'name': 'endtry', 'minlen': 4, 'flags': 'TRLBAR|SBOXOK|CMDWIN', 'parser': 'parse_cmd_endtry'}, + \ {'name': 'endwhile', 'minlen': 4, 'flags': 'TRLBAR|SBOXOK|CMDWIN', 'parser': 'parse_cmd_endwhile'}, + \ {'name': 'enew', 'minlen': 3, 'flags': 'BANG|TRLBAR', 'parser': 'parse_cmd_common'}, + \ {'name': 'ex', 'minlen': 2, 'flags': 'BANG|FILE1|EDITCMD|ARGOPT|TRLBAR', 'parser': 'parse_cmd_common'}, + \ {'name': 'execute', 'minlen': 3, 'flags': 'EXTRA|NOTRLCOM|SBOXOK|CMDWIN', 'parser': 'parse_cmd_execute'}, + \ {'name': 'exit', 'minlen': 3, 'flags': 'RANGE|WHOLEFOLD|BANG|FILE1|ARGOPT|DFLALL|TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'exusage', 'minlen': 3, 'flags': 'TRLBAR', 'parser': 'parse_cmd_common'}, + \ {'name': 'file', 'minlen': 1, 'flags': 'RANGE|NOTADR|ZEROR|BANG|FILE1|TRLBAR', 'parser': 'parse_cmd_common'}, + \ {'name': 'files', 'minlen': 5, 'flags': 'BANG|TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'filetype', 'minlen': 5, 'flags': 'EXTRA|TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'find', 'minlen': 3, 'flags': 'RANGE|NOTADR|BANG|FILE1|EDITCMD|ARGOPT|TRLBAR', 'parser': 'parse_cmd_common'}, + \ {'name': 'finally', 'minlen': 4, 'flags': 'TRLBAR|SBOXOK|CMDWIN', 'parser': 'parse_cmd_finally'}, + \ {'name': 'finish', 'minlen': 4, 'flags': 'TRLBAR|SBOXOK|CMDWIN', 'parser': 'parse_cmd_finish'}, + \ {'name': 'first', 'minlen': 3, 'flags': 'EXTRA|BANG|EDITCMD|ARGOPT|TRLBAR', 'parser': 'parse_cmd_common'}, + \ {'name': 'fixdel', 'minlen': 3, 'flags': 'TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'fold', 'minlen': 2, 'flags': 'RANGE|WHOLEFOLD|TRLBAR|SBOXOK|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'foldclose', 'minlen': 5, 'flags': 'RANGE|BANG|WHOLEFOLD|TRLBAR|SBOXOK|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'folddoopen', 'minlen': 5, 'flags': 'RANGE|DFLALL|NEEDARG|EXTRA|NOTRLCOM', 'parser': 'parse_cmd_common'}, + \ {'name': 'folddoclosed', 'minlen': 7, 'flags': 'RANGE|DFLALL|NEEDARG|EXTRA|NOTRLCOM', 'parser': 'parse_cmd_common'}, + \ {'name': 'foldopen', 'minlen': 5, 'flags': 'RANGE|BANG|WHOLEFOLD|TRLBAR|SBOXOK|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'for', 'minlen': 3, 'flags': 'EXTRA|NOTRLCOM|SBOXOK|CMDWIN', 'parser': 'parse_cmd_for'}, + \ {'name': 'function', 'minlen': 2, 'flags': 'EXTRA|BANG|CMDWIN', 'parser': 'parse_cmd_function'}, + \ {'name': 'global', 'minlen': 1, 'flags': 'RANGE|WHOLEFOLD|BANG|EXTRA|DFLALL|SBOXOK|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'goto', 'minlen': 2, 'flags': 'RANGE|NOTADR|COUNT|TRLBAR|SBOXOK|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'grep', 'minlen': 2, 'flags': 'RANGE|NOTADR|BANG|NEEDARG|EXTRA|NOTRLCOM|TRLBAR|XFILE', 'parser': 'parse_cmd_common'}, + \ {'name': 'grepadd', 'minlen': 5, 'flags': 'RANGE|NOTADR|BANG|NEEDARG|EXTRA|NOTRLCOM|TRLBAR|XFILE', 'parser': 'parse_cmd_common'}, + \ {'name': 'gui', 'minlen': 2, 'flags': 'BANG|FILES|EDITCMD|ARGOPT|TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'gvim', 'minlen': 2, 'flags': 'BANG|FILES|EDITCMD|ARGOPT|TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'hardcopy', 'minlen': 2, 'flags': 'RANGE|COUNT|EXTRA|TRLBAR|DFLALL|BANG', 'parser': 'parse_cmd_common'}, + \ {'name': 'help', 'minlen': 1, 'flags': 'BANG|EXTRA|NOTRLCOM', 'parser': 'parse_cmd_common'}, + \ {'name': 'helpfind', 'minlen': 5, 'flags': 'EXTRA|NOTRLCOM', 'parser': 'parse_cmd_common'}, + \ {'name': 'helpgrep', 'minlen': 5, 'flags': 'EXTRA|NOTRLCOM|NEEDARG', 'parser': 'parse_cmd_common'}, + \ {'name': 'helptags', 'minlen': 5, 'flags': 'NEEDARG|FILES|TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'highlight', 'minlen': 2, 'flags': 'BANG|EXTRA|TRLBAR|SBOXOK|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'hide', 'minlen': 3, 'flags': 'BANG|EXTRA|NOTRLCOM', 'parser': 'parse_cmd_common'}, + \ {'name': 'history', 'minlen': 3, 'flags': 'EXTRA|TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'insert', 'minlen': 1, 'flags': 'BANG|RANGE|TRLBAR|CMDWIN|MODIFY', 'parser': 'parse_cmd_insert'}, + \ {'name': 'iabbrev', 'minlen': 2, 'flags': 'EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'iabclear', 'minlen': 4, 'flags': 'EXTRA|TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'if', 'minlen': 2, 'flags': 'EXTRA|NOTRLCOM|SBOXOK|CMDWIN', 'parser': 'parse_cmd_if'}, + \ {'name': 'ijump', 'minlen': 2, 'flags': 'BANG|RANGE|DFLALL|WHOLEFOLD|EXTRA', 'parser': 'parse_cmd_common'}, + \ {'name': 'ilist', 'minlen': 2, 'flags': 'BANG|RANGE|DFLALL|WHOLEFOLD|EXTRA|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'imap', 'minlen': 2, 'flags': 'EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'imapclear', 'minlen': 5, 'flags': 'EXTRA|TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'imenu', 'minlen': 3, 'flags': 'RANGE|NOTADR|ZEROR|EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'inoremap', 'minlen': 3, 'flags': 'EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'inoreabbrev', 'minlen': 6, 'flags': 'EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'inoremenu', 'minlen': 7, 'flags': 'RANGE|NOTADR|ZEROR|EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'intro', 'minlen': 3, 'flags': 'TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'isearch', 'minlen': 2, 'flags': 'BANG|RANGE|DFLALL|WHOLEFOLD|EXTRA|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'isplit', 'minlen': 3, 'flags': 'BANG|RANGE|DFLALL|WHOLEFOLD|EXTRA', 'parser': 'parse_cmd_common'}, + \ {'name': 'iunmap', 'minlen': 2, 'flags': 'EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'iunabbrev', 'minlen': 4, 'flags': 'EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'iunmenu', 'minlen': 5, 'flags': 'EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'join', 'minlen': 1, 'flags': 'BANG|RANGE|WHOLEFOLD|COUNT|EXFLAGS|TRLBAR|CMDWIN|MODIFY', 'parser': 'parse_cmd_common'}, + \ {'name': 'jumps', 'minlen': 2, 'flags': 'TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'k', 'minlen': 1, 'flags': 'RANGE|WORD1|TRLBAR|SBOXOK|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'keepalt', 'minlen': 5, 'flags': 'NEEDARG|EXTRA|NOTRLCOM', 'parser': 'parse_cmd_common'}, + \ {'name': 'keepmarks', 'minlen': 3, 'flags': 'NEEDARG|EXTRA|NOTRLCOM', 'parser': 'parse_cmd_common'}, + \ {'name': 'keepjumps', 'minlen': 5, 'flags': 'NEEDARG|EXTRA|NOTRLCOM', 'parser': 'parse_cmd_common'}, + \ {'name': 'keeppatterns', 'minlen': 5, 'flags': 'NEEDARG|EXTRA|NOTRLCOM', 'parser': 'parse_cmd_common'}, + \ {'name': 'lNext', 'minlen': 2, 'flags': 'RANGE|NOTADR|COUNT|TRLBAR|BANG', 'parser': 'parse_cmd_common'}, + \ {'name': 'lNfile', 'minlen': 3, 'flags': 'RANGE|NOTADR|COUNT|TRLBAR|BANG', 'parser': 'parse_cmd_common'}, + \ {'name': 'list', 'minlen': 1, 'flags': 'RANGE|WHOLEFOLD|COUNT|EXFLAGS|TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'laddexpr', 'minlen': 3, 'flags': 'NEEDARG|WORD1|NOTRLCOM|TRLBAR', 'parser': 'parse_cmd_common'}, + \ {'name': 'laddbuffer', 'minlen': 5, 'flags': 'RANGE|NOTADR|WORD1|TRLBAR', 'parser': 'parse_cmd_common'}, + \ {'name': 'laddfile', 'minlen': 5, 'flags': 'TRLBAR|FILE1', 'parser': 'parse_cmd_common'}, + \ {'name': 'last', 'minlen': 2, 'flags': 'EXTRA|BANG|EDITCMD|ARGOPT|TRLBAR', 'parser': 'parse_cmd_common'}, + \ {'name': 'language', 'minlen': 3, 'flags': 'EXTRA|TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'later', 'minlen': 3, 'flags': 'TRLBAR|EXTRA|NOSPC|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'lbuffer', 'minlen': 2, 'flags': 'BANG|RANGE|NOTADR|WORD1|TRLBAR', 'parser': 'parse_cmd_common'}, + \ {'name': 'lcd', 'minlen': 2, 'flags': 'BANG|FILE1|TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'lchdir', 'minlen': 3, 'flags': 'BANG|FILE1|TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'lclose', 'minlen': 3, 'flags': 'RANGE|NOTADR|COUNT|TRLBAR', 'parser': 'parse_cmd_common'}, + \ {'name': 'lcscope', 'minlen': 3, 'flags': 'EXTRA|NOTRLCOM|XFILE', 'parser': 'parse_cmd_common'}, + \ {'name': 'left', 'minlen': 2, 'flags': 'TRLBAR|RANGE|WHOLEFOLD|EXTRA|CMDWIN|MODIFY', 'parser': 'parse_cmd_common'}, + \ {'name': 'leftabove', 'minlen': 5, 'flags': 'NEEDARG|EXTRA|NOTRLCOM', 'parser': 'parse_cmd_common'}, + \ {'name': 'let', 'minlen': 3, 'flags': 'EXTRA|NOTRLCOM|SBOXOK|CMDWIN', 'parser': 'parse_cmd_let'}, + \ {'name': 'lexpr', 'minlen': 3, 'flags': 'NEEDARG|WORD1|NOTRLCOM|TRLBAR|BANG', 'parser': 'parse_cmd_common'}, + \ {'name': 'lfile', 'minlen': 2, 'flags': 'TRLBAR|FILE1|BANG', 'parser': 'parse_cmd_common'}, + \ {'name': 'lfirst', 'minlen': 4, 'flags': 'RANGE|NOTADR|COUNT|TRLBAR|BANG', 'parser': 'parse_cmd_common'}, + \ {'name': 'lgetbuffer', 'minlen': 5, 'flags': 'RANGE|NOTADR|WORD1|TRLBAR', 'parser': 'parse_cmd_common'}, + \ {'name': 'lgetexpr', 'minlen': 5, 'flags': 'NEEDARG|WORD1|NOTRLCOM|TRLBAR', 'parser': 'parse_cmd_common'}, + \ {'name': 'lgetfile', 'minlen': 2, 'flags': 'TRLBAR|FILE1', 'parser': 'parse_cmd_common'}, + \ {'name': 'lgrep', 'minlen': 3, 'flags': 'RANGE|NOTADR|BANG|NEEDARG|EXTRA|NOTRLCOM|TRLBAR|XFILE', 'parser': 'parse_cmd_common'}, + \ {'name': 'lgrepadd', 'minlen': 6, 'flags': 'RANGE|NOTADR|BANG|NEEDARG|EXTRA|NOTRLCOM|TRLBAR|XFILE', 'parser': 'parse_cmd_common'}, + \ {'name': 'lhelpgrep', 'minlen': 2, 'flags': 'EXTRA|NOTRLCOM|NEEDARG', 'parser': 'parse_cmd_common'}, + \ {'name': 'll', 'minlen': 2, 'flags': 'RANGE|NOTADR|COUNT|TRLBAR|BANG', 'parser': 'parse_cmd_common'}, + \ {'name': 'llast', 'minlen': 3, 'flags': 'RANGE|NOTADR|COUNT|TRLBAR|BANG', 'parser': 'parse_cmd_common'}, + \ {'name': 'list', 'minlen': 3, 'flags': 'BANG|EXTRA|TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'lmake', 'minlen': 4, 'flags': 'BANG|EXTRA|NOTRLCOM|TRLBAR|XFILE', 'parser': 'parse_cmd_common'}, + \ {'name': 'lmap', 'minlen': 2, 'flags': 'EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'lmapclear', 'minlen': 5, 'flags': 'EXTRA|TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'lnext', 'minlen': 3, 'flags': 'RANGE|NOTADR|COUNT|TRLBAR|BANG', 'parser': 'parse_cmd_common'}, + \ {'name': 'lnewer', 'minlen': 4, 'flags': 'RANGE|NOTADR|COUNT|TRLBAR', 'parser': 'parse_cmd_common'}, + \ {'name': 'lnfile', 'minlen': 3, 'flags': 'RANGE|NOTADR|COUNT|TRLBAR|BANG', 'parser': 'parse_cmd_common'}, + \ {'name': 'lnoremap', 'minlen': 2, 'flags': 'EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'loadkeymap', 'minlen': 5, 'flags': 'CMDWIN', 'parser': 'parse_cmd_loadkeymap'}, + \ {'name': 'loadview', 'minlen': 2, 'flags': 'FILE1|TRLBAR', 'parser': 'parse_cmd_common'}, + \ {'name': 'lockmarks', 'minlen': 3, 'flags': 'NEEDARG|EXTRA|NOTRLCOM', 'parser': 'parse_cmd_common'}, + \ {'name': 'lockvar', 'minlen': 5, 'flags': 'BANG|EXTRA|NEEDARG|SBOXOK|CMDWIN', 'parser': 'parse_cmd_lockvar'}, + \ {'name': 'lolder', 'minlen': 3, 'flags': 'RANGE|NOTADR|COUNT|TRLBAR', 'parser': 'parse_cmd_common'}, + \ {'name': 'lopen', 'minlen': 3, 'flags': 'RANGE|NOTADR|COUNT|TRLBAR', 'parser': 'parse_cmd_common'}, + \ {'name': 'lprevious', 'minlen': 2, 'flags': 'RANGE|NOTADR|COUNT|TRLBAR|BANG', 'parser': 'parse_cmd_common'}, + \ {'name': 'lpfile', 'minlen': 3, 'flags': 'RANGE|NOTADR|COUNT|TRLBAR|BANG', 'parser': 'parse_cmd_common'}, + \ {'name': 'lrewind', 'minlen': 2, 'flags': 'RANGE|NOTADR|COUNT|TRLBAR|BANG', 'parser': 'parse_cmd_common'}, + \ {'name': 'ls', 'minlen': 2, 'flags': 'BANG|TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'ltag', 'minlen': 2, 'flags': 'NOTADR|TRLBAR|BANG|WORD1', 'parser': 'parse_cmd_common'}, + \ {'name': 'lunmap', 'minlen': 2, 'flags': 'EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'lua', 'minlen': 3, 'flags': 'RANGE|EXTRA|NEEDARG|CMDWIN', 'parser': 'parse_cmd_lua'}, + \ {'name': 'luado', 'minlen': 4, 'flags': 'RANGE|DFLALL|EXTRA|NEEDARG|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'luafile', 'minlen': 4, 'flags': 'RANGE|FILE1|NEEDARG|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'lvimgrep', 'minlen': 2, 'flags': 'RANGE|NOTADR|BANG|NEEDARG|EXTRA|NOTRLCOM|TRLBAR|XFILE', 'parser': 'parse_cmd_common'}, + \ {'name': 'lvimgrepadd', 'minlen': 9, 'flags': 'RANGE|NOTADR|BANG|NEEDARG|EXTRA|NOTRLCOM|TRLBAR|XFILE', 'parser': 'parse_cmd_common'}, + \ {'name': 'lwindow', 'minlen': 2, 'flags': 'RANGE|NOTADR|COUNT|TRLBAR', 'parser': 'parse_cmd_common'}, + \ {'name': 'move', 'minlen': 1, 'flags': 'RANGE|WHOLEFOLD|EXTRA|TRLBAR|CMDWIN|MODIFY', 'parser': 'parse_cmd_common'}, + \ {'name': 'mark', 'minlen': 2, 'flags': 'RANGE|WORD1|TRLBAR|SBOXOK|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'make', 'minlen': 3, 'flags': 'BANG|EXTRA|NOTRLCOM|TRLBAR|XFILE', 'parser': 'parse_cmd_common'}, + \ {'name': 'map', 'minlen': 3, 'flags': 'BANG|EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'mapclear', 'minlen': 4, 'flags': 'EXTRA|BANG|TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'marks', 'minlen': 5, 'flags': 'EXTRA|TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'match', 'minlen': 3, 'flags': 'RANGE|NOTADR|EXTRA|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'menu', 'minlen': 2, 'flags': 'RANGE|NOTADR|ZEROR|BANG|EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'menutranslate', 'minlen': 5, 'flags': 'EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'messages', 'minlen': 3, 'flags': 'TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'mkexrc', 'minlen': 2, 'flags': 'BANG|FILE1|TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'mksession', 'minlen': 3, 'flags': 'BANG|FILE1|TRLBAR', 'parser': 'parse_cmd_common'}, + \ {'name': 'mkspell', 'minlen': 4, 'flags': 'BANG|NEEDARG|EXTRA|NOTRLCOM|TRLBAR|XFILE', 'parser': 'parse_cmd_common'}, + \ {'name': 'mkvimrc', 'minlen': 3, 'flags': 'BANG|FILE1|TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'mkview', 'minlen': 5, 'flags': 'BANG|FILE1|TRLBAR', 'parser': 'parse_cmd_common'}, + \ {'name': 'mode', 'minlen': 3, 'flags': 'WORD1|TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'mzscheme', 'minlen': 2, 'flags': 'RANGE|EXTRA|DFLALL|NEEDARG|CMDWIN|SBOXOK', 'parser': 'parse_cmd_mzscheme'}, + \ {'name': 'mzfile', 'minlen': 3, 'flags': 'RANGE|FILE1|NEEDARG|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'nbclose', 'minlen': 3, 'flags': 'TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'nbkey', 'minlen': 2, 'flags': 'EXTRA|NOTADR|NEEDARG', 'parser': 'parse_cmd_common'}, + \ {'name': 'nbstart', 'minlen': 3, 'flags': 'WORD1|TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'next', 'minlen': 1, 'flags': 'RANGE|NOTADR|BANG|FILES|EDITCMD|ARGOPT|TRLBAR', 'parser': 'parse_cmd_common'}, + \ {'name': 'new', 'minlen': 3, 'flags': 'BANG|FILE1|RANGE|NOTADR|EDITCMD|ARGOPT|TRLBAR', 'parser': 'parse_cmd_common'}, + \ {'name': 'nmap', 'minlen': 2, 'flags': 'EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'nmapclear', 'minlen': 5, 'flags': 'EXTRA|TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'nmenu', 'minlen': 3, 'flags': 'RANGE|NOTADR|ZEROR|EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'nnoremap', 'minlen': 2, 'flags': 'EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'nnoremenu', 'minlen': 7, 'flags': 'RANGE|NOTADR|ZEROR|EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'noautocmd', 'minlen': 3, 'flags': 'NEEDARG|EXTRA|NOTRLCOM', 'parser': 'parse_cmd_common'}, + \ {'name': 'noremap', 'minlen': 2, 'flags': 'BANG|EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'nohlsearch', 'minlen': 3, 'flags': 'TRLBAR|SBOXOK|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'noreabbrev', 'minlen': 5, 'flags': 'EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'noremenu', 'minlen': 6, 'flags': 'RANGE|NOTADR|ZEROR|BANG|EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'normal', 'minlen': 4, 'flags': 'RANGE|BANG|EXTRA|NEEDARG|NOTRLCOM|USECTRLV|SBOXOK|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'number', 'minlen': 2, 'flags': 'RANGE|WHOLEFOLD|COUNT|EXFLAGS|TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'nunmap', 'minlen': 3, 'flags': 'EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'nunmenu', 'minlen': 5, 'flags': 'EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'oldfiles', 'minlen': 2, 'flags': 'BANG|TRLBAR|SBOXOK|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'open', 'minlen': 1, 'flags': 'RANGE|BANG|EXTRA', 'parser': 'parse_cmd_common'}, + \ {'name': 'omap', 'minlen': 2, 'flags': 'EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'omapclear', 'minlen': 5, 'flags': 'EXTRA|TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'omenu', 'minlen': 3, 'flags': 'RANGE|NOTADR|ZEROR|EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'only', 'minlen': 2, 'flags': 'BANG|TRLBAR', 'parser': 'parse_cmd_common'}, + \ {'name': 'onoremap', 'minlen': 3, 'flags': 'EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'onoremenu', 'minlen': 7, 'flags': 'RANGE|NOTADR|ZEROR|EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'options', 'minlen': 3, 'flags': 'TRLBAR', 'parser': 'parse_cmd_common'}, + \ {'name': 'ounmap', 'minlen': 2, 'flags': 'EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'ounmenu', 'minlen': 5, 'flags': 'EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'ownsyntax', 'minlen': 2, 'flags': 'EXTRA|NOTRLCOM|SBOXOK|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'pclose', 'minlen': 2, 'flags': 'BANG|TRLBAR', 'parser': 'parse_cmd_common'}, + \ {'name': 'pedit', 'minlen': 3, 'flags': 'BANG|FILE1|EDITCMD|ARGOPT|TRLBAR', 'parser': 'parse_cmd_common'}, + \ {'name': 'perl', 'minlen': 2, 'flags': 'RANGE|EXTRA|DFLALL|NEEDARG|SBOXOK|CMDWIN', 'parser': 'parse_cmd_perl'}, + \ {'name': 'print', 'minlen': 1, 'flags': 'RANGE|WHOLEFOLD|COUNT|EXFLAGS|TRLBAR|CMDWIN|SBOXOK', 'parser': 'parse_cmd_common'}, + \ {'name': 'profdel', 'minlen': 5, 'flags': 'EXTRA|TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'profile', 'minlen': 4, 'flags': 'BANG|EXTRA|TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'promptfind', 'minlen': 3, 'flags': 'EXTRA|NOTRLCOM|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'promptrepl', 'minlen': 7, 'flags': 'EXTRA|NOTRLCOM|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'perldo', 'minlen': 5, 'flags': 'RANGE|EXTRA|DFLALL|NEEDARG|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'pop', 'minlen': 2, 'flags': 'RANGE|NOTADR|BANG|COUNT|TRLBAR|ZEROR', 'parser': 'parse_cmd_common'}, + \ {'name': 'popup', 'minlen': 4, 'flags': 'NEEDARG|EXTRA|BANG|TRLBAR|NOTRLCOM|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'ppop', 'minlen': 2, 'flags': 'RANGE|NOTADR|BANG|COUNT|TRLBAR|ZEROR', 'parser': 'parse_cmd_common'}, + \ {'name': 'preserve', 'minlen': 3, 'flags': 'TRLBAR', 'parser': 'parse_cmd_common'}, + \ {'name': 'previous', 'minlen': 4, 'flags': 'EXTRA|RANGE|NOTADR|COUNT|BANG|EDITCMD|ARGOPT|TRLBAR', 'parser': 'parse_cmd_common'}, + \ {'name': 'psearch', 'minlen': 2, 'flags': 'BANG|RANGE|WHOLEFOLD|DFLALL|EXTRA', 'parser': 'parse_cmd_common'}, + \ {'name': 'ptag', 'minlen': 2, 'flags': 'RANGE|NOTADR|BANG|WORD1|TRLBAR|ZEROR', 'parser': 'parse_cmd_common'}, + \ {'name': 'ptNext', 'minlen': 3, 'flags': 'RANGE|NOTADR|BANG|TRLBAR|ZEROR', 'parser': 'parse_cmd_common'}, + \ {'name': 'ptfirst', 'minlen': 3, 'flags': 'RANGE|NOTADR|BANG|TRLBAR|ZEROR', 'parser': 'parse_cmd_common'}, + \ {'name': 'ptjump', 'minlen': 3, 'flags': 'BANG|TRLBAR|WORD1', 'parser': 'parse_cmd_common'}, + \ {'name': 'ptlast', 'minlen': 3, 'flags': 'BANG|TRLBAR', 'parser': 'parse_cmd_common'}, + \ {'name': 'ptnext', 'minlen': 3, 'flags': 'RANGE|NOTADR|BANG|TRLBAR|ZEROR', 'parser': 'parse_cmd_common'}, + \ {'name': 'ptprevious', 'minlen': 3, 'flags': 'RANGE|NOTADR|BANG|TRLBAR|ZEROR', 'parser': 'parse_cmd_common'}, + \ {'name': 'ptrewind', 'minlen': 3, 'flags': 'RANGE|NOTADR|BANG|TRLBAR|ZEROR', 'parser': 'parse_cmd_common'}, + \ {'name': 'ptselect', 'minlen': 3, 'flags': 'BANG|TRLBAR|WORD1', 'parser': 'parse_cmd_common'}, + \ {'name': 'put', 'minlen': 2, 'flags': 'RANGE|WHOLEFOLD|BANG|REGSTR|TRLBAR|ZEROR|CMDWIN|MODIFY', 'parser': 'parse_cmd_common'}, + \ {'name': 'pwd', 'minlen': 2, 'flags': 'TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'py3', 'minlen': 3, 'flags': 'RANGE|EXTRA|NEEDARG|CMDWIN', 'parser': 'parse_cmd_python3'}, + \ {'name': 'python3', 'minlen': 7, 'flags': 'RANGE|EXTRA|NEEDARG|CMDWIN', 'parser': 'parse_cmd_python3'}, + \ {'name': 'py3file', 'minlen': 4, 'flags': 'RANGE|FILE1|NEEDARG|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'python', 'minlen': 2, 'flags': 'RANGE|EXTRA|NEEDARG|CMDWIN', 'parser': 'parse_cmd_python'}, + \ {'name': 'pyfile', 'minlen': 3, 'flags': 'RANGE|FILE1|NEEDARG|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'pydo', 'minlen': 3, 'flags': 'RANGE|DFLALL|EXTRA|NEEDARG|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'py3do', 'minlen': 4, 'flags': 'RANGE|DFLALL|EXTRA|NEEDARG|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'quit', 'minlen': 1, 'flags': 'BANG|TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'quitall', 'minlen': 5, 'flags': 'BANG|TRLBAR', 'parser': 'parse_cmd_common'}, + \ {'name': 'qall', 'minlen': 2, 'flags': 'BANG|TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'read', 'minlen': 1, 'flags': 'BANG|RANGE|WHOLEFOLD|FILE1|ARGOPT|TRLBAR|ZEROR|CMDWIN|MODIFY', 'parser': 'parse_cmd_common'}, + \ {'name': 'recover', 'minlen': 3, 'flags': 'BANG|FILE1|TRLBAR', 'parser': 'parse_cmd_common'}, + \ {'name': 'redo', 'minlen': 3, 'flags': 'TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'redir', 'minlen': 4, 'flags': 'BANG|FILES|TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'redraw', 'minlen': 4, 'flags': 'BANG|TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'redrawstatus', 'minlen': 7, 'flags': 'BANG|TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'registers', 'minlen': 3, 'flags': 'EXTRA|NOTRLCOM|TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'resize', 'minlen': 3, 'flags': 'RANGE|NOTADR|TRLBAR|WORD1', 'parser': 'parse_cmd_common'}, + \ {'name': 'retab', 'minlen': 3, 'flags': 'TRLBAR|RANGE|WHOLEFOLD|DFLALL|BANG|WORD1|CMDWIN|MODIFY', 'parser': 'parse_cmd_common'}, + \ {'name': 'return', 'minlen': 4, 'flags': 'EXTRA|NOTRLCOM|SBOXOK|CMDWIN', 'parser': 'parse_cmd_return'}, + \ {'name': 'rewind', 'minlen': 3, 'flags': 'EXTRA|BANG|EDITCMD|ARGOPT|TRLBAR', 'parser': 'parse_cmd_common'}, + \ {'name': 'right', 'minlen': 2, 'flags': 'TRLBAR|RANGE|WHOLEFOLD|EXTRA|CMDWIN|MODIFY', 'parser': 'parse_cmd_common'}, + \ {'name': 'rightbelow', 'minlen': 6, 'flags': 'NEEDARG|EXTRA|NOTRLCOM', 'parser': 'parse_cmd_common'}, + \ {'name': 'ruby', 'minlen': 3, 'flags': 'RANGE|EXTRA|NEEDARG|CMDWIN', 'parser': 'parse_cmd_ruby'}, + \ {'name': 'rubydo', 'minlen': 5, 'flags': 'RANGE|DFLALL|EXTRA|NEEDARG|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'rubyfile', 'minlen': 5, 'flags': 'RANGE|FILE1|NEEDARG|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'rundo', 'minlen': 4, 'flags': 'NEEDARG|FILE1', 'parser': 'parse_cmd_common'}, + \ {'name': 'runtime', 'minlen': 2, 'flags': 'BANG|NEEDARG|FILES|TRLBAR|SBOXOK|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'rviminfo', 'minlen': 2, 'flags': 'BANG|FILE1|TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'substitute', 'minlen': 1, 'flags': 'RANGE|WHOLEFOLD|EXTRA|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'sNext', 'minlen': 2, 'flags': 'EXTRA|RANGE|NOTADR|COUNT|BANG|EDITCMD|ARGOPT|TRLBAR', 'parser': 'parse_cmd_common'}, + \ {'name': 'sandbox', 'minlen': 3, 'flags': 'NEEDARG|EXTRA|NOTRLCOM', 'parser': 'parse_cmd_common'}, + \ {'name': 'sargument', 'minlen': 2, 'flags': 'BANG|RANGE|NOTADR|COUNT|EXTRA|EDITCMD|ARGOPT|TRLBAR', 'parser': 'parse_cmd_common'}, + \ {'name': 'sall', 'minlen': 3, 'flags': 'BANG|RANGE|NOTADR|COUNT|TRLBAR', 'parser': 'parse_cmd_common'}, + \ {'name': 'saveas', 'minlen': 3, 'flags': 'BANG|DFLALL|FILE1|ARGOPT|CMDWIN|TRLBAR', 'parser': 'parse_cmd_common'}, + \ {'name': 'sbuffer', 'minlen': 2, 'flags': 'BANG|RANGE|NOTADR|BUFNAME|BUFUNL|COUNT|EXTRA|TRLBAR', 'parser': 'parse_cmd_common'}, + \ {'name': 'sbNext', 'minlen': 3, 'flags': 'RANGE|NOTADR|COUNT|TRLBAR', 'parser': 'parse_cmd_common'}, + \ {'name': 'sball', 'minlen': 3, 'flags': 'RANGE|NOTADR|COUNT|TRLBAR', 'parser': 'parse_cmd_common'}, + \ {'name': 'sbfirst', 'minlen': 3, 'flags': 'TRLBAR', 'parser': 'parse_cmd_common'}, + \ {'name': 'sblast', 'minlen': 3, 'flags': 'TRLBAR', 'parser': 'parse_cmd_common'}, + \ {'name': 'sbmodified', 'minlen': 3, 'flags': 'RANGE|NOTADR|COUNT|TRLBAR', 'parser': 'parse_cmd_common'}, + \ {'name': 'sbnext', 'minlen': 3, 'flags': 'RANGE|NOTADR|COUNT|TRLBAR', 'parser': 'parse_cmd_common'}, + \ {'name': 'sbprevious', 'minlen': 3, 'flags': 'RANGE|NOTADR|COUNT|TRLBAR', 'parser': 'parse_cmd_common'}, + \ {'name': 'sbrewind', 'minlen': 3, 'flags': 'TRLBAR', 'parser': 'parse_cmd_common'}, + \ {'name': 'scriptnames', 'minlen': 3, 'flags': 'TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'scriptencoding', 'minlen': 7, 'flags': 'WORD1|TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'scscope', 'minlen': 3, 'flags': 'EXTRA|NOTRLCOM', 'parser': 'parse_cmd_common'}, + \ {'name': 'set', 'minlen': 2, 'flags': 'TRLBAR|EXTRA|CMDWIN|SBOXOK', 'parser': 'parse_cmd_common'}, + \ {'name': 'setfiletype', 'minlen': 4, 'flags': 'TRLBAR|EXTRA|NEEDARG|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'setglobal', 'minlen': 4, 'flags': 'TRLBAR|EXTRA|CMDWIN|SBOXOK', 'parser': 'parse_cmd_common'}, + \ {'name': 'setlocal', 'minlen': 4, 'flags': 'TRLBAR|EXTRA|CMDWIN|SBOXOK', 'parser': 'parse_cmd_common'}, + \ {'name': 'sfind', 'minlen': 2, 'flags': 'BANG|FILE1|RANGE|NOTADR|EDITCMD|ARGOPT|TRLBAR', 'parser': 'parse_cmd_common'}, + \ {'name': 'sfirst', 'minlen': 4, 'flags': 'EXTRA|BANG|EDITCMD|ARGOPT|TRLBAR', 'parser': 'parse_cmd_common'}, + \ {'name': 'shell', 'minlen': 2, 'flags': 'TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'simalt', 'minlen': 3, 'flags': 'NEEDARG|WORD1|TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'sign', 'minlen': 3, 'flags': 'NEEDARG|RANGE|NOTADR|EXTRA|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'silent', 'minlen': 3, 'flags': 'NEEDARG|EXTRA|BANG|NOTRLCOM|SBOXOK|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'sleep', 'minlen': 2, 'flags': 'RANGE|NOTADR|COUNT|EXTRA|TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'slast', 'minlen': 3, 'flags': 'EXTRA|BANG|EDITCMD|ARGOPT|TRLBAR', 'parser': 'parse_cmd_common'}, + \ {'name': 'smagic', 'minlen': 2, 'flags': 'RANGE|WHOLEFOLD|EXTRA|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'smap', 'minlen': 4, 'flags': 'EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'smapclear', 'minlen': 5, 'flags': 'EXTRA|TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'smenu', 'minlen': 3, 'flags': 'RANGE|NOTADR|ZEROR|EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'snext', 'minlen': 2, 'flags': 'RANGE|NOTADR|BANG|FILES|EDITCMD|ARGOPT|TRLBAR', 'parser': 'parse_cmd_common'}, + \ {'name': 'sniff', 'minlen': 3, 'flags': 'EXTRA|TRLBAR', 'parser': 'parse_cmd_common'}, + \ {'name': 'snomagic', 'minlen': 3, 'flags': 'RANGE|WHOLEFOLD|EXTRA|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'snoremap', 'minlen': 4, 'flags': 'EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'snoremenu', 'minlen': 7, 'flags': 'RANGE|NOTADR|ZEROR|EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'sort', 'minlen': 3, 'flags': 'RANGE|DFLALL|WHOLEFOLD|BANG|EXTRA|NOTRLCOM|MODIFY', 'parser': 'parse_cmd_common'}, + \ {'name': 'source', 'minlen': 2, 'flags': 'BANG|FILE1|TRLBAR|SBOXOK|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'spelldump', 'minlen': 6, 'flags': 'BANG|TRLBAR', 'parser': 'parse_cmd_common'}, + \ {'name': 'spellgood', 'minlen': 3, 'flags': 'BANG|RANGE|NOTADR|NEEDARG|EXTRA|TRLBAR', 'parser': 'parse_cmd_common'}, + \ {'name': 'spellinfo', 'minlen': 6, 'flags': 'TRLBAR', 'parser': 'parse_cmd_common'}, + \ {'name': 'spellrepall', 'minlen': 6, 'flags': 'TRLBAR', 'parser': 'parse_cmd_common'}, + \ {'name': 'spellundo', 'minlen': 6, 'flags': 'BANG|RANGE|NOTADR|NEEDARG|EXTRA|TRLBAR', 'parser': 'parse_cmd_common'}, + \ {'name': 'spellwrong', 'minlen': 6, 'flags': 'BANG|RANGE|NOTADR|NEEDARG|EXTRA|TRLBAR', 'parser': 'parse_cmd_common'}, + \ {'name': 'split', 'minlen': 2, 'flags': 'BANG|FILE1|RANGE|NOTADR|EDITCMD|ARGOPT|TRLBAR', 'parser': 'parse_cmd_common'}, + \ {'name': 'sprevious', 'minlen': 3, 'flags': 'EXTRA|RANGE|NOTADR|COUNT|BANG|EDITCMD|ARGOPT|TRLBAR', 'parser': 'parse_cmd_common'}, + \ {'name': 'srewind', 'minlen': 3, 'flags': 'EXTRA|BANG|EDITCMD|ARGOPT|TRLBAR', 'parser': 'parse_cmd_common'}, + \ {'name': 'stop', 'minlen': 2, 'flags': 'TRLBAR|BANG|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'stag', 'minlen': 3, 'flags': 'RANGE|NOTADR|BANG|WORD1|TRLBAR|ZEROR', 'parser': 'parse_cmd_common'}, + \ {'name': 'startinsert', 'minlen': 4, 'flags': 'BANG|TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'startgreplace', 'minlen': 6, 'flags': 'BANG|TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'startreplace', 'minlen': 6, 'flags': 'BANG|TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'stopinsert', 'minlen': 5, 'flags': 'BANG|TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'stjump', 'minlen': 3, 'flags': 'BANG|TRLBAR|WORD1', 'parser': 'parse_cmd_common'}, + \ {'name': 'stselect', 'minlen': 3, 'flags': 'BANG|TRLBAR|WORD1', 'parser': 'parse_cmd_common'}, + \ {'name': 'sunhide', 'minlen': 3, 'flags': 'RANGE|NOTADR|COUNT|TRLBAR', 'parser': 'parse_cmd_common'}, + \ {'name': 'sunmap', 'minlen': 4, 'flags': 'EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'sunmenu', 'minlen': 5, 'flags': 'EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'suspend', 'minlen': 3, 'flags': 'TRLBAR|BANG|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'sview', 'minlen': 2, 'flags': 'BANG|FILE1|RANGE|NOTADR|EDITCMD|ARGOPT|TRLBAR', 'parser': 'parse_cmd_common'}, + \ {'name': 'swapname', 'minlen': 2, 'flags': 'TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'syntax', 'minlen': 2, 'flags': 'EXTRA|NOTRLCOM|CMDWIN', 'parser': 'parse_cmd_syntax'}, + \ {'name': 'syntime', 'minlen': 5, 'flags': 'NEEDARG|WORD1|TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'syncbind', 'minlen': 4, 'flags': 'TRLBAR', 'parser': 'parse_cmd_common'}, + \ {'name': 't', 'minlen': 1, 'flags': 'RANGE|WHOLEFOLD|EXTRA|TRLBAR|CMDWIN|MODIFY', 'parser': 'parse_cmd_common'}, + \ {'name': 'tNext', 'minlen': 2, 'flags': 'RANGE|NOTADR|BANG|TRLBAR|ZEROR', 'parser': 'parse_cmd_common'}, + \ {'name': 'tabNext', 'minlen': 4, 'flags': 'RANGE|NOTADR|COUNT|TRLBAR', 'parser': 'parse_cmd_common'}, + \ {'name': 'tabclose', 'minlen': 4, 'flags': 'RANGE|NOTADR|COUNT|BANG|TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'tabdo', 'minlen': 4, 'flags': 'NEEDARG|EXTRA|NOTRLCOM', 'parser': 'parse_cmd_common'}, + \ {'name': 'tabedit', 'minlen': 4, 'flags': 'BANG|FILE1|RANGE|NOTADR|ZEROR|EDITCMD|ARGOPT|TRLBAR', 'parser': 'parse_cmd_common'}, + \ {'name': 'tabfind', 'minlen': 4, 'flags': 'BANG|FILE1|RANGE|NOTADR|ZEROR|EDITCMD|ARGOPT|NEEDARG|TRLBAR', 'parser': 'parse_cmd_common'}, + \ {'name': 'tabfirst', 'minlen': 6, 'flags': 'TRLBAR', 'parser': 'parse_cmd_common'}, + \ {'name': 'tablast', 'minlen': 4, 'flags': 'TRLBAR', 'parser': 'parse_cmd_common'}, + \ {'name': 'tabmove', 'minlen': 4, 'flags': 'RANGE|NOTADR|ZEROR|EXTRA|NOSPC|TRLBAR', 'parser': 'parse_cmd_common'}, + \ {'name': 'tabnew', 'minlen': 6, 'flags': 'BANG|FILE1|RANGE|NOTADR|ZEROR|EDITCMD|ARGOPT|TRLBAR', 'parser': 'parse_cmd_common'}, + \ {'name': 'tabnext', 'minlen': 4, 'flags': 'RANGE|NOTADR|COUNT|TRLBAR', 'parser': 'parse_cmd_common'}, + \ {'name': 'tabonly', 'minlen': 4, 'flags': 'BANG|TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'tabprevious', 'minlen': 4, 'flags': 'RANGE|NOTADR|COUNT|TRLBAR', 'parser': 'parse_cmd_common'}, + \ {'name': 'tabrewind', 'minlen': 4, 'flags': 'TRLBAR', 'parser': 'parse_cmd_common'}, + \ {'name': 'tabs', 'minlen': 4, 'flags': 'TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'tab', 'minlen': 3, 'flags': 'NEEDARG|EXTRA|NOTRLCOM', 'parser': 'parse_cmd_common'}, + \ {'name': 'tag', 'minlen': 2, 'flags': 'RANGE|NOTADR|BANG|WORD1|TRLBAR|ZEROR', 'parser': 'parse_cmd_common'}, + \ {'name': 'tags', 'minlen': 4, 'flags': 'TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'tcl', 'minlen': 2, 'flags': 'RANGE|EXTRA|NEEDARG|CMDWIN', 'parser': 'parse_cmd_tcl'}, + \ {'name': 'tcldo', 'minlen': 4, 'flags': 'RANGE|DFLALL|EXTRA|NEEDARG|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'tclfile', 'minlen': 4, 'flags': 'RANGE|FILE1|NEEDARG|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'tearoff', 'minlen': 2, 'flags': 'NEEDARG|EXTRA|TRLBAR|NOTRLCOM|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'tfirst', 'minlen': 2, 'flags': 'RANGE|NOTADR|BANG|TRLBAR|ZEROR', 'parser': 'parse_cmd_common'}, + \ {'name': 'throw', 'minlen': 2, 'flags': 'EXTRA|NEEDARG|SBOXOK|CMDWIN', 'parser': 'parse_cmd_throw'}, + \ {'name': 'tjump', 'minlen': 2, 'flags': 'BANG|TRLBAR|WORD1', 'parser': 'parse_cmd_common'}, + \ {'name': 'tlast', 'minlen': 2, 'flags': 'BANG|TRLBAR', 'parser': 'parse_cmd_common'}, + \ {'name': 'tmenu', 'minlen': 2, 'flags': 'RANGE|NOTADR|ZEROR|EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'tnext', 'minlen': 2, 'flags': 'RANGE|NOTADR|BANG|TRLBAR|ZEROR', 'parser': 'parse_cmd_common'}, + \ {'name': 'topleft', 'minlen': 2, 'flags': 'NEEDARG|EXTRA|NOTRLCOM', 'parser': 'parse_cmd_common'}, + \ {'name': 'tprevious', 'minlen': 2, 'flags': 'RANGE|NOTADR|BANG|TRLBAR|ZEROR', 'parser': 'parse_cmd_common'}, + \ {'name': 'trewind', 'minlen': 2, 'flags': 'RANGE|NOTADR|BANG|TRLBAR|ZEROR', 'parser': 'parse_cmd_common'}, + \ {'name': 'try', 'minlen': 3, 'flags': 'TRLBAR|SBOXOK|CMDWIN', 'parser': 'parse_cmd_try'}, + \ {'name': 'tselect', 'minlen': 2, 'flags': 'BANG|TRLBAR|WORD1', 'parser': 'parse_cmd_common'}, + \ {'name': 'tunmenu', 'minlen': 2, 'flags': 'EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'undo', 'minlen': 1, 'flags': 'RANGE|NOTADR|COUNT|ZEROR|TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'undojoin', 'minlen': 5, 'flags': 'TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'undolist', 'minlen': 5, 'flags': 'TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'unabbreviate', 'minlen': 3, 'flags': 'EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'unhide', 'minlen': 3, 'flags': 'RANGE|NOTADR|COUNT|TRLBAR', 'parser': 'parse_cmd_common'}, + \ {'name': 'unlet', 'minlen': 3, 'flags': 'BANG|EXTRA|NEEDARG|SBOXOK|CMDWIN', 'parser': 'parse_cmd_unlet'}, + \ {'name': 'unlockvar', 'minlen': 4, 'flags': 'BANG|EXTRA|NEEDARG|SBOXOK|CMDWIN', 'parser': 'parse_cmd_unlockvar'}, + \ {'name': 'unmap', 'minlen': 3, 'flags': 'BANG|EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'unmenu', 'minlen': 4, 'flags': 'BANG|EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'unsilent', 'minlen': 3, 'flags': 'NEEDARG|EXTRA|NOTRLCOM|SBOXOK|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'update', 'minlen': 2, 'flags': 'RANGE|WHOLEFOLD|BANG|FILE1|ARGOPT|DFLALL|TRLBAR', 'parser': 'parse_cmd_common'}, + \ {'name': 'vglobal', 'minlen': 1, 'flags': 'RANGE|WHOLEFOLD|EXTRA|DFLALL|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'version', 'minlen': 2, 'flags': 'EXTRA|TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'verbose', 'minlen': 4, 'flags': 'NEEDARG|RANGE|NOTADR|EXTRA|NOTRLCOM|SBOXOK|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'vertical', 'minlen': 4, 'flags': 'NEEDARG|EXTRA|NOTRLCOM', 'parser': 'parse_cmd_common'}, + \ {'name': 'vimgrep', 'minlen': 3, 'flags': 'RANGE|NOTADR|BANG|NEEDARG|EXTRA|NOTRLCOM|TRLBAR|XFILE', 'parser': 'parse_cmd_common'}, + \ {'name': 'vimgrepadd', 'minlen': 8, 'flags': 'RANGE|NOTADR|BANG|NEEDARG|EXTRA|NOTRLCOM|TRLBAR|XFILE', 'parser': 'parse_cmd_common'}, + \ {'name': 'visual', 'minlen': 2, 'flags': 'BANG|FILE1|EDITCMD|ARGOPT|TRLBAR', 'parser': 'parse_cmd_common'}, + \ {'name': 'viusage', 'minlen': 3, 'flags': 'TRLBAR', 'parser': 'parse_cmd_common'}, + \ {'name': 'view', 'minlen': 3, 'flags': 'BANG|FILE1|EDITCMD|ARGOPT|TRLBAR', 'parser': 'parse_cmd_common'}, + \ {'name': 'vmap', 'minlen': 2, 'flags': 'EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'vmapclear', 'minlen': 5, 'flags': 'EXTRA|TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'vmenu', 'minlen': 3, 'flags': 'RANGE|NOTADR|ZEROR|EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'vnew', 'minlen': 3, 'flags': 'BANG|FILE1|RANGE|NOTADR|EDITCMD|ARGOPT|TRLBAR', 'parser': 'parse_cmd_common'}, + \ {'name': 'vnoremap', 'minlen': 2, 'flags': 'EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'vnoremenu', 'minlen': 7, 'flags': 'RANGE|NOTADR|ZEROR|EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'vsplit', 'minlen': 2, 'flags': 'BANG|FILE1|RANGE|NOTADR|EDITCMD|ARGOPT|TRLBAR', 'parser': 'parse_cmd_common'}, + \ {'name': 'vunmap', 'minlen': 2, 'flags': 'EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'vunmenu', 'minlen': 5, 'flags': 'EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'windo', 'minlen': 5, 'flags': 'BANG|NEEDARG|EXTRA|NOTRLCOM', 'parser': 'parse_cmd_common'}, + \ {'name': 'write', 'minlen': 1, 'flags': 'RANGE|WHOLEFOLD|BANG|FILE1|ARGOPT|DFLALL|TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'wNext', 'minlen': 2, 'flags': 'RANGE|WHOLEFOLD|NOTADR|BANG|FILE1|ARGOPT|TRLBAR', 'parser': 'parse_cmd_common'}, + \ {'name': 'wall', 'minlen': 2, 'flags': 'BANG|TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'while', 'minlen': 2, 'flags': 'EXTRA|NOTRLCOM|SBOXOK|CMDWIN', 'parser': 'parse_cmd_while'}, + \ {'name': 'winsize', 'minlen': 2, 'flags': 'EXTRA|NEEDARG|TRLBAR', 'parser': 'parse_cmd_common'}, + \ {'name': 'wincmd', 'minlen': 4, 'flags': 'NEEDARG|WORD1|RANGE|NOTADR', 'parser': 'parse_wincmd'}, + \ {'name': 'winpos', 'minlen': 4, 'flags': 'EXTRA|TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'wnext', 'minlen': 2, 'flags': 'RANGE|NOTADR|BANG|FILE1|ARGOPT|TRLBAR', 'parser': 'parse_cmd_common'}, + \ {'name': 'wprevious', 'minlen': 2, 'flags': 'RANGE|NOTADR|BANG|FILE1|ARGOPT|TRLBAR', 'parser': 'parse_cmd_common'}, + \ {'name': 'wq', 'minlen': 2, 'flags': 'RANGE|WHOLEFOLD|BANG|FILE1|ARGOPT|DFLALL|TRLBAR', 'parser': 'parse_cmd_common'}, + \ {'name': 'wqall', 'minlen': 3, 'flags': 'BANG|FILE1|ARGOPT|DFLALL|TRLBAR', 'parser': 'parse_cmd_common'}, + \ {'name': 'wsverb', 'minlen': 2, 'flags': 'EXTRA|NOTADR|NEEDARG', 'parser': 'parse_cmd_common'}, + \ {'name': 'wundo', 'minlen': 2, 'flags': 'BANG|NEEDARG|FILE1', 'parser': 'parse_cmd_common'}, + \ {'name': 'wviminfo', 'minlen': 2, 'flags': 'BANG|FILE1|TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'xit', 'minlen': 1, 'flags': 'RANGE|WHOLEFOLD|BANG|FILE1|ARGOPT|DFLALL|TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'xall', 'minlen': 2, 'flags': 'BANG|TRLBAR', 'parser': 'parse_cmd_common'}, + \ {'name': 'xmapclear', 'minlen': 5, 'flags': 'EXTRA|TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'xmap', 'minlen': 2, 'flags': 'EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'xmenu', 'minlen': 3, 'flags': 'RANGE|NOTADR|ZEROR|EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'xnoremap', 'minlen': 2, 'flags': 'EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'xnoremenu', 'minlen': 7, 'flags': 'RANGE|NOTADR|ZEROR|EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'xunmap', 'minlen': 2, 'flags': 'EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'xunmenu', 'minlen': 5, 'flags': 'EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'yank', 'minlen': 1, 'flags': 'RANGE|WHOLEFOLD|REGSTR|COUNT|TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'z', 'minlen': 1, 'flags': 'RANGE|WHOLEFOLD|EXTRA|EXFLAGS|TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': '!', 'minlen': 1, 'flags': 'RANGE|WHOLEFOLD|BANG|FILES|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': '#', 'minlen': 1, 'flags': 'RANGE|WHOLEFOLD|COUNT|EXFLAGS|TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': '&', 'minlen': 1, 'flags': 'RANGE|WHOLEFOLD|EXTRA|CMDWIN|MODIFY', 'parser': 'parse_cmd_common'}, + \ {'name': '*', 'minlen': 1, 'flags': 'RANGE|WHOLEFOLD|EXTRA|TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': '<', 'minlen': 1, 'flags': 'RANGE|WHOLEFOLD|COUNT|EXFLAGS|TRLBAR|CMDWIN|MODIFY', 'parser': 'parse_cmd_common'}, + \ {'name': '=', 'minlen': 1, 'flags': 'RANGE|TRLBAR|DFLALL|EXFLAGS|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': '>', 'minlen': 1, 'flags': 'RANGE|WHOLEFOLD|COUNT|EXFLAGS|TRLBAR|CMDWIN|MODIFY', 'parser': 'parse_cmd_common'}, + \ {'name': '@', 'minlen': 1, 'flags': 'RANGE|WHOLEFOLD|EXTRA|TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'Next', 'minlen': 1, 'flags': 'EXTRA|RANGE|NOTADR|COUNT|BANG|EDITCMD|ARGOPT|TRLBAR', 'parser': 'parse_cmd_common'}, + \ {'name': 'Print', 'minlen': 1, 'flags': 'RANGE|WHOLEFOLD|COUNT|EXFLAGS|TRLBAR|CMDWIN', 'parser': 'parse_cmd_common'}, + \ {'name': 'X', 'minlen': 1, 'flags': 'TRLBAR', 'parser': 'parse_cmd_common'}, + \ {'name': '~', 'minlen': 1, 'flags': 'RANGE|WHOLEFOLD|EXTRA|CMDWIN|MODIFY', 'parser': 'parse_cmd_common'}, + \ + \ {'flags': 'TRLBAR', 'minlen': 3, 'name': 'cbottom', 'parser': 'parse_cmd_common'}, + \ {'flags': 'BANG|NEEDARG|EXTRA|NOTRLCOM|RANGE|NOTADR|DFLALL', 'minlen': 3, 'name': 'cdo', 'parser': 'parse_cmd_common'}, + \ {'flags': 'BANG|NEEDARG|EXTRA|NOTRLCOM|RANGE|NOTADR|DFLALL', 'minlen': 3, 'name': 'cfdo', 'parser': 'parse_cmd_common'}, + \ {'flags': 'TRLBAR', 'minlen': 3, 'name': 'chistory', 'parser': 'parse_cmd_common'}, + \ {'flags': 'TRLBAR|CMDWIN', 'minlen': 3, 'name': 'clearjumps', 'parser': 'parse_cmd_common'}, + \ {'flags': 'BANG|NEEDARG|EXTRA|NOTRLCOM', 'minlen': 4, 'name': 'filter', 'parser': 'parse_cmd_common'}, + \ {'flags': 'RANGE|NOTADR|COUNT|TRLBAR', 'minlen': 5, 'name': 'helpclose', 'parser': 'parse_cmd_common'}, + \ {'flags': 'TRLBAR', 'minlen': 3, 'name': 'lbottom', 'parser': 'parse_cmd_common'}, + \ {'flags': 'BANG|NEEDARG|EXTRA|NOTRLCOM|RANGE|NOTADR|DFLALL', 'minlen': 2, 'name': 'ldo', 'parser': 'parse_cmd_common'}, + \ {'flags': 'BANG|NEEDARG|EXTRA|NOTRLCOM|RANGE|NOTADR|DFLALL', 'minlen': 3, 'name': 'lfdo', 'parser': 'parse_cmd_common'}, + \ {'flags': 'TRLBAR', 'minlen': 3, 'name': 'lhistory', 'parser': 'parse_cmd_common'}, + \ {'flags': 'BANG|EXTRA|TRLBAR|CMDWIN', 'minlen': 3, 'name': 'llist', 'parser': 'parse_cmd_common'}, + \ {'flags': 'NEEDARG|EXTRA|NOTRLCOM', 'minlen': 3, 'name': 'noswapfile', 'parser': 'parse_cmd_common'}, + \ {'flags': 'BANG|FILE1|NEEDARG|TRLBAR|SBOXOK|CMDWIN', 'minlen': 2, 'name': 'packadd', 'parser': 'parse_cmd_common'}, + \ {'flags': 'BANG|TRLBAR|SBOXOK|CMDWIN', 'minlen': 5, 'name': 'packloadall', 'parser': 'parse_cmd_common'}, + \ {'flags': 'TRLBAR|CMDWIN|SBOXOK', 'minlen': 3, 'name': 'smile', 'parser': 'parse_cmd_common'}, + \ {'flags': 'RANGE|EXTRA|NEEDARG|CMDWIN', 'minlen': 3, 'name': 'pyx', 'parser': 'parse_cmd_common'}, + \ {'flags': 'RANGE|DFLALL|EXTRA|NEEDARG|CMDWIN', 'minlen': 4, 'name': 'pyxdo', 'parser': 'parse_cmd_common'}, + \ {'flags': 'RANGE|EXTRA|NEEDARG|CMDWIN', 'minlen': 7, 'name': 'pythonx', 'parser': 'parse_cmd_common'}, + \ {'flags': 'RANGE|FILE1|NEEDARG|CMDWIN', 'minlen': 4, 'name': 'pyxfile', 'parser': 'parse_cmd_common'}, + \ {'flags': 'RANGE|BANG|FILES|CMDWIN', 'minlen': 3, 'name': 'terminal', 'parser': 'parse_cmd_common'}, + \ {'flags': 'EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN', 'minlen': 3, 'name': 'tmap', 'parser': 'parse_cmd_common'}, + \ {'flags': 'EXTRA|TRLBAR|CMDWIN', 'minlen': 5, 'name': 'tmapclear', 'parser': 'parse_cmd_common'}, + \ {'flags': 'EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN', 'minlen': 3, 'name': 'tnoremap', 'parser': 'parse_cmd_common'}, + \ {'flags': 'EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN', 'minlen': 5, 'name': 'tunmap', 'parser': 'parse_cmd_common'}, + \] + +let s:ExprTokenizer = {} + +function! s:ExprTokenizer.new(...) + let obj = copy(self) + call call(obj.__init__, a:000, obj) + return obj +endfunction + +function! s:ExprTokenizer.__init__(reader) + let self.reader = a:reader + let self.cache = {} +endfunction + +function! s:ExprTokenizer.token(type, value, pos) + return {'type': a:type, 'value': a:value, 'pos': a:pos} +endfunction + +function! s:ExprTokenizer.peek() + let pos = self.reader.tell() + let r = self.get() + call self.reader.seek_set(pos) + return r +endfunction + +function! s:ExprTokenizer.get() + " FIXME: remove dirty hack + if has_key(self.cache, self.reader.tell()) + let x = self.cache[self.reader.tell()] + call self.reader.seek_set(x[0]) + return x[1] + endif + let pos = self.reader.tell() + call self.reader.skip_white() + let r = self.get2() + let self.cache[pos] = [self.reader.tell(), r] + return r +endfunction + +function! s:ExprTokenizer.get2() + let r = self.reader + let pos = r.getpos() + let c = r.peek() + if c ==# '<EOF>' + return self.token(s:TOKEN_EOF, c, pos) + elseif c ==# '<EOL>' + call r.seek_cur(1) + return self.token(s:TOKEN_EOL, c, pos) + elseif s:iswhite(c) + let s = r.read_white() + return self.token(s:TOKEN_SPACE, s, pos) + elseif c ==# '0' && (r.p(1) ==# 'X' || r.p(1) ==# 'x') && s:isxdigit(r.p(2)) + let s = r.getn(3) + let s .= r.read_xdigit() + return self.token(s:TOKEN_NUMBER, s, pos) + elseif s:isdigit(c) + let s = r.read_digit() + if r.p(0) ==# '.' && s:isdigit(r.p(1)) + let s .= r.getn(1) + let s .= r.read_digit() + if (r.p(0) ==# 'E' || r.p(0) ==# 'e') && (s:isdigit(r.p(1)) || ((r.p(1) ==# '-' || r.p(1) ==# '+') && s:isdigit(r.p(2)))) + let s .= r.getn(2) + let s .= r.read_digit() + endif + endif + return self.token(s:TOKEN_NUMBER, s, pos) + elseif c ==# 'i' && r.p(1) ==# 's' && !s:isidc(r.p(2)) + if r.p(2) ==# '?' + call r.seek_cur(3) + return self.token(s:TOKEN_ISCI, 'is?', pos) + elseif r.p(2) ==# '#' + call r.seek_cur(3) + return self.token(s:TOKEN_ISCS, 'is#', pos) + else + call r.seek_cur(2) + return self.token(s:TOKEN_IS, 'is', pos) + endif + elseif c ==# 'i' && r.p(1) ==# 's' && r.p(2) ==# 'n' && r.p(3) ==# 'o' && r.p(4) ==# 't' && !s:isidc(r.p(5)) + if r.p(5) ==# '?' + call r.seek_cur(6) + return self.token(s:TOKEN_ISNOTCI, 'isnot?', pos) + elseif r.p(5) ==# '#' + call r.seek_cur(6) + return self.token(s:TOKEN_ISNOTCS, 'isnot#', pos) + else + call r.seek_cur(5) + return self.token(s:TOKEN_ISNOT, 'isnot', pos) + endif + elseif s:isnamec1(c) + let s = r.read_name() + return self.token(s:TOKEN_IDENTIFIER, s, pos) + elseif c ==# '|' && r.p(1) ==# '|' + call r.seek_cur(2) + return self.token(s:TOKEN_OROR, '||', pos) + elseif c ==# '&' && r.p(1) ==# '&' + call r.seek_cur(2) + return self.token(s:TOKEN_ANDAND, '&&', pos) + elseif c ==# '=' && r.p(1) ==# '=' + if r.p(2) ==# '?' + call r.seek_cur(3) + return self.token(s:TOKEN_EQEQCI, '==?', pos) + elseif r.p(2) ==# '#' + call r.seek_cur(3) + return self.token(s:TOKEN_EQEQCS, '==#', pos) + else + call r.seek_cur(2) + return self.token(s:TOKEN_EQEQ, '==', pos) + endif + elseif c ==# '!' && r.p(1) ==# '=' + if r.p(2) ==# '?' + call r.seek_cur(3) + return self.token(s:TOKEN_NEQCI, '!=?', pos) + elseif r.p(2) ==# '#' + call r.seek_cur(3) + return self.token(s:TOKEN_NEQCS, '!=#', pos) + else + call r.seek_cur(2) + return self.token(s:TOKEN_NEQ, '!=', pos) + endif + elseif c ==# '>' && r.p(1) ==# '=' + if r.p(2) ==# '?' + call r.seek_cur(3) + return self.token(s:TOKEN_GTEQCI, '>=?', pos) + elseif r.p(2) ==# '#' + call r.seek_cur(3) + return self.token(s:TOKEN_GTEQCS, '>=#', pos) + else + call r.seek_cur(2) + return self.token(s:TOKEN_GTEQ, '>=', pos) + endif + elseif c ==# '<' && r.p(1) ==# '=' + if r.p(2) ==# '?' + call r.seek_cur(3) + return self.token(s:TOKEN_LTEQCI, '<=?', pos) + elseif r.p(2) ==# '#' + call r.seek_cur(3) + return self.token(s:TOKEN_LTEQCS, '<=#', pos) + else + call r.seek_cur(2) + return self.token(s:TOKEN_LTEQ, '<=', pos) + endif + elseif c ==# '=' && r.p(1) ==# '~' + if r.p(2) ==# '?' + call r.seek_cur(3) + return self.token(s:TOKEN_MATCHCI, '=~?', pos) + elseif r.p(2) ==# '#' + call r.seek_cur(3) + return self.token(s:TOKEN_MATCHCS, '=~#', pos) + else + call r.seek_cur(2) + return self.token(s:TOKEN_MATCH, '=~', pos) + endif + elseif c ==# '!' && r.p(1) ==# '~' + if r.p(2) ==# '?' + call r.seek_cur(3) + return self.token(s:TOKEN_NOMATCHCI, '!~?', pos) + elseif r.p(2) ==# '#' + call r.seek_cur(3) + return self.token(s:TOKEN_NOMATCHCS, '!~#', pos) + else + call r.seek_cur(2) + return self.token(s:TOKEN_NOMATCH, '!~', pos) + endif + elseif c ==# '>' + if r.p(1) ==# '?' + call r.seek_cur(2) + return self.token(s:TOKEN_GTCI, '>?', pos) + elseif r.p(1) ==# '#' + call r.seek_cur(2) + return self.token(s:TOKEN_GTCS, '>#', pos) + else + call r.seek_cur(1) + return self.token(s:TOKEN_GT, '>', pos) + endif + elseif c ==# '<' + if r.p(1) ==# '?' + call r.seek_cur(2) + return self.token(s:TOKEN_LTCI, '<?', pos) + elseif r.p(1) ==# '#' + call r.seek_cur(2) + return self.token(s:TOKEN_LTCS, '<#', pos) + else + call r.seek_cur(1) + return self.token(s:TOKEN_LT, '<', pos) + endif + elseif c ==# '+' + call r.seek_cur(1) + return self.token(s:TOKEN_PLUS, '+', pos) + elseif c ==# '-' + if r.p(1) ==# '>' + call r.seek_cur(2) + return self.token(s:TOKEN_ARROW, '->', pos) + else + call r.seek_cur(1) + return self.token(s:TOKEN_MINUS, '-', pos) + endif + elseif c ==# '.' + if r.p(1) ==# '.' && r.p(2) ==# '.' + call r.seek_cur(3) + return self.token(s:TOKEN_DOTDOTDOT, '...', pos) + else + call r.seek_cur(1) + return self.token(s:TOKEN_DOT, '.', pos) + endif + elseif c ==# '*' + call r.seek_cur(1) + return self.token(s:TOKEN_STAR, '*', pos) + elseif c ==# '/' + call r.seek_cur(1) + return self.token(s:TOKEN_SLASH, '/', pos) + elseif c ==# '%' + call r.seek_cur(1) + return self.token(s:TOKEN_PERCENT, '%', pos) + elseif c ==# '!' + call r.seek_cur(1) + return self.token(s:TOKEN_NOT, '!', pos) + elseif c ==# '?' + call r.seek_cur(1) + return self.token(s:TOKEN_QUESTION, '?', pos) + elseif c ==# ':' + call r.seek_cur(1) + return self.token(s:TOKEN_COLON, ':', pos) + elseif c ==# '#' + call r.seek_cur(1) + return self.token(s:TOKEN_SHARP, '#', pos) + elseif c ==# '(' + call r.seek_cur(1) + return self.token(s:TOKEN_POPEN, '(', pos) + elseif c ==# ')' + call r.seek_cur(1) + return self.token(s:TOKEN_PCLOSE, ')', pos) + elseif c ==# '[' + call r.seek_cur(1) + return self.token(s:TOKEN_SQOPEN, '[', pos) + elseif c ==# ']' + call r.seek_cur(1) + return self.token(s:TOKEN_SQCLOSE, ']', pos) + elseif c ==# '{' + call r.seek_cur(1) + return self.token(s:TOKEN_COPEN, '{', pos) + elseif c ==# '}' + call r.seek_cur(1) + return self.token(s:TOKEN_CCLOSE, '}', pos) + elseif c ==# ',' + call r.seek_cur(1) + return self.token(s:TOKEN_COMMA, ',', pos) + elseif c ==# "'" + call r.seek_cur(1) + return self.token(s:TOKEN_SQUOTE, "'", pos) + elseif c ==# '"' + call r.seek_cur(1) + return self.token(s:TOKEN_DQUOTE, '"', pos) + elseif c ==# '$' + let s = r.getn(1) + let s .= r.read_word() + return self.token(s:TOKEN_ENV, s, pos) + elseif c ==# '@' + " @<EOL> is treated as @" + return self.token(s:TOKEN_REG, r.getn(2), pos) + elseif c ==# '&' + let s = '' + if (r.p(1) ==# 'g' || r.p(1) ==# 'l') && r.p(2) ==# ':' + let s = r.getn(3) . r.read_word() + else + let s = r.getn(1) . r.read_word() + endif + return self.token(s:TOKEN_OPTION, s, pos) + elseif c ==# '=' + call r.seek_cur(1) + return self.token(s:TOKEN_EQ, '=', pos) + elseif c ==# '|' + call r.seek_cur(1) + return self.token(s:TOKEN_OR, '|', pos) + elseif c ==# ';' + call r.seek_cur(1) + return self.token(s:TOKEN_SEMICOLON, ';', pos) + elseif c ==# '`' + call r.seek_cur(1) + return self.token(s:TOKEN_BACKTICK, '`', pos) + else + throw s:Err(printf('unexpected character: %s', c), self.reader.getpos()) + endif +endfunction + +function! s:ExprTokenizer.get_sstring() + call self.reader.skip_white() + let c = self.reader.p(0) + if c !=# "'" + throw s:Err(printf('unexpected character: %s', c), self.reader.getpos()) + endif + call self.reader.seek_cur(1) + let s = '' + while s:TRUE + let c = self.reader.p(0) + if c ==# '<EOF>' || c ==# '<EOL>' + throw s:Err('unexpected EOL', self.reader.getpos()) + elseif c ==# "'" + call self.reader.seek_cur(1) + if self.reader.p(0) ==# "'" + call self.reader.seek_cur(1) + let s .= "''" + else + break + endif + else + call self.reader.seek_cur(1) + let s .= c + endif + endwhile + return s +endfunction + +function! s:ExprTokenizer.get_dstring() + call self.reader.skip_white() + let c = self.reader.p(0) + if c !=# '"' + throw s:Err(printf('unexpected character: %s', c), self.reader.getpos()) + endif + call self.reader.seek_cur(1) + let s = '' + while s:TRUE + let c = self.reader.p(0) + if c ==# '<EOF>' || c ==# '<EOL>' + throw s:Err('unexpectd EOL', self.reader.getpos()) + elseif c ==# '"' + call self.reader.seek_cur(1) + break + elseif c ==# '\' + call self.reader.seek_cur(1) + let s .= c + let c = self.reader.p(0) + if c ==# '<EOF>' || c ==# '<EOL>' + throw s:Err('ExprTokenizer: unexpected EOL', self.reader.getpos()) + endif + call self.reader.seek_cur(1) + let s .= c + else + call self.reader.seek_cur(1) + let s .= c + endif + endwhile + return s +endfunction + +let s:ExprParser = {} + +function! s:ExprParser.new(...) + let obj = copy(self) + call call(obj.__init__, a:000, obj) + return obj +endfunction + +function! s:ExprParser.__init__(reader) + let self.reader = a:reader + let self.tokenizer = s:ExprTokenizer.new(a:reader) +endfunction + +function! s:ExprParser.parse() + return self.parse_expr1() +endfunction + +" expr1: expr2 ? expr1 : expr1 +function! s:ExprParser.parse_expr1() + let left = self.parse_expr2() + let pos = self.reader.tell() + let token = self.tokenizer.get() + if token.type == s:TOKEN_QUESTION + let node = s:Node(s:NODE_TERNARY) + let node.pos = token.pos + let node.cond = left + let node.left = self.parse_expr1() + let token = self.tokenizer.get() + if token.type != s:TOKEN_COLON + throw s:Err(printf('unexpected token: %s', token.value), token.pos) + endif + let node.right = self.parse_expr1() + let left = node + else + call self.reader.seek_set(pos) + endif + return left +endfunction + +" expr2: expr3 || expr3 .. +function! s:ExprParser.parse_expr2() + let left = self.parse_expr3() + while s:TRUE + let pos = self.reader.tell() + let token = self.tokenizer.get() + if token.type == s:TOKEN_OROR + let node = s:Node(s:NODE_OR) + let node.pos = token.pos + let node.left = left + let node.right = self.parse_expr3() + let left = node + else + call self.reader.seek_set(pos) + break + endif + endwhile + return left +endfunction + +" expr3: expr4 && expr4 +function! s:ExprParser.parse_expr3() + let left = self.parse_expr4() + while s:TRUE + let pos = self.reader.tell() + let token = self.tokenizer.get() + if token.type == s:TOKEN_ANDAND + let node = s:Node(s:NODE_AND) + let node.pos = token.pos + let node.left = left + let node.right = self.parse_expr4() + let left = node + else + call self.reader.seek_set(pos) + break + endif + endwhile + return left +endfunction + +" expr4: expr5 == expr5 +" expr5 != expr5 +" expr5 > expr5 +" expr5 >= expr5 +" expr5 < expr5 +" expr5 <= expr5 +" expr5 =~ expr5 +" expr5 !~ expr5 +" +" expr5 ==? expr5 +" expr5 ==# expr5 +" etc. +" +" expr5 is expr5 +" expr5 isnot expr5 +function! s:ExprParser.parse_expr4() + let left = self.parse_expr5() + let pos = self.reader.tell() + let token = self.tokenizer.get() + if token.type == s:TOKEN_EQEQ + let node = s:Node(s:NODE_EQUAL) + let node.pos = token.pos + let node.left = left + let node.right = self.parse_expr5() + let left = node + elseif token.type == s:TOKEN_EQEQCI + let node = s:Node(s:NODE_EQUALCI) + let node.pos = token.pos + let node.left = left + let node.right = self.parse_expr5() + let left = node + elseif token.type == s:TOKEN_EQEQCS + let node = s:Node(s:NODE_EQUALCS) + let node.pos = token.pos + let node.left = left + let node.right = self.parse_expr5() + let left = node + elseif token.type == s:TOKEN_NEQ + let node = s:Node(s:NODE_NEQUAL) + let node.pos = token.pos + let node.left = left + let node.right = self.parse_expr5() + let left = node + elseif token.type == s:TOKEN_NEQCI + let node = s:Node(s:NODE_NEQUALCI) + let node.pos = token.pos + let node.left = left + let node.right = self.parse_expr5() + let left = node + elseif token.type == s:TOKEN_NEQCS + let node = s:Node(s:NODE_NEQUALCS) + let node.pos = token.pos + let node.left = left + let node.right = self.parse_expr5() + let left = node + elseif token.type == s:TOKEN_GT + let node = s:Node(s:NODE_GREATER) + let node.pos = token.pos + let node.left = left + let node.right = self.parse_expr5() + let left = node + elseif token.type == s:TOKEN_GTCI + let node = s:Node(s:NODE_GREATERCI) + let node.pos = token.pos + let node.left = left + let node.right = self.parse_expr5() + let left = node + elseif token.type == s:TOKEN_GTCS + let node = s:Node(s:NODE_GREATERCS) + let node.pos = token.pos + let node.left = left + let node.right = self.parse_expr5() + let left = node + elseif token.type == s:TOKEN_GTEQ + let node = s:Node(s:NODE_GEQUAL) + let node.pos = token.pos + let node.left = left + let node.right = self.parse_expr5() + let left = node + elseif token.type == s:TOKEN_GTEQCI + let node = s:Node(s:NODE_GEQUALCI) + let node.pos = token.pos + let node.left = left + let node.right = self.parse_expr5() + let left = node + elseif token.type == s:TOKEN_GTEQCS + let node = s:Node(s:NODE_GEQUALCS) + let node.pos = token.pos + let node.left = left + let node.right = self.parse_expr5() + let left = node + elseif token.type == s:TOKEN_LT + let node = s:Node(s:NODE_SMALLER) + let node.pos = token.pos + let node.left = left + let node.right = self.parse_expr5() + let left = node + elseif token.type == s:TOKEN_LTCI + let node = s:Node(s:NODE_SMALLERCI) + let node.pos = token.pos + let node.left = left + let node.right = self.parse_expr5() + let left = node + elseif token.type == s:TOKEN_LTCS + let node = s:Node(s:NODE_SMALLERCS) + let node.pos = token.pos + let node.left = left + let node.right = self.parse_expr5() + let left = node + elseif token.type == s:TOKEN_LTEQ + let node = s:Node(s:NODE_SEQUAL) + let node.pos = token.pos + let node.left = left + let node.right = self.parse_expr5() + let left = node + elseif token.type == s:TOKEN_LTEQCI + let node = s:Node(s:NODE_SEQUALCI) + let node.pos = token.pos + let node.left = left + let node.right = self.parse_expr5() + let left = node + elseif token.type == s:TOKEN_LTEQCS + let node = s:Node(s:NODE_SEQUALCS) + let node.pos = token.pos + let node.left = left + let node.right = self.parse_expr5() + let left = node + elseif token.type == s:TOKEN_MATCH + let node = s:Node(s:NODE_MATCH) + let node.pos = token.pos + let node.left = left + let node.right = self.parse_expr5() + let left = node + elseif token.type == s:TOKEN_MATCHCI + let node = s:Node(s:NODE_MATCHCI) + let node.pos = token.pos + let node.left = left + let node.right = self.parse_expr5() + let left = node + elseif token.type == s:TOKEN_MATCHCS + let node = s:Node(s:NODE_MATCHCS) + let node.pos = token.pos + let node.left = left + let node.right = self.parse_expr5() + let left = node + elseif token.type == s:TOKEN_NOMATCH + let node = s:Node(s:NODE_NOMATCH) + let node.pos = token.pos + let node.left = left + let node.right = self.parse_expr5() + let left = node + elseif token.type == s:TOKEN_NOMATCHCI + let node = s:Node(s:NODE_NOMATCHCI) + let node.pos = token.pos + let node.left = left + let node.right = self.parse_expr5() + let left = node + elseif token.type == s:TOKEN_NOMATCHCS + let node = s:Node(s:NODE_NOMATCHCS) + let node.pos = token.pos + let node.left = left + let node.right = self.parse_expr5() + let left = node + elseif token.type == s:TOKEN_IS + let node = s:Node(s:NODE_IS) + let node.pos = token.pos + let node.left = left + let node.right = self.parse_expr5() + let left = node + elseif token.type == s:TOKEN_ISCI + let node = s:Node(s:NODE_ISCI) + let node.pos = token.pos + let node.left = left + let node.right = self.parse_expr5() + let left = node + elseif token.type == s:TOKEN_ISCS + let node = s:Node(s:NODE_ISCS) + let node.pos = token.pos + let node.left = left + let node.right = self.parse_expr5() + let left = node + elseif token.type == s:TOKEN_ISNOT + let node = s:Node(s:NODE_ISNOT) + let node.pos = token.pos + let node.left = left + let node.right = self.parse_expr5() + let left = node + elseif token.type == s:TOKEN_ISNOTCI + let node = s:Node(s:NODE_ISNOTCI) + let node.pos = token.pos + let node.left = left + let node.right = self.parse_expr5() + let left = node + elseif token.type == s:TOKEN_ISNOTCS + let node = s:Node(s:NODE_ISNOTCS) + let node.pos = token.pos + let node.left = left + let node.right = self.parse_expr5() + let left = node + else + call self.reader.seek_set(pos) + endif + return left +endfunction + +" expr5: expr6 + expr6 .. +" expr6 - expr6 .. +" expr6 . expr6 .. +function! s:ExprParser.parse_expr5() + let left = self.parse_expr6() + while s:TRUE + let pos = self.reader.tell() + let token = self.tokenizer.get() + if token.type == s:TOKEN_PLUS + let node = s:Node(s:NODE_ADD) + let node.pos = token.pos + let node.left = left + let node.right = self.parse_expr6() + let left = node + elseif token.type == s:TOKEN_MINUS + let node = s:Node(s:NODE_SUBTRACT) + let node.pos = token.pos + let node.left = left + let node.right = self.parse_expr6() + let left = node + elseif token.type == s:TOKEN_DOT + let node = s:Node(s:NODE_CONCAT) + let node.pos = token.pos + let node.left = left + let node.right = self.parse_expr6() + let left = node + else + call self.reader.seek_set(pos) + break + endif + endwhile + return left +endfunction + +" expr6: expr7 * expr7 .. +" expr7 / expr7 .. +" expr7 % expr7 .. +function! s:ExprParser.parse_expr6() + let left = self.parse_expr7() + while s:TRUE + let pos = self.reader.tell() + let token = self.tokenizer.get() + if token.type == s:TOKEN_STAR + let node = s:Node(s:NODE_MULTIPLY) + let node.pos = token.pos + let node.left = left + let node.right = self.parse_expr7() + let left = node + elseif token.type == s:TOKEN_SLASH + let node = s:Node(s:NODE_DIVIDE) + let node.pos = token.pos + let node.left = left + let node.right = self.parse_expr7() + let left = node + elseif token.type == s:TOKEN_PERCENT + let node = s:Node(s:NODE_REMAINDER) + let node.pos = token.pos + let node.left = left + let node.right = self.parse_expr7() + let left = node + else + call self.reader.seek_set(pos) + break + endif + endwhile + return left +endfunction + +" expr7: ! expr7 +" - expr7 +" + expr7 +function! s:ExprParser.parse_expr7() + let pos = self.reader.tell() + let token = self.tokenizer.get() + if token.type == s:TOKEN_NOT + let node = s:Node(s:NODE_NOT) + let node.pos = token.pos + let node.left = self.parse_expr7() + return node + elseif token.type == s:TOKEN_MINUS + let node = s:Node(s:NODE_MINUS) + let node.pos = token.pos + let node.left = self.parse_expr7() + return node + elseif token.type == s:TOKEN_PLUS + let node = s:Node(s:NODE_PLUS) + let node.pos = token.pos + let node.left = self.parse_expr7() + return node + else + call self.reader.seek_set(pos) + let node = self.parse_expr8() + return node + endif +endfunction + +" expr8: expr8[expr1] +" expr8[expr1 : expr1] +" expr8.name +" expr8(expr1, ...) +function! s:ExprParser.parse_expr8() + let left = self.parse_expr9() + while s:TRUE + let pos = self.reader.tell() + let c = self.reader.peek() + let token = self.tokenizer.get() + if !s:iswhite(c) && token.type == s:TOKEN_SQOPEN + let npos = token.pos + if self.tokenizer.peek().type == s:TOKEN_COLON + call self.tokenizer.get() + let node = s:Node(s:NODE_SLICE) + let node.pos = npos + let node.left = left + let node.rlist = [s:NIL, s:NIL] + let token = self.tokenizer.peek() + if token.type != s:TOKEN_SQCLOSE + let node.rlist[1] = self.parse_expr1() + endif + let token = self.tokenizer.get() + if token.type != s:TOKEN_SQCLOSE + throw s:Err(printf('unexpected token: %s', token.value), token.pos) + endif + let left = node + else + let right = self.parse_expr1() + if self.tokenizer.peek().type == s:TOKEN_COLON + call self.tokenizer.get() + let node = s:Node(s:NODE_SLICE) + let node.pos = npos + let node.left = left + let node.rlist = [right, s:NIL] + let token = self.tokenizer.peek() + if token.type != s:TOKEN_SQCLOSE + let node.rlist[1] = self.parse_expr1() + endif + let token = self.tokenizer.get() + if token.type != s:TOKEN_SQCLOSE + throw s:Err(printf('unexpected token: %s', token.value), token.pos) + endif + let left = node + else + let node = s:Node(s:NODE_SUBSCRIPT) + let node.pos = npos + let node.left = left + let node.right = right + let token = self.tokenizer.get() + if token.type != s:TOKEN_SQCLOSE + throw s:Err(printf('unexpected token: %s', token.value), token.pos) + endif + let left = node + endif + endif + unlet node + elseif token.type == s:TOKEN_POPEN + let node = s:Node(s:NODE_CALL) + let node.pos = token.pos + let node.left = left + let node.rlist = [] + if self.tokenizer.peek().type == s:TOKEN_PCLOSE + call self.tokenizer.get() + else + while s:TRUE + call add(node.rlist, self.parse_expr1()) + let token = self.tokenizer.get() + if token.type == s:TOKEN_COMMA + " XXX: Vim allows foo(a, b, ). Lint should warn it. + if self.tokenizer.peek().type == s:TOKEN_PCLOSE + call self.tokenizer.get() + break + endif + elseif token.type == s:TOKEN_PCLOSE + break + else + throw s:Err(printf('unexpected token: %s', token.value), token.pos) + endif + endwhile + endif + if len(node.rlist) > s:MAX_FUNC_ARGS + " TODO: funcname E740: Too many arguments for function: %s + throw s:Err('E740: Too many arguments for function', node.pos) + endif + let left = node + unlet node + elseif !s:iswhite(c) && token.type == s:TOKEN_DOT + let node = self.parse_dot(token, left) + if node is s:NIL + call self.reader.seek_set(pos) + break + endif + let left = node + unlet node + else + call self.reader.seek_set(pos) + break + endif + endwhile + return left +endfunction + +" expr9: number +" "string" +" 'string' +" [expr1, ...] +" {expr1: expr1, ...} +" {args -> expr1} +" &option +" (expr1) +" variable +" var{ria}ble +" $VAR +" @r +" function(expr1, ...) +" func{ti}on(expr1, ...) +function! s:ExprParser.parse_expr9() + let pos = self.reader.tell() + let token = self.tokenizer.get() + let node = s:Node(-1) + if token.type == s:TOKEN_NUMBER + let node = s:Node(s:NODE_NUMBER) + let node.pos = token.pos + let node.value = token.value + elseif token.type == s:TOKEN_DQUOTE + call self.reader.seek_set(pos) + let node = s:Node(s:NODE_STRING) + let node.pos = token.pos + let node.value = '"' . self.tokenizer.get_dstring() . '"' + elseif token.type == s:TOKEN_SQUOTE + call self.reader.seek_set(pos) + let node = s:Node(s:NODE_STRING) + let node.pos = token.pos + let node.value = "'" . self.tokenizer.get_sstring() . "'" + elseif token.type == s:TOKEN_SQOPEN + let node = s:Node(s:NODE_LIST) + let node.pos = token.pos + let node.value = [] + let token = self.tokenizer.peek() + if token.type == s:TOKEN_SQCLOSE + call self.tokenizer.get() + else + while s:TRUE + call add(node.value, self.parse_expr1()) + let token = self.tokenizer.peek() + if token.type == s:TOKEN_COMMA + call self.tokenizer.get() + if self.tokenizer.peek().type == s:TOKEN_SQCLOSE + call self.tokenizer.get() + break + endif + elseif token.type == s:TOKEN_SQCLOSE + call self.tokenizer.get() + break + else + throw s:Err(printf('unexpected token: %s', token.value), token.pos) + endif + endwhile + endif + elseif token.type == s:TOKEN_COPEN + let savepos = self.reader.tell() + let nodepos = token.pos + let token = self.tokenizer.get() + let lambda = token.type == s:TOKEN_ARROW + if !lambda && !(token.type == s:TOKEN_SQUOTE || token.type == s:TOKEN_DQUOTE) + " if the token type is stirng, we cannot peek next token and we can + " assume it's not lambda. + let token2 = self.tokenizer.peek() + let lambda = token2.type == s:TOKEN_ARROW || token2.type == s:TOKEN_COMMA + endif + " fallback to dict or {expr} if true + let fallback = s:FALSE + if lambda + " lambda {token,...} {->...} {token->...} + let node = s:Node(s:NODE_LAMBDA) + let node.pos = nodepos + let node.rlist = [] + let named = {} + while s:TRUE + if token.type == s:TOKEN_ARROW + break + elseif token.type == s:TOKEN_IDENTIFIER + if !s:isargname(token.value) + throw s:Err(printf('E125: Illegal argument: %s', token.value), token.pos) + elseif has_key(named, token.value) + throw s:Err(printf('E853: Duplicate argument name: %s', token.value), token.pos) + endif + let named[token.value] = 1 + let varnode = s:Node(s:NODE_IDENTIFIER) + let varnode.pos = token.pos + let varnode.value = token.value + " XXX: Vim doesn't skip white space before comma. {a ,b -> ...} => E475 + if s:iswhite(self.reader.p(0)) && self.tokenizer.peek().type == s:TOKEN_COMMA + throw s:Err('E475: Invalid argument: White space is not allowed before comma', self.reader.getpos()) + endif + let token = self.tokenizer.get() + call add(node.rlist, varnode) + if token.type == s:TOKEN_COMMA + " XXX: Vim allows last comma. {a, b, -> ...} => OK + let token = self.tokenizer.peek() + if token.type == s:TOKEN_ARROW + call self.tokenizer.get() + break + endif + elseif token.type == s:TOKEN_ARROW + break + else + throw s:Err(printf('unexpected token: %s, type: %d', token.value, token.type), token.pos) + endif + elseif token.type == s:TOKEN_DOTDOTDOT + let varnode = s:Node(s:NODE_IDENTIFIER) + let varnode.pos = token.pos + let varnode.value = token.value + call add(node.rlist, varnode) + let token = self.tokenizer.peek() + if token.type == s:TOKEN_ARROW + call self.tokenizer.get() + break + else + throw s:Err(printf('unexpected token: %s', token.value), token.pos) + endif + else + let fallback = s:TRUE + break + endif + let token = self.tokenizer.get() + endwhile + if !fallback + let node.left = self.parse_expr1() + let token = self.tokenizer.get() + if token.type != s:TOKEN_CCLOSE + throw s:Err(printf('unexpected token: %s', token.value), token.pos) + endif + return node + endif + endif + " dict + let node = s:Node(s:NODE_DICT) + let node.pos = nodepos + let node.value = [] + call self.reader.seek_set(savepos) + let token = self.tokenizer.peek() + if token.type == s:TOKEN_CCLOSE + call self.tokenizer.get() + return node + endif + while 1 + let key = self.parse_expr1() + let token = self.tokenizer.get() + if token.type == s:TOKEN_CCLOSE + if !empty(node.value) + throw s:Err(printf('unexpected token: %s', token.value), token.pos) + endif + call self.reader.seek_set(pos) + let node = self.parse_identifier() + break + endif + if token.type != s:TOKEN_COLON + throw s:Err(printf('unexpected token: %s', token.value), token.pos) + endif + let val = self.parse_expr1() + call add(node.value, [key, val]) + let token = self.tokenizer.get() + if token.type == s:TOKEN_COMMA + if self.tokenizer.peek().type == s:TOKEN_CCLOSE + call self.tokenizer.get() + break + endif + elseif token.type == s:TOKEN_CCLOSE + break + else + throw s:Err(printf('unexpected token: %s', token.value), token.pos) + endif + endwhile + return node + elseif token.type == s:TOKEN_POPEN + let node = self.parse_expr1() + let token = self.tokenizer.get() + if token.type != s:TOKEN_PCLOSE + throw s:Err(printf('unexpected token: %s', token.value), token.pos) + endif + elseif token.type == s:TOKEN_OPTION + let node = s:Node(s:NODE_OPTION) + let node.pos = token.pos + let node.value = token.value + elseif token.type == s:TOKEN_IDENTIFIER + call self.reader.seek_set(pos) + let node = self.parse_identifier() + elseif s:FALSE && (token.type == s:TOKEN_COLON || token.type == s:TOKEN_SHARP) + " XXX: no parse error but invalid expression + call self.reader.seek_set(pos) + let node = self.parse_identifier() + elseif token.type == s:TOKEN_LT && self.reader.peekn(4) ==? 'SID>' + call self.reader.seek_set(pos) + let node = self.parse_identifier() + elseif token.type == s:TOKEN_IS || token.type == s:TOKEN_ISCS || token.type == s:TOKEN_ISNOT || token.type == s:TOKEN_ISNOTCS + call self.reader.seek_set(pos) + let node = self.parse_identifier() + elseif token.type == s:TOKEN_ENV + let node = s:Node(s:NODE_ENV) + let node.pos = token.pos + let node.value = token.value + elseif token.type == s:TOKEN_REG + let node = s:Node(s:NODE_REG) + let node.pos = token.pos + let node.value = token.value + else + throw s:Err(printf('unexpected token: %s', token.value), token.pos) + endif + return node +endfunction + +" SUBSCRIPT or CONCAT +" dict "." [0-9A-Za-z_]+ => (subscript dict key) +" str "." expr6 => (concat str expr6) +function! s:ExprParser.parse_dot(token, left) + if a:left.type != s:NODE_IDENTIFIER && a:left.type != s:NODE_CURLYNAME && a:left.type != s:NODE_DICT && a:left.type != s:NODE_SUBSCRIPT && a:left.type != s:NODE_CALL && a:left.type != s:NODE_DOT + return s:NIL + endif + if !s:iswordc(self.reader.p(0)) + return s:NIL + endif + let pos = self.reader.getpos() + let name = self.reader.read_word() + if s:isnamec(self.reader.p(0)) + " XXX: foo is str => ok, foo is obj => invalid expression + " foo.s:bar or foo.bar#baz + return s:NIL + endif + let node = s:Node(s:NODE_DOT) + let node.pos = a:token.pos + let node.left = a:left + let node.right = s:Node(s:NODE_IDENTIFIER) + let node.right.pos = pos + let node.right.value = name + return node +endfunction + +function! s:ExprParser.parse_identifier() + call self.reader.skip_white() + let npos = self.reader.getpos() + let curly_parts = self.parse_curly_parts() + if len(curly_parts) == 1 && curly_parts[0].type == s:NODE_CURLYNAMEPART + let node = s:Node(s:NODE_IDENTIFIER) + let node.pos = npos + let node.value = curly_parts[0].value + return node + else + let node = s:Node(s:NODE_CURLYNAME) + let node.pos = npos + let node.value = curly_parts + return node + endif +endfunction + +function! s:ExprParser.parse_curly_parts() + let curly_parts = [] + let c = self.reader.peek() + let pos = self.reader.getpos() + if c ==# '<' && self.reader.peekn(5) ==? '<SID>' + let name = self.reader.getn(5) + let node = s:Node(s:NODE_CURLYNAMEPART) + let node.curly = s:FALSE " Keep backword compatibility for the curly attribute + let node.pos = pos + let node.value = name + call add(curly_parts, node) + endif + while s:TRUE + let c = self.reader.peek() + if s:isnamec(c) + let pos = self.reader.getpos() + let name = self.reader.read_name() + let node = s:Node(s:NODE_CURLYNAMEPART) + let node.curly = s:FALSE " Keep backword compatibility for the curly attribute + let node.pos = pos + let node.value = name + call add(curly_parts, node) + elseif c ==# '{' + call self.reader.get() + let pos = self.reader.getpos() + let node = s:Node(s:NODE_CURLYNAMEEXPR) + let node.curly = s:TRUE " Keep backword compatibility for the curly attribute + let node.pos = pos + let node.value = self.parse_expr1() + call add(curly_parts, node) + call self.reader.skip_white() + let c = self.reader.p(0) + if c !=# '}' + throw s:Err(printf('unexpected token: %s', c), self.reader.getpos()) + endif + call self.reader.seek_cur(1) + else + break + endif + endwhile + return curly_parts +endfunction + +let s:LvalueParser = copy(s:ExprParser) + +function! s:LvalueParser.parse() + return self.parse_lv8() +endfunction + +" expr8: expr8[expr1] +" expr8[expr1 : expr1] +" expr8.name +function! s:LvalueParser.parse_lv8() + let left = self.parse_lv9() + while s:TRUE + let pos = self.reader.tell() + let c = self.reader.peek() + let token = self.tokenizer.get() + if !s:iswhite(c) && token.type == s:TOKEN_SQOPEN + let npos = token.pos + let node = s:Node(-1) + if self.tokenizer.peek().type == s:TOKEN_COLON + call self.tokenizer.get() + let node = s:Node(s:NODE_SLICE) + let node.pos = npos + let node.left = left + let node.rlist = [s:NIL, s:NIL] + let token = self.tokenizer.peek() + if token.type != s:TOKEN_SQCLOSE + let node.rlist[1] = self.parse_expr1() + endif + let token = self.tokenizer.get() + if token.type != s:TOKEN_SQCLOSE + throw s:Err(printf('unexpected token: %s', token.value), token.pos) + endif + else + let right = self.parse_expr1() + if self.tokenizer.peek().type == s:TOKEN_COLON + call self.tokenizer.get() + let node = s:Node(s:NODE_SLICE) + let node.pos = npos + let node.left = left + let node.rlist = [right, s:NIL] + let token = self.tokenizer.peek() + if token.type != s:TOKEN_SQCLOSE + let node.rlist[1] = self.parse_expr1() + endif + let token = self.tokenizer.get() + if token.type != s:TOKEN_SQCLOSE + throw s:Err(printf('unexpected token: %s', token.value), token.pos) + endif + else + let node = s:Node(s:NODE_SUBSCRIPT) + let node.pos = npos + let node.left = left + let node.right = right + let token = self.tokenizer.get() + if token.type != s:TOKEN_SQCLOSE + throw s:Err(printf('unexpected token: %s', token.value), token.pos) + endif + endif + endif + let left = node + unlet node + elseif !s:iswhite(c) && token.type == s:TOKEN_DOT + let node = self.parse_dot(token, left) + if node is s:NIL + call self.reader.seek_set(pos) + break + endif + let left = node + unlet node + else + call self.reader.seek_set(pos) + break + endif + endwhile + return left +endfunction + +" expr9: &option +" variable +" var{ria}ble +" $VAR +" @r +function! s:LvalueParser.parse_lv9() + let pos = self.reader.tell() + let token = self.tokenizer.get() + let node = s:Node(-1) + if token.type == s:TOKEN_COPEN + call self.reader.seek_set(pos) + let node = self.parse_identifier() + elseif token.type == s:TOKEN_OPTION + let node = s:Node(s:NODE_OPTION) + let node.pos = token.pos + let node.value = token.value + elseif token.type == s:TOKEN_IDENTIFIER + call self.reader.seek_set(pos) + let node = self.parse_identifier() + elseif token.type == s:TOKEN_LT && self.reader.peekn(4) ==? 'SID>' + call self.reader.seek_set(pos) + let node = self.parse_identifier() + elseif token.type == s:TOKEN_ENV + let node = s:Node(s:NODE_ENV) + let node.pos = token.pos + let node.value = token.value + elseif token.type == s:TOKEN_REG + let node = s:Node(s:NODE_REG) + let node.pos = token.pos + let node.pos = token.pos + let node.value = token.value + else + throw s:Err(printf('unexpected token: %s', token.value), token.pos) + endif + return node +endfunction + +let s:StringReader = {} + +function! s:StringReader.new(...) + let obj = copy(self) + call call(obj.__init__, a:000, obj) + return obj +endfunction + +function! s:StringReader.__init__(lines) + let self.buf = [] + let self.pos = [] + let lnum = 0 + let offset = 0 + while lnum < len(a:lines) + let col = 0 + for c in split(a:lines[lnum], '\zs') + call add(self.buf, c) + call add(self.pos, [lnum + 1, col + 1, offset]) + let col += len(c) + let offset += len(c) + endfor + while lnum + 1 < len(a:lines) && a:lines[lnum + 1] =~# '^\s*\\' + let skip = s:TRUE + let col = 0 + for c in split(a:lines[lnum + 1], '\zs') + if skip + if c == '\' + let skip = s:FALSE + endif + else + call add(self.buf, c) + call add(self.pos, [lnum + 2, col + 1, offset]) + endif + let col += len(c) + let offset += len(c) + endfor + let lnum += 1 + let offset += 1 + endwhile + call add(self.buf, '<EOL>') + call add(self.pos, [lnum + 1, col + 1, offset]) + let lnum += 1 + let offset += 1 + endwhile + " for <EOF> + call add(self.pos, [lnum + 1, 0, offset]) + let self.i = 0 +endfunction + +function! s:StringReader.eof() + return self.i >= len(self.buf) +endfunction + +function! s:StringReader.tell() + return self.i +endfunction + +function! s:StringReader.seek_set(i) + let self.i = a:i +endfunction + +function! s:StringReader.seek_cur(i) + let self.i = self.i + a:i +endfunction + +function! s:StringReader.seek_end(i) + let self.i = len(self.buf) + a:i +endfunction + +function! s:StringReader.p(i) + if self.i >= len(self.buf) + return '<EOF>' + endif + return self.buf[self.i + a:i] +endfunction + +function! s:StringReader.peek() + if self.i >= len(self.buf) + return '<EOF>' + endif + return self.buf[self.i] +endfunction + +function! s:StringReader.get() + if self.i >= len(self.buf) + return '<EOF>' + endif + let self.i += 1 + return self.buf[self.i - 1] +endfunction + +function! s:StringReader.peekn(n) + let pos = self.tell() + let r = self.getn(a:n) + call self.seek_set(pos) + return r +endfunction + +function! s:StringReader.getn(n) + let r = '' + let j = 0 + while self.i < len(self.buf) && (a:n < 0 || j < a:n) + let c = self.buf[self.i] + if c ==# '<EOL>' + break + endif + let r .= c + let self.i += 1 + let j += 1 + endwhile + return r +endfunction + +function! s:StringReader.peekline() + return self.peekn(-1) +endfunction + +function! s:StringReader.readline() + let r = self.getn(-1) + call self.get() + return r +endfunction + +function! s:StringReader.getstr(begin, end) + let r = '' + for i in range(a:begin.i, a:end.i - 1) + if i >= len(self.buf) + break + endif + let c = self.buf[i] + if c ==# '<EOL>' + let c = "\n" + endif + let r .= c + endfor + return r +endfunction + +function! s:StringReader.getpos() + let [lnum, col, offset] = self.pos[self.i] + return {'i': self.i, 'lnum': lnum, 'col': col, 'offset': offset} +endfunction + +function! s:StringReader.setpos(pos) + let self.i = a:pos.i +endfunction + +function! s:StringReader.read_alpha() + let r = '' + while s:isalpha(self.peekn(1)) + let r .= self.getn(1) + endwhile + return r +endfunction + +function! s:StringReader.read_alnum() + let r = '' + while s:isalnum(self.peekn(1)) + let r .= self.getn(1) + endwhile + return r +endfunction + +function! s:StringReader.read_digit() + let r = '' + while s:isdigit(self.peekn(1)) + let r .= self.getn(1) + endwhile + return r +endfunction + +function! s:StringReader.read_odigit() + let r = '' + while s:isodigit(self.peekn(1)) + let r .= self.getn(1) + endwhile + return r +endfunction + +function! s:StringReader.read_xdigit() + let r = '' + while s:isxdigit(self.peekn(1)) + let r .= self.getn(1) + endwhile + return r +endfunction + +function! s:StringReader.read_integer() + let r = '' + let c = self.peekn(1) + if c == '-' || c == '+' + let r = self.getn(1) + endif + return r . self.read_digit() +endfunction + +function! s:StringReader.read_word() + let r = '' + while s:iswordc(self.peekn(1)) + let r .= self.getn(1) + endwhile + return r +endfunction + +function! s:StringReader.read_white() + let r = '' + while s:iswhite(self.peekn(1)) + let r .= self.getn(1) + endwhile + return r +endfunction + +function! s:StringReader.read_nonwhite() + let r = '' + while !s:iswhite(self.peekn(1)) + let r .= self.getn(1) + endwhile + return r +endfunction + +function! s:StringReader.read_name() + let r = '' + while s:isnamec(self.peekn(1)) + let r .= self.getn(1) + endwhile + return r +endfunction + +function! s:StringReader.skip_white() + while s:iswhite(self.peekn(1)) + call self.seek_cur(1) + endwhile +endfunction + +function! s:StringReader.skip_white_and_colon() + while s:TRUE + let c = self.peekn(1) + if !s:iswhite(c) && c !=# ':' + break + endif + call self.seek_cur(1) + endwhile +endfunction + +let s:Compiler = {} + +function! s:Compiler.new(...) + let obj = copy(self) + call call(obj.__init__, a:000, obj) + return obj +endfunction + +function! s:Compiler.__init__() + let self.indent = [''] + let self.lines = [] +endfunction + +function! s:Compiler.out(...) + if len(a:000) == 1 + if a:000[0][0] ==# ')' + let self.lines[-1] .= a:000[0] + else + call add(self.lines, self.indent[0] . a:000[0]) + endif + else + call add(self.lines, self.indent[0] . call('printf', a:000)) + endif +endfunction + +function! s:Compiler.incindent(s) + call insert(self.indent, self.indent[0] . a:s) +endfunction + +function! s:Compiler.decindent() + call remove(self.indent, 0) +endfunction + +function! s:Compiler.compile(node) + if a:node.type == s:NODE_TOPLEVEL + return self.compile_toplevel(a:node) + elseif a:node.type == s:NODE_COMMENT + call self.compile_comment(a:node) + return s:NIL + elseif a:node.type == s:NODE_EXCMD + call self.compile_excmd(a:node) + return s:NIL + elseif a:node.type == s:NODE_FUNCTION + call self.compile_function(a:node) + return s:NIL + elseif a:node.type == s:NODE_DELFUNCTION + call self.compile_delfunction(a:node) + return s:NIL + elseif a:node.type == s:NODE_RETURN + call self.compile_return(a:node) + return s:NIL + elseif a:node.type == s:NODE_EXCALL + call self.compile_excall(a:node) + return s:NIL + elseif a:node.type == s:NODE_LET + call self.compile_let(a:node) + return s:NIL + elseif a:node.type == s:NODE_UNLET + call self.compile_unlet(a:node) + return s:NIL + elseif a:node.type == s:NODE_LOCKVAR + call self.compile_lockvar(a:node) + return s:NIL + elseif a:node.type == s:NODE_UNLOCKVAR + call self.compile_unlockvar(a:node) + return s:NIL + elseif a:node.type == s:NODE_IF + call self.compile_if(a:node) + return s:NIL + elseif a:node.type == s:NODE_WHILE + call self.compile_while(a:node) + return s:NIL + elseif a:node.type == s:NODE_FOR + call self.compile_for(a:node) + return s:NIL + elseif a:node.type == s:NODE_CONTINUE + call self.compile_continue(a:node) + return s:NIL + elseif a:node.type == s:NODE_BREAK + call self.compile_break(a:node) + return s:NIL + elseif a:node.type == s:NODE_TRY + call self.compile_try(a:node) + return s:NIL + elseif a:node.type == s:NODE_THROW + call self.compile_throw(a:node) + return s:NIL + elseif a:node.type == s:NODE_ECHO + call self.compile_echo(a:node) + return s:NIL + elseif a:node.type == s:NODE_ECHON + call self.compile_echon(a:node) + return s:NIL + elseif a:node.type == s:NODE_ECHOHL + call self.compile_echohl(a:node) + return s:NIL + elseif a:node.type == s:NODE_ECHOMSG + call self.compile_echomsg(a:node) + return s:NIL + elseif a:node.type == s:NODE_ECHOERR + call self.compile_echoerr(a:node) + return s:NIL + elseif a:node.type == s:NODE_EXECUTE + call self.compile_execute(a:node) + return s:NIL + elseif a:node.type == s:NODE_TERNARY + return self.compile_ternary(a:node) + elseif a:node.type == s:NODE_OR + return self.compile_or(a:node) + elseif a:node.type == s:NODE_AND + return self.compile_and(a:node) + elseif a:node.type == s:NODE_EQUAL + return self.compile_equal(a:node) + elseif a:node.type == s:NODE_EQUALCI + return self.compile_equalci(a:node) + elseif a:node.type == s:NODE_EQUALCS + return self.compile_equalcs(a:node) + elseif a:node.type == s:NODE_NEQUAL + return self.compile_nequal(a:node) + elseif a:node.type == s:NODE_NEQUALCI + return self.compile_nequalci(a:node) + elseif a:node.type == s:NODE_NEQUALCS + return self.compile_nequalcs(a:node) + elseif a:node.type == s:NODE_GREATER + return self.compile_greater(a:node) + elseif a:node.type == s:NODE_GREATERCI + return self.compile_greaterci(a:node) + elseif a:node.type == s:NODE_GREATERCS + return self.compile_greatercs(a:node) + elseif a:node.type == s:NODE_GEQUAL + return self.compile_gequal(a:node) + elseif a:node.type == s:NODE_GEQUALCI + return self.compile_gequalci(a:node) + elseif a:node.type == s:NODE_GEQUALCS + return self.compile_gequalcs(a:node) + elseif a:node.type == s:NODE_SMALLER + return self.compile_smaller(a:node) + elseif a:node.type == s:NODE_SMALLERCI + return self.compile_smallerci(a:node) + elseif a:node.type == s:NODE_SMALLERCS + return self.compile_smallercs(a:node) + elseif a:node.type == s:NODE_SEQUAL + return self.compile_sequal(a:node) + elseif a:node.type == s:NODE_SEQUALCI + return self.compile_sequalci(a:node) + elseif a:node.type == s:NODE_SEQUALCS + return self.compile_sequalcs(a:node) + elseif a:node.type == s:NODE_MATCH + return self.compile_match(a:node) + elseif a:node.type == s:NODE_MATCHCI + return self.compile_matchci(a:node) + elseif a:node.type == s:NODE_MATCHCS + return self.compile_matchcs(a:node) + elseif a:node.type == s:NODE_NOMATCH + return self.compile_nomatch(a:node) + elseif a:node.type == s:NODE_NOMATCHCI + return self.compile_nomatchci(a:node) + elseif a:node.type == s:NODE_NOMATCHCS + return self.compile_nomatchcs(a:node) + elseif a:node.type == s:NODE_IS + return self.compile_is(a:node) + elseif a:node.type == s:NODE_ISCI + return self.compile_isci(a:node) + elseif a:node.type == s:NODE_ISCS + return self.compile_iscs(a:node) + elseif a:node.type == s:NODE_ISNOT + return self.compile_isnot(a:node) + elseif a:node.type == s:NODE_ISNOTCI + return self.compile_isnotci(a:node) + elseif a:node.type == s:NODE_ISNOTCS + return self.compile_isnotcs(a:node) + elseif a:node.type == s:NODE_ADD + return self.compile_add(a:node) + elseif a:node.type == s:NODE_SUBTRACT + return self.compile_subtract(a:node) + elseif a:node.type == s:NODE_CONCAT + return self.compile_concat(a:node) + elseif a:node.type == s:NODE_MULTIPLY + return self.compile_multiply(a:node) + elseif a:node.type == s:NODE_DIVIDE + return self.compile_divide(a:node) + elseif a:node.type == s:NODE_REMAINDER + return self.compile_remainder(a:node) + elseif a:node.type == s:NODE_NOT + return self.compile_not(a:node) + elseif a:node.type == s:NODE_PLUS + return self.compile_plus(a:node) + elseif a:node.type == s:NODE_MINUS + return self.compile_minus(a:node) + elseif a:node.type == s:NODE_SUBSCRIPT + return self.compile_subscript(a:node) + elseif a:node.type == s:NODE_SLICE + return self.compile_slice(a:node) + elseif a:node.type == s:NODE_DOT + return self.compile_dot(a:node) + elseif a:node.type == s:NODE_CALL + return self.compile_call(a:node) + elseif a:node.type == s:NODE_NUMBER + return self.compile_number(a:node) + elseif a:node.type == s:NODE_STRING + return self.compile_string(a:node) + elseif a:node.type == s:NODE_LIST + return self.compile_list(a:node) + elseif a:node.type == s:NODE_DICT + return self.compile_dict(a:node) + elseif a:node.type == s:NODE_OPTION + return self.compile_option(a:node) + elseif a:node.type == s:NODE_IDENTIFIER + return self.compile_identifier(a:node) + elseif a:node.type == s:NODE_CURLYNAME + return self.compile_curlyname(a:node) + elseif a:node.type == s:NODE_ENV + return self.compile_env(a:node) + elseif a:node.type == s:NODE_REG + return self.compile_reg(a:node) + elseif a:node.type == s:NODE_CURLYNAMEPART + return self.compile_curlynamepart(a:node) + elseif a:node.type == s:NODE_CURLYNAMEEXPR + return self.compile_curlynameexpr(a:node) + elseif a:node.type == s:NODE_LAMBDA + return self.compile_lambda(a:node) + else + throw printf('Compiler: unknown node: %s', string(a:node)) + endif + return s:NIL +endfunction + +function! s:Compiler.compile_body(body) + for node in a:body + call self.compile(node) + endfor +endfunction + +function! s:Compiler.compile_toplevel(node) + call self.compile_body(a:node.body) + return self.lines +endfunction + +function! s:Compiler.compile_comment(node) + call self.out(';%s', a:node.str) +endfunction + +function! s:Compiler.compile_excmd(node) + call self.out('(excmd "%s")', escape(a:node.str, '\"')) +endfunction + +function! s:Compiler.compile_function(node) + let left = self.compile(a:node.left) + let rlist = map(a:node.rlist, 'self.compile(v:val)') + if !empty(rlist) && rlist[-1] ==# '...' + let rlist[-1] = '. ...' + endif + if empty(rlist) + call self.out('(function (%s)', left) + else + call self.out('(function (%s %s)', left, join(rlist, ' ')) + endif + call self.incindent(' ') + call self.compile_body(a:node.body) + call self.out(')') + call self.decindent() +endfunction + +function! s:Compiler.compile_delfunction(node) + call self.out('(delfunction %s)', self.compile(a:node.left)) +endfunction + +function! s:Compiler.compile_return(node) + if a:node.left is s:NIL + call self.out('(return)') + else + call self.out('(return %s)', self.compile(a:node.left)) + endif +endfunction + +function! s:Compiler.compile_excall(node) + call self.out('(call %s)', self.compile(a:node.left)) +endfunction + +function! s:Compiler.compile_let(node) + let left = '' + if a:node.left isnot s:NIL + let left = self.compile(a:node.left) + else + let left = join(map(a:node.list, 'self.compile(v:val)'), ' ') + if a:node.rest isnot s:NIL + let left .= ' . ' . self.compile(a:node.rest) + endif + let left = '(' . left . ')' + endif + let right = self.compile(a:node.right) + call self.out('(let %s %s %s)', a:node.op, left, right) +endfunction + +function! s:Compiler.compile_unlet(node) + let list = map(a:node.list, 'self.compile(v:val)') + call self.out('(unlet %s)', join(list, ' ')) +endfunction + +function! s:Compiler.compile_lockvar(node) + let list = map(a:node.list, 'self.compile(v:val)') + if a:node.depth is s:NIL + call self.out('(lockvar %s)', join(list, ' ')) + else + call self.out('(lockvar %s %s)', a:node.depth, join(list, ' ')) + endif +endfunction + +function! s:Compiler.compile_unlockvar(node) + let list = map(a:node.list, 'self.compile(v:val)') + if a:node.depth is s:NIL + call self.out('(unlockvar %s)', join(list, ' ')) + else + call self.out('(unlockvar %s %s)', a:node.depth, join(list, ' ')) + endif +endfunction + +function! s:Compiler.compile_if(node) + call self.out('(if %s', self.compile(a:node.cond)) + call self.incindent(' ') + call self.compile_body(a:node.body) + call self.decindent() + for enode in a:node.elseif + call self.out(' elseif %s', self.compile(enode.cond)) + call self.incindent(' ') + call self.compile_body(enode.body) + call self.decindent() + endfor + if a:node.else isnot s:NIL + call self.out(' else') + call self.incindent(' ') + call self.compile_body(a:node.else.body) + call self.decindent() + endif + call self.incindent(' ') + call self.out(')') + call self.decindent() +endfunction + +function! s:Compiler.compile_while(node) + call self.out('(while %s', self.compile(a:node.cond)) + call self.incindent(' ') + call self.compile_body(a:node.body) + call self.out(')') + call self.decindent() +endfunction + +function! s:Compiler.compile_for(node) + let left = '' + if a:node.left isnot s:NIL + let left = self.compile(a:node.left) + else + let left = join(map(a:node.list, 'self.compile(v:val)'), ' ') + if a:node.rest isnot s:NIL + let left .= ' . ' . self.compile(a:node.rest) + endif + let left = '(' . left . ')' + endif + let right = self.compile(a:node.right) + call self.out('(for %s %s', left, right) + call self.incindent(' ') + call self.compile_body(a:node.body) + call self.out(')') + call self.decindent() +endfunction + +function! s:Compiler.compile_continue(node) + call self.out('(continue)') +endfunction + +function! s:Compiler.compile_break(node) + call self.out('(break)') +endfunction + +function! s:Compiler.compile_try(node) + call self.out('(try') + call self.incindent(' ') + call self.compile_body(a:node.body) + for cnode in a:node.catch + if cnode.pattern isnot s:NIL + call self.decindent() + call self.out(' catch /%s/', cnode.pattern) + call self.incindent(' ') + call self.compile_body(cnode.body) + else + call self.decindent() + call self.out(' catch') + call self.incindent(' ') + call self.compile_body(cnode.body) + endif + endfor + if a:node.finally isnot s:NIL + call self.decindent() + call self.out(' finally') + call self.incindent(' ') + call self.compile_body(a:node.finally.body) + endif + call self.out(')') + call self.decindent() +endfunction + +function! s:Compiler.compile_throw(node) + call self.out('(throw %s)', self.compile(a:node.left)) +endfunction + +function! s:Compiler.compile_echo(node) + let list = map(a:node.list, 'self.compile(v:val)') + call self.out('(echo %s)', join(list, ' ')) +endfunction + +function! s:Compiler.compile_echon(node) + let list = map(a:node.list, 'self.compile(v:val)') + call self.out('(echon %s)', join(list, ' ')) +endfunction + +function! s:Compiler.compile_echohl(node) + call self.out('(echohl "%s")', escape(a:node.str, '\"')) +endfunction + +function! s:Compiler.compile_echomsg(node) + let list = map(a:node.list, 'self.compile(v:val)') + call self.out('(echomsg %s)', join(list, ' ')) +endfunction + +function! s:Compiler.compile_echoerr(node) + let list = map(a:node.list, 'self.compile(v:val)') + call self.out('(echoerr %s)', join(list, ' ')) +endfunction + +function! s:Compiler.compile_execute(node) + let list = map(a:node.list, 'self.compile(v:val)') + call self.out('(execute %s)', join(list, ' ')) +endfunction + +function! s:Compiler.compile_ternary(node) + return printf('(?: %s %s %s)', self.compile(a:node.cond), self.compile(a:node.left), self.compile(a:node.right)) +endfunction + +function! s:Compiler.compile_or(node) + return printf('(|| %s %s)', self.compile(a:node.left), self.compile(a:node.right)) +endfunction + +function! s:Compiler.compile_and(node) + return printf('(&& %s %s)', self.compile(a:node.left), self.compile(a:node.right)) +endfunction + +function! s:Compiler.compile_equal(node) + return printf('(== %s %s)', self.compile(a:node.left), self.compile(a:node.right)) +endfunction + +function! s:Compiler.compile_equalci(node) + return printf('(==? %s %s)', self.compile(a:node.left), self.compile(a:node.right)) +endfunction + +function! s:Compiler.compile_equalcs(node) + return printf('(==# %s %s)', self.compile(a:node.left), self.compile(a:node.right)) +endfunction + +function! s:Compiler.compile_nequal(node) + return printf('(!= %s %s)', self.compile(a:node.left), self.compile(a:node.right)) +endfunction + +function! s:Compiler.compile_nequalci(node) + return printf('(!=? %s %s)', self.compile(a:node.left), self.compile(a:node.right)) +endfunction + +function! s:Compiler.compile_nequalcs(node) + return printf('(!=# %s %s)', self.compile(a:node.left), self.compile(a:node.right)) +endfunction + +function! s:Compiler.compile_greater(node) + return printf('(> %s %s)', self.compile(a:node.left), self.compile(a:node.right)) +endfunction + +function! s:Compiler.compile_greaterci(node) + return printf('(>? %s %s)', self.compile(a:node.left), self.compile(a:node.right)) +endfunction + +function! s:Compiler.compile_greatercs(node) + return printf('(># %s %s)', self.compile(a:node.left), self.compile(a:node.right)) +endfunction + +function! s:Compiler.compile_gequal(node) + return printf('(>= %s %s)', self.compile(a:node.left), self.compile(a:node.right)) +endfunction + +function! s:Compiler.compile_gequalci(node) + return printf('(>=? %s %s)', self.compile(a:node.left), self.compile(a:node.right)) +endfunction + +function! s:Compiler.compile_gequalcs(node) + return printf('(>=# %s %s)', self.compile(a:node.left), self.compile(a:node.right)) +endfunction + +function! s:Compiler.compile_smaller(node) + return printf('(< %s %s)', self.compile(a:node.left), self.compile(a:node.right)) +endfunction + +function! s:Compiler.compile_smallerci(node) + return printf('(<? %s %s)', self.compile(a:node.left), self.compile(a:node.right)) +endfunction + +function! s:Compiler.compile_smallercs(node) + return printf('(<# %s %s)', self.compile(a:node.left), self.compile(a:node.right)) +endfunction + +function! s:Compiler.compile_sequal(node) + return printf('(<= %s %s)', self.compile(a:node.left), self.compile(a:node.right)) +endfunction + +function! s:Compiler.compile_sequalci(node) + return printf('(<=? %s %s)', self.compile(a:node.left), self.compile(a:node.right)) +endfunction + +function! s:Compiler.compile_sequalcs(node) + return printf('(<=# %s %s)', self.compile(a:node.left), self.compile(a:node.right)) +endfunction + +function! s:Compiler.compile_match(node) + return printf('(=~ %s %s)', self.compile(a:node.left), self.compile(a:node.right)) +endfunction + +function! s:Compiler.compile_matchci(node) + return printf('(=~? %s %s)', self.compile(a:node.left), self.compile(a:node.right)) +endfunction + +function! s:Compiler.compile_matchcs(node) + return printf('(=~# %s %s)', self.compile(a:node.left), self.compile(a:node.right)) +endfunction + +function! s:Compiler.compile_nomatch(node) + return printf('(!~ %s %s)', self.compile(a:node.left), self.compile(a:node.right)) +endfunction + +function! s:Compiler.compile_nomatchci(node) + return printf('(!~? %s %s)', self.compile(a:node.left), self.compile(a:node.right)) +endfunction + +function! s:Compiler.compile_nomatchcs(node) + return printf('(!~# %s %s)', self.compile(a:node.left), self.compile(a:node.right)) +endfunction + +function! s:Compiler.compile_is(node) + return printf('(is %s %s)', self.compile(a:node.left), self.compile(a:node.right)) +endfunction + +function! s:Compiler.compile_isci(node) + return printf('(is? %s %s)', self.compile(a:node.left), self.compile(a:node.right)) +endfunction + +function! s:Compiler.compile_iscs(node) + return printf('(is# %s %s)', self.compile(a:node.left), self.compile(a:node.right)) +endfunction + +function! s:Compiler.compile_isnot(node) + return printf('(isnot %s %s)', self.compile(a:node.left), self.compile(a:node.right)) +endfunction + +function! s:Compiler.compile_isnotci(node) + return printf('(isnot? %s %s)', self.compile(a:node.left), self.compile(a:node.right)) +endfunction + +function! s:Compiler.compile_isnotcs(node) + return printf('(isnot# %s %s)', self.compile(a:node.left), self.compile(a:node.right)) +endfunction + +function! s:Compiler.compile_add(node) + return printf('(+ %s %s)', self.compile(a:node.left), self.compile(a:node.right)) +endfunction + +function! s:Compiler.compile_subtract(node) + return printf('(- %s %s)', self.compile(a:node.left), self.compile(a:node.right)) +endfunction + +function! s:Compiler.compile_concat(node) + return printf('(concat %s %s)', self.compile(a:node.left), self.compile(a:node.right)) +endfunction + +function! s:Compiler.compile_multiply(node) + return printf('(* %s %s)', self.compile(a:node.left), self.compile(a:node.right)) +endfunction + +function! s:Compiler.compile_divide(node) + return printf('(/ %s %s)', self.compile(a:node.left), self.compile(a:node.right)) +endfunction + +function! s:Compiler.compile_remainder(node) + return printf('(%% %s %s)', self.compile(a:node.left), self.compile(a:node.right)) +endfunction + +function! s:Compiler.compile_not(node) + return printf('(! %s)', self.compile(a:node.left)) +endfunction + +function! s:Compiler.compile_plus(node) + return printf('(+ %s)', self.compile(a:node.left)) +endfunction + +function! s:Compiler.compile_minus(node) + return printf('(- %s)', self.compile(a:node.left)) +endfunction + +function! s:Compiler.compile_subscript(node) + return printf('(subscript %s %s)', self.compile(a:node.left), self.compile(a:node.right)) +endfunction + +function! s:Compiler.compile_slice(node) + let r0 = a:node.rlist[0] is s:NIL ? 'nil' : self.compile(a:node.rlist[0]) + let r1 = a:node.rlist[1] is s:NIL ? 'nil' : self.compile(a:node.rlist[1]) + return printf('(slice %s %s %s)', self.compile(a:node.left), r0, r1) +endfunction + +function! s:Compiler.compile_dot(node) + return printf('(dot %s %s)', self.compile(a:node.left), self.compile(a:node.right)) +endfunction + +function! s:Compiler.compile_call(node) + let rlist = map(a:node.rlist, 'self.compile(v:val)') + if empty(rlist) + return printf('(%s)', self.compile(a:node.left)) + else + return printf('(%s %s)', self.compile(a:node.left), join(rlist, ' ')) + endif +endfunction + +function! s:Compiler.compile_number(node) + return a:node.value +endfunction + +function! s:Compiler.compile_string(node) + return a:node.value +endfunction + +function! s:Compiler.compile_list(node) + let value = map(a:node.value, 'self.compile(v:val)') + if empty(value) + return '(list)' + else + return printf('(list %s)', join(value, ' ')) + endif +endfunction + +function! s:Compiler.compile_dict(node) + let value = map(a:node.value, '"(" . self.compile(v:val[0]) . " " . self.compile(v:val[1]) . ")"') + if empty(value) + return '(dict)' + else + return printf('(dict %s)', join(value, ' ')) + endif +endfunction + +function! s:Compiler.compile_option(node) + return a:node.value +endfunction + +function! s:Compiler.compile_identifier(node) + return a:node.value +endfunction + +function! s:Compiler.compile_curlyname(node) + return join(map(a:node.value, 'self.compile(v:val)'), '') +endfunction + +function! s:Compiler.compile_env(node) + return a:node.value +endfunction + +function! s:Compiler.compile_reg(node) + return a:node.value +endfunction + +function! s:Compiler.compile_curlynamepart(node) + return a:node.value +endfunction + +function! s:Compiler.compile_curlynameexpr(node) + return '{' . self.compile(a:node.value) . '}' +endfunction + +function! s:Compiler.compile_lambda(node) + let rlist = map(a:node.rlist, 'self.compile(v:val)') + return printf('(lambda (%s) %s)', join(rlist, ' '), self.compile(a:node.left)) +endfunction + +" TODO: under construction +let s:RegexpParser = {} + +let s:RegexpParser.RE_VERY_NOMAGIC = 1 +let s:RegexpParser.RE_NOMAGIC = 2 +let s:RegexpParser.RE_MAGIC = 3 +let s:RegexpParser.RE_VERY_MAGIC = 4 + +function! s:RegexpParser.new(...) + let obj = copy(self) + call call(obj.__init__, a:000, obj) + return obj +endfunction + +function! s:RegexpParser.__init__(reader, cmd, delim) + let self.reader = a:reader + let self.cmd = a:cmd + let self.delim = a:delim + let self.reg_magic = self.RE_MAGIC +endfunction + +function! s:RegexpParser.isend(c) + return a:c ==# '<EOF>' || a:c ==# '<EOL>' || a:c ==# self.delim +endfunction + +function! s:RegexpParser.parse_regexp() + let prevtoken = '' + let ntoken = '' + let ret = [] + if self.reader.peekn(4) ==# '\%#=' + let epos = self.reader.getpos() + let token = self.reader.getn(5) + if token !=# '\%#=0' && token !=# '\%#=1' && token !=# '\%#=2' + throw s:Err('E864: \%#= can only be followed by 0, 1, or 2', epos) + endif + call add(ret, token) + endif + while !self.isend(self.reader.peek()) + let prevtoken = ntoken + let [token, ntoken] = self.get_token() + if ntoken ==# '\m' + let self.reg_magic = self.RE_MAGIC + elseif ntoken ==# '\M' + let self.reg_magic = self.RE_NOMAGIC + elseif ntoken ==# '\v' + let self.reg_magic = self.RE_VERY_MAGIC + elseif ntoken ==# '\V' + let self.reg_magic = self.RE_VERY_NOMAGIC + elseif ntoken ==# '\*' + " '*' is not magic as the very first character. + if prevtoken ==# '' || prevtoken ==# '\^' || prevtoken ==# '\&' || prevtoken ==# '\|' || prevtoken ==# '\(' + let ntoken = '*' + endif + elseif ntoken ==# '\^' + " '^' is only magic as the very first character. + if self.reg_magic != self.RE_VERY_MAGIC && prevtoken !=# '' && prevtoken !=# '\&' && prevtoken !=# '\|' && prevtoken !=# '\n' && prevtoken !=# '\(' && prevtoken !=# '\%(' + let ntoken = '^' + endif + elseif ntoken ==# '\$' + " '$' is only magic as the very last character + let pos = self.reader.tell() + if self.reg_magic != self.RE_VERY_MAGIC + while !self.isend(self.reader.peek()) + let [t, n] = self.get_token() + " XXX: Vim doesn't check \v and \V? + if n ==# '\c' || n ==# '\C' || n ==# '\m' || n ==# '\M' || n ==# '\Z' + continue + endif + if n !=# '\|' && n !=# '\&' && n !=# '\n' && n !=# '\)' + let ntoken = '$' + endif + break + endwhile + endif + call self.reader.seek_set(pos) + elseif ntoken ==# '\?' + " '?' is literal in '?' command. + if self.cmd ==# '?' + let ntoken = '?' + endif + endif + call add(ret, ntoken) + endwhile + return ret +endfunction + +" @return [actual_token, normalized_token] +function! s:RegexpParser.get_token() + if self.reg_magic == self.RE_VERY_MAGIC + return self.get_token_very_magic() + elseif self.reg_magic == self.RE_MAGIC + return self.get_token_magic() + elseif self.reg_magic == self.RE_NOMAGIC + return self.get_token_nomagic() + elseif self.reg_magic == self.RE_VERY_NOMAGIC + return self.get_token_very_nomagic() + endif +endfunction + +function! s:RegexpParser.get_token_very_magic() + if self.isend(self.reader.peek()) + return ['<END>', '<END>'] + endif + let c = self.reader.get() + if c ==# '\' + return self.get_token_backslash_common() + elseif c ==# '*' + return ['*', '\*'] + elseif c ==# '+' + return ['+', '\+'] + elseif c ==# '=' + return ['=', '\='] + elseif c ==# '?' + return ['?', '\?'] + elseif c ==# '{' + return self.get_token_brace('{') + elseif c ==# '@' + return self.get_token_at('@') + elseif c ==# '^' + return ['^', '\^'] + elseif c ==# '$' + return ['$', '\$'] + elseif c ==# '.' + return ['.', '\.'] + elseif c ==# '<' + return ['<', '\<'] + elseif c ==# '>' + return ['>', '\>'] + elseif c ==# '%' + return self.get_token_percent('%') + elseif c ==# '[' + return self.get_token_sq('[') + elseif c ==# '~' + return ['~', '\~'] + elseif c ==# '|' + return ['|', '\|'] + elseif c ==# '&' + return ['&', '\&'] + elseif c ==# '(' + return ['(', '\('] + elseif c ==# ')' + return [')', '\)'] + endif + return [c, c] +endfunction + +function! s:RegexpParser.get_token_magic() + if self.isend(self.reader.peek()) + return ['<END>', '<END>'] + endif + let c = self.reader.get() + if c ==# '\' + let pos = self.reader.tell() + let c = self.reader.get() + if c ==# '+' + return ['\+', '\+'] + elseif c ==# '=' + return ['\=', '\='] + elseif c ==# '?' + return ['\?', '\?'] + elseif c ==# '{' + return self.get_token_brace('\{') + elseif c ==# '@' + return self.get_token_at('\@') + elseif c ==# '<' + return ['\<', '\<'] + elseif c ==# '>' + return ['\>', '\>'] + elseif c ==# '%' + return self.get_token_percent('\%') + elseif c ==# '|' + return ['\|', '\|'] + elseif c ==# '&' + return ['\&', '\&'] + elseif c ==# '(' + return ['\(', '\('] + elseif c ==# ')' + return ['\)', '\)'] + endif + call self.reader.seek_set(pos) + return self.get_token_backslash_common() + elseif c ==# '*' + return ['*', '\*'] + elseif c ==# '^' + return ['^', '\^'] + elseif c ==# '$' + return ['$', '\$'] + elseif c ==# '.' + return ['.', '\.'] + elseif c ==# '[' + return self.get_token_sq('[') + elseif c ==# '~' + return ['~', '\~'] + endif + return [c, c] +endfunction + +function! s:RegexpParser.get_token_nomagic() + if self.isend(self.reader.peek()) + return ['<END>', '<END>'] + endif + let c = self.reader.get() + if c ==# '\' + let pos = self.reader.tell() + let c = self.reader.get() + if c ==# '*' + return ['\*', '\*'] + elseif c ==# '+' + return ['\+', '\+'] + elseif c ==# '=' + return ['\=', '\='] + elseif c ==# '?' + return ['\?', '\?'] + elseif c ==# '{' + return self.get_token_brace('\{') + elseif c ==# '@' + return self.get_token_at('\@') + elseif c ==# '.' + return ['\.', '\.'] + elseif c ==# '<' + return ['\<', '\<'] + elseif c ==# '>' + return ['\>', '\>'] + elseif c ==# '%' + return self.get_token_percent('\%') + elseif c ==# '~' + return ['\~', '\^'] + elseif c ==# '[' + return self.get_token_sq('\[') + elseif c ==# '|' + return ['\|', '\|'] + elseif c ==# '&' + return ['\&', '\&'] + elseif c ==# '(' + return ['\(', '\('] + elseif c ==# ')' + return ['\)', '\)'] + endif + call self.reader.seek_set(pos) + return self.get_token_backslash_common() + elseif c ==# '^' + return ['^', '\^'] + elseif c ==# '$' + return ['$', '\$'] + endif + return [c, c] +endfunction + +function! s:RegexpParser.get_token_very_nomagic() + if self.isend(self.reader.peek()) + return ['<END>', '<END>'] + endif + let c = self.reader.get() + if c ==# '\' + let pos = self.reader.tell() + let c = self.reader.get() + if c ==# '*' + return ['\*', '\*'] + elseif c ==# '+' + return ['\+', '\+'] + elseif c ==# '=' + return ['\=', '\='] + elseif c ==# '?' + return ['\?', '\?'] + elseif c ==# '{' + return self.get_token_brace('\{') + elseif c ==# '@' + return self.get_token_at('\@') + elseif c ==# '^' + return ['\^', '\^'] + elseif c ==# '$' + return ['\$', '\$'] + elseif c ==# '<' + return ['\<', '\<'] + elseif c ==# '>' + return ['\>', '\>'] + elseif c ==# '%' + return self.get_token_percent('\%') + elseif c ==# '~' + return ['\~', '\~'] + elseif c ==# '[' + return self.get_token_sq('\[') + elseif c ==# '|' + return ['\|', '\|'] + elseif c ==# '&' + return ['\&', '\&'] + elseif c ==# '(' + return ['\(', '\('] + elseif c ==# ')' + return ['\)', '\)'] + endif + call self.reader.seek_set(pos) + return self.get_token_backslash_common() + endif + return [c, c] +endfunction + +function! s:RegexpParser.get_token_backslash_common() + let cclass = 'iIkKfFpPsSdDxXoOwWhHaAlLuU' + let c = self.reader.get() + if c ==# '\' + return ['\\', '\\'] + elseif stridx(cclass, c) != -1 + return ['\' . c, '\' . c] + elseif c == '_' + let epos = self.reader.getpos() + let c = self.reader.get() + if stridx(cclass, c) != -1 + return ['\_' . c, '\_ . c'] + elseif c ==# '^' + return ['\_^', '\_^'] + elseif c ==# '$' + return ['\_$', '\_$'] + elseif c ==# '.' + return ['\_.', '\_.'] + elseif c ==# '[' + return self.get_token_sq('\_[') + endif + throw s:Err('E63: invalid use of \_', epos) + elseif stridx('etrb', c) != -1 + return ['\' . c, '\' . c] + elseif stridx('123456789', c) != -1 + return ['\' . c, '\' . c] + elseif c == 'z' + let epos = self.reader.getpos() + let c = self.reader.get() + if stridx('123456789', c) != -1 + return ['\z' . c, '\z' . c] + elseif c ==# 's' + return ['\zs', '\zs'] + elseif c ==# 'e' + return ['\ze', '\ze'] + elseif c ==# '(' + return ['\z(', '\z('] + endif + throw s:Err('E68: Invalid character after \z', epos) + elseif stridx('cCmMvVZ', c) != -1 + return ['\' . c, '\' . c] + elseif c == '%' + let epos = self.reader.getpos() + let c = self.reader.get() + if c ==# 'd' + let r = self.getdecchrs() + if r !=# '' + return ['\%d' . r, '\%d' . r] + endif + elseif c ==# 'o' + let r = self.getoctchrs() + if r !=# '' + return ['\%o' . r, '\%o' . r] + endif + elseif c ==# 'x' + let r = self.gethexchrs(2) + if r !=# '' + return ['\%x' . r, '\%x' . r] + endif + elseif c ==# 'u' + let r = self.gethexchrs(4) + if r !=# '' + return ['\%u' . r, '\%u' . r] + endif + elseif c ==# 'U' + let r = self.gethexchrs(8) + if r !=# '' + return ['\%U' . r, '\%U' . r] + endif + endif + throw s:Err('E678: Invalid character after \%[dxouU]', epos) + endif + return ['\' . c, c] +endfunction + +" \{} +function! s:RegexpParser.get_token_brace(pre) + let r = '' + let minus = '' + let comma = '' + let n = '' + let m = '' + if self.reader.p(0) ==# '-' + let minus = self.reader.get() + let r .= minus + endif + if s:isdigit(self.reader.p(0)) + let n = self.reader.read_digit() + let r .= n + endif + if self.reader.p(0) ==# ',' + let comma = self.rader.get() + let r .= comma + endif + if s:isdigit(self.reader.p(0)) + let m = self.reader.read_digit() + let r .= m + endif + if self.reader.p(0) ==# '\' + let r .= self.reader.get() + endif + if self.reader.p(0) !=# '}' + throw s:Err('E554: Syntax error in \{...}', self.reader.getpos()) + endif + call self.reader.get() + return [a:pre . r, '\{' . minus . n . comma . m . '}'] +endfunction + +" \[] +function! s:RegexpParser.get_token_sq(pre) + let start = self.reader.tell() + let r = '' + " Complement of range + if self.reader.p(0) ==# '^' + let r .= self.reader.get() + endif + " At the start ']' and '-' mean the literal character. + if self.reader.p(0) ==# ']' || self.reader.p(0) ==# '-' + let r .= self.reader.get() + endif + while s:TRUE + let startc = 0 + let c = self.reader.p(0) + if self.isend(c) + " If there is no matching ']', we assume the '[' is a normal character. + call self.reader.seek_set(start) + return [a:pre, '['] + elseif c ==# ']' + call self.reader.seek_cur(1) + return [a:pre . r . ']', '\[' . r . ']'] + elseif c ==# '[' + let e = self.get_token_sq_char_class() + if e ==# '' + let e = self.get_token_sq_equi_class() + if e ==# '' + let e = self.get_token_sq_coll_element() + if e ==# '' + let [e, startc] = self.get_token_sq_c() + endif + endif + endif + let r .= e + else + let [e, startc] = self.get_token_sq_c() + let r .= e + endif + if startc != 0 && self.reader.p(0) ==# '-' && !self.isend(self.reader.p(1)) && !(self.reader.p(1) ==# '\' && self.reader.p(2) ==# 'n') + call self.reader.seek_cur(1) + let r .= '-' + let c = self.reader.p(0) + if c ==# '[' + let e = self.get_token_sq_coll_element() + if e !=# '' + let endc = char2nr(e[2]) + else + let [e, endc] = self.get_token_sq_c() + endif + let r .= e + else + let [e, endc] = self.get_token_sq_c() + let r .= e + endif + if startc > endc || endc > startc + 256 + throw s:Err('E16: Invalid range', self.reader.getpos()) + endif + endif + endwhile +endfunction + +" [c] +function! s:RegexpParser.get_token_sq_c() + let c = self.reader.p(0) + if c ==# '\' + call self.reader.seek_cur(1) + let c = self.reader.p(0) + if c ==# 'n' + call self.reader.seek_cur(1) + return ['\n', 0] + elseif c ==# 'r' + call self.reader.seek_cur(1) + return ['\r', char2nr("\r")] + elseif c ==# 't' + call self.reader.seek_cur(1) + return ['\t', char2nr("\t")] + elseif c ==# 'e' + call self.reader.seek_cur(1) + return ['\e', char2nr("\e")] + elseif c ==# 'b' + call self.reader.seek_cur(1) + return ['\b', char2nr("\b")] + elseif stridx(']^-\', c) != -1 + call self.reader.seek_cur(1) + return ['\' . c, char2nr(c)] + elseif stridx('doxuU', c) != -1 + let [c, n] = self.get_token_sq_coll_char() + return [c, n] + else + return ['\', char2nr('\')] + endif + elseif c ==# '-' + call self.reader.seek_cur(1) + return ['-', char2nr('-')] + else + call self.reader.seek_cur(1) + return [c, char2nr(c)] + endif +endfunction + +" [\d123] +function! s:RegexpParser.get_token_sq_coll_char() + let pos = self.reader.tell() + let c = self.reader.get() + if c ==# 'd' + let r = self.getdecchrs() + let n = str2nr(r, 10) + elseif c ==# 'o' + let r = self.getoctchrs() + let n = str2nr(r, 8) + elseif c ==# 'x' + let r = self.gethexchrs(2) + let n = str2nr(r, 16) + elseif c ==# 'u' + let r = self.gethexchrs(4) + let n = str2nr(r, 16) + elseif c ==# 'U' + let r = self.gethexchrs(8) + let n = str2nr(r, 16) + else + let r = '' + endif + if r ==# '' + call self.reader.seek_set(pos) + return '\' + endif + return ['\' . c . r, n] +endfunction + +" [[.a.]] +function! s:RegexpParser.get_token_sq_coll_element() + if self.reader.p(0) ==# '[' && self.reader.p(1) ==# '.' && !self.isend(self.reader.p(2)) && self.reader.p(3) ==# '.' && self.reader.p(4) ==# ']' + return self.reader.getn(5) + endif + return '' +endfunction + +" [[=a=]] +function! s:RegexpParser.get_token_sq_equi_class() + if self.reader.p(0) ==# '[' && self.reader.p(1) ==# '=' && !self.isend(self.reader.p(2)) && self.reader.p(3) ==# '=' && self.reader.p(4) ==# ']' + return self.reader.getn(5) + endif + return '' +endfunction + +" [[:alpha:]] +function! s:RegexpParser.get_token_sq_char_class() + let class_names = ["alnum", "alpha", "blank", "cntrl", "digit", "graph", "lower", "print", "punct", "space", "upper", "xdigit", "tab", "return", "backspace", "escape"] + let pos = self.reader.tell() + if self.reader.p(0) ==# '[' && self.reader.p(1) ==# ':' + call self.reader.seek_cur(2) + let r = self.reader.read_alpha() + if self.reader.p(0) ==# ':' && self.reader.p(1) ==# ']' + call self.reader.seek_cur(2) + for name in class_names + if r ==# name + return '[:' . name . ':]' + endif + endfor + endif + endif + call self.reader.seek_set(pos) + return '' +endfunction + +" \@... +function! s:RegexpParser.get_token_at(pre) + let epos = self.reader.getpos() + let c = self.reader.get() + if c ==# '>' + return [a:pre . '>', '\@>'] + elseif c ==# '=' + return [a:pre . '=', '\@='] + elseif c ==# '!' + return [a:pre . '!', '\@!'] + elseif c ==# '<' + let c = self.reader.get() + if c ==# '=' + return [a:pre . '<=', '\@<='] + elseif c ==# '!' + return [a:pre . '<!', '\@<!'] + endif + endif + throw s:Err('E64: @ follows nothing', epos) +endfunction + +" \%... +function! s:RegexpParser.get_token_percent(pre) + let c = self.reader.get() + if c ==# '^' + return [a:pre . '^', '\%^'] + elseif c ==# '$' + return [a:pre . '$', '\%$'] + elseif c ==# 'V' + return [a:pre . 'V', '\%V'] + elseif c ==# '#' + return [a:pre . '#', '\%#'] + elseif c ==# '[' + return self.get_token_percent_sq(a:pre . '[') + elseif c ==# '(' + return [a:pre . '(', '\%('] + else + return self.get_token_mlcv(a:pre) + endif +endfunction + +" \%[] +function! s:RegexpParser.get_token_percent_sq(pre) + let r = '' + while s:TRUE + let c = self.reader.peek() + if self.isend(c) + throw s:Err('E69: Missing ] after \%[', self.reader.getpos()) + elseif c ==# ']' + if r ==# '' + throw s:Err('E70: Empty \%[', self.reader.getpos()) + endif + call self.reader.seek_cur(1) + break + endif + call self.reader.seek_cur(1) + let r .= c + endwhile + return [a:pre . r . ']', '\%[' . r . ']'] +endfunction + +" \%'m \%l \%c \%v +function! s:RegexpParser.get_token_mlvc(pre) + let r = '' + let cmp = '' + if self.reader.p(0) ==# '<' || self.reader.p(0) ==# '>' + let cmp = self.reader.get() + let r .= cmp + endif + if self.reader.p(0) ==# "'" + let r .= self.reader.get() + let c = self.reader.p(0) + if self.isend(c) + " FIXME: Should be error? Vim allow this. + let c = '' + else + let c = self.reader.get() + endif + return [a:pre . r . c, '\%' . cmp . "'" . c] + elseif s:isdigit(self.reader.p(0)) + let d = self.reader.read_digit() + let r .= d + let c = self.reader.p(0) + if c ==# 'l' + call self.reader.get() + return [a:pre . r . 'l', '\%' . cmp . d . 'l'] + elseif c ==# 'c' + call self.reader.get() + return [a:pre . r . 'c', '\%' . cmp . d . 'c'] + elseif c ==# 'v' + call self.reader.get() + return [a:pre . r . 'v', '\%' . cmp . d . 'v'] + endif + endif + throw s:Err('E71: Invalid character after %', self.reader.getpos()) +endfunction + +function! s:RegexpParser.getdecchrs() + return self.reader.read_digit() +endfunction + +function! s:RegexpParser.getoctchrs() + return self.reader.read_odigit() +endfunction + +function! s:RegexpParser.gethexchrs(n) + let r = '' + for i in range(a:n) + let c = self.reader.peek() + if !s:isxdigit(c) + break + endif + let r .= self.reader.get() + endfor + return r +endfunction + diff --git a/autoload/vital/_vimlparser.vim b/autoload/vital/_vimlparser.vim new file mode 100644 index 00000000..55104952 --- /dev/null +++ b/autoload/vital/_vimlparser.vim @@ -0,0 +1,9 @@ +let s:_plugin_name = expand('<sfile>:t:r') + +function! vital#{s:_plugin_name}#new() abort + return vital#{s:_plugin_name[1:]}#new() +endfunction + +function! vital#{s:_plugin_name}#function(funcname) abort + silent! return function(a:funcname) +endfunction diff --git a/autoload/vital/vimlparser.vim b/autoload/vital/vimlparser.vim new file mode 100644 index 00000000..b622a97e --- /dev/null +++ b/autoload/vital/vimlparser.vim @@ -0,0 +1,328 @@ +let s:plugin_name = expand('<sfile>:t:r') +let s:vital_base_dir = expand('<sfile>:h') +let s:project_root = expand('<sfile>:h:h:h') +let s:is_vital_vim = s:plugin_name is# 'vital' + +let s:loaded = {} +let s:cache_sid = {} + +" function() wrapper +if v:version > 703 || v:version == 703 && has('patch1170') + function! s:_function(fstr) abort + return function(a:fstr) + endfunction +else + function! s:_SID() abort + return matchstr(expand('<sfile>'), '<SNR>\zs\d\+\ze__SID$') + endfunction + let s:_s = '<SNR>' . s:_SID() . '_' + function! s:_function(fstr) abort + return function(substitute(a:fstr, 's:', s:_s, 'g')) + endfunction +endif + +function! vital#{s:plugin_name}#new() abort + return s:new(s:plugin_name) +endfunction + +function! vital#{s:plugin_name}#import(...) abort + if !exists('s:V') + let s:V = s:new(s:plugin_name) + endif + return call(s:V.import, a:000, s:V) +endfunction + +let s:Vital = {} + +function! s:new(plugin_name) abort + let base = deepcopy(s:Vital) + let base._plugin_name = a:plugin_name + return base +endfunction + +function! s:vital_files() abort + if !exists('s:vital_files') + let s:vital_files = map( + \ s:is_vital_vim ? s:_global_vital_files() : s:_self_vital_files(), + \ 'fnamemodify(v:val, ":p:gs?[\\\\/]?/?")') + endif + return copy(s:vital_files) +endfunction +let s:Vital.vital_files = s:_function('s:vital_files') + +function! s:import(name, ...) abort dict + let target = {} + let functions = [] + for a in a:000 + if type(a) == type({}) + let target = a + elseif type(a) == type([]) + let functions = a + endif + unlet a + endfor + let module = self._import(a:name) + if empty(functions) + call extend(target, module, 'keep') + else + for f in functions + if has_key(module, f) && !has_key(target, f) + let target[f] = module[f] + endif + endfor + endif + return target +endfunction +let s:Vital.import = s:_function('s:import') + +function! s:load(...) abort dict + for arg in a:000 + let [name; as] = type(arg) == type([]) ? arg[: 1] : [arg, arg] + let target = split(join(as, ''), '\W\+') + let dict = self + let dict_type = type({}) + while !empty(target) + let ns = remove(target, 0) + if !has_key(dict, ns) + let dict[ns] = {} + endif + if type(dict[ns]) == dict_type + let dict = dict[ns] + else + unlet dict + break + endif + endwhile + if exists('dict') + call extend(dict, self._import(name)) + endif + unlet arg + endfor + return self +endfunction +let s:Vital.load = s:_function('s:load') + +function! s:unload() abort dict + let s:loaded = {} + let s:cache_sid = {} + unlet! s:vital_files +endfunction +let s:Vital.unload = s:_function('s:unload') + +function! s:exists(name) abort dict + if a:name !~# '\v^\u\w*%(\.\u\w*)*$' + throw 'vital: Invalid module name: ' . a:name + endif + return s:_module_path(a:name) isnot# '' +endfunction +let s:Vital.exists = s:_function('s:exists') + +function! s:search(pattern) abort dict + let paths = s:_extract_files(a:pattern, self.vital_files()) + let modules = sort(map(paths, 's:_file2module(v:val)')) + return s:_uniq(modules) +endfunction +let s:Vital.search = s:_function('s:search') + +function! s:plugin_name() abort dict + return self._plugin_name +endfunction +let s:Vital.plugin_name = s:_function('s:plugin_name') + +function! s:_self_vital_files() abort + let builtin = printf('%s/__%s__/', s:vital_base_dir, s:plugin_name) + let installed = printf('%s/_%s/', s:vital_base_dir, s:plugin_name) + let base = builtin . ',' . installed + return split(globpath(base, '**/*.vim', 1), "\n") +endfunction + +function! s:_global_vital_files() abort + let pattern = 'autoload/vital/__*__/**/*.vim' + return split(globpath(&runtimepath, pattern, 1), "\n") +endfunction + +function! s:_extract_files(pattern, files) abort + let tr = {'.': '/', '*': '[^/]*', '**': '.*'} + let target = substitute(a:pattern, '\.\|\*\*\?', '\=tr[submatch(0)]', 'g') + let regexp = printf('autoload/vital/[^/]\+/%s.vim$', target) + return filter(a:files, 'v:val =~# regexp') +endfunction + +function! s:_file2module(file) abort + let filename = fnamemodify(a:file, ':p:gs?[\\/]?/?') + let tail = matchstr(filename, 'autoload/vital/_\w\+/\zs.*\ze\.vim$') + return join(split(tail, '[\\/]\+'), '.') +endfunction + +" @param {string} name e.g. Data.List +function! s:_import(name) abort dict + if has_key(s:loaded, a:name) + return copy(s:loaded[a:name]) + endif + let module = self._get_module(a:name) + if has_key(module, '_vital_created') + call module._vital_created(module) + endif + let export_module = filter(copy(module), 'v:key =~# "^\\a"') + " Cache module before calling module.vital_loaded() to avoid cyclic + " dependences but remove the cache if module._vital_loaded() fails. + " let s:loaded[a:name] = export_module + let s:loaded[a:name] = export_module + if has_key(module, '_vital_loaded') + try + call module._vital_loaded(vital#{s:plugin_name}#new()) + catch + unlet s:loaded[a:name] + throw 'vital: fail to call ._vital_loaded(): ' . v:exception + endtry + endif + return copy(s:loaded[a:name]) +endfunction +let s:Vital._import = s:_function('s:_import') + +" s:_get_module() returns module object wihch has all script local functions. +function! s:_get_module(name) abort dict + let funcname = s:_import_func_name(self.plugin_name(), a:name) + try + return call(funcname, []) + catch /^Vim\%((\a\+)\)\?:E117/ + return s:_get_builtin_module(a:name) + endtry +endfunction + +function! s:_get_builtin_module(name) abort + return s:sid2sfuncs(s:_module_sid(a:name)) +endfunction + +if s:is_vital_vim + " For vital.vim, we can use s:_get_builtin_module directly + let s:Vital._get_module = s:_function('s:_get_builtin_module') +else + let s:Vital._get_module = s:_function('s:_get_module') +endif + +function! s:_import_func_name(plugin_name, module_name) abort + return printf('vital#_%s#%s#import', a:plugin_name, s:_dot_to_sharp(a:module_name)) +endfunction + +function! s:_module_sid(name) abort + let path = s:_module_path(a:name) + if !filereadable(path) + throw 'vital: module not found: ' . a:name + endif + let vital_dir = s:is_vital_vim ? '__\w\+__' : printf('_\{1,2}%s\%%(__\)\?', s:plugin_name) + let base = join([vital_dir, ''], '[/\\]\+') + let p = base . substitute('' . a:name, '\.', '[/\\\\]\\+', 'g') + let sid = s:_sid(path, p) + if !sid + call s:_source(path) + let sid = s:_sid(path, p) + if !sid + throw printf('vital: cannot get <SID> from path: %s', path) + endif + endif + return sid +endfunction + +function! s:_module_path(name) abort + return get(s:_extract_files(a:name, s:vital_files()), 0, '') +endfunction + +function! s:_module_sid_base_dir() abort + return s:is_vital_vim ? &rtp : s:project_root +endfunction + +function! s:_dot_to_sharp(name) abort + return substitute(a:name, '\.', '#', 'g') +endfunction + +function! s:_source(path) abort + execute 'source' fnameescape(a:path) +endfunction + +" @vimlint(EVL102, 1, l:_) +" @vimlint(EVL102, 1, l:__) +function! s:_sid(path, filter_pattern) abort + let unified_path = s:_unify_path(a:path) + if has_key(s:cache_sid, unified_path) + return s:cache_sid[unified_path] + endif + for line in filter(split(s:_execute(':scriptnames'), "\n"), 'v:val =~# a:filter_pattern') + let [_, sid, path; __] = matchlist(line, '^\s*\(\d\+\):\s\+\(.\+\)\s*$') + if s:_unify_path(path) is# unified_path + let s:cache_sid[unified_path] = sid + return s:cache_sid[unified_path] + endif + endfor + return 0 +endfunction + +" A bug of execute() is fixed in Vim 8.0.0264 +if has('patch-8.0.0264') + let s:_execute = function('execute') +else + function! s:_execute(cmd) abort + let [save_verbose, save_verbosefile] = [&verbose, &verbosefile] + set verbose=0 verbosefile= + redir => res + silent! execute a:cmd + redir END + let [&verbose, &verbosefile] = [save_verbose, save_verbosefile] + return res + endfunction +endif + +if filereadable(expand('<sfile>:r') . '.VIM') " is case-insensitive or not + let s:_unify_path_cache = {} + " resolve() is slow, so we cache results. + " Note: On windows, vim can't expand path names from 8.3 formats. + " So if getting full path via <sfile> and $HOME was set as 8.3 format, + " vital load duplicated scripts. Below's :~ avoid this issue. + function! s:_unify_path(path) abort + if has_key(s:_unify_path_cache, a:path) + return s:_unify_path_cache[a:path] + endif + let value = tolower(fnamemodify(resolve(fnamemodify( + \ a:path, ':p')), ':~:gs?[\\/]?/?')) + let s:_unify_path_cache[a:path] = value + return value + endfunction +else + function! s:_unify_path(path) abort + return resolve(fnamemodify(a:path, ':p:gs?[\\/]?/?')) + endfunction +endif + +" copied and modified from Vim.ScriptLocal +let s:SNR = join(map(range(len("\<SNR>")), '"[\\x" . printf("%0x", char2nr("\<SNR>"[v:val])) . "]"'), '') +function! s:sid2sfuncs(sid) abort + let fs = split(s:_execute(printf(':function /^%s%s_', s:SNR, a:sid)), "\n") + let r = {} + let pattern = printf('\m^function\s<SNR>%d_\zs\w\{-}\ze(', a:sid) + for fname in map(fs, 'matchstr(v:val, pattern)') + let r[fname] = function(s:_sfuncname(a:sid, fname)) + endfor + return r +endfunction + +"" Return funcname of script local functions with SID +function! s:_sfuncname(sid, funcname) abort + return printf('<SNR>%s_%s', a:sid, a:funcname) +endfunction + +if exists('*uniq') + function! s:_uniq(list) abort + return uniq(a:list) + endfunction +else + function! s:_uniq(list) abort + let i = len(a:list) - 1 + while 0 < i + if a:list[i] ==# a:list[i - 1] + call remove(a:list, i) + endif + let i -= 1 + endwhile + return a:list + endfunction +endif diff --git a/autoload/vital/vimlparser.vital b/autoload/vital/vimlparser.vital new file mode 100644 index 00000000..d8f2701e --- /dev/null +++ b/autoload/vital/vimlparser.vital @@ -0,0 +1,3 @@ +vimlparser +982e0bf3a5c181c0fa9d37bab784412f941f6b80 + diff --git a/js/jscompiler.vim b/js/jscompiler.vim index da90892b..86521aad 100644 --- a/js/jscompiler.vim +++ b/js/jscompiler.vim @@ -885,7 +885,7 @@ endfunction function! s:parse_args() abort let v = [ - \ fnamemodify(s:script_dir . '/../autoload/vimlparser.vim', ':p'), + \ fnamemodify(s:script_dir . '/../autoload/vital/__vimlparser__/VimLParser.vim', ':p'), \ fnamemodify(s:script_dir . '/vimlparser.js', ':p') \] let args = argv()[1:] @@ -894,7 +894,7 @@ function! s:parse_args() abort if len(args) != 2 throw 'invalid argument: ' . string(args) endif - let v = args + let v = args endif return v endfunction: @@ -907,6 +907,15 @@ function! s:main() abort call writefile([v:exception], has('win32') ? 'conout$' : '/dev/stderr') cquit endtry + if mode(1) ==# 'ce' + " This :visual is needed to make exit code 0 for old vim. + " Exit code is set to 1, Vim exit from Ex mode after an error + " output is performed even if the error is caught by try-catch. + " + " This problem is fixed at Vim v.8.0.0184. + " https://github.com/vim/vim/releases/tag/v8.0.0184 + visual + endif endfunction call s:main() diff --git a/js/vimlparser.js b/js/vimlparser.js index 236abe61..6558777d 100644 --- a/js/vimlparser.js +++ b/js/vimlparser.js @@ -620,9 +620,9 @@ VimLParser.prototype.pop_context = function() { VimLParser.prototype.find_context = function(type) { var i = 0; - var __c3 = this.context; - for (var __i3 = 0; __i3 < __c3.length; ++__i3) { - var node = __c3[__i3]; + var __c1 = this.context; + for (var __i1 = 0; __i1 < __c1.length; ++__i1) { + var node = __c1[__i1]; if (node.type == type) { return i; } @@ -1201,9 +1201,9 @@ VimLParser.prototype.find_command = function() { return this.find_command_cache[name]; } var cmd = NIL; - var __c4 = this.builtin_commands; - for (var __i4 = 0; __i4 < __c4.length; ++__i4) { - var x = __c4[__i4]; + var __c2 = this.builtin_commands; + for (var __i2 = 0; __i2 < __c2.length; ++__i2) { + var x = __c2[__i2]; if (viml_stridx(x.name, name) == 0 && viml_len(name) >= x.minlen) { delete cmd; var cmd = x; @@ -1211,18 +1211,18 @@ VimLParser.prototype.find_command = function() { } } if (this.neovim) { - var __c5 = this.neovim_additional_commands; - for (var __i5 = 0; __i5 < __c5.length; ++__i5) { - var x = __c5[__i5]; + var __c3 = this.neovim_additional_commands; + for (var __i3 = 0; __i3 < __c3.length; ++__i3) { + var x = __c3[__i3]; if (viml_stridx(x.name, name) == 0 && viml_len(name) >= x.minlen) { delete cmd; var cmd = x; break; } } - var __c6 = this.neovim_removed_commands; - for (var __i6 = 0; __i6 < __c6.length; ++__i6) { - var x = __c6[__i6]; + var __c4 = this.neovim_removed_commands; + for (var __i4 = 0; __i4 < __c4.length; ++__i4) { + var x = __c4[__i4]; if (viml_stridx(x.name, name) == 0 && viml_len(name) >= x.minlen) { delete cmd; var cmd = NIL; @@ -3667,9 +3667,9 @@ StringReader.prototype.__init__ = function(lines) { var offset = 0; while (lnum < viml_len(lines)) { var col = 0; - var __c7 = viml_split(lines[lnum], "\\zs"); - for (var __i7 = 0; __i7 < __c7.length; ++__i7) { - var c = __c7[__i7]; + var __c5 = viml_split(lines[lnum], "\\zs"); + for (var __i5 = 0; __i5 < __c5.length; ++__i5) { + var c = __c5[__i5]; viml_add(this.buf, c); viml_add(this.pos, [lnum + 1, col + 1, offset]); col += viml_len(c); @@ -3678,9 +3678,9 @@ StringReader.prototype.__init__ = function(lines) { while (lnum + 1 < viml_len(lines) && viml_eqregh(lines[lnum + 1], "^\\s*\\\\")) { var skip = TRUE; var col = 0; - var __c8 = viml_split(lines[lnum + 1], "\\zs"); - for (var __i8 = 0; __i8 < __c8.length; ++__i8) { - var c = __c8[__i8]; + var __c6 = viml_split(lines[lnum + 1], "\\zs"); + for (var __i6 = 0; __i6 < __c6.length; ++__i6) { + var c = __c6[__i6]; if (skip) { if (c == "\\") { var skip = FALSE; @@ -3782,9 +3782,9 @@ StringReader.prototype.readline = function() { StringReader.prototype.getstr = function(begin, end) { var r = ""; - var __c9 = viml_range(begin.i, end.i - 1); - for (var __i9 = 0; __i9 < __c9.length; ++__i9) { - var i = __c9[__i9]; + var __c7 = viml_range(begin.i, end.i - 1); + for (var __i7 = 0; __i7 < __c7.length; ++__i7) { + var i = __c7[__i7]; if (i >= viml_len(this.buf)) { break; } @@ -4212,9 +4212,9 @@ Compiler.prototype.compile = function(node) { } Compiler.prototype.compile_body = function(body) { - var __c10 = body; - for (var __i10 = 0; __i10 < __c10.length; ++__i10) { - var node = __c10[__i10]; + var __c8 = body; + for (var __i8 = 0; __i8 < __c8.length; ++__i8) { + var node = __c8[__i8]; this.compile(node); } } @@ -4313,9 +4313,9 @@ Compiler.prototype.compile_if = function(node) { this.incindent(" "); this.compile_body(node.body); this.decindent(); - var __c11 = node.elseif; - for (var __i11 = 0; __i11 < __c11.length; ++__i11) { - var enode = __c11[__i11]; + var __c9 = node.elseif; + for (var __i9 = 0; __i9 < __c9.length; ++__i9) { + var enode = __c9[__i9]; this.out(" elseif %s", this.compile(enode.cond)); this.incindent(" "); this.compile_body(enode.body); @@ -4372,9 +4372,9 @@ Compiler.prototype.compile_try = function(node) { this.out("(try"); this.incindent(" "); this.compile_body(node.body); - var __c12 = node.catch; - for (var __i12 = 0; __i12 < __c12.length; ++__i12) { - var cnode = __c12[__i12]; + var __c10 = node.catch; + for (var __i10 = 0; __i10 < __c10.length; ++__i10) { + var cnode = __c10[__i10]; if (cnode.pattern !== NIL) { this.decindent(); this.out(" catch /%s/", cnode.pattern); @@ -5364,9 +5364,9 @@ RegexpParser.prototype.get_token_sq_char_class = function() { var r = this.reader.read_alpha(); if (this.reader.p(0) == ":" && this.reader.p(1) == "]") { this.reader.seek_cur(2); - var __c13 = class_names; - for (var __i13 = 0; __i13 < __c13.length; ++__i13) { - var name = __c13[__i13]; + var __c11 = class_names; + for (var __i11 = 0; __i11 < __c11.length; ++__i11) { + var name = __c11[__i11]; if (r == name) { return "[:" + name + ":]"; } @@ -5499,9 +5499,9 @@ RegexpParser.prototype.getoctchrs = function() { RegexpParser.prototype.gethexchrs = function(n) { var r = ""; - var __c14 = viml_range(n); - for (var __i14 = 0; __i14 < __c14.length; ++__i14) { - var i = __c14[__i14]; + var __c12 = viml_range(n); + for (var __i12 = 0; __i12 < __c12.length; ++__i12) { + var i = __c12[__i12]; var c = this.reader.peek(); if (!isxdigit(c)) { break; diff --git a/py/pycompiler.vim b/py/pycompiler.vim index 8e387d99..475f5425 100644 --- a/py/pycompiler.vim +++ b/py/pycompiler.vim @@ -857,7 +857,7 @@ endfunction function! s:parse_args() abort let v = [ - \ fnamemodify(s:script_dir . '/../autoload/vimlparser.vim', ':p'), + \ fnamemodify(s:script_dir . '/../autoload/vital/__vimlparser__/VimLParser.vim', ':p'), \ fnamemodify(s:script_dir . '/vimlparser.py', ':p') \] let args = argv()[1:] @@ -866,7 +866,7 @@ function! s:parse_args() abort if len(args) != 2 throw 'invalid argument: ' . string(args) endif - let v = args + let v = args endif return v endfunction: @@ -879,6 +879,15 @@ function! s:main() abort call writefile([v:exception], has('win32') ? 'conout$' : '/dev/stderr') cquit endtry + if mode(1) ==# 'ce' + " This :visual is needed to make exit code 0 for old vim. + " Exit code is set to 1, Vim exit from Ex mode after an error + " output is performed even if the error is caught by try-catch. + " + " This problem is fixed at Vim v.8.0.0184. + " https://github.com/vim/vim/releases/tag/v8.0.0184 + visual + endif endfunction call s:main() diff --git a/scripts/update_builtin_commands.vim b/scripts/update_builtin_commands.vim index 213bbc3a..2bec4e40 100644 --- a/scripts/update_builtin_commands.vim +++ b/scripts/update_builtin_commands.vim @@ -129,9 +129,9 @@ function! g:VimLParserNewCmds(ex_cmds_h) abort let new_cmds = s:gen_new_builtin(vimlparser#import().VimLParser.builtin_commands, latest) let generated_text = s:gen_viml(new_cmds) if generated_text == '' - verbose echo 's:VimLParser.builtin_commands in autoload/vimlparser.vim is up-to-date.' + verbose echo 's:VimLParser.builtin_commands is up-to-date.' else - verbose echo "Append following lines to s:VimLParser.builtin_commands in autoload/vimlparser.vim\n" + verbose echo "Append following lines to s:VimLParser.builtin_commands\n" verbose echo generated_text endif endfunction diff --git a/test/vimrc b/test/vimrc index e98989a5..4604974e 100644 --- a/test/vimrc +++ b/test/vimrc @@ -2,5 +2,5 @@ let &rtp .= ',' . getcwd() if $TEST_PROFILE != '' execute 'profile' 'start' $TEST_PROFILE - profile! file ./autoload/* + profile! file ./autoload/vital/__vimlparser__/* endif