Commits

ZyX_I  committed ec7c1e4

@/fwc: Added `tuple' check and pipe

  • Participants
  • Parent commits 40b9ff1

Comments (0)

Files changed (4)

File plugin/frawor/fwc/compiler.vim

             \   'nrange': '%s is not in range [%s, %s]',
             \  'nindict': '%s is not in dictionary',
             \  'ninlist': 'argument is not in list',
-        \}, '"Error while processing check %u for %s: ".v:val'))
+            \'invlstlen': 'invalid list length: expected %u, but got %u',
+        \}, '"Error while processing check %s for %s: ".v:val'))
 let s:_messages._types=['number', 'string', 'function reference', 'list',
             \           'dictionary']
 if has('float')
     call add(s:_messages._types, 'float')
 endif
+"▶1 Matchers
 "▶1 string         :: String → String
 function s:F.string(str)
     return substitute(substitute(substitute(string(a:str),
 endfunction
 "▶1 addthrow       :: msg::String, msgarg, ... + self → self + self
 function s:constructor.addthrow(msg, ...)
-    let args=map(copy(a:000), '((v:val is "@#@")?(string(self.argstr())):'.
-                \                               '(v:val))')
+    let args=copy(a:000)
+    let curidx=index(args, '@#@')
+    if curidx!=-1
+        let args=map(args[:(curidx-1)],'string(v:val)')+[string(self.argstr())]+
+                    \args[(curidx+1):]
+    endif
     return self.add('call add(@$@messages, ['.string(a:msg).', '.
                 \                             join(args, ', ').'])',
                 \   'throw "CHECKFAILED"')
                         \       (self.getvar(desc[1][1]))).', '.
                         \join(map(desc[2:], 'self.compilestring(v:val)'), ', ').
                         \')')
+        elseif desc[0] is 'tuple'
+            call self.nextthrow('len('.curargstr.')!='.len(desc[1]),
+                        \       'invlstlen', a:idx, '@#@', len(desc[1]),
+                        \                    'len('.curargstr.')').close()
+            let i=0
+            for arg in desc[1]
+                call add(self.subs, i)
+                call self.compilepipe(arg, a:idx.'.'.i)
+                call remove(self.subs, -1)
+                let i+=1
+            endfor
         elseif desc[0] is 'in'
             if len(desc)==2 || (desc[2][1][0] is 'intfunc' &&
                         \       desc[2][1][1] is 'exact' &&
                 " TODO
             "▶3 `tuple'
             elseif desc[0] is 'tuple'
-                " TODO
+                call self.addtypecond([type([])], idx)
+                call self.nextthrow('len('.curargstr.')!='.len(desc[1]),
+                            \       'invlstlen', idx, '@#@', len(desc[1]),
+                            \                    'len('.curargstr.')')
+                let i=0
+                for arg in desc[1]
+                    call add(self.subs,  i)
+                    call self.compilecheck(arg, idx.'.'.i)
+                    call remove(self.subs, -1)
+                    let i+=1
+                endfor
             "▶3 `either'
             elseif desc[0] is 'either'
                 " TODO
             "▶3 `path'
             elseif desc[0] is 'path'
+                call self.addtypecond([type('')], idx)
                 " TODO
             "▶3 `_', `any'
             elseif desc[0] is '_' || desc[0] is 'any'
             "▲3
         endif
         "▲2
-        let idx+=1
+        let idx=s:F.incidx(idx)
     endfor
     if addedcond
         call self.close()
             \      'take': ['intfunc', 'type',   [type('')]],
             \       'run': ['intfunc', 'isfunc', 0         ],
             \      'earg': ['intfunc', 'type',   [type('')]],
+            \     'tuple': ['intfunc', 'type',   [type([])]],
         \}
 function s:constructor.compileadesc(adescr)
     if !has_key(a:adescr, 'minimum')

File plugin/frawor/fwc/parser.vim

 "▶3 pipe.substitute
 " Runs substitute on {argument}
 let s:args.pipe.substitute=['reg', 'string', 'string']
+"▶3 pipe.tuple
+" Checks whether {argument} is a list with a fixed length and then process given 
+" pipes for each of the arguments
+let s:args.pipe.tuple=['*arg']
 "▶3 pipe.in
 " Picks up first element from {var}::List that matches {argument}. If {matcher} 
 " is absent then {argument} may be of any type. In other case it should be 
 "▶3 check.tuple
 " Checks whether {argument} is a list with a fixed length and each element 
 " matching given specification
-let s:args.check.tuple=['*check']
+let s:args.check.tuple=['*arg']
 "▶3 check.either
 " Checks whether {argument} matches one of given specifications
 let s:args.check.either=['*check']
 function s:parser.scan()
     "▶2 optional, prefixes, actions, next
     let c=self.readc()
-    let type=self.l[0]
+    let type=get(self.l, 0, '')
     if type is 'top' || type is 'optional'
                 \|| (type is 'action' && len(self.l)>1)
         if c is '['

File test/fwccheck.ok

 plugin/frawor/fwc/compiler:runfail
 plugin/frawor/fwc/compiler:evalfail
 plugin/frawor/fwc/compiler:nsfunc
+plugin/frawor/fwc/compiler:invlstlen
+plugin/frawor/fwc/compiler:typefail
 ::: Section <Pipes/Built-in pipes/key>
 plugin/frawor/fwc/compiler:nindict
 plugin/frawor/fwc/compiler:typefail
 plugin/frawor/fwc/compiler:typefail
 plugin/frawor/fwc/compiler:ninlist
 plugin/frawor/fwc/compiler:ninlist
+::: Section <Checks/Built-in checks/tuple>
+plugin/frawor/fwc/compiler:nreg
+plugin/frawor/fwc/compiler:invlstlen
+plugin/frawor/fwc/compiler:typefail
 ::: Section <Checks/Built-in checks/range>
 plugin/frawor/fwc/compiler:typefail
 plugin/frawor/fwc/compiler:nrange

File test/fwctests.dat

 ['earg',                   'filter'], ['('],                0
 ['isfunc',                 'filter'], [0],                  0
 ['isfunc',                 'filter'], [function('tr')],     [function("tr")]
+['tuple bool, bool',       'filter'], [['', 'cba']],        [[0, 1]]
+['tuple bool, bool',       'filter'], [['abc']],            0
+['tuple bool, bool',       'filter'], ['abc'],              0
 #▶3 key
 ['key={"abc": 1}~exact',   'filter'], ['abc'],              ['abc']
 ['key={"abc": 1}',         'filter'], ['abc'],              ['abc']
 ['in =["a",0]',     'check'], [0],                  1
 ['_',               'check'], [[[[]]]],             1
 ['any',             'check'], [[[[]]]],             1
+#▶3 tuple
+['tuple isreg, isreg', 'check'], [['abc', 'cba']],  1
+['tuple isreg, isreg', 'check'], [['abc', '\(']],   0
+['tuple isreg, isreg', 'check'], [['abc']],         0
+['tuple isreg, isreg', 'check'], ['abc'],           0
 #▶3 range
 :let s:n1=-1
 :let s:n2=1