88 t = self.parse(tokeniter) |
88 t = self.parse(tokeniter) |
89 if self._methods: |
89 if self._methods: |
90 return self.eval(t) |
90 return self.eval(t) |
91 return t |
91 return t |
92 |
92 |
93 def buildargsdict(trees, funcname, keys, keyvaluenode, keynode): |
93 def splitargspec(spec): |
|
94 """Parse spec of function arguments into (poskeys, varkey, keys) |
|
95 |
|
96 >>> splitargspec('') |
|
97 ([], None, []) |
|
98 >>> splitargspec('foo bar') |
|
99 ([], None, ['foo', 'bar']) |
|
100 >>> splitargspec('foo *bar baz') |
|
101 (['foo'], 'bar', ['baz']) |
|
102 >>> splitargspec('*foo') |
|
103 ([], 'foo', []) |
|
104 """ |
|
105 pre, sep, post = spec.partition('*') |
|
106 pres = pre.split() |
|
107 posts = post.split() |
|
108 if sep: |
|
109 if not posts: |
|
110 raise error.ProgrammingError('no *varkey name provided') |
|
111 return pres, posts[0], posts[1:] |
|
112 return [], None, pres |
|
113 |
|
114 def buildargsdict(trees, funcname, argspec, keyvaluenode, keynode): |
94 """Build dict from list containing positional and keyword arguments |
115 """Build dict from list containing positional and keyword arguments |
95 |
116 |
96 Invalid keywords or too many positional arguments are rejected, but |
117 Arguments are specified by a tuple of ``(poskeys, varkey, keys)`` where |
97 missing arguments are just omitted. |
118 |
|
119 - ``poskeys``: list of names of positional arguments |
|
120 - ``varkey``: optional argument name that takes up remainder |
|
121 - ``keys``: list of names that can be either positional or keyword arguments |
|
122 |
|
123 If ``varkey`` specified, all ``keys`` must be given as keyword arguments. |
|
124 |
|
125 Invalid keywords, too few positional arguments, or too many positional |
|
126 arguments are rejected, but missing keyword arguments are just omitted. |
98 """ |
127 """ |
|
128 poskeys, varkey, keys = argspec |
99 kwstart = next((i for i, x in enumerate(trees) if x[0] == keyvaluenode), |
129 kwstart = next((i for i, x in enumerate(trees) if x[0] == keyvaluenode), |
100 len(trees)) |
130 len(trees)) |
101 if len(trees) > len(keys): |
131 if kwstart < len(poskeys): |
|
132 raise error.ParseError(_("%(func)s takes at least %(nargs)d positional " |
|
133 "arguments") |
|
134 % {'func': funcname, 'nargs': len(poskeys)}) |
|
135 if not varkey and len(trees) > len(poskeys) + len(keys): |
102 raise error.ParseError(_("%(func)s takes at most %(nargs)d arguments") |
136 raise error.ParseError(_("%(func)s takes at most %(nargs)d arguments") |
103 % {'func': funcname, 'nargs': len(keys)}) |
137 % {'func': funcname, |
|
138 'nargs': len(poskeys) + len(keys)}) |
104 args = {} |
139 args = {} |
105 # consume positional arguments |
140 # consume positional arguments |
106 for k, x in zip(keys, trees[:kwstart]): |
141 for k, x in zip(poskeys, trees[:kwstart]): |
107 args[k] = x |
142 args[k] = x |
108 assert len(args) == kwstart |
143 if varkey: |
|
144 args[varkey] = trees[len(args):kwstart] |
|
145 else: |
|
146 for k, x in zip(keys, trees[len(args):kwstart]): |
|
147 args[k] = x |
109 # remainder should be keyword arguments |
148 # remainder should be keyword arguments |
110 for x in trees[kwstart:]: |
149 for x in trees[kwstart:]: |
111 if x[0] != keyvaluenode or x[1][0] != keynode: |
150 if x[0] != keyvaluenode or x[1][0] != keynode: |
112 raise error.ParseError(_("%(func)s got an invalid argument") |
151 raise error.ParseError(_("%(func)s got an invalid argument") |
113 % {'func': funcname}) |
152 % {'func': funcname}) |