Commits

ZyX_I committed 86380df

Some checks scanner improvements

Comments (0)

Files changed (3)

plugin/frawor/checks.vim

                 \            'plugin %s: ID is not a string',
             \}
 endif
+call extend(s:_messages, {
+            \     'int': 'internal error: %s',
+            \     'eos': 'unexpected end of string',
+            \  'ukfunc': 'unknown function: %s',
+            \  'ukfarg': 'unknown function argument: %s',
+            \'unmatchp': 'unmatched `%s''',
+            \ 'uenvvar': 'unknown enviroment variable: %s',
+            \  'invvar': 'invalid variable description: %s',
+            \ 'invpref': 'invalid prefix description: %s',
+            \  'invact': 'invalid action description: %s',
+            \'noadescr': 'action description is missing',
+            \'invssubs': 'invalid subscript in slice expression: %s',
+            \ 'uoption': 'unknown option: %s',
+            \  'argmis': 'missing arguments to %s',
+            \ 'funcmis': 'missing %s function',
+            \ 'subsmis': 'subscript range missing',
+            \   'nonum': 'number expected',
+            \  'varmis': 'missing variable description',
+            \ 'pipemis': 'missing pipe description',
+            \  'msgmis': 'missing message description',
+            \ 'prefmis': 'missing prefixes description',
+            \  'actmis': 'missing arguments description',
+        \})
 "▶1 conschecker feature
 let s:checkers={'lastid': 0}
-"▶2 conschecker :: {f}, checker → chkfunc + s:checkers
+"▶2 conschecker  :: {f}, checker → chkfunc + s:checkers
 function s:F.conschecker(plugdict, fdict, Chk)
     let id=printf('%x', s:checkers.lastid)
     call add(a:fdict.ids, id)
         call s:_f.throw('uchecker', a:plugdict.id)
     endif
 endfunction
-"▶2 delcheckers :: {f} → + s:checkers
+"▶2 delcheckers  :: {f} → + s:checkers
 function s:F.delcheckers(plugdict, fdict)
-    for id in a:fdict.ids
+    for id in filter(a:fdict.ids, 'has_key(s:checkers, v:val)')
         unlet s:checkers[id]
     endfor
 endfunction
             \                        'init': {'ids': []}})
 "▶1 consfilter feature
 let s:filters={'lastid': 0}
-"▶2 consfilter :: {f}, filter → filfunc + s:filters
+"▶2 consfilter  :: {f}, filter → filfunc + s:filters
 function s:F.consfilter(plugdict, fdict, Fil)
     let id=printf('%x', s:filters.lastid)
     call add(a:fdict.ids, id)
         call s:_f.throw('ufilter', a:plugdict.id)
     endif
 endfunction
-"▶2 delfilters :: {f} → + s:filters
+"▶2 delfilters  :: {f} → + s:filters
 function s:F.delfilters(plugdict, fdict)
     for id in a:fdict.ids
         unlet s:filters[id]
 "▶1 func
 let s:F.func={}
 let s:args.func={}
+"▶1 arg
+let s:F.arg={}
+let s:args.arg={}
+"▶1 matcher
+let s:F.matcher={}
+let s:args.matcher={}
+"▶1 getmatch        :: Dict, String → String
+function s:F.getmatch(dict, str)
+    let lstr=len(a:str)
+    for key in sort(keys(a:dict))
+        if key[:(ltsr-1)] is a:str
+            return key
+        endif
+    endfor
+endfunction
 "▶1 scan
 let s:F.scan={}
-"▶2 scan.delblanks :: &self
-function s:F.scan.delblanks()
-    let self.s=substitute(self.s, '^\s\+', '', 'g')
-    return self
-endfunction
-"▶2 scan.conclose  :: &self
+"▶2 scan.conclose   :: &self
 function s:F.scan.conclose()
     call remove(self.stack, -1)
     let self.l=self.stack[-1]
     return self
 endfunction
-"▶2 scan.addcon    :: ()[, coninit] + self → self + self
+"▶2 scan.addcon     :: ()[, coninit] + self → self + self
 function s:F.scan.addcon(...)
-    let con=a:000
+    let con=copy(a:000)
     call add(self.l, con)
     call add(self.stack, con)
     let self.l=con
     return self
 endfunction
-"▶2 scan.nextc     :: () + self → Char + self
+"▶2 scan.ungetc     :: (Char) + self → self + self(s)
+function s:F.scan.ungetc(c)
+    call add(self.ungot, a:c)
+    let self.eos=0
+    return self
+endfunction
+"▶2 scan.delblanks  :: &self(s)
+function s:F.scan.delblanks()
+    let self.s=substitute(self.s, '^\s\+', '', 'g')
+    let self.eos=empty(self.s)
+    return self
+endfunction
+"▶2 scan.nextc      :: () + self → String + self(s)
 function s:F.scan.nextc()
+    if self.eos
+        call self.throw('eos')
+    endif
+    if !empty(self.ungot)
+        let r=remove(self.ungot, -1)
+        let self.eos=(empty(self.ungot) && empty(self.s))
+        return r
+    endif
     let c=self.s[0]
     if c!~#'\w'
         let self.s=self.s[1:]
         let self.s=self.s[len(c):]
     endif
     call self.delblanks()
+    let self.eos=empty(self.s)
     return c
 endfunction
-"▶2 scan.intfunc   :: &self
+"▶2 scan.nextstr    :: () + self → String + self(s)
+function s:F.scan.nextstr()
+    if !empty(self.ungot)
+        call self.throw('int', 'strungetc')
+    endif
+    let c=matchstr(self.s, '\v(\\.|[^\\"]*)+"')
+    if empty(c)
+        call self.throw('unmatchp', '"')
+    endif
+    let self.s=self.s[len(c):]
+    let self.eos=empty(self.s)
+    return substitute(c[:-2], '\\\(.\)', '\1', 'g')
+endfunction
+"▶2 scan.scanlist   :: farg + self → self
+function s:F.scan.scanlist(farg)
+    let c=self.nextc()
+    if c is '('
+        while !self.eos
+            let c=self.nextc()
+            if c is ')'
+                break
+            elseif c isnot ','
+                call self['get'.a:farg]()
+            endif
+        endwhile
+    else
+        call self.ungetc(c)
+        while !self.eos
+            call self['get'.a:farg]()
+            if !self.eos
+                let c=self.nextc()
+                if c isnot ','
+                    call self.ungetc(c)
+                    break
+                endif
+            endif
+        endwhile
+    endif
+    return self
+endfunction
+"▶2 scan.intfunc    :: &self
 function s:F.scan.intfunc()
-    let type=self.stack[-2][0]
-    let func=s:F.getmatch(s:F[type], self.nextc())
+    let type=self.stack[-1][0]
+    if self.eos
+        call self.throw('funcmis', type)
+    endif
+    let c=self.nextc()
+    let func=s:F.getmatch(s:F[type], c)
+    if func is 0
+        call self.throw("ukfunc", c)
+    endif
     call self.addcon('intfunc', func)
-    let fargs=get(s:fargs[type], func, [])
+    let fargs=get(s:args[type], func, [])
     for farg in fargs
-        call self['get'.farg]()
+        if self.eos
+            call self.throw('argmis', type.'.'.func)
+        elseif farg[0] is '*'
+            call self.scanlist(farg[1:])
+        else
+            call self['get'.farg]()
+        endif
     endfor
     return self.conclose()
 endfunction
-"▶2 scan.getplvar  :: &self
-function s:F.scan.getplvar()
-    return self.addcon('plvar', self.nextc()).conclose()
-endfunction
-"▶2 scan.getfunc   :: &self
-function s:F.scan.getfunc()
-    call self.addcon('func')
-    let c=self.nextc()
-    if c is ':'
-        call self.getvar()
-    else
-        call self.intfunc()
+"▶2 scan.getchvar   :: &self
+function s:F.scan.getchvar()
+    call self.addcon('this', 0)
+    if !self.eos
+        let c=self.nextc()
+        if c is '<'
+            call self.addcon('this', 1)
+            while !self.eos
+                let c=self.nextc()
+                if c is '<'
+                    let self.l[-1]+=1
+                else
+                    break
+                endif
+            endwhile
+        endif
+        if c is '.'
+            call self.addcon('subscript', [])
+            while !self.eos
+                let c=self.nextc()
+                if c is '"'
+                    call add(self.l[-1], self.nextstr())
+                elseif c=~#'^\d'
+                    call add(self.l[-1], +c)
+                elseif c=~#'^\w'
+                    call add(self.l[-1], c)
+                elseif c is ':'
+                    call self.addcon('splice')
+                    " Start and end subscripts
+                    for i in range(0, 1)
+                        if self.eos
+                            call self.throw('subsmis')
+                        endif
+                        let v=self.nextc()
+                        if v is '-'
+                            if self.eos
+                                call self.throw('nonum')
+                            endif
+                            let v.=self.nextc()
+                        endif
+                        call add(self.l, +v)
+                    endfor
+                elseif c isnot '.'
+                    break
+                endif
+            endwhile
+            call self.conclose()
+        else
+            call self.ungetc(c)
+        endif
     endif
     return self.conclose()
 endfunction
-"▶2 scan.addpipe   :: &self
-function s:F.scan.addpipe()
+"▶2 scan.getlist    :: &self
+function s:F.scan.getlist()
+    call self.addcon('list')
+    while !self.eos
+        let c=self.nextc()
+        if c is ']'
+            break
+        elseif c is '"'
+            call add(self.l, self.nexstr())
+        else
+            call add(self.l, c)
+        endif
+    endwhile
+    return self.conclose()
+endfunction
+"▶2 scan.getvar     :: &self
+function s:F.scan.getvar()
+    if self.eos
+        call self.throw('varmis')
+    endif
+    let c=self.nextc()
+    if c=~#'^\w'
+        call self.addcon('plugvar', c)
+        while !self.eos
+            let c=self.nextc()
+            if c=~#'^\w'
+                let self.l[-1].=".".c
+            elseif c isnot '.'
+                call self.ungetc(c)
+                break
+            endif
+        endwhile
+    elseif c is '@'
+        return self.getchvar()
+    elseif c is '"'
+        call self.addcon('svar', self.nextstr())
+    elseif c is '['
+        call self.getlist()
+    else
+        call self.throw('invvar', c)
+    endif
+    return self.conclose()
+endfunction
+"▶2 scan.getfunc    :: &self
+function s:F.scan.getfunc()
+    call self.addcon('func')
+    if self.eos
+        call self.throw('funcmis', 'external')
+    endif
+    let c=self.nextc()
+    if c is '$'
+        call self.getvar()
+        if !self.eos
+            let c=self.nextc()
+            if c is '('
+                while !self.eos
+                    let c=self.nextc()
+                    if c is ')'
+                        break
+                    elseif c is '$'
+                        call self.getvar()
+                    elseif c is '*'
+                        call self.getfunc()
+                    elseif c is '@'
+                        call self.getchvar()
+                    else
+                        call self.throw('ukfarg', c)
+                    endif
+                endwhile
+            else
+                call self.ungetc(c)
+            endif
+        endif
+    else
+        call self.ungetc(c).intfunc()
+    endif
+    return self.conclose()
+endfunction
+"▶2 scan.getpipe    :: &self
+function s:F.scan.getpipe()
+    if self.eos
+        call self.throw('pipemis')
+    endif
     call self.addcon('pipe')
     let c=self.nextc()
     if c is '*'
         call self.getfunc()
     else
-        call self.intfunc()
+        call self.ungetc(c).intfunc()
     endif
     return self.conclose()
 endfunction
-"▶2 scan.scan      :: + self → s + &
-function s:F.scan.scan()
-    call self.addcon()
-    let pc=self.pc
-    while 1
+"▶2 scan.getmsg     :: &self
+function s:F.scan.getmsg()
+    call self.addcon('msg')
+    if self.eos
+        call self.throw('msgmis')
+    endif
+    let c=self.nextc()
+    " TODO
+    return self.conclose()
+endfunction
+"▶2 scan.scanopt    :: &self
+function s:F.scan.scanopt()
+    call self.addcon('optional')
+    while !self.eos
         let c=self.nextc()
-        if c is '('
-            let self.pc+=1
-        elseif c is ')'
-            let self.pc-=1
-            if pc is self.pc
+        if c is ']'
+            break
+        endif
+        call self.ungetc(c).scan()
+    endwhile
+    return self.conclose()
+endfunction
+"▶2 scan.scanpref   :: &self
+function s:F.scan.scanpref()
+    call self.addcon('prefixes')
+    if self.eos
+        call self.throw('prefmis')
+    endif
+    let c=self.nextc()
+    if c is '~'
+        call self.addcon("matcher").intfunc().conclose()
+    else
+        call self.ungetc(c)
+    endif
+    while !self.eos
+        let c=self.nextc()
+        if !exists('pref')
+            if !exists('prefopts')
+                let prefopts={}
+            endif
+            if c is '"'
+                let c=self.nextstr()
+                let pref=c
+            elseif c=~#'^\w'
+                let pref=c
+            elseif c is '?'
+                let prefopts.alt=1
+            elseif c is '*'
+                let prefopts.list=1
+            elseif c is '}'
                 break
+            else
+                call self.throw('invpref', c)
             endif
-        elseif c is '|'
-            call self.addpipe()
+        else
+            call self.ungetc(c).addcon(pref, prefopts).scan().conclose()
+            unlet pref prefopts
         endif
     endwhile
     return self.conclose()
 endfunction
-"▶2 scan.string    :: String → SynTree
+"▶2 scan.scanact    :: &self
+function s:F.scan.scanact()
+    let p={}
+    call self.addcon('actions', p)
+    if self.eos
+        call self.throw('actmis')
+    endif
+    let c=self.nextc()
+    if c is '~'
+        call self.addcon("matcher").intfunc().conclose()
+    else
+        call self.ungetc(c)
+    endif
+    while !self.eos
+        let c=self.nextc()
+        if !exists('action')
+            if c is '"'
+                let c=self.nextstr()
+                let action=c
+            elseif c=~#'^\w'
+                let action=c
+            elseif c is '>'
+                break
+            else
+                call self.throw('invact', c)
+            endif
+        else
+            if c is '('
+                call self.addcon(action)
+                unlet action
+                while !self.eos
+                    let c=self.nextc()
+                    if c is ')'
+                        break
+                    endif
+                    call self.ungetc(c).scan()
+                endwhile
+            else
+                call self.throw('noadescr')
+            endif
+        endif
+    endwhile
+    return self.conclose()
+endfunction
+"▶2 scan.scan       :: &self
+function s:F.scan.scan()
+    let c=self.nextc()
+    if c is '['
+        return self.scanopt()
+    elseif c is '{'
+        return self.scanpref()
+    elseif c is '<'
+        return self.scanact()
+    endif
+    call self.addcon('arg')
+    let hasparen=0
+    let hastext=0
+    if c is '('
+        let hasparen=1
+    else
+        call self.ungetc(c)
+    endif
+    while !self.eos
+        let c=self.nextc()
+        if c is '|'
+            call self.getpipe()
+        elseif c is '#'
+            call self.getmsg()
+        elseif (!hastext || hasparen || self.o.only) && c=~#'^\w'
+            let hastext=1
+            call self.ungetc(c).intfunc()
+        elseif hasparen && c is ')'
+            let hasparen=0
+            break
+        else
+            call self.ungetc(c)
+            break
+        endif
+    endwhile
+    if hasparen
+        call self.throw('unmatchp', '(')
+    endif
+    return self.conclose()
+endfunction
+"▶2 scan.getoptions :: &self
+let s:options={'only': 0,}
+function s:F.scan.getoptions()
+    let c=self.nextc()
+    if c is '-'
+        call self.nextc()  " Here must be a parenthesis
+        while !self.eos
+            let c=self.nextc()
+            if c is ')'
+                break
+            elseif has_key(self.o, c)     " -(option)
+                let self.o[c]=1
+            elseif has_key(self.o, c[2:]) " -(nooption)
+                let self.o[c]=0
+            else
+                call self.throw('uoption', c)
+            endif
+        endwhile
+    else
+        call self.ungetc(c)
+    endif
+endfunction
+"▶2 scan.string     :: String → SynTree
 function s:F.scan.string(string)
     let s   =   {    's': a:string,
-                \ 'tree': [[]],
+                \ 'tree': [],
                 \'stack': [],
+                \'ungot': [],
                 \    'l': 0,
-                \   'pc': 0,}
+                \  'eos': 0,
+                \ 'type': 'check',
+                \    'o': copy(s:options),
+                \}
     call extend(s, s:F.scan, 'error')
-    call add(s.stack, s.tree[0])
+    " FIXME Redefine these functions with more verbose ones
+    let s.throw=s:_f.throw
+    let s.warn=s:_f.warn
+    call add(s.stack, s.tree)
     let s.l=s.stack[-1]
-    call s.delblanks().scan()
+    call s.delblanks().getoptions()
+    while !s.eos
+        call s.scan()
+    endwhile
     return s.tree
 endfunction
+"▶1 FIXME this is for debugging
+if !exists('g:curtest')
+    let g:scan=s:F.scan
+endif
 "▶1
 call frawor#Lockvar(s:, 'checkers,filters')
 " vim: fmr=▶,▲ sw=4 ts=4 sts=4 et tw=80

plugin/frawor/mappings.vim

         unlet s:fts[a:mgroup.filetype][a:mgroup.id]
     endif
 endfunction
-"▶1 delmapgroups  :: {f} → + s:mgroups, …
-function s:F.delmapgroups(plugdict, fdict)
-    call map(values(a:fdict), 's:F.delmgroup(v:val)')
-endfunction
 "▶1 strfunc       :: key → (-1|3, 0, 0)
 function s:F.strfunc(key)
     if key==#"\<CR>" || key==#"\n"
     call s:F.delmgroup(mgroup)
     unlet a:fdict[mgroup.id]
 endfunction
+"▶2 delmapgroups   :: {f} → + s:mgroups, …
+function s:F.delmapgroups(plugdict, fdict)
+    call map(values(a:fdict), 's:F.delmgroup(v:val)')
+endfunction
 "▶2 Register mapgroup feature
 call s:_f.newfeature('mapgroup', {'cons': s:F.mapgroup,
             \                   'unload': s:F.delmapgroups})

plugin/frawor/os.vim

                     \join(map(a:command[1:],
                     \'((v:val=~#"^[[:alnum:]/\\-]\\+$")?'.
                     \   '(v:val):'.
-                    \   '(shellescape(v:val, 1)))'))
+                    \   '(shellescape(v:val)))'))
     else
-        let cmd=join(map(copy(a:command), 'shellescape(v:val, 1)'))
+        let cmd=join(map(copy(a:command), 'shellescape(v:val)'))
     endif
     if a:0
         new