Commits

ZyX_I committed 90d24e6

@/fwc: Implemented path check (untested)

  • Participants
  • Parent commits 3869d9f

Comments (0)

Files changed (5)

File plugin/frawor/fwc/compiler.vim

             \exists('g:frawor__donotload')
     finish
 endif
-execute frawor#Setup('0.0', {'@/fwc/parser': '0.0'}, 1)
+execute frawor#Setup('0.0', {'@/fwc/parser': '0.0',
+            \                '@/os'        : '0.0'}, 1)
 let s:constructor={}
 "▶1 Messages
 let s:_messages={
             \   'ninlist': 'argument is not in list',
             \ 'invlstlen': 'invalid list length: expected %u, but got %u',
             \'eitherfail': 'all alternatives failed',
+            \     'isdir': 'not a directory: %s',
+            \    'isfile': 'directories are not accepted: %s',
+            \    'nwrite': '%s is not writable',
+            \   'nowrite': '%s is neither writable nor '.
+            \              'contained in a writable directory',
+            \     'nread': '%s is not readable',
+            \ 'nexecable': '%s is not executable',
         \}, '"Error while processing check %s for %s: ".v:val'))
 let s:_messages._types=['number', 'string', 'function reference', 'list',
             \           'dictionary']
 "▶1 Matchers
 "▶1 string         :: String → String
 function s:F.string(str)
-    return substitute(substitute(substitute(string(a:str),
-                \"\n",     '''."\\n".''', 'g'),
-                \"^''\\.", '',            ''),
-                \"\\.''$", '',            '')
+    return substitute(substitute(substitute(substitute(string(a:str),
+                \"@",      '''."\\x40".''', 'g'),
+                \"\n",     '''."\\n".''',   'g'),
+                \"^''\\.", '',              '' ),
+                \"\\.''$", '',              '' )
 endfunction
 "▶1 cleanup        :: list::[_, {arg}*] → + list
 function s:F.cleanup(list)
 endfunction
 "▶1 addtuple       :: tupledesc, idx, defaultArgType + self → self + self
 function s:constructor.addtuple(tuple, idx, default)
-    let i=0
+    call add(self.subs, 0)
     for arg in a:tuple[1]
-        call add(self.subs, i)
-        call self.compilearg(arg, a:idx.'(tuple).'.i, a:default)
-        call remove(self.subs, -1)
-        let i+=1
+        call self.compilearg(arg, a:idx.'(tuple).'.self.subs[-1], a:default)
+        let self.subs[-1]+=1
     endfor
+    call remove(self.subs, -1)
     return self
 endfunction
 "▶1 addlist        :: listdesc, idx, defaultArgType + self → self + self
     let istr=self.getlvarid('i')
     call self.add('let '.largstr.'=len('.self.argstr().')',
                 \ 'let '.istr.'=0',
-                \ 'while '.istr.'<'.largstr)
-                \.deeper()
+                \ 'while '.istr.'<'.largstr).deeper()
     call add(self.subs, [istr])
     call self.compilearg(a:list[1], a:idx.'(list)', a:default)
     call self.add('let '.istr.'+=1')
             call self.compilecheck(['check', a:pipe[1]], a:idx)
         endif
     endif
+    "▲2
     return self
 endfunction
 let s:constructor.compilefilter=s:constructor.compilepipe
+"▶1 addpathp       :: idx + self → self + self
+function s:constructor.addpathp(idx)
+    let curargstr=self.argstr()
+    let dirnamestr=self.getlvarid('dirname')
+    let prevdirstr=self.getlvarid('prevdir')
+    let foundstr=self.getlvarid('found')
+    call self.nextcond('!@%@.os.path.exists('.curargstr.')')
+                \.add('let '.dirnamestr.'='.'@%@.os.path.normpath('.
+                \                                                 curargstr.')',
+                \     'let '.prevdirstr.'=""',
+                \     'let '.foundstr.'=0',
+                \     'while '.dirnamestr.'!=#'.prevdirstr).deeper()
+                    \.nextcond('filewritable('.dirnamestr.')==2')
+                        \.add('let '.foundstr.'=1',
+                        \     'break').up()
+                    \.nextcond('@%@.os.path.exists('.dirnamestr.')')
+                        \.add('break')
+                    \.up().close()
+                    \.add('let '.prevdirstr.'='.dirnamestr,
+                    \     'let '.dirnamestr.'='.'@%@.os.path.dirname('.
+                    \                                            dirnamestr.')')
+                \.up().close()
+                \.nextthrow('!'.foundstr, 'nowrite', a:idx, '@#@', curargstr)
+                \.close()
+    return self
+endfunction
 "▶1 addtypecond    :: types, idx + self → self + self
 function s:constructor.addtypecond(types, idx)
     let curargstr=self.argstr()
             elseif desc[0] is 'path'
                 let addedcond=1
                 call self.addtypecond([type('')], idx)
-                " TODO
+                let spec=desc[1]
+                if spec[0] is 'd'
+                    let spec=spec[1:]
+                    if spec[0] is 'w'
+                        call self.nextthrow('filewritable('.curargstr.')!=2',
+                                    \      'nwrite', idx, '@#@', curargstr)
+                        let spec=spec[1:]
+                    elseif spec[0] is 'W'
+                        call self.nextthrow('filewritable('.curargstr.')!=2 &&'.
+                                    \      '(@%@.os.path.exists('.curargstr.')'.
+                                    \       '|| filewritable('.
+                                    \               '@%@.os.path.dirname('.
+                                    \                        curargstr.'))!=2)',
+                                    \      'nowrite', idx, '@#@', curargstr)
+                        let spec=spec[1:]
+                    elseif spec[0] is 'p'
+                        call self.addpathp(idx)
+                        let spec=spec[1:]
+                    else
+                        call self.nextthrow('!@%@.os.path.isdir('.curargstr.')',
+                                    \       'isdir', idx, '@#@', curargstr)
+                    endif
+                else
+                    let fileonly=0
+                    if spec[0] is 'f'
+                        let spec=spec[1:]
+                        let fileonly=1
+                    endif
+                    if fileonly
+                        if spec[0] is 'r'
+                            call self.nextthrow('!filereadable('.curargstr.')',
+                                        \       'nread', idx, '@#@', curargstr)
+                            let spec=spec[1:]
+                        elseif spec[-1:] isnot 'x'
+                            call self.nextthrow('@%@.os.path.isdir('.
+                                        \                         curargstr.')'.
+                                        \       'isfile', idx, '@#@', curargstr)
+                        endif
+                    endif
+                    if spec[0] is 'w'
+                        call self.nextthrow('filewritable('.curargstr.')',
+                                    \       'nwrite', idx, '@#@', curargstr)
+                        let spec=spec[1:]
+                    elseif spec[0] is 'W'
+                        call self.nextthrow('filewritable('.curargstr.') &&'.
+                                    \      '(@%@.os.path.exists('.curargstr.')'.
+                                    \       '|| filewritable('.
+                                    \               '@%@.os.path.dirname('.
+                                    \                        curargstr.'))!=2)',
+                                    \      'nowrite', idx, '@#@', curargstr)
+                        let spec=spec[1:]
+                    elseif spec[0] is 'p'
+                        call self.addpathp(idx)
+                        let spec=spec[1:]
+                    endif
+                    if spec is 'x'
+                        call self.nextthrow('!executable('.curargstr.')',
+                                    \       'nexecable', idx, '@#@', curargstr)
+                    endif
+                endif
+                call self.up()
             "▶3 `type'
             elseif desc[0] is 'type'
                 let addedcond=1
     let id=printf('%s%X', a:type, s:lastid)
     let s:lastid+=1
     let s:vars[id]={
-                \'F': {'warn': s:_f.warn},
-                \'p': a:plugdict.g,
-                \'m': {'types': s:_messages._types},
+                \ 'F': {'warn': s:_f.warn},
+                \ 'p': a:plugdict.g,
+                \ 'm': {'types': s:_messages._types},
+                \'os': s:_r.os,
             \}
     call add(a:fdict.ids, id)
     execute "function d.f(args)\n    ".

File plugin/frawor/fwc/parser.vim

 "▶1 getpath    :: &self!
 " Gets path specification:
 " Input: [( "d" | "f" )] [ "r" ] [( "w" | "W" | "p" )] [ "x" ]
-"        & ! ( "d" ) "r"
+"        & ! ( "d" | ^ ) "r"
 "        & ! ( "d" ) [( "w" | "W" | "p" )] "x"
 " 1. "d" for directory and "f" for regular file, otherwise both may be accepted
 " 2. "r" for readable file (not directory)
 " Output: add({pathspec})
 function s:parser.getpath()
     let c=self.readc()
-    if c=~#'^[df]\=r\=[wWp]\=x\=$' && c!~#'^d\%(.\{,2}x\|r\)'
+    if c=~#'\v^[df]?r?[wWp]?x?$' && c!~#'\v^%(d%(.{,2}x|r)|r)'
         call self.add(c)
     else
         call self.add('r').ungetc(c)

File test/fwccheck.ok

 plugin/frawor/fwc/compiler:typefail
 plugin/frawor/fwc/compiler:ninlist
 plugin/frawor/fwc/compiler:ninlist
+::: Section <Checks/Built-in checks/path>
 ::: Section <Checks/Built-in checks/either>
 plugin/frawor/fwc/compiler:nbool
 plugin/frawor/fwc/compiler:typefail

File test/fwctests.dat

 ['in =["a",0]',     'check'], [0],                  1
 ['_',               'check'], [[[[]]]],             1
 ['any',             'check'], [[[[]]]],             1
+#▶3 path
+['path p',          'check'], ['abc'],              1
 #▶3 either
 ['either bool, isreg',      'check'], ['abc'],         1
 ['either bool, isreg',      'check'], [2],             0

File test/reload-frawor.ok

 unloadpre: plugin/frawor/autocommands
 unloadpre: plugin/frawor/options
 unloadpre: plugin/writefile-feature
-unloadpre: plugin/frawor/os
 unloadpre: plugin/frawor/functions
 unloadpre: plugin/frawor/checks
 unloadpre: plugin/frawor/fwc
 unloadpre: plugin/frawor/fwc/compiler
 unloadpre: plugin/frawor/fwc/parser
+unloadpre: plugin/frawor/os
 unloadpre: plugin/frawor/resources
 unloadpre: plugin/frawor
 unload: autoload/frawor