Commits

ZyX_I committed 6af57fc

@/fwc: Moved gettype, addtuple, addlist and adddict functions to @/fwc/intfuncs, added {one} argument to `range' check, made all matchers lookup for exact match before doing any other processing

Comments (0)

Files changed (4)

plugin/frawor/fwc/compiler.vim

         let curargstr=self.argstr()
         let r.=', '.join(map(a:matcher[1][2:-2],
                     \        'type(v:val)=='.type([]).'?'.
-                    \           'self.getvar(v:val, 0, curargstr):'.
+                    \           'self.getvar(v:val, 0, a:ldstr, a:strstr):'.
                     \           'string(v:val)'),
                     \    ', ')
     endif
 function s:compiler.getlvarid(v)
     return printf('@$@%s%X', a:v, len(self.stack))
 endfunction
-"▶1 addtuple       :: tupledesc, idx, defaultArgType + self → self + self
-function s:compiler.addtuple(tuple, idx, default)
-    call add(self.subs, 0)
-    for arg in a:tuple[1]
-        call self.compilearg(arg, a:idx.'(tuple).'.self.subs[-1], a:default)
-        call self.incsub()
-    endfor
-    call remove(self.subs, -1)
-    return self
-endfunction
-"▶1 addlist        :: listdesc, idx, defaultArgType + self → self + self
-function s:compiler.addlist(list, idx, default)
-    let largstr=self.getlvarid('larg')
-    let lststr=self.argstr()
-    let istr=self.getlvarid('i')
-    call add(self.subs, [istr])
-    call     self.let(largstr, 'len('.lststr.')')
-                \.let(istr, 0)
-                \.while(istr.'<'.largstr)
-                    \.compilearg(a:list[1], a:idx.'(list)', a:default)
-                    \.increment(istr)
-                \.up().up()
-    call remove(self.subs, -1)
-    return self
-endfunction
-"▶1 adddict        :: dicdesc, idx, defaultArgType + self → self + self
-function s:compiler.adddict(dic, idx, default)
-    if len(a:dic[1])==1
-        let curargstr=self.argstr()
-        return self.nextthrow('!empty('.curargstr.')',
-                    \         'keynmatch', a:idx, 'keys('.curargstr.')[0]')
-    endif
-    let keystr=self.getlvarid('key')
-    call self.for(keystr, 'keys('.self.argstr().')')
-    call add(self.subs, [keystr])
-    let foundstr=self.getlvarid('found')
-    let msglenstr=self.getlvarid('msglen')
-    let pmsglenstr=self.getlvarid('pmsglen')
-    let hascheck=0
-    let i=-1
-    for check in a:dic[1][1:]
-        let i+=1
-        if check[0] is 'eq'
-            call self.addif(keystr.' is '.s:F.string(check[1]))
-        elseif check[0] is 'regex'
-            call self.addif(keystr.'=~#'.s:F.string(check[1]))
-        elseif check[0] is 'func'
-            call self.addif(self.getfunc(check[1], 0, keystr))
-        elseif check[0] is 'expr'
-            call self.addif(self.getexpr(check[1], keystr))
-        elseif check[0] is 'any'
-            call self.compilearg(check[1], a:idx.'.'.i.'(val)', a:default)
-                        \.continue()
-            break
-        elseif check[0] is 'check'
-            if !hascheck
-                call self.addsavemsgs()
-            endif
-            let hascheck=1
-            call self.try()
-                        \.pushms('throw')
-                        \.let(foundstr, 0)
-                        \.witharg([keystr])
-                        \.compilearg(check[1], a:idx.'.'.i.'(key)', 'check')
-                        \.without()
-                        \.let(foundstr, 1)
-                        \.compilearg(check[2],a:idx.'.'.i.'(val)',a:default)
-                        \.popms()
-                    \.up().catch(s:cfreg)
-                        \.addif(foundstr)
-                            \.fail()
-                        \.addrestmsgs(1)
-                    \.up().addif(foundstr)
-                        \.continue().up()
-            continue
-        endif
-        call self.compilearg(check[2], a:idx.'.'.i.'(val)',a:default).continue()
-                    \.up()
-    endfor
-    if hascheck
-        call remove(self.msgs.savevars, -1)
-    endif
-    call self.addthrow('keynmatch', 1, a:idx, keystr)
-    call remove(self.subs, -1)
-    return self
-endfunction
 "▶1 compilemsg     :: msgcontext, _ + self → self + self
 function s:compiler.compilemsg(msg, idx)
     if a:msg[1] is 0

plugin/frawor/fwc/intfuncs.vim

 endfunction
 "▶1 `tuple'
 let s:r.tuple={'args': ['*arg']}
+"▶2 addtuple       :: tupledesc, idx, defaultArgType + self → self + self
+function s:F.addtuple(tuple, idx, default)
+    call add(self.subs, 0)
+    for arg in a:tuple[1]
+        call self.compilearg(arg, a:idx.'(tuple).'.self.subs[-1], a:default)
+        call self.incsub()
+    endfor
+    call remove(self.subs, -1)
+    return self
+endfunction
+"▲2
 " Checks whether {argument} is a list with a fixed length and each element 
 " matching given specification
 function s:r.tuple.check(desc, idx, type)
     let curargstr=self.argstr()
-    return self.addtypecond([type([])], a:idx)
+    call self.addtypecond([type([])], a:idx)
                 \.nextthrow('len('.curargstr.')!='.len(a:desc[1]),
                 \           'invlstlen', a:idx, len(a:desc[1]),
                 \                        'len('.curargstr.')')
-                \.addtuple(a:desc, a:idx, a:type)
+    return call(s:F.addtuple, [a:desc, a:idx, a:type], self)
 endfunction
 " Checks whether {argument} is a list with a fixed length and then process given 
 " pipes for each of the arguments
 let s:r.tuple.pipe=s:r.tuple.check
 "▶1 `list'
 let s:r.list={'args': ['arg']}
+"▶2 addlist        :: listdesc, idx, defaultArgType + self → self + self
+function s:F.addlist(list, idx, default)
+    let largstr=self.getlvarid('larg')
+    let lststr=self.argstr()
+    let istr=self.getlvarid('i')
+    call add(self.subs, [istr])
+    call     self.let(largstr, 'len('.lststr.')')
+                \.let(istr, 0)
+                \.while(istr.'<'.largstr)
+                    \.compilearg(a:list[1], a:idx.'(list)', a:default)
+                    \.increment(istr)
+                \.up().up()
+    call remove(self.subs, -1)
+    return self
+endfunction
+"▲2
 " Checks whether {argument} is a list where each item matches given 
 " specification
 function s:r.list.check(desc, idx, type)
-    return self.addtypecond([type([])], a:idx).addlist(a:desc, a:idx, a:type)
+    call self.addtypecond([type([])], a:idx)
+    return call(s:F.addlist, [a:desc, a:idx, a:type], self)
 endfunction
 " Checks whether {argument} is a list and then filter each item using given 
 " specification
 let s:r.list.pipe=s:r.list.check
 "▶1 `dict'
 let s:r.dict={'args': ['get']}
+"▶2 adddict        :: dicdesc, idx, defaultArgType + self → self + self
+function s:F.adddict(dic, idx, default)
+    if len(a:dic[1])==1
+        let curargstr=self.argstr()
+        return self.nextthrow('!empty('.curargstr.')',
+                    \         'keynmatch', a:idx, 'keys('.curargstr.')[0]')
+    endif
+    let keystr=self.getlvarid('key')
+    call self.for(keystr, 'keys('.self.argstr().')')
+    call add(self.subs, [keystr])
+    let foundstr=self.getlvarid('found')
+    let msglenstr=self.getlvarid('msglen')
+    let pmsglenstr=self.getlvarid('pmsglen')
+    let hascheck=0
+    let i=-1
+    for check in a:dic[1][1:]
+        let i+=1
+        if check[0] is 'eq'
+            call self.addif(keystr.' is '.s:F.string(check[1]))
+        elseif check[0] is 'regex'
+            call self.addif(keystr.'=~#'.s:F.string(check[1]))
+        elseif check[0] is 'func'
+            call self.addif(self.getfunc(check[1], 0, keystr).' isnot 0')
+        elseif check[0] is 'expr'
+            call self.addif(self.getexpr(check[1], keystr).' isnot 0')
+        elseif check[0] is 'any'
+            call self.compilearg(check[1], a:idx.'.'.i.'(val)', a:default)
+                        \.continue()
+            break
+        elseif check[0] is 'check'
+            if !hascheck
+                call self.addsavemsgs()
+            endif
+            let hascheck=1
+            call self.try()
+                        \.pushms('throw')
+                        \.let(foundstr, 0)
+                        \.witharg([keystr])
+                        \.compilearg(check[1], a:idx.'.'.i.'(key)', 'check')
+                        \.without()
+                        \.let(foundstr, 1)
+                        \.compilearg(check[2],a:idx.'.'.i.'(val)',a:default)
+                        \.popms()
+                    \.up().catch(s:cfreg)
+                        \.addif(foundstr)
+                            \.fail()
+                        \.addrestmsgs(1)
+                    \.up().addif(foundstr)
+                        \.continue().up()
+            continue
+        endif
+        call self.compilearg(check[2], a:idx.'.'.i.'(val)',a:default).continue()
+                    \.up()
+    endfor
+    if hascheck
+        call remove(self.msgs.savevars, -1)
+    endif
+    call self.addthrow('keynmatch', 1, a:idx, keystr)
+    call remove(self.subs, -1)
+    return self
+endfunction
 "▶2 getddescr  :: &self
 " Gets dictionary description:
 " Input: "{" ({keydescr} {arg})* "}"
 "        {keydescr} :: {str}
+"                    | {wordchar}+
 "                    | "/" {reg}(endstr=/)
 "                    | "?" {arg}
 "                    | "*" {func}
 "                    | "=" {expr}
 "                    | "-"
-"                    | {wordchar}+
 " Output: context(ddescr, {keycon}*)
 "         {keycon} :: context(eq,    String, {arg})
 "                   | context(regex, String, {arg})
 "▲2
 " Checks whether {argument} is a dictionary matching given {ddescr}
 function s:r.dict.check(desc, idx, type)
-    return self.addtypecond([type({})], a:idx).adddict(a:desc, a:idx, a:type)
+    call self.addtypecond([type({})], a:idx)
+    return call(s:F.adddict, [a:desc, a:idx, a:type], self)
 endfunction
 " Checks whether {argument} is a dictionary and transform it using given 
 " {ddescr}
 endfunction
 "▶1 `range'
 " Checks whether {argument} is in given range
-let s:r.range={'args': ['number', 'number']}
+let s:r.range={'args': ['number', 'number', '?one']}
 function s:r.range.check(desc, idx, type)
     let curargstr=self.argstr()
     "▶2 Determine whether we accept floating-point values
     let acceptfloat=has('float') &&
-                \(a:desc[1][0] is 'float' || a:desc[1][1] is 'float')
+                \(a:desc[3] || a:desc[1][0] is 'float'
+                \           || a:desc[2][0] is 'float')
     if acceptfloat
         call self.addtypecond([type(0), type(0.0)], a:idx)
     else
         call self.addtypecond([type(0)], a:idx)
     endif
     "▶2 Obtain range borders
-    let range=map(a:desc[1:],
+    let range=map(a:desc[1:2],
                 \'((v:val[0] is "inf" || v:val[0] is "nan")?'.
                 \   '(""):'.
                 \   '((v:val[0] is "number"||v:val[0] is "float")?'.
 let s:r.path={'args': ['get']}
 "▶2 getpath    :: &self!
 " Gets path specification:
-" Input: [( "d" | "f" )] [ "r" ] [( "w" | "W" | "p" )] [ "x" ]
+" Input: [df]? "r"? [wWp]? "x"?
 "        & ! ( "d" | ^ ) "r"
-"        & ! ( "d" ) ( "w" | "W" | "p" )? "x"
+"        & ! "d" [wWp]? "x"
 " 1. "d" for directory and "f" for regular file, otherwise both may be accepted
 " 2. "r" for readable file (not directory)
 " 3. "w" for writeable file or directory (unless "f" is specified),
 endfunction
 "▶1 `type'
 " Checks whether {argument} has one of given types
-let s:r.type={'args': ['*type']}
+let s:r.type={'args': ['*get']}
+"▶2 gettype    :: &self!
+" Adds type number to the context.
+" Valid arguments: s[tring], n[umber], f[loat], d[ictionary], l[ist], fu[nction]
+"                   "", '',     -0,      .0,         {},        []
+" Input: {typedescr}
+" Output: add({typeNumber})
+"         {typeNumber}: any number described in |type()|
+let s:typechars={
+            \'{': [type({}),  '}'],
+            \'[': [type([]),  ']'],
+            \'"': [type(""),  '"'],
+            \"'": [type(''),  "'"],
+            \'-': [type(0),   '0'],
+        \}
+let s:typewords={
+            \    'string': type(''),
+            \    'number': type(0),
+            \'dictionary': type({}),
+            \      'list': type([]),
+            \  'function': 2,
+        \}
+if has('float')
+    let s:typechars['.']=[type(0.0), '0']
+    let s:typewords.float=type(0.0)
+endif
+function s:r.type.get()
+    if !self.len
+        call self.throw('typemis')
+    endif
+    let c=self.readc()
+    if has_key(s:typechars, c)
+        call self.add(s:typechars[c][0])
+        if self.len
+            let readchar=s:typechars[c][1]
+            let c=self.readc()
+            if c isnot readchar
+                call self.ungetc(c)
+            endif
+        endif
+    else
+        let type=tolower(c)
+        if !has_key(s:typewords, type)
+            call self.throw('invtype', c)
+        endif
+        call self.add(s:typewords[type])
+    endif
+    return self
+endfunction
+"▲2
 function s:r.type.check(desc, idx, type)
     return self.addtypecond(a:desc[1], a:idx)
 endfunction
     let curargstr=self.argstr()
     let self.typechanged=1
     if self.o.onlystrings
-        return self.let(curargstr, curargstr.'=~#''\c\v^%(1|yes|ok|true)$''')
+        return self.let(curargstr, curargstr.'=~?''\v^%(1|yes|ok|true)$''')
     else
         return self.let(curargstr, '!empty('.curargstr.')')
     endif
 "▲1
 "Matchers ---------------------------------------------------------------------
 "▶1 `func'
-" Uses some other function as matcher. Function must accept list or dictionary 
-" and return a list of strings. Additional argument determines what should be 
-" done if function returns list with more then one item
+" Uses some other function as matcher. Function must accept a String (dot 
+" argument, can be overriden by explicitely supplying a list of arguments) and 
+" return a list of strings. Additional argument determines what should be done 
+" if function returns list with more then one item
 function s:r.func.matcher(ld, str, variants, acceptfirst)
     if a:acceptfirst is 2
         return a:variants
 let s:r.exact={'args': ['?one']}
 function s:r.exact.matcher(ld, str, ignorecase, acceptfirst)
     if type(a:ld)==type({})
-        if a:ignorecase
+        if has_key(a:ld, a:str)
+            return ((a:acceptfirst is 2)?([a:str]):(a:str))
+        elseif a:ignorecase
             let list=sort(keys(a:ld))
         else
-            return ((has_key(a:ld, a:str)==-1)?(0):(a:str))
+            return 0
         endif
-    elseif !a:ignorecase
-        return ((index(a:ld, a:str)==-1)?(0):(a:str))
     else
-        let list=a:ld
+        if index(a:ld, a:str)!=-1
+            return ((a:acceptfirst is 2)?([a:str]):(a:str))
+        elseif a:ignorecase
+            let list=a:ld
+        else
+            return 0
+        endif
     endif
     let idx=index(list, a:str, 0, 1)
     if idx==-1
 let s:r.start={'args': ['?one']}
 function s:r.start.matcher(ld, str, ignorecase, acceptfirst)
     if type(a:ld)==type({})
+        if has_key(a:ld, a:str)
+            return ((a:acceptfirst is 2)?([a:str]):(a:str))
+        endif
         let list=sort(keys(a:ld))
     else
-        let list=a:ld
+        if index(a:ld, a:str)!=-1
+            return ((a:acceptfirst is 2)?([a:str]):(a:str))
+        endif
+        let list=filter(copy(a:ld), 'type(v:val)=='.type(''))
     endif
     let r=[]
     let lstr=len(a:str)-1
     for value in list
         if type(value)==type('')
-            if value is a:str
-                let r=[value]
-                break
-            elseif ((a:ignorecase)?(value[:(lstr)]==?a:str):
-                        \          (value[:(lstr)]==#a:str))
+            if ((a:ignorecase)?(value[:(lstr)]==?a:str):
+                        \      (value[:(lstr)]==#a:str))
                 if a:acceptfirst is 1
                     return value
                 elseif empty(r)
 " match in sorted list will be taken)
 let s:r.smart={'args': []}
 let s:smartfilters=[
-            \'v:val is a:str',
             \'v:val==?a:str',
-            \'v:val=~#''\V\^''.estr',
-            \'v:val=~?''\V\^''.estr',
+            \'v:val[:(lstr)] is a:str',
+            \'v:val[:(lstr)]==?a:str',
             \'stridx(v:val, a:str)!=-1',
-            \'v:val=~?"\\V".estr',
+            \'stridx(tolower(v:val), lowstr)!=-1',
             \'v:val=~#reg',
             \'v:val=~?reg',
             \'v:val=~#reg2',
             \'v:val=~?reg2',
             \]
 function s:r.smart.matcher(ld, str, acceptfirst)
+    if type(a:ld)==type({})
+        if has_key(a:ld, a:str)
+            return ((a:acceptfirst is 2)?([a:str]):(a:str))
+        endif
+        let list=sort(keys(a:ld))
+    else
+        if index(a:ld, a:str)!=-1
+            return ((a:acceptfirst is 2)?([a:str]):(a:str))
+        endif
+        let list=filter(copy(a:ld), 'type(v:val)=='.type(''))
+    endif
+    let lowstr=tolower(a:str)
+    let lstr=len(a:str)-1
     let estr=escape(a:str, '\')
     let reg='\V'.join(split(estr, '\v[[:punct:]]@<=|[[:punct:]]@='), '\.\*')
     let reg2='\V'.join(map(split(a:str,'\v\_.@='),'escape(v:val,"\\")'), '\.\*')
-    let list=filter(((type(a:ld)==type({})?(sort(keys(a:ld))):(copy(a:ld)))),
-                \   'type(v:val)=='.type(''))
     for filter in s:smartfilters
         let r=filter(copy(list), filter)
         if !empty(r)

plugin/frawor/fwc/parser.vim

             \ 'wordend': 'regular expression cannot end with %s',
             \  'noexpr': 'expected expression, but got nothing',
         \}
-"▶1 getmatch   :: Dict|List, String → String
-function s:F.getmatch(ld, str)
-    if type(a:ld)==type({})
-        return has_key(a:ld, a:str)? a:str : 0
-    else
-        return index(a:ld, a:str)==-1? 0 : a:str
-    endif
-endfunction
 "▶1 add        :: &self
 " Adds an element to current context
 function s:parser.add(item)
     endif
     return c
 endfunction
-"▶1 scanlist   :: farg + self → self
+"▶1 scanlist   :: F + self → self
 " Scans a list of elements that looks either like "{e1}, {e2}", "({e1} {e2})" or 
 " "({e1}, {e2})" (last two can be combined).
 " Input: {<farg>} ( "," {<farg>} )*
 "      | "(" ( {<farg>} ","? )* ")"?
 " Output: context({<farg>}*)
-function s:parser.scanlist(farg)
+function s:parser.scanlist(F)
     call self.addcon()
     if self.len
         let c=self.readc()
                     break
                 elseif c isnot ','
                     call self.ungetc(c)
-                    call call(self['get'.a:farg], [], self)
+                    call call(a:F, [], self)
                 endif
             endwhile
         else
             call self.ungetc(c)
             while self.len
-                call call(self['get'.a:farg], [], self)
+                call call(a:F, [], self)
                 if self.len
                     let c=self.readc()
                     if c isnot ','
     if type is 'arg'
         let type.=self.type
     endif
-    let c=self.readc()
-    let func=s:F.getmatch(s:_r.FWC_intfuncs, c)
-    if func is 0 "▶2
-        call self.throw('ukfunc', c)
-    endif        "▲2
+    let func=self.readc()
+    if !has_key(s:_r.FWC_intfuncs, func) "▶2
+        call self.throw('ukfunc', func)
+    endif                                "▲2
     call self.addcon('intfunc', func)
     let fargs=s:_r.FWC_intfuncs[func].args
     if type is 'matcher'
             call self.throw('argmis', type.'.'.func)
         endif            "▲2
         if farg[0] is '*'
-            call self.scanlist(farg[1:])
+            let farg=farg[1:]
+            call self.scanlist(((farg[:2] is 'get')?
+                        \           (s:_r.FWC_intfuncs[func][farg]):
+                        \           (self['get'.farg])))
         else
             call call(((farg[:2] is 'get')?
                         \(s:_r.FWC_intfuncs[func][farg]):
     endif
     return self
 endfunction
-"▶1 gettype    :: &self!
-" Adds type number to the context.
-" Valid arguments: s[tring], n[umber], f[loat], d[ictionary], l[ist], fu[nction]
-"                   "", '',     -0,      .0,         {},        []
-" Input: {typedescr}
-" Output: add({typeNumber})
-"         {typeNumber}: any number described in |type()|
-let s:typechars={
-            \'{': [type({}),  '}'],
-            \'[': [type([]),  ']'],
-            \'"': [type(""),  '"'],
-            \"'": [type(''),  "'"],
-            \'-': [type(0),   '0'],
-        \}
-let s:typewords={
-            \    'string': type(''),
-            \    'number': type(0),
-            \'dictionary': type({}),
-            \      'list': type([]),
-            \  'function': 2,
-        \}
-if has('float')
-    let s:typechars['.']=[type(0.0), '0']
-    let s:typewords.float=type(0.0)
-endif
-function s:parser.gettype()
-    if !self.len
-        call self.throw('typemis')
-    endif
-    let c=self.readc()
-    if has_key(s:typechars, c)
-        call self.add(s:typechars[c][0])
-        if self.len
-            let readchar=s:typechars[c][1]
-            let c=self.readc()
-            if c isnot readchar
-                call self.ungetc(c)
-            endif
-        endif
-    else
-        let type=s:F.getmatch(s:typewords, tolower(c))
-        if type is 0
-            call self.throw('invtype', c)
-        endif
-        call self.add(s:typewords[type])
-    endif
-    return self
-endfunction
 "▶1 getstring  :: &self!
 " Gets either a string or variable name
 " Input: ( "$" {var} | {str} | {wordchar}+ )?

test/fwctests.dat

 ['in list ~smart',         'filter'], ['a-d'],              0
 ['in list ~smart',         'filter'], ['b-d'],              ['abc-def']
 ['in list ~smart 1',       'filter'], ['a-d'],              ['abc-def']
-\function s:.getmatches(str, filter)
-\    return filter(s:list, a:filter)
+\function s:.getmatches(list, str, filter)
+\    return filter(a:list, a:filter)
 :endfunction
 :let s:filter="len(v:val)>len(a:str)"
 ['in list ~func getmatches(. filter) 1', 'filter'], ['a'],    ['abc']
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.