def _walk_action_stack(top_block, lc, convert_me=True): """ Turn a stack of blocks into a list of ASTs convert_me -- convert values and Primitives to ASTs or return them unconverted? """ block = top_block # value blocks don't have a primitive # (but constant blocks (colors, screen dimensions, etc.) do) if block.is_value_block(): raw_value = block.get_value(add_type_prefix=False) if convert_me: value_ast = value_to_ast(raw_value) if value_ast is not None: return [value_ast] else: return [] else: if raw_value is not None: return [raw_value] else: return [] def _get_prim(block): prim = lc.get_prim_callable(block.primitive) # fail gracefully if primitive is not a Primitive object if not isinstance(prim, Primitive): raise PyExportError(_("block is not exportable"), block=block) return prim prim = _get_prim(block) ast_list = [] arg_asts = [] def _finish_off(block, prim=None): """ Convert block to an AST and add it to the ast_list. Raise a PyExportError on failure. """ if prim is None: prim = _get_prim(block) if convert_me: if prim.export_me: try: new_ast = prim.get_ast(*arg_asts) except ValueError: traceback.print_exc() raise PyExportError(_("error while exporting block"), block=block) if isinstance(new_ast, (list, tuple)): ast_list.extend(new_ast) elif new_ast is not None: ast_list.append(new_ast) elif arg_asts: # TODO do we ever get here? new_ast = ast.List(elts=arg_asts, ctx=ast.Load) ast_list.append(new_ast) else: ast_list.append((prim, ) + tuple(arg_asts)) # skip the very first dock/ connection - it's either the previous block or # the return value of this block dock_queue = block.docks[1:] conn_queue = block.connections[1:] while dock_queue and conn_queue: dock = dock_queue.pop(0) conn = conn_queue.pop(0) if conn is None or dock[0] == 'unavailable': continue elif not dock_queue and dock[0] == 'flow': # finish off this block _finish_off(block, prim) arg_asts = [] # next block block = conn prim = _get_prim(block) dock_queue = block.docks[1:] conn_queue = block.connections[1:] else: # embedded stack of blocks (body of conditional or loop) or # argument block if dock[0] == 'flow': # body of conditional or loop new_arg_asts = _walk_action_stack(conn, lc, convert_me=convert_me) if (prim == LogoCode.prim_loop and not isinstance(new_arg_asts[-1], ast.Yield)): new_arg_asts.append(ast_yield_true()) arg_asts.append(new_arg_asts) else: # argument block new_arg_asts = _walk_action_stack(conn, lc, convert_me=False) arg_asts.append(*new_arg_asts) # finish off last block _finish_off(block, prim) return ast_list