1616from macropy .core .walkers import Walker
1717from macropy .core import unparse
1818
19+ from ..dynassign import dyn
20+
1921def nb (body , args ):
2022 p = args [0 ] if args else q [print ] # custom print function hook
2123 newbody = []
@@ -36,6 +38,8 @@ def nb(body, args):
3638
3739# -----------------------------------------------------------------------------
3840
41+ # TODO: refactor dbg into its own module
42+
3943def dbgprint_block (ks , vs , * , filename = None , lineno = None , sep = ", " , ** kwargs ):
4044 """Default debug printer for the ``dbg`` macro, block variant.
4145
@@ -154,3 +158,53 @@ def dbgprint_expr(k, v, *, filename, lineno):
154158def dbg_expr (tree ):
155159 ln = q [u [tree .lineno ]] if hasattr (tree , "lineno" ) else q [None ]
156160 return q [dbgprint_expr (u [unparse (tree )], ast_literal [tree ], filename = __file__ , lineno = ast_literal [ln ])]
161+
162+ # -----------------------------------------------------------------------------
163+
164+ # TODO: refactor pop_while into its own module
165+
166+ # Imperative list handling tool::
167+ #
168+ # with pop_while(name, expr):
169+ # ...
170+ #
171+ # with pop_while(expr):
172+ # ...
173+ #
174+ # transforms into::
175+ #
176+ # name = expr # or (gensym) = expr in the 1-arg form
177+ # while name:
178+ # it = name.pop(0) # "it" is literal, visible in user code
179+ # ...
180+ #
181+ # The point is the user code may append to or extend the list ``name``;
182+ # this simplifies writing some algorithms.
183+ #
184+ def pop_while (body , args ):
185+ gen_sym = dyn .gen_sym
186+ if len (args ) == 1 :
187+ theinput = args [0 ]
188+ thename = gen_sym ("_tmp" )
189+ elif len (args ) == 2 :
190+ theinput = args [1 ]
191+ thename = args [0 ]
192+ if type (thename ) is not Name :
193+ assert False , "in the two-argument form, the first argument must be a bare name"
194+ thename = thename .id
195+ else :
196+ assert False , "pop_while takes exactly one or two arguments"
197+
198+ with q as newbody :
199+ __the_tmp = ast_literal [theinput ]
200+ while __the_tmp :
201+ it = __the_tmp .pop (0 )
202+ thewhile = newbody [- 1 ]
203+ thewhile .body .extend (body )
204+
205+ @Walker
206+ def renametmp (tree , ** kw ):
207+ if type (tree ) is Name and tree .id == "__the_tmp" :
208+ tree .id = thename
209+ return tree
210+ return renametmp .recurse (newbody )
0 commit comments