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 __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 __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()
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( )
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
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)
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)