ZyX_I avatar ZyX_I committed 200f4ac

@/fwc: Added support for default values of optional arguments, added `curidx' message argument, added short version of function type

Comments (0)

Files changed (5)

plugin/frawor/fwc/compiler.vim

             endif
             unlet sub
         endfor
-        return join(map(chunks, 'v:key%2 ? v:val : string(v:val)'), '.')
+        return join(map(chunks, 'v:key%2 ? v:val : s:F.string(v:val)'), '.')
     else
         return self.argbase.(self.getsubs(get(a:000, 1, self.subs)))
     endif
 endfunction
 "▶1 addthrow       :: msg::String, msgarg, needcurarg, ... + self → self + self
 function s:compiler.addthrow(msg, needcurarg, ...)
-    let args=string(a:msg).', '
+    let args=s:F.string(a:msg).', '
     if a:needcurarg
-        let args.=string(a:1).', '.self.argstr(1).', '.join(a:000[1:], ', ')
+        let args.=s:F.string(a:1).', '.self.argstr(1).', '.join(a:000[1:], ', ')
     else
         let args.=join(a:000, ', ')
     endif
         let r.=', '.join(map(a:matcher[1][2:-2],
                     \        'type(v:val)=='.type([]).'?'.
                     \           'self.getvar(v:val, 0, a:ldstr, a:strstr):'.
-                    \           'string(v:val)'),
+                    \           's:F.string(v:val)'),
                     \    ', ')
     endif
     if self.type is 'check' || self.type is 'filter'
 function s:compiler.getexpr(expr, ...)
     let curargstr=self.argstr()
     let this=get(a:000, 0, curargstr)
-    return substitute(substitute(a:expr[1],
-                \'\V@.@', escape(this,      '&~\'), 'g'),
-                \'\V@:@', escape(curargstr, '&~\'), 'g')
+    return substitute(substitute(substitute(a:expr[1],
+                \'\V@@@', escape(self.argbase, '&~\'), 'g'),
+                \'\V@.@', escape(this,         '&~\'), 'g'),
+                \'\V@:@', escape(curargstr,    '&~\'), 'g')
 endfunction
 "▶1 getvar         :: varcontext[, splitsubs[, dotarg]] + self → String
 function s:compiler.getvar(var, ...)
         return self
     endif
     let msg=[]
-    let curargstr=self.argstr()
+    let curargstrstr=self.argstr(1)
     for msgarg in a:msg[2:]
         if msgarg[0] is 'curval'
-            call add(msg, curargstr)
+            call add(msg, self.argstr())
         elseif msgarg[0] is 'curarg'
-            call add(msg, string(curargstr))
+            call add(msg, curargstrstr)
+        elseif msgarg[0] is 'curidx'
+            call add(msg, s:F.string(idx))
         else
             call add(msg, substitute(self.getvar(msgarg), '@#@',
-                        \            escape(curargstr, '\&~'), 'g'))
+                        \            escape(curargstrstr, '\&~'), 'g'))
         endif
     endfor
-    let msgstr=string(a:msg[1]).', '.join(msg, ', ')
+    let msgstr=s:F.string(a:msg[1]).', '.join(msg, ', ')
     call add(self.msgs.own, msgstr)
     return self
 endfunction
     let i=0
     let savedonlystrings=self.o.onlystrings
     for proc in arg
+        let i+=1
         let compargs=[proc, a:idx.'.'.i]
         let comptype=proc[0]
         if comptype is 'intfunc'
             let comptype=type
             let compargs[0]=[comptype, compargs[0]]
+        elseif comptype is 'defval'
+            continue
         endif
         call call(self['compile'.comptype], compargs, self)
         if self.typechanged
             let self.o.onlystrings=0
             let self.typechanged=0
         endif
-        let i+=1
     endfor
     let self.o.onlystrings=savedonlystrings
     if len(self.msgs.own)>pmsgnum
     if has_key(a:adescr, 'arg')
         let i=0
         for arg in a:adescr.arg
+            let i+=1
             if self.o.only
                 let idx=''
             elseif a:0
             endif
             call self.compilearg(arg, idx)
             call self.incsub()
-            let i+=1
         endfor
         if !empty(self.subs)
             let nextsub=copy(self.subs[-1])
         call self.let(caidxstr, oldsub)
     endif
     let self.subs[-1]=copy(caidx)
+    let largsstr=self.getlargsstr()
     "▶2 `optional' key
     if has_key(a:adescr, 'optional')
         unlet nextsub
         let nextsub=copy(caidx)
+        " XXX nodefs will be still 0 when compiling next adescr. It is 
+        " intentional.
+        let nodefs=empty(self.defvals)
         let lopt=len(a:adescr.optional)
         if lopt>1
             let failstr=self.getlvarid('fail')
         if newsub isnot caidxstr
             call self.let(caidxstr, newsub)
         endif
-        call self.catch(s:cfreg).up()
+        call self.catch(s:cfreg)
+        if lopt==1 && has_key(a:adescr.optional[0], 'arg')
+            let defaults=reverse(map(filter(copy(a:adescr.optional[0].arg),
+                        \                   'exists("v:val[0][0]") && '.
+                        \                   'v:val[0][0] is "defval"'),
+                        \            'v:val[0][1]'))
+            let self.defvals+=defaults
+            if !empty(defaults) && nodefs
+                let base=self.argstr(0, self.subs[:-2])
+                for defvar in self.defvals
+                    call self.call('insert('.base.', '.self.getvar(defvar).', '.
+                                \            caidxstr.')')
+                endfor
+                let ldefaults=len(self.defvals)
+                call     self.increment(caidxstr, ldefaults)
+                            \.increment(largsstr, ldefaults)
+            endif
+        endif
+        call self.up()
         let self.subs[-1]=copy(caidx)
         if lopt>1
             let i=1
         let haslist=!empty(lists)
         let lastliststr=self.getlvarid('lastlist')
         let addtry=(has_key(a:adescr, 'next') || has_key(a:adescr, 'actions'))
-        let largsstr=self.getlargsstr()
         "▶3 Add messages saving if required
         if addtry
             if !addedsavemsgs
         call self.incsub()
         let astartsub=copy(self.subs[-1])
         for action in actions
-            call self.addif(actionstr.' is '.string(action[0]))
+            call self.addif(actionstr.' is '.s:F.string(action[0]))
             if len(action)>1
                 call self.compileadesc(action[1], idx.'.'.s:F.string(action[0]))
             endif
                 \           },
                 \'failcal': [],
                 \ 'lavars': {},
+                \'defvals': [],
                 \'typechanged': 0,
             \})
     let tree=s:_r.fwc_parser(a:string, a:type)[1:]

plugin/frawor/fwc/intfuncs.vim

 let s:r.type={'args': ['*get']}
 "▶2 gettype    :: &self!
 " Adds type number to the context.
-" Valid arguments: s[tring], n[umber], f[loat], d[ictionary], l[ist], fu[nction]
-"                   "", '',     -0,      .0,         {},        []
+" Valid arguments: string, number, float, dictionary, list, function
+"                  "", '',  -0,     .0,       {},      [],     **
 " Input: {typedescr}
 " Output: add({typeNumber})
 "         {typeNumber}: any number described in |type()|
 let s:typechars={
-            \'{': [type({}),  '}'],
-            \'[': [type([]),  ']'],
+            \'-': [type(0),   '0'],
             \'"': [type(""),  '"'],
             \"'": [type(''),  "'"],
-            \'-': [type(0),   '0'],
+            \'[': [type([]),  ']'],
+            \'{': [type({}),  '}'],
+            \'*': [2,         '*'],
         \}
 let s:typewords={
+            \    'number': type(0),
             \    'string': type(''),
-            \    'number': type(0),
+            \      'list': type([]),
             \'dictionary': type({}),
-            \      'list': type([]),
             \  'function': 2,
         \}
 if has('float')

plugin/frawor/fwc/parser.vim

     return self.conclose()
 endfunction
 "▶1 scanmsg    :: &self
-" Input: ( "#" | "^" | {wordchar}+ ( "(" ( "." | "%" | {var} | "," ) ")"? )? )
+" Input: ( "#" | "^" | {wordchar}+ ( "(" ( [.%#] | {var} | "," ) ")"? )? )
 " Output: context(msg, (String, {msgarg}* | 0 | 1))
 "         {msgarg} :: context(curval)
 "                   | context(curarg)
                     call self.addcon('curval').conclose()
                 elseif c is '%'
                     call self.addcon('curarg').conclose()
+                elseif c is '#'
+                    call self.addcon('curidx').conclose()
                 elseif c isnot ','
                     call self.ungetc(c).getvar()
                 endif
 plugin/frawor/fwc/compiler:typefail
 plugin/frawor/fwc/compiler:typefail
 plugin/frawor/fwc/compiler:typefail
+plugin/frawor/fwc/compiler:typefail
 plugin/frawor/fwc/compiler:typesfail
 ::: Section <Checks/Check composition>
 plugin/frawor/fwc/compiler:exprfail
 plugin/frawor/fwc/compiler:exprfail
 plugin/frawor/fwc/compiler:exprfail
 ::: Section <Messages>
-Frawor:plugin/fwccheck:str:a:args[0]<
+Frawor:plugin/fwccheck:str:@@@[0]<
 plugin/frawor/fwc/compiler:nbool
 Frawor:plugin/fwccheck:str:\v(<
 plugin/frawor/fwc/compiler:nreg
 plugin/frawor/fwc/compiler:nbool
 plugin/frawor/fwc/compiler:nbool
 plugin/frawor/fwc/compiler:nbool
-Frawor:plugin/fwccheck:str:a:args[0]<
+Frawor:plugin/fwccheck:str:@@@[0]<
 plugin/frawor/fwc/compiler:nbool
 plugin/frawor/fwc/compiler:nbool
 ::: Section <Option `only'>

test/fwctests.dat

 ['type function',   'check'], [function("tr")],     1
 ['type function',   'check'], [function("s:Eval")], 1
 ['type function',   'check'], ["tr"],               0
+['type **',         'check'], [function("tr")],     1
+['type **',         'check'], [function("s:Eval")], 1
+['type **',         'check'], ["tr"],               0
 # Not checking float here: it may be absent on some setups
 ['type {}, []',     'check'], [{}],                 1
 ['type {}, []',     'check'], [[]],                 1
 ['[bool] [is=2]',                        'check'], [1],          1
 ['[bool] [is=2]',                        'check'], [2],          1
 ['[bool] [is=2]',                        'check'], [3],          0
+['[:=(2) bool]',                        'filter'], [],           [2]
+['[:=(2) bool [:=(3) bool]]',           'filter'], [],           [2, 3]
+['[:=(2) bool [:=(3) bool]]',           'filter'], [0],          [0, 3]
+['[:=(2) bool [:=(3) bool]]',           'filter'], [0, 1],       [0, 1]
 #▶2 Complex length checks
 ['bool bool [bool]',                    'filter'], [0, {}, {}],  [0, 0, 0]
 ['bool [bool bool]',                    'filter'], [0, {}, {}],  [0, 0, 0]
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.