annotate Mac/Tools/IDE/PyFontify.py @ 25838:8540887bcec6 2.2

Backport of 2.183: Fix memory leak in add_subclass() found by NealN with valgrind.
author Guido van Rossum <guido@python.org>
date Fri, 18 Oct 2002 13:42:21 +0000
parents e78a51268c81
children 71a294bd7950
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
10047
a0b06891d286 First Checked In.
Just van Rossum <just@lettererror.com>
parents:
diff changeset
1 """Module to analyze Python source code; for syntax coloring tools.
a0b06891d286 First Checked In.
Just van Rossum <just@lettererror.com>
parents:
diff changeset
2
a0b06891d286 First Checked In.
Just van Rossum <just@lettererror.com>
parents:
diff changeset
3 Interface:
a0b06891d286 First Checked In.
Just van Rossum <just@lettererror.com>
parents:
diff changeset
4 tags = fontify(pytext, searchfrom, searchto)
a0b06891d286 First Checked In.
Just van Rossum <just@lettererror.com>
parents:
diff changeset
5
a0b06891d286 First Checked In.
Just van Rossum <just@lettererror.com>
parents:
diff changeset
6 The 'pytext' argument is a string containing Python source code.
a0b06891d286 First Checked In.
Just van Rossum <just@lettererror.com>
parents:
diff changeset
7 The (optional) arguments 'searchfrom' and 'searchto' may contain a slice in pytext.
a0b06891d286 First Checked In.
Just van Rossum <just@lettererror.com>
parents:
diff changeset
8 The returned value is a list of tuples, formatted like this:
a0b06891d286 First Checked In.
Just van Rossum <just@lettererror.com>
parents:
diff changeset
9 [('keyword', 0, 6, None), ('keyword', 11, 17, None), ('comment', 23, 53, None), etc. ]
a0b06891d286 First Checked In.
Just van Rossum <just@lettererror.com>
parents:
diff changeset
10 The tuple contents are always like this:
a0b06891d286 First Checked In.
Just van Rossum <just@lettererror.com>
parents:
diff changeset
11 (tag, startindex, endindex, sublist)
a0b06891d286 First Checked In.
Just van Rossum <just@lettererror.com>
parents:
diff changeset
12 tag is one of 'keyword', 'string', 'comment' or 'identifier'
a0b06891d286 First Checked In.
Just van Rossum <just@lettererror.com>
parents:
diff changeset
13 sublist is not used, hence always None.
a0b06891d286 First Checked In.
Just van Rossum <just@lettererror.com>
parents:
diff changeset
14 """
a0b06891d286 First Checked In.
Just van Rossum <just@lettererror.com>
parents:
diff changeset
15
a0b06891d286 First Checked In.
Just van Rossum <just@lettererror.com>
parents:
diff changeset
16 # Based on FontText.py by Mitchell S. Chapman,
a0b06891d286 First Checked In.
Just van Rossum <just@lettererror.com>
parents:
diff changeset
17 # which was modified by Zachary Roadhouse,
a0b06891d286 First Checked In.
Just van Rossum <just@lettererror.com>
parents:
diff changeset
18 # then un-Tk'd by Just van Rossum.
a0b06891d286 First Checked In.
Just van Rossum <just@lettererror.com>
parents:
diff changeset
19 # Many thanks for regular expression debugging & authoring are due to:
a0b06891d286 First Checked In.
Just van Rossum <just@lettererror.com>
parents:
diff changeset
20 # Tim (the-incredib-ly y'rs) Peters and Cristian Tismer
a0b06891d286 First Checked In.
Just van Rossum <just@lettererror.com>
parents:
diff changeset
21 # So, who owns the copyright? ;-) How about this:
18453
e78a51268c81 - fixed some re usage, partly so it'll still work when re uses pre instead
Just van Rossum <just@letterror.com>
parents: 16725
diff changeset
22 # Copyright 1996-2001:
10047
a0b06891d286 First Checked In.
Just van Rossum <just@lettererror.com>
parents:
diff changeset
23 # Mitchell S. Chapman,
a0b06891d286 First Checked In.
Just van Rossum <just@lettererror.com>
parents:
diff changeset
24 # Zachary Roadhouse,
a0b06891d286 First Checked In.
Just van Rossum <just@lettererror.com>
parents:
diff changeset
25 # Tim Peters,
a0b06891d286 First Checked In.
Just van Rossum <just@lettererror.com>
parents:
diff changeset
26 # Just van Rossum
a0b06891d286 First Checked In.
Just van Rossum <just@lettererror.com>
parents:
diff changeset
27
18453
e78a51268c81 - fixed some re usage, partly so it'll still work when re uses pre instead
Just van Rossum <just@letterror.com>
parents: 16725
diff changeset
28 __version__ = "0.4"
10047
a0b06891d286 First Checked In.
Just van Rossum <just@lettererror.com>
parents:
diff changeset
29
18453
e78a51268c81 - fixed some re usage, partly so it'll still work when re uses pre instead
Just van Rossum <just@letterror.com>
parents: 16725
diff changeset
30 import string
e78a51268c81 - fixed some re usage, partly so it'll still work when re uses pre instead
Just van Rossum <just@letterror.com>
parents: 16725
diff changeset
31 import re
10047
a0b06891d286 First Checked In.
Just van Rossum <just@lettererror.com>
parents:
diff changeset
32
a0b06891d286 First Checked In.
Just van Rossum <just@lettererror.com>
parents:
diff changeset
33 # First a little helper, since I don't like to repeat things. (Tismer speaking)
a0b06891d286 First Checked In.
Just van Rossum <just@lettererror.com>
parents:
diff changeset
34 import string
a0b06891d286 First Checked In.
Just van Rossum <just@lettererror.com>
parents:
diff changeset
35 def replace(where, what, with):
a0b06891d286 First Checked In.
Just van Rossum <just@lettererror.com>
parents:
diff changeset
36 return string.join(string.split(where, what), with)
a0b06891d286 First Checked In.
Just van Rossum <just@lettererror.com>
parents:
diff changeset
37
a0b06891d286 First Checked In.
Just van Rossum <just@lettererror.com>
parents:
diff changeset
38 # This list of keywords is taken from ref/node13.html of the
a0b06891d286 First Checked In.
Just van Rossum <just@lettererror.com>
parents:
diff changeset
39 # Python 1.3 HTML documentation. ("access" is intentionally omitted.)
a0b06891d286 First Checked In.
Just van Rossum <just@lettererror.com>
parents:
diff changeset
40 keywordsList = [
12305
1f7c32801dc1 oops, keyword list missed exec... doh! thanks to Maik Roeder (jvr)
Just van Rossum <just@lettererror.com>
parents: 10047
diff changeset
41 "assert", "exec",
10047
a0b06891d286 First Checked In.
Just van Rossum <just@lettererror.com>
parents:
diff changeset
42 "del", "from", "lambda", "return",
a0b06891d286 First Checked In.
Just van Rossum <just@lettererror.com>
parents:
diff changeset
43 "and", "elif", "global", "not", "try",
a0b06891d286 First Checked In.
Just van Rossum <just@lettererror.com>
parents:
diff changeset
44 "break", "else", "if", "or", "while",
a0b06891d286 First Checked In.
Just van Rossum <just@lettererror.com>
parents:
diff changeset
45 "class", "except", "import", "pass",
a0b06891d286 First Checked In.
Just van Rossum <just@lettererror.com>
parents:
diff changeset
46 "continue", "finally", "in", "print",
18453
e78a51268c81 - fixed some re usage, partly so it'll still work when re uses pre instead
Just van Rossum <just@letterror.com>
parents: 16725
diff changeset
47 "def", "for", "is", "raise", "yield"]
10047
a0b06891d286 First Checked In.
Just van Rossum <just@lettererror.com>
parents:
diff changeset
48
a0b06891d286 First Checked In.
Just van Rossum <just@lettererror.com>
parents:
diff changeset
49 # Build up a regular expression which will match anything
a0b06891d286 First Checked In.
Just van Rossum <just@lettererror.com>
parents:
diff changeset
50 # interesting, including multi-line triple-quoted strings.
18453
e78a51268c81 - fixed some re usage, partly so it'll still work when re uses pre instead
Just van Rossum <just@letterror.com>
parents: 16725
diff changeset
51 commentPat = r"#[^\n]*"
10047
a0b06891d286 First Checked In.
Just van Rossum <just@lettererror.com>
parents:
diff changeset
52
18453
e78a51268c81 - fixed some re usage, partly so it'll still work when re uses pre instead
Just van Rossum <just@letterror.com>
parents: 16725
diff changeset
53 pat = r"q[^\\q\n]*(\\[\000-\377][^\\q\n]*)*q"
e78a51268c81 - fixed some re usage, partly so it'll still work when re uses pre instead
Just van Rossum <just@letterror.com>
parents: 16725
diff changeset
54 quotePat = replace(pat, "q", "'") + "|" + replace(pat, 'q', '"')
10047
a0b06891d286 First Checked In.
Just van Rossum <just@lettererror.com>
parents:
diff changeset
55
a0b06891d286 First Checked In.
Just van Rossum <just@lettererror.com>
parents:
diff changeset
56 # Way to go, Tim!
18453
e78a51268c81 - fixed some re usage, partly so it'll still work when re uses pre instead
Just van Rossum <just@letterror.com>
parents: 16725
diff changeset
57 pat = r"""
10047
a0b06891d286 First Checked In.
Just van Rossum <just@lettererror.com>
parents:
diff changeset
58 qqq
a0b06891d286 First Checked In.
Just van Rossum <just@lettererror.com>
parents:
diff changeset
59 [^\\q]*
18453
e78a51268c81 - fixed some re usage, partly so it'll still work when re uses pre instead
Just van Rossum <just@letterror.com>
parents: 16725
diff changeset
60 (
e78a51268c81 - fixed some re usage, partly so it'll still work when re uses pre instead
Just van Rossum <just@letterror.com>
parents: 16725
diff changeset
61 ( \\[\000-\377]
e78a51268c81 - fixed some re usage, partly so it'll still work when re uses pre instead
Just van Rossum <just@letterror.com>
parents: 16725
diff changeset
62 | q
e78a51268c81 - fixed some re usage, partly so it'll still work when re uses pre instead
Just van Rossum <just@letterror.com>
parents: 16725
diff changeset
63 ( \\[\000-\377]
e78a51268c81 - fixed some re usage, partly so it'll still work when re uses pre instead
Just van Rossum <just@letterror.com>
parents: 16725
diff changeset
64 | [^\q]
e78a51268c81 - fixed some re usage, partly so it'll still work when re uses pre instead
Just van Rossum <just@letterror.com>
parents: 16725
diff changeset
65 | q
e78a51268c81 - fixed some re usage, partly so it'll still work when re uses pre instead
Just van Rossum <just@letterror.com>
parents: 16725
diff changeset
66 ( \\[\000-\377]
e78a51268c81 - fixed some re usage, partly so it'll still work when re uses pre instead
Just van Rossum <just@letterror.com>
parents: 16725
diff changeset
67 | [^\\q]
e78a51268c81 - fixed some re usage, partly so it'll still work when re uses pre instead
Just van Rossum <just@letterror.com>
parents: 16725
diff changeset
68 )
e78a51268c81 - fixed some re usage, partly so it'll still work when re uses pre instead
Just van Rossum <just@letterror.com>
parents: 16725
diff changeset
69 )
e78a51268c81 - fixed some re usage, partly so it'll still work when re uses pre instead
Just van Rossum <just@letterror.com>
parents: 16725
diff changeset
70 )
10047
a0b06891d286 First Checked In.
Just van Rossum <just@lettererror.com>
parents:
diff changeset
71 [^\\q]*
18453
e78a51268c81 - fixed some re usage, partly so it'll still work when re uses pre instead
Just van Rossum <just@letterror.com>
parents: 16725
diff changeset
72 )*
10047
a0b06891d286 First Checked In.
Just van Rossum <just@lettererror.com>
parents:
diff changeset
73 qqq
a0b06891d286 First Checked In.
Just van Rossum <just@lettererror.com>
parents:
diff changeset
74 """
a0b06891d286 First Checked In.
Just van Rossum <just@lettererror.com>
parents:
diff changeset
75 pat = string.join(string.split(pat), '') # get rid of whitespace
18453
e78a51268c81 - fixed some re usage, partly so it'll still work when re uses pre instead
Just van Rossum <just@letterror.com>
parents: 16725
diff changeset
76 tripleQuotePat = replace(pat, "q", "'") + "|" + replace(pat, 'q', '"')
10047
a0b06891d286 First Checked In.
Just van Rossum <just@lettererror.com>
parents:
diff changeset
77
a0b06891d286 First Checked In.
Just van Rossum <just@lettererror.com>
parents:
diff changeset
78 # Build up a regular expression which matches all and only
a0b06891d286 First Checked In.
Just van Rossum <just@lettererror.com>
parents:
diff changeset
79 # Python keywords. This will let us skip the uninteresting
a0b06891d286 First Checked In.
Just van Rossum <just@lettererror.com>
parents:
diff changeset
80 # identifier references.
a0b06891d286 First Checked In.
Just van Rossum <just@lettererror.com>
parents:
diff changeset
81 # nonKeyPat identifies characters which may legally precede
a0b06891d286 First Checked In.
Just van Rossum <just@lettererror.com>
parents:
diff changeset
82 # a keyword pattern.
18453
e78a51268c81 - fixed some re usage, partly so it'll still work when re uses pre instead
Just van Rossum <just@letterror.com>
parents: 16725
diff changeset
83 nonKeyPat = r"(^|[^a-zA-Z0-9_.\"'])"
10047
a0b06891d286 First Checked In.
Just van Rossum <just@lettererror.com>
parents:
diff changeset
84
18453
e78a51268c81 - fixed some re usage, partly so it'll still work when re uses pre instead
Just van Rossum <just@letterror.com>
parents: 16725
diff changeset
85 keyPat = nonKeyPat + "(" + "|".join(keywordsList) + ")" + nonKeyPat
10047
a0b06891d286 First Checked In.
Just van Rossum <just@lettererror.com>
parents:
diff changeset
86
18453
e78a51268c81 - fixed some re usage, partly so it'll still work when re uses pre instead
Just van Rossum <just@letterror.com>
parents: 16725
diff changeset
87 matchPat = commentPat + "|" + keyPat + "|" + tripleQuotePat + "|" + quotePat
16725
d170c1e772c5 Use re in stead of regex, so we get rid of the annoying warning during startup.
Jack Jansen <jack.jansen@cwi.nl>
parents: 13291
diff changeset
88 matchRE = re.compile(matchPat)
10047
a0b06891d286 First Checked In.
Just van Rossum <just@lettererror.com>
parents:
diff changeset
89
a0b06891d286 First Checked In.
Just van Rossum <just@lettererror.com>
parents:
diff changeset
90 idKeyPat = "[ \t]*[A-Za-z_][A-Za-z_0-9.]*" # Ident w. leading whitespace.
16725
d170c1e772c5 Use re in stead of regex, so we get rid of the annoying warning during startup.
Jack Jansen <jack.jansen@cwi.nl>
parents: 13291
diff changeset
91 idRE = re.compile(idKeyPat)
10047
a0b06891d286 First Checked In.
Just van Rossum <just@lettererror.com>
parents:
diff changeset
92
a0b06891d286 First Checked In.
Just van Rossum <just@lettererror.com>
parents:
diff changeset
93
a0b06891d286 First Checked In.
Just van Rossum <just@lettererror.com>
parents:
diff changeset
94 def fontify(pytext, searchfrom = 0, searchto = None):
a0b06891d286 First Checked In.
Just van Rossum <just@lettererror.com>
parents:
diff changeset
95 if searchto is None:
a0b06891d286 First Checked In.
Just van Rossum <just@lettererror.com>
parents:
diff changeset
96 searchto = len(pytext)
a0b06891d286 First Checked In.
Just van Rossum <just@lettererror.com>
parents:
diff changeset
97 # Cache a few attributes for quicker reference.
a0b06891d286 First Checked In.
Just van Rossum <just@lettererror.com>
parents:
diff changeset
98 search = matchRE.search
a0b06891d286 First Checked In.
Just van Rossum <just@lettererror.com>
parents:
diff changeset
99 idSearch = idRE.search
a0b06891d286 First Checked In.
Just van Rossum <just@lettererror.com>
parents:
diff changeset
100
a0b06891d286 First Checked In.
Just van Rossum <just@lettererror.com>
parents:
diff changeset
101 tags = []
a0b06891d286 First Checked In.
Just van Rossum <just@lettererror.com>
parents:
diff changeset
102 tags_append = tags.append
a0b06891d286 First Checked In.
Just van Rossum <just@lettererror.com>
parents:
diff changeset
103 commentTag = 'comment'
a0b06891d286 First Checked In.
Just van Rossum <just@lettererror.com>
parents:
diff changeset
104 stringTag = 'string'
a0b06891d286 First Checked In.
Just van Rossum <just@lettererror.com>
parents:
diff changeset
105 keywordTag = 'keyword'
a0b06891d286 First Checked In.
Just van Rossum <just@lettererror.com>
parents:
diff changeset
106 identifierTag = 'identifier'
a0b06891d286 First Checked In.
Just van Rossum <just@lettererror.com>
parents:
diff changeset
107
a0b06891d286 First Checked In.
Just van Rossum <just@lettererror.com>
parents:
diff changeset
108 start = 0
a0b06891d286 First Checked In.
Just van Rossum <just@lettererror.com>
parents:
diff changeset
109 end = searchfrom
a0b06891d286 First Checked In.
Just van Rossum <just@lettererror.com>
parents:
diff changeset
110 while 1:
16725
d170c1e772c5 Use re in stead of regex, so we get rid of the annoying warning during startup.
Jack Jansen <jack.jansen@cwi.nl>
parents: 13291
diff changeset
111 m = search(pytext, end)
18453
e78a51268c81 - fixed some re usage, partly so it'll still work when re uses pre instead
Just van Rossum <just@letterror.com>
parents: 16725
diff changeset
112 if m is None:
e78a51268c81 - fixed some re usage, partly so it'll still work when re uses pre instead
Just van Rossum <just@letterror.com>
parents: 16725
diff changeset
113 break # EXIT LOOP
e78a51268c81 - fixed some re usage, partly so it'll still work when re uses pre instead
Just van Rossum <just@letterror.com>
parents: 16725
diff changeset
114 start = m.start()
e78a51268c81 - fixed some re usage, partly so it'll still work when re uses pre instead
Just van Rossum <just@letterror.com>
parents: 16725
diff changeset
115 if start >= searchto:
10047
a0b06891d286 First Checked In.
Just van Rossum <just@lettererror.com>
parents:
diff changeset
116 break # EXIT LOOP
16725
d170c1e772c5 Use re in stead of regex, so we get rid of the annoying warning during startup.
Jack Jansen <jack.jansen@cwi.nl>
parents: 13291
diff changeset
117 match = m.group(0)
10047
a0b06891d286 First Checked In.
Just van Rossum <just@lettererror.com>
parents:
diff changeset
118 end = start + len(match)
a0b06891d286 First Checked In.
Just van Rossum <just@lettererror.com>
parents:
diff changeset
119 c = match[0]
a0b06891d286 First Checked In.
Just van Rossum <just@lettererror.com>
parents:
diff changeset
120 if c not in "#'\"":
a0b06891d286 First Checked In.
Just van Rossum <just@lettererror.com>
parents:
diff changeset
121 # Must have matched a keyword.
a0b06891d286 First Checked In.
Just van Rossum <just@lettererror.com>
parents:
diff changeset
122 if start <> searchfrom:
a0b06891d286 First Checked In.
Just van Rossum <just@lettererror.com>
parents:
diff changeset
123 # there's still a redundant char before and after it, strip!
a0b06891d286 First Checked In.
Just van Rossum <just@lettererror.com>
parents:
diff changeset
124 match = match[1:-1]
a0b06891d286 First Checked In.
Just van Rossum <just@lettererror.com>
parents:
diff changeset
125 start = start + 1
a0b06891d286 First Checked In.
Just van Rossum <just@lettererror.com>
parents:
diff changeset
126 else:
a0b06891d286 First Checked In.
Just van Rossum <just@lettererror.com>
parents:
diff changeset
127 # this is the first keyword in the text.
a0b06891d286 First Checked In.
Just van Rossum <just@lettererror.com>
parents:
diff changeset
128 # Only a space at the end.
a0b06891d286 First Checked In.
Just van Rossum <just@lettererror.com>
parents:
diff changeset
129 match = match[:-1]
a0b06891d286 First Checked In.
Just van Rossum <just@lettererror.com>
parents:
diff changeset
130 end = end - 1
a0b06891d286 First Checked In.
Just van Rossum <just@lettererror.com>
parents:
diff changeset
131 tags_append((keywordTag, start, end, None))
a0b06891d286 First Checked In.
Just van Rossum <just@lettererror.com>
parents:
diff changeset
132 # If this was a defining keyword, look ahead to the
a0b06891d286 First Checked In.
Just van Rossum <just@lettererror.com>
parents:
diff changeset
133 # following identifier.
a0b06891d286 First Checked In.
Just van Rossum <just@lettererror.com>
parents:
diff changeset
134 if match in ["def", "class"]:
16725
d170c1e772c5 Use re in stead of regex, so we get rid of the annoying warning during startup.
Jack Jansen <jack.jansen@cwi.nl>
parents: 13291
diff changeset
135 m = idSearch(pytext, end)
18453
e78a51268c81 - fixed some re usage, partly so it'll still work when re uses pre instead
Just van Rossum <just@letterror.com>
parents: 16725
diff changeset
136 if m is not None:
e78a51268c81 - fixed some re usage, partly so it'll still work when re uses pre instead
Just van Rossum <just@letterror.com>
parents: 16725
diff changeset
137 start = m.start()
e78a51268c81 - fixed some re usage, partly so it'll still work when re uses pre instead
Just van Rossum <just@letterror.com>
parents: 16725
diff changeset
138 if start == end:
e78a51268c81 - fixed some re usage, partly so it'll still work when re uses pre instead
Just van Rossum <just@letterror.com>
parents: 16725
diff changeset
139 match = m.group(0)
e78a51268c81 - fixed some re usage, partly so it'll still work when re uses pre instead
Just van Rossum <just@letterror.com>
parents: 16725
diff changeset
140 end = start + len(match)
e78a51268c81 - fixed some re usage, partly so it'll still work when re uses pre instead
Just van Rossum <just@letterror.com>
parents: 16725
diff changeset
141 tags_append((identifierTag, start, end, None))
10047
a0b06891d286 First Checked In.
Just van Rossum <just@lettererror.com>
parents:
diff changeset
142 elif c == "#":
a0b06891d286 First Checked In.
Just van Rossum <just@lettererror.com>
parents:
diff changeset
143 tags_append((commentTag, start, end, None))
a0b06891d286 First Checked In.
Just van Rossum <just@lettererror.com>
parents:
diff changeset
144 else:
a0b06891d286 First Checked In.
Just van Rossum <just@lettererror.com>
parents:
diff changeset
145 tags_append((stringTag, start, end, None))
a0b06891d286 First Checked In.
Just van Rossum <just@lettererror.com>
parents:
diff changeset
146 return tags
a0b06891d286 First Checked In.
Just van Rossum <just@lettererror.com>
parents:
diff changeset
147
a0b06891d286 First Checked In.
Just van Rossum <just@lettererror.com>
parents:
diff changeset
148
a0b06891d286 First Checked In.
Just van Rossum <just@lettererror.com>
parents:
diff changeset
149 def test(path):
a0b06891d286 First Checked In.
Just van Rossum <just@lettererror.com>
parents:
diff changeset
150 f = open(path)
a0b06891d286 First Checked In.
Just van Rossum <just@lettererror.com>
parents:
diff changeset
151 text = f.read()
a0b06891d286 First Checked In.
Just van Rossum <just@lettererror.com>
parents:
diff changeset
152 f.close()
a0b06891d286 First Checked In.
Just van Rossum <just@lettererror.com>
parents:
diff changeset
153 tags = fontify(text)
a0b06891d286 First Checked In.
Just van Rossum <just@lettererror.com>
parents:
diff changeset
154 for tag, start, end, sublist in tags:
a0b06891d286 First Checked In.
Just van Rossum <just@lettererror.com>
parents:
diff changeset
155 print tag, `text[start:end]`