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
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
def pythonNewlineHelper(self, s, i, parenCount, startIndent, underIndentedStart): trace = False breakFlag = False j, indent = g.skip_leading_ws_with_indent(s, i, self.tab_width) if trace: g.trace('startIndent', startIndent, 'indent', indent, 'parenCount', parenCount, 'line', repr(g.get_line(s, j))) if indent <= startIndent and parenCount == 0: # An underindented line: it ends the block *unless* # it is a blank or comment line or (2008/9/1) the end of a triple-quoted string. if g.match(s, j, '#'): if trace: g.trace('underindent: comment') if underIndentedStart is None: underIndentedStart = i i = j elif g.match(s, j, '\n'): if trace: g.trace('underindent: blank line') # Blank lines never start the range of underindented lines. i = j else: if trace: g.trace('underindent: end of block') breakFlag = True # The actual end of the block. else: if underIndentedStart and g.match(s, j, '\n'): # Add the blank line to the underindented range. if trace: g.trace( 'properly indented blank line extends underindent range' ) elif underIndentedStart and g.match(s, j, '#'): # Add the (properly indented!) comment line to the underindented range. if trace: g.trace( 'properly indented comment line extends underindent range' ) elif underIndentedStart is None: pass else: # A properly indented non-comment line. # Give a message for all underindented comments in underindented range. if trace: g.trace( 'properly indented line generates underindent errors') s2 = s[underIndentedStart:i] lines = g.splitlines(s2) for line in lines: if line.strip(): junk, indent = g.skip_leading_ws_with_indent( line, 0, self.tab_width) if indent <= startIndent: if j not in self.errorLines: # No error yet given. self.errorLines.append(j) self.underindentedComment(line) underIndentedStart = None if trace: g.trace('breakFlag', breakFlag, 'returns', i, 'underIndentedStart', underIndentedStart) return i, underIndentedStart, breakFlag
def skipInterface(self, s, i): """Skip from the opening delim to *past* the matching closing delim. If no matching is found i is set to len(s)""" trace = False start = i delim2 = "end." level = 0 start = i startIndent = self.startSigIndent if trace: g.trace("***", "startIndent", startIndent, g.callers()) while i < len(s): progress = i if g.is_nl(s, i): backslashNewline = i > 0 and g.match(s, i - 1, "\\\n") i = g.skip_nl(s, i) if not backslashNewline and not g.is_nl(s, i): j, indent = g.skip_leading_ws_with_indent(s, i, self.tab_width) line = g.get_line(s, j) if trace: g.trace("indent", indent, line) if indent < startIndent and line.strip(): # An non-empty underindented line. # Issue an error unless it contains just the closing bracket. if level == 1 and g.match(s, j, delim2): pass else: if j not in self.errorLines: # No error yet given. self.errorLines.append(j) self.underindentedLine(line) elif s[i] in (" ", "\t"): i += 1 # speed up the scan. elif self.startsComment(s, i): i = self.skipComment(s, i) elif self.startsString(s, i): i = self.skipString(s, i) elif g.match(s, i, delim2): i += len(delim2) if trace: g.trace("returns\n", repr(s[start:i])) return i else: i += 1 assert progress < i self.error("no interface") if 1: g.pr("** no interface **") i, j = g.getLine(s, start) g.trace(i, s[i:j]) else: if trace: g.trace("** no interface") return start
def skipInterface(self, s, i): '''Skip from the opening delim to *past* the matching closing delim. If no matching is found i is set to len(s)''' trace = False start = i delim2 = 'end.' level = 0 start = i startIndent = self.startSigIndent if trace: g.trace('***', 'startIndent', startIndent, g.callers()) while i < len(s): progress = i if g.is_nl(s, i): backslashNewline = i > 0 and g.match(s, i - 1, '\\\n') i = g.skip_nl(s, i) if not backslashNewline and not g.is_nl(s, i): j, indent = g.skip_leading_ws_with_indent( s, i, self.tab_width) line = g.get_line(s, j) if trace: g.trace('indent', indent, line) if indent < startIndent and line.strip(): # An non-empty underindented line. # Issue an error unless it contains just the closing bracket. if level == 1 and g.match(s, j, delim2): pass else: if j not in self.errorLines: # No error yet given. self.errorLines.append(j) self.underindentedLine(line) elif s[i] in ( ' ', '\t', ): i += 1 # speed up the scan. elif self.startsComment(s, i): i = self.skipComment(s, i) elif self.startsString(s, i): i = self.skipString(s, i) elif g.match(s, i, delim2): i += len(delim2) if trace: g.trace('returns\n', repr(s[start:i])) return i else: i += 1 assert progress < i self.error('no interface') if 1: g.pr('** no interface **') i, j = g.getLine(s, start) g.trace(i, s[i:j]) else: if trace: g.trace('** no interface') return start
def pythonNewlineHelper (self,s,i,parenCount,startIndent,underIndentedStart): trace = False breakFlag = False j, indent = g.skip_leading_ws_with_indent(s,i,self.tab_width) if trace: g.trace( 'startIndent',startIndent,'indent',indent,'parenCount',parenCount, 'line',repr(g.get_line(s,j))) if indent <= startIndent and parenCount == 0: # An underindented line: it ends the block *unless* # it is a blank or comment line or (2008/9/1) the end of a triple-quoted string. if g.match(s,j,'#'): if trace: g.trace('underindent: comment') if underIndentedStart is None: underIndentedStart = i i = j elif g.match(s,j,'\n'): if trace: g.trace('underindent: blank line') # Blank lines never start the range of underindented lines. i = j else: if trace: g.trace('underindent: end of block') breakFlag = True # The actual end of the block. else: if underIndentedStart and g.match(s,j,'\n'): # Add the blank line to the underindented range. if trace: g.trace('properly indented blank line extends underindent range') elif underIndentedStart and g.match(s,j,'#'): # Add the (properly indented!) comment line to the underindented range. if trace: g.trace('properly indented comment line extends underindent range') elif underIndentedStart is None: pass else: # A properly indented non-comment line. # Give a message for all underindented comments in underindented range. if trace: g.trace('properly indented line generates underindent errors') s2 = s[underIndentedStart:i] lines = g.splitlines(s2) for line in lines: if line.strip(): junk, indent = g.skip_leading_ws_with_indent(line,0,self.tab_width) if indent <= startIndent: if j not in self.errorLines: # No error yet given. self.errorLines.append(j) self.underindentedComment(line) underIndentedStart = None if trace: g.trace('breakFlag',breakFlag,'returns',i,'underIndentedStart',underIndentedStart) return i,underIndentedStart,breakFlag
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
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
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
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