Exemple #1
0
    def skipCodeBlock (self,s,i,kind):

        trace = False ; verbose = True
        # if trace: g.trace('***',g.callers())
        startIndent = self.startSigIndent
        if trace: g.trace('startIndent',startIndent)
        assert startIndent is not None
        i = start = g.skip_ws_and_nl(s,i)
        parenCount = 0
        underIndentedStart = None # The start of trailing underindented blank or comment lines.
        while i < len(s):
            progress = i
            ch = s[i]
            if g.is_nl(s,i):
                if trace and verbose: g.trace(g.get_line(s,i))
                backslashNewline = (i > 0 and g.match(s,i-1,'\\\n'))
                if backslashNewline:
                    # An underindented line, including docstring,
                    # does not end the code block.
                    i += 1 # 2010/11/01
                else:
                    i = g.skip_nl(s,i)
                    j = g.skip_ws(s,i)
                    if g.is_nl(s,j):
                        pass # We have already made progress.
                    else:
                        i,underIndentedStart,breakFlag = self.pythonNewlineHelper(
                            s,i,parenCount,startIndent,underIndentedStart)
                        if breakFlag: break
            elif ch == '#':
                i = g.skip_to_end_of_line(s,i)
            elif ch == '"' or ch == '\'':
                i = g.skip_python_string(s,i)
            elif ch in '[{(':
                i += 1 ; parenCount += 1
                # g.trace('ch',ch,parenCount)
            elif ch in ']})':
                i += 1 ; parenCount -= 1
                # g.trace('ch',ch,parenCount)
            else: i += 1
            assert(progress < i)

        # The actual end of the block.
        if underIndentedStart is not None:
            i = underIndentedStart
            if trace: g.trace('***backtracking to underindent range')
            if trace: g.trace(g.get_line(s,i))

        if 0 < i < len(s) and not g.match(s,i-1,'\n'):
            g.trace('Can not happen: Python block does not end in a newline.')
            g.trace(g.get_line(s,i))
            return i,False

        # 2010/02/19: Include all following material
        # until the next 'def' or 'class'
        i = self.skipToTheNextClassOrFunction(s,i,startIndent)

        if (trace or self.trace) and s[start:i].strip():
            g.trace('%s returns\n' % (kind) + s[start:i])
        return i,True
Exemple #2
0
 def skipCodeBlock(self, s, i, kind):
     trace = False
     verbose = True
     # if trace: g.trace('***',g.callers())
     startIndent = self.startSigIndent
     if trace: g.trace('startIndent', startIndent)
     assert startIndent is not None
     i = start = g.skip_ws_and_nl(s, i)
     parenCount = 0
     underIndentedStart = None  # The start of trailing underindented blank or comment lines.
     while i < len(s):
         progress = i
         ch = s[i]
         if g.is_nl(s, i):
             if trace and verbose: g.trace(g.get_line(s, i))
             backslashNewline = (i > 0 and g.match(s, i - 1, '\\\n'))
             if backslashNewline:
                 # An underindented line, including docstring,
                 # does not end the code block.
                 i += 1  # 2010/11/01
             else:
                 i = g.skip_nl(s, i)
                 j = g.skip_ws(s, i)
                 if g.is_nl(s, j):
                     pass  # We have already made progress.
                 else:
                     i, underIndentedStart, breakFlag = self.pythonNewlineHelper(
                         s, i, parenCount, startIndent, underIndentedStart)
                     if breakFlag: break
         elif ch == '#':
             i = g.skip_to_end_of_line(s, i)
         elif ch == '"' or ch == '\'':
             i = g.skip_python_string(s, i)
         elif ch in '[{(':
             i += 1
             parenCount += 1
             # g.trace('ch',ch,parenCount)
         elif ch in ']})':
             i += 1
             parenCount -= 1
             # g.trace('ch',ch,parenCount)
         else:
             i += 1
         assert (progress < i)
     # The actual end of the block.
     if underIndentedStart is not None:
         i = underIndentedStart
         if trace: g.trace('***backtracking to underindent range')
         if trace: g.trace(g.get_line(s, i))
     if 0 < i < len(s) and not g.match(s, i - 1, '\n'):
         g.trace('Can not happen: Python block does not end in a newline.')
         g.trace(g.get_line(s, i))
         return i, False
     # 2010/02/19: Include all following material
     # until the next 'def' or 'class'
     i = self.skipToTheNextClassOrFunction(s, i, startIndent)
     if (trace or self.trace) and s[start:i].strip():
         g.trace('%s returns\n' % (kind) + s[start:i])
     return i, True
Exemple #3
0
 def scanFunction(self, parent, s, i):
     '''scan function(args) { body } and then rescan body.'''
     trace = True and not g.unitTesting
     # k1, k2 = g.getLine(s,i)
     # g.trace(s[k1:k2])
     i1 = i
     # Scan backward for '('
     i2 = i - 1
     while 0 <= i2 and s[i2].isspace():
         i2 -= 1
     in_expr = s[i2] == '('
     assert g.match(s, i, 'function')
     i += len('function')
     i = g.skip_ws_and_nl(s, i)
     i = self.skipId(s, i)
     i = g.skip_ws_and_nl(s, i)
     # Skip the argument list.
     if not g.match(s, i, '('):
         if trace: g.trace('syntax error: no argument list', i)
         return i
     i = self.skipBlock(s, i, '(', ')')
     # skipBlock skips the ')'
     if i == len(s):
         g.trace('no args', g.get_line(s, i))
         return i
     # Skip the body.
     i = g.skip_ws_and_nl(s, i)
     if not g.match(s, i, '{'):
         if trace: g.trace('no function body', i)
         return i
     block_i1 = i
     block_i2 = i = self.skipBlock(s, i, '{', '}')
     j = g.skip_ws_and_nl(s, i)
     if g.match(s, j, '('):
         i = g.skip_parens(s, i)
     if in_expr:
         j = g.skip_ws_and_nl(s, i)
         if g.match(s, j, ')'):
             i = j + 1
     assert i > i1
     block_s = s[block_i1 + 1:block_i2 - 1].strip()
     if trace: g.trace('*** rescanning ***\n\n%s\n\n' % block_s)
     self.scanHelper(parent, block_s)
     return i
Exemple #4
0
 def scanFunction(self, parent, s, i):
     '''scan function(args) { body } and then rescan body.'''
     trace = True and not g.unitTesting
     # k1, k2 = g.getLine(s,i)
     # g.trace(s[k1:k2])
     i1 = i
     # Scan backward for '('
     i2 = i-1
     while 0 <= i2 and s[i2].isspace():
         i2 -= 1
     in_expr = s[i2] == '('
     assert g.match(s, i, 'function')
     i += len('function')
     i = g.skip_ws_and_nl(s, i)
     i = self.skipId(s, i)
     i = g.skip_ws_and_nl(s, i)
     # Skip the argument list.
     if not g.match(s, i, '('):
         if trace: g.trace('syntax error: no argument list',i)
         return i
     i = self.skipBlock(s, i,'(', ')')
         # skipBlock skips the ')'
     if i == len(s):
         g.trace('no args', g.get_line(s, i))
         return i
     # Skip the body.
     i = g.skip_ws_and_nl(s, i)
     if not g.match(s, i, '{'):
         if trace: g.trace('no function body', i)
         return i
     block_i1 = i
     block_i2 = i = self.skipBlock(s, i, '{', '}')
     j = g.skip_ws_and_nl(s,i)
     if g.match(s, j, '('):
         i = g.skip_parens(s, i)
     if in_expr:
         j = g.skip_ws_and_nl(s,i)
         if g.match(s, j, ')'):
             i = j + 1
     assert i > i1
     block_s = s[block_i1+1:block_i2-1].strip()
     if trace: g.trace('*** rescanning ***\n\n%s\n\n' % block_s)
     self.scanHelper(parent, block_s)
     return i
Exemple #5
0
    def skipArgs(self, s, i, kind):
        '''Skip the argument or class list.  Return i, ok

        kind is in ('class','function')'''
        start = i
        i = g.skip_ws_and_nl(s, i)
        if not g.match(s, i, '('):
            return start, kind == 'class'
        i = self.skipParens(s, i)
        # skipParens skips the ')'
        if i >= len(s):
            return start, False
        else:
            return i, True
Exemple #6
0
    def skipArgs(self, s, i, kind):
        '''Skip the argument or class list.  Return i, ok

        kind is in ('class','function')'''
        start = i
        i = g.skip_ws_and_nl(s, i)
        if not g.match(s, i, '('):
            return start, kind == 'class'
        i = self.skipParens(s, i)
        # skipParens skips the ')'
        if i >= len(s):
            return start, False
        else:
            return i, True
Exemple #7
0
    def extendSignature(self, s, i):
        '''Extend the text to be added to the class node following the signature.

        The text *must* end with a newline.'''
        # Add a docstring to the class node,
        # And everything on the line following it
        j = g.skip_ws_and_nl(s, i)
        if g.match(s, j, '"""') or g.match(s, j, "'''"):
            j = g.skip_python_string(s, j)
            if j < len(s): # No scanning error.
                # Return the docstring only if nothing but whitespace follows.
                j = g.skip_ws(s, j)
                if g.is_nl(s, j):
                    return j + 1
        return i
Exemple #8
0
    def extendSignature(self, s, i):
        '''Extend the text to be added to the class node following the signature.

        The text *must* end with a newline.'''
        # Add a docstring to the class node,
        # And everything on the line following it
        j = g.skip_ws_and_nl(s, i)
        if g.match(s, j, '"""') or g.match(s, j, "'''"):
            j = g.skip_python_string(s, j)
            if j < len(s):  # No scanning error.
                # Return the docstring only if nothing but whitespace follows.
                j = g.skip_ws(s, j)
                if g.is_nl(s, j):
                    return j + 1
        return i
Exemple #9
0
    def skipToMatchingTag (self,s,i,tag,tags,start):

        '''Skip the entire class definition. Return i,ok.
        '''

        trace = False
        found,level,target_tag = False,1,tag.lower()
        while i < len(s): 
            progress = i
            if s[i] == '"':
                i = self.skipString(s,i)
            elif g.match(s,i,'<!--'):
                i = self.skipComment(s,i)
            elif g.match(s,i,'</'):
                j = i+2
                i = self.skipId(s,j)
                tag2 = s[j:i].lower()
                i,ok,complete = self.skipToEndOfTag(s,i,start=j)
                    # Sets complete if /> terminates the tag.
                if ok and tag2 == target_tag:
                    level -= 1
                    if level == 0:
                        found = True ; break
            elif g.match(s,i,'<'):
                # An open tag.
                j = g.skip_ws_and_nl(s,i+1)
                i = self.skipId(s,j)
                word = s[j:i].lower()
                i,ok,complete = self.skipToEndOfTag(s,i,start=j)
                # **Important**: only bump level for nested *target* tags.
                # This avoids problems when interior tags are not properly nested.
                if ok and word == target_tag and not complete:
                    level += 1
            elif g.match(s,i,'/>'):
                # This is a syntax error.
                # This should have been eaten by skipToEndOfTag.
                i += 2
                g.trace('syntax error: unmatched "/>"')
            else:
                i += 1

            assert progress < i

        if trace: g.trace('%sfound:%s\n%s\n\n*****end %s\n' % (
            '' if found else 'not ',target_tag,s[start:i],target_tag))

        return i,found
Exemple #10
0
    def skipArgs(self, s, i, kind):
        """Skip the argument or class list.  Return i, ok

        kind is in ('class','function')"""
        # Pascal interfaces have no argument list.
        if kind == "class":
            return i, True
        start = i
        i = g.skip_ws_and_nl(s, i)
        if not g.match(s, i, "("):
            return start, kind == "class"
        i = self.skipParens(s, i)
        # skipParens skips the ')'
        if i >= len(s):
            return start, False
        else:
            return i, True
Exemple #11
0
 def skipToMatchingTag(self, s, i, tag, tags, start):
     '''Skip the entire class definition. Return i,ok.
     '''
     trace = False
     found, level, target_tag = False, 1, tag.lower()
     while i < len(s):
         progress = i
         if s[i] == '"':
             i = self.skipString(s, i)
         elif g.match(s, i, '<!--'):
             i = self.skipComment(s, i)
         elif g.match(s, i, '</'):
             j = i + 2
             i = self.skipId(s, j)
             tag2 = s[j:i].lower()
             i, ok, complete = self.skipToEndOfTag(s, i, start=j)
             # Sets complete if /> terminates the tag.
             if ok and tag2 == target_tag:
                 level -= 1
                 if level == 0:
                     found = True
                     break
         elif g.match(s, i, '<'):
             # An open tag.
             j = g.skip_ws_and_nl(s, i + 1)
             i = self.skipId(s, j)
             word = s[j:i].lower()
             i, ok, complete = self.skipToEndOfTag(s, i, start=j)
             # **Important**: only bump level for nested *target* tags.
             # This avoids problems when interior tags are not properly nested.
             if ok and word == target_tag and not complete:
                 level += 1
         elif g.match(s, i, '/>'):
             # This is a syntax error.
             # This should have been eaten by skipToEndOfTag.
             i += 2
             g.trace('syntax error: unmatched "/>"')
         else:
             i += 1
         assert progress < i
     if trace:
         g.trace(
             '%sfound:%s\n%s\n\n*****end %s\n' %
             ('' if found else 'not ', target_tag, s[start:i], target_tag))
     return i, found
Exemple #12
0
 def startsFunction(self, s, i):
     '''Return True if s[i:] starts a function.
     Sets sigStart, sigEnd, sigId and codeEnd ivars.'''
     self.startSigIndent = self.getLeadingIndent(s, i)
     self.sigStart = i
     self.codeEnd = self.sigEnd = self.sigId = None
     if not g.match(s, i, '('): return False
     end = self.skipBlock(s, i)
     # g.trace('%3s %15s block: %s' % (i,repr(s[i:i+10]),repr(s[i:end])))
     if not g.match(s, end - 1, ')'): return False
     i = g.skip_ws(s, i + 1)
     if not g.match_word(s, i, 'defun'): return False
     i += len('defun')
     sigEnd = i = g.skip_ws_and_nl(s, i)
     j = self.skipId(s, i) # Bug fix: 2009/09/30
     word = s[i: j]
     if not word: return False
     self.codeEnd = end + 1
     self.sigEnd = sigEnd
     self.sigId = word
     return True
Exemple #13
0
 def startsFunction(self, s, i):
     '''Return True if s[i:] starts a function.
     Sets sigStart, sigEnd, sigId and codeEnd ivars.'''
     self.startSigIndent = self.getLeadingIndent(s, i)
     self.sigStart = i
     self.codeEnd = self.sigEnd = self.sigId = None
     if not g.match(s, i, '('): return False
     end = self.skipBlock(s, i)
     # g.trace('%3s %15s block: %s' % (i,repr(s[i:i+10]),repr(s[i:end])))
     if not g.match(s, end - 1, ')'): return False
     i = g.skip_ws(s, i + 1)
     if not g.match_word(s, i, 'defun'): return False
     i += len('defun')
     sigEnd = i = g.skip_ws_and_nl(s, i)
     j = self.skipId(s, i)  # Bug fix: 2009/09/30
     word = s[i:j]
     if not word: return False
     self.codeEnd = end + 1
     self.sigEnd = sigEnd
     self.sigId = word
     return True
Exemple #14
0
    def startsHelper(self,s,i,kind,tags,tag=None):
        '''return True if s[i:] starts a class or function.
        Sets sigStart, sigEnd, sigId and codeEnd ivars.'''

        trace = (False and kind == 'class') # and not g.unitTesting
        verbose = True
        self.codeEnd = self.sigEnd = self.sigId = None

        # Underindented lines can happen in any language, not just Python.
        # The skipBlock method of the base class checks for such lines.
        self.startSigIndent = self.getLeadingIndent(s,i)

        # Get the tag that starts the class or function.
        if not g.match(s,i,'<'): return False
        self.sigStart = i
        i += 1
        sigIdStart = j = g.skip_ws_and_nl(s,i)
        i = self.skipId(s,j)

        # Fix bug 501636: Leo's import code should support non-ascii xml tags.
        # The call to g.toUnicode only needed on Python 2.x.
        self.sigId = theId = g.toUnicode(s[j:i].lower())
            # Set sigId ivar 'early' for error messages.
            # Bug fix: html case does not matter.
        if not theId: return False

        if theId not in tags:
            if trace and verbose:
                g.trace('**** %s theId: %s not in tags: %s' % (
                    kind,theId,tags))
            return False

        if trace and verbose: g.trace(theId)
        classId = '' 
        sigId = theId

        # Complete the opening tag.
        i, ok, complete = self.skipToEndOfTag(s,i,start=sigIdStart)
        if not ok:
            if trace and verbose: g.trace('no tail',g.get_line(s,i))
            return False
        sigEnd = i

        # Bug fix: 2011/11/05.
        # For xml/html, make sure the signature includes any trailing whitespace.
        if not g.match(s,sigEnd,'\n') and not g.match(s,sigEnd-1,'\n'):
            # sigEnd = g.skip_line(s,sigEnd)
            sigEnd = g.skip_ws(s,sigEnd)

        if not complete:
            i,ok = self.skipToMatchingTag(s,i,theId,tags,start=sigIdStart)
            if not ok:
                if trace and verbose: g.trace('no matching tag:',theId)
                return False

        # Success: set the ivars.
        # Not used in xml/html.
        # self.sigStart = self.adjustDefStart(s,self.sigStart)
        self.codeEnd = i
        self.sigEnd = sigEnd
        self.sigId = sigId
        self.classId = classId

        # Scan to the start of the next tag.
        done = False
        while not done and i < len(s):
            progress = i
            if self.startsComment(s,i):
                i = self.skipComment(s,i)
            elif self.startsString(s,i):
                i = self.skipString(s,i)
            elif s[i] == '<':
                start = i
                i += 1
                if i < len(s) and s[i] == '/':
                    i += 1
                j = g.skip_ws_and_nl(s,i)
                if self.startsId(s,j):
                    i = self.skipId(s,j)
                    word = s[j:i].lower()
                    if word in tags:
                        self.codeEnd = start
                        done = True
                        break
                else:
                    i = j
            else:
                i += 1

            assert done or progress < i,'i: %d, ch: %s' % (i,repr(s[i]))

        if trace: g.trace(repr(s[self.sigStart:self.codeEnd]))
        return True
Exemple #15
0
 def startsHelper(self, s, i, kind, tags, tag=None):
     '''return True if s[i:] starts a class or function.
     Sets sigStart, sigEnd, sigId and codeEnd ivars.'''
     trace = (False and kind == 'class')  # and not g.unitTesting
     verbose = True
     self.codeEnd = self.sigEnd = self.sigId = None
     # Underindented lines can happen in any language, not just Python.
     # The skipBlock method of the base class checks for such lines.
     self.startSigIndent = self.getLeadingIndent(s, i)
     # Get the tag that starts the class or function.
     if not g.match(s, i, '<'): return False
     self.sigStart = i
     i += 1
     sigIdStart = j = g.skip_ws_and_nl(s, i)
     i = self.skipId(s, j)
     # Fix bug 501636: Leo's import code should support non-ascii xml tags.
     # The call to g.toUnicode only needed on Python 2.x.
     self.sigId = theId = g.toUnicode(s[j:i].lower())
     # Set sigId ivar 'early' for error messages.
     # Bug fix: html case does not matter.
     if not theId: return False
     if theId not in tags:
         if trace and verbose:
             g.trace('**** %s theId: %s not in tags: %s' %
                     (kind, theId, tags))
         return False
     if trace and verbose: g.trace(theId)
     classId = ''
     sigId = theId
     # Complete the opening tag.
     i, ok, complete = self.skipToEndOfTag(s, i, start=sigIdStart)
     if not ok:
         if trace and verbose: g.trace('no tail', g.get_line(s, i))
         return False
     sigEnd = i
     # Bug fix: 2011/11/05.
     # For xml/html, make sure the signature includes any trailing whitespace.
     if not g.match(s, sigEnd, '\n') and not g.match(s, sigEnd - 1, '\n'):
         # sigEnd = g.skip_line(s,sigEnd)
         sigEnd = g.skip_ws(s, sigEnd)
     if not complete:
         i, ok = self.skipToMatchingTag(s, i, theId, tags, start=sigIdStart)
         if not ok:
             if trace and verbose: g.trace('no matching tag:', theId)
             return False
     # Success: set the ivars.
     # Not used in xml/html.
     # self.sigStart = self.adjustDefStart(s,self.sigStart)
     self.codeEnd = i
     self.sigEnd = sigEnd
     self.sigId = sigId
     self.classId = classId
     # Scan to the start of the next tag.
     done = False
     while not done and i < len(s):
         progress = i
         if self.startsComment(s, i):
             i = self.skipComment(s, i)
         elif self.startsString(s, i):
             i = self.skipString(s, i)
         elif s[i] == '<':
             start = i
             i += 1
             if i < len(s) and s[i] == '/':
                 i += 1
             j = g.skip_ws_and_nl(s, i)
             if self.startsId(s, j):
                 i = self.skipId(s, j)
                 word = s[j:i].lower()
                 if word in tags:
                     self.codeEnd = start
                     done = True
                     break
             else:
                 i = j
         else:
             i += 1
         assert done or progress < i, 'i: %d, ch: %s' % (i, repr(s[i]))
     if trace: g.trace(repr(s[self.sigStart:self.codeEnd]))
     return True