Commits

ZyX_I committed 7c71cb2

@/fwc/compiler: Finished `prefixes' key. Checker and filter parts of FWC are finished completely now

Comments (0)

Files changed (3)

plugin/frawor/fwc/compiler.vim

             \              'processed %u out of %u',
             \   'FWCfail': 'Error while processing arguments of function %s '.
             \              'for plugin %s',
+            \ 'ambprefix': 'Error while compiling FWC string: prefix `%s'' '.
+            \              'already defined',
         \}
 call extend(s:_messages, map({
             \'decargnlst': 'decorator argument is not a List',
 endfunction
 "▶1 addtypecond    :: types, idx + self → self + self
 function s:compiler.addtypecond(types, idx)
+    if self.o.onlystrings
+        return self
+    endif
     let curargstr=self.argstr()
     let typenames=map(copy(a:types), 's:_messages._types[v:val]')
     if len(a:types)>=2
     let self.vars[a:name][id]=a:init
     return '@%@'.self.getsubs([a:name, id])
 endfunction
+"▶1 addprefix
+function s:compiler.addprefix(preflist, prefix)
+    if index(a:preflist, a:prefix)!=-1
+        call self._throw('ambprefix', a:prefix)
+    endif
+    call add(a:preflist, a:prefix)
+endfunction
 "▶1 compileadesc   :: adescr[, idx[, purgemax]] + self → self + self
 let s:actdefmatcher=['matcher', ['intfunc', 'start', 0, 0]]
 let s:prefdefmatcher=s:actdefmatcher
     endif
     "▶2 `prefixes' key
     if has_key(a:adescr, 'prefixes')
+        "▶3 Define variables
         unlet nextsub
         let nextsub=copy(caidx)
         let preflist=[]
         let plstr=self.getfunstatvar('prefixes', preflist)
         let prefdictstr=self.getlvarid('prefdict')
         let base=self.argstr(0, self.subs[:-2])
+        let astr=self.getlvarid('arg')
+        let idx=get(a:000, 0, '').'(prefixes)'
+        let defaults=filter(copy(a:adescr.prefixes),
+                    \       'exists("v:val[2][0]") && v:val[2][0] isnot "arg"')
+        let lists=filter(copy(a:adescr.prefixes), 'v:val[1].list')
+        let haslist=!empty(lists)
+        let lastliststr=self.getlvarid('lastlist')
         let addtry=(has_key(a:adescr, 'next') || has_key(a:adescr, 'actions'))
+        "▶3 Add messages saving if required
         if addtry
             if !addedsavemsgs
                 call self.addsavemsgs()
             endif
             call self.try().pushms('throw')
         endif
-        let dstr=self.getlvarid('d')
-        let astr=dstr.'.arg'
-        let idx=get(a:000, 0, '').'(prefixes)'
+        "▶3 Initialize variables inside constructed function
         call self.let(prefdictstr, '{}')
-                    \.let(dstr, '{}')
                     \.call('insert('.base.', '.prefdictstr.', '.
                     \                s:F.getsub(nextsub).')')
                     \.increment(caidxstr)
-        let defaults=filter(copy(a:adescr.prefixes),
-                    \       'exists("v:val[2][0]") && v:val[2][0] isnot "arg"')
-        let haslist=!empty(filter(copy(a:adescr.prefixes), 'v:val[1].list'))
+        "▶3 Add default values
         for [prefix, prefopts, defval; dummylist] in defaults
             call self.let(prefdictstr.self.getsubs([prefix]),
                         \ self.getvar(defval))
         endfor
+        "▲3
         call self.while('len('.base.')>'.caidxstr)
-        if !self.o.onlystrings
+        "▶3 Get `astr' variable
+        if haslist
+            call self.if('type('.self.argstr().')=='.type(''))
+        elseif !self.o.onlystrings
             call self.addtypecond([type('')], idx)
         endif
-        if haslist
-            " TODO
-        endif
         call self.let(astr, self.getmatcher(get(a:adescr, 'prefixesmatcher',
                     \                           s:prefdefmatcher), plstr,
-                    \                       'remove('.base.', '.caidxstr.')'))
-                    \.nextthrow(astr.' is 0', 'pnf', idx)
+                    \                       self.argstr()))
+        let removestr='remove('.base.', '.caidxstr.')'
+        if haslist
+            call self.up().else().let(astr, 0).up().endif()
+                        \.if(astr.' isnot 0').call(removestr).up().endif()
+        else
+            call self.call(removestr).nextthrow(astr.' is 0', 'pnf', idx)
+        endif
+        "▲3
         for [prefix, prefopts; args] in a:adescr.prefixes
-            call add(preflist, prefix)
+            "▶3 Add prefix to prefix list
+            call self.addprefix(preflist, prefix)
             if prefopts.alt
-                call add(preflist, 'no'.prefix)
+                call self.addprefix(preflist, 'no'.prefix)
             endif
-            let prefstr=prefdictstr.self.getsubs([prefix])
+            "▶3 Remove default value specification if any
+            let hasdefault=0
             if !empty(args) && args[0][0] isnot 'arg'
+                let hasdefault=1
                 call remove(args, 0)
             endif
-            call self.addif(astr.' is '.s:F.string(prefix))
-            " TODO prefopts.list
+            "▲3
+            let prefstr=prefdictstr.self.getsubs([prefix])
+            let prefixstr=s:F.string(prefix)
+            "▶3 Construct prefix condition
+            let cond=astr.' is '.prefixstr
+            if prefopts.list
+                let cond.=' || ('.astr.' is 0 && '.
+                            \   lastliststr.' is '.prefixstr.')'
+            endif
+            call self.addif(cond)
+            "▶3 Process prefix arguments
             for i in range(1, prefopts.argnum)
                 call self.compilearg(args[i-1], idx.s:F.string(prefix))
                             \.incsub()
             endfor
-            if !prefopts.list && prefopts.argnum==1
-                call self.let(prefstr, 'remove('.base.', '.caidxstr.')')
-            elseif prefopts.argnum>0
-                call self.let(prefstr, 'remove('.base.', '.caidxstr.', '.
-                            \                  caidxstr.'+'.(prefopts.argnum-1).
-                            \                ')')
+            "▶3 Move prefix arguments to prefix dictionary
+            if prefopts.list
+                let removestr='remove('.base.', '.caidxstr.', '.
+                            \           caidxstr.'+'.(prefopts.argnum-1).')'
+                let cond='has_key('.prefdictstr.', '.prefixstr.')'
+                if hasdefault
+                    let cond.=' && type('.prefstr.')=='.type([])
+                endif
+                call self.if(cond)
+                            \.increment(prefstr, removestr)
+                        \.else()
+                            \.let(prefstr, removestr)
+                        \.up()
+                call self.let(lastliststr, prefixstr)
             else
-                call self.let(prefstr, 1)
+                if haslist
+                    call self.let(lastliststr, 0)
+                endif
+                if prefopts.argnum==1
+                    call self.let(prefstr, 'remove('.base.', '.caidxstr.')')
+                elseif prefopts.argnum>0
+                    call self.let(prefstr,
+                                \'remove('.base.', '.caidxstr.', '.
+                                \        caidxstr.'+'.(prefopts.argnum-1).')')
+                else
+                    call self.let(prefstr, 1)
+                endif
             endif
+            "▲3
             let self.subs[-1]=copy(caidx)
             call self.up()
+            "▶3 Process `no{prefix}'
             if prefopts.alt
                 call self.addif(astr.' is '.s:F.string('no'.prefix))
                             \.let(prefstr, 0)
                             \.up()
             endif
+            "▶3 Discard arguments length cache
             let key=string([self.argbase]+self.subs[:-2])[1:-2]
             if has_key(self.lavars, key)
                 unlet self.lavars[key]
             endif
+            "▲3
         endfor
-        call self.up()
+        call self.up().up()
         if addtry
             call self.addrestmsgs(1).catch(s:cfreg).popms()
-                        \.if('has_key('.dstr.', "arg")')
+                        \.if('exists('.string(astr).')')
                             \.call('insert('.base.', '.astr.')')
                         \.up().up()
         endif
-        " TODO
     endif
     "▶2 `next' key
     if has_key(a:adescr, 'next')
 call s:_f.adddecorator('FWC', s:F.makedec)
 "▶1
 " TODO implement recursion protection
-" TODO implement onlystrings option (disables type checks)
 call frawor#Lockvar(s:, 'lastid,vars')
 " vim: fmr=▶,▲ sw=4 ts=4 sts=4 et tw=80
 plugin/frawor/fwc/compiler:invlen
 plugin/frawor/fwc/compiler:anf
 ::: Section <Prefixes>
+plugin/frawor/fwc/compiler:pnf
+plugin/frawor/fwc/compiler:nreg
+plugin/frawor/fwc/compiler:pnf
 <<< messages

test/fwctests.dat

 ['<abc (bool) def (bool bool) - (isreg)>',   'filter'], ['b', ''], 0
 ['<~smart abc (bool)>',                      'filter'], ['b', ''], ['abc', 0]
 #▶1 Prefixes
-['{abc bool}',                      'filter'], ['a', {}], [{'abc': 0}]
-['{abc :=(2) bool}',                'filter'], ['a', {}], [{'abc': 0}]
-['{abc :=(2) bool}',                'filter'], [],        [{'abc': 2}]
-['{!abc !def :=(2)}',               'filter'], ['a'],     [{'abc': 1, 'def': 2}]
-['{!abc !def :=(2)}',               'filter'], ['noa'],   [{'abc': 0, 'def': 2}]
-['{!abc}',                          'filter'], ['a'],     [{'abc': 1}]
-['{!abc}',                          'filter'], ['noa'],   [{'abc': 0}]
-['{!+2 abc bool bool}',             'filter'], ['a',2,3], [{'abc': [1, 1]}]
-['{!+2 abc bool bool}',             'filter'], ['noa'],   [{'abc': 0}]
+['{abc bool}',                    'filter'], ['a', {}],   [{'abc': 0}]
+['{abc bool}',                    'filter'], ['b', {}],   0
+['{abc :=(2) bool}',              'filter'], ['a', {}],   [{'abc': 0}]
+['{abc :=(2) bool}',              'filter'], [],          [{'abc': 2}]
+['{!abc !def :=(2)}',             'filter'], ['a'],       [{'abc': 1, 'def': 2}]
+['{!abc !def :=(2)}',             'filter'], ['noa'],     [{'abc': 0, 'def': 2}]
+['{!abc}',                        'filter'], ['a'],       [{'abc': 1}]
+['{!abc}',                        'filter'], ['noa'],     [{'abc': 0}]
+['{!?abc}',                       'filter'], ['a'],       [{'abc': 1}]
+['{!?abc}',                       'filter'], ['noa'],     [{'abc': 0}]
+['{!?abc}',                       'filter'], [],          [{}]
+['{!+2 abc bool bool}',           'filter'], ['a',2,3],   [{'abc': [1, 1]}]
+['{!+2 abc bool bool}',           'filter'], ['noa'],     [{'abc': 0}]
+['{abc isreg}',                   'filter'], ['a','\v('], 0
+['{!abc !abd}',                   'filter'], ['a', 'a'],  0
+['{*b isreg !?a}', 'filter'], ['b', 'n', 'n'], [{'b': ['n'], 'a': 0}]
+['{*b isreg !?a}', 'filter'], ['b', 'n', 'c'], [{'b': ['n', 'c']}]
 # vim: cms=#%s fmr=▶,▲