10c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi""" 20c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiHyperParser 30c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi=========== 40c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiThis module defines the HyperParser class, which provides advanced parsing 50c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yiabilities for the ParenMatch and other extensions. 60c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiThe HyperParser uses PyParser. PyParser is intended mostly to give information 70c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yion the proper indentation of code. HyperParser gives some information on the 80c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yistructure of code, used by extensions to help the user. 90c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi""" 100c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi 110c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yiimport string 120c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yiimport keyword 130c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yifrom idlelib import PyParse 140c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi 150c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yiclass HyperParser: 160c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi 170c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi def __init__(self, editwin, index): 180c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi """Initialize the HyperParser to analyze the surroundings of the given 190c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi index. 200c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi """ 210c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi 220c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi self.editwin = editwin 230c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi self.text = text = editwin.text 240c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi 250c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi parser = PyParse.Parser(editwin.indentwidth, editwin.tabwidth) 260c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi 270c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi def index2line(index): 280c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi return int(float(index)) 290c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi lno = index2line(text.index(index)) 300c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi 310c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi if not editwin.context_use_ps1: 320c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi for context in editwin.num_context_lines: 330c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi startat = max(lno - context, 1) 340c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi startatindex = repr(startat) + ".0" 350c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi stopatindex = "%d.end" % lno 360c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi # We add the newline because PyParse requires a newline at end. 370c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi # We add a space so that index won't be at end of line, so that 380c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi # its status will be the same as the char before it, if should. 390c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi parser.set_str(text.get(startatindex, stopatindex)+' \n') 400c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi bod = parser.find_good_parse_start( 410c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi editwin._build_char_in_string_func(startatindex)) 420c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi if bod is not None or startat == 1: 430c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi break 440c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi parser.set_lo(bod or 0) 450c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi else: 460c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi r = text.tag_prevrange("console", index) 470c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi if r: 480c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi startatindex = r[1] 490c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi else: 500c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi startatindex = "1.0" 510c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi stopatindex = "%d.end" % lno 520c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi # We add the newline because PyParse requires a newline at end. 530c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi # We add a space so that index won't be at end of line, so that 540c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi # its status will be the same as the char before it, if should. 550c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi parser.set_str(text.get(startatindex, stopatindex)+' \n') 560c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi parser.set_lo(0) 570c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi 580c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi # We want what the parser has, except for the last newline and space. 590c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi self.rawtext = parser.str[:-2] 600c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi # As far as I can see, parser.str preserves the statement we are in, 610c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi # so that stopatindex can be used to synchronize the string with the 620c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi # text box indices. 630c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi self.stopatindex = stopatindex 640c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi self.bracketing = parser.get_last_stmt_bracketing() 650c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi # find which pairs of bracketing are openers. These always correspond 660c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi # to a character of rawtext. 670c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi self.isopener = [i>0 and self.bracketing[i][1] > self.bracketing[i-1][1] 680c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi for i in range(len(self.bracketing))] 690c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi 700c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi self.set_index(index) 710c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi 720c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi def set_index(self, index): 730c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi """Set the index to which the functions relate. Note that it must be 740c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi in the same statement. 750c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi """ 760c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi indexinrawtext = \ 770c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi len(self.rawtext) - len(self.text.get(index, self.stopatindex)) 780c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi if indexinrawtext < 0: 790c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi raise ValueError("The index given is before the analyzed statement") 800c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi self.indexinrawtext = indexinrawtext 810c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi # find the rightmost bracket to which index belongs 820c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi self.indexbracket = 0 830c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi while self.indexbracket < len(self.bracketing)-1 and \ 840c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi self.bracketing[self.indexbracket+1][0] < self.indexinrawtext: 850c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi self.indexbracket += 1 860c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi if self.indexbracket < len(self.bracketing)-1 and \ 870c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi self.bracketing[self.indexbracket+1][0] == self.indexinrawtext and \ 880c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi not self.isopener[self.indexbracket+1]: 890c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi self.indexbracket += 1 900c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi 910c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi def is_in_string(self): 920c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi """Is the index given to the HyperParser is in a string?""" 930c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi # The bracket to which we belong should be an opener. 940c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi # If it's an opener, it has to have a character. 950c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi return self.isopener[self.indexbracket] and \ 960c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi self.rawtext[self.bracketing[self.indexbracket][0]] in ('"', "'") 970c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi 980c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi def is_in_code(self): 990c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi """Is the index given to the HyperParser is in a normal code?""" 1000c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi return not self.isopener[self.indexbracket] or \ 1010c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi self.rawtext[self.bracketing[self.indexbracket][0]] not in \ 1020c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi ('#', '"', "'") 1030c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi 1040c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi def get_surrounding_brackets(self, openers='([{', mustclose=False): 1050c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi """If the index given to the HyperParser is surrounded by a bracket 1060c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi defined in openers (or at least has one before it), return the 1070c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi indices of the opening bracket and the closing bracket (or the 1080c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi end of line, whichever comes first). 1090c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi If it is not surrounded by brackets, or the end of line comes before 1100c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi the closing bracket and mustclose is True, returns None. 1110c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi """ 1120c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi bracketinglevel = self.bracketing[self.indexbracket][1] 1130c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi before = self.indexbracket 1140c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi while not self.isopener[before] or \ 1150c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi self.rawtext[self.bracketing[before][0]] not in openers or \ 1160c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi self.bracketing[before][1] > bracketinglevel: 1170c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi before -= 1 1180c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi if before < 0: 1190c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi return None 1200c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi bracketinglevel = min(bracketinglevel, self.bracketing[before][1]) 1210c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi after = self.indexbracket + 1 1220c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi while after < len(self.bracketing) and \ 1230c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi self.bracketing[after][1] >= bracketinglevel: 1240c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi after += 1 1250c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi 1260c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi beforeindex = self.text.index("%s-%dc" % 1270c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi (self.stopatindex, len(self.rawtext)-self.bracketing[before][0])) 1280c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi if after >= len(self.bracketing) or \ 1290c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi self.bracketing[after][0] > len(self.rawtext): 1300c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi if mustclose: 1310c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi return None 1320c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi afterindex = self.stopatindex 1330c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi else: 1340c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi # We are after a real char, so it is a ')' and we give the index 1350c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi # before it. 1360c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi afterindex = self.text.index("%s-%dc" % 1370c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi (self.stopatindex, 1380c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi len(self.rawtext)-(self.bracketing[after][0]-1))) 1390c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi 1400c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi return beforeindex, afterindex 1410c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi 1420c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi # This string includes all chars that may be in a white space 1430c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi _whitespace_chars = " \t\n\\" 1440c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi # This string includes all chars that may be in an identifier 1450c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi _id_chars = string.ascii_letters + string.digits + "_" 1460c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi # This string includes all chars that may be the first char of an identifier 1470c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi _id_first_chars = string.ascii_letters + "_" 1480c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi 1490c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi # Given a string and pos, return the number of chars in the identifier 1500c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi # which ends at pos, or 0 if there is no such one. Saved words are not 1510c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi # identifiers. 1520c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi def _eat_identifier(self, str, limit, pos): 1530c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi i = pos 1540c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi while i > limit and str[i-1] in self._id_chars: 1550c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi i -= 1 1560c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi if i < pos and (str[i] not in self._id_first_chars or \ 1570c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi keyword.iskeyword(str[i:pos])): 1580c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi i = pos 1590c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi return pos - i 1600c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi 1610c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi def get_expression(self): 1620c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi """Return a string with the Python expression which ends at the given 1630c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi index, which is empty if there is no real one. 1640c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi """ 1650c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi if not self.is_in_code(): 1660c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi raise ValueError("get_expression should only be called if index "\ 1670c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi "is inside a code.") 1680c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi 1690c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi rawtext = self.rawtext 1700c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi bracketing = self.bracketing 1710c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi 1720c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi brck_index = self.indexbracket 1730c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi brck_limit = bracketing[brck_index][0] 1740c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi pos = self.indexinrawtext 1750c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi 1760c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi last_identifier_pos = pos 1770c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi postdot_phase = True 1780c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi 1790c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi while 1: 1800c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi # Eat whitespaces, comments, and if postdot_phase is False - one dot 1810c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi while 1: 1820c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi if pos>brck_limit and rawtext[pos-1] in self._whitespace_chars: 1830c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi # Eat a whitespace 1840c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi pos -= 1 1850c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi elif not postdot_phase and \ 1860c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi pos > brck_limit and rawtext[pos-1] == '.': 1870c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi # Eat a dot 1880c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi pos -= 1 1890c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi postdot_phase = True 1900c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi # The next line will fail if we are *inside* a comment, but we 1910c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi # shouldn't be. 1920c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi elif pos == brck_limit and brck_index > 0 and \ 1930c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi rawtext[bracketing[brck_index-1][0]] == '#': 1940c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi # Eat a comment 1950c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi brck_index -= 2 1960c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi brck_limit = bracketing[brck_index][0] 1970c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi pos = bracketing[brck_index+1][0] 1980c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi else: 1990c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi # If we didn't eat anything, quit. 2000c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi break 2010c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi 2020c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi if not postdot_phase: 2030c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi # We didn't find a dot, so the expression end at the last 2040c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi # identifier pos. 2050c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi break 2060c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi 2070c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi ret = self._eat_identifier(rawtext, brck_limit, pos) 2080c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi if ret: 2090c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi # There is an identifier to eat 2100c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi pos = pos - ret 2110c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi last_identifier_pos = pos 2120c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi # Now, in order to continue the search, we must find a dot. 2130c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi postdot_phase = False 2140c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi # (the loop continues now) 2150c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi 2160c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi elif pos == brck_limit: 2170c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi # We are at a bracketing limit. If it is a closing bracket, 2180c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi # eat the bracket, otherwise, stop the search. 2190c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi level = bracketing[brck_index][1] 2200c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi while brck_index > 0 and bracketing[brck_index-1][1] > level: 2210c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi brck_index -= 1 2220c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi if bracketing[brck_index][0] == brck_limit: 2230c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi # We were not at the end of a closing bracket 2240c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi break 2250c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi pos = bracketing[brck_index][0] 2260c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi brck_index -= 1 2270c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi brck_limit = bracketing[brck_index][0] 2280c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi last_identifier_pos = pos 2290c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi if rawtext[pos] in "([": 2300c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi # [] and () may be used after an identifier, so we 2310c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi # continue. postdot_phase is True, so we don't allow a dot. 2320c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi pass 2330c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi else: 2340c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi # We can't continue after other types of brackets 2350c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi if rawtext[pos] in "'\"": 2360c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi # Scan a string prefix 2370c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi while pos > 0 and rawtext[pos - 1] in "rRbBuU": 2380c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi pos -= 1 2390c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi last_identifier_pos = pos 2400c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi break 2410c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi 2420c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi else: 2430c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi # We've found an operator or something. 2440c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi break 2450c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi 2460c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi return rawtext[last_identifier_pos:self.indexinrawtext] 247