Ejemplo n.º 1
0
    def __init__(self, *children, new_element=ElementOperation.make_new):
        super(Node, self).__init__()
        if len(children) == 1 and isinstance(children[0], list):
            children = children[0]

        self.first = None
        """The first Element of the doubly-linked list."""
        self.last = None
        """The last Element of the doubly-linked list."""

        self.range = StreamRange()

        if len(children) > 0:
            assert isinstance(children[0], Code) or isinstance(
                children[0], Element)
            current = self.first = new_element(children[0], self)

            self.range.update(current.code.range)
            for child in children[1:]:
                assert isinstance(child, Code) or isinstance(child, Element)
                current.next = new_element(child, self)
                current.next.prev = current
                current = current.next
                self.range.update(current.range)

            self.last = current
Ejemplo n.º 2
0
    def __init__(self, *children, new_element=ElementOperation.make_new):
        super(Node, self).__init__()
        if len(children) == 1 and isinstance(children[0], list):
            children = children[0]

        self.first = None
        """The first Element of the doubly-linked list."""
        self.last = None
        """The last Element of the doubly-linked list."""

        self.range = StreamRange()

        if len(children) > 0:
            assert isinstance(children[0], Code) or isinstance(children[0], Element)
            current = self.first = new_element(children[0], self)

            self.range.update(current.code.range)
            for child in children[1:]:
                assert isinstance(child, Code) or isinstance(child, Element)
                current.next = new_element(child, self)
                current.next.prev = current
                current = current.next
                self.range.update(current.range)

            self.last = current
Ejemplo n.º 3
0
 def __init__(self, value, type_=None, range: StreamRange = None):
     super(Literal, self).__init__()
     self.type = type_ or type(value)
     """Some instance representing the type of the literal."""
     self.value = value
     """The value associated with the literal."""
     self.range = range if range is not None else StreamRange()
Ejemplo n.º 4
0
 def __init__(self, full_name: str, stream_range: StreamRange = None):
     super(Identifier, self).__init__()
     name, semantic_name = Identifier.split_name(full_name)
     self.name = name
     self.semantic_name = semantic_name
     self.range = stream_range if stream_range is not None else StreamRange(
     )
Ejemplo n.º 5
0
    def apply(self, element) -> Element:
        if element.next is element.end:
            parent = element.parent
            parent.remove(element.end)
            element.code = Literal(
                "", self.string_literal_type,
                StreamRange(element.range.position_after,
                            element.range.position_after))
            return element.next

        assert is_token(element.next, Tokens.STRING)

        if element.next.next is element.end:
            parent = element.parent
            string_token = element.next
            parent.remove(element)
            parent.remove(element.end)
            string_token.code = Literal(string_token.value,
                                        self.string_literal_type,
                                        string_token.range)
            return string_token.next
        else:
            # FIXME: allow for interpolation
            new_form_element = element.parent.wrap(element, element.end, Form)
            new_form = new_form_element.code
            new_form.prepend(Identifier("str", element.range))
            # str BEGIN_MACRO('“') seq of STRING tokens, interspersed with Identifiers and BEGIN_MACRO / END_MACRO pairs END_MACRO

            new_form.remove(element)  # remove BEGIN_MACRO('“')
            new_form.remove(element.end)  # remove END_MACRO

            elm = new_form[1]  # first element
            while elm is not None:
                if is_token(elm, Tokens.STRING):
                    elm.code = Literal(elm.value, self.string_literal_type,
                                       elm.range)
                if is_token(elm, Tokens.BEGIN_MACRO):
                    elm = elm.end.next
                else:
                    elm = elm.next

            return new_form_element.next
Ejemplo n.º 6
0
class Node (Code):
    """
    A doubly-linked list.
    """

    # Given a list of elements and/or Code instances, or a sequence of elements and/or Code instances as arguments
    # creates a node whose elements have the given code instances, and the code instances of the given elements;
    # e.g., Node(1, 2, elm) has elements: Element.make(1), Element.make(2), Element.make(elm.value)
    def __init__(self, *children, new_element=ElementOperation.make_new):
        super(Node, self).__init__()
        if len(children) == 1 and isinstance(children[0], list):
            children = children[0]

        self.first = None
        """The first Element of the doubly-linked list."""
        self.last = None
        """The last Element of the doubly-linked list."""

        self.range = StreamRange()

        if len(children) > 0:
            assert isinstance(children[0], Code) or isinstance(children[0], Element)
            current = self.first = new_element(children[0], self)

            self.range.update(current.code.range)
            for child in children[1:]:
                assert isinstance(child, Code) or isinstance(child, Element)
                current.next = new_element(child, self)
                current.next.prev = current
                current = current.next
                self.range.update(current.range)

            self.last = current

    def erase(self):
        """
        Empties the entire list.
        """
        for node in self:
            node.parent = node.next = node.prev = None
        self.first = self.last = None

    def prepend(self, child:Union[Code,Element], new_element=ElementOperation.make_new):
        """
        Adds an element to the beginning of this node.


        :param child: A Code or an Element to be inserted. If ``child`` is an Element whose ``parent`` field is ``None``,
          the element will be changed to have this node as its parent.

        :param steal: Whether, if given an element that already has a parent, we remove the element from the current parent ("steal"), or create a new element.

        :type child: Code or Element

        """
        assert isinstance(child, Code) or isinstance(child, Element)

        element = new_element(child, self)
        self.range.update(element.range)
        if self.first is None:
            self.first = self.last = element
        else:
            self.first.prev = element
            element.next = self.first
            self.first = element

    def append(self, child, new_element=ElementOperation.make_new):
        """
        Adds an element to the end of this node.

        :param child: A Code or an Element to be inserted. If ``child`` is an Element whose ``parent`` field is ``None``,
          the element will be changed to have this node as its parent.

        :type child: Code or Element

        """
        assert isinstance(child, Code) or isinstance(child, Element)
        element = new_element(child, self)
        self.range.update(element.range)
        if self.first is None:
            self.first = self.last = element
        else:
            self.last.next = element
            element.prev = self.last
            self.last = element

    def insert(self, after_this:Element, child, new_element=ElementOperation.make_new):
        """
        Inserts a new element after a given element of this node.

        :param after_this: An Element (whose ``parent`` must be this node) after which
           the new element is to be inserted.

        :type after_this: Element

        :param child: A Code or an Element to be inserted. If ``child`` is an Element whose ``parent`` field is ``None``,
          the element will be changed to have this node as its parent.

        :type child: Code or Element

        """
        assert isinstance(after_this, Element) or (after_this is None and self.first is None)
        assert isinstance(child, Code) or isinstance(child, Element)
        if after_this is None and self.first is None:
            self.append(child)
            return self.first
        else:
            assert after_this.parent is self
            element = new_element(child, self)
            self.range.update(element.range)
            element.next = after_this.next
            element.prev = after_this
            if after_this.next is not None:
                after_this.next.prev = element
            else: self.last = element
            after_this.next = element
            return element

    def remove(self, element):
        """
        Inserts a new element after a given element of this node.

        :param element: An Element (whose ``parent`` must be this node) after which
           the new element is to be inserted.

        :type element: Element

        """
        assert isinstance(element, Element)
        assert element.parent is self

        if element.prev is None: self.first = element.next
        else: element.prev.next = element.next
         # if node is the tail
        if element.next is None: self.last = element.prev
        else: element.next.prev = element.prev
        element.parent = element.next = element.prev = None

    def replace(self, element, new_child, new_element=ElementOperation.make_new):
        """
        Replacesa given element of this node with a new element.

        :param element: The element (whose ``parent`` must be this node)
            to be replaced.

        :type element: Element

        :param new_child: A Code or an Element to be inserted. If ``child`` is an Element whose ``parent`` field is ``None``,
          the element will be changed to have this node as its parent.

        :type new_child: Code or Element

        """
        assert isinstance(element, Element)
        assert element.parent is self
        assert isinstance(new_child, Code) or isinstance(new_child, Element)
        new_element = new_element(new_child, self)
        self.range.update(new_element.range)
        new_element.next = element.next
        new_element.prev = element.prev
        # if c is the head
        if element.prev is None: self.first = new_element
        else: element.prev.next = new_element
         # if c is the tail
        if element.next is None: self.last = new_element
        else: element.next.prev = new_element
        element.parent = element.next = element.prev = None
        return new_element

    # replaces node in self with the elements of given Node
    # Destroys the given Node in the process
    # so (a b c).replace_explode(b, (d e)) = (a d e c), and the (d e) node becomes ()
    def replace_explode_modify(self, element, node):
        """
        Replaces a given element of this node with the sequence of elements given by another node.

        **This operation removes the elements from the given node, and makes this node their parent.**

        :param element: The element (whose ``parent`` must be this node)
            to be replaced.

        :type element: Element

        :param node: A ``Node`` whose elements will replace the given element.

        :type node: Node

        """
        assert isinstance(node, Node)
        assert isinstance(element, Element)
        assert element.parent is self

        if node.first is None:
            self.remove(element)
            return

        after_element = element.next

        element_to_add = node.first
        while element_to_add is not None:
            element_to_add.parent = self
            element_to_add = element_to_add.next

        element.next = node.first
        node.first.prev = element

        node.last.next = after_element
        if after_element is None: self.last = node
        else: after_element.prev = node.last
        node.first = None
        node.last = None

        self.remove(element)


    # ( ... first_node ... last_node ...)
    # =>
    # ( ... (first_node ... last_node) ...)
    def wrap(self, first_element, last_element, node_class_constructor = None, *node_class_constructor_args, **node_class_constructor_kwargs):
        """
        Replaces the sequence of elements of this node between first_element and end_punctuation_marker with a new node,
        containing that very same sequence.

        :param first_element: The first element (whose ``parent`` must be this node)
            in the sequence to be wrapped.

        :type first_element: Element

        :param last_element: The first element (whose ``parent`` must be this node)
            in the sequence to be wrapped.

        :type last_element: Element

        :param node_class_constructor: A subtype of ``Node`` which will be used to construct the new node.

        :type node_class_constructor: type

        :param node_class_constructor_args: Arguments to pass to the constructor of the new node.

        :param node_class_constructor_kwargs: Keyword arguments to pass to the constructor of the new node.

        """
        new_node = Node() if node_class_constructor is None else node_class_constructor(*node_class_constructor_args, **node_class_constructor_kwargs)
        new_element = Element(new_node, self)
        new_element.prev = first_element.prev
        new_element.next = last_element.next
        new_node.first = first_element
        new_node.last = last_element
        # if c is the head
        if first_element.prev is None: self.first = new_element
        else: first_element.prev.next = new_element
         # if c is the tail
        if last_element.next is None: self.last = new_element
        else: last_element.next.prev = new_element

        new_node.last.next = new_node.first.prev = None

        for e in new_node:
            e.parent = new_node
            new_node.range.update(e.code.range if e.code is not None else e.range)

        return new_element


    def __len__(self):
        count = 0
        for _ in self:
            count += 1
        return count

    def __getitem__(self, key):
        c = len(self)
        if c == 0 and key == 0:
            return None

        if isinstance(key, slice):
            # start, stop, step = slice.start, slice.stop, slice.step
            # if step is not None:
            #     raise NotImplementedError()

            ii = key.indices(c)
            return [self[i] for i in range(*ii)]

            # raise NotImplementedError()

        if not isinstance(key, int) or key >= c or key < -c:
            raise IndexError()
        if key >= 0:
            for c in self:
                if key == 0: return c
                key -= 1
        else:
            return self[c + key]


    def __setitem__(self, key, value):
        c = len(self)
        if not isinstance(key, int) or key >= c or key < -c:
            raise IndexError()
        if key >= 0:
            for c in self:
                if key == 0:
                    self.replace(c, value)
                key -= 1
        else:
            self[c + key] = value

    def __delitem__(self, key):
        c = len(self)
        if not isinstance(key, int) or key >= c or key < -c:
            raise IndexError()
        if key >= 0:
            for c in self:
                if key == 0:
                    self.remove(c)
                key -= 1
        else:
            del self[c + key]

    def __iter__(self):
        return NodeIterator(self.first)

    def iterate_from(self, start:Union[int,Element]):
        """
        Returns an iterator that goes through all elements from the ``start`` position/element to the end of the node.
        """
        if isinstance(start, int):
            return NodeIterator(self[start] if len(self) > start else None)
        else:
            assert isinstance(start, Element)
            return NodeIterator(start)

    def __str__(self):
        children = [str(element.code) if element.code is not None else str(element) for element in self]
        return "Node(%s)" % ", ".join(children)
Ejemplo n.º 7
0
class Node(Code):
    """
    A doubly-linked list.
    """

    # Given a list of elements and/or Code instances, or a sequence of elements and/or Code instances as arguments
    # creates a node whose elements have the given code instances, and the code instances of the given elements;
    # e.g., Node(1, 2, elm) has elements: Element.make(1), Element.make(2), Element.make(elm.value)
    def __init__(self, *children, new_element=ElementOperation.make_new):
        super(Node, self).__init__()
        if len(children) == 1 and isinstance(children[0], list):
            children = children[0]

        self.first = None
        """The first Element of the doubly-linked list."""
        self.last = None
        """The last Element of the doubly-linked list."""

        self.range = StreamRange()

        if len(children) > 0:
            assert isinstance(children[0], Code) or isinstance(
                children[0], Element)
            current = self.first = new_element(children[0], self)

            self.range.update(current.code.range)
            for child in children[1:]:
                assert isinstance(child, Code) or isinstance(child, Element)
                current.next = new_element(child, self)
                current.next.prev = current
                current = current.next
                self.range.update(current.range)

            self.last = current

    def erase(self):
        """
        Empties the entire list.
        """
        for node in self:
            node.parent = node.next = node.prev = None
        self.first = self.last = None

    def prepend(self,
                child: Union[Code, Element],
                new_element=ElementOperation.make_new):
        """
        Adds an element to the beginning of this node.


        :param child: A Code or an Element to be inserted. If ``child`` is an Element whose ``parent`` field is ``None``,
          the element will be changed to have this node as its parent.

        :param steal: Whether, if given an element that already has a parent, we remove the element from the current parent ("steal"), or create a new element.

        :type child: Code or Element

        """
        assert isinstance(child, Code) or isinstance(child, Element)

        element = new_element(child, self)
        self.range.update(element.range)
        if self.first is None:
            self.first = self.last = element
        else:
            self.first.prev = element
            element.next = self.first
            self.first = element

    def append(self, child, new_element=ElementOperation.make_new):
        """
        Adds an element to the end of this node.

        :param child: A Code or an Element to be inserted. If ``child`` is an Element whose ``parent`` field is ``None``,
          the element will be changed to have this node as its parent.

        :type child: Code or Element

        """
        assert isinstance(child, Code) or isinstance(child, Element)
        element = new_element(child, self)
        self.range.update(element.range)
        if self.first is None:
            self.first = self.last = element
        else:
            self.last.next = element
            element.prev = self.last
            self.last = element

    def insert(self,
               after_this: Element,
               child,
               new_element=ElementOperation.make_new):
        """
        Inserts a new element after a given element of this node.

        :param after_this: An Element (whose ``parent`` must be this node) after which
           the new element is to be inserted.

        :type after_this: Element

        :param child: A Code or an Element to be inserted. If ``child`` is an Element whose ``parent`` field is ``None``,
          the element will be changed to have this node as its parent.

        :type child: Code or Element

        """
        assert isinstance(after_this, Element) or (after_this is None
                                                   and self.first is None)
        assert isinstance(child, Code) or isinstance(child, Element)
        if after_this is None and self.first is None:
            self.append(child)
            return self.first
        else:
            assert after_this.parent is self
            element = new_element(child, self)
            self.range.update(element.range)
            element.next = after_this.next
            element.prev = after_this
            if after_this.next is not None:
                after_this.next.prev = element
            else:
                self.last = element
            after_this.next = element
            return element

    def remove(self, element):
        """
        Inserts a new element after a given element of this node.

        :param element: An Element (whose ``parent`` must be this node) after which
           the new element is to be inserted.

        :type element: Element

        """
        assert isinstance(element, Element)
        assert element.parent is self

        if element.prev is None: self.first = element.next
        else: element.prev.next = element.next
        # if node is the tail
        if element.next is None: self.last = element.prev
        else: element.next.prev = element.prev
        element.parent = element.next = element.prev = None

    def replace(self,
                element,
                new_child,
                new_element=ElementOperation.make_new):
        """
        Replacesa given element of this node with a new element.

        :param element: The element (whose ``parent`` must be this node)
            to be replaced.

        :type element: Element

        :param new_child: A Code or an Element to be inserted. If ``child`` is an Element whose ``parent`` field is ``None``,
          the element will be changed to have this node as its parent.

        :type new_child: Code or Element

        """
        assert isinstance(element, Element)
        assert element.parent is self
        assert isinstance(new_child, Code) or isinstance(new_child, Element)
        new_element = new_element(new_child, self)
        self.range.update(new_element.range)
        new_element.next = element.next
        new_element.prev = element.prev
        # if c is the head
        if element.prev is None: self.first = new_element
        else: element.prev.next = new_element
        # if c is the tail
        if element.next is None: self.last = new_element
        else: element.next.prev = new_element
        element.parent = element.next = element.prev = None
        return new_element

    # replaces node in self with the elements of given Node
    # Destroys the given Node in the process
    # so (a b c).replace_explode(b, (d e)) = (a d e c), and the (d e) node becomes ()
    def replace_explode_modify(self, element, node):
        """
        Replaces a given element of this node with the sequence of elements given by another node.

        **This operation removes the elements from the given node, and makes this node their parent.**

        :param element: The element (whose ``parent`` must be this node)
            to be replaced.

        :type element: Element

        :param node: A ``Node`` whose elements will replace the given element.

        :type node: Node

        """
        assert isinstance(node, Node)
        assert isinstance(element, Element)
        assert element.parent is self

        if node.first is None:
            self.remove(element)
            return

        after_element = element.next

        element_to_add = node.first
        while element_to_add is not None:
            element_to_add.parent = self
            element_to_add = element_to_add.next

        element.next = node.first
        node.first.prev = element

        node.last.next = after_element
        if after_element is None: self.last = node
        else: after_element.prev = node.last
        node.first = None
        node.last = None

        self.remove(element)

    # ( ... first_node ... last_node ...)
    # =>
    # ( ... (first_node ... last_node) ...)
    def wrap(self,
             first_element,
             last_element,
             node_class_constructor=None,
             *node_class_constructor_args,
             **node_class_constructor_kwargs):
        """
        Replaces the sequence of elements of this node between first_element and end_punctuation_marker with a new node,
        containing that very same sequence.

        :param first_element: The first element (whose ``parent`` must be this node)
            in the sequence to be wrapped.

        :type first_element: Element

        :param last_element: The first element (whose ``parent`` must be this node)
            in the sequence to be wrapped.

        :type last_element: Element

        :param node_class_constructor: A subtype of ``Node`` which will be used to construct the new node.

        :type node_class_constructor: type

        :param node_class_constructor_args: Arguments to pass to the constructor of the new node.

        :param node_class_constructor_kwargs: Keyword arguments to pass to the constructor of the new node.

        """
        new_node = Node(
        ) if node_class_constructor is None else node_class_constructor(
            *node_class_constructor_args, **node_class_constructor_kwargs)
        new_element = Element(new_node, self)
        new_element.prev = first_element.prev
        new_element.next = last_element.next
        new_node.first = first_element
        new_node.last = last_element
        # if c is the head
        if first_element.prev is None: self.first = new_element
        else: first_element.prev.next = new_element
        # if c is the tail
        if last_element.next is None: self.last = new_element
        else: last_element.next.prev = new_element

        new_node.last.next = new_node.first.prev = None

        for e in new_node:
            e.parent = new_node
            new_node.range.update(
                e.code.range if e.code is not None else e.range)

        return new_element

    def __len__(self):
        count = 0
        for _ in self:
            count += 1
        return count

    def __getitem__(self, key):
        c = len(self)
        if c == 0 and key == 0:
            return None

        if isinstance(key, slice):
            # start, stop, step = slice.start, slice.stop, slice.step
            # if step is not None:
            #     raise NotImplementedError()

            ii = key.indices(c)
            return [self[i] for i in range(*ii)]

            # raise NotImplementedError()

        if not isinstance(key, int) or key >= c or key < -c:
            raise IndexError()
        if key >= 0:
            for c in self:
                if key == 0: return c
                key -= 1
        else:
            return self[c + key]

    def __setitem__(self, key, value):
        c = len(self)
        if not isinstance(key, int) or key >= c or key < -c:
            raise IndexError()
        if key >= 0:
            for c in self:
                if key == 0:
                    self.replace(c, value)
                key -= 1
        else:
            self[c + key] = value

    def __delitem__(self, key):
        c = len(self)
        if not isinstance(key, int) or key >= c or key < -c:
            raise IndexError()
        if key >= 0:
            for c in self:
                if key == 0:
                    self.remove(c)
                key -= 1
        else:
            del self[c + key]

    def __iter__(self):
        return NodeIterator(self.first)

    def iterate_from(self, start: Union[int, Element]):
        """
        Returns an iterator that goes through all elements from the ``start`` position/element to the end of the node.
        """
        if isinstance(start, int):
            return NodeIterator(self[start] if len(self) > start else None)
        else:
            assert isinstance(start, Element)
            return NodeIterator(start)

    def __str__(self):
        children = [
            str(element.code) if element.code is not None else str(element)
            for element in self
        ]
        return "Node(%s)" % ", ".join(children)