1
###############################################################################
2
# Name: feritetags.py #
3
# Purpose: Generate Tags for Ferite Documents #
4
# Author: Cody Precord <cprecord@editra.org> #
5
# Copyright: (c) 2008 Cody Precord <staff@editra.org> #
6
# License: wxWindows License #
7
###############################################################################
14
Generate a DocStruct object that captures the structure of a Ferite document.
15
Supports parsing of Namespaces, Classes, Protocols, Functions.
17
@todo: Currently Parsing of Namespaces within Namespaces is not supported
21
__author__ = "Cody Precord <cprecord@editra.org>"
22
__svnid__ = "$Id: feritetags.py 52805 2008-03-25 09:56:14Z CJP $"
23
__revision__ = "$Revision: 52805 $"
25
#--------------------------------------------------------------------------#
30
#--------------------------------------------------------------------------#
32
def GenerateTags(buff):
33
"""Create a DocStruct object that represents a Ferite document
34
@param buff: a file like buffer object (StringIO)
37
rtags = taglib.DocStruct()
39
# Setup document structure
40
rtags.SetElementDescription('namespace', "Namespaces")
41
rtags.SetElementDescription('class', "Class Definitions")
42
rtags.SetElementDescription('protocol', "Protocols")
43
rtags.SetElementDescription('function', "Function Definitions")
44
rtags.SetElementPriority('namespace', 4)
45
rtags.SetElementPriority('class', 3)
46
rtags.SetElementPriority('protocol', 2)
47
rtags.SetElementPriority('function', 1)
49
# Variables for tracking parse state
50
incomment = False # Inside a comment
51
innamespace = False # Inside a namespace
52
inclass = False # Inside a class defintion
53
inprotocol = False # Inside a protocol
54
infundef = False # Inside a function definition
55
lastnspace = None # Last Namespace
56
lastclass = None # Last Class
57
lastprotocol = None # Last Protocol
58
lastfun = None # last Function
59
openb = 0 # Keep track of open brackets for scope resolution
62
return innamespace or inclass or inprotocol or infundef
64
# Parse the contents of the buffer
65
for lnum, line in enumerate(buff):
69
while idx < len(line):
71
idx = parselib.SkipWhitespace(line, idx)
74
if line[idx:].startswith(u'/*'):
77
elif line[idx:].startswith(u'//'):
78
break # go to next line
79
elif line[idx:].startswith(u'*/'):
90
elif line[idx] == u'{':
93
# Namespace/Class/Protocol names must be followed by a {
94
if not InSubScope() and lastnspace is not None:
96
rtags.AddElement('namespace', lastnspace)
97
elif not inclass and lastclass is not None:
99
if lastnspace is not None:
100
# Class is in a namespace
101
lastnspace.AddElement('class', lastclass)
103
# Class is at the global scope
104
rtags.AddClass(lastclass)
105
elif not InSubScope() and lastprotocol is not None:
107
rtags.AddElement('protocol', lastprotocol)
108
elif lastfun is not None:
113
elif line[idx] == u'}':
116
# Check if the scope needs to change
117
if innamespace and openb == 0:
120
elif innamespace and inclass and openb == 1:
123
elif (innamespace and inclass and infundef and openb == 2) or \
124
(innamespace and infundef and openb == 1):
127
elif inclass and openb == 0:
130
elif inclass and infundef and openb == 1:
133
elif inprotocol and openb == 0:
136
elif inprotocol and infundef and openb == 1:
139
elif infundef and openb == 0:
144
elif not infundef and parselib.IsToken(line, idx, u'class'):
146
idx = parselib.SkipWhitespace(line, idx + 5)
147
name = parselib.GetFirstIdentifier(line[idx:])
149
idx += len(name) # Move past the class name
150
lastclass = taglib.Class(name, lnum)
151
elif not infundef and not inclass and \
152
parselib.IsToken(line, idx, 'namespace'):
153
idx = parselib.SkipWhitespace(line, idx + 9)
154
name = GetElementName(line[idx:])
157
lastnspace = taglib.Namespace(name, lnum)
158
elif parselib.IsToken(line, idx, u'protocol'):
159
idx = parselib.SkipWhitespace(line, idx + 8)
160
name = parselib.GetFirstIdentifier(line[idx:])
163
lastprotocol = Protocol(name, lnum)
164
elif parselib.IsToken(line, idx, u'function'):
166
idx = parselib.SkipWhitespace(line, idx + 8)
167
name = parselib.GetFirstIdentifier(line[idx:])
171
idx = parselib.SkipWhitespace(line, idx + len(name))
173
if line[idx] != u'(':
176
tfun = taglib.Function(name, lnum)
177
if innamespace and not inclass and lastnspace:
178
lastnspace.AddElement('function', tfun)
179
elif inclass and lastclass is not None:
180
lastclass.AddMethod(taglib.Method(name, lnum, lastclass.GetName()))
181
elif inprotocol and lastprotocol is not None:
182
lastprotocol.AddElement('function', tfun)
184
rtags.AddFunction(tfun)
190
#-----------------------------------------------------------------------------#
191
class Protocol(taglib.Scope):
192
"""Protocol Code Object"""
193
def __init__(self, name, line, scope=None):
194
taglib.Scope.__init__(self, name, line, "protocol", scope)
196
def GetElementName(line):
197
"""Get the first element name on the given line, ignoring whitespace and
200
@return: string or None
203
for part in line.split():
204
name = parselib.GetFirstIdentifier(part)
205
if name is not None and name not in FERITE_KW:
211
FERITE_KW = ("false null self super true abstract alias and arguments "
212
"attribute_missing break case class closure conformsToProtocol "
213
"constructor continue default deliver destructor diliver "
214
"directive do else extends eval final fix for function global "
215
"handle if iferr implements include instanceof isa "
216
"method_missing modifies monitor namespace new or private "
217
"protected protocol public raise recipient rename return "
218
"static switch uses using while")
220
#-----------------------------------------------------------------------------#
222
if __name__ == '__main__':
225
fhandle = open(sys.argv[1])
228
tags = GenerateTags(StringIO.StringIO(txt))
229
print "\n\nElements:"
230
for element in tags.GetElements():
231
print "\n%s:" % element.keys()[0]
232
for val in element.values()[0]:
233
print "%s [%d]" % (val.GetName(), val.GetLine())