diff options
author | Guido van Rossum <guido@python.org> | 1997-10-27 20:44:15 (GMT) |
---|---|---|
committer | Guido van Rossum <guido@python.org> | 1997-10-27 20:44:15 (GMT) |
commit | 3b631775b26b866e072cd3340f303bf5903af883 (patch) | |
tree | 7e92990e253f41403be8958774bd4c1ecd2c9fd1 /Lib | |
parent | 9d37a4d332570792c054ecbd6c598cf5eb91d785 (diff) | |
download | cpython-3b631775b26b866e072cd3340f303bf5903af883.zip cpython-3b631775b26b866e072cd3340f303bf5903af883.tar.gz cpython-3b631775b26b866e072cd3340f303bf5903af883.tar.bz2 |
Redone (by Ka-Ping) using the new re module, and adding recognition
for r"..." raw strings. (And R"..." string support added by Guido.)
Diffstat (limited to 'Lib')
-rw-r--r-- | Lib/tokenize.py | 112 |
1 files changed, 55 insertions, 57 deletions
diff --git a/Lib/tokenize.py b/Lib/tokenize.py index fc1d45b..c74e93a 100644 --- a/Lib/tokenize.py +++ b/Lib/tokenize.py @@ -7,16 +7,11 @@ function which is called once for each token found. The latter function is passed the token type, a string containing the token, the starting and ending (row, column) coordinates of the token, and the original line. It is designed to match the working of the Python tokenizer exactly, except that -it produces COMMENT tokens for comments and gives type OP for all operators. +it produces COMMENT tokens for comments and gives type OP for all operators.""" -For compatibility with the older 'tokenize' module, this also compiles a -regular expression into 'tokenprog' that matches Python tokens in individual -lines of text, leaving the token in 'tokenprog.group(3)', but does not -handle indentation, continuations, or multi-line strings.""" +__version__ = "Ka-Ping Yee, 26 October 1997" -__version__ = "Ka-Ping Yee, 29 March 1997" - -import string, regex +import string, re from token import * COMMENT = N_TOKENS @@ -26,56 +21,55 @@ tok_name[COMMENT] = 'COMMENT' # Ignore now accepts \f as whitespace. Operator now includes '**'. # Ignore and Special now accept \n or \r\n at the end of a line. # Imagnumber is new. Expfloat is corrected to reject '0e4'. -# Note: to get a quoted backslash in a regex, it must be enclosed in brackets. +# Note: to quote a backslash in a regex, it must be doubled in a r'aw' string. -def group(*choices): return '\(' + string.join(choices, '\|') + '\)' +def group(*choices): return '(' + string.join(choices, '|') + ')' +def any(*choices): return apply(group, choices) + '*' +def maybe(*choices): return apply(group, choices) + '?' -Whitespace = '[ \f\t]*' -Comment = '\(#[^\r\n]*\)' -Ignore = Whitespace + group('[\]\r?\n' + Whitespace)+'*' + Comment+'?' -Name = '[a-zA-Z_][a-zA-Z0-9_]*' +Whitespace = r'[ \f\t]*' +Comment = r'#[^\r\n]*' +Ignore = Whitespace + any(r'\\\r?\n' + Whitespace) + maybe(Comment) +Name = r'[a-zA-Z_]\w*' -Hexnumber = '0[xX][0-9a-fA-F]*[lL]?' -Octnumber = '0[0-7]*[lL]?' -Decnumber = '[1-9][0-9]*[lL]?' +Hexnumber = r'0[xX][\da-fA-F]*[lL]?' +Octnumber = r'0[0-7]*[lL]?' +Decnumber = r'[1-9]\d*[lL]?' Intnumber = group(Hexnumber, Octnumber, Decnumber) -Exponent = '[eE][-+]?[0-9]+' -Pointfloat = group('[0-9]+\.[0-9]*', '\.[0-9]+') + group(Exponent) + '?' -Expfloat = '[1-9][0-9]*' + Exponent +Exponent = r'[eE][-+]?\d+' +Pointfloat = group(r'\d+\.\d*', r'\.\d+') + maybe(Exponent) +Expfloat = r'[1-9]\d*' + Exponent Floatnumber = group(Pointfloat, Expfloat) -Imagnumber = group('0[jJ]', '[1-9][0-9]*[jJ]', Floatnumber + '[jJ]') +Imagnumber = group(r'0[jJ]', r'[1-9]\d*[jJ]', Floatnumber + r'[jJ]') Number = group(Imagnumber, Floatnumber, Intnumber) -Single = group("[^'\]", "[\].") + "*'" -Double = group('[^"\]', '[\].') + '*"' -Single3 = group("[^'\]","[\].","'[^'\]","'[\].","''[^'\]","''[\].") + "*'''" -Double3 = group('[^"\]','[\].','"[^"\]','"[\].','""[^"\]','""[\].') + '*"""' -Triple = group("'''", '"""') -String = group("'" + group("[^\n'\]", "[\].") + "*'", - '"' + group('[^\n"\]', '[\].') + '*"') +Single = any(r"[^'\\]", r'\\.') + "'" +Double = any(r'[^"\\]', r'\\.') + '"' +Single3 = any(r"[^'\\]",r'\\.',r"'[^'\\]",r"'\\.",r"''[^'\\]",r"''\\.") + "'''" +Double3 = any(r'[^"\\]',r'\\.',r'"[^"\\]',r'"\\.',r'""[^"\\]',r'""\\.') + '"""' +Triple = group("'''", '"""', "r'''", 'r"""') +String = group("[rR]?'" + any(r"[^\n'\\]", r'\\.') + "'", + '[rR]?"' + any(r'[^\n"\\]', r'\\.') + '"') -Operator = group('\+', '\-', '\*\*', '\*', '\^', '~', '/', '%', '&', '|', +Operator = group('\+', '\-', '\*\*', '\*', '\^', '~', '/', '%', '&', '\|', '<<', '>>', '==', '<=', '<>', '!=', '>=', '=', '<', '>') Bracket = '[][(){}]' -Special = group('\r?\n', '[:;.,`]') +Special = group(r'\r?\n', r'[:;.,`]') Funny = group(Operator, Bracket, Special) -PlainToken = group(Name, Number, String, Funny) +PlainToken = group(Number, Funny, String, Name) Token = Ignore + PlainToken -ContStr = group("'" + group('[\].', "[^\n'\]")+'*' + group("'", '[\]\r?\n'), - '"' + group('[\].', '[^\n"\]')+'*' + group('"', '[\]\r?\n')) -PseudoExtras = group('[\]\r?\n', Comment, Triple) -PseudoToken = Whitespace + group(PseudoExtras, Name, Number, ContStr, Funny) +ContStr = group("r?'" + any(r'\\.', r"[^\n'\\]") + group("'", r'\\\r?\n'), + 'r?"' + any(r'\\.', r'[^\n"\\]') + group('"', r'\\\r?\n')) +PseudoExtras = group(r'\\\r?\n', Comment, Triple) +PseudoToken = Whitespace + group(PseudoExtras, Number, Funny, ContStr, Name) -try: - saved_syntax = regex.set_syntax(0) # use default syntax - tokenprog = regex.compile(Token) - pseudoprog = regex.compile(PseudoToken) - endprogs = { '\'': regex.compile(Single), '"': regex.compile(Double), - '\'\'\'': regex.compile(Single3), '"""': regex.compile(Double3) } -finally: - regex.set_syntax(saved_syntax) # restore original syntax +tokenprog, pseudoprog, single3prog, double3prog = map( + re.compile, (Token, PseudoToken, Single3, Double3)) +endprogs = {"'": re.compile(Single), '"': re.compile(Double), 'r': None, + "'''": single3prog, '"""': double3prog, + "r'''": single3prog, 'r"""': double3prog} tabsize = 8 TokenError = 'TokenError' @@ -97,8 +91,9 @@ def tokenize(readline, tokeneater=printtoken): if contstr: # continued string if not line: raise TokenError, ("EOF in multi-line string", strstart) - if endprog.match(line) >= 0: - pos = end = endprog.regs[0][1] + endmatch = endprog.match(line) + if endmatch: + pos = end = endmatch.end(0) tokeneater(STRING, contstr + line[:end], strstart, (lnum, end), line) contstr, needcont = '', 0 @@ -140,40 +135,42 @@ def tokenize(readline, tokeneater=printtoken): continued = 0 while pos < max: - if pseudoprog.match(line, pos) > 0: # scan for tokens - start, end = pseudoprog.regs[1] + pseudomatch = pseudoprog.match(line, pos) + if pseudomatch: # scan for tokens + start, end = pseudomatch.span(1) spos, epos, pos = (lnum, start), (lnum, end), end token, initial = line[start:end], line[start] - if initial in namechars: # ordinary name - tokeneater(NAME, token, spos, epos, line) - elif initial in numchars \ + if initial in numchars \ or (initial == '.' and token != '.'): # ordinary number tokeneater(NUMBER, token, spos, epos, line) elif initial in '\r\n': tokeneater(NEWLINE, token, spos, epos, line) elif initial == '#': tokeneater(COMMENT, token, spos, epos, line) - elif initial == '\\': # continued stmt - continued = 1 - elif token in ('\'\'\'', '"""'): # triple-quoted + elif token in ("'''",'"""',"r'''",'r"""'): # triple-quoted endprog = endprogs[token] - if endprog.match(line, pos) >= 0: # all on one line - pos = endprog.regs[0][1] + endmatch = endprog.match(line, pos) + if endmatch: # all on one line + pos = endmatch.end(0) token = line[start:pos] tokeneater(STRING, token, spos, (lnum, pos), line) else: strstart = (lnum, start) # multiple lines contstr = line[start:] break - elif initial in '\'"': + elif initial in ("'", '"') or token[:2] in ("r'", 'r"'): if token[-1] == '\n': # continued string strstart = (lnum, start) - endprog = endprogs[initial] + endprog = endprogs[initial] or endprogs[token[1]] contstr, needcont = line[start:], 1 break else: # ordinary string tokeneater(STRING, token, spos, epos, line) + elif initial in namechars: # ordinary name + tokeneater(NAME, token, spos, epos, line) + elif initial == '\\': # continued stmt + continued = 1 else: if initial in '([{': parenlev = parenlev + 1 elif initial in ')]}': parenlev = parenlev - 1 @@ -191,3 +188,4 @@ if __name__ == '__main__': # testing import sys if len(sys.argv) > 1: tokenize(open(sys.argv[1]).readline) else: tokenize(sys.stdin.readline) + |