15f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#
25f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)# TreeFragments - parsing of strings to trees
35f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#
45f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
55f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)import re
65f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)from StringIO import StringIO
75f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)from Scanning import PyrexScanner, StringSourceDescriptor
85f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)from Symtab import ModuleScope
95f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)import PyrexTypes
105f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)from Visitor import VisitorTransform
115f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)from Nodes import Node, StatListNode
125f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)from ExprNodes import NameNode
135f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)import Parsing
145f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)import Main
155f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)import UtilNodes
165f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
175f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)"""
185f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)Support for parsing strings into code trees.
195f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)"""
205f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
215f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)class StringParseContext(Main.Context):
225f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    def __init__(self, name, include_directories=None):
235f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        if include_directories is None: include_directories = []
245f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        Main.Context.__init__(self, include_directories, {},
255f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                              create_testscope=False)
265f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        self.module_name = name
275f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
285f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    def find_module(self, module_name, relative_to = None, pos = None, need_pxd = 1):
295f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        if module_name not in (self.module_name, 'cython'):
305f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            raise AssertionError("Not yet supporting any cimports/includes from string code snippets")
315f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        return ModuleScope(module_name, parent_module = None, context = self)
325f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
335f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)def parse_from_strings(name, code, pxds={}, level=None, initial_pos=None,
345f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                       context=None, allow_struct_enum_decorator=False):
355f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    """
365f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    Utility method to parse a (unicode) string of code. This is mostly
375f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    used for internal Cython compiler purposes (creating code snippets
385f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    that transforms should emit, as well as unit testing).
395f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
405f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    code - a unicode string containing Cython (module-level) code
415f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    name - a descriptive name for the code source (to use in error messages etc.)
425f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
435f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    RETURNS
445f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
455f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    The tree, i.e. a ModuleNode. The ModuleNode's scope attribute is
465f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    set to the scope used when parsing.
475f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    """
485f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    if context is None:
495f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        context = StringParseContext(name)
505f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    # Since source files carry an encoding, it makes sense in this context
515f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    # to use a unicode string so that code fragments don't have to bother
525f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    # with encoding. This means that test code passed in should not have an
535f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    # encoding header.
545f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    assert isinstance(code, unicode), "unicode code snippets only please"
555f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    encoding = "UTF-8"
565f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
575f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    module_name = name
585f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    if initial_pos is None:
595f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        initial_pos = (name, 1, 0)
605f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    code_source = StringSourceDescriptor(name, code)
615f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
625f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    scope = context.find_module(module_name, pos = initial_pos, need_pxd = 0)
635f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
645f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    buf = StringIO(code)
655f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
665f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    scanner = PyrexScanner(buf, code_source, source_encoding = encoding,
675f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                     scope = scope, context = context, initial_pos = initial_pos)
685f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    ctx = Parsing.Ctx(allow_struct_enum_decorator=allow_struct_enum_decorator)
695f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
705f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    if level is None:
715f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        tree = Parsing.p_module(scanner, 0, module_name, ctx=ctx)
725f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        tree.scope = scope
735f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        tree.is_pxd = False
745f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    else:
755f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        tree = Parsing.p_code(scanner, level=level, ctx=ctx)
765f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
775f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    tree.scope = scope
785f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    return tree
795f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
805f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)class TreeCopier(VisitorTransform):
815f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    def visit_Node(self, node):
825f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        if node is None:
835f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            return node
845f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        else:
855f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            c = node.clone_node()
865f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            self.visitchildren(c)
875f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            return c
885f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
895f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)class ApplyPositionAndCopy(TreeCopier):
905f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    def __init__(self, pos):
915f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        super(ApplyPositionAndCopy, self).__init__()
925f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        self.pos = pos
935f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
945f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    def visit_Node(self, node):
955f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        copy = super(ApplyPositionAndCopy, self).visit_Node(node)
965f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        copy.pos = self.pos
975f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        return copy
985f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
995f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)class TemplateTransform(VisitorTransform):
1005f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    """
1015f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    Makes a copy of a template tree while doing substitutions.
1025f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1035f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    A dictionary "substitutions" should be passed in when calling
1045f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    the transform; mapping names to replacement nodes. Then replacement
1055f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    happens like this:
1065f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)     - If an ExprStatNode contains a single NameNode, whose name is
1075f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)       a key in the substitutions dictionary, the ExprStatNode is
1085f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)       replaced with a copy of the tree given in the dictionary.
1095f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)       It is the responsibility of the caller that the replacement
1105f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)       node is a valid statement.
1115f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)     - If a single NameNode is otherwise encountered, it is replaced
1125f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)       if its name is listed in the substitutions dictionary in the
1135f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)       same way. It is the responsibility of the caller to make sure
1145f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)       that the replacement nodes is a valid expression.
1155f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1165f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    Also a list "temps" should be passed. Any names listed will
1175f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    be transformed into anonymous, temporary names.
1185f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1195f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    Currently supported for tempnames is:
1205f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    NameNode
1215f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    (various function and class definition nodes etc. should be added to this)
1225f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1235f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    Each replacement node gets the position of the substituted node
1245f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    recursively applied to every member node.
1255f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    """
1265f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1275f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    temp_name_counter = 0
1285f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1295f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    def __call__(self, node, substitutions, temps, pos):
1305f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        self.substitutions = substitutions
1315f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        self.pos = pos
1325f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        tempmap = {}
1335f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        temphandles = []
1345f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        for temp in temps:
1355f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            TemplateTransform.temp_name_counter += 1
1365f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            handle = UtilNodes.TempHandle(PyrexTypes.py_object_type)
1375f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            tempmap[temp] = handle
1385f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            temphandles.append(handle)
1395f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        self.tempmap = tempmap
1405f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        result = super(TemplateTransform, self).__call__(node)
1415f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        if temps:
1425f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            result = UtilNodes.TempsBlockNode(self.get_pos(node),
1435f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                                              temps=temphandles,
1445f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                                              body=result)
1455f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        return result
1465f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1475f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    def get_pos(self, node):
1485f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        if self.pos:
1495f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            return self.pos
1505f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        else:
1515f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            return node.pos
1525f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1535f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    def visit_Node(self, node):
1545f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        if node is None:
1555f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            return None
1565f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        else:
1575f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            c = node.clone_node()
1585f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            if self.pos is not None:
1595f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                c.pos = self.pos
1605f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            self.visitchildren(c)
1615f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            return c
1625f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1635f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    def try_substitution(self, node, key):
1645f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        sub = self.substitutions.get(key)
1655f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        if sub is not None:
1665f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            pos = self.pos
1675f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            if pos is None: pos = node.pos
1685f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            return ApplyPositionAndCopy(pos)(sub)
1695f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        else:
1705f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            return self.visit_Node(node) # make copy as usual
1715f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1725f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    def visit_NameNode(self, node):
1735f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        temphandle = self.tempmap.get(node.name)
1745f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        if temphandle:
1755f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            # Replace name with temporary
1765f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            return temphandle.ref(self.get_pos(node))
1775f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        else:
1785f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            return self.try_substitution(node, node.name)
1795f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1805f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    def visit_ExprStatNode(self, node):
1815f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        # If an expression-as-statement consists of only a replaceable
1825f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        # NameNode, we replace the entire statement, not only the NameNode
1835f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        if isinstance(node.expr, NameNode):
1845f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            return self.try_substitution(node, node.expr.name)
1855f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        else:
1865f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            return self.visit_Node(node)
1875f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1885f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)def copy_code_tree(node):
1895f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    return TreeCopier()(node)
1905f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1915f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)INDENT_RE = re.compile(ur"^ *")
1925f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)def strip_common_indent(lines):
1935f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    "Strips empty lines and common indentation from the list of strings given in lines"
1945f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    # TODO: Facilitate textwrap.indent instead
1955f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    lines = [x for x in lines if x.strip() != u""]
1965f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    minindent = min([len(INDENT_RE.match(x).group(0)) for x in lines])
1975f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    lines = [x[minindent:] for x in lines]
1985f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    return lines
1995f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
2005f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)class TreeFragment(object):
2015f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    def __init__(self, code, name="(tree fragment)", pxds={}, temps=[], pipeline=[], level=None, initial_pos=None):
2025f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        if isinstance(code, unicode):
2035f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            def fmt(x): return u"\n".join(strip_common_indent(x.split(u"\n")))
2045f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
2055f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            fmt_code = fmt(code)
2065f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            fmt_pxds = {}
2075f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            for key, value in pxds.iteritems():
2085f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                fmt_pxds[key] = fmt(value)
2095f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            mod = t = parse_from_strings(name, fmt_code, fmt_pxds, level=level, initial_pos=initial_pos)
2105f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            if level is None:
2115f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                t = t.body # Make sure a StatListNode is at the top
2125f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            if not isinstance(t, StatListNode):
2135f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                t = StatListNode(pos=mod.pos, stats=[t])
2145f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            for transform in pipeline:
2155f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                if transform is None:
2165f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                    continue
2175f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                t = transform(t)
2185f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            self.root = t
2195f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        elif isinstance(code, Node):
2205f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            if pxds != {}: raise NotImplementedError()
2215f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            self.root = code
2225f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        else:
2235f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            raise ValueError("Unrecognized code format (accepts unicode and Node)")
2245f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        self.temps = temps
2255f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
2265f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    def copy(self):
2275f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        return copy_code_tree(self.root)
2285f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
2295f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    def substitute(self, nodes={}, temps=[], pos = None):
2305f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        return TemplateTransform()(self.root,
2315f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                                   substitutions = nodes,
2325f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                                   temps = self.temps + temps, pos = pos)
2335f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
2345f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)class SetPosTransform(VisitorTransform):
2355f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    def __init__(self, pos):
2365f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        super(SetPosTransform, self).__init__()
2375f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        self.pos = pos
2385f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
2395f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    def visit_Node(self, node):
2405f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        node.pos = self.pos
2415f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        self.visitchildren(node)
2425f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        return node
243