Commits

ZyX_I committed 6daf27d

@/fwc/compiler: Made function fail if there are some arguments left that do not match optional specification

  • Participants
  • Parent commits ba74a54

Comments (0)

Files changed (3)

File plugin/frawor/fwc/compiler.vim

             \   'toolong': 'Argument list is too long: '.
             \              'expected at most %u, but got %u',
             \    'invlen': 'Invalid arguments length: expected %u, but got %u',
+            \ 'lennmatch': 'Failed to process all arguments: '.
+            \              'processed %u out of %u',
             \   'FWCfail': 'Error while processing arguments of function %s '.
             \              'for plugin %s',
         \}
         return self.argbase.(self.getsubs(get(a:000, 1, self.subs)))
     endif
 endfunction
-"▶1 incsub         :: &self
-function s:compiler.incsub()
-    if type(self.subs[-1])==type(0)
-        let self.subs[-1]+=1
+"▶1 incrementsub   :: subscript, incby → subscript
+function s:F.incrementsub(sub, incby)
+    if type(a:sub)==type(0)
+        return a:sub+a:incby
+    elseif type(a:sub)==type([]) && len(a:sub)==1
+        let num=matchstr(a:sub[0], '[+-]\d\+$')
+        return [printf('%s%+i', a:sub[0][:-1-len(num)],
+                    \           str2nr(num)+a:incby)]
+    endif
+endfunction
+"▶1 incsub         :: &self([incby])
+function s:compiler.incsub(...)
+    if empty(self.subs)
+        return self
     else
-        let num=matchstr(self.subs[-1][0], '[+-]\d\+$')
-        let self.subs[-1][0]=self.subs[-1][0][:-1-len(num)].printf('%+i', num+1)
+        let self.subs[-1]=s:F.incrementsub(self.subs[-1], get(a:000, 0, 1))
     endif
     return self
 endfunction
     let a:adescr.maximum=maximum
     return [minimum, maximum]
 endfunction
+"▶1 getlargsstr    :: () + self → varname + self
+function s:compiler.getlargsstr()
+    let key=string([self.argbase]+self.subs[:-2])[1:-2]
+    if has_key(self.lavars, key)
+        return self.lavars[key]
+    else
+        let largsstr=self.getlvarid('largs')
+        call self.let(largsstr, 'len('.self.argstr(0, self.subs[:-2]).')')
+        let self.lavars[key]=largsstr
+        return largsstr
+    endif
+endfunction
+"▶1 getsub         :: subscript → string
+function s:F.getsub(subscript)
+    return ((type(a:subscript)==type([]))?(a:subscript[0]):(a:subscript))
+endfunction
 "▶1 addlencheck    :: minlen, maxlen + self → self + self
 function s:compiler.addlencheck(minimum, maximum)
-    let largsstr=self.getlvarid('largs')
-    call self.let(largsstr, 'len('.self.argstr(0, self.subs[:-2]).')')
-    if type(self.subs[-1])==type([])
-        let minimum=printf('%s+%u', self.subs[-1][0], a:minimum)
-        let maximum=printf('%s+%u', self.subs[-1][0], a:maximum)
-    else
-        let minimum=self.subs[-1]+a:minimum
-        let maximum=self.subs[-1]+a:maximum
-    endif
+    let largsstr=self.getlargsstr()
+    let minimum=s:F.getsub(s:F.incrementsub(self.subs[-1], a:minimum))
+    let maximum=s:F.getsub(s:F.incrementsub(self.subs[-1], a:maximum))
     if a:maximum==a:minimum
         call self.addif(largsstr.' isnot '.maximum)
                     \.addthrow('invlen', 0, minimum, largsstr)
             let a:adescr.checkedfor=1
         endif
     endif
+    if !empty(self.subs)
+        let subinit=copy(self.subs[-1])
+    endif
     if has_key(a:adescr, 'arg')
         let i=0
         for arg in a:adescr.arg
                 let idx=''
             endif
             call self.compilearg(arg, idx)
-            if !self.o.only
-                call self.incsub()
-            endif
+            call self.incsub()
             let i+=1
         endfor
     endif
-    if self.o.only
+    if empty(self.subs)
         return self
     endif
     if has_key(a:adescr, 'optional')
         let caidxstr=self.getlvarid('caidx')
         let caidx=[caidxstr]
         let failstr=self.getlvarid('fail')
-        call     self.let(caidxstr, ((type(self.subs[-1])==type([]))?
-                    \                   (self.subs[-1][0]):
-                    \                   (self.subs[-1])))
-                    \.let(failstr, 0)
-        let self.subs[-1]=caidx
+        let self.subs[-1]=copy(subinit)
+        call     self.let(caidxstr, s:F.getsub(self.subs[-1]))
+                    \.let(failstr, 1)
+        let self.subs[-1]=copy(caidx)
+        call self.incsub()
         call self.addsavemsgs()
                     \.try()
                         \.pushms('throw')
                         \.compileadesc(a:adescr.optional[0],
                         \              get(a:000, 0, '').'.(optional)')
                         \.popms()
-                        \.let(caidxstr, self.subs[-1][0])
-                        \.let(failstr, 1)
-                    \.catch(s:cfreg).up()
-                    \.addrestmsgs()
-        let self.subs[-1]=caidx
+                        \.let(failstr, 0)
+            let newsub=s:F.getsub(self.subs[-1])
+            if newsub isnot caidxstr
+                call self.let(caidxstr, newsub)
+            endif
+        call self.catch(s:cfreg)
+                        \.let(caidxstr, s:F.getsub(s:F.incrementsub(subinit,1)))
+                    \.up().addrestmsgs()
+        let self.subs[-1]=copy(caidx)
+        let largsstr=self.getlargsstr()
     endif
     " TODO
+    " XXX a:0 is checked here
+    if !a:0 && type(self.subs[-1])==type([])
+        let largsstr=self.getlargsstr()
+        let proclen=s:F.getsub(self.subs[-1])
+        call self.addif(proclen.' isnot '.largsstr)
+                    \.addthrow('lennmatch', 0, proclen, largsstr)
+    endif
     return self
 endfunction
 "▶1 compilestr     :: vars, String, type, doreturn → [String]
                 \                 'own': [],
                 \           },
                 \'failcal': [],
+                \ 'lavars': {},
             \})
     let tree=s:_r.fwc_parser(a:string, a:type)[1:]
     call extend(t, s:compiler, 'error')

File test/fwccheck.ok

 plugin/frawor/fwc/compiler:nbool
 plugin/frawor/fwc/compiler:nreg
 plugin/frawor/fwc/compiler:isnot
+::: Section <Optional arguments>
+plugin/frawor/fwc/compiler:lennmatch
+plugin/frawor/fwc/compiler:lennmatch
 <<< messages

File test/fwctests.dat

 ['-(only) |bool is =1',                  'check'], [1],        1
 ['-(only) bool',                        'filter'], [],         0
 ['-(only) bool',                        'filter'], [1],        1
+#▶1 Optional arguments
+['bool [bool bool]',                    'filter'], [0, {}, {}],  [0, 0, 0]
+['bool [bool [bool]]',                  'filter'], [0, {}, {}],  [0, 0, 0]
+['bool [bool [bool]]',                  'filter'], [0, {}],      [0, 0]
+['bool [bool [bool]]',                  'filter'], [0],          [0]
+['bool [bool bool]',                    'filter'], [0, {}],      0
+['bool [bool [bool bool]]',             'filter'], [0],          [0]
+['bool [bool [bool bool]]',             'filter'], [0, 0],       [0, 0]
+['bool [bool [bool bool]]',             'filter'], [0, 0, 0],    0
+['bool [bool [bool bool]]',             'filter'], [0, 0, 0, 0], [0, 0, 0, 0]
 # vim: cms=#%s fmr=▶,▲