Commits

ZyX_I committed e9387e3

@/fwc: Improved constructor

Comments (0)

Files changed (2)

plugin/frawor/fwc/compiler.vim

             \                '@/os'             : '0.0',
             \                '@/decorators'     : '0.0'}, 1)
 let s:compiler={}
+let s:cf='CHECKFAILED'
+let s:cfstr=string(s:cf)
+let s:cfreg='\v^'.s:cf.'$'
 "▶1 Messages
 let s:_messages={
             \   'notypes': 'Expected at least one type specification',
                     \args[(curidx+1):]
     endif
     if !empty(self.pmsgs) && !empty(self.pmsgs[-1])
-        call self.add('call add(@$@pmessages, ['.self.pmsgs[-1].'])')
+        call self.call('add(@$@pmessages, ['.self.pmsgs[-1].'])')
     endif
-    return self.add('call add(@$@messages, ['.string(a:msg).', '.
-                \                             join(args, ', ').'])',
-                \   'throw "CHECKFAILED"').up()
+    return self.call('add(@$@messages, ['.string(a:msg).', '.join(args, ', ').
+                \                     '])')
+                \.throw(s:cfstr).up()
 endfunction
 "▶1 nextthrow      :: condition::expr, throwargs + self → self + self
 function s:compiler.nextthrow(cond, ...)
-    return call(self.nextcond(a:cond).addthrow, a:000, self)
+    return call(self.addif(a:cond).addthrow, a:000, self)
 endfunction
-"▶1 addsavemsgs     :: msglenstr, pmsglenstr + self → self + self
-function s:compiler.addsavemsgs(msglenstr, pmsglenstr)
-    return self.add('let '.a:msglenstr.'=len(@$@messages)',
-                \   'let '.a:pmsglenstr.'=len(@$@pmessages)')
+"▶1 addsavemsgs    :: &self
+function s:compiler.addsavemsgs()
+    let msglenstr=self.getlvarid('msglen')
+    let pmsglenstr=self.getlvarid('pmsglen')
+    call add(self.restmsg, [msglenstr, pmsglenstr])
+    return   self.let(msglenstr,  'len(@$@messages)')
+                \.let(pmsglenstr, 'len(@$@pmessages)')
 endfunction
-"▶1 addrestmsgs    :: msglenstr, pmsglenstr + self → self + self
-function s:compiler.addrestmsgs(msglenstr, pmsglenstr)
-    return self.nextcond('len(@$@messages)>'.a:msglenstr)
-                       \.add('call remove(@$@messages, '.a:msglenstr.', -1)')
-               \.up().close()
-               \.nextcond('len(@$@pmessages)>'.a:pmsglenstr)
-                       \.add('call remove(@$@pmessages, '.a:pmsglenstr.', -1)')
-               \.up().close()
+"▶1 addrestmsgs    :: a:0::Bool + self → self + self
+function s:compiler.addrestmsgs(...)
+    let [msglenstr, pmsglenstr]=self.restmsg[-1]
+    if !a:0
+        call remove(self.restmsg, -1)
+    endif
+    return   self.if('len(@$@messages)>'.msglenstr)
+                    \.call('remove(@$@messages, '.msglenstr.', -1)')
+                \.up().if('len(@$@pmessages)>'.pmsglenstr)
+                    \.call('remove(@$@pmessages, '.pmsglenstr.', -1)')
+                \.up().endif()
 endfunction
 "▶1 witharg        :: (argbase[, [subscript]]) + self → self + self
 function s:compiler.witharg(newarg)
 "▶1 addlist        :: listdesc, idx, defaultArgType + self → self + self
 function s:compiler.addlist(list, idx, default)
     let largstr=self.getlvarid('larg')
+    let lststr=self.argstr()
     let istr=self.getlvarid('i')
-    call self.add('let '.largstr.'=len('.self.argstr().')',
-                \ 'let '.istr.'=0',
-                \ '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.let(largstr, 'len('.lststr.')')
+                \.let(istr, 0)
+                \.while(istr.'<'.largstr)
+                    \.compilearg(a:list[1], a:idx.'(list)', a:default)
+                    \.increment(istr)
+                \.up().up()
     call remove(self.subs, -1)
-    call self.up().close()
+    return self
 endfunction
 "▶1 adddict        :: dicdesc, idx, defaultArgType + self → self + self
 function s:compiler.adddict(dic, idx, default)
         let curargstr=self.argstr()
         return self.nextthrow('!empty('.curargstr.')',
                     \         'keynmatch',a:idx,'@#@', 'keys('.curargstr.')[0]')
-                    \.close()
     endif
     let keystr=self.getlvarid('key')
-    call self.add('for '.keystr.' in keys('.self.argstr().')').deeper()
+    call self.for(keystr, 'keys('.self.argstr().')')
     call add(self.subs, [keystr])
     let foundstr=self.getlvarid('found')
     let msglenstr=self.getlvarid('msglen')
     let pmsglenstr=self.getlvarid('pmsglen')
-    let addedcond=0
     let hascheck=0
     let i=-1
     for check in a:dic[1][1:]
         let i+=1
         if check[0] is 'eq'
-            let addedcond=1
-            call self.nextcond(keystr.' is '.s:F.string(check[1]))
+            call self.addif(keystr.' is '.s:F.string(check[1]))
         elseif check[0] is 'regex'
-            let addedcond=1
-            call self.nextcond(keystr.'=~#'.s:F.string(check[1]))
+            call self.addif(keystr.'=~#'.s:F.string(check[1]))
         elseif check[0] is 'func'
-            let addedcond=1
-            call self.nextcond(self.getfunc(check[1], 0, keystr))
+            call self.addif(self.getfunc(check[1], 0, keystr))
         elseif check[0] is 'expr'
-            let addedcond=1
-            call self.nextcond(self.getexpr(check[1], keystr))
+            call self.addif(self.getexpr(check[1], keystr))
         elseif check[0] is 'any'
-            if addedcond
-                call self.close()
-                let addedcond=0
-            endif
             call self.compilearg(check[1], a:idx.'.'.i.'(val)', a:default)
-                        \.add('continue')
+                        \.continue()
             break
         elseif check[0] is 'check'
-            if addedcond
-                call self.close()
-            endif
             if !hascheck
-                call self.addsavemsgs(msglenstr, pmsglenstr)
+                call self.addsavemsgs()
             endif
             let hascheck=1
-            call self.add('try').deeper()
-                            \.add('let '.foundstr.'=0')
-                            \.witharg([keystr])
-                            \.compilearg(check[1], a:idx.'.'.i.'(key)', 'check')
-                            \.without()
-                            \.add('let '.foundstr.'=1')
-                            \.compilearg(check[2],a:idx.'.'.i.'(val)',a:default)
-                            \.up()
-                        \.add('catch /^CHECKFAILED$/').deeper()
-                            \.nextcond(foundstr)
-                                \.add('throw "CHECKFAILED"')
-                            \.up().close()
-                            \.addrestmsgs(msglenstr, pmsglenstr)
-                        \.up().close()
-                        \.nextcond(foundstr).add('continue').up().close()
-            let addedcond=0
+            call self.try()
+                        \.let(foundstr, 0)
+                        \.witharg([keystr])
+                        \.compilearg(check[1], a:idx.'.'.i.'(key)', 'check')
+                        \.without()
+                        \.let(foundstr, 1)
+                        \.compilearg(check[2],a:idx.'.'.i.'(val)',a:default)
+                    \.up().catch(s:cfreg)
+                        \.addif(foundstr)
+                            \.throw(s:cfstr)
+                        \.addrestmsgs(1)
+                    \.up().addif(foundstr)
+                        \.continue().up()
             continue
         endif
-        call self.compilearg(check[2], a:idx.'.'.i.'(val)', a:default)
-                    \.add('continue').up()
+        call self.compilearg(check[2], a:idx.'.'.i.'(val)',a:default).continue()
+                    \.up()
     endfor
-    if addedcond
-        call self.close()
+    if hascheck
+        call remove(self.restmsg, -1)
     endif
-    call self.addthrow('keynmatch', a:idx, '@#@', keystr).close()
+    call self.addthrow('keynmatch', a:idx, '@#@', keystr)
     call remove(self.subs, -1)
     return self
 endfunction
     let curargstr=self.argstr()
     "▶2 `func' pipe
     if a:pipe[1][0] is 'func'
-        call self.add('let '.curargstr.'='.self.getfunc(a:pipe[1],0, curargstr))
+        call self.let(curargstr, self.getfunc(a:pipe[1],0, curargstr))
     "▶2 `expr' pipe
     elseif a:pipe[1][0] is 'expr'
-        call self.add('let '.curargstr.'='.self.getexpr(a:pipe[1], curargstr))
+        call self.let(curargstr, self.getexpr(a:pipe[1], curargstr))
     "▶2 Built-in pipes
     elseif a:pipe[1][0] is 'intfunc'
         let desc=a:pipe[1][1:]
             call self.compilepipe(desc, a:idx)
         "▶3 `if'
         elseif desc[0] is 'if'
-            let msglenstr=self.getlvarid('msglen')
-            let pmsglenstr=self.getlvarid('pmsglen')
             let condstr=self.getlvarid('cond')
-            call self.add('try').deeper()
-                        \.addsavemsgs(msglenstr, pmsglenstr)
+            call self.addsavemsgs()
+                    \.try()
                         \.compilearg(desc[1], a:idx.'(cond)', 'check')
-                        \.add('let '.condstr.'=1').up()
-                    \.add('catch /^CHECKFAILED$/')
-                        \.deeper('let '.condstr.'=0')
-                    \.up().close()
-                    \.addrestmsgs(msglenstr, pmsglenstr)
+                        \.let(condstr, 1)
+                    \.up().catch(s:cfreg)
+                        \.let(condstr, 0)
+                    \.up().addrestmsgs()
             if len(desc[2])>1
-                call self.nextcond(condstr).compilearg(desc[2], a:idx.'(if)',
-                            \                          'pipe').up()
+                call self.addif(condstr).compilearg(desc[2],a:idx.'(if)','pipe')
+                            \.up()
                 if len(desc[3])>1
-                    call self.nextcond().compilearg(desc[3], a:idx.'(else)',
-                                \                   'pipe').up()
+                    call self.addif()
+                                \.compilearg(desc[3], a:idx.'(else)', 'pipe')
+                                \.up()
                 endif
             else
-                call self.nextcond('!'.condstr).compilearg(desc[3],
-                            \                              a:idx.'(else)',
-                            \                              'pipe').up()
+                call self.addif('!'.condstr)
+                            \.compilearg(desc[3], a:idx.'(else)', 'pipe')
+                            \.up()
             endif
-            call self.close()
+            call self.up()
         "▶3 `run'
         elseif desc[0] is 'run'
-            call self.add('try')
-                        \.deeper('let '.curargstr.'=call('.curargstr.', '.
+            call self.try()
+                        \.let(curargstr, 'call('.curargstr.', '.
                         \                          self.getvar(desc[1]).', {})')
-                        \.up().add('catch /.*/').deeper()
+                    \.up().catch()
                         \.addthrow('runfail', a:idx, '@#@', 'v:exception')
-                        \.close()
         "▶3 `earg'
         elseif desc[0] is 'earg'
-            call self.add('try')
-                        \.deeper('let '.curargstr.'=eval('.curargstr.')')
-                        \.up().add('catch /.*/').deeper()
+            call self.try()
+                        \.let(curargstr, 'eval('.curargstr.')')
+                    \.up().catch()
                         \.addthrow('evalfail', a:idx, '@#@', 'v:exception')
-                        \.close()
         "▶3 `tuple'
         elseif desc[0] is 'tuple'
             call self.nextthrow('len('.curargstr.')!='.len(desc[1]),
                         \       'invlstlen', a:idx, '@#@', len(desc[1]),
-                        \                    'len('.curargstr.')').close()
+                        \                    'len('.curargstr.')')
                         \.addtuple(desc, a:idx, 'pipe')
         "▶3 `list'
         elseif desc[0] is 'list'
                         \       desc[2][1][2] is 0)
                 call self.compilecheck(['check', a:pipe[1]], a:idx)
             else
-                call self.addtypecond([type('')], a:idx).close()
                 let matchstr=self.getlvarid('match')
-                call self.add('let '.matchstr.'='.
-                            \              self.getmatcher(desc[2],
+                call self.addtypecond([type('')], a:idx)
+                            \.let(matchstr,self.getmatcher(desc[2],
                             \                              self.getvar(desc[1]),
                             \                              curargstr))
                             \.nextthrow(matchstr.' is 0',
-                            \           'nmatch', a:idx,'@#@',curargstr).close()
-                            \.add('let '.curargstr.'='.matchstr)
+                            \           'nmatch', a:idx, '@#@', curargstr)
+                            \.let(curargstr, matchstr)
             endif
         "▶3 `take'
         elseif desc[0] is 'take'
-            call self.addtypecond([type('')], a:idx).close()
             let varstr=self.getvar(desc[1])
             let matchstr=self.getlvarid('match')
-            call self.add('let '.matchstr.'='.self.getmatcher(desc[2], varstr,
-                        \                                     curargstr))
+            call self.addtypecond([type('')], a:idx)
+                        \.let(matchstr, self.getmatcher(desc[2], varstr,
+                        \                               curargstr))
                         \.nextthrow(matchstr.' is 0',
-                        \           'nmatch', a:idx, '@#@', curargstr).close()
-                        \.add('let '.curargstr.'='.varstr.'['.matchstr.']')
+                        \           'nmatch', a:idx, '@#@', curargstr)
+                        \.let(curargstr, varstr.'['.matchstr.']')
         "▶3 `substitute'
         elseif desc[0] is 'substitute'
-            call self.add('let '.curargstr.'=substitute('.curargstr.', '.
+            call self.let(curargstr, 'substitute('.curargstr.', '.
                         \((type(desc[1][1])==type(''))?
                         \       (s:F.string(desc[1][1])):
                         \       (self.getvar(desc[1][1]))).', '.
                         \')')
         "▶3 `bool'
         elseif desc[0] is 'bool'
-            call self.add('let '.curargstr.'=!empty('.curargstr.')')
+            call self.let(curargstr, '!empty('.curargstr.')')
         "▶3 `value'
         elseif desc[0] is 'value'
             call self.witharg(self.getvar(desc[1], 1))
     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()
+    call self.addif('!@%@.os.path.exists('.curargstr.')')
+                \.let(dirnamestr, '@%@.os.path.normpath('.curargstr.')')
+                \.let(prevdirstr, '""')
+                \.let(foundstr, 0)
+                \.while(dirnamestr.' isnot '.prevdirstr)
+                    \.addif('filewritable('.dirnamestr.')==2')
+                        \.let(foundstr, 1)
+                        \.break().up()
+                    \.addif('@%@.os.path.exists('.dirnamestr.')')
+                        \.break().up()
+                    \.let(prevdirstr, dirnamestr)
+                    \.let(dirnamestr, '@%@.os.path.dirname('.dirnamestr.')')
+                \.up()
                 \.nextthrow('!'.foundstr, 'nowrite', a:idx, '@#@', curargstr)
-                \.close()
-                \.up()
+            \.up()
     return self
 endfunction
 "▶1 addtypecond    :: types, idx + self → self + self
                     \       'typefail', a:idx, '@#@', string(typenames[0]),
                     \                   '@%@.m.types[type('.curargstr.')]')
     else
-        call self.throw('notypes')
+        call self._throw('notypes')
     endif
     return self
 endfunction
 "▶1 compilecheck   :: checkcontext, idx + self → self + self
 function s:compiler.compilecheck(check, idx)
     let curargstr=self.argstr()
-    let addedcond=0
     let idx=a:idx
     for check in a:check[1:]
         "▶2 `func' check
         if check[0] is 'func'
-            let addedcond=1
             call self.nextthrow(self.getfunc(check, 0, curargstr).' is 0',
                         \       'funcfail', idx, '@#@')
         "▶2 `expr' check
         elseif check[0] is 'expr'
-            let addedcond=1
             call self.nextthrow(self.getexpr(check, curargstr).' is 0',
                         \       'exprfail', idx, '@#@')
         "▶2 `intfunc' check
             let desc=check[1:]
             "▶3 `func'
             if desc[0] is 'func'
-                let addedcond=1
                 call self.nextthrow(self.getfunc(desc[1], 0, curargstr).' is 0',
                             \       'funcfail', idx, '@#@')
             "▶3 `eval'
             elseif desc[0] is 'eval'
-                let addedcond=1
                 call self.nextthrow(self.getexpr(desc[1], curargstr).' is 0',
                             \       'exprfail', idx, '@#@')
             "▶3 `not'
             elseif desc[0] is 'not'
-                if addedcond
-                    call self.close()
-                    let addedcond=0
-                endif
                 let msglenstr=self.getlvarid('msglen')
                 let pmsglenstr=self.getlvarid('pmsglen')
-                call self.add('try').addsavemsgs(msglenstr, pmsglenstr).deeper()
-                                \.compilearg(desc[1], idx.'(not)')
-                                \.add('throw "NOTFAILED"').up()
-                            \.add('catch /^CHECKFAILED$/')
-                                \.deeper().addrestmsgs(msglenstr, pmsglenstr)
-                            \.add('catch /^NOTFAILED$/').deeper()
-                                \.addthrow('notfail', idx, '@#@')
-                            \.close()
+                call self.addsavemsgs()
+                        \.try()
+                            \.compilearg(desc[1], idx.'(not)')
+                            \.throw('"NOTFAILED"')
+                        \.catch(s:cfreg)
+                            \.addrestmsgs()
+                        \.up().catch('^NOTFAILED$')
+                            \.addthrow('notfail', idx, '@#@')
             "▶3 `either'
             elseif desc[0] is 'either'
-                if addedcond
-                    call self.close()
-                    let addedcond=0
-                endif
                 let sucstr=self.getlvarid('succeeded')
                 let msglenstr=self.getlvarid('msglen')
                 let pmsglenstr=self.getlvarid('pmsglen')
-                call self.add('let '.sucstr.'=1')
-                            \.addsavemsgs(msglenstr, pmsglenstr)
+                call self.let(sucstr, 1).addsavemsgs()
                 if !empty(desc[1])
-                    call self.add('try').deeper()
+                    call self.try()
                                 \.compilearg(desc[1][0], idx.'(either).0',
                                 \            'check')
-                                \.up()
-                                \.add('catch /^CHECKFAILED$/')
-                                \.deeper('let '.sucstr.'=0')
-                                \.up().close()
+                            \.up().catch(s:cfreg)
+                                \.let(sucstr, 0).up()
                 endif
                 let i=1
                 for arg in desc[1][1:]
-                    call self.add('if !'.sucstr)
-                                \.deeper('let '.sucstr.'=1',
-                                \        'try').deeper()
-                                \.compilearg(arg, idx.'(either).'.i, 'check')
+                    call self.addif('!'.sucstr)
+                                \.let(sucstr, 1)
+                                \.try()
+                                    \.compilearg(arg, idx.'(either).'.i,'check')
+                                \.up().catch(s:cfreg)
+                                    \.let(sucstr, 0)
                                 \.up()
-                                \.add('catch /^CHECKFAILED$/')
-                                \.deeper('let '.sucstr.'=0')
-                                \.up().close()
-                                \.up().close()
+                            \.up()
                     let i+=1
                 endfor
-                call self.nextcond(sucstr).addrestmsgs(msglenstr, pmsglenstr)
-                            \.up()
-                            \.add('else').deeper()
-                                \.addthrow('eitherfail', idx, '@#@')
-                            \.close()
+                call self.addif(sucstr).addrestmsgs().up()
+                            \.addif().addthrow('eitherfail',idx,'@#@').up().up()
             "▶3 `tuple'
             elseif desc[0] is 'tuple'
                 call self.addtypecond([type([])], idx)
                             \.addtuple(desc, idx, 'check')
             "▶3 `list'
             elseif desc[0] is 'list'
-                call self.addtypecond([type([])], idx).close()
-                let addedcond=0
-                call self.addlist(desc, idx, 'check')
+                call self.addtypecond([type([])], idx).addlist(desc,idx,'check')
             "▶3 `dict'
             elseif desc[0] is 'dict'
-                call self.addtypecond([type({})], idx).close()
-                let addedcond=0
-                call self.adddict(desc, idx, 'check')
+                call self.addtypecond([type({})], idx).adddict(desc,idx,'check')
             "▶3 `in'
             elseif desc[0] is 'in'
-                let addedcond=1
                 call self.nextthrow('index('.self.getvar(desc[1]).', '.
                             \                curargstr.')==-1',
                             \       'ninlist', idx, '@#@')
             "▶3 `key'
             elseif desc[0] is 'key'
-                let addedcond=1
                 call self.addtypecond([type('')], idx)
-                call self.nextthrow('!has_key('.self.getvar(desc[1]).', '.
-                            \                   curargstr.')',
-                            \       'nindict', idx, '@#@', curargstr)
+                            \.nextthrow('!has_key('.self.getvar(desc[1]).', '.
+                            \                       curargstr.')',
+                            \           'nindict', idx, '@#@', curargstr)
             "▶3 `haskey'
             elseif desc[0] is 'haskey'
-                let addedcond=1
                 call self.addtypecond([type({})], idx)
                 if len(desc[1])>1
                     let keys='['.join(map(copy(desc[1]),
                 endif
             "▶3 `range'
             elseif desc[0] is 'range'
-                let addedcond=1
                 "▶4 Determine whether we accept floating-point values
                 let acceptfloat=has('float') &&
                             \(desc[1][0] is 'float' || desc[1][1] is 'float')
                 endif
             "▶3 `match'
             elseif desc[0] is 'match'
-                let addedcond=1
-                call self.addtypecond([type('')], idx)
                 let regex=((type(desc[1][1])==type(''))?
                             \(s:F.string(desc[1][1])):
                             \(self.getvar(desc[1][1])))
-                call self.nextthrow(curargstr.'!~#'.regex,
-                            \       'nregmatch', idx, '@#@', curargstr, regex)
+                call self.addtypecond([type('')], idx)
+                            \.nextthrow(curargstr.'!~#'.regex,
+                            \           'nregmatch',idx,'@#@', curargstr, regex)
             "▶3 `path'
             elseif desc[0] is 'path'
-                let addedcond=1
                 call self.addtypecond([type('')], idx)
                 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)
+                                    \       'nwrite', idx, '@#@', curargstr)
                         let spec=spec[1:]
                     elseif spec[0] is 'W'
                         call self.nextthrow('filewritable('.curargstr.')!=2 &&'.
                                     \.nextthrow('!@%@.os.path.isdir('.
                                     \                             curargstr.')',
                                     \           'isdir', idx, '@#@', curargstr)
-                                    \.close()
-                        let addedcond=0
                         let spec=spec[1:]
                     else
                         call self.nextthrow('!@%@.os.path.isdir('.curargstr.')',
                                     \      'nowrite', idx, '@#@', curargstr)
                         let spec=spec[1:]
                     elseif spec[0] is 'p'
-                        call self.addpathp(idx).close()
-                        let addedcond=0
+                        call self.addpathp(idx).up()
                         let spec=spec[1:]
                     endif
                     if spec is 'x'
                 endif
             "▶3 `type'
             elseif desc[0] is 'type'
-                let addedcond=1
                 call self.addtypecond(desc[1], idx)
             "▶3 `isfunc'
             elseif desc[0] is 'isfunc'
-                let addedcond=1
                 let frefpref='string('.curargstr.')[10:11]'
                 if desc[1]
                     call self.addtypecond([2], idx)
                                 \        '|| (type('.curargstr.')=='.type('').
                                 \            '&& '.curargstr.'=~#'.
                                 \             '''\v^%(%([sla]@!\w:)?%(\w|\.)+|'.
-                                \                    '%(s@!\w:)?\w+)$'''.
+                                \                    '%(s@!\w:)?\w+|'.
+                                \                    '%(<SNR>\w+))$'''.
                                 \            '&& exists("*".'.curargstr.')))',
                                 \       'nsfunc', idx, '@#@',
                                 \                 'string('.curargstr.')')
             "▶3 `isreg'
             elseif desc[0] is 'isreg'
                 call self.addtypecond([type('')], idx)
-                call self.close()
-                let addedcond=0
-                call self.add('try')
-                          \.deeper('call matchstr("", '.curargstr.')').up()
-                        \.add('catch /.*/').deeper()
-                          \.addthrow('nreg', idx, '@#@', curargstr,
-                          \                  'v:exception')
-                        \.close()
+                            \.try().call('matchstr("", '.curargstr.')').up()
+                            \.catch().addthrow('nreg', idx, '@#@', curargstr,
+                            \                  'v:exception')
             "▶3 `bool'
             elseif desc[0] is 'bool'
-                let addedcond=1
                 call self.nextthrow('index([0, 1], '.curargstr.')==-1',
                             \       'nbool', idx,'@#@', 'string('.curargstr.')')
             "▶3 `is'
             elseif desc[0] is 'is'
-                let addedcond=1
                 let var=self.getvar(desc[1])
                 call self.nextthrow(curargstr.' isnot '.var,
                             \       'isnot', idx, '@#@', var,
                             \                'string('.curargstr.')')
             "▶3 `value'
             elseif desc[0] is 'value'
-                if addedcond
-                    call self.close()
-                    let addedcond=0
-                endif
                 call self.witharg(self.getvar(desc[1], 1))
                             \.compilearg(desc[2], idx.'(value)', 'check')
                             \.without()
         "▲2
         let idx=s:F.incidx(idx)
     endfor
-    if addedcond
-        call self.close()
-    endif
     return self
 endfunction
 "▶1 compilearg     :: argcontext, idx[, defcomptype] + self → self + self
 "▶1 addlencheck    :: minlen, maxlen + self → self + self
 function s:compiler.addlencheck(minimum, maximum)
     let largsstr=self.getlvarid('largs')
-    call self.add('let '.largsstr.'=len('.self.argstr(0, self.subs[:-2]).')')
+    call self.let(largsstr, 'len('.self.argstr(0, self.subs[:-2]).')')
     if a:maximum==a:minimum
         call self.nextthrow(largsstr.' isnot '.a:maximum,
                     \       'invlen', a:minimum, largsstr)
                         \       'toolong',  a:maximum, largsstr)
         endif
     endif
-    return self.close()
+    return self
 endfunction
 "▶1 compileadesc   :: adescr + self → self + self
 " XXX in order for this function to work self.argstr(self.subs[:-2]) should 
                 \'argbase': '@@@',
                 \  'pmsgs': [],
                 \  'preva': [],
+                \'restmsg': [],
             \})
     call extend(t, s:compiler, 'error')
-    let t.throw=s:_f.throw
-    call add(t.stack, t.ctree)
-    let t.l=t.stack[-1]
+    let t._throw=s:_f.throw
     "▲2
     call s:F.cleanup(t.tree)
     let t.o=remove(t.tree, 0)
     let t.tree=t.tree[0]
     if t.type is 'check' || t.type is 'filter'
-        call   t.add('let @$@messages=[]',
-                    \'let @$@pmessages=[]',
-                    \'try').deeper()
+        call        t.let('@$@messages',  '[]')
+                    \.let('@$@pmessages', '[]')
+                    \.try()
         if !t.o.only
             if t.type is 'check' || t.type is 'filter'
                 call t.compileadesc(t.tree)
             else
             endif
         endif
+        call t.up().catch(s:cfreg)
+                    \.for('@$@targs', '@$@messages')
+                        \.call('call(@%@.F.warn, @$@targs, {})').up()
+                    \.for('@$@targs', '@$@pmessages')
+                        \.call('call(@%@.p._f.warn, @$@targs, {})').up()
+        if a:doreturn is 1
+            call t.return(0)
+        else
+            call t.call('@%@.F.throw('.a:doreturn.')')
+        endif
         call t.up()
-        call t.add('catch /^CHECKFAILED$/')
-                \.deeper('for @$@targs in @$@messages')
-                  \.deeper('call call(@%@.F.warn, @$@targs, {})')
-                \.up().close()
-                \.add('for @$@targs in @$@pmessages')
-                  \.deeper('call call(@%@.p._f.warn, @$@targs, {})')
-                \.up().close()
-                \.add((a:doreturn is 1)?('return 0'):
-                \                       ('call @%@.F.throw('.a:doreturn.')'))
-              \.up().close()
     else
-        call t.add('let @@@=[]')
+        call t.let('@@@', '[]')
     endif
     if a:doreturn is 1
         if t.type is 'check'
-            call t.add('return 1')
+            call t.return(1)
         elseif t.type is 'filter'
-            call t.add('return @@@')
+            call t.return('@@@')
         else
-            call t.add('return @@@')
+            call t.return('@@@')
         endif
     endif
-    return t.tolstofstr()
+    return t.tolist()
 endfunction
 "▶1 createvars     :: plugdict → id + s:lastid, s:vars
 function s:F.createvars(plugdict)

plugin/frawor/fwc/constructor.vim

 endif
 execute frawor#Setup('0.0', {'@/resources': '0.0'}, 1)
 let s:constructor={}
-"▶1 add            :: item, ... + self → self + self
+"▶1 add        :: item, ... + self → self + self
 function s:constructor.add(...)
     let self.l+=a:000
     return self
 endfunction
-"▶1 up             :: &self
+"▶1 up         :: &self
 function s:constructor.up()
     call remove(self.stack, -1)
     let self.l=self.stack[-1]
     return self
 endfunction
-"▶1 deeper         :: ()[, conelement1[, ...]] + self → self + self
-function s:constructor.deeper(...)
-    if type(get(self.l, -1))==type([])
-        let self.l[-1]+=a:000
-        call add(self.stack, self.l[-1])
-    else
-        let con=copy(a:000)
-        call self.add(con)
-        call add(self.stack, con)
-    endif
-    let self.l=self.stack[-1]
+"▶1 down       :: &self(list)
+function s:constructor.down(list)
+    call add(self.stack, a:list)
+    let self.l=a:list
     return self
 endfunction
-"▶1 close          :: &self
-let s:cmdends={
-            \    'if': 'endif',
-            \'elseif': 'endif',
-            \'else'  : 'endif',
-            \'try'    : 'endtry',
-            \'catch'  : 'endtry',
-            \'finally': 'endtry',
-            \'function': 'endfunction',
-            \     'for': 'endfor',
-            \   'while': 'endwhile',
-            \'augroup': 'augroup END',
-            \  'redir': 'redir END',
-        \}
-function s:constructor.close()
-    let command=matchstr(self.l[-2], '\S\+')
-    if has_key(s:cmdends, command)
-        return self.add(s:cmdends[command])
-    else
-        return self
+"▶1 deeper     :: ()[, conelement1[, ...]] + self → self + self
+function s:constructor.deeper(...)
+    let con=copy(a:000)
+    call self.add(con)
+    return self.down(con)
+endfunction
+"▶1 out        :: &self
+function s:constructor.out()
+    if type(get(self.l, 0))==type('')
+        return self.up()
     endif
+    return self
 endfunction
-"▶1 nextcond       :: [condition] + self → self + self
-function s:constructor.nextcond(...)
-    if !empty(self.l)
-        if type(self.l[-1])==type([])
-            let prevline=self.l[-2]
+"▶1 if         :: &self(condition)
+function s:constructor.if(condition)
+    return self.out().deeper('if', a:condition).deeper()
+endfunction
+"▶1 else       :: &self
+function s:constructor.else()
+    return self.add('else').deeper()
+endfunction
+"▶1 elseif     :: &self(condition)
+function s:constructor.elseif(condition)
+    return self.add('elseif', a:condition).deeper()
+endfunction
+"▶1 endif      :: &self
+function s:constructor.endif()
+    if get(self.l, 0) is 'if'
+        return self.add('endif').up()
+    endif
+    return self
+endfunction
+"▶1 addif      :: &self(condition?)
+function s:constructor.addif(...)
+    if a:0
+        if get(self.l, 0) is 'if' && get(self.l, -2) isnot 'else' &&
+                    \                get(self.l, -1) isnot 'endif'
+            return self.elseif(a:1)
         else
-            let prevline=self.l[-1]
-        endif
-        let command=prevline[:(stridx(prevline, ' ')-1)]
-    endif
-    if exists('command') && (command is 'if' || command is 'elseif')
-        if a:0
-            return self.add('elseif '.a:1).deeper()
-        else
-            return self.add('else').deeper()
+            return self.if(a:1)
         endif
     else
-        if a:0
-            return self.add('if '.a:1).deeper()
+        if get(self.l, 0) is 'if'
+            return self.else()
         else
             return self
         endif
     endif
 endfunction
-"▶1 tolstofstr     :: () + self → [String]
-function s:constructor.tolstofstr()
+"▶1 try        :: &self()
+function s:constructor.try()
+    return self.out().deeper('try').deeper()
+endfunction
+"▶1 catch      :: &self(regex?)
+function s:constructor.catch(...)
+    return self.add('catch', '/'.escape(get(a:000, 0, '.*'), '/').'/').deeper()
+endfunction
+"▶1 finally    :: &self
+function s:constructor.finally()
+    return self.add('finally').deeper()
+endfunction
+"▶1 while      :: &self(condition)
+function s:constructor.while(condition)
+    return self.out().deeper('while', a:condition).deeper()
+endfunction
+"▶1 for        :: &self(vars, list)
+function s:constructor.for(vars, list)
+    return self.out().deeper('for', a:vars, a:list).deeper()
+endfunction
+"▶1 continue   :: &self
+function s:constructor.continue()
+    return self.out().deeper('continue').up()
+endfunction
+"▶1 break      :: &self
+function s:constructor.break()
+    return self.out().deeper('break').up()
+endfunction
+"▶1 return     :: &self(expr)
+function s:constructor.return(expr)
+    return self.out().deeper('return', a:expr).up()
+endfunction
+"▶1 let        :: &self(var, val)
+function s:constructor.let(var, val)
+    return self.out().deeper('let', a:var, a:val).up()
+endfunction
+"▶1 increment  :: &self(var[, val])
+function s:constructor.increment(var, ...)
+    return self.out().deeper('inc', a:var, get(a:000, 0, 1)).up()
+endfunction
+"▶1 call       :: &self(expr)
+function s:constructor.call(expr)
+    return self.out().deeper('call', a:expr).up()
+endfunction
+"▶1 throw      :: &self(expr)
+function s:constructor.throw(expr)
+    return self.out().deeper('throw', a:expr).up().up()
+endfunction
+"▶1 tolist     :: () + self → [String]
+function s:constructor.tolist()
     let r=[]
     let items=map(deepcopy(self.ctree), '[0, v:val]')
+    let toextend=[]
     while !empty(items)
         let [indent, item]=remove(items, 0)
-        if type(item)==type([])
-            call extend(items, map(item, '['.(indent+1).', v:val]'), 0)
+        let istr=repeat('    ', indent)
+        if type(item)==type('')
+            call add(r, istr.item)
         else
-            call add(r, repeat('    ', indent).item)
+            let type=remove(item, 0)
+            if type is 'if'
+                call add(r, istr.'if '.remove(item, 0))
+                if !empty(item)
+                    let toextend+=map(remove(item, 0),'['.(indent+1).', v:val]')
+                endif
+                while !empty(item)
+                    let type=remove(item, 0)
+                    if type is 'elseif'
+                        call add(toextend, [indent, 'elseif '.remove(item, 0)])
+                    elseif type is 'else'
+                        call add(toextend, [indent, 'else'])
+                    elseif type is 'endif'
+                        break
+                    endif
+                    let toextend+=map(remove(item, 0),'['.(indent+1).', v:val]')
+                endwhile
+                call add(toextend, [indent, 'endif'])
+            elseif type is 'try'
+                call add(r, istr.'try')
+                if !empty(item)
+                    let toextend+=map(remove(item, 0),'['.(indent+1).', v:val]')
+                endif
+                while !empty(item)
+                    let type=remove(item, 0)
+                    if type is 'catch'
+                        call add(toextend, [indent, 'catch '.remove(item, 0)])
+                    elseif type is 'finally'
+                        call add(toextend, [indent, 'finally'])
+                    elseif type is 'endtry'
+                        break
+                    endif
+                    let toextend+=map(remove(item, 0),'['.(indent+1).', v:val]')
+                endwhile
+                call add(toextend, [indent, 'endtry'])
+            elseif type is 'while'
+                call add(r, istr.'while '.remove(item, 0))
+                let toextend+=map(remove(item, 0),'['.(indent+1).', v:val]')
+                call add(toextend, [indent, 'endwhile'])
+            elseif type is 'for'
+                call add(r, istr.'for '.remove(item, 0).' in '.remove(item, 0))
+                let toextend+=map(remove(item, 0),'['.(indent+1).', v:val]')
+                call add(toextend, [indent, 'endfor'])
+            elseif type is 'let'
+                call add(r, istr.'let '.remove(item, 0).'='.remove(item, 0))
+            elseif type is 'inc'
+                call add(r, istr.'let '.remove(item, 0).'+='.remove(item, 0))
+            elseif type is 'call' || type is 'throw' || type is 'return'
+                call add(r, istr.type.' '.remove(item, 0))
+            elseif type is 'continue' || type is 'break'
+                call add(r, istr.type)
+            endif
+            if !empty(toextend)
+                call extend(items, remove(toextend, 0, -1), 0)
+            endif
         endif
         unlet item
     endwhile
 endfunction
 "▶1 new
 call extend(s:constructor, {'ctree': [],
-            \               'stack': [],
-            \                   'l': [],})
+            \               'stack': [],})
 function s:F.new()
-    return deepcopy(s:constructor)
+    let r=deepcopy(s:constructor)
+    call add(r.stack, r.ctree)
+    let r.l=r.stack[-1]
+    return r
 endfunction
 call s:_f.postresource('new_constructor', s:F.new)
 "▶1