Exemplo n.º 1
0
    def check_as_closer(self, node, active_node):
        #print node
        #print self
        # The node passed in should be a MakoNode or a MakoLeaf at the same indentation level

        # Who is closing?
        if self is active_node:
            # I am the active node, so I am the unambiguous choice to be closed at this time
            return      

        potentially_closed = active_node.parent
        while potentially_closed is not None:

            #print 'Checking: %s' % potentially_closed
            if potentially_closed.depth == node.depth:
                # <potentially_closed> is definitely being closed by <node>, and all is well
                # Todo: Perform type checking to make sure MakoNodes only close against other MakoNodes
                return
            elif potentially_closed.depth < node.depth:
                # How am is <node> closing someone at a lower depth than it?
                raise NemoException('\nIncorrect indentation\n' + \
                                    'at:\n\t%s\n' % node + \
                                    'Tried to close against::\n\t%s\n' % self + \
                                    'Within active scope of:\n\t%s' % active_node )

            potentially_closed = potentially_closed.parent
Exemplo n.º 2
0
    def _add_control_leaf_to_tree(self, node, active_node):
        if node.depth > active_node.depth:
            active_node.add_child(node)
            return active_node

            # The following check is disabled
            # --------

            # Leafs cannot appear on a higher indentation point than the active node
            # That would be ambiguous
            #raise NemoException('\nIncorrect indentation\n' + \
            #                    'at:\n\t%s\n' % active_node + \
            #                    'Followed by:\n\t%s\n' % node + \
            #                    'Parent:\n\t%s' % active_node.parent )
        else:
            """Try to assign node to one of the ancestors of active_node"""
            testing_node = active_node

            while testing_node is not None:
                # Close against the first element in the tree that is inline with you
                if testing_node.depth == node.depth:
                    # We are trying to close against the root element
                    if not testing_node.parent:
                        raise NemoException('\nIncorrect indentation\n' + \
                                    'at:\n\t%s\n' % node + \
                                    'attempted to close against:\n\t%s' % testing_node )
                    else:
                        parent = testing_node.parent
                        parent.add_child(node)

                        # Todo: Remove this check
                        testing_node.check_as_closer(node, active_node)
                        
                        return testing_node.parent
                elif testing_node.depth < node.depth:
                    raise NemoException('\nIncorrect indentation\n' + \
                                'at:\n\t%s\n' % node + \
                                'attempted to close against:\n\t%s' % testing_node )
                testing_node = testing_node.parent
            else:
                # This should never be reached because NemoRoot has a depth of -1
                raise NemoException('\nIncorrect indentation\n' + \
                                    'at:\n\t%s\n' % active_node + \
                                    'Followed by:\n\t%s\n' % node + \
                                    'Parent:\n\t%s' % parent )
Exemplo n.º 3
0
 def check_as_closer(self, node, active_node):
     """
        The passed in node was added as your child, and is attempting to close your scope.
        Is this allowed?
     """
     raise NemoException('\nIncorrect indentation\n' + \
                         'at:\n\t%s\n' % node + \
                         'Tried to close against:\n\t%s\n' % self + \
                         'Within active scope of:\n\t%s' % active_node )
Exemplo n.º 4
0
    def check_open_close_on_mako_nodes(self, children):
        open_mako_context = None
        for child in children:
            child_type = type(child)

            # Check child nodes for open/close semantics
            if child_type is MakoNode and open_mako_context is None:
                open_mako_context = child
            if child_type is MakoEndTag:
                if open_mako_context is None:
                    # Closer w/o an open context
                    raise NemoException('\nEnd tag without open context\n' + \
                                        'at:\n\t%s\n' % child + \
                                        'within:\n\t%s\n' % self )
                # Close context
                open_mako_context = None

            yield child

        if open_mako_context is not None:
            # Open context without a closer
            raise NemoException('\nOpen tag without a closer found:\n' + \
                                'at:\n\t%s\n' % open_mako_context + \
                                'within:\n\t%s\n' % self )
Exemplo n.º 5
0
    def _place_in_ancestor(self, node, active_node):
        """Try to assign node to one of the ancestors of active_node"""
        parent = active_node
        while parent is not None:
            if parent.depth < node.depth:
                parent.add_child(node)
                
                return parent

            parent = parent.parent
        else:
            # This should never be reached because NemoRoot has a depth of -1
            raise NemoException('\nIncorrect indentation\n' + \
                                'at:\n\t%s\n' % active_node + \
                                'Followed by:\n\t%s\n' % node + \
                                'Parent:\n\t%s' % parent )
Exemplo n.º 6
0
    def check_indentation_rules(self, children):
        depth_seen = None
        for child in children:
            # Ensure child is at correct depth
            # If this is disabled then depth.failure and inner_tag_indentation.failure will both succeed
            # It is dubious if we want this
            # Todo: Permissive mode
            if child.follows_indentation_rules and not PERMISSIVE:
                if depth_seen is None:
                    depth_seen = child.depth
                elif child.depth is not depth_seen:
                    raise NemoException('\nIncorrect indentation\n' + \
                                         'at:\n\t%s\n' % child + \
                                         'within:\n\t%s\n' % self + \
                                         'expected indentation of %d ' % depth_seen)

            yield child
Exemplo n.º 7
0
    def parse(self, source):
        self.buffer = Buffer()
        self._init(raw=iter(source))
        quotes = ['\'', '"']
        expect = None

        while True:
            try:
                self._next()
            except StopIteration:
                break

            if expect is None:
                # Match class token (.) or id token (#)
                if self._c == ' ':
                    self.buffer.write(self._c)
                elif self._c == '.':
                    expect = quotes
                    self.buffer.write('class=')
                elif self._c == '#':
                    expect = quotes
                    self.buffer.write('id=')
                else:
                    # Slurp up attribute name til we see a quote
                    self.buffer.write(self._c)
                    self._slurp_till(quotes)

                    # Slurp up attribute value till we see another of the same quote
                    delimiter_found = self._c
                    self._slurp_till(delimiter_found)
            else:
                if self._c not in expect:
                    raise NemoException('Expected one of: %s but received %s' %
                                        (expect, self._c))
                if expect is quotes:
                    delimiter_found = self._c

                    # Write quote to buffer, then slurp up til the next quote
                    self.buffer.write(delimiter_found)
                    arg = self._slurp_till(delimiter_found)

                    # We have a keyword/arg combination complete so go back to expecting nothing
                    expect = None

        return self.buffer.getvalue()
Exemplo n.º 8
0
    def check_as_closer(self, node, active_node):
        """
        Originally this was slated to be removed because it only provided security against bugs we hadn't tested against.
        In practice (the last 4 years), it proved to be invaluable in
        providing better error messages than otherwise would be available.

        It didn't uncover any real bugs, but it showed incorrect indentation at a better level than would otherwise be provided.

        Technically removing this wouldn't result in invalid code immediately,
        but it'll let you write poorly Nemo and forget about it.
        Then later on, you'll end up writing more seemingly valid code which will
        caused an error in previously written statements.

        Unlike in HAML, we've chosen to cause an error as soon as possible,
        rather than implicitly swallowing the error node.
        """

        # Debugging
        #print node
        #print self
        # The node passed in should be a MakoNode or a MakoLeaf at the same indentation level

        # Who is closing?
        if self is active_node:
            # I am the active node, so I am the unambiguous choice to be closed at this time
            return

        potentially_closed = active_node.parent
        while potentially_closed is not None:

            #print 'Checking: %s' % potentially_closed
            if potentially_closed.depth == node.depth:
                # <potentially_closed> is definitely being closed by <node>, and all is well
                # Todo: Perform type checking to make sure MakoNodes only close against other MakoNodes
                return
            elif potentially_closed.depth < node.depth:
                # How am is <node> closing someone at a lower depth than it?
                raise NemoException('\nIncorrect indentation\n' + \
                                    'at:\n\t%s\n' % node + \
                                    'Tried to close against::\n\t%s\n' % self + \
                                    'Within active scope of:\n\t%s' % active_node )

            potentially_closed = potentially_closed.parent
Exemplo n.º 9
0
    def _slurp_till(self, end_delimiters):
        """ Read until a given delimiter is found in a string iterator.
        Keeps white space, and ignores the end_delimiter if it is preceded by \
        Return a string
        """
        cc = None
        if type(end_delimiters) in [str, unicode]:
            end_delimiters = [end_delimiters]

        while True:
            try:
                self._next()
            except StopIteration:
                raise NemoException('Expected delimiter %s but EOL found instead' % end_delimiters)

            self.buffer.write(self._c)

            for end in end_delimiters:
                if self._c == end and self._last_c != '\\':
                    return
Exemplo n.º 10
0
 def add_child(self, node):
     # This should never be called
     raise NemoException('Parser error. Tried to add node:\n\t%s to leaf: \n\t%s' % (node, self))